Skip to content

Commit a5b06da

Browse files
committed
getBaseDocument should always get results from remoteDocumentCache.
1 parent fcac75d commit a5b06da

File tree

2 files changed

+204
-60
lines changed

2 files changed

+204
-60
lines changed

packages/firestore/src/local/local_documents_view.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class LocalDocumentsView {
9191
.getOverlay(transaction, key)
9292
.next(value => {
9393
overlay = value;
94-
return this.getBaseDocument(transaction, key, overlay);
94+
return this.remoteDocumentCache.getEntry(transaction, key);
9595
})
9696
.next(document => {
9797
if (overlay !== null) {
@@ -423,11 +423,11 @@ export class LocalDocumentsView {
423423
if (originalDocs.get(key)) {
424424
return PersistencePromise.resolve();
425425
}
426-
return this.getBaseDocument(transaction, key, overlay).next(
427-
doc => {
426+
return this.remoteDocumentCache
427+
.getEntry(transaction, key)
428+
.next(doc => {
428429
modifiedDocs = modifiedDocs.insert(key, doc);
429-
}
430-
);
430+
});
431431
}
432432
)
433433
.next(() =>
@@ -549,17 +549,4 @@ export class LocalDocumentsView {
549549
return results;
550550
});
551551
}
552-
553-
/** Returns a base document that can be used to apply `overlay`. */
554-
private getBaseDocument(
555-
transaction: PersistenceTransaction,
556-
key: DocumentKey,
557-
overlay: Overlay | null
558-
): PersistencePromise<MutableDocument> {
559-
return this.remoteDocumentCache.getEntry(transaction, key);
560-
// TODO(COUNT): ROI of this is pretty low and it could be quite confusing.
561-
// return overlay === null || overlay.mutation.type === MutationType.Patch
562-
// ? this.remoteDocumentCache.getEntry(transaction, key)
563-
// : PersistencePromise.resolve(MutableDocument.newInvalidDocument(key));
564-
}
565552
}

packages/firestore/test/unit/local/local_store.test.ts

Lines changed: 199 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,10 @@ class LocalStoreTester {
398398
return this;
399399
}
400400

401-
toReturnChanged(...docs: Document[]): LocalStoreTester {
401+
toReturnChangedInternal(
402+
docs: Document[],
403+
isEqual?: (lhs: Document | null, rhs: Document | null) => boolean
404+
): LocalStoreTester {
402405
this.promiseChain = this.promiseChain.then(() => {
403406
debugAssert(
404407
this.lastChanges !== null,
@@ -407,13 +410,29 @@ class LocalStoreTester {
407410
expect(this.lastChanges.size).to.equal(docs.length, 'number of changes');
408411
for (const doc of docs) {
409412
const returned = this.lastChanges.get(doc.key);
410-
expectEqual(doc, returned, `Expected '${returned}' to equal '${doc}'.`);
413+
const message = `Expected '${returned}' to equal '${doc}'.`;
414+
if (isEqual) {
415+
expect(isEqual(doc, returned)).to.equal(true, message);
416+
} else {
417+
expectEqual(doc, returned, message);
418+
}
411419
}
412420
this.lastChanges = null;
413421
});
414422
return this;
415423
}
416424

425+
toReturnChanged(...docs: Document[]): LocalStoreTester {
426+
return this.toReturnChangedInternal(docs);
427+
}
428+
429+
toReturnChangedWithDocComparator(
430+
isEqual: (lhs: Document | null, rhs: Document | null) => boolean,
431+
...docs: Document[]
432+
): LocalStoreTester {
433+
return this.toReturnChangedInternal(docs, isEqual);
434+
}
435+
417436
toReturnRemoved(...keyStrings: string[]): LocalStoreTester {
418437
this.promiseChain = this.promiseChain.then(() => {
419438
debugAssert(
@@ -433,16 +452,20 @@ class LocalStoreTester {
433452
return this;
434453
}
435454

436-
toContain(doc: Document): LocalStoreTester {
455+
toContain(
456+
doc: Document,
457+
isEqual?: (lhs: Document, rhs: Document) => boolean
458+
): LocalStoreTester {
437459
this.promiseChain = this.promiseChain.then(() => {
438460
return localStoreReadDocument(this.localStore, doc.key).then(result => {
439-
expectEqual(
440-
result,
441-
doc,
442-
`Expected ${
443-
result ? result.toString() : null
444-
} to match ${doc.toString()}.`
445-
);
461+
const message = `Expected ${
462+
result ? result.toString() : null
463+
} to match ${doc.toString()}.`;
464+
if (isEqual) {
465+
expect(isEqual(result, doc)).to.equal(true, message);
466+
} else {
467+
expectEqual(result, doc, message);
468+
}
446469
});
447470
});
448471
return this;
@@ -539,22 +562,38 @@ class LocalStoreTester {
539562
}
540563
}
541564

542-
describe('LocalStore w/ Memory Persistence', () => {
543-
async function initialize(): Promise<LocalStoreComponents> {
544-
const queryEngine = new CountingQueryEngine();
545-
const persistence = await persistenceHelpers.testMemoryEagerPersistence();
546-
const localStore = newLocalStore(
547-
persistence,
548-
queryEngine,
549-
User.UNAUTHENTICATED,
550-
JSON_SERIALIZER
551-
);
552-
return { queryEngine, persistence, localStore };
553-
}
565+
// The `isEqual` method for the Document class does not compare createTime and
566+
// readTime. For some tests, we'd like to verify that a certain createTime has
567+
// been calculated for documents. In such cases we can use this comparator.
568+
function compareDocsWithCreateTime(
569+
lhs: Document | null,
570+
rhs: Document | null
571+
): boolean {
572+
return (
573+
(lhs === null && rhs === null) ||
574+
(lhs !== null &&
575+
rhs !== null &&
576+
lhs.isEqual(rhs) &&
577+
lhs.createTime.isEqual(rhs.createTime))
578+
);
579+
}
554580

555-
addEqualityMatcher();
556-
genericLocalStoreTests(initialize, /* gcIsEager= */ true);
557-
});
581+
// describe('LocalStore w/ Memory Persistence', () => {
582+
// async function initialize(): Promise<LocalStoreComponents> {
583+
// const queryEngine = new CountingQueryEngine();
584+
// const persistence = await persistenceHelpers.testMemoryEagerPersistence();
585+
// const localStore = newLocalStore(
586+
// persistence,
587+
// queryEngine,
588+
// User.UNAUTHENTICATED,
589+
// JSON_SERIALIZER
590+
// );
591+
// return { queryEngine, persistence, localStore };
592+
// }
593+
//
594+
// addEqualityMatcher();
595+
// genericLocalStoreTests(initialize, /* gcIsEager= */ true);
596+
// });
558597

559598
describe('LocalStore w/ IndexedDB Persistence', () => {
560599
if (!IndexedDbPersistence.isAvailable()) {
@@ -1964,28 +2003,58 @@ function genericLocalStoreTests(
19642003
.afterAllocatingQuery(query('col'))
19652004
.toReturnTargetId(2)
19662005
.after(docAddedRemoteEvent(doc('col/doc1', 12, { foo: 'bar' }, 5), [2]))
1967-
.toReturnChanged(doc('col/doc1', 12, { foo: 'bar' }, 5))
1968-
.toContain(doc('col/doc1', 12, { foo: 'bar' }, 5))
2006+
.toReturnChangedWithDocComparator(
2007+
compareDocsWithCreateTime,
2008+
doc('col/doc1', 12, { foo: 'bar' }, 5)
2009+
)
2010+
.toContain(
2011+
doc('col/doc1', 12, { foo: 'bar' }, 5),
2012+
compareDocsWithCreateTime
2013+
)
19692014
.after(setMutation('col/doc1', { foo: 'newBar' }))
1970-
.toReturnChanged(
2015+
.toReturnChangedWithDocComparator(
2016+
compareDocsWithCreateTime,
19712017
doc('col/doc1', 12, { foo: 'newBar' }, 5).setHasLocalMutations()
19722018
)
19732019
.toContain(
1974-
doc('col/doc1', 12, { foo: 'newBar' }, 5).setHasLocalMutations()
2020+
doc('col/doc1', 12, { foo: 'newBar' }, 5).setHasLocalMutations(),
2021+
compareDocsWithCreateTime
19752022
)
19762023
.afterAcknowledgingMutation({ documentVersion: 13 })
19772024
// We haven't seen the remote event yet
1978-
.toReturnChanged(
2025+
.toReturnChangedWithDocComparator(
2026+
compareDocsWithCreateTime,
19792027
doc('col/doc1', 13, { foo: 'newBar' }, 5).setHasCommittedMutations()
19802028
)
19812029
.toContain(
1982-
doc('col/doc1', 13, { foo: 'newBar' }, 5).setHasCommittedMutations()
2030+
doc('col/doc1', 13, { foo: 'newBar' }, 5).setHasCommittedMutations(),
2031+
compareDocsWithCreateTime
19832032
)
19842033
.finish()
19852034
);
19862035
});
19872036

1988-
it('saves updateTime as createTime when creating new doc', () => {
2037+
it('saves updateTime as createTime when receives ack for creating a new doc', () => {
2038+
if (gcIsEager) {
2039+
return;
2040+
}
2041+
2042+
return expectLocalStore()
2043+
.after(setMutation('col/doc1', { foo: 'newBar' }))
2044+
.afterAcknowledgingMutation({ documentVersion: 13 })
2045+
.afterExecutingQuery(query('col'))
2046+
.toReturnChangedWithDocComparator(
2047+
compareDocsWithCreateTime,
2048+
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations()
2049+
)
2050+
.toContain(
2051+
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations(),
2052+
compareDocsWithCreateTime
2053+
)
2054+
.finish();
2055+
});
2056+
2057+
it('saves updateTime as createTime when recreating a deleted doc', async () => {
19892058
if (gcIsEager) {
19902059
return;
19912060
}
@@ -1998,28 +2067,29 @@ function genericLocalStoreTests(
19982067
.toReturnChanged(deletedDoc('col/doc1', 12))
19992068
.toContain(deletedDoc('col/doc1', 12))
20002069
.after(setMutation('col/doc1', { foo: 'newBar' }))
2001-
.toReturnChanged(
2070+
.toReturnChangedWithDocComparator(
2071+
compareDocsWithCreateTime,
20022072
doc('col/doc1', 12, { foo: 'newBar' }, 12).setHasLocalMutations()
20032073
)
2004-
// TODO(COUNT): Below has createTime=0 due to an optimization that uses invalid doc as base doc for
2005-
// set mutations. This is OK because it has no impact on aggregation's heuristic logic. But it feels
2006-
// "wrong" to have createTime 0 here. We should revisit this.
20072074
.toContain(
2008-
doc('col/doc1', 12, { foo: 'newBar' }, 0).setHasLocalMutations()
2075+
doc('col/doc1', 12, { foo: 'newBar' }, 12).setHasLocalMutations(),
2076+
compareDocsWithCreateTime
20092077
)
20102078
.afterAcknowledgingMutation({ documentVersion: 13 })
20112079
// We haven't seen the remote event yet
2012-
.toReturnChanged(
2080+
.toReturnChangedWithDocComparator(
2081+
compareDocsWithCreateTime,
20132082
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations()
20142083
)
20152084
.toContain(
2016-
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations()
2085+
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations(),
2086+
compareDocsWithCreateTime
20172087
)
20182088
.finish()
20192089
);
20202090
});
20212091

2022-
it('saves updateTime as createTime when creating new doc', () => {
2092+
it('document createTime is preserved through Set -> Ack -> Patch -> Ack', () => {
20232093
if (gcIsEager) {
20242094
return;
20252095
}
@@ -2028,11 +2098,98 @@ function genericLocalStoreTests(
20282098
.after(setMutation('col/doc1', { foo: 'newBar' }))
20292099
.afterAcknowledgingMutation({ documentVersion: 13 })
20302100
.afterExecutingQuery(query('col'))
2031-
.toReturnChanged(
2101+
.toReturnChangedWithDocComparator(
2102+
compareDocsWithCreateTime,
20322103
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations()
20332104
)
20342105
.toContain(
2035-
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations()
2106+
doc('col/doc1', 13, { foo: 'newBar' }, 13).setHasCommittedMutations(),
2107+
compareDocsWithCreateTime
2108+
)
2109+
.afterMutations([patchMutation('col/doc1', { 'likes': 1 })])
2110+
.toReturnChangedWithDocComparator(
2111+
compareDocsWithCreateTime,
2112+
doc(
2113+
'col/doc1',
2114+
13,
2115+
{ foo: 'newBar', likes: 1 },
2116+
13
2117+
).setHasLocalMutations()
2118+
)
2119+
.toContain(
2120+
doc(
2121+
'col/doc1',
2122+
13,
2123+
{ foo: 'newBar', likes: 1 },
2124+
13
2125+
).setHasLocalMutations(),
2126+
compareDocsWithCreateTime
2127+
)
2128+
.afterAcknowledgingMutation({ documentVersion: 14 })
2129+
.toReturnChangedWithDocComparator(
2130+
compareDocsWithCreateTime,
2131+
doc(
2132+
'col/doc1',
2133+
14,
2134+
{ foo: 'newBar', likes: 1 },
2135+
13
2136+
).setHasCommittedMutations()
2137+
)
2138+
.toContain(
2139+
doc(
2140+
'col/doc1',
2141+
14,
2142+
{ foo: 'newBar', likes: 1 },
2143+
13
2144+
).setHasCommittedMutations(),
2145+
compareDocsWithCreateTime
2146+
)
2147+
.finish();
2148+
});
2149+
2150+
it('document createTime is preserved through Doc Added -> Patch -> Ack', () => {
2151+
if (gcIsEager) {
2152+
return;
2153+
}
2154+
return expectLocalStore()
2155+
.afterAllocatingQuery(query('col'))
2156+
.toReturnTargetId(2)
2157+
.after(docAddedRemoteEvent(doc('col/doc1', 12, { foo: 'bar' }, 5), [2]))
2158+
.toReturnChangedWithDocComparator(
2159+
compareDocsWithCreateTime,
2160+
doc('col/doc1', 12, { foo: 'bar' }, 5)
2161+
)
2162+
.toContain(
2163+
doc('col/doc1', 12, { foo: 'bar' }, 5),
2164+
compareDocsWithCreateTime
2165+
)
2166+
.afterMutations([patchMutation('col/doc1', { 'likes': 1 })])
2167+
.toReturnChangedWithDocComparator(
2168+
compareDocsWithCreateTime,
2169+
doc('col/doc1', 13, { foo: 'bar', likes: 1 }, 5).setHasLocalMutations()
2170+
)
2171+
.toContain(
2172+
doc('col/doc1', 13, { foo: 'bar', likes: 1 }, 5).setHasLocalMutations(),
2173+
compareDocsWithCreateTime
2174+
)
2175+
.afterAcknowledgingMutation({ documentVersion: 14 })
2176+
.toReturnChangedWithDocComparator(
2177+
compareDocsWithCreateTime,
2178+
doc(
2179+
'col/doc1',
2180+
14,
2181+
{ foo: 'bar', likes: 1 },
2182+
5
2183+
).setHasCommittedMutations()
2184+
)
2185+
.toContain(
2186+
doc(
2187+
'col/doc1',
2188+
14,
2189+
{ foo: 'bar', likes: 1 },
2190+
5
2191+
).setHasCommittedMutations(),
2192+
compareDocsWithCreateTime
20362193
)
20372194
.finish();
20382195
});

0 commit comments

Comments
 (0)