Skip to content

Commit 25cda8a

Browse files
authored
Firestore: deleteAllPersistentCacheIndexes() added, but hidden for now (#7587)
1 parent 5f6304d commit 25cda8a

12 files changed

+274
-0
lines changed

.changeset/healthy-peas-heal.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@firebase/firestore': patch
3+
'firebase': patch
4+
---
5+
6+
Implemented internal logic to delete all client-side indexes

packages/firestore/src/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export {
205205
export {
206206
PersistentCacheIndexManager,
207207
getPersistentCacheIndexManager,
208+
deleteAllPersistentCacheIndexes,
208209
enablePersistentCacheIndexAutoCreation,
209210
disablePersistentCacheIndexAutoCreation
210211
} from './api/persistent_cache_index_manager';

packages/firestore/src/api/persistent_cache_index_manager.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import {
19+
firestoreClientDeleteAllFieldIndexes,
1920
firestoreClientSetPersistentCacheIndexAutoCreationEnabled,
2021
FirestoreClient
2122
} from '../core/firestore_client';
@@ -99,6 +100,29 @@ export function disablePersistentCacheIndexAutoCreation(
99100
setPersistentCacheIndexAutoCreationEnabled(indexManager, false);
100101
}
101102

103+
/**
104+
* Removes all persistent cache indexes.
105+
*
106+
* Please note this function will also deletes indexes generated by
107+
* `setIndexConfiguration()`, which is deprecated.
108+
*
109+
* TODO(CSI) Remove @internal to make the API publicly available.
110+
* @internal
111+
*/
112+
export function deleteAllPersistentCacheIndexes(
113+
indexManager: PersistentCacheIndexManager
114+
): void {
115+
indexManager._client.verifyNotTerminated();
116+
117+
const promise = firestoreClientDeleteAllFieldIndexes(indexManager._client);
118+
119+
promise
120+
.then(_ => logDebug('deleting all persistent cache indexes succeeded'))
121+
.catch(error =>
122+
logWarn('deleting all persistent cache indexes failed', error)
123+
);
124+
}
125+
102126
function setPersistentCacheIndexAutoCreationEnabled(
103127
indexManager: PersistentCacheIndexManager,
104128
isEnabled: boolean

packages/firestore/src/core/firestore_client.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { User } from '../auth/user';
2626
import { LocalStore } from '../local/local_store';
2727
import {
2828
localStoreConfigureFieldIndexes,
29+
localStoreDeleteAllFieldIndexes,
2930
localStoreExecuteQuery,
3031
localStoreGetNamedQuery,
3132
localStoreHandleUserChange,
@@ -841,3 +842,11 @@ export function firestoreClientSetPersistentCacheIndexAutoCreationEnabled(
841842
);
842843
});
843844
}
845+
846+
export function firestoreClientDeleteAllFieldIndexes(
847+
client: FirestoreClient
848+
): Promise<void> {
849+
return client.asyncQueue.enqueue(async () => {
850+
return localStoreDeleteAllFieldIndexes(await getLocalStore(client));
851+
});
852+
}

packages/firestore/src/local/index_manager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ export interface IndexManager {
105105
index: FieldIndex
106106
): PersistencePromise<void>;
107107

108+
/** Removes all field indexes and deletes all index values. */
109+
deleteAllFieldIndexes(
110+
transaction: PersistenceTransaction
111+
): PersistencePromise<void>;
112+
108113
/** Creates a full matched field index which serves the given target. */
109114
createTargetIndexes(
110115
transaction: PersistenceTransaction,

packages/firestore/src/local/indexeddb_index_manager.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,19 @@ export class IndexedDbIndexManager implements IndexManager {
252252
);
253253
}
254254

255+
deleteAllFieldIndexes(
256+
transaction: PersistenceTransaction
257+
): PersistencePromise<void> {
258+
const indexes = indexConfigurationStore(transaction);
259+
const entries = indexEntriesStore(transaction);
260+
const states = indexStateStore(transaction);
261+
262+
return indexes
263+
.deleteAll()
264+
.next(() => entries.deleteAll())
265+
.next(() => states.deleteAll());
266+
}
267+
255268
createTargetIndexes(
256269
transaction: PersistenceTransaction,
257270
target: Target

packages/firestore/src/local/local_store_impl.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,6 +1535,18 @@ export function localStoreSetIndexAutoCreationEnabled(
15351535
localStoreImpl.queryEngine.indexAutoCreationEnabled = isEnabled;
15361536
}
15371537

1538+
export function localStoreDeleteAllFieldIndexes(
1539+
localStore: LocalStore
1540+
): Promise<void> {
1541+
const localStoreImpl = debugCast(localStore, LocalStoreImpl);
1542+
const indexManager = localStoreImpl.indexManager;
1543+
return localStoreImpl.persistence.runTransaction(
1544+
'Delete All Indexes',
1545+
'readwrite',
1546+
transaction => indexManager.deleteAllFieldIndexes(transaction)
1547+
);
1548+
}
1549+
15381550
/**
15391551
* Test-only hooks into the SDK for use exclusively by tests.
15401552
*/

packages/firestore/src/local/memory_index_manager.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ export class MemoryIndexManager implements IndexManager {
6666
return PersistencePromise.resolve();
6767
}
6868

69+
deleteAllFieldIndexes(
70+
transaction: PersistenceTransaction
71+
): PersistencePromise<void> {
72+
// Field indices are not supported with memory persistence.
73+
return PersistencePromise.resolve();
74+
}
75+
6976
createTargetIndexes(
7077
transaction: PersistenceTransaction,
7178
target: Target

packages/firestore/test/integration/api/persistent_cache_index_manager.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import { expect } from 'chai';
1919

2020
import {
21+
deleteAllPersistentCacheIndexes,
2122
disablePersistentCacheIndexAutoCreation,
2223
doc,
2324
enablePersistentCacheIndexAutoCreation,
@@ -149,4 +150,66 @@ apiDescribe('PersistentCacheIndexManager', persistence => {
149150
});
150151
});
151152
});
153+
154+
describe('delete all persistent cache indexes', () => {
155+
it('deleteAllPersistentCacheIndexes() on new instance should succeed', () =>
156+
withTestDb(persistence, async db => {
157+
const indexManager = getPersistentCacheIndexManager(db)!;
158+
deleteAllPersistentCacheIndexes(indexManager);
159+
}));
160+
161+
it('deleteAllPersistentCacheIndexes() should be successful when auto-indexing is enabled', () =>
162+
withTestDb(persistence, async db => {
163+
const indexManager = getPersistentCacheIndexManager(db)!;
164+
enablePersistentCacheIndexAutoCreation(indexManager);
165+
deleteAllPersistentCacheIndexes(indexManager);
166+
}));
167+
168+
it('deleteAllPersistentCacheIndexes() should be successful when auto-indexing is disabled', () =>
169+
withTestDb(persistence, async db => {
170+
const indexManager = getPersistentCacheIndexManager(db)!;
171+
enablePersistentCacheIndexAutoCreation(indexManager);
172+
disablePersistentCacheIndexAutoCreation(indexManager);
173+
deleteAllPersistentCacheIndexes(indexManager);
174+
}));
175+
176+
it('deleteAllPersistentCacheIndexes() after terminate() should throw', () =>
177+
withTestDb(persistence, async db => {
178+
const indexManager = getPersistentCacheIndexManager(db)!;
179+
terminate(db).catch(e => expect.fail(`terminate() failed: ${e}`));
180+
expect(() => deleteAllPersistentCacheIndexes(indexManager)).to.throw(
181+
'The client has already been terminated.'
182+
);
183+
}));
184+
185+
it('query returns correct results when auto-created index has been deleted', () => {
186+
const testDocs = partitionedTestDocs({
187+
matching: { documentData: { match: true }, documentCount: 1 },
188+
nonmatching: { documentData: { match: false }, documentCount: 100 }
189+
});
190+
return withTestCollection(persistence, testDocs, async (coll, db) => {
191+
const indexManager = getPersistentCacheIndexManager(db)!;
192+
enablePersistentCacheIndexAutoCreation(indexManager);
193+
194+
// Populate the local cache with the entire collection's contents.
195+
await getDocs(coll);
196+
197+
// Run a query that matches only one of the documents in the collection;
198+
// this should cause an index to be auto-created.
199+
const query_ = query(coll, where('match', '==', true));
200+
const snapshot1 = await getDocsFromCache(query_);
201+
expect(snapshot1.size).to.equal(1);
202+
203+
// Delete the index
204+
deleteAllPersistentCacheIndexes(indexManager);
205+
206+
// Run the query that matches only one of the documents again, which
207+
// should _still_ return the one and only document that matches. Since
208+
// the public API surface does not reveal whether an index was used,
209+
// there isn't anything else that can be verified.
210+
const snapshot2 = await getDocsFromCache(query_);
211+
expect(snapshot2.size).to.equal(1);
212+
});
213+
});
214+
});
152215
});

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,6 +1734,21 @@ describe('IndexedDbIndexManager', async () => {
17341734
await validateIsFullIndex(query_);
17351735
});
17361736

1737+
it('deleteAllFieldIndexes() deletes all indexes', async () => {
1738+
// Create some indexes.
1739+
const query1 = queryWithAddedFilter(query('coll'), filter('a', '==', 42));
1740+
await indexManager.createTargetIndexes(queryToTarget(query1));
1741+
await validateIsFullIndex(query1);
1742+
const query2 = queryWithAddedFilter(query('coll'), filter('b', '==', 42));
1743+
await indexManager.createTargetIndexes(queryToTarget(query2));
1744+
await validateIsFullIndex(query2);
1745+
1746+
// Verify that deleteAllFieldIndexes() deletes the indexes.
1747+
await indexManager.deleteAllFieldIndexes();
1748+
await validateIsNoneIndex(query1);
1749+
await validateIsNoneIndex(query2);
1750+
});
1751+
17371752
async function validateIsPartialIndex(query: Query): Promise<void> {
17381753
await validateIndexType(query, IndexType.PARTIAL);
17391754
}

0 commit comments

Comments
 (0)