From a2cc10468b4f2e5cf73ba6888baffeba5dcdb95f Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 11:10:20 -0400 Subject: [PATCH 01/13] port one test to local_store_indexeddb.test.ts --- .../test/unit/local/local_store.test.ts | 37 +----------- .../unit/local/local_store_indexeddb.test.ts | 57 ++++++++++++++++++- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 845e73a6efb..bd6fd2495bf 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2757,42 +2757,7 @@ function indexedDbLocalStoreTests( ); } - it('can auto-create indexes', () => { - const query_ = query('coll', filter('matches', '==', true)); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { matches: true }), [2], []) - ]) - // First time query runs without indexes. - // Based on current heuristic, collection document counts (5) > - // 2 * resultSize (2). - // Full matched index should be created. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterBackfillIndexes() - .afterRemoteEvent( - docAddedRemoteEvent(doc('coll/f', 20, { matches: true }), [2], []) - ) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 2, documentsByCollection: 1 }) - .toReturnChanged('coll/a', 'coll/e', 'coll/f') - .finish() - ); - }); - + // TODO(dconeybe) port this test next it('does not auto-create indexes for small collections', () => { const query_ = query('coll', filter('count', '>=', 3)); return ( diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 530ca40b5e4..28742cbefdb 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -36,8 +36,10 @@ import { localStoreApplyRemoteEventToLocalCache, localStoreConfigureFieldIndexes, localStoreExecuteQuery, + localStoreSetIndexAutoCreationEnabled, localStoreWriteLocally, - newLocalStore + newLocalStore, + TestingHooks as LocalStoreTestingHooks } from '../../../src/local/local_store_impl'; import { Persistence } from '../../../src/local/persistence'; import { DocumentMap } from '../../../src/model/collections'; @@ -126,6 +128,25 @@ class AsyncLocalStoreTester { this.lastChanges = result.changes; } + configureIndexAutoCreation(config: { + isEnabled?: boolean; + indexAutoCreationMinCollectionSize?: number; + relativeIndexReadCostPerDocument?: number; + }): void { + this.prepareNextStep(); + + if (config.isEnabled !== undefined) { + localStoreSetIndexAutoCreationEnabled( + this.localStore, + config.isEnabled + ); + } + LocalStoreTestingHooks.setIndexAutoCreationSettings( + this.localStore, + config + ); + } + async configureAndAssertFieldsIndexes( ...indexes: FieldIndex[] ): Promise { @@ -464,4 +485,38 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { }); test.assertQueryReturned('coll/a'); }); + + it('can auto-create indexes', async () => { + const query_ = query('coll', filter('matches', '==', true)); + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]) + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { matches: true }), [targetId])); + + // First time query runs without indexes. + // Based on current heuristic, collection document counts (5) > + // 2 * resultSize (2). + // Full matched index should be created. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.backfillIndexes(); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { matches: true }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(2, 1); + test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); + }); }); From ba0aa3bdca6d17d2b2600eb6774ff462321809c8 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 14:39:31 -0400 Subject: [PATCH 02/13] move does not auto-create indexes for small collections --- .../test/unit/local/local_store.test.ts | 31 ------------------- .../unit/local/local_store_indexeddb.test.ts | 31 ++++++++++++++++++- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index bd6fd2495bf..9831da806ae 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,37 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('does not auto-create indexes for small collections', () => { - const query_ = query('coll', filter('count', '>=', 3)); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [2], []) - ]) - // SDK will not create indexes since collection size is too small. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterBackfillIndexes() - .afterRemoteEvent( - docAddedRemoteEvent(doc('coll/f', 20, { count: 4 }), [2], []) - ) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 3 }) - .toReturnChanged('coll/a', 'coll/e', 'coll/f') - .finish() - ); - }); it('does not auto create indexes when index lookup is expensive', () => { const query_ = query('coll', filter('array', 'array-contains-any', [0, 7])); diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 28742cbefdb..a464057a3eb 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -486,7 +486,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a'); }); - it('can auto-create indexes', async () => { + it.only('can auto-create indexes', async () => { const query_ = query('coll', filter('matches', '==', true)); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -519,4 +519,33 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(2, 1); test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); + + it.only('does not auto-create indexes for small collections', async () => { + const query_ = query('coll', filter('count', '>=', 3)); + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [targetId])); + + // SDK will not create indexes since collection size is too small. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.backfillIndexes(); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { count: 4 }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 3); + test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); + }); + }); From 7063e1518f1417a2b9842a468f46c15546f5f89b Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 14:42:51 -0400 Subject: [PATCH 03/13] move does not auto create indexes when index lookup is expensive --- .../test/unit/local/local_store.test.ts | 38 ------------------- .../unit/local/local_store_indexeddb.test.ts | 30 +++++++++++++++ 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 9831da806ae..6e74ca8a3e7 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,44 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - - it('does not auto create indexes when index lookup is expensive', () => { - const query_ = query('coll', filter('array', 'array-contains-any', [0, 7])); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 5 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [2], []), - docAddedRemoteEvent( - doc('coll/d', 10, { array: [2, 10, 20] }), - [2], - [] - ), - docAddedRemoteEvent(doc('coll/e', 10, { array: [2, 0, 8] }), [2], []) - ]) - // SDK will not create indexes since relative read cost is too large. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterBackfillIndexes() - .afterRemoteEvent( - docAddedRemoteEvent(doc('coll/f', 20, { array: [0] }), [2], []) - ) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 3 }) - .toReturnChanged('coll/a', 'coll/e', 'coll/f') - .finish() - ); - }); - it('index auto creation works when backfiller runs halfway', () => { const query_ = query('coll', filter('matches', '==', 'foo')); return ( diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index a464057a3eb..8645e5c17fc 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -548,4 +548,34 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); + it.only('does not auto create indexes when index lookup is expensive', async () => { + const query_ = query('coll', filter('array', 'array-contains-any', [0, 7])); + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 5 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { array: [2, 10, 20] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { array: [2, 0, 8] }), [targetId])); + + // SDK will not create indexes since relative read cost is too large. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.backfillIndexes(); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { array: [0] }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 3); + test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); + }); + + }); From 3318e71ba5b2fb48a191fb1f23fe060c705b7e26 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 14:47:26 -0400 Subject: [PATCH 04/13] move index auto creation works when backfiller runs halfway --- .../test/unit/local/local_store.test.ts | 36 ---------------- .../unit/local/local_store_indexeddb.test.ts | 42 ++++++++++++++++--- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 6e74ca8a3e7..1ec22a9a6b8 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,42 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('index auto creation works when backfiller runs halfway', () => { - const query_ = query('coll', filter('matches', '==', 'foo')); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [2], []) - ]) - // First time query runs without indexes. - // Based on current heuristic, collection document counts (5) > - // 2 * resultSize (2). - // Full matched index should be created. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterBackfillIndexes({ maxDocumentsToProcess: 2 }) - .afterRemoteEvent( - docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo' }), [2], []) - ) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 1, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e', 'coll/f') - .finish() - ); - }); - it('index created by index auto creation exists after turn off auto creation', () => { const query_ = query('coll', filter('value', 'not-in', [3])); return ( diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 8645e5c17fc..91c23c6d5ba 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -204,8 +204,8 @@ class AsyncLocalStoreTester { } } - async backfillIndexes(): Promise { - await this.indexBackfiller.backfill(); + async backfillIndexes(config?: { maxDocumentsToProcess?: 2 }): Promise { + await this.indexBackfiller.backfill(config?.maxDocumentsToProcess); } } @@ -486,7 +486,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a'); }); - it.only('can auto-create indexes', async () => { + it('can auto-create indexes', async () => { const query_ = query('coll', filter('matches', '==', true)); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -520,7 +520,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); - it.only('does not auto-create indexes for small collections', async () => { + it('does not auto-create indexes for small collections', async () => { const query_ = query('coll', filter('count', '>=', 3)); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -548,7 +548,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); - it.only('does not auto create indexes when index lookup is expensive', async () => { + it('does not auto create indexes when index lookup is expensive', async () => { const query_ = query('coll', filter('array', 'array-contains-any', [0, 7])); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -577,5 +577,37 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); + it.only('index auto creation works when backfiller runs halfway', async () => { + const query_ = query('coll', filter('matches', '==', 'foo')); + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [targetId])); + + // First time query runs without indexes. + // Based on current heuristic, collection document counts (5) > + // 2 * resultSize (2). + // Full matched index should be created. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.backfillIndexes({ maxDocumentsToProcess: 2 }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo' }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(1, 2); + test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); + }); + }); From 555e8dd2bb186b6fee05a611b8d293079e15fcfc Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 14:52:08 -0400 Subject: [PATCH 05/13] move index created by index auto creation exists after turn off auto creation --- .../test/unit/local/local_store.test.ts | 37 ------------------- .../unit/local/local_store_indexeddb.test.ts | 34 ++++++++++++++++- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 1ec22a9a6b8..8b63d37242d 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,43 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('index created by index auto creation exists after turn off auto creation', () => { - const query_ = query('coll', filter('value', 'not-in', [3])); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { value: 2 }), [2], []) - ]) - // First time query runs without indexes. - // Based on current heuristic, collection document counts (5) > - // 2 * resultSize (2). - // Full matched index should be created. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterIndexAutoCreationConfigure({ isEnabled: false }) - .afterBackfillIndexes() - .afterRemoteEvent( - docAddedRemoteEvent(doc('coll/f', 20, { value: 7 }), [2], []) - ) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 2, documentsByCollection: 1 }) - .toReturnChanged('coll/a', 'coll/e', 'coll/f') - .finish() - ); - }); - it('disable index auto creation works', () => { const query1 = query('coll', filter('value', 'in', [0, 1])); const query2 = query('foo', filter('value', '!=', Number.NaN)); diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 91c23c6d5ba..472fc6d0493 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -577,7 +577,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); - it.only('index auto creation works when backfiller runs halfway', async () => { + it('index auto creation works when backfiller runs halfway', async () => { const query_ = query('coll', filter('matches', '==', 'foo')); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -609,5 +609,37 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); + it('index created by index auto creation exists after turn off auto creation', async () => { + const query_ = query('coll', filter('value', 'not-in', [3])); + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 2 }), [targetId])); + + // First time query runs without indexes. + // Based on current heuristic, collection document counts (5) > + // 2 * resultSize (2). + // Full matched index should be created. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + test.configureIndexAutoCreation({isEnabled: false,}); + await test.backfillIndexes(); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { value: 7 }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(2, 1); + test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); + }); }); From e78b1a65f5fb73f2e2f860e8357759c58f7df24b Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 23:44:08 -0400 Subject: [PATCH 06/13] move disable index auto creation works --- .../test/unit/local/local_store.test.ts | 49 ------------------- .../unit/local/local_store_indexeddb.test.ts | 45 +++++++++++++++++ 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 8b63d37242d..5f138809f5f 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,55 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('disable index auto creation works', () => { - const query1 = query('coll', filter('value', 'in', [0, 1])); - const query2 = query('foo', filter('value', '!=', Number.NaN)); - return ( - expectLocalStore() - .afterAllocatingQuery(query1) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [2], []), - docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { value: 0 }), [2], []) - ]) - // First time query runs without indexes. - // Based on current heuristic, collection document counts (5) > - // 2 * resultSize (2). - // Full matched index should be created. - .afterExecutingQuery(query1) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterIndexAutoCreationConfigure({ isEnabled: false }) - .afterBackfillIndexes() - .afterExecutingQuery(query1) - .toHaveRead({ documentsByKey: 2, documentsByCollection: 0 }) - .toReturnChanged('coll/a', 'coll/e') - .afterAllocatingQuery(query2) - .toReturnTargetId(4) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [2], []), - docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [2], []), - docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [2], []), - docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [2], []), - docAddedRemoteEvent(doc('foo/e', 10, { value: 'string' }), [2], []) - ]) - .afterExecutingQuery(query2) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .afterBackfillIndexes() - .afterExecutingQuery(query2) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .finish() - ); - }); - it('index auto creation works with mutation', () => { const query_ = query( 'coll', diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 472fc6d0493..608788c6f66 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -642,4 +642,49 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e', 'coll/f'); }); + it('disable index auto creation works', async () => { + const query1 = query('coll', filter('value', 'in', [0, 1])); + const query2 = query('foo', filter('value', '!=', Number.NaN)); + + const targetId1 = await test.allocateQuery(query1); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [targetId1])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [targetId1])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [targetId1])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [targetId1])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 0 }), [targetId1])); + + // First time query runs without indexes. + // Based on current heuristic, collection document counts (5) > + // 2 * resultSize (2). + // Full matched index should be created. + await test.executeQuery(query1); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + test.configureIndexAutoCreation({isEnabled: false,}); + await test.backfillIndexes(); + await test.executeQuery(query1); + test.assertRemoteDocumentsRead(2, 0); + test.assertQueryReturned('coll/a', 'coll/e'); + + const targetId2 = await test.allocateQuery(query2); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [targetId2])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [targetId2])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [targetId2])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [targetId2])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/e', 10, { value: 'string' }), [targetId2])); + + await test.executeQuery(query2); + test.assertRemoteDocumentsRead(0, 2); + await test.backfillIndexes(); + await test.executeQuery(query2); + test.assertRemoteDocumentsRead(0, 2); + }); + }); From 469f3d6f80f00e243997371eefba1a35085410ca Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 23:52:53 -0400 Subject: [PATCH 07/13] move index auto creation works with mutation --- .../test/unit/local/local_store.test.ts | 41 ------------------- .../unit/local/local_store_indexeddb.test.ts | 41 ++++++++++++++++--- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 5f138809f5f..1c2adb8674f 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,47 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('index auto creation works with mutation', () => { - const query_ = query( - 'coll', - filter('value', 'array-contains-any', [8, 1, 'string']) - ); - return expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent( - doc('coll/a', 10, { value: [8, 1, 'string'] }), - [2], - [] - ), - docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [2], []), - docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [2], []), - docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [2], []), - docAddedRemoteEvent(doc('coll/e', 10, { value: ['string'] }), [2], []) - ]) - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterMutation(deleteMutation('coll/e')) - .afterBackfillIndexes() - .afterMutation(setMutation('coll/f', { value: [1] })) - .afterExecutingQuery(query_) - .toHaveRead({ - documentsByKey: 1, - documentsByCollection: 0, - overlaysByKey: 1, - overlaysByCollection: 1 - }) - .toReturnChanged('coll/a', 'coll/f') - .finish(); - }); - it('delete all indexes works with index auto creation', () => { const query_ = query('coll', filter('value', '==', 'match')); return ( diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 608788c6f66..41db6049ee2 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -181,7 +181,7 @@ class AsyncLocalStoreTester { assertOverlaysRead( byKey: number, byCollection: number, - overlayTypes: { [k: string]: MutationType } + overlayTypes?: { [k: string]: MutationType } ): void { expect(this.queryEngine.overlaysReadByCollection).to.equal( byCollection, @@ -191,10 +191,12 @@ class AsyncLocalStoreTester { byKey, 'Overlays read (by key)' ); - expect(this.queryEngine.overlayTypes).to.deep.equal( - overlayTypes, - 'Overlay types read' - ); + if (overlayTypes) { + expect(this.queryEngine.overlayTypes).to.deep.equal( + overlayTypes, + 'Overlay types read' + ); + } } assertQueryReturned(...keys: string[]): void { @@ -687,4 +689,33 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 2); }); + it('index auto creation works with mutation', async () => { + const query_ = query('coll', filter('value', 'array-contains-any', [8, 1, 'string'])); + + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: [8, 1, 'string'] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: ['string'] }), [targetId])); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.writeMutations(deleteMutation('coll/e')); + await test.backfillIndexes(); + await test.writeMutations(setMutation('coll/f', { value: [1] })); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(1, 0); + test.assertOverlaysRead(1, 1); + test.assertQueryReturned('coll/a', 'coll/f'); + }); }); From 419cd5aff614ffa50b9bf74b9f1aa6c3e1424b46 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Thu, 31 Aug 2023 23:58:09 -0400 Subject: [PATCH 08/13] move delete all indexes works with index auto creation --- .../test/unit/local/local_store.test.ts | 46 ------------------- .../unit/local/local_store_indexeddb.test.ts | 42 +++++++++++++++++ 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 1c2adb8674f..f3ef2d25433 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -2758,52 +2758,6 @@ function indexedDbLocalStoreTests( } // TODO(dconeybe) port this test next - it('delete all indexes works with index auto creation', () => { - const query_ = query('coll', filter('value', '==', 'match')); - return ( - expectLocalStore() - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterIndexAutoCreationConfigure({ - isEnabled: true, - indexAutoCreationMinCollectionSize: 0, - relativeIndexReadCostPerDocument: 2 - }) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [2], []), - docAddedRemoteEvent( - doc('coll/b', 10, { value: Number.NaN }), - [2], - [] - ), - docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [2], []), - docAddedRemoteEvent( - doc('coll/d', 10, { value: 'mismatch' }), - [2], - [] - ), - docAddedRemoteEvent(doc('coll/e', 10, { value: 'match' }), [2], []) - ]) - // First time query is running without indexes. - // Based on current heuristic, collection document counts (5) > - // 2 * resultSize (2). - // Full matched index should be created. - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .afterIndexAutoCreationConfigure({ isEnabled: false }) - .afterBackfillIndexes() - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 2, documentsByCollection: 0 }) - .toReturnChanged('coll/a', 'coll/e') - .afterDeleteAllFieldIndexes() - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 2 }) - .toReturnChanged('coll/a', 'coll/e') - .finish() - ); - }); - it('delete all indexes works with manual added indexes', () => { const query_ = query('coll', filter('matches', '==', true)); return expectLocalStore() diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 41db6049ee2..ff752efa247 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -35,6 +35,7 @@ import { localStoreAllocateTarget, localStoreApplyRemoteEventToLocalCache, localStoreConfigureFieldIndexes, + localStoreDeleteAllFieldIndexes, localStoreExecuteQuery, localStoreSetIndexAutoCreationEnabled, localStoreWriteLocally, @@ -147,6 +148,10 @@ class AsyncLocalStoreTester { ); } + deleteAllFieldIndexes(): Promise { + return localStoreDeleteAllFieldIndexes(this.localStore) + } + async configureAndAssertFieldsIndexes( ...indexes: FieldIndex[] ): Promise { @@ -718,4 +723,41 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertOverlaysRead(1, 1); test.assertQueryReturned('coll/a', 'coll/f'); }); + + it('delete all indexes works with index auto creation', async () => { + const query_ = query('coll', filter('value', '==', 'match')); + + const targetId = await test.allocateQuery(query_); + test.configureIndexAutoCreation({ + isEnabled: true, + indexAutoCreationMinCollectionSize: 0, + relativeIndexReadCostPerDocument: 2 + }); + + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: Number.NaN }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: 'mismatch' }), [targetId])); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 'match' }), [targetId])); + + // First time query is running without indexes. + // Based on current heuristic, collection document counts (5) > + // 2 * resultSize (2). + // Full matched index should be created. + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + + test.configureIndexAutoCreation({isEnabled: false}) + await test.backfillIndexes(); + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(2, 0); + test.assertQueryReturned('coll/a', 'coll/e'); + + await test.deleteAllFieldIndexes(); + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 2); + test.assertQueryReturned('coll/a', 'coll/e'); + }); + }); From 5999ae613720678501b0a37477917610f5d95679 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 1 Sep 2023 00:17:28 -0400 Subject: [PATCH 09/13] move the last test --- .../test/unit/local/local_store.test.ts | 177 +----------------- .../unit/local/local_store_indexeddb.test.ts | 22 +++ 2 files changed, 32 insertions(+), 167 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index f3ef2d25433..129601f4539 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -31,7 +31,6 @@ import { import { SnapshotVersion } from '../../../src/core/snapshot_version'; import { Target } from '../../../src/core/target'; import { BatchId, TargetId } from '../../../src/core/types'; -import { IndexBackfiller } from '../../../src/local/index_backfiller'; import { IndexedDbPersistence } from '../../../src/local/indexeddb_persistence'; import { LocalStore } from '../../../src/local/local_store'; import { @@ -39,8 +38,6 @@ import { localStoreAllocateTarget, localStoreApplyBundledDocuments, localStoreApplyRemoteEventToLocalCache, - localStoreConfigureFieldIndexes, - localStoreDeleteAllFieldIndexes, localStoreExecuteQuery, localStoreGetHighestUnacknowledgedBatchId, localStoreGetTargetData, @@ -55,8 +52,7 @@ import { localStoreReleaseTarget, localStoreSaveBundle, localStoreSaveNamedQuery, - newLocalStore, - TestingHooks as LocalStoreTestingHooks + newLocalStore } from '../../../src/local/local_store_impl'; import { LocalViewChanges } from '../../../src/local/local_view_changes'; import { Persistence } from '../../../src/local/persistence'; @@ -66,12 +62,6 @@ import { DocumentMap } from '../../../src/model/collections'; import { Document } from '../../../src/model/document'; -import { - FieldIndex, - IndexKind, - IndexSegment, - IndexState -} from '../../../src/model/field_index'; import { FieldMask } from '../../../src/model/field_mask'; import { FieldTransform, @@ -86,7 +76,6 @@ import { MutationBatchResult } from '../../../src/model/mutation_batch'; import { ObjectValue } from '../../../src/model/object_value'; -import { FieldPath } from '../../../src/model/path'; import { serverTimestamp } from '../../../src/model/server_timestamps'; import { ServerTimestampTransform } from '../../../src/model/transform_operation'; import { BundleMetadata as ProtoBundleMetadata } from '../../../src/protos/firestore_bundle_proto'; @@ -146,7 +135,6 @@ class LocalStoreTester { private lastTargetId: TargetId | null = null; private batches: MutationBatch[] = []; private bundleConverter: BundleConverterImpl; - private indexBackfiller: IndexBackfiller; private queryExecutionCount = 0; @@ -157,7 +145,6 @@ class LocalStoreTester { readonly gcIsEager: boolean ) { this.bundleConverter = new BundleConverterImpl(JSON_SERIALIZER); - this.indexBackfiller = new IndexBackfiller(localStore, persistence); } private prepareNextStep(): void { @@ -192,10 +179,6 @@ class LocalStoreTester { } } - afterMutation(mutation: Mutation): LocalStoreTester { - return this.afterMutations([mutation]); - } - afterMutations(mutations: Mutation[]): LocalStoreTester { this.prepareNextStep(); @@ -223,11 +206,6 @@ class LocalStoreTester { return this; } - afterRemoteEvents(remoteEvents: RemoteEvent[]): LocalStoreTester { - remoteEvents.forEach(remoteEvent => this.afterRemoteEvent(remoteEvent)); - return this; - } - afterBundleDocuments( documents: BundledDocuments, bundleName?: string @@ -353,59 +331,6 @@ class LocalStoreTester { return this; } - afterIndexAutoCreationConfigure(config: { - isEnabled?: boolean; - indexAutoCreationMinCollectionSize?: number; - relativeIndexReadCostPerDocument?: number; - }): LocalStoreTester { - this.prepareNextStep(); - - this.promiseChain = this.promiseChain.then(() => { - if (config.isEnabled !== undefined) { - localStoreSetIndexAutoCreationEnabled( - this.localStore, - config.isEnabled - ); - } - LocalStoreTestingHooks.setIndexAutoCreationSettings( - this.localStore, - config - ); - }); - - return this; - } - - afterDeleteAllFieldIndexes(): LocalStoreTester { - this.prepareNextStep(); - this.promiseChain = this.promiseChain.then(() => - localStoreDeleteAllFieldIndexes(this.localStore) - ); - return this; - } - - afterConfigureFieldIndexes(fieldIndexes: FieldIndex[]): LocalStoreTester { - this.prepareNextStep(); - this.promiseChain = this.promiseChain.then(() => - localStoreConfigureFieldIndexes(this.localStore, fieldIndexes) - ); - return this; - } - - afterBackfillIndexes(options?: { - maxDocumentsToProcess?: number; - }): LocalStoreTester { - this.prepareNextStep(); - - this.promiseChain = this.promiseChain.then(() => - this.indexBackfiller - .backfill(options?.maxDocumentsToProcess) - .then(() => {}) - ); - - return this; - } - /** * Asserts the expected number of mutations and documents read by * the MutationQueue and the RemoteDocumentCache. @@ -485,7 +410,7 @@ class LocalStoreTester { } toReturnChangedInternal( - docsOrKeyStrs: Document[] | string[], + docs: Document[], isEqual?: (lhs: Document | null, rhs: Document | null) => boolean ): LocalStoreTester { this.promiseChain = this.promiseChain.then(() => { @@ -493,21 +418,14 @@ class LocalStoreTester { this.lastChanges !== null, 'Called toReturnChanged() without prior after()' ); - expect(this.lastChanges.size).to.equal( - docsOrKeyStrs.length, - 'number of changes' - ); - for (const docOrKeyStr of docsOrKeyStrs) { - const docKey = - typeof docOrKeyStr === 'string' ? key(docOrKeyStr) : docOrKeyStr.key; - const returned = this.lastChanges.get(docKey); + expect(this.lastChanges.size).to.equal(docs.length, 'number of changes'); + for (const doc of docs) { + const returned = this.lastChanges.get(doc.key); const message = `Expected '${returned}' to equal '${doc}'.`; - if (typeof docOrKeyStr === 'string') { - expect(returned?.isValidDocument()).to.equal(true, message); - } else if (isEqual) { - expect(isEqual(docOrKeyStr, returned)).to.equal(true, message); + if (isEqual) { + expect(isEqual(doc, returned)).to.equal(true, message); } else { - expectEqual(docOrKeyStr, returned, message); + expectEqual(doc, returned, message); } } this.lastChanges = null; @@ -515,10 +433,8 @@ class LocalStoreTester { return this; } - toReturnChanged(...docs: Document[]): LocalStoreTester; - toReturnChanged(...docKeyStrs: string[]): LocalStoreTester; - toReturnChanged(...docsOrKeyStrs: Document[] | string[]): LocalStoreTester { - return this.toReturnChangedInternal(docsOrKeyStrs); + toReturnChanged(...docs: Document[]): LocalStoreTester { + return this.toReturnChangedInternal(docs); } toReturnChangedWithDocComparator( @@ -673,18 +589,6 @@ function compareDocsWithCreateTime( ); } -function fieldIndex( - collectionGroup: string, - indexId: number, - indexState: IndexState, - field: string, - kind: IndexKind -): FieldIndex { - const fieldPath = new FieldPath(field.split('.')); - const segments = [new IndexSegment(fieldPath, kind)]; - return new FieldIndex(indexId, collectionGroup, segments, indexState); -} - describe('LocalStore w/ Memory Persistence', () => { async function initialize(): Promise { const queryEngine = new CountingQueryEngine(); @@ -725,8 +629,6 @@ describe('LocalStore w/ IndexedDB Persistence', () => { addEqualityMatcher(); describe('genericLocalStoreTests', () => genericLocalStoreTests(initialize, /* gcIsEager= */ false)); - describe('indexedDbLocalStoreTests', () => - indexedDbLocalStoreTests(initialize, /* gcIsEager= */ false)); }); function genericLocalStoreTests( @@ -2727,62 +2629,3 @@ function genericLocalStoreTests( } ); } - -function indexedDbLocalStoreTests( - getComponents: () => Promise, - gcIsEager: boolean -): void { - let persistence: Persistence; - let localStore: LocalStore; - let queryEngine: CountingQueryEngine; - - beforeEach(async () => { - const components = await getComponents(); - persistence = components.persistence; - localStore = components.localStore; - queryEngine = components.queryEngine; - }); - - afterEach(async () => { - await persistence.shutdown(); - await persistenceHelpers.clearTestPersistence(); - }); - - function expectLocalStore(): LocalStoreTester { - return new LocalStoreTester( - localStore, - persistence, - queryEngine, - gcIsEager - ); - } - - // TODO(dconeybe) port this test next - it('delete all indexes works with manual added indexes', () => { - const query_ = query('coll', filter('matches', '==', true)); - return expectLocalStore() - .afterConfigureFieldIndexes([ - fieldIndex( - 'coll', - 0, - IndexState.empty(), - 'matches', - IndexKind.ASCENDING - ) - ]) - .afterAllocatingQuery(query_) - .toReturnTargetId(2) - .afterRemoteEvents([ - docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [2], []) - ]) - .afterBackfillIndexes() - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 1, documentsByCollection: 0 }) - .toReturnChanged('coll/a') - .afterDeleteAllFieldIndexes() - .afterExecutingQuery(query_) - .toHaveRead({ documentsByKey: 0, documentsByCollection: 1 }) - .toReturnChanged('coll/a') - .finish(); - }); -} diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index ff752efa247..68852e6eb3c 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -760,4 +760,26 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e'); }); + it('delete all indexes works with manual added indexes', async () => { + const query_ = query('coll', filter('matches', '==', true)); + + await test.configureFieldsIndexes(fieldIndex('coll', { + fields: [['matches', IndexKind.ASCENDING]] + })); + + const targetId = await test.allocateQuery(query_); + await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId])); + await test.backfillIndexes(); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(1, 0); + test.assertQueryReturned('coll/a'); + + await test.deleteAllFieldIndexes(); + + await test.executeQuery(query_); + test.assertRemoteDocumentsRead(0, 1); + test.assertQueryReturned('coll/a'); + }); + }); From 60fa4824f6fef2a8050f9e6be0e0677b4023a953 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 1 Sep 2023 00:18:45 -0400 Subject: [PATCH 10/13] yarn prettier --- .../unit/local/local_store_indexeddb.test.ts | 241 +++++++++++++----- 1 file changed, 173 insertions(+), 68 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 68852e6eb3c..0ad34bfae38 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -137,10 +137,7 @@ class AsyncLocalStoreTester { this.prepareNextStep(); if (config.isEnabled !== undefined) { - localStoreSetIndexAutoCreationEnabled( - this.localStore, - config.isEnabled - ); + localStoreSetIndexAutoCreationEnabled(this.localStore, config.isEnabled); } LocalStoreTestingHooks.setIndexAutoCreationSettings( this.localStore, @@ -149,7 +146,7 @@ class AsyncLocalStoreTester { } deleteAllFieldIndexes(): Promise { - return localStoreDeleteAllFieldIndexes(this.localStore) + return localStoreDeleteAllFieldIndexes(this.localStore); } async configureAndAssertFieldsIndexes( @@ -502,13 +499,23 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]) + docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { matches: true }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { matches: true }), [targetId]) + ); // First time query runs without indexes. // Based on current heuristic, collection document counts (5) > @@ -520,7 +527,9 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { await test.backfillIndexes(); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { matches: true }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/f', 20, { matches: true }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(2, 1); @@ -535,11 +544,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [targetId]) + ); // SDK will not create indexes since collection size is too small. await test.executeQuery(query_); @@ -548,7 +567,9 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { await test.backfillIndexes(); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { count: 4 }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/f', 20, { count: 4 }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(0, 3); @@ -564,11 +585,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 5 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { array: [2, 10, 20] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { array: [2, 0, 8] }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { array: [2, 10, 20] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { array: [2, 0, 8] }), [targetId]) + ); // SDK will not create indexes since relative read cost is too large. await test.executeQuery(query_); @@ -577,7 +608,9 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { await test.backfillIndexes(); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { array: [0] }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/f', 20, { array: [0] }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(0, 3); @@ -593,11 +626,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [targetId]) + ); // First time query runs without indexes. // Based on current heuristic, collection document counts (5) > @@ -609,7 +652,9 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { await test.backfillIndexes({ maxDocumentsToProcess: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo' }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/f', 20, { matches: 'foo' }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(1, 2); @@ -625,11 +670,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 2 }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { value: 2 }), [targetId]) + ); // First time query runs without indexes. // Based on current heuristic, collection document counts (5) > @@ -639,10 +694,12 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 2); test.assertQueryReturned('coll/a', 'coll/e'); - test.configureIndexAutoCreation({isEnabled: false,}); + test.configureIndexAutoCreation({ isEnabled: false }); await test.backfillIndexes(); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/f', 20, { value: 7 }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/f', 20, { value: 7 }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(2, 1); @@ -660,11 +717,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [targetId1])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [targetId1])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [targetId1])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [targetId1])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 0 }), [targetId1])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [targetId1]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [targetId1]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [targetId1]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [targetId1]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { value: 0 }), [targetId1]) + ); // First time query runs without indexes. // Based on current heuristic, collection document counts (5) > @@ -674,18 +741,28 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 2); test.assertQueryReturned('coll/a', 'coll/e'); - test.configureIndexAutoCreation({isEnabled: false,}); + test.configureIndexAutoCreation({ isEnabled: false }); await test.backfillIndexes(); await test.executeQuery(query1); test.assertRemoteDocumentsRead(2, 0); test.assertQueryReturned('coll/a', 'coll/e'); const targetId2 = await test.allocateQuery(query2); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [targetId2])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [targetId2])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [targetId2])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [targetId2])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('foo/e', 10, { value: 'string' }), [targetId2])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [targetId2]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [targetId2]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [targetId2]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [targetId2]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('foo/e', 10, { value: 'string' }), [targetId2]) + ); await test.executeQuery(query2); test.assertRemoteDocumentsRead(0, 2); @@ -695,7 +772,10 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { }); it('index auto creation works with mutation', async () => { - const query_ = query('coll', filter('value', 'array-contains-any', [8, 1, 'string'])); + const query_ = query( + 'coll', + filter('value', 'array-contains-any', [8, 1, 'string']) + ); const targetId = await test.allocateQuery(query_); test.configureIndexAutoCreation({ @@ -704,11 +784,23 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: [8, 1, 'string'] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: ['string'] }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { value: [8, 1, 'string'] }), [ + targetId + ]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { value: ['string'] }), [targetId]) + ); await test.executeQuery(query_); test.assertRemoteDocumentsRead(0, 2); @@ -723,7 +815,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertOverlaysRead(1, 1); test.assertQueryReturned('coll/a', 'coll/f'); }); - + it('delete all indexes works with index auto creation', async () => { const query_ = query('coll', filter('value', '==', 'match')); @@ -734,11 +826,21 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/b', 10, { value: Number.NaN }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/d', 10, { value: 'mismatch' }), [targetId])); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/e', 10, { value: 'match' }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/b', 10, { value: Number.NaN }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/d', 10, { value: 'mismatch' }), [targetId]) + ); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/e', 10, { value: 'match' }), [targetId]) + ); // First time query is running without indexes. // Based on current heuristic, collection document counts (5) > @@ -748,7 +850,7 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 2); test.assertQueryReturned('coll/a', 'coll/e'); - test.configureIndexAutoCreation({isEnabled: false}) + test.configureIndexAutoCreation({ isEnabled: false }); await test.backfillIndexes(); await test.executeQuery(query_); test.assertRemoteDocumentsRead(2, 0); @@ -759,16 +861,20 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 2); test.assertQueryReturned('coll/a', 'coll/e'); }); - + it('delete all indexes works with manual added indexes', async () => { const query_ = query('coll', filter('matches', '==', true)); - - await test.configureFieldsIndexes(fieldIndex('coll', { - fields: [['matches', IndexKind.ASCENDING]] - })); + + await test.configureFieldsIndexes( + fieldIndex('coll', { + fields: [['matches', IndexKind.ASCENDING]] + }) + ); const targetId = await test.allocateQuery(query_); - await test.applyRemoteEvent(docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId])); + await test.applyRemoteEvent( + docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]) + ); await test.backfillIndexes(); await test.executeQuery(query_); @@ -781,5 +887,4 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertRemoteDocumentsRead(0, 1); test.assertQueryReturned('coll/a'); }); - }); From 2c2ff354666dd785c885f2483dd713b7e0b58262 Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 1 Sep 2023 00:27:45 -0400 Subject: [PATCH 11/13] another minor undo --- packages/firestore/test/unit/local/local_store.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store.test.ts b/packages/firestore/test/unit/local/local_store.test.ts index 129601f4539..b8fe6878d9f 100644 --- a/packages/firestore/test/unit/local/local_store.test.ts +++ b/packages/firestore/test/unit/local/local_store.test.ts @@ -627,8 +627,7 @@ describe('LocalStore w/ IndexedDB Persistence', () => { } addEqualityMatcher(); - describe('genericLocalStoreTests', () => - genericLocalStoreTests(initialize, /* gcIsEager= */ false)); + genericLocalStoreTests(initialize, /* gcIsEager= */ false); }); function genericLocalStoreTests( From f424efc54505131ea37f2b6165a7599c9a7831dd Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 1 Sep 2023 00:36:09 -0400 Subject: [PATCH 12/13] add applyRemoteEvents() --- .../unit/local/local_store_indexeddb.test.ts | 172 ++++++------------ 1 file changed, 53 insertions(+), 119 deletions(-) diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index 0ad34bfae38..c1bf6af9fde 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -112,6 +112,12 @@ class AsyncLocalStoreTester { return this.lastTargetId; } + async applyRemoteEvents(...remoteEvents: RemoteEvent[]): Promise { + for (const remoteEvent of remoteEvents) { + await this.applyRemoteEvent(remoteEvent); + } + } + async applyRemoteEvent(remoteEvent: RemoteEvent): Promise { this.prepareNextStep(); this.lastChanges = await localStoreApplyRemoteEventToLocalCache( @@ -499,21 +505,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]); - - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { matches: true }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { matches: false }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { matches: false }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { matches: false }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { matches: true }), [targetId]) ); @@ -544,19 +540,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { count: 5 }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { count: 1 }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { count: 0 }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { count: 1 }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { count: 3 }), [targetId]) ); @@ -585,19 +573,13 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 5 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { array: [2, 10, 20] }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { array: [2, 7] }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { array: [] }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { array: [3] }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { array: [2, 10, 20] }), [ + targetId + ]), docAddedRemoteEvent(doc('coll/e', 10, { array: [2, 0, 8] }), [targetId]) ); @@ -626,19 +608,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { matches: 'foo' }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { matches: '' }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { matches: 'bar' }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { matches: 7 }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { matches: 'foo' }), [targetId]) ); @@ -670,19 +644,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { value: 5 }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { value: 3 }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { value: 3 }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { value: 3 }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { value: 2 }), [targetId]) ); @@ -717,19 +683,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [targetId1]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [targetId1]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [targetId1]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [targetId1]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { value: 1 }), [targetId1]), + docAddedRemoteEvent(doc('coll/b', 10, { value: 8 }), [targetId1]), + docAddedRemoteEvent(doc('coll/c', 10, { value: 'string' }), [targetId1]), + docAddedRemoteEvent(doc('coll/d', 10, { value: false }), [targetId1]), docAddedRemoteEvent(doc('coll/e', 10, { value: 0 }), [targetId1]) ); @@ -748,19 +706,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { test.assertQueryReturned('coll/a', 'coll/e'); const targetId2 = await test.allocateQuery(query2); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [targetId2]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [targetId2]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [targetId2]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [targetId2]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('foo/a', 10, { value: 5 }), [targetId2]), + docAddedRemoteEvent(doc('foo/b', 10, { value: Number.NaN }), [targetId2]), + docAddedRemoteEvent(doc('foo/c', 10, { value: Number.NaN }), [targetId2]), + docAddedRemoteEvent(doc('foo/d', 10, { value: Number.NaN }), [targetId2]), docAddedRemoteEvent(doc('foo/e', 10, { value: 'string' }), [targetId2]) ); @@ -784,21 +734,13 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( + await test.applyRemoteEvents( docAddedRemoteEvent(doc('coll/a', 10, { value: [8, 1, 'string'] }), [ targetId - ]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [targetId]) - ); - await test.applyRemoteEvent( + ]), + docAddedRemoteEvent(doc('coll/b', 10, { value: [] }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { value: [3] }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { value: [0, 5] }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { value: ['string'] }), [targetId]) ); @@ -826,19 +768,11 @@ describe('LocalStore w/ IndexedDB Persistence (Non generic)', () => { relativeIndexReadCostPerDocument: 2 }); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/b', 10, { value: Number.NaN }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [targetId]) - ); - await test.applyRemoteEvent( - docAddedRemoteEvent(doc('coll/d', 10, { value: 'mismatch' }), [targetId]) - ); - await test.applyRemoteEvent( + await test.applyRemoteEvents( + docAddedRemoteEvent(doc('coll/a', 10, { value: 'match' }), [targetId]), + docAddedRemoteEvent(doc('coll/b', 10, { value: Number.NaN }), [targetId]), + docAddedRemoteEvent(doc('coll/c', 10, { value: null }), [targetId]), + docAddedRemoteEvent(doc('coll/d', 10, { value: 'mismatch' }), [targetId]), docAddedRemoteEvent(doc('coll/e', 10, { value: 'match' }), [targetId]) ); From ff01e07cd7c329d871c49681fa6b966c25f9a71b Mon Sep 17 00:00:00 2001 From: Denver Coneybeare Date: Fri, 1 Sep 2023 00:42:53 -0400 Subject: [PATCH 13/13] fix type of maxDocumentsToProcess from 2 to number --- .../firestore/test/unit/local/local_store_indexeddb.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts index c1bf6af9fde..214ee276016 100644 --- a/packages/firestore/test/unit/local/local_store_indexeddb.test.ts +++ b/packages/firestore/test/unit/local/local_store_indexeddb.test.ts @@ -214,7 +214,9 @@ class AsyncLocalStoreTester { } } - async backfillIndexes(config?: { maxDocumentsToProcess?: 2 }): Promise { + async backfillIndexes(config?: { + maxDocumentsToProcess?: number; + }): Promise { await this.indexBackfiller.backfill(config?.maxDocumentsToProcess); } }