diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index c0e36d6..1792495 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v2 # Sets up Node and an .npmrc file. This is the official Github supported way to set up node. - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: node-version: "12" registry-url: "https://registry.npmjs.org" diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 5d25ad2..d546abe 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v2 # Sets up Node and an .npmrc file. This is the official Github supported way to set up node. - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: node-version: "12" registry-url: "https://registry.npmjs.org" diff --git a/package.json b/package.json index b4a56a1..6fdac0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/objectstoreprovider", - "version": "0.7.2", + "version": "0.8.0", "description": "A cross-browser object store library", "author": "Mukundan Kavanur Kidambi ", "scripts": { diff --git a/src/IndexedDbProvider.ts b/src/IndexedDbProvider.ts index 7b27e1a..277cc30 100644 --- a/src/IndexedDbProvider.ts +++ b/src/IndexedDbProvider.ts @@ -61,6 +61,7 @@ import { TransactionLockHelper, } from "./TransactionLockHelper"; import { LogWriter } from "./LogWriter"; +import { IDBGetAllRecordsOptions } from "./types/extended-idb"; const IndexPrefix = "nsp_i_"; @@ -74,6 +75,14 @@ declare global { } } +export interface IDBConfigs { + useGetAllRecordsForGetRange: boolean; +} + +const defaultIDBConfigs: IDBConfigs = { + useGetAllRecordsForGetRange: false, +}; + // The DbProvider implementation for IndexedDB. This one is fairly straightforward since the library's access patterns pretty // closely mirror IndexedDB's. We mostly do a lot of wrapping of the APIs into JQuery promises and have some fancy footwork to // do semi-automatic schema upgrades. @@ -93,7 +102,8 @@ export class IndexedDbProvider extends DbProvider { explicitDbFactorySupportsCompoundKeys?: boolean, handleOnClose?: OnCloseHandler, logger?: IObjectStoreProviderLogger, - upgradeCallback?: UpgradeCallback + upgradeCallback?: UpgradeCallback, + private idbConfigs: IDBConfigs = defaultIDBConfigs ) { super(); @@ -450,7 +460,8 @@ export class IndexedDbProvider extends DbProvider { fakeToken, schema, this._fakeComplicatedKeys, - this.logWriter + this.logWriter, + this.idbConfigs ); const tStore = iTrans.getStore(storeSchema.name); @@ -688,7 +699,8 @@ export class IndexedDbProvider extends DbProvider { transToken, this._schema!!!, this._fakeComplicatedKeys, - this.logWriter + this.logWriter, + this.idbConfigs ) ); } @@ -706,7 +718,8 @@ class IndexedDbTransaction implements DbTransaction { private _transToken: TransactionToken, private _schema: DbSchema, private _fakeComplicatedKeys: boolean, - private logWriter: LogWriter + private logWriter: LogWriter, + private idbConfigs?: IDBConfigs ) { this._stores = map(this._transToken.storeNames, (storeName) => this._trans.objectStore(storeName) @@ -801,7 +814,8 @@ class IndexedDbTransaction implements DbTransaction { store, indexStores, storeSchema, - this._fakeComplicatedKeys + this._fakeComplicatedKeys, + this.idbConfigs ); } @@ -839,7 +853,8 @@ class IndexedDbStore implements DbStore { private _store: IDBObjectStore, private _indexStores: IDBObjectStore[], private _schema: StoreSchema, - private _fakeComplicatedKeys: boolean + private _fakeComplicatedKeys: boolean, + private idbConfigs?: IDBConfigs ) { // NOP } @@ -1166,7 +1181,8 @@ class IndexedDbStore implements DbStore { indexSchema, this._schema.primaryKeyPath, this._fakeComplicatedKeys, - this._store + this._store, + this.idbConfigs ); } else { const index = this._store.index(indexName); @@ -1177,7 +1193,9 @@ class IndexedDbStore implements DbStore { index, indexSchema, this._schema.primaryKeyPath, - this._fakeComplicatedKeys + this._fakeComplicatedKeys, + undefined, + this.idbConfigs ); } } @@ -1187,7 +1205,9 @@ class IndexedDbStore implements DbStore { this._store, undefined, this._schema.primaryKeyPath, - this._fakeComplicatedKeys + this._fakeComplicatedKeys, + undefined, + this.idbConfigs ); } @@ -1214,7 +1234,8 @@ class IndexedDbIndex extends DbIndexFTSFromRangeQueries { indexSchema: IndexSchema | undefined, primaryKeyPath: KeyPathType, private _fakeComplicatedKeys: boolean, - private _fakedOriginalStore?: IDBObjectStore + private _fakedOriginalStore?: IDBObjectStore, + private idbConfigs?: IDBConfigs ) { super(indexSchema, primaryKeyPath); } @@ -1351,6 +1372,29 @@ class IndexedDbIndex extends DbIndexFTSFromRangeQueries { ) { return IndexedDbProvider.WrapRequest(this._store.getAll(keyRange, limit)); } + + const shouldUseGetAllRecords = this.idbConfigs?.useGetAllRecordsForGetRange; + if ( + shouldUseGetAllRecords && + !!this._store.getAllRecords && + typeof this._store.getAllRecords === "function" && + reverse && + !!limit && + !offset + ) { + // use getAllRecords for reverse order, if available. + // It does not support offset currently. + const query_options = { + direction: "prev", + count: limit, + query: keyRange, + } as IDBGetAllRecordsOptions; + + return IndexedDbProvider.WrapRequest( + this._store.getAllRecords(query_options) + ); + } + const req = this._store.openCursor(keyRange, reverse ? "prev" : "next"); return this._resolveCursorResult(req, limit, offset); } diff --git a/src/types/extended-idb.d.ts b/src/types/extended-idb.d.ts new file mode 100644 index 0000000..51daa42 --- /dev/null +++ b/src/types/extended-idb.d.ts @@ -0,0 +1,43 @@ +export {}; + +export type IDBGetAllRecordsOptions = { + // The maximum number of records to retrieve. + count: number; + + // The direction of the cursor when retrieving records. + // "next" for ascending order, "prev" for descending order. + direction: "next" | "prev"; + + query: IDBKeyRange | null; +}; + +// Response of new getAllRecords method. +type IDBRecord = { + key: any; + primaryKey: any; + value: any; +}; + +// Extending interfaces with new methods, which are not in typeScript library yet. +// More details can be found in https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/IndexedDbGetAllEntries/explainer.md +declare global { + interface IDBIndex { + /** + * Retrieves all records in the index. + * This is an experimental new API and may not be available in all environments. + */ + getAllRecords?: ( + options?: IDBGetAllRecordsOptions + ) => IDBRequest; + } + + interface IDBObjectStore { + /** + * Retrieves all records in the index + * This is an experimental new API and may not be available in all environments. + */ + getAllRecords?: ( + options?: IDBGetAllRecordsOptions + ) => IDBRequest; + } +}