Skip to content

Commit 4b6fa67

Browse files
author
Brian Chen
committed
add set() overrides to lite sdk
1 parent 695d0a4 commit 4b6fa67

File tree

4 files changed

+152
-7
lines changed

4 files changed

+152
-7
lines changed

packages/firestore/lite/index.d.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export function setLogLevel(logLevel: LogLevel): void;
4545

4646
export interface FirestoreDataConverter<T> {
4747
toFirestore(modelObject: T): DocumentData;
48+
toFirestore(modelObject: Partial<T>, options: SetOptions): DocumentData;
4849
fromFirestore(snapshot: QueryDocumentSnapshot): T;
4950
}
5051

@@ -182,9 +183,10 @@ export class WriteBatch {
182183
commit(): Promise<void>;
183184
}
184185

185-
export type SetOptions =
186-
| { merge: true }
187-
| { mergeFields: Array<string | FieldPath> };
186+
export interface SetOptions {
187+
readonly merge?: boolean;
188+
readonly mergeFields?: Array<string | FieldPath>;
189+
}
188190

189191
export class DocumentReference<T = DocumentData> {
190192
private constructor();

packages/firestore/lite/src/api/write_batch.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export class WriteBatch implements firestore.WriteBatch {
6060
const ref = validateReference(documentRef, this._firestore);
6161

6262
const convertedValue = applyFirestoreDataConverter(ref._converter, value);
63-
6463
const parsed = this._dataReader.parseSetData(
6564
'WriteBatch.set',
6665
ref._key,
@@ -162,7 +161,10 @@ export function validateReference<T>(
162161
'Provided document reference is from a different Firestore instance.'
163162
);
164163
} else {
165-
return cast(documentRef, DocumentReference) as DocumentReference<T>;
164+
return (cast(
165+
documentRef,
166+
DocumentReference
167+
) as unknown) as DocumentReference<T>;
166168
}
167169
}
168170

packages/firestore/lite/test/integration.test.ts

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,8 @@ describe('equality', () => {
881881
expect(refEqual(coll1a, coll2)).to.be.false;
882882

883883
const coll1c = collection(firestore, 'a').withConverter({
884-
toFirestore: data => data as firestore.DocumentData,
884+
toFirestore: (data: firestore.DocumentData) =>
885+
data as firestore.DocumentData,
885886
fromFirestore: snap => snap.data()
886887
});
887888
expect(refEqual(coll1a, coll1c)).to.be.false;
@@ -900,7 +901,8 @@ describe('equality', () => {
900901
expect(refEqual(doc1a, doc2)).to.be.false;
901902

902903
const doc1c = collection(firestore, 'a').withConverter({
903-
toFirestore: data => data as firestore.DocumentData,
904+
toFirestore: (data: firestore.DocumentData) =>
905+
data as firestore.DocumentData,
904906
fromFirestore: snap => snap.data()
905907
});
906908
expect(refEqual(doc1a, doc1c)).to.be.false;
@@ -985,6 +987,35 @@ describe('withConverter() support', () => {
985987
}
986988
};
987989

990+
const postConverterMerge = {
991+
toFirestore(
992+
post: Partial<Post>,
993+
options?: firestore.SetOptions
994+
): firestore.DocumentData {
995+
if (
996+
options &&
997+
((options as { merge: true }).merge ||
998+
(options as { mergeFields: Array<string | number> }).mergeFields)
999+
) {
1000+
expect(post).to.not.be.an.instanceof(Post);
1001+
} else {
1002+
expect(post).to.be.an.instanceof(Post);
1003+
}
1004+
const result: firestore.DocumentData = {};
1005+
if (post.title) {
1006+
result.title = post.title;
1007+
}
1008+
if (post.author) {
1009+
result.author = post.author;
1010+
}
1011+
return result;
1012+
},
1013+
fromFirestore(snapshot: firestore.QueryDocumentSnapshot): Post {
1014+
const data = snapshot.data();
1015+
return new Post(data.title, data.author);
1016+
}
1017+
};
1018+
9881019
it('for DocumentReference.withConverter()', () => {
9891020
return withTestDoc(async docRef => {
9901021
docRef = docRef.withConverter(postConverter);
@@ -1045,4 +1076,110 @@ describe('withConverter() support', () => {
10451076
expect(refEqual(docRef, docRef2)).to.be.false;
10461077
});
10471078
});
1079+
1080+
it('requires the correct converter for Partial usage', async () => {
1081+
return withTestDb(async db => {
1082+
const coll = collection(db, 'posts');
1083+
const ref = doc(coll, 'post').withConverter(postConverter);
1084+
const batch = writeBatch(db);
1085+
expect(() =>
1086+
batch.set(ref, { title: 'olive' }, { merge: true })
1087+
).to.throw(
1088+
'Function WriteBatch.set() called with invalid data. Unsupported ' +
1089+
'field value: undefined (found in field author in document posts/post)'
1090+
);
1091+
});
1092+
});
1093+
1094+
it('WriteBatch.set() supports partials with merge', async () => {
1095+
return withTestDb(async db => {
1096+
const coll = collection(db, 'posts');
1097+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1098+
await setDoc(ref, new Post('walnut', 'author'));
1099+
const batch = writeBatch(db);
1100+
batch.set(ref, { title: 'olive' }, { merge: true });
1101+
await batch.commit();
1102+
const postDoc = await getDoc(ref);
1103+
expect(postDoc.get('title')).to.equal('olive');
1104+
expect(postDoc.get('author')).to.equal('author');
1105+
});
1106+
});
1107+
1108+
it('WriteBatch.set() supports partials with mergeFields', async () => {
1109+
return withTestDb(async db => {
1110+
const coll = collection(db, 'posts');
1111+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1112+
await setDoc(ref, new Post('walnut', 'author'));
1113+
const batch = writeBatch(db);
1114+
batch.set(ref, { title: 'olive' }, { merge: true });
1115+
await batch.commit();
1116+
const postDoc = await getDoc(ref);
1117+
expect(postDoc.get('title')).to.equal('olive');
1118+
expect(postDoc.get('author')).to.equal('author');
1119+
});
1120+
});
1121+
1122+
it('Transaction.set() supports partials with merge', async () => {
1123+
return withTestDb(async db => {
1124+
const coll = collection(db, 'posts');
1125+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1126+
await setDoc(ref, new Post('walnut', 'author'));
1127+
await runTransaction(db, async tx => {
1128+
tx.set(
1129+
ref,
1130+
{ title: 'olive', author: 'person' },
1131+
{ mergeFields: ['title'] }
1132+
);
1133+
});
1134+
const postDoc = await getDoc(ref);
1135+
expect(postDoc.get('title')).to.equal('olive');
1136+
expect(postDoc.get('author')).to.equal('author');
1137+
});
1138+
});
1139+
1140+
it('Transaction.set() supports partials with mergeFields', async () => {
1141+
return withTestDb(async db => {
1142+
const coll = collection(db, 'posts');
1143+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1144+
await setDoc(ref, new Post('walnut', 'author'));
1145+
await runTransaction(db, async tx => {
1146+
tx.set(
1147+
ref,
1148+
{ title: 'olive', author: 'person' },
1149+
{ mergeFields: ['title'] }
1150+
);
1151+
});
1152+
const postDoc = await getDoc(ref);
1153+
expect(postDoc.get('title')).to.equal('olive');
1154+
expect(postDoc.get('author')).to.equal('author');
1155+
});
1156+
});
1157+
1158+
it('DocumentReference.set() supports partials with merge', async () => {
1159+
return withTestDb(async db => {
1160+
const coll = collection(db, 'posts');
1161+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1162+
await setDoc(ref, new Post('walnut', 'author'));
1163+
await setDoc(ref, { title: 'olive' }, { merge: true });
1164+
const postDoc = await getDoc(ref);
1165+
expect(postDoc.get('title')).to.equal('olive');
1166+
expect(postDoc.get('author')).to.equal('author');
1167+
});
1168+
});
1169+
1170+
it('DocumentReference.set() supports partials with mergeFields', async () => {
1171+
return withTestDb(async db => {
1172+
const coll = collection(db, 'posts');
1173+
const ref = doc(coll, 'post').withConverter(postConverterMerge);
1174+
await setDoc(ref, new Post('walnut', 'author'));
1175+
await setDoc(
1176+
ref,
1177+
{ title: 'olive', author: 'writer' },
1178+
{ mergeFields: ['title'] }
1179+
);
1180+
const postDoc = await getDoc(ref);
1181+
expect(postDoc.get('title')).to.equal('olive');
1182+
expect(postDoc.get('author')).to.equal('author');
1183+
});
1184+
});
10481185
});

packages/firestore/src/api/user_data_reader.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ const RESERVED_FIELD_REGEX = /^__.*__$/;
5858
*/
5959
export interface UntypedFirestoreDataConverter<T> {
6060
toFirestore(modelObject: T): firestore.DocumentData;
61+
toFirestore(
62+
modelObject: Partial<T>,
63+
options: firestore.SetOptions
64+
): firestore.DocumentData;
6165
fromFirestore(snapshot: unknown, options?: unknown): T;
6266
}
6367

0 commit comments

Comments
 (0)