summaryrefslogtreecommitdiff
path: root/packages/idb-bridge
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-02-08 15:23:44 +0100
committerFlorian Dold <florian@dold.me>2021-02-08 15:23:44 +0100
commit4452984a24334e3b7afb60e3db9dc12db02d65ba (patch)
tree50baf32f3a624d77346e38ba2bc573c063651ad2 /packages/idb-bridge
parent883637d3f287e5026de5bcafb559ff3e6ba1f3bb (diff)
downloadwallet-core-4452984a24334e3b7afb60e3db9dc12db02d65ba.tar.gz
wallet-core-4452984a24334e3b7afb60e3db9dc12db02d65ba.tar.bz2
wallet-core-4452984a24334e3b7afb60e3db9dc12db02d65ba.zip
idb-bridge: remove cyclic dependencies, rip out api extractor
Diffstat (limited to 'packages/idb-bridge')
-rw-r--r--packages/idb-bridge/api-extractor.json131
-rw-r--r--packages/idb-bridge/package.json11
-rw-r--r--packages/idb-bridge/src/BridgeIDBCursor.ts364
-rw-r--r--packages/idb-bridge/src/BridgeIDBCursorWithValue.ts48
-rw-r--r--packages/idb-bridge/src/BridgeIDBDatabase.ts249
-rw-r--r--packages/idb-bridge/src/BridgeIDBFactory.ts226
-rw-r--r--packages/idb-bridge/src/BridgeIDBIndex.ts319
-rw-r--r--packages/idb-bridge/src/BridgeIDBKeyRange.ts131
-rw-r--r--packages/idb-bridge/src/BridgeIDBObjectStore.ts467
-rw-r--r--packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts35
-rw-r--r--packages/idb-bridge/src/BridgeIDBRequest.ts86
-rw-r--r--packages/idb-bridge/src/BridgeIDBTransaction.ts326
-rw-r--r--packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts39
-rw-r--r--packages/idb-bridge/src/MemoryBackend.test.ts14
-rw-r--r--packages/idb-bridge/src/MemoryBackend.ts28
-rw-r--r--packages/idb-bridge/src/backend-interface.ts47
-rw-r--r--packages/idb-bridge/src/bridge-idb.ts2053
-rw-r--r--packages/idb-bridge/src/index.ts53
-rw-r--r--packages/idb-bridge/src/tree/b+tree.ts2
-rw-r--r--packages/idb-bridge/src/util/FakeEvent.ts11
-rw-r--r--packages/idb-bridge/src/util/FakeEventTarget.ts3
-rw-r--r--packages/idb-bridge/src/util/canInjectKey.ts4
-rw-r--r--packages/idb-bridge/src/util/deepEquals.ts2
-rw-r--r--packages/idb-bridge/src/util/extractKey.ts6
-rw-r--r--packages/idb-bridge/src/util/fakeDOMStringList.ts10
-rw-r--r--packages/idb-bridge/src/util/getIndexKeys.ts12
-rw-r--r--packages/idb-bridge/src/util/injectKey.ts10
-rw-r--r--packages/idb-bridge/src/util/makeStoreKeyValue.ts14
-rw-r--r--packages/idb-bridge/src/util/types.ts84
-rw-r--r--packages/idb-bridge/src/util/validateKeyPath.ts35
-rw-r--r--packages/idb-bridge/src/util/valueToKey.ts7
-rw-r--r--packages/idb-bridge/tsconfig.json1
32 files changed, 2195 insertions, 2633 deletions
diff --git a/packages/idb-bridge/api-extractor.json b/packages/idb-bridge/api-extractor.json
deleted file mode 100644
index f57d81d8c..000000000
--- a/packages/idb-bridge/api-extractor.json
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Config file for API Extractor. For more info, please visit: https://api-extractor.com
- */
-{
- "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
-
- /**
- * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
- * analyzes the symbols exported by this module.
- *
- * The file extension must be ".d.ts" and not ".ts".
- *
- * The path is resolved relative to the folder of the config file that contains the setting; to change this,
- * prepend a folder token such as "<projectFolder>".
- *
- * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
- */
- "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
-
- /**
- * A list of NPM package names whose exports should be treated as part of this package.
- *
- * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
- * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
- * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
- * imports library2. To avoid this, we can specify:
- *
- * "bundledPackages": [ "library2" ],
- *
- * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
- * local files for library1.
- */
- "bundledPackages": [],
-
- /**
- * Configures how the API report file (*.api.md) will be generated.
- */
- "apiReport": {
- /**
- * (REQUIRED) Whether to generate an API report.
- */
- "enabled": false
- },
-
- /**
- * Configures how the doc model file (*.api.json) will be generated.
- */
- "docModel": {
- /**
- * (REQUIRED) Whether to generate a doc model file.
- */
- "enabled": false
- },
-
- /**
- * Configures how the .d.ts rollup file will be generated.
- */
- "dtsRollup": {
- /**
- * (REQUIRED) Whether to generate the .d.ts rollup file.
- */
- "enabled": true
- },
-
- /**
- * Configures how the tsdoc-metadata.json file will be generated.
- */
- "tsdocMetadata": {
- /**
- * Whether to generate the tsdoc-metadata.json file.
- *
- * DEFAULT VALUE: true
- */
- "enabled": false
- },
-
- /**
- * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
- * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
- * To use the OS's default newline kind, specify "os".
- *
- * DEFAULT VALUE: "crlf"
- */
- "newlineKind": "lf",
-
- /**
- * Configures how API Extractor reports error and warning messages produced during analysis.
- *
- * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
- */
- "messages": {
- /**
- * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
- * the input .d.ts files.
- *
- * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
- *
- * DEFAULT VALUE: A single "default" entry with logLevel=warning.
- */
- "compilerMessageReporting": {
- /**
- * Configures the default routing for messages that don't match an explicit rule in this table.
- */
- "default": {
- "logLevel": "warning"
- }
- },
-
- /**
- * Configures handling of messages reported by API Extractor during its analysis.
- *
- * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
- *
- * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
- */
- "extractorMessageReporting": {
- "default": {
- "logLevel": "warning"
- }
- },
-
- /**
- * Configures handling of messages reported by the TSDoc parser when analyzing code comments.
- */
- "tsdocMessageReporting": {
- "default": {
- "logLevel": "warning"
- }
- }
- }
-}
diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json
index f8be82987..cfa0fa9f6 100644
--- a/packages/idb-bridge/package.json
+++ b/packages/idb-bridge/package.json
@@ -4,19 +4,19 @@
"description": "IndexedDB implementation that uses SQLite3 as storage",
"main": "./dist/idb-bridge.js",
"module": "./lib/index.js",
- "types": "./dist/idb-bridge.d.ts",
+ "types": "./lib/index.d.ts",
"author": "Florian Dold",
"license": "AGPL-3.0-or-later",
"private": false,
"scripts": {
"test": "tsc && ava",
- "prepare": "tsc && rollup -c && api-extractor run",
- "compile": "tsc && rollup -c && api-extractor run",
+ "prepare": "tsc && rollup -c",
+ "compile": "tsc && rollup -c",
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
"pretty": "prettier --write src"
},
"devDependencies": {
- "@microsoft/api-extractor": "^7.13.0",
+ "@types/node": "^14.14.22",
"ava": "^3.15.0",
"esm": "^3.2.25",
"prettier": "^2.2.1",
@@ -25,7 +25,6 @@
"typescript": "^4.1.3"
},
"dependencies": {
- "@types/node": "^14.14.22",
"tslib": "^2.1.0"
},
"ava": {
@@ -33,4 +32,4 @@
"esm"
]
}
-} \ No newline at end of file
+}
diff --git a/packages/idb-bridge/src/BridgeIDBCursor.ts b/packages/idb-bridge/src/BridgeIDBCursor.ts
deleted file mode 100644
index a18c0bebc..000000000
--- a/packages/idb-bridge/src/BridgeIDBCursor.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
-
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import compareKeys from "./util/cmp";
-import {
- DataError,
- InvalidStateError,
- ReadOnlyError,
- TransactionInactiveError,
-} from "./util/errors";
-import structuredClone from "./util/structuredClone";
-import {
- CursorRange,
- CursorSource,
- Key,
- Value,
- BridgeIDBCursorDirection,
-} from "./util/types";
-import valueToKey from "./util/valueToKey";
-import {
- RecordGetRequest,
- ResultLevel,
- Backend,
- RecordStoreRequest,
- StoreLevel,
-} from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-
-/**
- * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
- *
- * @public
- */
-export class BridgeIDBCursor {
- _request: BridgeIDBRequest | undefined;
-
- private _gotValue: boolean = false;
- private _range: CursorRange;
- private _indexPosition = undefined; // Key of previously returned record
- private _objectStorePosition = undefined;
- private _keyOnly: boolean;
-
- private _source: CursorSource;
- private _direction: BridgeIDBCursorDirection;
- private _key = undefined;
- private _primaryKey: Key | undefined = undefined;
- private _indexName: string | undefined;
- private _objectStoreName: string;
-
- protected _value: Value = undefined;
-
- constructor(
- source: CursorSource,
- objectStoreName: string,
- indexName: string | undefined,
- range: CursorRange,
- direction: BridgeIDBCursorDirection,
- request: BridgeIDBRequest,
- keyOnly: boolean,
- ) {
- this._indexName = indexName;
- this._objectStoreName = objectStoreName;
- this._range = range;
- this._source = source;
- this._direction = direction;
- this._request = request;
- this._keyOnly = keyOnly;
- }
-
- get _effectiveObjectStore(): BridgeIDBObjectStore {
- if (this.source instanceof BridgeIDBObjectStore) {
- return this.source;
- }
- return this.source.objectStore;
- }
-
- get _backend(): Backend {
- return this._source._backend;
- }
-
- // Read only properties
- get source() {
- return this._source;
- }
- set source(val) {
- /* For babel */
- }
-
- get direction() {
- return this._direction;
- }
- set direction(val) {
- /* For babel */
- }
-
- get key() {
- return this._key;
- }
- set key(val) {
- /* For babel */
- }
-
- get primaryKey() {
- return this._primaryKey;
- }
-
- set primaryKey(val) {
- /* For babel */
- }
-
- protected get _isValueCursor(): boolean {
- return false;
- }
-
- /**
- * https://w3c.github.io/IndexedDB/#iterate-a-cursor
- */
- async _iterate(key?: Key, primaryKey?: Key): Promise<any> {
- BridgeIDBFactory.enableTracing &&
- console.log(
- `iterating cursor os=${this._objectStoreName},idx=${this._indexName}`,
- );
- BridgeIDBFactory.enableTracing &&
- console.log("cursor type ", this.toString());
- const recordGetRequest: RecordGetRequest = {
- direction: this.direction,
- indexName: this._indexName,
- lastIndexPosition: this._indexPosition,
- lastObjectStorePosition: this._objectStorePosition,
- limit: 1,
- range: this._range,
- objectStoreName: this._objectStoreName,
- advanceIndexKey: key,
- advancePrimaryKey: primaryKey,
- resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
- };
-
- const { btx } = this.source._confirmActiveTransaction();
-
- let response = await this._backend.getRecords(btx, recordGetRequest);
-
- if (response.count === 0) {
- if (BridgeIDBFactory.enableTracing) {
- console.log("cursor is returning empty result");
- }
- this._gotValue = false;
- return null;
- }
-
- if (response.count !== 1) {
- throw Error("invariant failed");
- }
-
- if (BridgeIDBFactory.enableTracing) {
- console.log("request is:", JSON.stringify(recordGetRequest));
- console.log("get response is:", JSON.stringify(response));
- }
-
- if (this._indexName !== undefined) {
- this._key = response.indexKeys![0];
- } else {
- this._key = response.primaryKeys![0];
- }
-
- this._primaryKey = response.primaryKeys![0];
-
- if (!this._keyOnly) {
- this._value = response.values![0];
- }
-
- this._gotValue = true;
- this._objectStorePosition = structuredClone(response.primaryKeys![0]);
- if (response.indexKeys !== undefined && response.indexKeys.length > 0) {
- this._indexPosition = structuredClone(response.indexKeys[0]);
- }
-
- return this;
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
- public update(value: Value) {
- if (value === undefined) {
- throw new TypeError();
- }
-
- const transaction = this._effectiveObjectStore.transaction;
-
- if (transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- if (transaction.mode === "readonly") {
- throw new ReadOnlyError();
- }
-
- if (this._effectiveObjectStore._deleted) {
- throw new InvalidStateError();
- }
-
- if (
- !(this.source instanceof BridgeIDBObjectStore) &&
- this.source._deleted
- ) {
- throw new InvalidStateError();
- }
-
- if (!this._gotValue || !this._isValueCursor) {
- throw new InvalidStateError();
- }
-
- const storeReq: RecordStoreRequest = {
- key: this._primaryKey,
- value: value,
- objectStoreName: this._objectStoreName,
- storeLevel: StoreLevel.UpdateExisting,
- };
-
- const operation = async () => {
- if (BridgeIDBFactory.enableTracing) {
- console.log("updating at cursor");
- }
- const { btx } = this.source._confirmActiveTransaction();
- await this._backend.storeRecord(btx, storeReq);
- };
- return transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- /**
- * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
- */
- public advance(count: number) {
- throw Error("not implemented");
- }
-
- /**
- * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
- */
- public continue(key?: Key) {
- const transaction = this._effectiveObjectStore.transaction;
-
- if (transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- if (this._effectiveObjectStore._deleted) {
- throw new InvalidStateError();
- }
- if (
- !(this.source instanceof BridgeIDBObjectStore) &&
- this.source._deleted
- ) {
- throw new InvalidStateError();
- }
-
- if (!this._gotValue) {
- throw new InvalidStateError();
- }
-
- if (key !== undefined) {
- key = valueToKey(key);
- let lastKey =
- this._indexName === undefined
- ? this._objectStorePosition
- : this._indexPosition;
-
- const cmpResult = compareKeys(key, lastKey);
-
- if (
- (cmpResult <= 0 &&
- (this.direction === "next" || this.direction === "nextunique")) ||
- (cmpResult >= 0 &&
- (this.direction === "prev" || this.direction === "prevunique"))
- ) {
- throw new DataError();
- }
- }
-
- if (this._request) {
- this._request.readyState = "pending";
- }
-
- const operation = async () => {
- return this._iterate(key);
- };
-
- transaction._execRequestAsync({
- operation,
- request: this._request,
- source: this.source,
- });
-
- this._gotValue = false;
- }
-
- // https://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
- public continuePrimaryKey(key: Key, primaryKey: Key) {
- throw Error("not implemented");
- }
-
- public delete() {
- const transaction = this._effectiveObjectStore.transaction;
-
- if (transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- if (transaction.mode === "readonly") {
- throw new ReadOnlyError();
- }
-
- if (this._effectiveObjectStore._deleted) {
- throw new InvalidStateError();
- }
- if (
- !(this.source instanceof BridgeIDBObjectStore) &&
- this.source._deleted
- ) {
- throw new InvalidStateError();
- }
-
- if (!this._gotValue || !this._isValueCursor) {
- throw new InvalidStateError();
- }
-
- const operation = async () => {
- const { btx } = this.source._confirmActiveTransaction();
- this._backend.deleteRecord(
- btx,
- this._objectStoreName,
- BridgeIDBKeyRange._valueToKeyRange(this._primaryKey),
- );
- };
-
- return transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- public toString() {
- return "[object IDBCursor]";
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts b/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
deleted file mode 100644
index 8561879cf..000000000
--- a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import { BridgeIDBCursor } from "./BridgeIDBCursor";
-import {
- CursorRange,
- CursorSource,
- BridgeIDBCursorDirection,
- Value,
-} from "./util/types";
-
-export class BridgeIDBCursorWithValue extends BridgeIDBCursor {
- get value(): Value {
- return this._value;
- }
-
- protected get _isValueCursor(): boolean {
- return true;
- }
-
- constructor(
- source: CursorSource,
- objectStoreName: string,
- indexName: string | undefined,
- range: CursorRange,
- direction: BridgeIDBCursorDirection,
- request?: any,
- ) {
- super(source, objectStoreName, indexName, range, direction, request, false);
- }
-
- public toString() {
- return "[object IDBCursorWithValue]";
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBDatabase.ts b/packages/idb-bridge/src/BridgeIDBDatabase.ts
deleted file mode 100644
index ffd897f9c..000000000
--- a/packages/idb-bridge/src/BridgeIDBDatabase.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import {
- ConstraintError,
- InvalidAccessError,
- InvalidStateError,
- NotFoundError,
- TransactionInactiveError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import FakeEventTarget from "./util/FakeEventTarget";
-import { FakeDOMStringList, KeyPath, TransactionMode } from "./util/types";
-import validateKeyPath from "./util/validateKeyPath";
-import queueTask from "./util/queueTask";
-import {
- Backend,
- DatabaseConnection,
- Schema,
- DatabaseTransaction,
-} from "./backend-interface";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-
-/**
- * Ensure that an active version change transaction is currently running.
- */
-const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => {
- if (!database._runningVersionchangeTransaction) {
- throw new InvalidStateError();
- }
-
- // Find the latest versionchange transaction
- const transactions = database._transactions.filter(
- (tx: BridgeIDBTransaction) => {
- return tx.mode === "versionchange";
- },
- );
- const transaction = transactions[transactions.length - 1];
-
- if (!transaction || transaction._state === "finished") {
- throw new InvalidStateError();
- }
-
- if (transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- return transaction;
-};
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
-/** @public */
-export class BridgeIDBDatabase extends FakeEventTarget {
- _closePending = false;
- _closed = false;
- _runningVersionchangeTransaction = false;
- _transactions: Array<BridgeIDBTransaction> = [];
-
- _backendConnection: DatabaseConnection;
- _backend: Backend;
-
- _schema: Schema;
-
- get name(): string {
- return this._schema.databaseName;
- }
-
- get version(): number {
- return this._schema.databaseVersion;
- }
-
- get objectStoreNames(): FakeDOMStringList {
- return fakeDOMStringList(Object.keys(this._schema.objectStores)).sort();
- }
-
- /**
- * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
- */
- _closeConnection() {
- this._closePending = true;
-
- const transactionsComplete = this._transactions.every(
- (transaction: BridgeIDBTransaction) => {
- return transaction._state === "finished";
- },
- );
-
- if (transactionsComplete) {
- this._closed = true;
- this._backend.close(this._backendConnection);
- } else {
- queueTask(() => {
- this._closeConnection();
- });
- }
- }
-
- constructor(backend: Backend, backendConnection: DatabaseConnection) {
- super();
-
- this._schema = backend.getSchema(backendConnection);
-
- this._backend = backend;
- this._backendConnection = backendConnection;
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
- public createObjectStore(
- name: string,
- options: { autoIncrement?: boolean; keyPath?: KeyPath } | null = {},
- ): BridgeIDBObjectStore {
- if (name === undefined) {
- throw new TypeError();
- }
- const transaction = confirmActiveVersionchangeTransaction(this);
- const backendTx = transaction._backendTransaction;
- if (!backendTx) {
- throw Error("invariant violated");
- }
-
- const keyPath =
- options !== null && options.keyPath !== undefined
- ? options.keyPath
- : null;
- const autoIncrement =
- options !== null && options.autoIncrement !== undefined
- ? options.autoIncrement
- : false;
-
- if (keyPath !== null) {
- validateKeyPath(keyPath);
- }
-
- if (Object.keys(this._schema.objectStores).includes(name)) {
- throw new ConstraintError();
- }
-
- if (autoIncrement && (keyPath === "" || Array.isArray(keyPath))) {
- throw new InvalidAccessError();
- }
-
- transaction._backend.createObjectStore(
- backendTx,
- name,
- keyPath,
- autoIncrement,
- );
-
- this._schema = this._backend.getSchema(this._backendConnection);
-
- return transaction.objectStore(name);
- }
-
- public deleteObjectStore(name: string): void {
- if (name === undefined) {
- throw new TypeError();
- }
- const transaction = confirmActiveVersionchangeTransaction(this);
- transaction._objectStoresCache.delete(name);
- }
-
- public _internalTransaction(
- storeNames: string | string[],
- mode?: TransactionMode,
- backendTransaction?: DatabaseTransaction,
- ): BridgeIDBTransaction {
- mode = mode !== undefined ? mode : "readonly";
- if (
- mode !== "readonly" &&
- mode !== "readwrite" &&
- mode !== "versionchange"
- ) {
- throw new TypeError("Invalid mode: " + mode);
- }
-
- const hasActiveVersionchange = this._transactions.some(
- (transaction: BridgeIDBTransaction) => {
- return (
- transaction._state === "active" &&
- transaction.mode === "versionchange" &&
- transaction.db === this
- );
- },
- );
- if (hasActiveVersionchange) {
- throw new InvalidStateError();
- }
-
- if (this._closePending) {
- throw new InvalidStateError();
- }
-
- if (!Array.isArray(storeNames)) {
- storeNames = [storeNames];
- }
- if (storeNames.length === 0 && mode !== "versionchange") {
- throw new InvalidAccessError();
- }
- for (const storeName of storeNames) {
- if (this.objectStoreNames.indexOf(storeName) < 0) {
- throw new NotFoundError(
- "No objectStore named " + storeName + " in this database",
- );
- }
- }
-
- const tx = new BridgeIDBTransaction(
- storeNames,
- mode,
- this,
- backendTransaction,
- );
- this._transactions.push(tx);
- queueTask(() => tx._start());
- return tx;
- }
-
- public transaction(
- storeNames: string | string[],
- mode?: TransactionMode,
- ): BridgeIDBTransaction {
- if (mode === "versionchange") {
- throw new TypeError("Invalid mode: " + mode);
- }
- return this._internalTransaction(storeNames, mode);
- }
-
- public close() {
- this._closeConnection();
- }
-
- public toString() {
- return "[object IDBDatabase]";
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBFactory.ts b/packages/idb-bridge/src/BridgeIDBFactory.ts
deleted file mode 100644
index 7954cdd99..000000000
--- a/packages/idb-bridge/src/BridgeIDBFactory.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- * Copyright 2019 Florian Dold
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBOpenDBRequest } from "./BridgeIDBOpenDBRequest";
-import { BridgeIDBVersionChangeEvent } from "./BridgeIDBVersionChangeEvent";
-import compareKeys from "./util/cmp";
-import enforceRange from "./util/enforceRange";
-import { AbortError, VersionError } from "./util/errors";
-import FakeEvent from "./util/FakeEvent";
-import { Backend, DatabaseConnection } from "./backend-interface";
-import queueTask from "./util/queueTask";
-
-/** @public */
-export type DatabaseList = Array<{ name: string; version: number }>;
-
-/** @public */
-export class BridgeIDBFactory {
- public cmp = compareKeys;
- private backend: Backend;
- private connections: BridgeIDBDatabase[] = [];
- static enableTracing: boolean = false;
-
- public constructor(backend: Backend) {
- this.backend = backend;
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
- public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
- const request = new BridgeIDBOpenDBRequest();
- request.source = null;
-
- queueTask(async () => {
- const databases = await this.backend.getDatabases();
- const dbInfo = databases.find((x) => x.name == name);
- if (!dbInfo) {
- // Database already doesn't exist, success!
- const event = new BridgeIDBVersionChangeEvent("success", {
- newVersion: null,
- oldVersion: 0,
- });
- request.dispatchEvent(event);
- return;
- }
- const oldVersion = dbInfo.version;
-
- try {
- const dbconn = await this.backend.connectDatabase(name);
- const backendTransaction = await this.backend.enterVersionChange(
- dbconn,
- 0,
- );
- await this.backend.deleteDatabase(backendTransaction, name);
- await this.backend.commit(backendTransaction);
- await this.backend.close(dbconn);
-
- request.result = undefined;
- request.readyState = "done";
-
- const event2 = new BridgeIDBVersionChangeEvent("success", {
- newVersion: null,
- oldVersion,
- });
- request.dispatchEvent(event2);
- } catch (err) {
- request.error = new Error();
- request.error.name = err.name;
- request.readyState = "done";
-
- const event = new FakeEvent("error", {
- bubbles: true,
- cancelable: true,
- });
- event.eventPath = [];
- request.dispatchEvent(event);
- }
- });
-
- return request;
- }
-
- // tslint:disable-next-line max-line-length
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-open-IDBOpenDBRequest-DOMString-name-unsigned-long-long-version
- public open(name: string, version?: number) {
- if (arguments.length > 1 && version !== undefined) {
- // Based on spec, not sure why "MAX_SAFE_INTEGER" instead of "unsigned long long", but it's needed to pass
- // tests
- version = enforceRange(version, "MAX_SAFE_INTEGER");
- }
- if (version === 0) {
- throw new TypeError();
- }
-
- const request = new BridgeIDBOpenDBRequest();
-
- queueTask(async () => {
- let dbconn: DatabaseConnection;
- try {
- dbconn = await this.backend.connectDatabase(name);
- } catch (err) {
- request._finishWithError(err);
- return;
- }
-
- const schema = this.backend.getSchema(dbconn);
- const existingVersion = schema.databaseVersion;
-
- if (version === undefined) {
- version = existingVersion !== 0 ? existingVersion : 1;
- }
-
- const requestedVersion = version;
-
- BridgeIDBFactory.enableTracing &&
- console.log(
- `TRACE: existing version ${existingVersion}, requested version ${requestedVersion}`,
- );
-
- if (existingVersion > requestedVersion) {
- request._finishWithError(new VersionError());
- return;
- }
-
- const db = new BridgeIDBDatabase(this.backend, dbconn);
-
- if (existingVersion == requestedVersion) {
- request.result = db;
- request.readyState = "done";
-
- const event2 = new FakeEvent("success", {
- bubbles: false,
- cancelable: false,
- });
- event2.eventPath = [request];
- request.dispatchEvent(event2);
- }
-
- if (existingVersion < requestedVersion) {
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
-
- for (const otherConn of this.connections) {
- const event = new BridgeIDBVersionChangeEvent("versionchange", {
- newVersion: version,
- oldVersion: existingVersion,
- });
- otherConn.dispatchEvent(event);
- }
-
- if (this._anyOpen()) {
- const event = new BridgeIDBVersionChangeEvent("blocked", {
- newVersion: version,
- oldVersion: existingVersion,
- });
- request.dispatchEvent(event);
- }
-
- const backendTransaction = await this.backend.enterVersionChange(
- dbconn,
- requestedVersion,
- );
- db._runningVersionchangeTransaction = true;
-
- const transaction = db._internalTransaction(
- [],
- "versionchange",
- backendTransaction,
- );
- const event = new BridgeIDBVersionChangeEvent("upgradeneeded", {
- newVersion: version,
- oldVersion: existingVersion,
- });
-
- request.result = db;
- request.readyState = "done";
- request.transaction = transaction;
- request.dispatchEvent(event);
-
- await transaction._waitDone();
-
- // We don't explicitly exit the versionchange transaction,
- // since this is already done by the BridgeIDBTransaction.
- db._runningVersionchangeTransaction = false;
-
- const event2 = new FakeEvent("success", {
- bubbles: false,
- cancelable: false,
- });
- event2.eventPath = [request];
-
- request.dispatchEvent(event2);
- }
-
- this.connections.push(db);
- return db;
- });
-
- return request;
- }
-
- // https://w3c.github.io/IndexedDB/#dom-idbfactory-databases
- public databases(): Promise<DatabaseList> {
- return this.backend.getDatabases();
- }
-
- public toString(): string {
- return "[object IDBFactory]";
- }
-
- private _anyOpen(): boolean {
- return this.connections.some((c) => !c._closed && !c._closePending);
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBIndex.ts b/packages/idb-bridge/src/BridgeIDBIndex.ts
deleted file mode 100644
index 9b214a234..000000000
--- a/packages/idb-bridge/src/BridgeIDBIndex.ts
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import {
- ConstraintError,
- InvalidStateError,
- TransactionInactiveError,
-} from "./util/errors";
-import { BridgeIDBCursorDirection, Key, KeyPath } from "./util/types";
-import valueToKey from "./util/valueToKey";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import {
- Schema,
- Backend,
- DatabaseTransaction,
- RecordGetRequest,
- ResultLevel,
-} from "./backend-interface";
-
-const confirmActiveTransaction = (
- index: BridgeIDBIndex,
-): BridgeIDBTransaction => {
- if (index._deleted || index.objectStore._deleted) {
- throw new InvalidStateError();
- }
-
- if (index.objectStore.transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- return index.objectStore.transaction;
-};
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
-/** @public */
-export class BridgeIDBIndex {
- objectStore: BridgeIDBObjectStore;
-
- get _schema(): Schema {
- return this.objectStore.transaction.db._schema;
- }
-
- get keyPath(): KeyPath {
- return this._schema.objectStores[this.objectStore.name].indexes[this._name]
- .keyPath;
- }
-
- get multiEntry(): boolean {
- return this._schema.objectStores[this.objectStore.name].indexes[this._name]
- .multiEntry;
- }
-
- get unique(): boolean {
- return this._schema.objectStores[this.objectStore.name].indexes[this._name]
- .unique;
- }
-
- get _backend(): Backend {
- return this.objectStore._backend;
- }
-
- _confirmActiveTransaction(): { btx: DatabaseTransaction } {
- return this.objectStore._confirmActiveTransaction();
- }
-
- private _name: string;
-
- public _deleted: boolean = false;
-
- constructor(objectStore: BridgeIDBObjectStore, name: string) {
- this._name = name;
- this.objectStore = objectStore;
- }
-
- get name() {
- return this._name;
- }
-
- // https://w3c.github.io/IndexedDB/#dom-idbindex-name
- set name(name: any) {
- const transaction = this.objectStore.transaction;
-
- if (!transaction.db._runningVersionchangeTransaction) {
- throw new InvalidStateError();
- }
-
- if (transaction._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- const { btx } = this._confirmActiveTransaction();
-
- const oldName = this._name;
- const newName = String(name);
-
- if (newName === oldName) {
- return;
- }
-
- this._backend.renameIndex(btx, this.objectStore.name, oldName, newName);
-
- if (this.objectStore.indexNames.indexOf(name) >= 0) {
- throw new ConstraintError();
- }
- }
-
- // tslint:disable-next-line max-line-length
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openCursor-IDBRequest-any-range-IDBCursorDirection-direction
- public openCursor(
- range?: BridgeIDBKeyRange | Key | null | undefined,
- direction: BridgeIDBCursorDirection = "next",
- ) {
- confirmActiveTransaction(this);
-
- if (range === null) {
- range = undefined;
- }
- if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
- range = BridgeIDBKeyRange.only(valueToKey(range));
- }
-
- const request = new BridgeIDBRequest();
- request.source = this;
- request.transaction = this.objectStore.transaction;
-
- const cursor = new BridgeIDBCursorWithValue(
- this,
- this.objectStore.name,
- this._name,
- range,
- direction,
- request,
- );
-
- const operation = async () => {
- return cursor._iterate();
- };
-
- return this.objectStore.transaction._execRequestAsync({
- operation,
- request,
- source: this,
- });
- }
-
- // tslint:disable-next-line max-line-length
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openKeyCursor-IDBRequest-any-range-IDBCursorDirection-direction
- public openKeyCursor(
- range?: BridgeIDBKeyRange | Key | null | undefined,
- direction: BridgeIDBCursorDirection = "next",
- ) {
- confirmActiveTransaction(this);
-
- if (range === null) {
- range = undefined;
- }
- if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
- range = BridgeIDBKeyRange.only(valueToKey(range));
- }
-
- const request = new BridgeIDBRequest();
- request.source = this;
- request.transaction = this.objectStore.transaction;
-
- const cursor = new BridgeIDBCursor(
- this,
- this.objectStore.name,
- this._name,
- range,
- direction,
- request,
- true,
- );
-
- return this.objectStore.transaction._execRequestAsync({
- operation: cursor._iterate.bind(cursor),
- request,
- source: this,
- });
- }
-
- public get(key: BridgeIDBKeyRange | Key) {
- confirmActiveTransaction(this);
-
- if (!(key instanceof BridgeIDBKeyRange)) {
- key = BridgeIDBKeyRange._valueToKeyRange(key);
- }
-
- const getReq: RecordGetRequest = {
- direction: "next",
- indexName: this._name,
- limit: 1,
- range: key,
- objectStoreName: this.objectStore._name,
- resultLevel: ResultLevel.Full,
- };
-
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.getRecords(btx, getReq);
- if (result.count == 0) {
- return undefined;
- }
- const values = result.values;
- if (!values) {
- throw Error("invariant violated");
- }
- return values[0];
- };
-
- return this.objectStore.transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbindex-getall
- public getAll(query?: BridgeIDBKeyRange | Key, count?: number) {
- throw Error("not implemented");
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-getKey-IDBRequest-any-key
- public getKey(key: BridgeIDBKeyRange | Key) {
- confirmActiveTransaction(this);
-
- if (!(key instanceof BridgeIDBKeyRange)) {
- key = BridgeIDBKeyRange._valueToKeyRange(key);
- }
-
- const getReq: RecordGetRequest = {
- direction: "next",
- indexName: this._name,
- limit: 1,
- range: key,
- objectStoreName: this.objectStore._name,
- resultLevel: ResultLevel.OnlyKeys,
- };
-
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.getRecords(btx, getReq);
- if (result.count == 0) {
- return undefined;
- }
- const primaryKeys = result.primaryKeys;
- if (!primaryKeys) {
- throw Error("invariant violated");
- }
- return primaryKeys[0];
- };
-
- return this.objectStore.transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
- public getAllKeys(query?: BridgeIDBKeyRange | Key, count?: number) {
- throw Error("not implemented");
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-count-IDBRequest-any-key
- public count(key: BridgeIDBKeyRange | Key | null | undefined) {
- confirmActiveTransaction(this);
-
- if (key === null) {
- key = undefined;
- }
- if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
- key = BridgeIDBKeyRange.only(valueToKey(key));
- }
-
- const getReq: RecordGetRequest = {
- direction: "next",
- indexName: this._name,
- limit: 1,
- range: key,
- objectStoreName: this.objectStore._name,
- resultLevel: ResultLevel.OnlyCount,
- };
-
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.getRecords(btx, getReq);
- return result.count;
- };
-
- return this.objectStore.transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- public toString() {
- return "[object IDBIndex]";
- }
-}
-
-export default BridgeIDBIndex;
diff --git a/packages/idb-bridge/src/BridgeIDBKeyRange.ts b/packages/idb-bridge/src/BridgeIDBKeyRange.ts
deleted file mode 100644
index d2eaa2d1b..000000000
--- a/packages/idb-bridge/src/BridgeIDBKeyRange.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- Copyright 2019 Florian Dold
- Copyright 2017 Jeremy Scheff
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import compareKeys from "./util/cmp";
-import { DataError } from "./util/errors";
-import { Key } from "./util/types";
-import valueToKey from "./util/valueToKey";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#range-concept
-/** @public */
-export class BridgeIDBKeyRange {
- public static only(value: Key) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- value = valueToKey(value);
- return new BridgeIDBKeyRange(value, value, false, false);
- }
-
- static lowerBound(lower: Key, open: boolean = false) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- lower = valueToKey(lower);
- return new BridgeIDBKeyRange(lower, undefined, open, true);
- }
-
- static upperBound(upper: Key, open: boolean = false) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- upper = valueToKey(upper);
- return new BridgeIDBKeyRange(undefined, upper, true, open);
- }
-
- static bound(
- lower: Key,
- upper: Key,
- lowerOpen: boolean = false,
- upperOpen: boolean = false,
- ) {
- if (arguments.length < 2) {
- throw new TypeError();
- }
-
- const cmpResult = compareKeys(lower, upper);
- if (cmpResult === 1 || (cmpResult === 0 && (lowerOpen || upperOpen))) {
- throw new DataError();
- }
-
- lower = valueToKey(lower);
- upper = valueToKey(upper);
- return new BridgeIDBKeyRange(lower, upper, lowerOpen, upperOpen);
- }
-
- readonly lower: Key | undefined;
- readonly upper: Key | undefined;
- readonly lowerOpen: boolean;
- readonly upperOpen: boolean;
-
- constructor(
- lower: Key | undefined,
- upper: Key | undefined,
- lowerOpen: boolean,
- upperOpen: boolean,
- ) {
- this.lower = lower;
- this.upper = upper;
- this.lowerOpen = lowerOpen;
- this.upperOpen = upperOpen;
- }
-
- // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes
- includes(key: Key) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- key = valueToKey(key);
-
- if (this.lower !== undefined) {
- const cmpResult = compareKeys(this.lower, key);
-
- if (cmpResult === 1 || (cmpResult === 0 && this.lowerOpen)) {
- return false;
- }
- }
- if (this.upper !== undefined) {
- const cmpResult = compareKeys(this.upper, key);
-
- if (cmpResult === -1 || (cmpResult === 0 && this.upperOpen)) {
- return false;
- }
- }
- return true;
- }
-
- toString() {
- return "[object IDBKeyRange]";
- }
-
- static _valueToKeyRange(value: any, nullDisallowedFlag: boolean = false) {
- if (value instanceof BridgeIDBKeyRange) {
- return value;
- }
-
- if (value === null || value === undefined) {
- if (nullDisallowedFlag) {
- throw new DataError();
- }
- return new BridgeIDBKeyRange(undefined, undefined, false, false);
- }
-
- const key = valueToKey(value);
-
- return BridgeIDBKeyRange.only(key);
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBObjectStore.ts b/packages/idb-bridge/src/BridgeIDBObjectStore.ts
deleted file mode 100644
index 6fdf35200..000000000
--- a/packages/idb-bridge/src/BridgeIDBObjectStore.ts
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- Copyright 2019 Florian Dold
- Copyright 2017 Jeremy Scheff
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-
-import {
- ConstraintError,
- InvalidAccessError,
- InvalidStateError,
- ReadOnlyError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import {
- FakeDOMStringList,
- BridgeIDBCursorDirection,
- Key,
- KeyPath,
- Value,
-} from "./util/types";
-import validateKeyPath from "./util/validateKeyPath";
-import valueToKey from "./util/valueToKey";
-import {
- DatabaseTransaction,
- RecordGetRequest,
- ResultLevel,
- StoreLevel,
- Schema,
- Backend,
- DatabaseConnection,
-} from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
-/** @public */
-export class BridgeIDBObjectStore {
- _indexesCache: Map<string, BridgeIDBIndex> = new Map();
-
- transaction: BridgeIDBTransaction;
-
- get autoIncrement(): boolean {
- return this._schema.objectStores[this._name].autoIncrement;
- }
-
- get indexNames(): FakeDOMStringList {
- return fakeDOMStringList(
- Object.keys(this._schema.objectStores[this._name].indexes),
- ).sort();
- }
-
- get keyPath(): KeyPath | null {
- return this._schema.objectStores[this._name].keyPath;
- }
-
- _name: string;
-
- get _schema(): Schema {
- return this.transaction.db._schema;
- }
-
- _deleted: boolean = false;
-
- constructor(transaction: BridgeIDBTransaction, name: string) {
- this._name = name;
- this.transaction = transaction;
- }
-
- get name() {
- return this._name;
- }
-
- get _backend(): Backend {
- return this.transaction.db._backend;
- }
-
- get _backendConnection(): DatabaseConnection {
- return this.transaction.db._backendConnection;
- }
-
- _confirmActiveTransaction(): { btx: DatabaseTransaction } {
- const btx = this.transaction._backendTransaction;
- if (!btx) {
- throw new InvalidStateError();
- }
- return { btx };
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
- set name(newName: any) {
- const transaction = this.transaction;
-
- if (!transaction.db._runningVersionchangeTransaction) {
- throw new InvalidStateError();
- }
-
- let { btx } = this._confirmActiveTransaction();
-
- newName = String(newName);
-
- const oldName = this._name;
-
- if (newName === oldName) {
- return;
- }
-
- this._backend.renameObjectStore(btx, oldName, newName);
- this.transaction.db._schema = this._backend.getSchema(
- this._backendConnection,
- );
- }
-
- public _store(value: Value, key: Key | undefined, overwrite: boolean) {
- if (BridgeIDBFactory.enableTracing) {
- console.log(`TRACE: IDBObjectStore._store`);
- }
- if (this.transaction.mode === "readonly") {
- throw new ReadOnlyError();
- }
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.storeRecord(btx, {
- objectStoreName: this._name,
- key: key,
- value: value,
- storeLevel: overwrite
- ? StoreLevel.AllowOverwrite
- : StoreLevel.NoOverwrite,
- });
- return result.key;
- };
-
- return this.transaction._execRequestAsync({ operation, source: this });
- }
-
- public put(value: Value, key?: Key) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- return this._store(value, key, true);
- }
-
- public add(value: Value, key?: Key) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
- return this._store(value, key, false);
- }
-
- public delete(key: Key | BridgeIDBKeyRange) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
-
- if (this.transaction.mode === "readonly") {
- throw new ReadOnlyError();
- }
-
- let keyRange: BridgeIDBKeyRange;
-
- if (key instanceof BridgeIDBKeyRange) {
- keyRange = key;
- } else {
- keyRange = BridgeIDBKeyRange.only(valueToKey(key));
- }
-
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- return this._backend.deleteRecord(btx, this._name, keyRange);
- };
-
- return this.transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- public get(key?: BridgeIDBKeyRange | Key) {
- if (BridgeIDBFactory.enableTracing) {
- console.log(`getting from object store ${this._name} key ${key}`);
- }
-
- if (arguments.length === 0) {
- throw new TypeError();
- }
-
- let keyRange: BridgeIDBKeyRange;
-
- if (key instanceof BridgeIDBKeyRange) {
- keyRange = key;
- } else {
- try {
- keyRange = BridgeIDBKeyRange.only(valueToKey(key));
- } catch (e) {
- throw Error(
- `invalid key (type ${typeof key}) for object store ${this._name}`,
- );
- }
- }
-
- const recordRequest: RecordGetRequest = {
- objectStoreName: this._name,
- indexName: undefined,
- lastIndexPosition: undefined,
- lastObjectStorePosition: undefined,
- direction: "next",
- limit: 1,
- resultLevel: ResultLevel.Full,
- range: keyRange,
- };
-
- const operation = async () => {
- if (BridgeIDBFactory.enableTracing) {
- console.log("running get operation:", recordRequest);
- }
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.getRecords(btx, recordRequest);
-
- if (BridgeIDBFactory.enableTracing) {
- console.log("get operation result count:", result.count);
- }
-
- if (result.count === 0) {
- return undefined;
- }
- const values = result.values;
- if (!values) {
- throw Error("invariant violated");
- }
- return values[0];
- };
-
- return this.transaction._execRequestAsync({
- operation,
- source: this,
- });
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
- public getAll(query?: BridgeIDBKeyRange | Key, count?: number) {
- throw Error("not implemented");
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
- public getKey(key?: BridgeIDBKeyRange | Key) {
- throw Error("not implemented");
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
- public getAllKeys(query?: BridgeIDBKeyRange | Key, count?: number) {
- throw Error("not implemented");
- }
-
- public clear() {
- throw Error("not implemented");
- }
-
- public openCursor(
- range?: BridgeIDBKeyRange | Key,
- direction: BridgeIDBCursorDirection = "next",
- ) {
- if (range === null) {
- range = undefined;
- }
- if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
- range = BridgeIDBKeyRange.only(valueToKey(range));
- }
-
- const request = new BridgeIDBRequest();
- request.source = this;
- request.transaction = this.transaction;
-
- const cursor = new BridgeIDBCursorWithValue(
- this,
- this._name,
- undefined,
- range,
- direction,
- request,
- );
-
- return this.transaction._execRequestAsync({
- operation: () => cursor._iterate(),
- request,
- source: this,
- });
- }
-
- public openKeyCursor(
- range?: BridgeIDBKeyRange | Key,
- direction?: BridgeIDBCursorDirection,
- ) {
- if (range === null) {
- range = undefined;
- }
- if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
- range = BridgeIDBKeyRange.only(valueToKey(range));
- }
-
- if (!direction) {
- direction = "next";
- }
-
- const request = new BridgeIDBRequest();
- request.source = this;
- request.transaction = this.transaction;
-
- const cursor = new BridgeIDBCursor(
- this,
- this._name,
- undefined,
- range,
- direction,
- request,
- true,
- );
-
- return this.transaction._execRequestAsync({
- operation: cursor._iterate.bind(cursor),
- request,
- source: this,
- });
- }
-
- // tslint:disable-next-line max-line-length
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-createIndex-IDBIndex-DOMString-name-DOMString-sequence-DOMString--keyPath-IDBIndexParameters-optionalParameters
- public createIndex(
- indexName: string,
- keyPath: KeyPath,
- optionalParameters: { multiEntry?: boolean; unique?: boolean } = {},
- ) {
- if (arguments.length < 2) {
- throw new TypeError();
- }
-
- if (!this.transaction.db._runningVersionchangeTransaction) {
- throw new InvalidStateError();
- }
-
- const { btx } = this._confirmActiveTransaction();
-
- const multiEntry =
- optionalParameters.multiEntry !== undefined
- ? optionalParameters.multiEntry
- : false;
- const unique =
- optionalParameters.unique !== undefined
- ? optionalParameters.unique
- : false;
-
- if (this.transaction.mode !== "versionchange") {
- throw new InvalidStateError();
- }
-
- if (this.indexNames.indexOf(indexName) >= 0) {
- throw new ConstraintError();
- }
-
- validateKeyPath(keyPath);
-
- if (Array.isArray(keyPath) && multiEntry) {
- throw new InvalidAccessError();
- }
-
- this._backend.createIndex(
- btx,
- indexName,
- this._name,
- keyPath,
- multiEntry,
- unique,
- );
-
- return new BridgeIDBIndex(this, indexName);
- }
-
- // https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
- public index(name: string) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
-
- if (this.transaction._state === "finished") {
- throw new InvalidStateError();
- }
-
- const index = this._indexesCache.get(name);
- if (index !== undefined) {
- return index;
- }
-
- return new BridgeIDBIndex(this, name);
- }
-
- public deleteIndex(indexName: string) {
- if (arguments.length === 0) {
- throw new TypeError();
- }
-
- if (this.transaction.mode !== "versionchange") {
- throw new InvalidStateError();
- }
-
- if (!this.transaction.db._runningVersionchangeTransaction) {
- throw new InvalidStateError();
- }
-
- const { btx } = this._confirmActiveTransaction();
-
- const index = this._indexesCache.get(indexName);
- if (index !== undefined) {
- index._deleted = true;
- }
-
- this._backend.deleteIndex(btx, this._name, indexName);
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-count-IDBRequest-any-key
- public count(key?: Key | BridgeIDBKeyRange) {
- if (key === null) {
- key = undefined;
- }
- if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
- key = BridgeIDBKeyRange.only(valueToKey(key));
- }
-
- const recordGetRequest: RecordGetRequest = {
- direction: "next",
- indexName: undefined,
- lastIndexPosition: undefined,
- limit: -1,
- objectStoreName: this._name,
- lastObjectStorePosition: undefined,
- range: key,
- resultLevel: ResultLevel.OnlyCount,
- };
-
- const operation = async () => {
- const { btx } = this._confirmActiveTransaction();
- const result = await this._backend.getRecords(btx, recordGetRequest);
- return result.count;
- };
-
- return this.transaction._execRequestAsync({ operation, source: this });
- }
-
- public toString() {
- return "[object IDBObjectStore]";
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts b/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts
deleted file mode 100644
index 306edcb7d..000000000
--- a/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- Copyright 2019 Florian Dold
- Copyright 2017 Jeremy Scheff
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
-*/
-
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { EventListener } from "./idbtypes";
-
-/** @public */
-export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
- public onupgradeneeded: EventListener | null = null;
- public onblocked: EventListener | null = null;
-
- constructor() {
- super();
- // https://www.w3.org/TR/IndexedDB/#open-requests
- this.source = null;
- }
-
- public toString() {
- return "[object IDBOpenDBRequest]";
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBRequest.ts b/packages/idb-bridge/src/BridgeIDBRequest.ts
deleted file mode 100644
index 4800a0582..000000000
--- a/packages/idb-bridge/src/BridgeIDBRequest.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- * Copyright 2019 Florian Dold
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-import { BridgeIDBCursor as BridgeFIBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { InvalidStateError } from "./util/errors";
-import FakeEventTarget from "./util/FakeEventTarget";
-import FakeEvent from "./util/FakeEvent";
-import { EventListener } from "./idbtypes";
-
-/** @public */
-export class BridgeIDBRequest extends FakeEventTarget {
- _result: any = null;
- _error: Error | null | undefined = null;
- source: BridgeFIBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null = null;
- transaction: BridgeIDBTransaction | null = null;
- readyState: "done" | "pending" = "pending";
- onsuccess: EventListener | null = null;
- onerror: EventListener | null = null;
-
- get error() {
- if (this.readyState === "pending") {
- throw new InvalidStateError();
- }
- return this._error;
- }
-
- set error(value: any) {
- this._error = value;
- }
-
- get result() {
- if (this.readyState === "pending") {
- throw new InvalidStateError();
- }
- return this._result;
- }
-
- set result(value: any) {
- this._result = value;
- }
-
- toString() {
- return "[object IDBRequest]";
- }
-
- _finishWithError(err: Error) {
- this.result = undefined;
- this.readyState = "done";
-
- this.error = new Error(err.message);
- this.error.name = err.name;
-
- const event = new FakeEvent("error", {
- bubbles: true,
- cancelable: true,
- });
- event.eventPath = [];
- this.dispatchEvent(event);
- }
-
- _finishWithResult(result: any) {
- this.result = result;
- this.readyState = "done";
-
- const event = new FakeEvent("success");
- event.eventPath = [];
- this.dispatchEvent(event);
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBTransaction.ts b/packages/idb-bridge/src/BridgeIDBTransaction.ts
deleted file mode 100644
index b064d069e..000000000
--- a/packages/idb-bridge/src/BridgeIDBTransaction.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import {
- AbortError,
- InvalidStateError,
- NotFoundError,
- TransactionInactiveError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import FakeEvent from "./util/FakeEvent";
-import FakeEventTarget from "./util/FakeEventTarget";
-import { FakeDOMStringList, RequestObj, TransactionMode } from "./util/types";
-import queueTask from "./util/queueTask";
-import openPromise from "./util/openPromise";
-import { DatabaseTransaction, Backend } from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-import { EventListener } from "./idbtypes";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
-/** @public */
-export class BridgeIDBTransaction extends FakeEventTarget {
- public _state: "active" | "inactive" | "committing" | "finished" = "active";
- public _started = false;
- public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
-
- public _backendTransaction?: DatabaseTransaction;
-
- public objectStoreNames: FakeDOMStringList;
- public mode: TransactionMode;
- public db: BridgeIDBDatabase;
- public error: Error | null = null;
- public onabort: EventListener | null = null;
- public oncomplete: EventListener | null = null;
- public onerror: EventListener | null = null;
-
- private _waitPromise: Promise<void>;
- private _resolveWait: () => void;
-
- public _scope: Set<string>;
- private _requests: Array<{
- operation: () => void;
- request: BridgeIDBRequest;
- }> = [];
-
- get _backend(): Backend {
- return this.db._backend;
- }
-
- constructor(
- storeNames: string[],
- mode: TransactionMode,
- db: BridgeIDBDatabase,
- backendTransaction?: DatabaseTransaction,
- ) {
- super();
-
- const myOpenPromise = openPromise<void>();
- this._waitPromise = myOpenPromise.promise;
- this._resolveWait = myOpenPromise.resolve;
-
- this._scope = new Set(storeNames);
- this._backendTransaction = backendTransaction;
- this.mode = mode;
- this.db = db;
- this.objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
-
- this.db._transactions.push(this);
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
- async _abort(errName: string | null) {
- this._state = "finished";
-
- if (errName !== null) {
- const e = new Error();
- e.name = errName;
- this.error = e;
- }
-
- // Should this directly remove from _requests?
- for (const { request } of this._requests) {
- if (request.readyState !== "done") {
- request.readyState = "done"; // This will cancel execution of this request's operation
- if (request.source) {
- request.result = undefined;
- request.error = new AbortError();
-
- const event = new FakeEvent("error", {
- bubbles: true,
- cancelable: true,
- });
- event.eventPath = [this.db, this];
- request.dispatchEvent(event);
- }
- }
- }
-
- // Only roll back if we actually executed the scheduled operations.
- const maybeBtx = this._backendTransaction;
- if (maybeBtx) {
- await this._backend.rollback(maybeBtx);
- }
-
- queueTask(() => {
- const event = new FakeEvent("abort", {
- bubbles: true,
- cancelable: false,
- });
- event.eventPath = [this.db];
- this.dispatchEvent(event);
- });
- }
-
- public abort() {
- if (this._state === "committing" || this._state === "finished") {
- throw new InvalidStateError();
- }
- this._state = "active";
-
- this._abort(null);
- }
-
- // http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
- public objectStore(name: string) {
- if (this._state !== "active") {
- throw new InvalidStateError();
- }
-
- const objectStore = this._objectStoresCache.get(name);
- if (objectStore !== undefined) {
- return objectStore;
- }
-
- return new BridgeIDBObjectStore(this, name);
- }
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-asynchronously-executing-a-request
- public _execRequestAsync(obj: RequestObj) {
- const source = obj.source;
- const operation = obj.operation;
- let request = obj.hasOwnProperty("request") ? obj.request : null;
-
- if (this._state !== "active") {
- throw new TransactionInactiveError();
- }
-
- // Request should only be passed for cursors
- if (!request) {
- if (!source) {
- // Special requests like indexes that just need to run some code
- request = new BridgeIDBRequest();
- } else {
- request = new BridgeIDBRequest();
- request.source = source;
- request.transaction = (source as any).transaction;
- }
- }
-
- this._requests.push({
- operation,
- request,
- });
-
- return request;
- }
-
- /**
- * Actually execute the scheduled work for this transaction.
- */
- public async _start() {
- if (BridgeIDBFactory.enableTracing) {
- console.log(
- `TRACE: IDBTransaction._start, ${this._requests.length} queued`,
- );
- }
- this._started = true;
-
- if (!this._backendTransaction) {
- this._backendTransaction = await this._backend.beginTransaction(
- this.db._backendConnection,
- Array.from(this._scope),
- this.mode,
- );
- }
-
- // Remove from request queue - cursor ones will be added back if necessary by cursor.continue and such
- let operation;
- let request;
- while (this._requests.length > 0) {
- const r = this._requests.shift();
-
- // This should only be false if transaction was aborted
- if (r && r.request.readyState !== "done") {
- request = r.request;
- operation = r.operation;
- break;
- }
- }
-
- if (request && operation) {
- if (!request.source) {
- // Special requests like indexes that just need to run some code, with error handling already built into
- // operation
- await operation();
- } else {
- let event;
- try {
- BridgeIDBFactory.enableTracing &&
- console.log("TRACE: running operation in transaction");
- const result = await operation();
- BridgeIDBFactory.enableTracing &&
- console.log(
- "TRACE: operation in transaction finished with success",
- );
- request.readyState = "done";
- request.result = result;
- request.error = undefined;
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-a-success-event
- if (this._state === "inactive") {
- this._state = "active";
- }
- event = new FakeEvent("success", {
- bubbles: false,
- cancelable: false,
- });
-
- try {
- event.eventPath = [request, this, this.db];
- request.dispatchEvent(event);
- } catch (err) {
- if (this._state !== "committing") {
- this._abort("AbortError");
- }
- throw err;
- }
- } catch (err) {
- if (BridgeIDBFactory.enableTracing) {
- console.log("TRACING: error during operation: ", err);
- }
- request.readyState = "done";
- request.result = undefined;
- request.error = err;
-
- // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
- if (this._state === "inactive") {
- this._state = "active";
- }
- event = new FakeEvent("error", {
- bubbles: true,
- cancelable: true,
- });
-
- try {
- event.eventPath = [this.db, this];
- request.dispatchEvent(event);
- } catch (err) {
- if (this._state !== "committing") {
- this._abort("AbortError");
- }
- throw err;
- }
- if (!event.canceled) {
- this._abort(err.name);
- }
- }
- }
-
- // On to the next one
- if (this._requests.length > 0) {
- this._start();
- } else {
- // Give it another chance for new handlers to be set before finishing
- queueTask(() => this._start());
- }
- return;
- }
-
- if (this._state !== "finished" && this._state !== "committing") {
- if (BridgeIDBFactory.enableTracing) {
- console.log("finishing transaction");
- }
-
- this._state = "committing";
-
- await this._backend.commit(this._backendTransaction);
-
- this._state = "finished";
-
- if (!this.error) {
- if (BridgeIDBFactory.enableTracing) {
- console.log("dispatching 'complete' event on transaction");
- }
- const event = new FakeEvent("complete");
- event.eventPath = [this, this.db];
- this.dispatchEvent(event);
- }
-
- const idx = this.db._transactions.indexOf(this);
- if (idx < 0) {
- throw Error("invariant failed");
- }
- this.db._transactions.splice(idx, 1);
-
- this._resolveWait();
- }
- }
-
- public commit() {
- if (this._state !== "active") {
- throw new InvalidStateError();
- }
-
- this._state = "committing";
- // We now just wait for auto-commit ...
- }
-
- public toString() {
- return "[object IDBRequest]";
- }
-
- _waitDone(): Promise<void> {
- return this._waitPromise;
- }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts b/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts
deleted file mode 100644
index 43e822d86..000000000
--- a/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- Copyright 2019 Florian Dold
- Copyright 2017 Jeremy Scheff
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
- */
-
-import FakeEvent from "./util/FakeEvent";
-
-export class BridgeIDBVersionChangeEvent extends FakeEvent {
- public newVersion: number | null;
- public oldVersion: number;
-
- constructor(
- type: "blocked" | "success" | "upgradeneeded" | "versionchange",
- parameters: { newVersion?: number | null; oldVersion?: number } = {},
- ) {
- super(type);
-
- this.newVersion =
- parameters.newVersion !== undefined ? parameters.newVersion : null;
- this.oldVersion =
- parameters.oldVersion !== undefined ? parameters.oldVersion : 0;
- }
-
- public toString() {
- return "[object IDBVersionChangeEvent]";
- }
-}
diff --git a/packages/idb-bridge/src/MemoryBackend.test.ts b/packages/idb-bridge/src/MemoryBackend.test.ts
index 737b83d9c..281a72e36 100644
--- a/packages/idb-bridge/src/MemoryBackend.test.ts
+++ b/packages/idb-bridge/src/MemoryBackend.test.ts
@@ -15,13 +15,15 @@
*/
import test from "ava";
+import {
+ BridgeIDBCursorWithValue,
+ BridgeIDBDatabase,
+ BridgeIDBFactory,
+ BridgeIDBKeyRange,
+ BridgeIDBRequest,
+ BridgeIDBTransaction,
+} from "./bridge-idb";
import MemoryBackend from "./MemoryBackend";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
function promiseFromRequest(request: BridgeIDBRequest): Promise<any> {
return new Promise((resolve, reject) => {
diff --git a/packages/idb-bridge/src/MemoryBackend.ts b/packages/idb-bridge/src/MemoryBackend.ts
index 531a7f299..6a52a555f 100644
--- a/packages/idb-bridge/src/MemoryBackend.ts
+++ b/packages/idb-bridge/src/MemoryBackend.ts
@@ -36,11 +36,14 @@ import {
} from "./util/errors";
import BTree, { ISortedMapF } from "./tree/b+tree";
import compareKeys from "./util/cmp";
-import { Key, Value, KeyPath, TransactionMode } from "./util/types";
import { StoreKeyResult, makeStoreKeyValue } from "./util/makeStoreKeyValue";
import getIndexKeys from "./util/getIndexKeys";
import openPromise from "./util/openPromise";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
+import { IDBKeyPath, IDBKeyRange, IDBTransactionMode, IDBValidKey } from "./idbtypes";
+import { BridgeIDBKeyRange } from "./bridge-idb";
+
+type Key = IDBValidKey;
+type Value = unknown;
enum TransactionLevel {
Disconnected = 0,
@@ -476,7 +479,7 @@ export class MemoryBackend implements Backend {
async beginTransaction(
conn: DatabaseConnection,
objectStores: string[],
- mode: TransactionMode,
+ mode: IDBTransactionMode,
): Promise<DatabaseTransaction> {
if (this.enableTracing) {
console.log(`TRACING: beginTransaction`);
@@ -773,6 +776,9 @@ export class MemoryBackend implements Backend {
if (!schema) {
throw Error("no schema for versionchange tx");
}
+ if (Array.isArray(keyPath)) {
+ throw Error("array key path not supported for object stores");
+ }
schema.objectStores[name] = {
autoIncrement,
keyPath,
@@ -785,7 +791,7 @@ export class MemoryBackend implements Backend {
btx: DatabaseTransaction,
indexName: string,
objectStoreName: string,
- keyPath: KeyPath,
+ keyPath: IDBKeyPath,
multiEntry: boolean,
unique: boolean,
): void {
@@ -843,7 +849,7 @@ export class MemoryBackend implements Backend {
async deleteRecord(
btx: DatabaseTransaction,
objectStoreName: string,
- range: BridgeIDBKeyRange,
+ range: IDBKeyRange,
): Promise<void> {
if (this.enableTracing) {
console.log(`TRACING: deleteRecord from store ${objectStoreName}`);
@@ -900,6 +906,10 @@ export class MemoryBackend implements Backend {
}
}
+ if (currKey === undefined) {
+ throw Error("invariant violated");
+ }
+
// make sure that currKey is either undefined or pointing to an
// existing object.
let firstValue = modifiedData.get(currKey);
@@ -1112,6 +1122,10 @@ export class MemoryBackend implements Backend {
indexPos = forward ? indexData.minKey() : indexData.maxKey();
}
+ if (indexPos === undefined) {
+ throw Error("invariant violated");
+ }
+
let indexEntry: IndexRecord | undefined;
indexEntry = indexData.get(indexPos);
if (!indexEntry) {
@@ -1191,13 +1205,13 @@ export class MemoryBackend implements Backend {
primkeySubPos < 0 ||
primkeySubPos >= indexEntry.primaryKeys.length
) {
- const res = forward
+ const res: any = forward
? indexData.nextHigherPair(indexPos)
: indexData.nextLowerPair(indexPos);
if (res) {
indexPos = res[1].indexKey;
indexEntry = res[1];
- primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
+ primkeySubPos = forward ? 0 : indexEntry!.primaryKeys.length - 1;
continue;
} else {
break;
diff --git a/packages/idb-bridge/src/backend-interface.ts b/packages/idb-bridge/src/backend-interface.ts
index 4d1f107ba..756a5b967 100644
--- a/packages/idb-bridge/src/backend-interface.ts
+++ b/packages/idb-bridge/src/backend-interface.ts
@@ -14,26 +14,25 @@
permissions and limitations under the License.
*/
+import { BridgeIDBDatabaseInfo, BridgeIDBKeyRange } from "./bridge-idb";
import {
- TransactionMode,
- Value,
- BridgeIDBCursorDirection,
- Key,
- KeyPath,
- BridgeIDBDatabaseInfo,
-} from "./util/types";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
+ IDBCursorDirection,
+ IDBKeyPath,
+ IDBTransactionMode,
+ IDBValidKey,
+} from "./idbtypes";
+
/** @public */
export interface ObjectStoreProperties {
- keyPath: KeyPath | null;
+ keyPath: IDBKeyPath | null;
autoIncrement: boolean;
indexes: { [nameame: string]: IndexProperties };
}
/** @public */
export interface IndexProperties {
- keyPath: KeyPath;
+ keyPath: IDBKeyPath;
multiEntry: boolean;
unique: boolean;
}
@@ -71,7 +70,7 @@ export enum StoreLevel {
/** @public */
export interface RecordGetRequest {
- direction: BridgeIDBCursorDirection;
+ direction: IDBCursorDirection;
objectStoreName: string;
indexName: string | undefined;
/**
@@ -79,7 +78,7 @@ export interface RecordGetRequest {
* If indexName is defined, the range refers to the index keys.
* Otherwise it refers to the object store keys.
*/
- range: BridgeIDBKeyRange | undefined;
+ range: BridgeIDBKeyRange | undefined | null;
/**
* Last cursor position in terms of the index key.
* Can only be specified if indexName is defined and
@@ -87,23 +86,23 @@ export interface RecordGetRequest {
*
* Must either be undefined or within range.
*/
- lastIndexPosition?: Key;
+ lastIndexPosition?: IDBValidKey;
/**
* Last position in terms of the object store key.
*/
- lastObjectStorePosition?: Key;
+ lastObjectStorePosition?: IDBValidKey;
/**
* If specified, the index key of the results must be
* greater or equal to advanceIndexKey.
*
* Only applicable if indexName is specified.
*/
- advanceIndexKey?: Key;
+ advanceIndexKey?: IDBValidKey;
/**
* If specified, the primary key of the results must be greater
* or equal to advancePrimaryKey.
*/
- advancePrimaryKey?: Key;
+ advancePrimaryKey?: IDBValidKey;
/**
* Maximum number of resuts to return.
* If -1, return all available results
@@ -114,17 +113,17 @@ export interface RecordGetRequest {
/** @public */
export interface RecordGetResponse {
- values: Value[] | undefined;
- indexKeys: Key[] | undefined;
- primaryKeys: Key[] | undefined;
+ values: any[] | undefined;
+ indexKeys: IDBValidKey[] | undefined;
+ primaryKeys: IDBValidKey[] | undefined;
count: number;
}
/** @public */
export interface RecordStoreRequest {
objectStoreName: string;
- value: Value;
- key: Key | undefined;
+ value: any;
+ key: IDBValidKey | undefined;
storeLevel: StoreLevel;
}
@@ -133,7 +132,7 @@ export interface RecordStoreResponse {
/**
* Key that the record was stored under in the object store.
*/
- key: Key;
+ key: IDBValidKey;
}
/** @public */
@@ -145,7 +144,7 @@ export interface Backend {
beginTransaction(
conn: DatabaseConnection,
objectStores: string[],
- mode: TransactionMode,
+ mode: IDBTransactionMode,
): Promise<DatabaseTransaction>;
enterVersionChange(
@@ -200,7 +199,7 @@ export interface Backend {
btx: DatabaseTransaction,
indexName: string,
objectStoreName: string,
- keyPath: KeyPath,
+ keyPath: IDBKeyPath,
multiEntry: boolean,
unique: boolean,
): void;
diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts
new file mode 100644
index 000000000..2bced800d
--- /dev/null
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -0,0 +1,2053 @@
+/*
+ Copyright 2017 Jeremy Scheff
+ Copyright 2019-2021 Taler Systems S.A.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ or implied. See the License for the specific language governing
+ permissions and limitations under the License.
+ */
+
+import {
+ Backend,
+ DatabaseConnection,
+ DatabaseTransaction,
+ RecordGetRequest,
+ RecordStoreRequest,
+ ResultLevel,
+ Schema,
+ StoreLevel,
+} from "./backend-interface";
+import { EventListener, IDBCursorDirection, IDBKeyPath, IDBKeyRange, IDBTransactionMode, IDBValidKey } from "./idbtypes";
+import compareKeys from "./util/cmp";
+import enforceRange from "./util/enforceRange";
+import {
+ AbortError,
+ ConstraintError,
+ DataError,
+ InvalidAccessError,
+ InvalidStateError,
+ NotFoundError,
+ ReadOnlyError,
+ TransactionInactiveError,
+ VersionError,
+} from "./util/errors";
+import { fakeDOMStringList } from "./util/fakeDOMStringList";
+import FakeEvent from "./util/FakeEvent";
+import FakeEventTarget from "./util/FakeEventTarget";
+import openPromise from "./util/openPromise";
+import queueTask from "./util/queueTask";
+import structuredClone from "./util/structuredClone";
+import validateKeyPath from "./util/validateKeyPath";
+import valueToKey from "./util/valueToKey";
+
+/** @public */
+export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore;
+
+/** @public */
+export interface FakeDOMStringList extends Array<string> {
+ contains: (value: string) => boolean;
+ item: (i: number) => string | undefined;
+}
+
+/** @public */
+export interface RequestObj {
+ operation: () => Promise<any>;
+ request?: BridgeIDBRequest | undefined;
+ source?: any;
+}
+
+/** @public */
+export interface BridgeIDBDatabaseInfo {
+ name: string;
+ version: number;
+}
+
+function simplifyRange(
+ r: IDBValidKey | IDBKeyRange | undefined | null,
+): IDBKeyRange | null {
+ if (r && typeof r === "object" && "lower" in r) {
+ return r;
+ }
+ if (r === undefined || r === null) {
+ return null;
+ }
+ return BridgeIDBKeyRange.bound(r, r, false, false);
+}
+
+/**
+ * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
+ *
+ * @public
+ */
+export class BridgeIDBCursor {
+ _request: BridgeIDBRequest | undefined;
+
+ private _gotValue: boolean = false;
+ private _range: IDBValidKey | IDBKeyRange | undefined | null;
+ private _indexPosition = undefined; // Key of previously returned record
+ private _objectStorePosition = undefined;
+ private _keyOnly: boolean;
+
+ private _source: CursorSource;
+ private _direction: IDBCursorDirection;
+ private _key: IDBValidKey | undefined = undefined;
+ private _primaryKey: IDBValidKey | undefined = undefined;
+ private _indexName: string | undefined;
+ private _objectStoreName: string;
+
+ protected _value: any = undefined;
+
+ constructor(
+ source: CursorSource,
+ objectStoreName: string,
+ indexName: string | undefined,
+ range: IDBValidKey | IDBKeyRange | null | undefined,
+ direction: IDBCursorDirection,
+ request: BridgeIDBRequest,
+ keyOnly: boolean,
+ ) {
+ this._indexName = indexName;
+ this._objectStoreName = objectStoreName;
+ this._range = range;
+ this._source = source;
+ this._direction = direction;
+ this._request = request;
+ this._keyOnly = keyOnly;
+ }
+
+ get _effectiveObjectStore(): BridgeIDBObjectStore {
+ if (this.source instanceof BridgeIDBObjectStore) {
+ return this.source;
+ }
+ return this.source.objectStore;
+ }
+
+ get _backend(): Backend {
+ return this._source._backend;
+ }
+
+ // Read only properties
+ get source() {
+ return this._source;
+ }
+ set source(val) {
+ /* For babel */
+ }
+
+ get direction() {
+ return this._direction;
+ }
+ set direction(val) {
+ /* For babel */
+ }
+
+ get key() {
+ return this._key;
+ }
+ set key(val) {
+ /* For babel */
+ }
+
+ get primaryKey() {
+ return this._primaryKey;
+ }
+
+ set primaryKey(val) {
+ /* For babel */
+ }
+
+ protected get _isValueCursor(): boolean {
+ return false;
+ }
+
+ /**
+ * https://w3c.github.io/IndexedDB/#iterate-a-cursor
+ */
+ async _iterate(key?: IDBValidKey, primaryKey?: IDBValidKey): Promise<any> {
+ BridgeIDBFactory.enableTracing &&
+ console.log(
+ `iterating cursor os=${this._objectStoreName},idx=${this._indexName}`,
+ );
+ BridgeIDBFactory.enableTracing &&
+ console.log("cursor type ", this.toString());
+ const recordGetRequest: RecordGetRequest = {
+ direction: this.direction,
+ indexName: this._indexName,
+ lastIndexPosition: this._indexPosition,
+ lastObjectStorePosition: this._objectStorePosition,
+ limit: 1,
+ range: simplifyRange(this._range),
+ objectStoreName: this._objectStoreName,
+ advanceIndexKey: key,
+ advancePrimaryKey: primaryKey,
+ resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
+ };
+
+ const { btx } = this.source._confirmActiveTransaction();
+
+ let response = await this._backend.getRecords(btx, recordGetRequest);
+
+ if (response.count === 0) {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("cursor is returning empty result");
+ }
+ this._gotValue = false;
+ return null;
+ }
+
+ if (response.count !== 1) {
+ throw Error("invariant failed");
+ }
+
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("request is:", JSON.stringify(recordGetRequest));
+ console.log("get response is:", JSON.stringify(response));
+ }
+
+ if (this._indexName !== undefined) {
+ this._key = response.indexKeys![0];
+ } else {
+ this._key = response.primaryKeys![0];
+ }
+
+ this._primaryKey = response.primaryKeys![0];
+
+ if (!this._keyOnly) {
+ this._value = response.values![0];
+ }
+
+ this._gotValue = true;
+ this._objectStorePosition = structuredClone(response.primaryKeys![0]);
+ if (response.indexKeys !== undefined && response.indexKeys.length > 0) {
+ this._indexPosition = structuredClone(response.indexKeys[0]);
+ }
+
+ return this;
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
+ public update(value: any) {
+ if (value === undefined) {
+ throw new TypeError();
+ }
+
+ const transaction = this._effectiveObjectStore.transaction;
+
+ if (transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ if (transaction.mode === "readonly") {
+ throw new ReadOnlyError();
+ }
+
+ if (this._effectiveObjectStore._deleted) {
+ throw new InvalidStateError();
+ }
+
+ if (
+ !(this.source instanceof BridgeIDBObjectStore) &&
+ this.source._deleted
+ ) {
+ throw new InvalidStateError();
+ }
+
+ if (!this._gotValue || !this._isValueCursor) {
+ throw new InvalidStateError();
+ }
+
+ const storeReq: RecordStoreRequest = {
+ key: this._primaryKey,
+ value: value,
+ objectStoreName: this._objectStoreName,
+ storeLevel: StoreLevel.UpdateExisting,
+ };
+
+ const operation = async () => {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("updating at cursor");
+ }
+ const { btx } = this.source._confirmActiveTransaction();
+ await this._backend.storeRecord(btx, storeReq);
+ };
+ return transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ /**
+ * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
+ */
+ public advance(count: number) {
+ throw Error("not implemented");
+ }
+
+ /**
+ * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
+ */
+ public continue(key?: IDBValidKey) {
+ const transaction = this._effectiveObjectStore.transaction;
+
+ if (transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ if (this._effectiveObjectStore._deleted) {
+ throw new InvalidStateError();
+ }
+ if (
+ !(this.source instanceof BridgeIDBObjectStore) &&
+ this.source._deleted
+ ) {
+ throw new InvalidStateError();
+ }
+
+ if (!this._gotValue) {
+ throw new InvalidStateError();
+ }
+
+ if (key !== undefined) {
+ key = valueToKey(key);
+ let lastKey =
+ this._indexName === undefined
+ ? this._objectStorePosition
+ : this._indexPosition;
+
+ const cmpResult = compareKeys(key, lastKey);
+
+ if (
+ (cmpResult <= 0 &&
+ (this.direction === "next" || this.direction === "nextunique")) ||
+ (cmpResult >= 0 &&
+ (this.direction === "prev" || this.direction === "prevunique"))
+ ) {
+ throw new DataError();
+ }
+ }
+
+ if (this._request) {
+ this._request.readyState = "pending";
+ }
+
+ const operation = async () => {
+ return this._iterate(key);
+ };
+
+ transaction._execRequestAsync({
+ operation,
+ request: this._request,
+ source: this.source,
+ });
+
+ this._gotValue = false;
+ }
+
+ // https://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
+ public continuePrimaryKey(key: IDBValidKey, primaryKey: IDBValidKey) {
+ throw Error("not implemented");
+ }
+
+ public delete() {
+ const transaction = this._effectiveObjectStore.transaction;
+
+ if (transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ if (transaction.mode === "readonly") {
+ throw new ReadOnlyError();
+ }
+
+ if (this._effectiveObjectStore._deleted) {
+ throw new InvalidStateError();
+ }
+ if (
+ !(this.source instanceof BridgeIDBObjectStore) &&
+ this.source._deleted
+ ) {
+ throw new InvalidStateError();
+ }
+
+ if (!this._gotValue || !this._isValueCursor) {
+ throw new InvalidStateError();
+ }
+
+ const operation = async () => {
+ const { btx } = this.source._confirmActiveTransaction();
+ this._backend.deleteRecord(
+ btx,
+ this._objectStoreName,
+ BridgeIDBKeyRange._valueToKeyRange(this._primaryKey),
+ );
+ };
+
+ return transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ public toString() {
+ return "[object IDBCursor]";
+ }
+}
+
+export class BridgeIDBCursorWithValue extends BridgeIDBCursor {
+ get value(): any {
+ return this._value;
+ }
+
+ protected get _isValueCursor(): boolean {
+ return true;
+ }
+
+ constructor(
+ source: CursorSource,
+ objectStoreName: string,
+ indexName: string | undefined,
+ range: IDBValidKey | IDBKeyRange | undefined | null,
+ direction: IDBCursorDirection,
+ request?: any,
+ ) {
+ super(source, objectStoreName, indexName, range, direction, request, false);
+ }
+
+ public toString() {
+ return "[object IDBCursorWithValue]";
+ }
+}
+
+/**
+ * Ensure that an active version change transaction is currently running.
+ */
+const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => {
+ if (!database._runningVersionchangeTransaction) {
+ throw new InvalidStateError();
+ }
+
+ // Find the latest versionchange transaction
+ const transactions = database._transactions.filter(
+ (tx: BridgeIDBTransaction) => {
+ return tx.mode === "versionchange";
+ },
+ );
+ const transaction = transactions[transactions.length - 1];
+
+ if (!transaction || transaction._state === "finished") {
+ throw new InvalidStateError();
+ }
+
+ if (transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ return transaction;
+};
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
+/** @public */
+export class BridgeIDBDatabase extends FakeEventTarget {
+ _closePending = false;
+ _closed = false;
+ _runningVersionchangeTransaction = false;
+ _transactions: Array<BridgeIDBTransaction> = [];
+
+ _backendConnection: DatabaseConnection;
+ _backend: Backend;
+
+ _schema: Schema;
+
+ get name(): string {
+ return this._schema.databaseName;
+ }
+
+ get version(): number {
+ return this._schema.databaseVersion;
+ }
+
+ get objectStoreNames(): FakeDOMStringList {
+ return fakeDOMStringList(Object.keys(this._schema.objectStores)).sort();
+ }
+
+ /**
+ * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
+ */
+ _closeConnection() {
+ this._closePending = true;
+
+ const transactionsComplete = this._transactions.every(
+ (transaction: BridgeIDBTransaction) => {
+ return transaction._state === "finished";
+ },
+ );
+
+ if (transactionsComplete) {
+ this._closed = true;
+ this._backend.close(this._backendConnection);
+ } else {
+ queueTask(() => {
+ this._closeConnection();
+ });
+ }
+ }
+
+ constructor(backend: Backend, backendConnection: DatabaseConnection) {
+ super();
+
+ this._schema = backend.getSchema(backendConnection);
+
+ this._backend = backend;
+ this._backendConnection = backendConnection;
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
+ public createObjectStore(
+ name: string,
+ options: { autoIncrement?: boolean; keyPath?: IDBKeyPath } | null = {},
+ ): BridgeIDBObjectStore {
+ if (name === undefined) {
+ throw new TypeError();
+ }
+ const transaction = confirmActiveVersionchangeTransaction(this);
+ const backendTx = transaction._backendTransaction;
+ if (!backendTx) {
+ throw Error("invariant violated");
+ }
+
+ const keyPath =
+ options !== null && options.keyPath !== undefined
+ ? options.keyPath
+ : null;
+ const autoIncrement =
+ options !== null && options.autoIncrement !== undefined
+ ? options.autoIncrement
+ : false;
+
+ if (keyPath !== null) {
+ validateKeyPath(keyPath);
+ }
+
+ if (Object.keys(this._schema.objectStores).includes(name)) {
+ throw new ConstraintError();
+ }
+
+ if (autoIncrement && (keyPath === "" || Array.isArray(keyPath))) {
+ throw new InvalidAccessError();
+ }
+
+ transaction._backend.createObjectStore(
+ backendTx,
+ name,
+ keyPath,
+ autoIncrement,
+ );
+
+ this._schema = this._backend.getSchema(this._backendConnection);
+
+ return transaction.objectStore(name);
+ }
+
+ public deleteObjectStore(name: string): void {
+ if (name === undefined) {
+ throw new TypeError();
+ }
+ const transaction = confirmActiveVersionchangeTransaction(this);
+ transaction._objectStoresCache.delete(name);
+ }
+
+ public _internalTransaction(
+ storeNames: string | string[],
+ mode?: IDBTransactionMode,
+ backendTransaction?: DatabaseTransaction,
+ ): BridgeIDBTransaction {
+ mode = mode !== undefined ? mode : "readonly";
+ if (
+ mode !== "readonly" &&
+ mode !== "readwrite" &&
+ mode !== "versionchange"
+ ) {
+ throw new TypeError("Invalid mode: " + mode);
+ }
+
+ const hasActiveVersionchange = this._transactions.some(
+ (transaction: BridgeIDBTransaction) => {
+ return (
+ transaction._state === "active" &&
+ transaction.mode === "versionchange" &&
+ transaction.db === this
+ );
+ },
+ );
+ if (hasActiveVersionchange) {
+ throw new InvalidStateError();
+ }
+
+ if (this._closePending) {
+ throw new InvalidStateError();
+ }
+
+ if (!Array.isArray(storeNames)) {
+ storeNames = [storeNames];
+ }
+ if (storeNames.length === 0 && mode !== "versionchange") {
+ throw new InvalidAccessError();
+ }
+ for (const storeName of storeNames) {
+ if (this.objectStoreNames.indexOf(storeName) < 0) {
+ throw new NotFoundError(
+ "No objectStore named " + storeName + " in this database",
+ );
+ }
+ }
+
+ const tx = new BridgeIDBTransaction(
+ storeNames,
+ mode,
+ this,
+ backendTransaction,
+ );
+ this._transactions.push(tx);
+ queueTask(() => tx._start());
+ return tx;
+ }
+
+ public transaction(
+ storeNames: string | string[],
+ mode?: IDBTransactionMode,
+ ): BridgeIDBTransaction {
+ if (mode === "versionchange") {
+ throw new TypeError("Invalid mode: " + mode);
+ }
+ return this._internalTransaction(storeNames, mode);
+ }
+
+ public close() {
+ this._closeConnection();
+ }
+
+ public toString() {
+ return "[object IDBDatabase]";
+ }
+}
+
+/** @public */
+export type DatabaseList = Array<{ name: string; version: number }>;
+
+/** @public */
+export class BridgeIDBFactory {
+ public cmp = compareKeys;
+ private backend: Backend;
+ private connections: BridgeIDBDatabase[] = [];
+ static enableTracing: boolean = false;
+
+ public constructor(backend: Backend) {
+ this.backend = backend;
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
+ public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
+ const request = new BridgeIDBOpenDBRequest();
+ request.source = null;
+
+ queueTask(async () => {
+ const databases = await this.backend.getDatabases();
+ const dbInfo = databases.find((x) => x.name == name);
+ if (!dbInfo) {
+ // Database already doesn't exist, success!
+ const event = new BridgeIDBVersionChangeEvent("success", {
+ newVersion: null,
+ oldVersion: 0,
+ });
+ request.dispatchEvent(event);
+ return;
+ }
+ const oldVersion = dbInfo.version;
+
+ try {
+ const dbconn = await this.backend.connectDatabase(name);
+ const backendTransaction = await this.backend.enterVersionChange(
+ dbconn,
+ 0,
+ );
+ await this.backend.deleteDatabase(backendTransaction, name);
+ await this.backend.commit(backendTransaction);
+ await this.backend.close(dbconn);
+
+ request.result = undefined;
+ request.readyState = "done";
+
+ const event2 = new BridgeIDBVersionChangeEvent("success", {
+ newVersion: null,
+ oldVersion,
+ });
+ request.dispatchEvent(event2);
+ } catch (err) {
+ request.error = new Error();
+ request.error.name = err.name;
+ request.readyState = "done";
+
+ const event = new FakeEvent("error", {
+ bubbles: true,
+ cancelable: true,
+ });
+ event.eventPath = [];
+ request.dispatchEvent(event);
+ }
+ });
+
+ return request;
+ }
+
+ // tslint:disable-next-line max-line-length
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-open-IDBOpenDBRequest-DOMString-name-unsigned-long-long-version
+ public open(name: string, version?: number) {
+ if (arguments.length > 1 && version !== undefined) {
+ // Based on spec, not sure why "MAX_SAFE_INTEGER" instead of "unsigned long long", but it's needed to pass
+ // tests
+ version = enforceRange(version, "MAX_SAFE_INTEGER");
+ }
+ if (version === 0) {
+ throw new TypeError();
+ }
+
+ const request = new BridgeIDBOpenDBRequest();
+
+ queueTask(async () => {
+ let dbconn: DatabaseConnection;
+ try {
+ dbconn = await this.backend.connectDatabase(name);
+ } catch (err) {
+ request._finishWithError(err);
+ return;
+ }
+
+ const schema = this.backend.getSchema(dbconn);
+ const existingVersion = schema.databaseVersion;
+
+ if (version === undefined) {
+ version = existingVersion !== 0 ? existingVersion : 1;
+ }
+
+ const requestedVersion = version;
+
+ BridgeIDBFactory.enableTracing &&
+ console.log(
+ `TRACE: existing version ${existingVersion}, requested version ${requestedVersion}`,
+ );
+
+ if (existingVersion > requestedVersion) {
+ request._finishWithError(new VersionError());
+ return;
+ }
+
+ const db = new BridgeIDBDatabase(this.backend, dbconn);
+
+ if (existingVersion == requestedVersion) {
+ request.result = db;
+ request.readyState = "done";
+
+ const event2 = new FakeEvent("success", {
+ bubbles: false,
+ cancelable: false,
+ });
+ event2.eventPath = [request];
+ request.dispatchEvent(event2);
+ }
+
+ if (existingVersion < requestedVersion) {
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
+
+ for (const otherConn of this.connections) {
+ const event = new BridgeIDBVersionChangeEvent("versionchange", {
+ newVersion: version,
+ oldVersion: existingVersion,
+ });
+ otherConn.dispatchEvent(event);
+ }
+
+ if (this._anyOpen()) {
+ const event = new BridgeIDBVersionChangeEvent("blocked", {
+ newVersion: version,
+ oldVersion: existingVersion,
+ });
+ request.dispatchEvent(event);
+ }
+
+ const backendTransaction = await this.backend.enterVersionChange(
+ dbconn,
+ requestedVersion,
+ );
+ db._runningVersionchangeTransaction = true;
+
+ const transaction = db._internalTransaction(
+ [],
+ "versionchange",
+ backendTransaction,
+ );
+ const event = new BridgeIDBVersionChangeEvent("upgradeneeded", {
+ newVersion: version,
+ oldVersion: existingVersion,
+ });
+
+ request.result = db;
+ request.readyState = "done";
+ request.transaction = transaction;
+ request.dispatchEvent(event);
+
+ await transaction._waitDone();
+
+ // We don't explicitly exit the versionchange transaction,
+ // since this is already done by the BridgeIDBTransaction.
+ db._runningVersionchangeTransaction = false;
+
+ const event2 = new FakeEvent("success", {
+ bubbles: false,
+ cancelable: false,
+ });
+ event2.eventPath = [request];
+
+ request.dispatchEvent(event2);
+ }
+
+ this.connections.push(db);
+ return db;
+ });
+
+ return request;
+ }
+
+ // https://w3c.github.io/IndexedDB/#dom-idbfactory-databases
+ public databases(): Promise<DatabaseList> {
+ return this.backend.getDatabases();
+ }
+
+ public toString(): string {
+ return "[object IDBFactory]";
+ }
+
+ private _anyOpen(): boolean {
+ return this.connections.some((c) => !c._closed && !c._closePending);
+ }
+}
+
+const confirmActiveTransaction = (
+ index: BridgeIDBIndex,
+): BridgeIDBTransaction => {
+ if (index._deleted || index.objectStore._deleted) {
+ throw new InvalidStateError();
+ }
+
+ if (index.objectStore.transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ return index.objectStore.transaction;
+};
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
+/** @public */
+export class BridgeIDBIndex {
+ objectStore: BridgeIDBObjectStore;
+
+ get _schema(): Schema {
+ return this.objectStore.transaction.db._schema;
+ }
+
+ get keyPath(): IDBKeyPath {
+ return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+ .keyPath;
+ }
+
+ get multiEntry(): boolean {
+ return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+ .multiEntry;
+ }
+
+ get unique(): boolean {
+ return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+ .unique;
+ }
+
+ get _backend(): Backend {
+ return this.objectStore._backend;
+ }
+
+ _confirmActiveTransaction(): { btx: DatabaseTransaction } {
+ return this.objectStore._confirmActiveTransaction();
+ }
+
+ private _name: string;
+
+ public _deleted: boolean = false;
+
+ constructor(objectStore: BridgeIDBObjectStore, name: string) {
+ this._name = name;
+ this.objectStore = objectStore;
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ // https://w3c.github.io/IndexedDB/#dom-idbindex-name
+ set name(name: any) {
+ const transaction = this.objectStore.transaction;
+
+ if (!transaction.db._runningVersionchangeTransaction) {
+ throw new InvalidStateError();
+ }
+
+ if (transaction._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ const { btx } = this._confirmActiveTransaction();
+
+ const oldName = this._name;
+ const newName = String(name);
+
+ if (newName === oldName) {
+ return;
+ }
+
+ this._backend.renameIndex(btx, this.objectStore.name, oldName, newName);
+
+ if (this.objectStore.indexNames.indexOf(name) >= 0) {
+ throw new ConstraintError();
+ }
+ }
+
+ // tslint:disable-next-line max-line-length
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openCursor-IDBRequest-any-range-IDBCursorDirection-direction
+ public openCursor(
+ range?: BridgeIDBKeyRange | IDBValidKey | null | undefined,
+ direction: IDBCursorDirection = "next",
+ ) {
+ confirmActiveTransaction(this);
+
+ if (range === null) {
+ range = undefined;
+ }
+ if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+ range = BridgeIDBKeyRange.only(valueToKey(range));
+ }
+
+ const request = new BridgeIDBRequest();
+ request.source = this;
+ request.transaction = this.objectStore.transaction;
+
+ const cursor = new BridgeIDBCursorWithValue(
+ this,
+ this.objectStore.name,
+ this._name,
+ range,
+ direction,
+ request,
+ );
+
+ const operation = async () => {
+ return cursor._iterate();
+ };
+
+ return this.objectStore.transaction._execRequestAsync({
+ operation,
+ request,
+ source: this,
+ });
+ }
+
+ // tslint:disable-next-line max-line-length
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openKeyCursor-IDBRequest-any-range-IDBCursorDirection-direction
+ public openKeyCursor(
+ range?: BridgeIDBKeyRange | IDBValidKey | null | undefined,
+ direction: IDBCursorDirection = "next",
+ ) {
+ confirmActiveTransaction(this);
+
+ if (range === null) {
+ range = undefined;
+ }
+ if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+ range = BridgeIDBKeyRange.only(valueToKey(range));
+ }
+
+ const request = new BridgeIDBRequest();
+ request.source = this;
+ request.transaction = this.objectStore.transaction;
+
+ const cursor = new BridgeIDBCursor(
+ this,
+ this.objectStore.name,
+ this._name,
+ range,
+ direction,
+ request,
+ true,
+ );
+
+ return this.objectStore.transaction._execRequestAsync({
+ operation: cursor._iterate.bind(cursor),
+ request,
+ source: this,
+ });
+ }
+
+ public get(key: BridgeIDBKeyRange | IDBValidKey) {
+ confirmActiveTransaction(this);
+
+ if (!(key instanceof BridgeIDBKeyRange)) {
+ key = BridgeIDBKeyRange._valueToKeyRange(key);
+ }
+
+ const getReq: RecordGetRequest = {
+ direction: "next",
+ indexName: this._name,
+ limit: 1,
+ range: key,
+ objectStoreName: this.objectStore._name,
+ resultLevel: ResultLevel.Full,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.getRecords(btx, getReq);
+ if (result.count == 0) {
+ return undefined;
+ }
+ const values = result.values;
+ if (!values) {
+ throw Error("invariant violated");
+ }
+ return values[0];
+ };
+
+ return this.objectStore.transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbindex-getall
+ public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+ throw Error("not implemented");
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-getKey-IDBRequest-any-key
+ public getKey(key: BridgeIDBKeyRange | IDBValidKey) {
+ confirmActiveTransaction(this);
+
+ if (!(key instanceof BridgeIDBKeyRange)) {
+ key = BridgeIDBKeyRange._valueToKeyRange(key);
+ }
+
+ const getReq: RecordGetRequest = {
+ direction: "next",
+ indexName: this._name,
+ limit: 1,
+ range: key,
+ objectStoreName: this.objectStore._name,
+ resultLevel: ResultLevel.OnlyKeys,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.getRecords(btx, getReq);
+ if (result.count == 0) {
+ return undefined;
+ }
+ const primaryKeys = result.primaryKeys;
+ if (!primaryKeys) {
+ throw Error("invariant violated");
+ }
+ return primaryKeys[0];
+ };
+
+ return this.objectStore.transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
+ public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+ throw Error("not implemented");
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-count-IDBRequest-any-key
+ public count(key: BridgeIDBKeyRange | IDBValidKey | null | undefined) {
+ confirmActiveTransaction(this);
+
+ if (key === null) {
+ key = undefined;
+ }
+ if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
+ key = BridgeIDBKeyRange.only(valueToKey(key));
+ }
+
+ const getReq: RecordGetRequest = {
+ direction: "next",
+ indexName: this._name,
+ limit: 1,
+ range: key,
+ objectStoreName: this.objectStore._name,
+ resultLevel: ResultLevel.OnlyCount,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.getRecords(btx, getReq);
+ return result.count;
+ };
+
+ return this.objectStore.transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ public toString() {
+ return "[object IDBIndex]";
+ }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#range-concept
+/** @public */
+export class BridgeIDBKeyRange {
+ public static only(value: IDBValidKey) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ value = valueToKey(value);
+ return new BridgeIDBKeyRange(value, value, false, false);
+ }
+
+ static lowerBound(lower: IDBValidKey, open: boolean = false) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ lower = valueToKey(lower);
+ return new BridgeIDBKeyRange(lower, undefined, open, true);
+ }
+
+ static upperBound(upper: IDBValidKey, open: boolean = false) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ upper = valueToKey(upper);
+ return new BridgeIDBKeyRange(undefined, upper, true, open);
+ }
+
+ static bound(
+ lower: IDBValidKey,
+ upper: IDBValidKey,
+ lowerOpen: boolean = false,
+ upperOpen: boolean = false,
+ ) {
+ if (arguments.length < 2) {
+ throw new TypeError();
+ }
+
+ const cmpResult = compareKeys(lower, upper);
+ if (cmpResult === 1 || (cmpResult === 0 && (lowerOpen || upperOpen))) {
+ throw new DataError();
+ }
+
+ lower = valueToKey(lower);
+ upper = valueToKey(upper);
+ return new BridgeIDBKeyRange(lower, upper, lowerOpen, upperOpen);
+ }
+
+ readonly lower: IDBValidKey | undefined;
+ readonly upper: IDBValidKey | undefined;
+ readonly lowerOpen: boolean;
+ readonly upperOpen: boolean;
+
+ constructor(
+ lower: IDBValidKey | undefined,
+ upper: IDBValidKey | undefined,
+ lowerOpen: boolean,
+ upperOpen: boolean,
+ ) {
+ this.lower = lower;
+ this.upper = upper;
+ this.lowerOpen = lowerOpen;
+ this.upperOpen = upperOpen;
+ }
+
+ // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes
+ includes(key: IDBValidKey) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ key = valueToKey(key);
+
+ if (this.lower !== undefined) {
+ const cmpResult = compareKeys(this.lower, key);
+
+ if (cmpResult === 1 || (cmpResult === 0 && this.lowerOpen)) {
+ return false;
+ }
+ }
+ if (this.upper !== undefined) {
+ const cmpResult = compareKeys(this.upper, key);
+
+ if (cmpResult === -1 || (cmpResult === 0 && this.upperOpen)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ toString() {
+ return "[object IDBKeyRange]";
+ }
+
+ static _valueToKeyRange(value: any, nullDisallowedFlag: boolean = false) {
+ if (value instanceof BridgeIDBKeyRange) {
+ return value;
+ }
+
+ if (value === null || value === undefined) {
+ if (nullDisallowedFlag) {
+ throw new DataError();
+ }
+ return new BridgeIDBKeyRange(undefined, undefined, false, false);
+ }
+
+ const key = valueToKey(value);
+
+ return BridgeIDBKeyRange.only(key);
+ }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
+/** @public */
+export class BridgeIDBObjectStore {
+ _indexesCache: Map<string, BridgeIDBIndex> = new Map();
+
+ transaction: BridgeIDBTransaction;
+
+ get autoIncrement(): boolean {
+ return this._schema.objectStores[this._name].autoIncrement;
+ }
+
+ get indexNames(): FakeDOMStringList {
+ return fakeDOMStringList(
+ Object.keys(this._schema.objectStores[this._name].indexes),
+ ).sort();
+ }
+
+ get keyPath(): IDBKeyPath | null {
+ return this._schema.objectStores[this._name].keyPath;
+ }
+
+ _name: string;
+
+ get _schema(): Schema {
+ return this.transaction.db._schema;
+ }
+
+ _deleted: boolean = false;
+
+ constructor(transaction: BridgeIDBTransaction, name: string) {
+ this._name = name;
+ this.transaction = transaction;
+ }
+
+ get name() {
+ return this._name;
+ }
+
+ get _backend(): Backend {
+ return this.transaction.db._backend;
+ }
+
+ get _backendConnection(): DatabaseConnection {
+ return this.transaction.db._backendConnection;
+ }
+
+ _confirmActiveTransaction(): { btx: DatabaseTransaction } {
+ const btx = this.transaction._backendTransaction;
+ if (!btx) {
+ throw new InvalidStateError();
+ }
+ return { btx };
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
+ set name(newName: any) {
+ const transaction = this.transaction;
+
+ if (!transaction.db._runningVersionchangeTransaction) {
+ throw new InvalidStateError();
+ }
+
+ let { btx } = this._confirmActiveTransaction();
+
+ newName = String(newName);
+
+ const oldName = this._name;
+
+ if (newName === oldName) {
+ return;
+ }
+
+ this._backend.renameObjectStore(btx, oldName, newName);
+ this.transaction.db._schema = this._backend.getSchema(
+ this._backendConnection,
+ );
+ }
+
+ public _store(value: any, key: IDBValidKey | undefined, overwrite: boolean) {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log(`TRACE: IDBObjectStore._store`);
+ }
+ if (this.transaction.mode === "readonly") {
+ throw new ReadOnlyError();
+ }
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.storeRecord(btx, {
+ objectStoreName: this._name,
+ key: key,
+ value: value,
+ storeLevel: overwrite
+ ? StoreLevel.AllowOverwrite
+ : StoreLevel.NoOverwrite,
+ });
+ return result.key;
+ };
+
+ return this.transaction._execRequestAsync({ operation, source: this });
+ }
+
+ public put(value: any, key?: IDBValidKey) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ return this._store(value, key, true);
+ }
+
+ public add(value: any, key?: IDBValidKey) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+ return this._store(value, key, false);
+ }
+
+ public delete(key: IDBValidKey | BridgeIDBKeyRange) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (this.transaction.mode === "readonly") {
+ throw new ReadOnlyError();
+ }
+
+ let keyRange: BridgeIDBKeyRange;
+
+ if (key instanceof BridgeIDBKeyRange) {
+ keyRange = key;
+ } else {
+ keyRange = BridgeIDBKeyRange.only(valueToKey(key));
+ }
+
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ return this._backend.deleteRecord(btx, this._name, keyRange);
+ };
+
+ return this.transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ public get(key?: BridgeIDBKeyRange | IDBValidKey) {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log(`getting from object store ${this._name} key ${key}`);
+ }
+
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ let keyRange: BridgeIDBKeyRange;
+
+ if (key instanceof BridgeIDBKeyRange) {
+ keyRange = key;
+ } else {
+ try {
+ keyRange = BridgeIDBKeyRange.only(valueToKey(key));
+ } catch (e) {
+ throw Error(
+ `invalid key (type ${typeof key}) for object store ${this._name}`,
+ );
+ }
+ }
+
+ const recordRequest: RecordGetRequest = {
+ objectStoreName: this._name,
+ indexName: undefined,
+ lastIndexPosition: undefined,
+ lastObjectStorePosition: undefined,
+ direction: "next",
+ limit: 1,
+ resultLevel: ResultLevel.Full,
+ range: keyRange,
+ };
+
+ const operation = async () => {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("running get operation:", recordRequest);
+ }
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.getRecords(btx, recordRequest);
+
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("get operation result count:", result.count);
+ }
+
+ if (result.count === 0) {
+ return undefined;
+ }
+ const values = result.values;
+ if (!values) {
+ throw Error("invariant violated");
+ }
+ return values[0];
+ };
+
+ return this.transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
+ public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+ throw Error("not implemented");
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
+ public getKey(key?: BridgeIDBKeyRange | IDBValidKey) {
+ throw Error("not implemented");
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
+ public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+ throw Error("not implemented");
+ }
+
+ public clear() {
+ throw Error("not implemented");
+ }
+
+ public openCursor(
+ range?: IDBKeyRange | IDBValidKey,
+ direction: IDBCursorDirection = "next",
+ ) {
+ if (range === null) {
+ range = undefined;
+ }
+ if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+ range = BridgeIDBKeyRange.only(valueToKey(range));
+ }
+
+ const request = new BridgeIDBRequest();
+ request.source = this;
+ request.transaction = this.transaction;
+
+ const cursor = new BridgeIDBCursorWithValue(
+ this,
+ this._name,
+ undefined,
+ range,
+ direction,
+ request,
+ );
+
+ return this.transaction._execRequestAsync({
+ operation: () => cursor._iterate(),
+ request,
+ source: this,
+ });
+ }
+
+ public openKeyCursor(
+ range?: BridgeIDBKeyRange | IDBValidKey,
+ direction?: IDBCursorDirection,
+ ) {
+ if (range === null) {
+ range = undefined;
+ }
+ if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+ range = BridgeIDBKeyRange.only(valueToKey(range));
+ }
+
+ if (!direction) {
+ direction = "next";
+ }
+
+ const request = new BridgeIDBRequest();
+ request.source = this;
+ request.transaction = this.transaction;
+
+ const cursor = new BridgeIDBCursor(
+ this,
+ this._name,
+ undefined,
+ range,
+ direction,
+ request,
+ true,
+ );
+
+ return this.transaction._execRequestAsync({
+ operation: cursor._iterate.bind(cursor),
+ request,
+ source: this,
+ });
+ }
+
+ // tslint:disable-next-line max-line-length
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-createIndex-IDBIndex-DOMString-name-DOMString-sequence-DOMString--keyPath-IDBIndexParameters-optionalParameters
+ public createIndex(
+ indexName: string,
+ keyPath: IDBKeyPath,
+ optionalParameters: { multiEntry?: boolean; unique?: boolean } = {},
+ ) {
+ if (arguments.length < 2) {
+ throw new TypeError();
+ }
+
+ if (!this.transaction.db._runningVersionchangeTransaction) {
+ throw new InvalidStateError();
+ }
+
+ const { btx } = this._confirmActiveTransaction();
+
+ const multiEntry =
+ optionalParameters.multiEntry !== undefined
+ ? optionalParameters.multiEntry
+ : false;
+ const unique =
+ optionalParameters.unique !== undefined
+ ? optionalParameters.unique
+ : false;
+
+ if (this.transaction.mode !== "versionchange") {
+ throw new InvalidStateError();
+ }
+
+ if (this.indexNames.indexOf(indexName) >= 0) {
+ throw new ConstraintError();
+ }
+
+ validateKeyPath(keyPath);
+
+ if (Array.isArray(keyPath) && multiEntry) {
+ throw new InvalidAccessError();
+ }
+
+ this._backend.createIndex(
+ btx,
+ indexName,
+ this._name,
+ keyPath,
+ multiEntry,
+ unique,
+ );
+
+ return new BridgeIDBIndex(this, indexName);
+ }
+
+ // https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
+ public index(name: string) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (this.transaction._state === "finished") {
+ throw new InvalidStateError();
+ }
+
+ const index = this._indexesCache.get(name);
+ if (index !== undefined) {
+ return index;
+ }
+
+ return new BridgeIDBIndex(this, name);
+ }
+
+ public deleteIndex(indexName: string) {
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (this.transaction.mode !== "versionchange") {
+ throw new InvalidStateError();
+ }
+
+ if (!this.transaction.db._runningVersionchangeTransaction) {
+ throw new InvalidStateError();
+ }
+
+ const { btx } = this._confirmActiveTransaction();
+
+ const index = this._indexesCache.get(indexName);
+ if (index !== undefined) {
+ index._deleted = true;
+ }
+
+ this._backend.deleteIndex(btx, this._name, indexName);
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-count-IDBRequest-any-key
+ public count(key?: IDBValidKey | BridgeIDBKeyRange) {
+ if (key === null) {
+ key = undefined;
+ }
+ if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
+ key = BridgeIDBKeyRange.only(valueToKey(key));
+ }
+
+ const recordGetRequest: RecordGetRequest = {
+ direction: "next",
+ indexName: undefined,
+ lastIndexPosition: undefined,
+ limit: -1,
+ objectStoreName: this._name,
+ lastObjectStorePosition: undefined,
+ range: key,
+ resultLevel: ResultLevel.OnlyCount,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmActiveTransaction();
+ const result = await this._backend.getRecords(btx, recordGetRequest);
+ return result.count;
+ };
+
+ return this.transaction._execRequestAsync({ operation, source: this });
+ }
+
+ public toString() {
+ return "[object IDBObjectStore]";
+ }
+}
+
+/** @public */
+export class BridgeIDBRequest extends FakeEventTarget {
+ _result: any = null;
+ _error: Error | null | undefined = null;
+ source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null = null;
+ transaction: BridgeIDBTransaction | null = null;
+ readyState: "done" | "pending" = "pending";
+ onsuccess: EventListener | null = null;
+ onerror: EventListener | null = null;
+
+ get error() {
+ if (this.readyState === "pending") {
+ throw new InvalidStateError();
+ }
+ return this._error;
+ }
+
+ set error(value: any) {
+ this._error = value;
+ }
+
+ get result() {
+ if (this.readyState === "pending") {
+ throw new InvalidStateError();
+ }
+ return this._result;
+ }
+
+ set result(value: any) {
+ this._result = value;
+ }
+
+ toString() {
+ return "[object IDBRequest]";
+ }
+
+ _finishWithError(err: Error) {
+ this.result = undefined;
+ this.readyState = "done";
+
+ this.error = new Error(err.message);
+ this.error.name = err.name;
+
+ const event = new FakeEvent("error", {
+ bubbles: true,
+ cancelable: true,
+ });
+ event.eventPath = [];
+ this.dispatchEvent(event);
+ }
+
+ _finishWithResult(result: any) {
+ this.result = result;
+ this.readyState = "done";
+
+ const event = new FakeEvent("success");
+ event.eventPath = [];
+ this.dispatchEvent(event);
+ }
+}
+
+/** @public */
+export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
+ public onupgradeneeded: EventListener | null = null;
+ public onblocked: EventListener | null = null;
+
+ constructor() {
+ super();
+ // https://www.w3.org/TR/IndexedDB/#open-requests
+ this.source = null;
+ }
+
+ public toString() {
+ return "[object IDBOpenDBRequest]";
+ }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
+/** @public */
+export class BridgeIDBTransaction extends FakeEventTarget {
+ public _state: "active" | "inactive" | "committing" | "finished" = "active";
+ public _started = false;
+ public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
+
+ public _backendTransaction?: DatabaseTransaction;
+
+ public objectStoreNames: FakeDOMStringList;
+ public mode: IDBTransactionMode;
+ public db: BridgeIDBDatabase;
+ public error: Error | null = null;
+ public onabort: EventListener | null = null;
+ public oncomplete: EventListener | null = null;
+ public onerror: EventListener | null = null;
+
+ private _waitPromise: Promise<void>;
+ private _resolveWait: () => void;
+
+ public _scope: Set<string>;
+ private _requests: Array<{
+ operation: () => void;
+ request: BridgeIDBRequest;
+ }> = [];
+
+ get _backend(): Backend {
+ return this.db._backend;
+ }
+
+ constructor(
+ storeNames: string[],
+ mode: IDBTransactionMode,
+ db: BridgeIDBDatabase,
+ backendTransaction?: DatabaseTransaction,
+ ) {
+ super();
+
+ const myOpenPromise = openPromise<void>();
+ this._waitPromise = myOpenPromise.promise;
+ this._resolveWait = myOpenPromise.resolve;
+
+ this._scope = new Set(storeNames);
+ this._backendTransaction = backendTransaction;
+ this.mode = mode;
+ this.db = db;
+ this.objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
+
+ this.db._transactions.push(this);
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
+ async _abort(errName: string | null) {
+ this._state = "finished";
+
+ if (errName !== null) {
+ const e = new Error();
+ e.name = errName;
+ this.error = e;
+ }
+
+ // Should this directly remove from _requests?
+ for (const { request } of this._requests) {
+ if (request.readyState !== "done") {
+ request.readyState = "done"; // This will cancel execution of this request's operation
+ if (request.source) {
+ request.result = undefined;
+ request.error = new AbortError();
+
+ const event = new FakeEvent("error", {
+ bubbles: true,
+ cancelable: true,
+ });
+ event.eventPath = [this.db, this];
+ request.dispatchEvent(event);
+ }
+ }
+ }
+
+ // Only roll back if we actually executed the scheduled operations.
+ const maybeBtx = this._backendTransaction;
+ if (maybeBtx) {
+ await this._backend.rollback(maybeBtx);
+ }
+
+ queueTask(() => {
+ const event = new FakeEvent("abort", {
+ bubbles: true,
+ cancelable: false,
+ });
+ event.eventPath = [this.db];
+ this.dispatchEvent(event);
+ });
+ }
+
+ public abort() {
+ if (this._state === "committing" || this._state === "finished") {
+ throw new InvalidStateError();
+ }
+ this._state = "active";
+
+ this._abort(null);
+ }
+
+ // http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
+ public objectStore(name: string) {
+ if (this._state !== "active") {
+ throw new InvalidStateError();
+ }
+
+ const objectStore = this._objectStoresCache.get(name);
+ if (objectStore !== undefined) {
+ return objectStore;
+ }
+
+ return new BridgeIDBObjectStore(this, name);
+ }
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-asynchronously-executing-a-request
+ public _execRequestAsync(obj: RequestObj) {
+ const source = obj.source;
+ const operation = obj.operation;
+ let request = obj.hasOwnProperty("request") ? obj.request : null;
+
+ if (this._state !== "active") {
+ throw new TransactionInactiveError();
+ }
+
+ // Request should only be passed for cursors
+ if (!request) {
+ if (!source) {
+ // Special requests like indexes that just need to run some code
+ request = new BridgeIDBRequest();
+ } else {
+ request = new BridgeIDBRequest();
+ request.source = source;
+ request.transaction = (source as any).transaction;
+ }
+ }
+
+ this._requests.push({
+ operation,
+ request,
+ });
+
+ return request;
+ }
+
+ /**
+ * Actually execute the scheduled work for this transaction.
+ */
+ public async _start() {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log(
+ `TRACE: IDBTransaction._start, ${this._requests.length} queued`,
+ );
+ }
+ this._started = true;
+
+ if (!this._backendTransaction) {
+ this._backendTransaction = await this._backend.beginTransaction(
+ this.db._backendConnection,
+ Array.from(this._scope),
+ this.mode,
+ );
+ }
+
+ // Remove from request queue - cursor ones will be added back if necessary by cursor.continue and such
+ let operation;
+ let request;
+ while (this._requests.length > 0) {
+ const r = this._requests.shift();
+
+ // This should only be false if transaction was aborted
+ if (r && r.request.readyState !== "done") {
+ request = r.request;
+ operation = r.operation;
+ break;
+ }
+ }
+
+ if (request && operation) {
+ if (!request.source) {
+ // Special requests like indexes that just need to run some code, with error handling already built into
+ // operation
+ await operation();
+ } else {
+ let event;
+ try {
+ BridgeIDBFactory.enableTracing &&
+ console.log("TRACE: running operation in transaction");
+ const result = await operation();
+ BridgeIDBFactory.enableTracing &&
+ console.log(
+ "TRACE: operation in transaction finished with success",
+ );
+ request.readyState = "done";
+ request.result = result;
+ request.error = undefined;
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-a-success-event
+ if (this._state === "inactive") {
+ this._state = "active";
+ }
+ event = new FakeEvent("success", {
+ bubbles: false,
+ cancelable: false,
+ });
+
+ try {
+ event.eventPath = [request, this, this.db];
+ request.dispatchEvent(event);
+ } catch (err) {
+ if (this._state !== "committing") {
+ this._abort("AbortError");
+ }
+ throw err;
+ }
+ } catch (err) {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("TRACING: error during operation: ", err);
+ }
+ request.readyState = "done";
+ request.result = undefined;
+ request.error = err;
+
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
+ if (this._state === "inactive") {
+ this._state = "active";
+ }
+ event = new FakeEvent("error", {
+ bubbles: true,
+ cancelable: true,
+ });
+
+ try {
+ event.eventPath = [this.db, this];
+ request.dispatchEvent(event);
+ } catch (err) {
+ if (this._state !== "committing") {
+ this._abort("AbortError");
+ }
+ throw err;
+ }
+ if (!event.canceled) {
+ this._abort(err.name);
+ }
+ }
+ }
+
+ // On to the next one
+ if (this._requests.length > 0) {
+ this._start();
+ } else {
+ // Give it another chance for new handlers to be set before finishing
+ queueTask(() => this._start());
+ }
+ return;
+ }
+
+ if (this._state !== "finished" && this._state !== "committing") {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("finishing transaction");
+ }
+
+ this._state = "committing";
+
+ await this._backend.commit(this._backendTransaction);
+
+ this._state = "finished";
+
+ if (!this.error) {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("dispatching 'complete' event on transaction");
+ }
+ const event = new FakeEvent("complete");
+ event.eventPath = [this, this.db];
+ this.dispatchEvent(event);
+ }
+
+ const idx = this.db._transactions.indexOf(this);
+ if (idx < 0) {
+ throw Error("invariant failed");
+ }
+ this.db._transactions.splice(idx, 1);
+
+ this._resolveWait();
+ }
+ }
+
+ public commit() {
+ if (this._state !== "active") {
+ throw new InvalidStateError();
+ }
+
+ this._state = "committing";
+ // We now just wait for auto-commit ...
+ }
+
+ public toString() {
+ return "[object IDBRequest]";
+ }
+
+ _waitDone(): Promise<void> {
+ return this._waitPromise;
+ }
+}
+
+export class BridgeIDBVersionChangeEvent extends FakeEvent {
+ public newVersion: number | null;
+ public oldVersion: number;
+
+ constructor(
+ type: "blocked" | "success" | "upgradeneeded" | "versionchange",
+ parameters: { newVersion?: number | null; oldVersion?: number } = {},
+ ) {
+ super(type);
+
+ this.newVersion =
+ parameters.newVersion !== undefined ? parameters.newVersion : null;
+ this.oldVersion =
+ parameters.oldVersion !== undefined ? parameters.oldVersion : 0;
+ }
+
+ public toString() {
+ return "[object IDBVersionChangeEvent]";
+ }
+}
diff --git a/packages/idb-bridge/src/index.ts b/packages/idb-bridge/src/index.ts
index 4c29be968..b6c15249d 100644
--- a/packages/idb-bridge/src/index.ts
+++ b/packages/idb-bridge/src/index.ts
@@ -1,26 +1,3 @@
-import { BridgeIDBFactory, DatabaseList } from "./BridgeIDBFactory";
-import { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBOpenDBRequest } from "./BridgeIDBOpenDBRequest";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { BridgeIDBVersionChangeEvent } from "./BridgeIDBVersionChangeEvent";
-import {
- Value,
- CursorSource,
- CursorRange,
- BridgeIDBCursorDirection,
- Key,
- KeyPath,
- TransactionMode,
- FakeDOMStringList,
- RequestObj,
- BridgeIDBDatabaseInfo,
- EventType,
-} from "./util/types";
import {
DatabaseTransaction,
RecordGetResponse,
@@ -45,12 +22,23 @@ import {
MemoryBackendDump,
} from "./MemoryBackend";
import { Event } from "./idbtypes";
+import {
+ BridgeIDBCursor,
+ BridgeIDBDatabase,
+ BridgeIDBFactory,
+ BridgeIDBIndex,
+ BridgeIDBKeyRange,
+ BridgeIDBObjectStore,
+ BridgeIDBOpenDBRequest,
+ BridgeIDBRequest,
+ BridgeIDBTransaction,
+ DatabaseList,
+ RequestObj,
+} from "./bridge-idb";
export {
BridgeIDBCursor,
- BridgeIDBCursorDirection,
BridgeIDBDatabase,
- BridgeIDBDatabaseInfo,
BridgeIDBFactory,
BridgeIDBIndex,
BridgeIDBKeyRange,
@@ -58,33 +46,26 @@ export {
BridgeIDBOpenDBRequest,
BridgeIDBRequest,
BridgeIDBTransaction,
- Value,
- CursorSource,
- CursorRange,
- Key,
+ StoreLevel,
+ ResultLevel,
+};
+export type {
DatabaseTransaction,
RecordGetRequest,
RecordGetResponse,
- KeyPath,
Schema,
Backend,
- TransactionMode,
DatabaseList,
RecordStoreRequest,
RecordStoreResponse,
- FakeEventTarget,
DatabaseConnection,
- FakeDOMStringList,
ObjectStoreProperties,
RequestObj,
- StoreLevel,
- ResultLevel,
DatabaseDump,
ObjectStoreDump,
IndexDump,
IndexRecord,
ObjectStoreRecord,
- EventType,
IndexProperties,
MemoryBackendDump,
Event,
diff --git a/packages/idb-bridge/src/tree/b+tree.ts b/packages/idb-bridge/src/tree/b+tree.ts
index ea09d0c0c..a45a98620 100644
--- a/packages/idb-bridge/src/tree/b+tree.ts
+++ b/packages/idb-bridge/src/tree/b+tree.ts
@@ -25,7 +25,7 @@ SPDX-License-Identifier: MIT
// Original repository: https://github.com/qwertie/btree-typescript
import { ISortedMap, ISortedMapF } from "./interfaces";
-export {
+export type {
ISetSource,
ISetSink,
ISet,
diff --git a/packages/idb-bridge/src/util/FakeEvent.ts b/packages/idb-bridge/src/util/FakeEvent.ts
index 1c558d8a0..c16a58fd3 100644
--- a/packages/idb-bridge/src/util/FakeEvent.ts
+++ b/packages/idb-bridge/src/util/FakeEvent.ts
@@ -15,9 +15,18 @@
*/
import FakeEventTarget from "./FakeEventTarget";
-import { EventType } from "./types";
import { Event, EventTarget } from "../idbtypes";
+/** @public */
+export type EventType =
+ | "abort"
+ | "blocked"
+ | "complete"
+ | "error"
+ | "success"
+ | "upgradeneeded"
+ | "versionchange";
+
export class FakeEvent implements Event {
public eventPath: FakeEventTarget[] = [];
public type: EventType;
diff --git a/packages/idb-bridge/src/util/FakeEventTarget.ts b/packages/idb-bridge/src/util/FakeEventTarget.ts
index 77df768f2..d2f46c98f 100644
--- a/packages/idb-bridge/src/util/FakeEventTarget.ts
+++ b/packages/idb-bridge/src/util/FakeEventTarget.ts
@@ -15,8 +15,7 @@
*/
import { InvalidStateError } from "./errors";
-import FakeEvent from "./FakeEvent";
-import { EventType } from "./types";
+import FakeEvent, { EventType } from "./FakeEvent";
import {
EventTarget,
Event,
diff --git a/packages/idb-bridge/src/util/canInjectKey.ts b/packages/idb-bridge/src/util/canInjectKey.ts
index 8a9666901..09ecbd3ad 100644
--- a/packages/idb-bridge/src/util/canInjectKey.ts
+++ b/packages/idb-bridge/src/util/canInjectKey.ts
@@ -14,10 +14,10 @@
permissions and limitations under the License.
*/
-import { KeyPath, Value } from "./types";
+import { IDBKeyPath } from "../idbtypes";
// http://w3c.github.io/IndexedDB/#check-that-a-key-could-be-injected-into-a-value
-const canInjectKey = (keyPath: KeyPath, value: Value) => {
+const canInjectKey = (keyPath: IDBKeyPath, value: any) => {
if (Array.isArray(keyPath)) {
// tslint:disable-next-line max-line-length
throw new Error(
diff --git a/packages/idb-bridge/src/util/deepEquals.ts b/packages/idb-bridge/src/util/deepEquals.ts
index 716786aba..bb7c0269c 100644
--- a/packages/idb-bridge/src/util/deepEquals.ts
+++ b/packages/idb-bridge/src/util/deepEquals.ts
@@ -24,7 +24,7 @@ const isArray = Array.isArray;
const keyList = Object.keys;
const hasProp = Object.prototype.hasOwnProperty;
-function deepEquals(a: any, b: any): boolean {
+export function deepEquals(a: any, b: any): boolean {
if (a === b) return true;
if (a && b && typeof a == "object" && typeof b == "object") {
diff --git a/packages/idb-bridge/src/util/extractKey.ts b/packages/idb-bridge/src/util/extractKey.ts
index 27f20310c..7aa8bd173 100644
--- a/packages/idb-bridge/src/util/extractKey.ts
+++ b/packages/idb-bridge/src/util/extractKey.ts
@@ -15,13 +15,13 @@
permissions and limitations under the License.
*/
-import { Key, KeyPath, Value } from "./types";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
import valueToKey from "./valueToKey";
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-extracting-a-key-from-a-value-using-a-key-path
-const extractKey = (keyPath: KeyPath, value: Value) => {
+const extractKey = (keyPath: IDBKeyPath | IDBKeyPath[], value: any) => {
if (Array.isArray(keyPath)) {
- const result: Key[] = [];
+ const result: IDBValidKey[] = [];
for (let item of keyPath) {
// This doesn't make sense to me based on the spec, but it is needed to pass the W3C KeyPath tests (see same
diff --git a/packages/idb-bridge/src/util/fakeDOMStringList.ts b/packages/idb-bridge/src/util/fakeDOMStringList.ts
index 5add17588..09ef77003 100644
--- a/packages/idb-bridge/src/util/fakeDOMStringList.ts
+++ b/packages/idb-bridge/src/util/fakeDOMStringList.ts
@@ -14,11 +14,15 @@
* permissions and limitations under the License.
*/
-import { FakeDOMStringList } from "./types";
+/** @public */
+export interface FakeDOMStringList extends Array<string> {
+ contains: (value: string) => boolean;
+ item: (i: number) => string | undefined;
+}
// Would be nicer to sublcass Array, but I'd have to sacrifice Node 4 support to do that.
-const fakeDOMStringList = (arr: string[]): FakeDOMStringList => {
+export const fakeDOMStringList = (arr: string[]): FakeDOMStringList => {
const arr2 = arr.slice();
Object.defineProperty(arr2, "contains", {
@@ -33,5 +37,3 @@ const fakeDOMStringList = (arr: string[]): FakeDOMStringList => {
return arr2 as FakeDOMStringList;
};
-
-export default fakeDOMStringList;
diff --git a/packages/idb-bridge/src/util/getIndexKeys.ts b/packages/idb-bridge/src/util/getIndexKeys.ts
index 253dc57bd..77b96b12f 100644
--- a/packages/idb-bridge/src/util/getIndexKeys.ts
+++ b/packages/idb-bridge/src/util/getIndexKeys.ts
@@ -15,15 +15,15 @@
permissions and limitations under the License.
*/
-import { Key, Value, KeyPath } from "./types";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
import extractKey from "./extractKey";
import valueToKey from "./valueToKey";
export function getIndexKeys(
- value: Value,
- keyPath: KeyPath,
+ value: any,
+ keyPath: IDBKeyPath | IDBKeyPath[],
multiEntry: boolean,
-): Key[] {
+): IDBValidKey[] {
if (multiEntry && Array.isArray(keyPath)) {
const keys = [];
for (const subkeyPath of keyPath) {
@@ -36,9 +36,11 @@ export function getIndexKeys(
}
}
return keys;
- } else {
+ } else if (typeof keyPath === "string" || Array.isArray(keyPath)) {
let key = extractKey(keyPath, value);
return [valueToKey(key)];
+ } else {
+ throw Error(`unsupported key path: ${typeof keyPath}`);
}
}
diff --git a/packages/idb-bridge/src/util/injectKey.ts b/packages/idb-bridge/src/util/injectKey.ts
index 38add33bd..678f42d28 100644
--- a/packages/idb-bridge/src/util/injectKey.ts
+++ b/packages/idb-bridge/src/util/injectKey.ts
@@ -15,12 +15,14 @@
permissions and limitations under the License.
*/
-import { KeyPath, Value, Key } from "./types";
-import canInjectKey from "./canInjectKey";
-import { DataError } from "./errors";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
import structuredClone from "./structuredClone";
-export function injectKey(keyPath: KeyPath, value: Value, key: Key): Value {
+export function injectKey(
+ keyPath: IDBKeyPath,
+ value: any,
+ key: IDBValidKey,
+): any {
if (Array.isArray(keyPath)) {
// tslint:disable-next-line max-line-length
throw new Error(
diff --git a/packages/idb-bridge/src/util/makeStoreKeyValue.ts b/packages/idb-bridge/src/util/makeStoreKeyValue.ts
index f9006ef51..b535bced5 100644
--- a/packages/idb-bridge/src/util/makeStoreKeyValue.ts
+++ b/packages/idb-bridge/src/util/makeStoreKeyValue.ts
@@ -14,25 +14,25 @@
permissions and limitations under the License.
*/
-import { Value, Key, KeyPath } from "./types";
import extractKey from "./extractKey";
import { DataError } from "./errors";
import valueToKey from "./valueToKey";
import structuredClone from "./structuredClone";
import injectKey from "./injectKey";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
export interface StoreKeyResult {
updatedKeyGenerator: number;
- key: Key;
- value: Value;
+ key: IDBValidKey;
+ value: any;
}
export function makeStoreKeyValue(
- value: Value,
- key: Key | undefined,
+ value: any,
+ key: IDBValidKey | undefined,
currentKeyGenerator: number,
autoIncrement: boolean,
- keyPath: KeyPath | null,
+ keyPath: IDBKeyPath | null,
): StoreKeyResult {
const haveKey = key !== null && key !== undefined;
const haveKeyPath = keyPath !== null && keyPath !== undefined;
@@ -89,7 +89,7 @@ export function makeStoreKeyValue(
updatedKeyGenerator = currentKeyGenerator;
}
return {
- key: key,
+ key: key!,
value: value,
updatedKeyGenerator,
};
diff --git a/packages/idb-bridge/src/util/types.ts b/packages/idb-bridge/src/util/types.ts
deleted file mode 100644
index b07f5ad00..000000000
--- a/packages/idb-bridge/src/util/types.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- or implied. See the License for the specific language governing
- permissions and limitations under the License.
-*/
-
-import { BridgeIDBRequest } from "../BridgeIDBRequest";
-import { BridgeIDBKeyRange } from "../BridgeIDBKeyRange";
-import { BridgeIDBIndex } from "../BridgeIDBIndex";
-import { BridgeIDBObjectStore } from "../BridgeIDBObjectStore";
-import { Event } from "../idbtypes";
-
-/** @public */
-export type EventType =
- | "abort"
- | "blocked"
- | "complete"
- | "error"
- | "success"
- | "upgradeneeded"
- | "versionchange";
-
-/** @public */
-export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore;
-
-/** @public */
-export interface FakeDOMStringList extends Array<string> {
- contains: (value: string) => boolean;
- item: (i: number) => string | undefined;
-}
-
-/**
- * @public
- */
-export type BridgeIDBCursorDirection =
- | "next"
- | "nextunique"
- | "prev"
- | "prevunique";
-
-/** @public */
-export type KeyPath = string | string[];
-
-/** @public */
-export type Key = any;
-
-/** @public */
-export type CursorRange = Key | BridgeIDBKeyRange | undefined;
-
-/** @public */
-export type Value = any;
-
-/** @public */
-export interface Record {
- key: Key;
- value: Key | Value; // For indexes, will be Key. For object stores, will be Value.
-}
-
-/** @public */
-export type TransactionMode = "readonly" | "readwrite" | "versionchange";
-
-/** @public */
-export interface BridgeIDBDatabaseInfo {
- name: string;
- version: number;
-}
-
-/** @public */
-export interface RequestObj {
- operation: () => Promise<any>;
- request?: BridgeIDBRequest | undefined;
- source?: any;
-}
diff --git a/packages/idb-bridge/src/util/validateKeyPath.ts b/packages/idb-bridge/src/util/validateKeyPath.ts
index 072832190..8057172df 100644
--- a/packages/idb-bridge/src/util/validateKeyPath.ts
+++ b/packages/idb-bridge/src/util/validateKeyPath.ts
@@ -14,24 +14,25 @@
permissions and limitations under the License.
*/
-import { KeyPath } from "./types";
+import { IDBKeyPath } from "../idbtypes";
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-valid-key-path
-const validateKeyPath = (keyPath: KeyPath, parent?: "array" | "string") => {
+const validateKeyPath = (keyPath: IDBKeyPath, parent?: "array" | "string") => {
// This doesn't make sense to me based on the spec, but it is needed to pass the W3C KeyPath tests (see same
// comment in extractKey)
+ let myKeyPath: IDBKeyPath | IDBKeyPath[] = keyPath;
if (
- keyPath !== undefined &&
- keyPath !== null &&
- typeof keyPath !== "string" &&
- keyPath.toString &&
- (parent === "array" || !Array.isArray(keyPath))
+ myKeyPath !== undefined &&
+ myKeyPath !== null &&
+ typeof myKeyPath !== "string" &&
+ (myKeyPath as any).toString &&
+ (parent === "array" || !Array.isArray(myKeyPath))
) {
- keyPath = keyPath.toString();
+ myKeyPath = (myKeyPath as any).toString();
}
- if (typeof keyPath === "string") {
- if (keyPath === "" && parent !== "string") {
+ if (typeof myKeyPath === "string") {
+ if (myKeyPath === "" && parent !== "string") {
return;
}
try {
@@ -39,33 +40,33 @@ const validateKeyPath = (keyPath: KeyPath, parent?: "array" | "string") => {
// reserved words at beginning removed
// tslint:disable-next-line max-line-length
const validIdentifierRegex = /^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC])(?:[\$0-9A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC])*$/;
- if (keyPath.length >= 1 && validIdentifierRegex.test(keyPath)) {
+ if (myKeyPath.length >= 1 && validIdentifierRegex.test(myKeyPath)) {
return;
}
} catch (err) {
throw new SyntaxError(err.message);
}
- if (keyPath.indexOf(" ") >= 0) {
+ if (myKeyPath.indexOf(" ") >= 0) {
throw new SyntaxError(
"The keypath argument contains an invalid key path (no spaces allowed).",
);
}
}
- if (Array.isArray(keyPath) && keyPath.length > 0) {
+ if (Array.isArray(myKeyPath) && myKeyPath.length > 0) {
if (parent) {
// No nested arrays
throw new SyntaxError(
"The keypath argument contains an invalid key path (nested arrays).",
);
}
- for (const part of keyPath) {
+ for (const part of myKeyPath) {
validateKeyPath(part, "array");
}
return;
- } else if (typeof keyPath === "string" && keyPath.indexOf(".") >= 0) {
- keyPath = keyPath.split(".");
- for (const part of keyPath) {
+ } else if (typeof myKeyPath === "string" && myKeyPath.indexOf(".") >= 0) {
+ myKeyPath = myKeyPath.split(".");
+ for (const part of myKeyPath) {
validateKeyPath(part, "string");
}
return;
diff --git a/packages/idb-bridge/src/util/valueToKey.ts b/packages/idb-bridge/src/util/valueToKey.ts
index 5cf5b2b1b..c3661f9a1 100644
--- a/packages/idb-bridge/src/util/valueToKey.ts
+++ b/packages/idb-bridge/src/util/valueToKey.ts
@@ -14,11 +14,14 @@
permissions and limitations under the License.
*/
+import { IDBValidKey } from "..";
import { DataError } from "./errors";
-import { Key } from "./types";
// https://w3c.github.io/IndexedDB/#convert-a-value-to-a-input
-function valueToKey(input: any, seen?: Set<object>): Key | Key[] {
+function valueToKey(
+ input: any,
+ seen?: Set<object>,
+): IDBValidKey | IDBValidKey[] {
if (typeof input === "number") {
if (isNaN(input)) {
throw new DataError();
diff --git a/packages/idb-bridge/tsconfig.json b/packages/idb-bridge/tsconfig.json
index a385e964a..99c5e6e3c 100644
--- a/packages/idb-bridge/tsconfig.json
+++ b/packages/idb-bridge/tsconfig.json
@@ -16,6 +16,7 @@
"rootDir": "./src",
"esModuleInterop": true,
"importHelpers": true,
+ "isolatedModules": true,
"typeRoots": ["./node_modules/@types"]
},
"include": ["src/**/*"]