Skip to content

Commit 6cd5ed1

Browse files
Add WriteBatch (#3152)
1 parent 5cf39ab commit 6cd5ed1

File tree

5 files changed

+364
-79
lines changed

5 files changed

+364
-79
lines changed

packages/firestore/lite/index.d.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,11 @@ export class Transaction {
140140

141141
get<T>(documentRef: DocumentReference<T>): Promise<DocumentSnapshot<T>>;
142142

143+
set<T>(documentRef: DocumentReference<T>, data: T): Transaction;
143144
set<T>(
144145
documentRef: DocumentReference<T>,
145-
data: T,
146-
options?: SetOptions
146+
data: Partial<T>,
147+
options: SetOptions
147148
): Transaction;
148149

149150
update(documentRef: DocumentReference<any>, data: UpdateData): Transaction;
@@ -160,10 +161,11 @@ export class Transaction {
160161
export class WriteBatch {
161162
private constructor();
162163

164+
set<T>(documentRef: DocumentReference<T>, data: T): WriteBatch;
163165
set<T>(
164166
documentRef: DocumentReference<T>,
165-
data: T,
166-
options?: SetOptions
167+
data: Partial<T>,
168+
options: SetOptions
167169
): WriteBatch;
168170

169171
update(documentRef: DocumentReference<any>, data: UpdateData): WriteBatch;

packages/firestore/lite/index.node.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ export {
5858

5959
export { DocumentSnapshot, QueryDocumentSnapshot } from './src/api/snapshot';
6060

61+
export { WriteBatch, writeBatch } from './src/api/write_batch';
62+
6163
export { setLogLevel } from '../src/util/log';
6264

6365
export function registerFirestore(): void {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,17 +318,17 @@ export function setDoc<T>(
318318
}
319319

320320
export function updateDoc(
321-
reference: firestore.DocumentReference,
321+
reference: firestore.DocumentReference<unknown>,
322322
data: firestore.UpdateData
323323
): Promise<void>;
324324
export function updateDoc(
325-
reference: firestore.DocumentReference,
325+
reference: firestore.DocumentReference<unknown>,
326326
field: string | firestore.FieldPath,
327327
value: unknown,
328328
...moreFieldsAndValues: unknown[]
329329
): Promise<void>;
330330
export function updateDoc(
331-
reference: firestore.DocumentReference,
331+
reference: firestore.DocumentReference<unknown>,
332332
fieldOrUpdateData: string | firestore.FieldPath | firestore.UpdateData,
333333
value?: unknown,
334334
...moreFieldsAndValues: unknown[]
@@ -418,7 +418,7 @@ export function addDoc<T>(
418418
.then(() => docRef);
419419
}
420420

421-
function newUserDataReader(
421+
export function newUserDataReader(
422422
databaseId: DatabaseId,
423423
settings: firestore.Settings
424424
): UserDataReader {
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import * as firestore from '../../index';
19+
import {
20+
DeleteMutation,
21+
Mutation,
22+
Precondition
23+
} from '../../../src/model/mutation';
24+
import { Code, FirestoreError } from '../../../src/util/error';
25+
import { applyFirestoreDataConverter } from '../../../src/api/database';
26+
import {
27+
DocumentKeyReference,
28+
UserDataReader
29+
} from '../../../src/api/user_data_reader';
30+
import { cast } from './util';
31+
import { DocumentReference, newUserDataReader } from './reference';
32+
import { Firestore } from './database';
33+
import { invokeCommitRpc } from '../../../src/remote/datastore';
34+
import { FieldPath } from './field_path';
35+
36+
export class WriteBatch implements firestore.WriteBatch {
37+
// This is the lite version of the WriteBatch API used in the legacy SDK. The
38+
// class is a close copy but takes different input types.
39+
40+
private _mutations = [] as Mutation[];
41+
private _committed = false;
42+
private _dataReader: UserDataReader;
43+
44+
constructor(private _firestore: Firestore) {
45+
// Kick off configuring the client, which freezes the settings.
46+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
47+
_firestore._ensureClientConfigured();
48+
this._dataReader = newUserDataReader(
49+
_firestore._databaseId,
50+
_firestore._settings!
51+
);
52+
}
53+
54+
set<T>(documentRef: firestore.DocumentReference<T>, value: T): WriteBatch;
55+
set<T>(
56+
documentRef: firestore.DocumentReference<T>,
57+
value: Partial<T>,
58+
options: firestore.SetOptions
59+
): WriteBatch;
60+
set<T>(
61+
documentRef: firestore.DocumentReference<T>,
62+
value: T,
63+
options?: firestore.SetOptions
64+
): WriteBatch {
65+
this.verifyNotCommitted();
66+
const ref = validateReference(documentRef, this._firestore);
67+
68+
const [convertedValue] = applyFirestoreDataConverter(
69+
ref._converter,
70+
value,
71+
'WriteBatch.set'
72+
);
73+
74+
const parsed = this._dataReader.parseSetData(
75+
'WriteBatch.set',
76+
convertedValue,
77+
options
78+
);
79+
this._mutations = this._mutations.concat(
80+
parsed.toMutations(ref._key, Precondition.none())
81+
);
82+
return this;
83+
}
84+
85+
update(
86+
documentRef: firestore.DocumentReference<unknown>,
87+
value: firestore.UpdateData
88+
): WriteBatch;
89+
update(
90+
documentRef: firestore.DocumentReference<unknown>,
91+
field: string | firestore.FieldPath,
92+
value: unknown,
93+
...moreFieldsAndValues: unknown[]
94+
): WriteBatch;
95+
update(
96+
documentRef: firestore.DocumentReference<unknown>,
97+
fieldOrUpdateData: string | firestore.FieldPath | firestore.UpdateData,
98+
value?: unknown,
99+
...moreFieldsAndValues: unknown[]
100+
): WriteBatch {
101+
this.verifyNotCommitted();
102+
const ref = validateReference(documentRef, this._firestore);
103+
104+
let parsed;
105+
106+
if (
107+
typeof fieldOrUpdateData === 'string' ||
108+
fieldOrUpdateData instanceof FieldPath
109+
) {
110+
parsed = this._dataReader.parseUpdateVarargs(
111+
'WriteBatch.update',
112+
fieldOrUpdateData,
113+
value,
114+
moreFieldsAndValues
115+
);
116+
} else {
117+
parsed = this._dataReader.parseUpdateData(
118+
'WriteBatch.update',
119+
fieldOrUpdateData
120+
);
121+
}
122+
123+
this._mutations = this._mutations.concat(
124+
parsed.toMutations(ref._key, Precondition.exists(true))
125+
);
126+
return this;
127+
}
128+
129+
delete(documentRef: firestore.DocumentReference<unknown>): WriteBatch {
130+
this.verifyNotCommitted();
131+
const ref = validateReference(documentRef, this._firestore);
132+
this._mutations = this._mutations.concat(
133+
new DeleteMutation(ref._key, Precondition.none())
134+
);
135+
return this;
136+
}
137+
138+
commit(): Promise<void> {
139+
this.verifyNotCommitted();
140+
this._committed = true;
141+
if (this._mutations.length > 0) {
142+
return this._firestore
143+
._ensureClientConfigured()
144+
.then(datastore => invokeCommitRpc(datastore, this._mutations));
145+
}
146+
147+
return Promise.resolve();
148+
}
149+
150+
private verifyNotCommitted(): void {
151+
if (this._committed) {
152+
throw new FirestoreError(
153+
Code.FAILED_PRECONDITION,
154+
'A write batch can no longer be used after commit() ' +
155+
'has been called.'
156+
);
157+
}
158+
}
159+
}
160+
161+
export function validateReference<T>(
162+
documentRef: firestore.DocumentReference<T>,
163+
firestore: Firestore
164+
): DocumentKeyReference<T> {
165+
if (documentRef.firestore !== firestore) {
166+
throw new FirestoreError(
167+
Code.INVALID_ARGUMENT,
168+
'Provided document reference is from a different Firestore instance.'
169+
);
170+
} else {
171+
return cast(documentRef, DocumentReference) as DocumentReference<T>;
172+
}
173+
}
174+
175+
export function writeBatch(
176+
firestore: firestore.FirebaseFirestore
177+
): firestore.WriteBatch {
178+
return new WriteBatch(cast(firestore, Firestore));
179+
}

0 commit comments

Comments
 (0)