Skip to content

Commit 2e5a8b3

Browse files
Comments
1 parent aa853da commit 2e5a8b3

File tree

3 files changed

+47
-26
lines changed

3 files changed

+47
-26
lines changed

packages/firestore/src/local/indexeddb_schema.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -426,17 +426,22 @@ export class DbNoDocument {
426426
}
427427

428428
/**
429-
* Represents a document that is know to exist but whose data is unknwon.
429+
* Represents a document that is known to exist but whose data is unknown.
430430
* Stored in IndexedDb as part of a DbRemoteDocument object.
431431
*/
432432
export class DbUnknownDocument {
433433
constructor(public path: string[], public readTime: DbTimestamp) {}
434434
}
435435

436436
/**
437-
* An object to be stored in the 'remoteDocuments' store in IndexedDb. It
438-
* represents either a cached document (if it exists) or a cached "no-document"
439-
* (if it is known to not exist).
437+
* An object to be stored in the 'remoteDocuments' store in IndexedDb.
438+
* It represents either:
439+
*
440+
* - A complete document.
441+
* - A "no document" representing a document that is known not to exist (at
442+
* some version).
443+
* - An "unknown document" representing a document that is known to exist (at
444+
* some version) but whose contents are unknown.
440445
*
441446
* Note: This is the persisted equivalent of a MaybeDocument and could perhaps
442447
* be made more general if necessary.
@@ -447,8 +452,8 @@ export class DbRemoteDocument {
447452
constructor(
448453
/**
449454
* Set to an instance of DbUnknownDocument if the data for a document is
450-
* not known, but it is known that a document exist at the specified version
451-
* (e.g. it had a successful update applied to it)
455+
* not known, but it is known that a document exists at the specified
456+
* version (e.g. it had a successful update applied to it)
452457
*/
453458
public unknownDocument: DbUnknownDocument | null | undefined,
454459
/**
@@ -464,8 +469,8 @@ export class DbRemoteDocument {
464469
/**
465470
* Documents that were written to the remote document store based on
466471
* a write acknowledgment are marked with `hasCommittedMutations`. These
467-
* documents are potentially inconsistent with the document's version on
468-
* the backend.
472+
* documents are potentially inconsistent with the backend's copy and use
473+
* the write's commit version as their document version.
469474
*/
470475
public hasCommittedMutations: boolean | undefined
471476
) {}

packages/firestore/src/model/document.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ export class NoDocument extends MaybeDocument {
128128
}
129129

130130
hasPendingWrites(): boolean {
131+
// We currently don't raise `hasPendingWrites` for deleted documents, even
132+
// if Watch hasn't caught up to the deleted version yet.
131133
return false;
132134
}
133135

packages/firestore/src/model/mutation.ts

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,14 @@ export class FieldTransform {
8484
export class MutationResult {
8585
constructor(
8686
/**
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.
8995
*/
9096
readonly version: SnapshotVersion,
9197
/**
@@ -174,8 +180,10 @@ export class Precondition {
174180
* create, replace, delete, and update subsets of documents.
175181
*
176182
* 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.
179187
*
180188
* Here's the expected transition table.
181189
*
@@ -194,6 +202,15 @@ export class Precondition {
194202
* DeleteMutation NoDocument(v3) NoDocument(v0)
195203
* DeleteMutation null NoDocument(v0)
196204
*
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+
*
197214
* Note that TransformMutations don't create Documents (in the case of being
198215
* applied to a NoDocument), even though they would on the backend. This is
199216
* because the client always combines the TransformMutation with a SetMutation
@@ -214,8 +231,9 @@ export abstract class Mutation {
214231

215232
/**
216233
* 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.
219237
*
220238
* @param maybeDoc The document to mutate. The input document can be null if
221239
* the client has no knowledge of the pre-mutation state of the document.
@@ -376,13 +394,11 @@ export class PatchMutation extends Mutation {
376394
'Transform results received by PatchMutation.'
377395
);
378396

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.
385397
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.
386402
return new UnknownDocument(this.key, mutationResult.version);
387403
}
388404

@@ -482,13 +498,11 @@ export class TransformMutation extends Mutation {
482498
'Transform results missing for TransformMutation.'
483499
);
484500

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.
491501
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.
492506
return new UnknownDocument(this.key, mutationResult.version);
493507
}
494508

0 commit comments

Comments
 (0)