From 8586373b4a3a5742da9962807a688b84ad9cee2d Mon Sep 17 00:00:00 2001 From: Tom Andersen Date: Tue, 5 Dec 2023 11:53:17 -0500 Subject: [PATCH] Improve performance by using getAll on IDBIndex. (#6975) * Improve performance by using getAll on IDBIndex. * Improve performance by using getAll on IDBIndex. * IndexedDBShim does not implement GetAll on indexes correctly. * Pretty --- packages/firestore/src/local/simple_db.ts | 9 +- .../test/unit/local/simple_db.test.ts | 117 +++++++++--------- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/packages/firestore/src/local/simple_db.ts b/packages/firestore/src/local/simple_db.ts index 9b66bdf1fea..2fc821efd21 100644 --- a/packages/firestore/src/local/simple_db.ts +++ b/packages/firestore/src/local/simple_db.ts @@ -670,9 +670,12 @@ export class SimpleDbStore< ): PersistencePromise { const iterateOptions = this.options(indexOrRange, range); // Use `getAll()` if the browser supports IndexedDB v3, as it is roughly - // 20% faster. Unfortunately, getAll() does not support custom indices. - if (!iterateOptions.index && typeof this.store.getAll === 'function') { - const request = this.store.getAll(iterateOptions.range); + // 20% faster. + const store = iterateOptions.index + ? this.store.index(iterateOptions.index) + : this.store; + if (typeof store.getAll === 'function') { + const request = store.getAll(iterateOptions.range); return new PersistencePromise((resolve, reject) => { request.onerror = (event: Event) => { reject((event.target as IDBRequest).error!); diff --git a/packages/firestore/test/unit/local/simple_db.test.ts b/packages/firestore/test/unit/local/simple_db.test.ts index 1b789623961..aff2761b9c3 100644 --- a/packages/firestore/test/unit/local/simple_db.test.ts +++ b/packages/firestore/test/unit/local/simple_db.test.ts @@ -531,67 +531,72 @@ describe('SimpleDb', () => { ); }); - it('correctly sorts keys with nested arrays', async function (this: Context) { - // This test verifies that the sorting in IndexedDb matches - // `dbKeyComparator()` - - const keys = [ - 'a/a/a/a/a/a/a/a/a/a', - 'a/b/a/a/a/a/a/a/a/b', - 'b/a/a/a/a/a/a/a/a/a', - 'b/b/a/a/a/a/a/a/a/b', - 'b/b/a/a/a/a/a/a', - 'b/b/b/a/a/a/a/b', - 'c/c/a/a/a/a', - 'd/d/a/a', - 'e/e' - ].map(k => DocumentKey.fromPath(k)); - - interface ValueType { - prefixPath: string[]; - collectionId: string; - documentId: string; - } - - const expectedOrder = [...keys]; - expectedOrder.sort(dbKeyComparator); + // Note: This tests is failing under `IndexedDBShim`. + // eslint-disable-next-line no-restricted-properties + (isIndexedDbMock() ? it.skip : it)( + 'correctly sorts keys with nested arrays', + async function (this: Context) { + // This test verifies that the sorting in IndexedDb matches + // `dbKeyComparator()` + + const keys = [ + 'a/a/a/a/a/a/a/a/a/a', + 'a/b/a/a/a/a/a/a/a/b', + 'b/a/a/a/a/a/a/a/a/a', + 'b/b/a/a/a/a/a/a/a/b', + 'b/b/a/a/a/a/a/a', + 'b/b/b/a/a/a/a/b', + 'c/c/a/a/a/a', + 'd/d/a/a', + 'e/e' + ].map(k => DocumentKey.fromPath(k)); + + interface ValueType { + prefixPath: string[]; + collectionId: string; + documentId: string; + } - const actualOrder = await db.runTransaction( - this.test!.fullTitle(), - 'readwrite', - ['docs'], - txn => { - const store = txn.store('docs'); - - const writes = keys.map(k => { - const path = k.path.toArray(); - return store.put(k.path.toArray(), { - prefixPath: path.slice(0, path.length - 2), - collectionId: path[path.length - 2], - documentId: path[path.length - 1] + const expectedOrder = [...keys]; + expectedOrder.sort(dbKeyComparator); + + const actualOrder = await db.runTransaction( + this.test!.fullTitle(), + 'readwrite', + ['docs'], + txn => { + const store = txn.store('docs'); + + const writes = keys.map(k => { + const path = k.path.toArray(); + return store.put(k.path.toArray(), { + prefixPath: path.slice(0, path.length - 2), + collectionId: path[path.length - 2], + documentId: path[path.length - 1] + }); }); - }); - return PersistencePromise.waitFor(writes).next(() => - store - .loadAll('path') - .next(keys => - keys.map(k => - DocumentKey.fromSegments([ - ...k.prefixPath, - k.collectionId, - k.documentId - ]) + return PersistencePromise.waitFor(writes).next(() => + store + .loadAll('path') + .next(keys => + keys.map(k => + DocumentKey.fromSegments([ + ...k.prefixPath, + k.collectionId, + k.documentId + ]) + ) ) - ) - ); - } - ); + ); + } + ); - expect(actualOrder.map(k => k.toString())).to.deep.equal( - expectedOrder.map(k => k.toString()) - ); - }); + expect(actualOrder.map(k => k.toString())).to.deep.equal( + expectedOrder.map(k => k.toString()) + ); + } + ); it('retries transactions', async function (this: Context) { let attemptCount = 0;