Skip to content

Commit 649e7f3

Browse files
ehsannaswu-hui
andauthored
Add createTime to Document. (#6781)
* Add createTime to Document. * More createTime tests * All tests pass except for Bundles tests. * Don't use createTime in isEqual. * getBaseDocument should always get results from remoteDocumentCache. * Bring back tests. * Add test that checks createTime gets updated after remote event. * Add test for Set->RemoteEvent->Ack. * try higher timeout. Co-authored-by: Wu-Hui <wu.hui.github@gmail.com>
1 parent 3bd0316 commit 649e7f3

File tree

10 files changed

+383
-46
lines changed

10 files changed

+383
-46
lines changed

packages/firestore/src/local/local_documents_view.ts

+5-17
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import { FieldMask } from '../model/field_mask';
4646
import {
4747
calculateOverlayMutation,
4848
mutationApplyToLocalView,
49-
MutationType,
5049
PatchMutation
5150
} from '../model/mutation';
5251
import { Overlay } from '../model/overlay';
@@ -92,7 +91,7 @@ export class LocalDocumentsView {
9291
.getOverlay(transaction, key)
9392
.next(value => {
9493
overlay = value;
95-
return this.getBaseDocument(transaction, key, overlay);
94+
return this.remoteDocumentCache.getEntry(transaction, key);
9695
})
9796
.next(document => {
9897
if (overlay !== null) {
@@ -424,11 +423,11 @@ export class LocalDocumentsView {
424423
if (originalDocs.get(key)) {
425424
return PersistencePromise.resolve();
426425
}
427-
return this.getBaseDocument(transaction, key, overlay).next(
428-
doc => {
426+
return this.remoteDocumentCache
427+
.getEntry(transaction, key)
428+
.next(doc => {
429429
modifiedDocs = modifiedDocs.insert(key, doc);
430-
}
431-
);
430+
});
432431
}
433432
)
434433
.next(() =>
@@ -550,15 +549,4 @@ export class LocalDocumentsView {
550549
return results;
551550
});
552551
}
553-
554-
/** Returns a base document that can be used to apply `overlay`. */
555-
private getBaseDocument(
556-
transaction: PersistenceTransaction,
557-
key: DocumentKey,
558-
overlay: Overlay | null
559-
): PersistencePromise<MutableDocument> {
560-
return overlay === null || overlay.mutation.type === MutationType.Patch
561-
? this.remoteDocumentCache.getEntry(transaction, key)
562-
: PersistencePromise.resolve(MutableDocument.newInvalidDocument(key));
563-
}
564552
}

packages/firestore/src/model/document.ts

+35-8
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ export interface Document {
101101
*/
102102
readonly readTime: SnapshotVersion;
103103

104+
/**
105+
* The timestamp at which the document was created. This value increases
106+
* monotonically when a document is deleted then recreated. It can also be
107+
* compared to `createTime` of other documents and the `readTime` of a query.
108+
*/
109+
readonly createTime: SnapshotVersion;
110+
104111
/** The underlying data of this document or an empty value if no data exists. */
105112
readonly data: ObjectValue;
106113

@@ -163,6 +170,7 @@ export class MutableDocument implements Document {
163170
private documentType: DocumentType,
164171
public version: SnapshotVersion,
165172
public readTime: SnapshotVersion,
173+
public createTime: SnapshotVersion,
166174
public data: ObjectValue,
167175
private documentState: DocumentState
168176
) {}
@@ -175,8 +183,9 @@ export class MutableDocument implements Document {
175183
return new MutableDocument(
176184
documentKey,
177185
DocumentType.INVALID,
178-
SnapshotVersion.min(),
179-
SnapshotVersion.min(),
186+
/* version */ SnapshotVersion.min(),
187+
/* readTime */ SnapshotVersion.min(),
188+
/* createTime */ SnapshotVersion.min(),
180189
ObjectValue.empty(),
181190
DocumentState.SYNCED
182191
);
@@ -189,13 +198,15 @@ export class MutableDocument implements Document {
189198
static newFoundDocument(
190199
documentKey: DocumentKey,
191200
version: SnapshotVersion,
201+
createTime: SnapshotVersion,
192202
value: ObjectValue
193203
): MutableDocument {
194204
return new MutableDocument(
195205
documentKey,
196206
DocumentType.FOUND_DOCUMENT,
197-
version,
198-
SnapshotVersion.min(),
207+
/* version */ version,
208+
/* readTime */ SnapshotVersion.min(),
209+
/* createTime */ createTime,
199210
value,
200211
DocumentState.SYNCED
201212
);
@@ -209,8 +220,9 @@ export class MutableDocument implements Document {
209220
return new MutableDocument(
210221
documentKey,
211222
DocumentType.NO_DOCUMENT,
212-
version,
213-
SnapshotVersion.min(),
223+
/* version */ version,
224+
/* readTime */ SnapshotVersion.min(),
225+
/* createTime */ SnapshotVersion.min(),
214226
ObjectValue.empty(),
215227
DocumentState.SYNCED
216228
);
@@ -228,8 +240,9 @@ export class MutableDocument implements Document {
228240
return new MutableDocument(
229241
documentKey,
230242
DocumentType.UNKNOWN_DOCUMENT,
231-
version,
232-
SnapshotVersion.min(),
243+
/* version */ version,
244+
/* readTime */ SnapshotVersion.min(),
245+
/* createTime */ SnapshotVersion.min(),
233246
ObjectValue.empty(),
234247
DocumentState.HAS_COMMITTED_MUTATIONS
235248
);
@@ -243,6 +256,18 @@ export class MutableDocument implements Document {
243256
version: SnapshotVersion,
244257
value: ObjectValue
245258
): MutableDocument {
259+
// If a document is switching state from being an invalid or deleted
260+
// document to a valid (FOUND_DOCUMENT) document, either due to receiving an
261+
// update from Watch or due to applying a local set mutation on top
262+
// of a deleted document, our best guess about its createTime would be the
263+
// version at which the document transitioned to a FOUND_DOCUMENT.
264+
if (
265+
this.createTime.isEqual(SnapshotVersion.min()) &&
266+
(this.documentType === DocumentType.NO_DOCUMENT ||
267+
this.documentType === DocumentType.INVALID)
268+
) {
269+
this.createTime = version;
270+
}
246271
this.version = version;
247272
this.documentType = DocumentType.FOUND_DOCUMENT;
248273
this.data = value;
@@ -340,6 +365,7 @@ export class MutableDocument implements Document {
340365
this.documentType,
341366
this.version,
342367
this.readTime,
368+
this.createTime,
343369
this.data.clone(),
344370
this.documentState
345371
);
@@ -350,6 +376,7 @@ export class MutableDocument implements Document {
350376
`Document(${this.key}, ${this.version}, ${JSON.stringify(
351377
this.data.value
352378
)}, ` +
379+
`{createTime: ${this.createTime}}), ` +
353380
`{documentType: ${this.documentType}}), ` +
354381
`{documentState: ${this.documentState}})`
355382
);

packages/firestore/src/remote/serializer.ts

+27-4
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,8 @@ export function toDocument(
404404
return {
405405
name: toName(serializer, document.key),
406406
fields: document.data.value.mapValue.fields,
407-
updateTime: toTimestamp(serializer, document.version.toTimestamp())
407+
updateTime: toTimestamp(serializer, document.version.toTimestamp()),
408+
createTime: toTimestamp(serializer, document.createTime.toTimestamp())
408409
};
409410
}
410411

@@ -415,8 +416,19 @@ export function fromDocument(
415416
): MutableDocument {
416417
const key = fromName(serializer, document.name!);
417418
const version = fromVersion(document.updateTime!);
419+
// If we read a document from persistence that is missing createTime, it's due
420+
// to older SDK versions not storing this information. In such cases, we'll
421+
// set the createTime to zero. This can be removed in the long term.
422+
const createTime = document.createTime
423+
? fromVersion(document.createTime)
424+
: SnapshotVersion.min();
418425
const data = new ObjectValue({ mapValue: { fields: document.fields } });
419-
const result = MutableDocument.newFoundDocument(key, version, data);
426+
const result = MutableDocument.newFoundDocument(
427+
key,
428+
version,
429+
createTime,
430+
data
431+
);
420432
if (hasCommittedMutations) {
421433
result.setHasCommittedMutations();
422434
}
@@ -435,8 +447,11 @@ function fromFound(
435447
assertPresent(doc.found.updateTime, 'doc.found.updateTime');
436448
const key = fromName(serializer, doc.found.name);
437449
const version = fromVersion(doc.found.updateTime);
450+
const createTime = doc.found.createTime
451+
? fromVersion(doc.found.createTime)
452+
: SnapshotVersion.min();
438453
const data = new ObjectValue({ mapValue: { fields: doc.found.fields } });
439-
return MutableDocument.newFoundDocument(key, version, data);
454+
return MutableDocument.newFoundDocument(key, version, createTime, data);
440455
}
441456

442457
function fromMissing(
@@ -502,10 +517,18 @@ export function fromWatchChange(
502517
);
503518
const key = fromName(serializer, entityChange.document.name);
504519
const version = fromVersion(entityChange.document.updateTime);
520+
const createTime = entityChange.document.createTime
521+
? fromVersion(entityChange.document.createTime)
522+
: SnapshotVersion.min();
505523
const data = new ObjectValue({
506524
mapValue: { fields: entityChange.document.fields }
507525
});
508-
const doc = MutableDocument.newFoundDocument(key, version, data);
526+
const doc = MutableDocument.newFoundDocument(
527+
key,
528+
version,
529+
createTime,
530+
data
531+
);
509532
const updatedTargetIds = entityChange.targetIds || [];
510533
const removedTargetIds = entityChange.removedTargetIds || [];
511534
watchChange = new DocumentWatchChange(

0 commit comments

Comments
 (0)