Skip to content

Commit 129415c

Browse files
committed
deleteAllPersistentCacheIndexes() added
1 parent 75df024 commit 129415c

12 files changed

+215
-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: 23 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
TestingHooks as FirestoreClientTestingHooks
@@ -101,6 +102,28 @@ export function disablePersistentCacheIndexAutoCreation(
101102
setPersistentCacheIndexAutoCreationEnabled(indexManager, false);
102103
}
103104

105+
/**
106+
* Removes all persistent cache indexes.
107+
*
108+
* Please note this function will also deletes indexes generated by
109+
* `setIndexConfiguration()`, which is deprecated.
110+
*/
111+
export function deleteAllPersistentCacheIndexes(
112+
indexManager: PersistentCacheIndexManager
113+
): void {
114+
indexManager._client.verifyNotTerminated();
115+
116+
const promise = firestoreClientDeleteAllFieldIndexes(indexManager._client);
117+
118+
promise
119+
.then(_ => logDebug('deleting all persistent cache indexes succeeded'))
120+
.catch(error =>
121+
logWarn('deleting all persistent cache indexes failed', error)
122+
);
123+
124+
testingHooksSpi?.notifyPersistentCacheDeleteAllIndexes(promise);
125+
}
126+
104127
function setPersistentCacheIndexAutoCreationEnabled(
105128
indexManager: PersistentCacheIndexManager,
106129
isEnabled: boolean

packages/firestore/src/core/firestore_client.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { IndexType } from '../local/index_manager';
2727
import { LocalStore } from '../local/local_store';
2828
import {
2929
localStoreConfigureFieldIndexes,
30+
localStoreDeleteAllFieldIndexes,
3031
localStoreExecuteQuery,
3132
localStoreGetNamedQuery,
3233
localStoreHandleUserChange,
@@ -844,6 +845,14 @@ export function firestoreClientSetPersistentCacheIndexAutoCreationEnabled(
844845
});
845846
}
846847

848+
export function firestoreClientDeleteAllFieldIndexes(
849+
client: FirestoreClient
850+
): Promise<void> {
851+
return client.asyncQueue.enqueue(async () => {
852+
return localStoreDeleteAllFieldIndexes(await getLocalStore(client));
853+
});
854+
}
855+
847856
/**
848857
* Test-only hooks into the SDK for use exclusively by tests.
849858
*/

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/src/util/testing_hooks.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,29 @@ export class TestingHooks {
8989
);
9090
}
9191

92+
/**
93+
* Registers a callback to be notified when
94+
* `deleteAllPersistentCacheIndexes()` is invoked.
95+
*
96+
* The relative order in which callbacks are notified is unspecified; do not
97+
* rely on any particular ordering. If a given callback is registered multiple
98+
* times then it will be notified multiple times, once per registration.
99+
*
100+
* @param callback the callback to invoke when
101+
* `deleteAllPersistentCacheIndexes()` is invoked.
102+
*
103+
* @return a function that, when called, unregisters the given callback; only
104+
* the first invocation of the returned function does anything; all subsequent
105+
* invocations do nothing.
106+
*/
107+
static onPersistentCacheDeleteAllIndexes(
108+
callback: PersistentCacheDeleteAllIndexesCallback
109+
): Unsubscribe {
110+
return TestingHooksSpiImpl.instance.onPersistentCacheDeleteAllIndexes(
111+
callback
112+
);
113+
}
114+
92115
/**
93116
* Determines the type of client-side index that will be used when executing the
94117
* given query against the local cache.
@@ -171,6 +194,22 @@ export type PersistentCacheIndexAutoCreationToggleCallback = (
171194
promise: Promise<void>
172195
) => unknown;
173196

197+
/**
198+
* The signature of callbacks registered with
199+
* `TestingHooks.onPersistentCacheDeleteAllIndexes()`.
200+
*
201+
* The `promise` argument will be fulfilled when the asynchronous work started
202+
* by the call to `deleteAllPersistentCacheIndexes()` completes successfully, or
203+
* will be rejected if it fails.
204+
*
205+
* The return value of the callback, if any, is ignored.
206+
*
207+
* @internal
208+
*/
209+
export type PersistentCacheDeleteAllIndexesCallback = (
210+
promise: Promise<void>
211+
) => unknown;
212+
174213
/**
175214
* The implementation of `TestingHooksSpi`.
176215
*/
@@ -183,6 +222,11 @@ class TestingHooksSpiImpl implements TestingHooksSpi {
183222
private readonly persistentCacheIndexAutoCreationToggleCallbacksById =
184223
new Map<Symbol, PersistentCacheIndexAutoCreationToggleCallback>();
185224

225+
private readonly persistentCacheDeleteAllIndexesCallbacksById = new Map<
226+
Symbol,
227+
PersistentCacheDeleteAllIndexesCallback
228+
>();
229+
186230
private constructor() {}
187231

188232
static get instance(): TestingHooksSpiImpl {
@@ -222,6 +266,21 @@ class TestingHooksSpiImpl implements TestingHooksSpi {
222266
this.persistentCacheIndexAutoCreationToggleCallbacksById
223267
);
224268
}
269+
270+
notifyPersistentCacheDeleteAllIndexes(promise: Promise<void>): void {
271+
this.persistentCacheDeleteAllIndexesCallbacksById.forEach(callback =>
272+
callback(promise)
273+
);
274+
}
275+
276+
onPersistentCacheDeleteAllIndexes(
277+
callback: PersistentCacheDeleteAllIndexesCallback
278+
): Unsubscribe {
279+
return registerCallback(
280+
callback,
281+
this.persistentCacheDeleteAllIndexesCallbacksById
282+
);
283+
}
225284
}
226285

