summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-02-23 20:16:10 +0100
committerFlorian Dold <florian@dold.me>2021-02-23 20:16:10 +0100
commit9c85f6277bf85606eb4fbbca47f1a1b5404d2a2e (patch)
tree553a3b9ff58be2962e81b16d87b97ea42c257081
parent29d23b192da66b38d7bf8d80303d3cfb61fc9bdd (diff)
downloadwallet-core-9c85f6277bf85606eb4fbbca47f1a1b5404d2a2e.tar.gz
wallet-core-9c85f6277bf85606eb4fbbca47f1a1b5404d2a2e.tar.bz2
wallet-core-9c85f6277bf85606eb4fbbca47f1a1b5404d2a2e.zip
idb: implement missing methods
-rw-r--r--packages/idb-bridge/src/MemoryBackend.ts39
-rw-r--r--packages/idb-bridge/src/backend-interface.ts5
-rw-r--r--packages/idb-bridge/src/bridge-idb.ts299
-rw-r--r--pnpm-lock.yaml55
4 files changed, 387 insertions, 11 deletions
diff --git a/packages/idb-bridge/src/MemoryBackend.ts b/packages/idb-bridge/src/MemoryBackend.ts
index 2317fb163..68f60f756 100644
--- a/packages/idb-bridge/src/MemoryBackend.ts
+++ b/packages/idb-bridge/src/MemoryBackend.ts
@@ -860,6 +860,45 @@ export class MemoryBackend implements Backend {
});
}
+ async clearObjectStore(
+ btx: DatabaseTransaction,
+ objectStoreName: string,
+ ): Promise<void> {
+ const myConn = this.requireConnectionFromTransaction(btx);
+ const db = this.databases[myConn.dbName];
+ if (!db) {
+ throw Error("db not found");
+ }
+ if (db.txLevel < TransactionLevel.Write) {
+ throw Error("only allowed in write transaction");
+ }
+ if (
+ db.txRestrictObjectStores &&
+ !db.txRestrictObjectStores.includes(objectStoreName)
+ ) {
+ throw Error(
+ `Not allowed to access store '${objectStoreName}', transaction is over ${JSON.stringify(
+ db.txRestrictObjectStores,
+ )}`,
+ );
+ }
+
+ const schema = myConn.modifiedSchema;
+ const objectStoreMapEntry = myConn.objectStoreMap[objectStoreName];
+
+ objectStoreMapEntry.store.modifiedData = new BTree([], compareKeys);
+
+ for (const indexName of Object.keys(
+ schema.objectStores[objectStoreName].indexes,
+ )) {
+ const index = myConn.objectStoreMap[objectStoreName].indexMap[indexName];
+ if (!index) {
+ throw Error("index referenced by object store does not exist");
+ }
+ index.modifiedData = new BTree([], compareKeys);
+ }
+ }
+
async deleteRecord(
btx: DatabaseTransaction,
objectStoreName: string,
diff --git a/packages/idb-bridge/src/backend-interface.ts b/packages/idb-bridge/src/backend-interface.ts
index 3d2953847..5ca70c8a4 100644
--- a/packages/idb-bridge/src/backend-interface.ts
+++ b/packages/idb-bridge/src/backend-interface.ts
@@ -216,4 +216,9 @@ export interface Backend {
btx: DatabaseTransaction,
storeReq: RecordStoreRequest,
): Promise<RecordStoreResponse>;
+
+ clearObjectStore(
+ btx: DatabaseTransaction,
+ objectStoreName: string,
+ ): Promise<void>
}
diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts
index 744ad1aef..3c168674d 100644
--- a/packages/idb-bridge/src/bridge-idb.ts
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -1234,11 +1234,48 @@ export class BridgeIDBIndex implements IDBIndex {
query?: BridgeIDBKeyRange | IDBValidKey,
count?: number,
): IDBRequest<any[]> {
- throw Error("not implemented");
+ this._confirmIndexExists();
+ this._confirmActiveTransaction();
+ if (this._deleted) {
+ throw new InvalidStateError();
+ }
+
+ if (!(query instanceof BridgeIDBKeyRange)) {
+ query = BridgeIDBKeyRange._valueToKeyRange(query);
+ }
+
+ if (count === undefined) {
+ count = -1;
+ }
+
+ const getReq: RecordGetRequest = {
+ direction: "next",
+ indexName: this._name,
+ limit: count,
+ range: query,
+ objectStoreName: this._objectStore._name,
+ resultLevel: ResultLevel.Full,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmStartedBackendTransaction();
+ const result = await this._backend.getRecords(btx, getReq);
+ const values = result.values;
+ if (!values) {
+ throw Error("invariant violated");
+ }
+ return values.map((x) => structuredRevive(x));
+ };
+
+ return this._objectStore._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-getKey-IDBRequest-any-key
public getKey(key: BridgeIDBKeyRange | IDBValidKey) {
+ this._confirmIndexExists();
this._confirmActiveTransaction();
if (!(key instanceof BridgeIDBKeyRange)) {
@@ -1278,11 +1315,45 @@ export class BridgeIDBIndex implements IDBIndex {
query?: BridgeIDBKeyRange | IDBValidKey,
count?: number,
): IDBRequest<IDBValidKey[]> {
- throw Error("not implemented");
+ this._confirmIndexExists();
+ this._confirmActiveTransaction();
+
+ if (!(query instanceof BridgeIDBKeyRange)) {
+ query = BridgeIDBKeyRange._valueToKeyRange(query);
+ }
+
+ if (count === undefined) {
+ count = -1;
+ }
+
+ const getReq: RecordGetRequest = {
+ direction: "next",
+ indexName: this._name,
+ limit: count,
+ range: query,
+ objectStoreName: this._objectStore._name,
+ resultLevel: ResultLevel.OnlyKeys,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmStartedBackendTransaction();
+ const result = await this._backend.getRecords(btx, getReq);
+ const primaryKeys = result.primaryKeys;
+ if (!primaryKeys) {
+ throw Error("invariant violated");
+ }
+ return primaryKeys;
+ };
+
+ return this._objectStore._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-count-IDBRequest-any-key
public count(key: BridgeIDBKeyRange | IDBValidKey | null | undefined) {
+ this._confirmIndexExists();
this._confirmActiveTransaction();
if (key === null) {
@@ -1718,14 +1789,147 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
query?: BridgeIDBKeyRange | IDBValidKey,
count?: number,
): IDBRequest<any[]> {
- throw Error("not implemented");
+ if (BridgeIDBFactory.enableTracing) {
+ console.log(`getting from object store ${this._name} key ${query}`);
+ }
+
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (!this._transaction._active) {
+ throw new TransactionInactiveError();
+ }
+
+ if (this._deleted) {
+ throw new InvalidStateError(
+ "tried to call 'delete' on a deleted object store",
+ );
+ }
+
+ if (count === undefined) {
+ count = -1;
+ }
+
+ let keyRange: BridgeIDBKeyRange;
+
+ if (query instanceof BridgeIDBKeyRange) {
+ keyRange = query;
+ } else {
+ try {
+ keyRange = BridgeIDBKeyRange.only(valueToKey(query));
+ } catch (e) {
+ throw new DataError(
+ `invalid key (type ${typeof query}) for object store '${this._name}'`,
+ );
+ }
+ }
+
+ const recordRequest: RecordGetRequest = {
+ objectStoreName: this._name,
+ indexName: undefined,
+ lastIndexPosition: undefined,
+ lastObjectStorePosition: undefined,
+ direction: "next",
+ limit: count,
+ resultLevel: ResultLevel.Full,
+ range: keyRange,
+ };
+
+ const operation = async () => {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("running getAll operation:", recordRequest);
+ }
+ const { btx } = this._confirmStartedBackendTransaction();
+ const result = await this._backend.getRecords(btx, recordRequest);
+
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("get operation result count:", result.count);
+ }
+ const values = result.values;
+ if (!values) {
+ throw Error("invariant violated");
+ }
+ return values.map((x) => structuredRevive(x));
+ };
+
+ return this._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
public getKey(
- key?: BridgeIDBKeyRange | IDBValidKey,
+ query?: BridgeIDBKeyRange | IDBValidKey,
): IDBRequest<IDBValidKey | undefined> {
- throw Error("not implemented");
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (!this._transaction._active) {
+ throw new TransactionInactiveError();
+ }
+
+ if (this._deleted) {
+ throw new InvalidStateError(
+ "tried to call 'delete' on a deleted object store",
+ );
+ }
+
+ let keyRange: BridgeIDBKeyRange;
+
+ if (query instanceof BridgeIDBKeyRange) {
+ keyRange = query;
+ } else {
+ try {
+ keyRange = BridgeIDBKeyRange.only(valueToKey(query));
+ } catch (e) {
+ throw new DataError(
+ `invalid key (type ${typeof query}) for object store '${this._name}'`,
+ );
+ }
+ }
+
+ const recordRequest: RecordGetRequest = {
+ objectStoreName: this._name,
+ indexName: undefined,
+ lastIndexPosition: undefined,
+ lastObjectStorePosition: undefined,
+ direction: "next",
+ limit: 1,
+ resultLevel: ResultLevel.OnlyKeys,
+ range: keyRange,
+ };
+
+ const operation = async () => {
+ if (BridgeIDBFactory.enableTracing) {
+ console.log("running get operation:", recordRequest);
+ }
+ const { btx } = this._confirmStartedBackendTransaction();
+ 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 primaryKeys = result.primaryKeys;
+ if (!primaryKeys) {
+ throw Error("invariant violated");
+ }
+ if (primaryKeys.length !== 1) {
+ throw Error("invariant violated");
+ }
+ return structuredRevive(primaryKeys[0]);
+ };
+
+ return this._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
@@ -1733,11 +1937,86 @@ export class BridgeIDBObjectStore implements IDBObjectStore {
query?: BridgeIDBKeyRange | IDBValidKey,
count?: number,
): IDBRequest<any[]> {
- throw Error("not implemented");
+ if (arguments.length === 0) {
+ throw new TypeError();
+ }
+
+ if (!this._transaction._active) {
+ throw new TransactionInactiveError();
+ }
+
+ if (this._deleted) {
+ throw new InvalidStateError(
+ "tried to call 'delete' on a deleted object store",
+ );
+ }
+
+ if (count === undefined) {
+ count = -1;
+ }
+
+ let keyRange: BridgeIDBKeyRange;
+
+ if (query instanceof BridgeIDBKeyRange) {
+ keyRange = query;
+ } else {
+ try {
+ keyRange = BridgeIDBKeyRange.only(valueToKey(query));
+ } catch (e) {
+ throw new DataError(
+ `invalid key (type ${typeof query}) for object store '${this._name}'`,
+ );
+ }
+ }
+
+ const recordRequest: RecordGetRequest = {
+ objectStoreName: this._name,
+ indexName: undefined,
+ lastIndexPosition: undefined,
+ lastObjectStorePosition: undefined,
+ direction: "next",
+ limit: count,
+ resultLevel: ResultLevel.OnlyKeys,
+ range: keyRange,
+ };
+
+ const operation = async () => {
+ const { btx } = this._confirmStartedBackendTransaction();
+ const result = await this._backend.getRecords(btx, recordRequest);
+
+ const primaryKeys = result.primaryKeys;
+ if (!primaryKeys) {
+ throw Error("invariant violated");
+ }
+ return primaryKeys.map((x) => structuredRevive(x));
+ };
+
+ return this._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
- public clear(): IDBRequest<undefined> {
- throw Error("not implemented");
+ public clear(): IDBRequest {
+ if (!this._transaction._active) {
+ throw new TransactionInactiveError();
+ }
+
+ if (this._deleted) {
+ throw new InvalidStateError(
+ "tried to call 'delete' on a deleted object store",
+ );
+ }
+
+ const operation = async () => {
+ const { btx } = this._confirmStartedBackendTransaction();
+ await this._backend.clearObjectStore(btx, this._name);
+ };
+
+ return this._transaction._execRequestAsync({
+ operation,
+ source: this,
+ });
}
public openCursor(
@@ -2228,12 +2507,12 @@ export class BridgeIDBTransaction
if (this._db._upgradeTransaction) {
for (const os of this._usedObjectStores) {
if (os._justCreated) {
- os._deleted = true
+ os._deleted = true;
}
}
for (const ind of this._usedIndexes) {
if (ind._justCreated) {
- ind._deleted = true
+ ind._deleted = true;
}
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 70a458397..be4eac3a4 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -7,6 +7,9 @@ importers:
typeson: 5.18.2
typeson-registry: 1.0.0-alpha.38
devDependencies:
+ '@rollup/plugin-commonjs': 17.1.0_rollup@2.37.1
+ '@rollup/plugin-json': 4.1.0_rollup@2.37.1
+ '@rollup/plugin-node-resolve': 11.2.0_rollup@2.37.1
'@types/node': 14.14.22
ava: 3.15.0
esm: 3.2.25
@@ -15,6 +18,9 @@ importers:
rollup: 2.37.1
typescript: 4.1.3
specifiers:
+ '@rollup/plugin-commonjs': ^17.1.0
+ '@rollup/plugin-json': ^4.1.0
+ '@rollup/plugin-node-resolve': ^11.2.0
'@types/node': ^14.14.22
ava: ^3.15.0
esm: ^3.2.25
@@ -520,6 +526,23 @@ packages:
rollup: ^2.30.0
resolution:
integrity: sha512-/omBIJG1nHQc+bgkYDuLpb/V08QyutP9amOrJRUSlYJZP+b/68gM//D8sxJe3Yry2QnYIr3QjR3x4AlxJEN3GA==
+ /@rollup/plugin-commonjs/17.1.0_rollup@2.37.1:
+ dependencies:
+ '@rollup/pluginutils': 3.1.0_rollup@2.37.1
+ commondir: 1.0.1
+ estree-walker: 2.0.2
+ glob: 7.1.6
+ is-reference: 1.2.1
+ magic-string: 0.25.7
+ resolve: 1.20.0
+ rollup: 2.37.1
+ dev: true
+ engines:
+ node: '>= 8.0.0'
+ peerDependencies:
+ rollup: ^2.30.0
+ resolution:
+ integrity: sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==
/@rollup/plugin-json/4.1.0_rollup@2.37.1:
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.37.1
@@ -545,6 +568,22 @@ packages:
rollup: ^1.20.0||^2.0.0
resolution:
integrity: sha512-ouBBppRdWJKCllDXGzJ7ZIkYbaq+5TmyP0smt1vdJCFfoZhLi31vhpmjLhyo8lreHf4RoeSNllaWrvSqHpHRog==
+ /@rollup/plugin-node-resolve/11.2.0_rollup@2.37.1:
+ dependencies:
+ '@rollup/pluginutils': 3.1.0_rollup@2.37.1
+ '@types/resolve': 1.17.1
+ builtin-modules: 3.2.0
+ deepmerge: 4.2.2
+ is-module: 1.0.0
+ resolve: 1.20.0
+ rollup: 2.37.1
+ dev: true
+ engines:
+ node: '>= 10.0.0'
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0
+ resolution:
+ integrity: sha512-qHjNIKYt5pCcn+5RUBQxK8krhRvf1HnyVgUCcFFcweDS7fhkOLZeYh0mhHK6Ery8/bb9tvN/ubPzmfF0qjDCTA==
/@rollup/plugin-replace/2.3.4_rollup@2.37.1:
dependencies:
'@rollup/pluginutils': 3.1.0_rollup@2.37.1
@@ -684,6 +723,10 @@ packages:
/@types/node/14.14.22:
resolution:
integrity: sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==
+ /@types/node/14.14.31:
+ dev: true
+ resolution:
+ integrity: sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
/@types/normalize-package-data/2.4.0:
dev: true
resolution:
@@ -707,7 +750,7 @@ packages:
integrity: sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==
/@types/resolve/1.17.1:
dependencies:
- '@types/node': 14.14.22
+ '@types/node': 14.14.31
dev: true
resolution:
integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
@@ -3296,6 +3339,7 @@ packages:
resolution:
integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=
/lodash.sortby/4.7.0:
+ dev: false
resolution:
integrity: sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
/lodash/4.17.20:
@@ -4239,6 +4283,13 @@ packages:
dev: true
resolution:
integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==
+ /resolve/1.20.0:
+ dependencies:
+ is-core-module: 2.2.0
+ path-parse: 1.0.6
+ dev: true
+ resolution:
+ integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
/responselike/1.0.2:
dependencies:
lowercase-keys: 1.0.1
@@ -4781,6 +4832,7 @@ packages:
/tr46/2.0.2:
dependencies:
punycode: 2.1.1
+ dev: false
engines:
node: '>=8'
resolution:
@@ -5015,6 +5067,7 @@ packages:
resolution:
integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
/webidl-conversions/6.1.0:
+ dev: false
engines:
node: '>=10.4'
resolution: