@@ -84,8 +84,14 @@ export class FieldTransform {
84
84
export class MutationResult {
85
85
constructor (
86
86
/**
87
- * The version at which the mutation was committed, either extracted from
88
- * the mutation's updateTime or from the backend commit time (for deletes).
87
+ * The version at which the mutation was committed:
88
+ *
89
+ * - For most operations, this is the updateTime in the WriteResult.
90
+ * - For deletes, the commitTime of the WriteResponse (because deletes are
91
+ * not stored and have no updateTime).
92
+ *
93
+ * Note that these versions can be different: No-op writes will not change
94
+ * the updateTime even though the commitTime advances.
89
95
*/
90
96
readonly version : SnapshotVersion ,
91
97
/**
@@ -174,8 +180,10 @@ export class Precondition {
174
180
* create, replace, delete, and update subsets of documents.
175
181
*
176
182
* Mutations not only act on the value of the document but also it version.
177
- * In the case of Set, Patch, and Transform mutations we preserve the existing
178
- * version. In the case of Delete mutations, we reset the version to 0.
183
+ *
184
+ * For local mutations (mutations that haven't been committed yet), we preserve
185
+ * the existing version for Set, Patch, and Transform mutations. For Delete
186
+ * mutations, we reset the version to 0.
179
187
*
180
188
* Here's the expected transition table.
181
189
*
@@ -194,6 +202,15 @@ export class Precondition {
194
202
* DeleteMutation NoDocument(v3) NoDocument(v0)
195
203
* DeleteMutation null NoDocument(v0)
196
204
*
205
+ * For acknowledged mutations, we use the updateTime of the WriteResponse as
206
+ * the resulting version for Set, Patch, and Transform mutations. As deletes
207
+ * have no explicit update time, we use the commitTime of the WriteResponse for
208
+ * Delete mutations.
209
+ *
210
+ * If due to precondition mismatches an acknowledged mutation can't be applied
211
+ * locally, we return an `UnknownDocument` and rely on Watch to send us the
212
+ * updated version.
213
+ *
197
214
* Note that TransformMutations don't create Documents (in the case of being
198
215
* applied to a NoDocument), even though they would on the backend. This is
199
216
* because the client always combines the TransformMutation with a SetMutation
@@ -214,8 +231,9 @@ export abstract class Mutation {
214
231
215
232
/**
216
233
* Applies this mutation to the given MaybeDocument or null for the purposes
217
- * of computing a new remote document. Both the input and returned documents
218
- * can be null.
234
+ * of computing a new remote document. If the input document doesn't match the
235
+ * expected state (e.g. it is null or outdated), an `UnknownDocument` can be
236
+ * returned.
219
237
*
220
238
* @param maybeDoc The document to mutate. The input document can be null if
221
239
* the client has no knowledge of the pre-mutation state of the document.
@@ -376,13 +394,11 @@ export class PatchMutation extends Mutation {
376
394
'Transform results received by PatchMutation.'
377
395
) ;
378
396
379
- // TODO(mcg): Relax enforcement of this precondition
380
- //
381
- // We shouldn't actually enforce the precondition since it already passed on
382
- // the backend, but we may not have a local version of the document to
383
- // patch, so we use the precondition to prevent incorrectly putting a
384
- // partial document into our cache.
385
397
if ( ! this . precondition . isValidFor ( maybeDoc ) ) {
398
+ // Since the mutation was not rejected, we know that the precondition
399
+ // matched on the backend. We therefore must not have the expected version
400
+ // of the document in our cache and return an UnknownDocument with the
401
+ // known updateTime.
386
402
return new UnknownDocument ( this . key , mutationResult . version ) ;
387
403
}
388
404
@@ -482,13 +498,11 @@ export class TransformMutation extends Mutation {
482
498
'Transform results missing for TransformMutation.'
483
499
) ;
484
500
485
- // TODO(mcg): Relax enforcement of this precondition
486
- //
487
- // We shouldn't actually enforce the precondition since it already passed on
488
- // the backend, but we may not have a local version of the document to
489
- // patch, so we use the precondition to prevent incorrectly putting a
490
- // partial document into our cache.
491
501
if ( ! this . precondition . isValidFor ( maybeDoc ) ) {
502
+ // Since the mutation was not rejected, we know that the precondition
503
+ // matched on the backend. We therefore must not have the expected version
504
+ // of the document in our cache and return an UnknownDocument with the
505
+ // known updateTime.
492
506
return new UnknownDocument ( this . key , mutationResult . version ) ;
493
507
}
494
508
0 commit comments