227286
function registerCallback<T>(

packages/firestore/src/util/testing_hooks_spi.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ export interface TestingHooksSpi {
5757
* promise.
5858
*/
5959
notifyPersistentCacheIndexAutoCreationToggle(promise: Promise<void>): void;
60+
61+
/**
62+
* Invokes all callbacks registered with
63+
* `TestingHooks.onPersistentCacheDeleteAllIndexes()` with the given
64+
* promise.
65+
*/
66+
notifyPersistentCacheDeleteAllIndexes(promise: Promise<void>): void;
6067
}
6168

6269
/**

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
import {
3939
getQueryIndexType,
4040
setPersistentCacheIndexAutoCreationSettings,
41+
verifyPersistentCacheDeleteAllIndexesSucceedsDuring,
4142
verifyPersistentCacheIndexAutoCreationToggleSucceedsDuring
4243
} from '../util/testing_hooks_util';
4344

@@ -162,6 +163,42 @@ apiDescribe('PersistentCacheIndexManager', persistence => {
162163
}));
163164
});
164165

166+
describe.only('deleteAllPersistentCacheIndexes()', () => {
167+
it('should return successfully', () =>
168+
withTestDb(persistence, async db => {
169+
const indexManager = getPersistentCacheIndexManager(db)!;
170+
deleteAllPersistentCacheIndexes(indexManager);
171+
}));
172+
173+
it('should be successful when auto-indexing is enabled', () =>
174+
withTestDb(persistence, db => {
175+
const indexManager = getPersistentCacheIndexManager(db)!;
176+
enablePersistentCacheIndexAutoCreation(indexManager);
177+
return verifyPersistentCacheDeleteAllIndexesSucceedsDuring(() =>
178+
deleteAllPersistentCacheIndexes(indexManager)
179+
);
180+
}));
181+
182+
it('should be successful when auto-indexing is disabled', () =>
183+
withTestDb(persistence, db => {
184+
const indexManager = getPersistentCacheIndexManager(db)!;
185+
enablePersistentCacheIndexAutoCreation(indexManager);
186+
disablePersistentCacheIndexAutoCreation(indexManager);
187+
return verifyPersistentCacheDeleteAllIndexesSucceedsDuring(() =>
188+
deleteAllPersistentCacheIndexes(indexManager)
189+
);
190+
}));
191+
192+
it('should fail if invoked after terminate()', () =>
193+
withTestDb(persistence, async db => {
194+
const indexManager = getPersistentCacheIndexManager(db)!;
195+
terminate(db).catch(e => expect.fail(`terminate() failed: ${e}`));
196+
expect(() => deleteAllPersistentCacheIndexes(indexManager)).to.throw(
197+
'The client has already been terminated.'
198+
);
199+
}));
200+
});
201+
165202
describe('Query execution', () => {
166203
it('Auto-indexing is disabled by default', () =>
167204
testIndexesGetAutoCreated({

packages/firestore/test/integration/util/testing_hooks_util.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,42 @@ export function verifyPersistentCacheIndexAutoCreationToggleSucceedsDuring(
138138
return promises[0];
139139
}
140140

141+
/**
142+
* Verifies than an invocation of `deleteAllPersistentCacheIndexes()` made
143+
* during the execution of the given callback succeeds.
144+
*
145+
* @param callback The callback to invoke; this callback must invoke
146+
* `deleteAllPersistentCacheIndexes()` exactly once; this callback is
147+
* called synchronously by this function, and is called exactly once.
148+
*
149+
* @return a promise that is fulfilled when the asynchronous work started by
150+
* `deleteAllPersistentCacheIndexes()` completes successfully, or is rejected
151+
* if it fails.
152+
*/
153+
export function verifyPersistentCacheDeleteAllIndexesSucceedsDuring(
154+
callback: () => void
155+
): Promise<void> {
156+
const promises: Array<Promise<void>> = [];
157+
158+
const unregister = TestingHooks.onPersistentCacheDeleteAllIndexes(promise =>
159+
promises.push(promise)
160+
);
161+
162+
try {
163+
callback();
164+
} finally {
165+
unregister();
166+
}
167+
168+
expect(
169+
promises,
170+
'exactly one invocation of deleteAllPersistentCacheIndexes() should be ' +
171+
'made by the callback'
172+
).to.have.length(1);
173+
174+
return promises[0];
175+
}
176+
141177
/**
142178
* Determines the type of client-side index that will be used when executing the
143179
* given query against the local cache.

0 commit comments

Comments
 (0)