Skip to content

Commit 6ab2ba5

Browse files
committed
memory spec tests pass sans limitToLast
1 parent 48a6324 commit 6ab2ba5

13 files changed

+387
-185
lines changed

packages/firestore/src/core/pipeline-util.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ function canonifyExpr(expr: Expr): string {
349349
return `fld(${expr.fieldName()})`;
350350
}
351351
if (expr instanceof Constant) {
352-
return `cst(${expr.value})`;
352+
// TODO(pipeline): use better alternatives than JSON.stringify
353+
return `cst(${JSON.stringify(expr.value)})`;
353354
}
354355
if (expr instanceof FirestoreFunction) {
355356
return `fn(${expr.name},[${expr.params.map(canonifyExpr).join(',')}])`;

packages/firestore/src/core/sync_engine_impl.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -930,14 +930,6 @@ function removeAndCleanupTarget(
930930
): void {
931931
syncEngineImpl.sharedClientState.removeLocalQueryTarget(targetId);
932932

933-
// TODO(pipeline): REMOVE this hack.
934-
if (
935-
!syncEngineImpl.queriesByTarget.has(targetId) ||
936-
syncEngineImpl.queriesByTarget.get(targetId)!.length !== 0
937-
) {
938-
return;
939-
}
940-
941933
debugAssert(
942934
syncEngineImpl.queriesByTarget.has(targetId) &&
943935
syncEngineImpl.queriesByTarget.get(targetId)!.length !== 0,

packages/firestore/src/remote/watch_change.ts

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ import {
4545
import { BloomFilter, BloomFilterError } from './bloom_filter';
4646
import { ExistenceFilter } from './existence_filter';
4747
import { RemoteEvent, TargetChange } from './remote_event';
48+
import {
49+
getPipelineDocuments,
50+
getPipelineFlavor,
51+
getPipelineSourceType,
52+
isPipeline,
53+
TargetOrPipeline
54+
} from '../core/pipeline-util';
55+
import { Pipeline } from '../lite-api/pipeline';
56+
import { ResourcePath } from '../model/path';
4857

4958
/**
5059
* Internal representation of the watcher API protocol buffers.
@@ -405,6 +414,17 @@ export class WatchChangeAggregator {
405414
}
406415
}
407416

417+
isSingleDocumentTarget(target: TargetOrPipeline): boolean {
418+
if (targetIsPipelineTarget(target)) {
419+
return (
420+
getPipelineSourceType(target) === 'documents' &&
421+
getPipelineDocuments(target)?.length === 1
422+
);
423+
}
424+
425+
return targetIsDocumentTarget(target);
426+
}
427+
408428
/**
409429
* Handles existence filters and synthesizes deletes for filter mismatches.
410430
* Targets that are invalidated by filter mismatches are added to
@@ -417,29 +437,7 @@ export class WatchChangeAggregator {
417437
const targetData = this.targetDataForActiveTarget(targetId);
418438
if (targetData) {
419439
const target = targetData.target;
420-
if (targetIsPipelineTarget(target)) {
421-
//TODO(pipeline): handle existence filter correctly for pipelines
422-
} else if (targetIsDocumentTarget(target)) {
423-
if (expectedCount === 0) {
424-
// The existence filter told us the document does not exist. We deduce
425-
// that this document does not exist and apply a deleted document to
426-
// our updates. Without applying this deleted document there might be
427-
// another query that will raise this document as part of a snapshot
428-
// until it is resolved, essentially exposing inconsistency between
429-
// queries.
430-
const key = new DocumentKey(target.path);
431-
this.removeDocumentFromTarget(
432-
targetId,
433-
key,
434-
MutableDocument.newNoDocument(key, SnapshotVersion.min())
435-
);
436-
} else {
437-
hardAssert(
438-
expectedCount === 1,
439-
'Single document existence filter with count: ' + expectedCount
440-
);
441-
}
442-
} else {
440+
if (!this.isSingleDocumentTarget(target)) {
443441
const currentSize = this.getCurrentDocumentCountForTarget(targetId);
444442
// Existence filter mismatch. Mark the documents as being in limbo, and
445443
// raise a snapshot with `isFromCache:true`.
@@ -474,6 +472,30 @@ export class WatchChangeAggregator {
474472
)
475473
);
476474
}
475+
} else {
476+
if (expectedCount === 0) {
477+
// The existence filter told us the document does not exist. We deduce
478+
// that this document does not exist and apply a deleted document to
479+
// our updates. Without applying this deleted document there might be
480+
// another query that will raise this document as part of a snapshot
481+
// until it is resolved, essentially exposing inconsistency between
482+
// queries.
483+
const key = new DocumentKey(
484+
targetIsPipelineTarget(target)
485+
? ResourcePath.fromString(getPipelineDocuments(target)![0])
486+
: target.path
487+
);
488+
this.removeDocumentFromTarget(
489+
targetId,
490+
key,
491+
MutableDocument.newNoDocument(key, SnapshotVersion.min())
492+
);
493+
} else {
494+
hardAssert(
495+
expectedCount === 1,
496+
'Single document existence filter with count: ' + expectedCount
497+
);
498+
}
477499
}
478500
}
479501
}
@@ -591,8 +613,7 @@ export class WatchChangeAggregator {
591613
if (targetData) {
592614
if (
593615
targetState.current &&
594-
!targetIsPipelineTarget(targetData.target) &&
595-
targetIsDocumentTarget(targetData.target)
616+
this.isSingleDocumentTarget(targetData.target)
596617
) {
597618
// Document queries for document that don't exist can produce an empty
598619
// result set. To update our local cache, we synthesize a document
@@ -603,7 +624,12 @@ export class WatchChangeAggregator {
603624
// TODO(dimond): Ideally we would have an explicit lookup target
604625
// instead resulting in an explicit delete message and we could
605626
// remove this special logic.
606-
const key = new DocumentKey(targetData.target.path);
627+
const path = targetIsPipelineTarget(targetData.target)
628+
? ResourcePath.fromString(
629+
getPipelineDocuments(targetData.target)![0]
630+
)
631+
: targetData.target.path;
632+
const key = new DocumentKey(path);
607633
if (
608634
this.pendingDocumentUpdates.get(key) === null &&
609635
!this.targetContainsDocument(targetId, key)
@@ -695,7 +721,12 @@ export class WatchChangeAggregator {
695721
targetState.addDocumentChange(document.key, changeType);
696722

697723
if (
698-
targetIsPipelineTarget(this.targetDataForActiveTarget(targetId)!.target)
724+
targetIsPipelineTarget(
725+
this.targetDataForActiveTarget(targetId)!.target
726+
) &&
727+
getPipelineFlavor(
728+
this.targetDataForActiveTarget(targetId)!.target as Pipeline
729+
) !== 'exact'
699730
) {
700731
this.pendingAugmentedDocumentUpdates =
701732
this.pendingAugmentedDocumentUpdates.insert(document.key, document);
@@ -747,7 +778,12 @@ export class WatchChangeAggregator {
747778

748779
if (updatedDocument) {
749780
if (
750-
targetIsPipelineTarget(this.targetDataForActiveTarget(targetId)!.target)
781+
targetIsPipelineTarget(
782+
this.targetDataForActiveTarget(targetId)!.target
783+
) &&
784+
getPipelineFlavor(
785+
this.targetDataForActiveTarget(targetId)!.target as Pipeline
786+
) !== 'exact'
751787
) {
752788
this.pendingAugmentedDocumentUpdates =
753789
this.pendingAugmentedDocumentUpdates.insert(key, updatedDocument);

packages/firestore/test/unit/core/pipeline.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ describe('pipelineEq', () => {
199199
});
200200
});
201201

202-
describe.only('runPipeline()', () => {
202+
describe('runPipeline()', () => {
203203
it('works with collection stage', () => {
204204
const p = db.pipeline().collection('test');
205205

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ function compareDocsWithCreateTime(
596596
);
597597
}
598598

599-
describe.only('LocalStore w/ Memory Persistence', () => {
599+
describe('LocalStore w/ Memory Persistence', () => {
600600
async function initialize(): Promise<LocalStoreComponents> {
601601
const queryEngine = new CountingQueryEngine();
602602
const persistence = await persistenceHelpers.testMemoryEagerPersistence();
@@ -616,7 +616,7 @@ describe.only('LocalStore w/ Memory Persistence', () => {
616616
});
617617
});
618618

619-
describe.only('LocalStore w/ Memory Persistence and Pipelines', () => {
619+
describe('LocalStore w/ Memory Persistence and Pipelines', () => {
620620
async function initialize(): Promise<LocalStoreComponents> {
621621
const queryEngine = new CountingQueryEngine();
622622
const persistence = await persistenceHelpers.testMemoryEagerPersistence();
@@ -663,7 +663,7 @@ describe('LocalStore w/ IndexedDB Persistence', () => {
663663
});
664664
});
665665

666-
describe.only('LocalStore w/ IndexedDB Persistence and Pipeline', () => {
666+
describe('LocalStore w/ IndexedDB Persistence and Pipeline', () => {
667667
if (!IndexedDbPersistence.isAvailable()) {
668668
console.warn(
669669
'No IndexedDB. Skipping LocalStore w/ IndexedDB persistence tests.'
@@ -2507,7 +2507,7 @@ function genericLocalStoreTests(
25072507
});
25082508

25092509
// eslint-disable-next-line no-restricted-properties
2510-
(options.gcIsEager ? it.skip : it.only)(
2510+
(options.gcIsEager ? it.skip : it)(
25112511
'ignores target mapping after existence filter mismatch',
25122512
async () => {
25132513
const query1 = query('foo', filter('matches', '==', true));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class TestLocalDocumentsView extends LocalDocumentsView {
123123
}
124124
}
125125

126-
describe.only('QueryEngine', async () => {
126+
describe('QueryEngine', async () => {
127127
describe('MemoryEagerPersistence usePipeline=false', async () => {
128128
/* not durable and without client side indexing */
129129
genericQueryEngineTest(persistenceHelpers.testMemoryEagerPersistence, {

packages/firestore/test/unit/specs/bundle_spec.test.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { TestBundleBuilder } from '../util/bundle_data';
3636

3737
import { describeSpec, specTest } from './describe_spec';
3838
import { client, spec } from './spec_builder';
39+
import { setLogLevel } from '../../../src';
3940

4041
interface TestBundleDocument {
4142
key: DocumentKey;
@@ -285,32 +286,36 @@ describeSpec('Bundles:', [], () => {
285286
);
286287
});
287288

288-
specTest('Bundles query can be resumed from same query.', [], () => {
289-
const query1 = query('collection');
290-
const docA = doc('collection/a', 100, { key: 'a' });
291-
const bundleString1 = bundleWithDocumentAndQuery(
292-
{
293-
key: docA.key,
294-
readTime: 500,
295-
createTime: 250,
296-
updateTime: 500,
297-
content: { value: 'b' }
298-
},
299-
{ name: 'bundled-query', readTime: 400, query: query1 }
300-
);
289+
specTest(
290+
'Bundles query can be resumed from same query.',
291+
['no-pipeline-conversion'],
292+
() => {
293+
const query1 = query('collection');
294+
const docA = doc('collection/a', 100, { key: 'a' });
295+
const bundleString1 = bundleWithDocumentAndQuery(
296+
{
297+
key: docA.key,
298+
readTime: 500,
299+
createTime: 250,
300+
updateTime: 500,
301+
content: { value: 'b' }
302+
},
303+
{ name: 'bundled-query', readTime: 400, query: query1 }
304+
);
301305

302-
return spec()
303-
.loadBundle(bundleString1)
304-
.userListens(query1, { readTime: 400 })
305-
.expectEvents(query1, {
306-
added: [doc('collection/a', 500, { value: 'b' })],
307-
fromCache: true
308-
});
309-
});
306+
return spec()
307+
.loadBundle(bundleString1)
308+
.userListens(query1, { readTime: 400 })
309+
.expectEvents(query1, {
310+
added: [doc('collection/a', 500, { value: 'b' })],
311+
fromCache: true
312+
});
313+
}
314+
);
310315

311316
specTest(
312317
'Bundles query can be loaded and resumed from different tabs',
313-
['multi-client'],
318+
['multi-client', 'no-pipeline-conversion'],
314319
() => {
315320
const query1 = query('collection');
316321
const query2 = query('collection', filter('value', '==', 'c'));

0 commit comments

Comments
 (0)