[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-wallet-core] branch master updated: idb-bridge: remove cyclic dep
From: |
gnunet |
Subject: |
[taler-wallet-core] branch master updated: idb-bridge: remove cyclic dependencies, rip out api extractor |
Date: |
Mon, 08 Feb 2021 15:23:49 +0100 |
This is an automated email from the git hooks/post-receive script.
dold pushed a commit to branch master
in repository wallet-core.
The following commit(s) were added to refs/heads/master by this push:
new 4452984a idb-bridge: remove cyclic dependencies, rip out api extractor
4452984a is described below
commit 4452984a24334e3b7afb60e3db9dc12db02d65ba
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Feb 8 15:23:44 2021 +0100
idb-bridge: remove cyclic dependencies, rip out api extractor
---
packages/idb-bridge/api-extractor.json | 131 --
packages/idb-bridge/package.json | 11 +-
packages/idb-bridge/src/BridgeIDBCursor.ts | 364 ----
.../idb-bridge/src/BridgeIDBCursorWithValue.ts | 48 -
packages/idb-bridge/src/BridgeIDBDatabase.ts | 249 ---
packages/idb-bridge/src/BridgeIDBFactory.ts | 226 ---
packages/idb-bridge/src/BridgeIDBIndex.ts | 319 ---
packages/idb-bridge/src/BridgeIDBKeyRange.ts | 131 --
packages/idb-bridge/src/BridgeIDBObjectStore.ts | 467 -----
packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts | 35 -
packages/idb-bridge/src/BridgeIDBRequest.ts | 86 -
packages/idb-bridge/src/BridgeIDBTransaction.ts | 326 ----
.../idb-bridge/src/BridgeIDBVersionChangeEvent.ts | 39 -
packages/idb-bridge/src/MemoryBackend.test.ts | 14 +-
packages/idb-bridge/src/MemoryBackend.ts | 28 +-
packages/idb-bridge/src/backend-interface.ts | 47 +-
packages/idb-bridge/src/bridge-idb.ts | 2053 ++++++++++++++++++++
packages/idb-bridge/src/index.ts | 53 +-
packages/idb-bridge/src/tree/b+tree.ts | 2 +-
packages/idb-bridge/src/util/FakeEvent.ts | 11 +-
packages/idb-bridge/src/util/FakeEventTarget.ts | 3 +-
packages/idb-bridge/src/util/canInjectKey.ts | 4 +-
packages/idb-bridge/src/util/deepEquals.ts | 2 +-
packages/idb-bridge/src/util/extractKey.ts | 6 +-
packages/idb-bridge/src/util/fakeDOMStringList.ts | 10 +-
packages/idb-bridge/src/util/getIndexKeys.ts | 12 +-
packages/idb-bridge/src/util/injectKey.ts | 10 +-
packages/idb-bridge/src/util/makeStoreKeyValue.ts | 14 +-
packages/idb-bridge/src/util/types.ts | 84 -
packages/idb-bridge/src/util/validateKeyPath.ts | 35 +-
packages/idb-bridge/src/util/valueToKey.ts | 7 +-
packages/idb-bridge/tsconfig.json | 1 +
pnpm-lock.yaml | 4 +-
33 files changed, 2196 insertions(+), 2636 deletions(-)
diff --git a/packages/idb-bridge/api-extractor.json
b/packages/idb-bridge/api-extractor.json
deleted file mode 100644
index f57d81d8..00000000
--- 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 f8be8298..cfa0fa9f 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 a18c0beb..00000000
--- 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 8561879c..00000000
--- 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 ffd897f9..00000000
--- 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 7954cdd9..00000000
--- 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 9b214a23..00000000
--- 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 d2eaa2d1..00000000
--- 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 6fdf3520..00000000
--- 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 306edcb7..00000000
--- 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 4800a058..00000000
--- 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 b064d069..00000000
--- 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 43e822d8..00000000
--- 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 737b83d9..281a72e3 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 531a7f29..6a52a555 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 4d1f107b..756a5b96 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 00000000..2bced800
--- /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 4c29be96..b6c15249 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 ea09d0c0..a45a9862 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 1c558d8a..c16a58fd 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 77df768f..d2f46c98 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 8a966690..09ecbd3a 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 716786ab..bb7c0269 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 27f20310..7aa8bd17 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 5add1758..09ef7700 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 253dc57b..77b96b12 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 38add33b..678f42d2 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 f9006ef5..b535bced 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 b07f5ad0..00000000
--- 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 07283219..8057172d 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\u0
[...]
- 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 5cf5b2b1..c3661f9a 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 a385e964..99c5e6e3 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/**/*"]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7ec0403c..2a75c2f2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3,10 +3,9 @@ importers:
specifiers: {}
packages/idb-bridge:
dependencies:
- '@types/node': 14.14.22
tslib: 2.1.0
devDependencies:
- '@microsoft/api-extractor': 7.13.0
+ '@types/node': 14.14.22
ava: 3.15.0
esm: 3.2.25
prettier: 2.2.1
@@ -14,7 +13,6 @@ importers:
rollup: 2.37.1
typescript: 4.1.3
specifiers:
- '@microsoft/api-extractor': ^7.13.0
'@types/node': ^14.14.22
ava: ^3.15.0
esm: ^3.2.25
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-wallet-core] branch master updated: idb-bridge: remove cyclic dependencies, rip out api extractor,
gnunet <=