idb: add first web platform tests, fix issues detected by them
This commit is contained in:
parent
5ff5a686e4
commit
8c92499d85
@ -25,7 +25,9 @@
|
|||||||
"typescript": "^4.1.3"
|
"typescript": "^4.1.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0",
|
||||||
|
"typeson": "^5.18.2",
|
||||||
|
"typeson-registry": "^1.0.0-alpha.38"
|
||||||
},
|
},
|
||||||
"ava": {
|
"ava": {
|
||||||
"require": [
|
"require": [
|
||||||
|
@ -27,7 +27,11 @@ import {
|
|||||||
StoreLevel,
|
StoreLevel,
|
||||||
RecordStoreResponse,
|
RecordStoreResponse,
|
||||||
} from "./backend-interface";
|
} from "./backend-interface";
|
||||||
import structuredClone from "./util/structuredClone";
|
import {
|
||||||
|
structuredClone,
|
||||||
|
structuredEncapsulate,
|
||||||
|
structuredRevive,
|
||||||
|
} from "./util/structuredClone";
|
||||||
import {
|
import {
|
||||||
InvalidStateError,
|
InvalidStateError,
|
||||||
InvalidAccessError,
|
InvalidAccessError,
|
||||||
@ -39,7 +43,12 @@ import compareKeys from "./util/cmp";
|
|||||||
import { StoreKeyResult, makeStoreKeyValue } from "./util/makeStoreKeyValue";
|
import { StoreKeyResult, makeStoreKeyValue } from "./util/makeStoreKeyValue";
|
||||||
import getIndexKeys from "./util/getIndexKeys";
|
import getIndexKeys from "./util/getIndexKeys";
|
||||||
import openPromise from "./util/openPromise";
|
import openPromise from "./util/openPromise";
|
||||||
import { IDBKeyPath, IDBKeyRange, IDBTransactionMode, IDBValidKey } from "./idbtypes";
|
import {
|
||||||
|
IDBKeyPath,
|
||||||
|
IDBKeyRange,
|
||||||
|
IDBTransactionMode,
|
||||||
|
IDBValidKey,
|
||||||
|
} from "./idbtypes";
|
||||||
import { BridgeIDBKeyRange } from "./bridge-idb";
|
import { BridgeIDBKeyRange } from "./bridge-idb";
|
||||||
|
|
||||||
type Key = IDBValidKey;
|
type Key = IDBValidKey;
|
||||||
@ -742,7 +751,7 @@ export class MemoryBackend implements Backend {
|
|||||||
createObjectStore(
|
createObjectStore(
|
||||||
btx: DatabaseTransaction,
|
btx: DatabaseTransaction,
|
||||||
name: string,
|
name: string,
|
||||||
keyPath: string | string[] | null,
|
keyPath: string[] | null,
|
||||||
autoIncrement: boolean,
|
autoIncrement: boolean,
|
||||||
): void {
|
): void {
|
||||||
if (this.enableTracing) {
|
if (this.enableTracing) {
|
||||||
@ -776,9 +785,6 @@ export class MemoryBackend implements Backend {
|
|||||||
if (!schema) {
|
if (!schema) {
|
||||||
throw Error("no schema for versionchange tx");
|
throw Error("no schema for versionchange tx");
|
||||||
}
|
}
|
||||||
if (Array.isArray(keyPath)) {
|
|
||||||
throw Error("array key path not supported for object stores");
|
|
||||||
}
|
|
||||||
schema.objectStores[name] = {
|
schema.objectStores[name] = {
|
||||||
autoIncrement,
|
autoIncrement,
|
||||||
keyPath,
|
keyPath,
|
||||||
@ -791,7 +797,7 @@ export class MemoryBackend implements Backend {
|
|||||||
btx: DatabaseTransaction,
|
btx: DatabaseTransaction,
|
||||||
indexName: string,
|
indexName: string,
|
||||||
objectStoreName: string,
|
objectStoreName: string,
|
||||||
keyPath: IDBKeyPath,
|
keyPath: string[],
|
||||||
multiEntry: boolean,
|
multiEntry: boolean,
|
||||||
unique: boolean,
|
unique: boolean,
|
||||||
): void {
|
): void {
|
||||||
@ -1401,9 +1407,10 @@ export class MemoryBackend implements Backend {
|
|||||||
schema.objectStores[storeReq.objectStoreName].autoIncrement;
|
schema.objectStores[storeReq.objectStoreName].autoIncrement;
|
||||||
const keyPath = schema.objectStores[storeReq.objectStoreName].keyPath;
|
const keyPath = schema.objectStores[storeReq.objectStoreName].keyPath;
|
||||||
let storeKeyResult: StoreKeyResult;
|
let storeKeyResult: StoreKeyResult;
|
||||||
|
const revivedValue = structuredRevive(storeReq.value);
|
||||||
try {
|
try {
|
||||||
storeKeyResult = makeStoreKeyValue(
|
storeKeyResult = makeStoreKeyValue(
|
||||||
storeReq.value,
|
revivedValue,
|
||||||
storeReq.key,
|
storeReq.key,
|
||||||
keygen,
|
keygen,
|
||||||
autoIncrement,
|
autoIncrement,
|
||||||
@ -1413,7 +1420,9 @@ export class MemoryBackend implements Backend {
|
|||||||
if (e instanceof DataError) {
|
if (e instanceof DataError) {
|
||||||
const kp = JSON.stringify(keyPath);
|
const kp = JSON.stringify(keyPath);
|
||||||
const n = storeReq.objectStoreName;
|
const n = storeReq.objectStoreName;
|
||||||
const m = `Could not extract key from value, objectStore=${n}, keyPath=${kp}`;
|
const m = `Could not extract key from value, objectStore=${n}, keyPath=${kp}, value=${JSON.stringify(
|
||||||
|
storeReq.value,
|
||||||
|
)}`;
|
||||||
if (this.enableTracing) {
|
if (this.enableTracing) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
console.error("value was:", storeReq.value);
|
console.error("value was:", storeReq.value);
|
||||||
|
@ -25,14 +25,14 @@ import {
|
|||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface ObjectStoreProperties {
|
export interface ObjectStoreProperties {
|
||||||
keyPath: IDBKeyPath | null;
|
keyPath: string[] | null;
|
||||||
autoIncrement: boolean;
|
autoIncrement: boolean;
|
||||||
indexes: { [nameame: string]: IndexProperties };
|
indexes: { [nameame: string]: IndexProperties };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export interface IndexProperties {
|
export interface IndexProperties {
|
||||||
keyPath: IDBKeyPath;
|
keyPath: string[];
|
||||||
multiEntry: boolean;
|
multiEntry: boolean;
|
||||||
unique: boolean;
|
unique: boolean;
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ export interface Backend {
|
|||||||
btx: DatabaseTransaction,
|
btx: DatabaseTransaction,
|
||||||
indexName: string,
|
indexName: string,
|
||||||
objectStoreName: string,
|
objectStoreName: string,
|
||||||
keyPath: IDBKeyPath,
|
keyPath: string | string[],
|
||||||
multiEntry: boolean,
|
multiEntry: boolean,
|
||||||
unique: boolean,
|
unique: boolean,
|
||||||
): void;
|
): void;
|
||||||
|
@ -25,7 +25,23 @@ import {
|
|||||||
Schema,
|
Schema,
|
||||||
StoreLevel,
|
StoreLevel,
|
||||||
} from "./backend-interface";
|
} from "./backend-interface";
|
||||||
import { EventListener, IDBCursorDirection, IDBKeyPath, IDBKeyRange, IDBTransactionMode, IDBValidKey } from "./idbtypes";
|
import {
|
||||||
|
DOMException,
|
||||||
|
DOMStringList,
|
||||||
|
EventListener,
|
||||||
|
IDBCursor,
|
||||||
|
IDBCursorDirection,
|
||||||
|
IDBDatabase,
|
||||||
|
IDBIndex,
|
||||||
|
IDBKeyPath,
|
||||||
|
IDBKeyRange,
|
||||||
|
IDBObjectStore,
|
||||||
|
IDBOpenDBRequest,
|
||||||
|
IDBRequest,
|
||||||
|
IDBTransaction,
|
||||||
|
IDBTransactionMode,
|
||||||
|
IDBValidKey,
|
||||||
|
} from "./idbtypes";
|
||||||
import compareKeys from "./util/cmp";
|
import compareKeys from "./util/cmp";
|
||||||
import enforceRange from "./util/enforceRange";
|
import enforceRange from "./util/enforceRange";
|
||||||
import {
|
import {
|
||||||
@ -42,9 +58,10 @@ import {
|
|||||||
import { fakeDOMStringList } from "./util/fakeDOMStringList";
|
import { fakeDOMStringList } from "./util/fakeDOMStringList";
|
||||||
import FakeEvent from "./util/FakeEvent";
|
import FakeEvent from "./util/FakeEvent";
|
||||||
import FakeEventTarget from "./util/FakeEventTarget";
|
import FakeEventTarget from "./util/FakeEventTarget";
|
||||||
|
import { normalizeKeyPath } from "./util/normalizeKeyPath";
|
||||||
import openPromise from "./util/openPromise";
|
import openPromise from "./util/openPromise";
|
||||||
import queueTask from "./util/queueTask";
|
import queueTask from "./util/queueTask";
|
||||||
import structuredClone from "./util/structuredClone";
|
import { structuredClone, structuredEncapsulate, structuredRevive } from "./util/structuredClone";
|
||||||
import validateKeyPath from "./util/validateKeyPath";
|
import validateKeyPath from "./util/validateKeyPath";
|
||||||
import valueToKey from "./util/valueToKey";
|
import valueToKey from "./util/valueToKey";
|
||||||
|
|
||||||
@ -87,7 +104,7 @@ function simplifyRange(
|
|||||||
*
|
*
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export class BridgeIDBCursor {
|
export class BridgeIDBCursor implements IDBCursor {
|
||||||
_request: BridgeIDBRequest | undefined;
|
_request: BridgeIDBRequest | undefined;
|
||||||
|
|
||||||
private _gotValue: boolean = false;
|
private _gotValue: boolean = false;
|
||||||
@ -127,7 +144,7 @@ export class BridgeIDBCursor {
|
|||||||
if (this.source instanceof BridgeIDBObjectStore) {
|
if (this.source instanceof BridgeIDBObjectStore) {
|
||||||
return this.source;
|
return this.source;
|
||||||
}
|
}
|
||||||
return this.source.objectStore;
|
return this.source._objectStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _backend(): Backend {
|
get _backend(): Backend {
|
||||||
@ -149,15 +166,23 @@ export class BridgeIDBCursor {
|
|||||||
/* For babel */
|
/* For babel */
|
||||||
}
|
}
|
||||||
|
|
||||||
get key() {
|
get key(): IDBValidKey {
|
||||||
return this._key;
|
const k = this._key;
|
||||||
|
if (k === null || k === undefined) {
|
||||||
|
throw Error("no key");
|
||||||
|
}
|
||||||
|
return k;
|
||||||
}
|
}
|
||||||
set key(val) {
|
set key(val) {
|
||||||
/* For babel */
|
/* For babel */
|
||||||
}
|
}
|
||||||
|
|
||||||
get primaryKey() {
|
get primaryKey(): IDBValidKey {
|
||||||
return this._primaryKey;
|
const k = this._primaryKey;
|
||||||
|
if (k === 0 || k === undefined) {
|
||||||
|
throw Error("no key");
|
||||||
|
}
|
||||||
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
set primaryKey(val) {
|
set primaryKey(val) {
|
||||||
@ -221,7 +246,7 @@ export class BridgeIDBCursor {
|
|||||||
this._primaryKey = response.primaryKeys![0];
|
this._primaryKey = response.primaryKeys![0];
|
||||||
|
|
||||||
if (!this._keyOnly) {
|
if (!this._keyOnly) {
|
||||||
this._value = response.values![0];
|
this._value = structuredRevive(response.values![0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._gotValue = true;
|
this._gotValue = true;
|
||||||
@ -239,7 +264,7 @@ export class BridgeIDBCursor {
|
|||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const transaction = this._effectiveObjectStore.transaction;
|
const transaction = this._effectiveObjectStore._transaction;
|
||||||
|
|
||||||
if (transaction._state !== "active") {
|
if (transaction._state !== "active") {
|
||||||
throw new TransactionInactiveError();
|
throw new TransactionInactiveError();
|
||||||
@ -266,7 +291,7 @@ export class BridgeIDBCursor {
|
|||||||
|
|
||||||
const storeReq: RecordStoreRequest = {
|
const storeReq: RecordStoreRequest = {
|
||||||
key: this._primaryKey,
|
key: this._primaryKey,
|
||||||
value: value,
|
value: structuredEncapsulate(value),
|
||||||
objectStoreName: this._objectStoreName,
|
objectStoreName: this._objectStoreName,
|
||||||
storeLevel: StoreLevel.UpdateExisting,
|
storeLevel: StoreLevel.UpdateExisting,
|
||||||
};
|
};
|
||||||
@ -295,7 +320,7 @@ export class BridgeIDBCursor {
|
|||||||
* http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
|
* http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
|
||||||
*/
|
*/
|
||||||
public continue(key?: IDBValidKey) {
|
public continue(key?: IDBValidKey) {
|
||||||
const transaction = this._effectiveObjectStore.transaction;
|
const transaction = this._effectiveObjectStore._transaction;
|
||||||
|
|
||||||
if (transaction._state !== "active") {
|
if (transaction._state !== "active") {
|
||||||
throw new TransactionInactiveError();
|
throw new TransactionInactiveError();
|
||||||
@ -357,7 +382,7 @@ export class BridgeIDBCursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public delete() {
|
public delete() {
|
||||||
const transaction = this._effectiveObjectStore.transaction;
|
const transaction = this._effectiveObjectStore._transaction;
|
||||||
|
|
||||||
if (transaction._state !== "active") {
|
if (transaction._state !== "active") {
|
||||||
throw new TransactionInactiveError();
|
throw new TransactionInactiveError();
|
||||||
@ -547,7 +572,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {
|
|||||||
transaction._backend.createObjectStore(
|
transaction._backend.createObjectStore(
|
||||||
backendTx,
|
backendTx,
|
||||||
name,
|
name,
|
||||||
keyPath,
|
(keyPath !== null) ? normalizeKeyPath(keyPath) : null,
|
||||||
autoIncrement,
|
autoIncrement,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -583,7 +608,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {
|
|||||||
return (
|
return (
|
||||||
transaction._state === "active" &&
|
transaction._state === "active" &&
|
||||||
transaction.mode === "versionchange" &&
|
transaction.mode === "versionchange" &&
|
||||||
transaction.db === this
|
transaction._db === this
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -656,7 +681,7 @@ export class BridgeIDBFactory {
|
|||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
|
||||||
public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
|
public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
|
||||||
const request = new BridgeIDBOpenDBRequest();
|
const request = new BridgeIDBOpenDBRequest();
|
||||||
request.source = null;
|
request._source = null;
|
||||||
|
|
||||||
queueTask(async () => {
|
queueTask(async () => {
|
||||||
const databases = await this.backend.getDatabases();
|
const databases = await this.backend.getDatabases();
|
||||||
@ -709,7 +734,7 @@ export class BridgeIDBFactory {
|
|||||||
|
|
||||||
// tslint:disable-next-line max-line-length
|
// 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
|
// 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) {
|
public open(name: string, version?: number): BridgeIDBOpenDBRequest {
|
||||||
if (arguments.length > 1 && version !== undefined) {
|
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
|
// Based on spec, not sure why "MAX_SAFE_INTEGER" instead of "unsigned long long", but it's needed to pass
|
||||||
// tests
|
// tests
|
||||||
@ -761,9 +786,7 @@ export class BridgeIDBFactory {
|
|||||||
});
|
});
|
||||||
event2.eventPath = [request];
|
event2.eventPath = [request];
|
||||||
request.dispatchEvent(event2);
|
request.dispatchEvent(event2);
|
||||||
}
|
} else if (existingVersion < requestedVersion) {
|
||||||
|
|
||||||
if (existingVersion < requestedVersion) {
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
|
||||||
|
|
||||||
for (const otherConn of this.connections) {
|
for (const otherConn of this.connections) {
|
||||||
@ -803,7 +826,9 @@ export class BridgeIDBFactory {
|
|||||||
request.transaction = transaction;
|
request.transaction = transaction;
|
||||||
request.dispatchEvent(event);
|
request.dispatchEvent(event);
|
||||||
|
|
||||||
|
console.log("awaiting until initial transaction is done");
|
||||||
await transaction._waitDone();
|
await transaction._waitDone();
|
||||||
|
console.log("initial transaction is done");
|
||||||
|
|
||||||
// We don't explicitly exit the versionchange transaction,
|
// We don't explicitly exit the versionchange transaction,
|
||||||
// since this is already done by the BridgeIDBTransaction.
|
// since this is already done by the BridgeIDBTransaction.
|
||||||
@ -842,47 +867,51 @@ export class BridgeIDBFactory {
|
|||||||
const confirmActiveTransaction = (
|
const confirmActiveTransaction = (
|
||||||
index: BridgeIDBIndex,
|
index: BridgeIDBIndex,
|
||||||
): BridgeIDBTransaction => {
|
): BridgeIDBTransaction => {
|
||||||
if (index._deleted || index.objectStore._deleted) {
|
if (index._deleted || index._objectStore._deleted) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index.objectStore.transaction._state !== "active") {
|
if (index._objectStore._transaction._state !== "active") {
|
||||||
throw new TransactionInactiveError();
|
throw new TransactionInactiveError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return index.objectStore.transaction;
|
return index._objectStore._transaction;
|
||||||
};
|
};
|
||||||
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
|
||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBIndex {
|
export class BridgeIDBIndex implements IDBIndex {
|
||||||
objectStore: BridgeIDBObjectStore;
|
_objectStore: BridgeIDBObjectStore;
|
||||||
|
|
||||||
get _schema(): Schema {
|
get objectStore(): IDBObjectStore {
|
||||||
return this.objectStore.transaction.db._schema;
|
return this._objectStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
get keyPath(): IDBKeyPath {
|
get _schema(): Schema {
|
||||||
return this._schema.objectStores[this.objectStore.name].indexes[this._name]
|
return this._objectStore._transaction._db._schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
get keyPath(): IDBKeyPath | IDBKeyPath[] {
|
||||||
|
return this._schema.objectStores[this._objectStore.name].indexes[this._name]
|
||||||
.keyPath;
|
.keyPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
get multiEntry(): boolean {
|
get multiEntry(): boolean {
|
||||||
return this._schema.objectStores[this.objectStore.name].indexes[this._name]
|
return this._schema.objectStores[this._objectStore.name].indexes[this._name]
|
||||||
.multiEntry;
|
.multiEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
get unique(): boolean {
|
get unique(): boolean {
|
||||||
return this._schema.objectStores[this.objectStore.name].indexes[this._name]
|
return this._schema.objectStores[this._objectStore.name].indexes[this._name]
|
||||||
.unique;
|
.unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _backend(): Backend {
|
get _backend(): Backend {
|
||||||
return this.objectStore._backend;
|
return this._objectStore._backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
_confirmActiveTransaction(): { btx: DatabaseTransaction } {
|
_confirmActiveTransaction(): { btx: DatabaseTransaction } {
|
||||||
return this.objectStore._confirmActiveTransaction();
|
return this._objectStore._confirmActiveTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _name: string;
|
private _name: string;
|
||||||
@ -891,7 +920,7 @@ export class BridgeIDBIndex {
|
|||||||
|
|
||||||
constructor(objectStore: BridgeIDBObjectStore, name: string) {
|
constructor(objectStore: BridgeIDBObjectStore, name: string) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
this.objectStore = objectStore;
|
this._objectStore = objectStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
@ -900,9 +929,9 @@ export class BridgeIDBIndex {
|
|||||||
|
|
||||||
// https://w3c.github.io/IndexedDB/#dom-idbindex-name
|
// https://w3c.github.io/IndexedDB/#dom-idbindex-name
|
||||||
set name(name: any) {
|
set name(name: any) {
|
||||||
const transaction = this.objectStore.transaction;
|
const transaction = this._objectStore._transaction;
|
||||||
|
|
||||||
if (!transaction.db._runningVersionchangeTransaction) {
|
if (!transaction._db._runningVersionchangeTransaction) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,9 +948,9 @@ export class BridgeIDBIndex {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._backend.renameIndex(btx, this.objectStore.name, oldName, newName);
|
this._backend.renameIndex(btx, this._objectStore.name, oldName, newName);
|
||||||
|
|
||||||
if (this.objectStore.indexNames.indexOf(name) >= 0) {
|
if (this._objectStore._indexNames.indexOf(name) >= 0) {
|
||||||
throw new ConstraintError();
|
throw new ConstraintError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -942,12 +971,12 @@ export class BridgeIDBIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = new BridgeIDBRequest();
|
const request = new BridgeIDBRequest();
|
||||||
request.source = this;
|
request._source = this;
|
||||||
request.transaction = this.objectStore.transaction;
|
request.transaction = this._objectStore._transaction;
|
||||||
|
|
||||||
const cursor = new BridgeIDBCursorWithValue(
|
const cursor = new BridgeIDBCursorWithValue(
|
||||||
this,
|
this,
|
||||||
this.objectStore.name,
|
this._objectStore.name,
|
||||||
this._name,
|
this._name,
|
||||||
range,
|
range,
|
||||||
direction,
|
direction,
|
||||||
@ -958,7 +987,7 @@ export class BridgeIDBIndex {
|
|||||||
return cursor._iterate();
|
return cursor._iterate();
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.objectStore.transaction._execRequestAsync({
|
return this._objectStore._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
request,
|
request,
|
||||||
source: this,
|
source: this,
|
||||||
@ -981,12 +1010,12 @@ export class BridgeIDBIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = new BridgeIDBRequest();
|
const request = new BridgeIDBRequest();
|
||||||
request.source = this;
|
request._source = this;
|
||||||
request.transaction = this.objectStore.transaction;
|
request.transaction = this._objectStore._transaction;
|
||||||
|
|
||||||
const cursor = new BridgeIDBCursor(
|
const cursor = new BridgeIDBCursor(
|
||||||
this,
|
this,
|
||||||
this.objectStore.name,
|
this._objectStore.name,
|
||||||
this._name,
|
this._name,
|
||||||
range,
|
range,
|
||||||
direction,
|
direction,
|
||||||
@ -994,7 +1023,7 @@ export class BridgeIDBIndex {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.objectStore.transaction._execRequestAsync({
|
return this._objectStore._transaction._execRequestAsync({
|
||||||
operation: cursor._iterate.bind(cursor),
|
operation: cursor._iterate.bind(cursor),
|
||||||
request,
|
request,
|
||||||
source: this,
|
source: this,
|
||||||
@ -1013,7 +1042,7 @@ export class BridgeIDBIndex {
|
|||||||
indexName: this._name,
|
indexName: this._name,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
range: key,
|
range: key,
|
||||||
objectStoreName: this.objectStore._name,
|
objectStoreName: this._objectStore._name,
|
||||||
resultLevel: ResultLevel.Full,
|
resultLevel: ResultLevel.Full,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1027,17 +1056,20 @@ export class BridgeIDBIndex {
|
|||||||
if (!values) {
|
if (!values) {
|
||||||
throw Error("invariant violated");
|
throw Error("invariant violated");
|
||||||
}
|
}
|
||||||
return values[0];
|
return structuredRevive(values[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.objectStore.transaction._execRequestAsync({
|
return this._objectStore._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbindex-getall
|
// http://w3c.github.io/IndexedDB/#dom-idbindex-getall
|
||||||
public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
|
public getAll(
|
||||||
|
query?: BridgeIDBKeyRange | IDBValidKey,
|
||||||
|
count?: number,
|
||||||
|
): IDBRequest<any[]> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1054,7 +1086,7 @@ export class BridgeIDBIndex {
|
|||||||
indexName: this._name,
|
indexName: this._name,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
range: key,
|
range: key,
|
||||||
objectStoreName: this.objectStore._name,
|
objectStoreName: this._objectStore._name,
|
||||||
resultLevel: ResultLevel.OnlyKeys,
|
resultLevel: ResultLevel.OnlyKeys,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1071,14 +1103,17 @@ export class BridgeIDBIndex {
|
|||||||
return primaryKeys[0];
|
return primaryKeys[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.objectStore.transaction._execRequestAsync({
|
return this._objectStore._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
|
// http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
|
||||||
public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
|
public getAllKeys(
|
||||||
|
query?: BridgeIDBKeyRange | IDBValidKey,
|
||||||
|
count?: number,
|
||||||
|
): IDBRequest<IDBValidKey[]> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1098,7 +1133,7 @@ export class BridgeIDBIndex {
|
|||||||
indexName: this._name,
|
indexName: this._name,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
range: key,
|
range: key,
|
||||||
objectStoreName: this.objectStore._name,
|
objectStoreName: this._objectStore._name,
|
||||||
resultLevel: ResultLevel.OnlyCount,
|
resultLevel: ResultLevel.OnlyCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1108,7 +1143,7 @@ export class BridgeIDBIndex {
|
|||||||
return result.count;
|
return result.count;
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.objectStore.transaction._execRequestAsync({
|
return this._objectStore._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
@ -1231,36 +1266,44 @@ export class BridgeIDBKeyRange {
|
|||||||
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
|
||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBObjectStore {
|
export class BridgeIDBObjectStore implements IDBObjectStore {
|
||||||
_indexesCache: Map<string, BridgeIDBIndex> = new Map();
|
_indexesCache: Map<string, BridgeIDBIndex> = new Map();
|
||||||
|
|
||||||
transaction: BridgeIDBTransaction;
|
_transaction: BridgeIDBTransaction;
|
||||||
|
|
||||||
|
get transaction(): IDBTransaction {
|
||||||
|
return this._transaction;
|
||||||
|
}
|
||||||
|
|
||||||
get autoIncrement(): boolean {
|
get autoIncrement(): boolean {
|
||||||
return this._schema.objectStores[this._name].autoIncrement;
|
return this._schema.objectStores[this._name].autoIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
get indexNames(): FakeDOMStringList {
|
get _indexNames(): FakeDOMStringList {
|
||||||
return fakeDOMStringList(
|
return fakeDOMStringList(
|
||||||
Object.keys(this._schema.objectStores[this._name].indexes),
|
Object.keys(this._schema.objectStores[this._name].indexes),
|
||||||
).sort();
|
).sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
get keyPath(): IDBKeyPath | null {
|
get indexNames(): DOMStringList {
|
||||||
return this._schema.objectStores[this._name].keyPath;
|
return this._indexNames as DOMStringList;
|
||||||
|
}
|
||||||
|
|
||||||
|
get keyPath(): IDBKeyPath | IDBKeyPath[] {
|
||||||
|
return this._schema.objectStores[this._name].keyPath!;
|
||||||
}
|
}
|
||||||
|
|
||||||
_name: string;
|
_name: string;
|
||||||
|
|
||||||
get _schema(): Schema {
|
get _schema(): Schema {
|
||||||
return this.transaction.db._schema;
|
return this._transaction._db._schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
_deleted: boolean = false;
|
_deleted: boolean = false;
|
||||||
|
|
||||||
constructor(transaction: BridgeIDBTransaction, name: string) {
|
constructor(transaction: BridgeIDBTransaction, name: string) {
|
||||||
this._name = name;
|
this._name = name;
|
||||||
this.transaction = transaction;
|
this._transaction = transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
@ -1268,15 +1311,15 @@ export class BridgeIDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get _backend(): Backend {
|
get _backend(): Backend {
|
||||||
return this.transaction.db._backend;
|
return this._transaction._db._backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
get _backendConnection(): DatabaseConnection {
|
get _backendConnection(): DatabaseConnection {
|
||||||
return this.transaction.db._backendConnection;
|
return this._transaction._db._backendConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
_confirmActiveTransaction(): { btx: DatabaseTransaction } {
|
_confirmActiveTransaction(): { btx: DatabaseTransaction } {
|
||||||
const btx = this.transaction._backendTransaction;
|
const btx = this._transaction._backendTransaction;
|
||||||
if (!btx) {
|
if (!btx) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
@ -1285,9 +1328,9 @@ export class BridgeIDBObjectStore {
|
|||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
|
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
|
||||||
set name(newName: any) {
|
set name(newName: any) {
|
||||||
const transaction = this.transaction;
|
const transaction = this._transaction;
|
||||||
|
|
||||||
if (!transaction.db._runningVersionchangeTransaction) {
|
if (!transaction._db._runningVersionchangeTransaction) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1302,7 +1345,7 @@ export class BridgeIDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._backend.renameObjectStore(btx, oldName, newName);
|
this._backend.renameObjectStore(btx, oldName, newName);
|
||||||
this.transaction.db._schema = this._backend.getSchema(
|
this._transaction._db._schema = this._backend.getSchema(
|
||||||
this._backendConnection,
|
this._backendConnection,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1311,7 +1354,7 @@ export class BridgeIDBObjectStore {
|
|||||||
if (BridgeIDBFactory.enableTracing) {
|
if (BridgeIDBFactory.enableTracing) {
|
||||||
console.log(`TRACE: IDBObjectStore._store`);
|
console.log(`TRACE: IDBObjectStore._store`);
|
||||||
}
|
}
|
||||||
if (this.transaction.mode === "readonly") {
|
if (this._transaction.mode === "readonly") {
|
||||||
throw new ReadOnlyError();
|
throw new ReadOnlyError();
|
||||||
}
|
}
|
||||||
const operation = async () => {
|
const operation = async () => {
|
||||||
@ -1319,7 +1362,7 @@ export class BridgeIDBObjectStore {
|
|||||||
const result = await this._backend.storeRecord(btx, {
|
const result = await this._backend.storeRecord(btx, {
|
||||||
objectStoreName: this._name,
|
objectStoreName: this._name,
|
||||||
key: key,
|
key: key,
|
||||||
value: value,
|
value: structuredEncapsulate(value),
|
||||||
storeLevel: overwrite
|
storeLevel: overwrite
|
||||||
? StoreLevel.AllowOverwrite
|
? StoreLevel.AllowOverwrite
|
||||||
: StoreLevel.NoOverwrite,
|
: StoreLevel.NoOverwrite,
|
||||||
@ -1327,7 +1370,7 @@ export class BridgeIDBObjectStore {
|
|||||||
return result.key;
|
return result.key;
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({ operation, source: this });
|
return this._transaction._execRequestAsync({ operation, source: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
public put(value: any, key?: IDBValidKey) {
|
public put(value: any, key?: IDBValidKey) {
|
||||||
@ -1349,7 +1392,7 @@ export class BridgeIDBObjectStore {
|
|||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.transaction.mode === "readonly") {
|
if (this._transaction.mode === "readonly") {
|
||||||
throw new ReadOnlyError();
|
throw new ReadOnlyError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1366,7 +1409,7 @@ export class BridgeIDBObjectStore {
|
|||||||
return this._backend.deleteRecord(btx, this._name, keyRange);
|
return this._backend.deleteRecord(btx, this._name, keyRange);
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({
|
return this._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
@ -1424,31 +1467,39 @@ export class BridgeIDBObjectStore {
|
|||||||
if (!values) {
|
if (!values) {
|
||||||
throw Error("invariant violated");
|
throw Error("invariant violated");
|
||||||
}
|
}
|
||||||
return values[0];
|
return structuredRevive(values[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({
|
return this._transaction._execRequestAsync({
|
||||||
operation,
|
operation,
|
||||||
source: this,
|
source: this,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
|
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
|
||||||
public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
|
public getAll(
|
||||||
|
query?: BridgeIDBKeyRange | IDBValidKey,
|
||||||
|
count?: number,
|
||||||
|
): IDBRequest<any[]> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
|
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
|
||||||
public getKey(key?: BridgeIDBKeyRange | IDBValidKey) {
|
public getKey(
|
||||||
|
key?: BridgeIDBKeyRange | IDBValidKey,
|
||||||
|
): IDBRequest<IDBValidKey | undefined> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
|
// http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
|
||||||
public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
|
public getAllKeys(
|
||||||
|
query?: BridgeIDBKeyRange | IDBValidKey,
|
||||||
|
count?: number,
|
||||||
|
): IDBRequest<any[]> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
public clear() {
|
public clear(): IDBRequest<undefined> {
|
||||||
throw Error("not implemented");
|
throw Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1464,8 +1515,8 @@ export class BridgeIDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = new BridgeIDBRequest();
|
const request = new BridgeIDBRequest();
|
||||||
request.source = this;
|
request._source = this;
|
||||||
request.transaction = this.transaction;
|
request.transaction = this._transaction;
|
||||||
|
|
||||||
const cursor = new BridgeIDBCursorWithValue(
|
const cursor = new BridgeIDBCursorWithValue(
|
||||||
this,
|
this,
|
||||||
@ -1476,7 +1527,7 @@ export class BridgeIDBObjectStore {
|
|||||||
request,
|
request,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({
|
return this._transaction._execRequestAsync({
|
||||||
operation: () => cursor._iterate(),
|
operation: () => cursor._iterate(),
|
||||||
request,
|
request,
|
||||||
source: this,
|
source: this,
|
||||||
@ -1499,8 +1550,8 @@ export class BridgeIDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const request = new BridgeIDBRequest();
|
const request = new BridgeIDBRequest();
|
||||||
request.source = this;
|
request._source = this;
|
||||||
request.transaction = this.transaction;
|
request.transaction = this._transaction;
|
||||||
|
|
||||||
const cursor = new BridgeIDBCursor(
|
const cursor = new BridgeIDBCursor(
|
||||||
this,
|
this,
|
||||||
@ -1512,7 +1563,7 @@ export class BridgeIDBObjectStore {
|
|||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({
|
return this._transaction._execRequestAsync({
|
||||||
operation: cursor._iterate.bind(cursor),
|
operation: cursor._iterate.bind(cursor),
|
||||||
request,
|
request,
|
||||||
source: this,
|
source: this,
|
||||||
@ -1530,7 +1581,7 @@ export class BridgeIDBObjectStore {
|
|||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.transaction.db._runningVersionchangeTransaction) {
|
if (!this._transaction._db._runningVersionchangeTransaction) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1545,11 +1596,11 @@ export class BridgeIDBObjectStore {
|
|||||||
? optionalParameters.unique
|
? optionalParameters.unique
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
if (this.transaction.mode !== "versionchange") {
|
if (this._transaction.mode !== "versionchange") {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.indexNames.indexOf(indexName) >= 0) {
|
if (this._indexNames.indexOf(indexName) >= 0) {
|
||||||
throw new ConstraintError();
|
throw new ConstraintError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1563,7 +1614,7 @@ export class BridgeIDBObjectStore {
|
|||||||
btx,
|
btx,
|
||||||
indexName,
|
indexName,
|
||||||
this._name,
|
this._name,
|
||||||
keyPath,
|
normalizeKeyPath(keyPath),
|
||||||
multiEntry,
|
multiEntry,
|
||||||
unique,
|
unique,
|
||||||
);
|
);
|
||||||
@ -1577,7 +1628,7 @@ export class BridgeIDBObjectStore {
|
|||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.transaction._state === "finished") {
|
if (this._transaction._state === "finished") {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1594,11 +1645,11 @@ export class BridgeIDBObjectStore {
|
|||||||
throw new TypeError();
|
throw new TypeError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.transaction.mode !== "versionchange") {
|
if (this._transaction.mode !== "versionchange") {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.transaction.db._runningVersionchangeTransaction) {
|
if (!this._transaction._db._runningVersionchangeTransaction) {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1638,7 +1689,7 @@ export class BridgeIDBObjectStore {
|
|||||||
return result.count;
|
return result.count;
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.transaction._execRequestAsync({ operation, source: this });
|
return this._transaction._execRequestAsync({ operation, source: this });
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString() {
|
public toString() {
|
||||||
@ -1647,10 +1698,20 @@ export class BridgeIDBObjectStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBRequest extends FakeEventTarget {
|
export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {
|
||||||
_result: any = null;
|
_result: any = null;
|
||||||
_error: Error | null | undefined = null;
|
_error: Error | null | undefined = null;
|
||||||
source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null = null;
|
get source(): IDBObjectStore | IDBIndex | IDBCursor {
|
||||||
|
if (this._source) {
|
||||||
|
return this._source;
|
||||||
|
}
|
||||||
|
throw Error("source is null");
|
||||||
|
}
|
||||||
|
_source:
|
||||||
|
| BridgeIDBCursor
|
||||||
|
| BridgeIDBIndex
|
||||||
|
| BridgeIDBObjectStore
|
||||||
|
| null = null;
|
||||||
transaction: BridgeIDBTransaction | null = null;
|
transaction: BridgeIDBTransaction | null = null;
|
||||||
readyState: "done" | "pending" = "pending";
|
readyState: "done" | "pending" = "pending";
|
||||||
onsuccess: EventListener | null = null;
|
onsuccess: EventListener | null = null;
|
||||||
@ -1708,14 +1769,16 @@ export class BridgeIDBRequest extends FakeEventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
|
export class BridgeIDBOpenDBRequest
|
||||||
|
extends BridgeIDBRequest
|
||||||
|
implements IDBOpenDBRequest {
|
||||||
public onupgradeneeded: EventListener | null = null;
|
public onupgradeneeded: EventListener | null = null;
|
||||||
public onblocked: EventListener | null = null;
|
public onblocked: EventListener | null = null;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
// https://www.w3.org/TR/IndexedDB/#open-requests
|
// https://www.w3.org/TR/IndexedDB/#open-requests
|
||||||
this.source = null;
|
this._source = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString() {
|
public toString() {
|
||||||
@ -1725,17 +1788,32 @@ export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
|
|||||||
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
|
||||||
/** @public */
|
/** @public */
|
||||||
export class BridgeIDBTransaction extends FakeEventTarget {
|
export class BridgeIDBTransaction
|
||||||
|
extends FakeEventTarget
|
||||||
|
implements IDBTransaction {
|
||||||
public _state: "active" | "inactive" | "committing" | "finished" = "active";
|
public _state: "active" | "inactive" | "committing" | "finished" = "active";
|
||||||
public _started = false;
|
public _started = false;
|
||||||
public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
|
public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
|
||||||
|
|
||||||
public _backendTransaction?: DatabaseTransaction;
|
public _backendTransaction?: DatabaseTransaction;
|
||||||
|
|
||||||
public objectStoreNames: FakeDOMStringList;
|
public _objectStoreNames: FakeDOMStringList;
|
||||||
|
get objectStoreNames(): DOMStringList {
|
||||||
|
return this._objectStoreNames as DOMStringList;
|
||||||
|
}
|
||||||
public mode: IDBTransactionMode;
|
public mode: IDBTransactionMode;
|
||||||
public db: BridgeIDBDatabase;
|
public _db: BridgeIDBDatabase;
|
||||||
public error: Error | null = null;
|
|
||||||
|
get db(): IDBDatabase {
|
||||||
|
return this.db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public _error: Error | null = null;
|
||||||
|
|
||||||
|
get error(): DOMException {
|
||||||
|
return this._error as DOMException;
|
||||||
|
}
|
||||||
|
|
||||||
public onabort: EventListener | null = null;
|
public onabort: EventListener | null = null;
|
||||||
public oncomplete: EventListener | null = null;
|
public oncomplete: EventListener | null = null;
|
||||||
public onerror: EventListener | null = null;
|
public onerror: EventListener | null = null;
|
||||||
@ -1750,7 +1828,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
get _backend(): Backend {
|
get _backend(): Backend {
|
||||||
return this.db._backend;
|
return this._db._backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -1768,10 +1846,10 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
this._scope = new Set(storeNames);
|
this._scope = new Set(storeNames);
|
||||||
this._backendTransaction = backendTransaction;
|
this._backendTransaction = backendTransaction;
|
||||||
this.mode = mode;
|
this.mode = mode;
|
||||||
this.db = db;
|
this._db = db;
|
||||||
this.objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
|
this._objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
|
||||||
|
|
||||||
this.db._transactions.push(this);
|
this._db._transactions.push(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
|
// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
|
||||||
@ -1781,14 +1859,14 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
if (errName !== null) {
|
if (errName !== null) {
|
||||||
const e = new Error();
|
const e = new Error();
|
||||||
e.name = errName;
|
e.name = errName;
|
||||||
this.error = e;
|
this._error = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should this directly remove from _requests?
|
// Should this directly remove from _requests?
|
||||||
for (const { request } of this._requests) {
|
for (const { request } of this._requests) {
|
||||||
if (request.readyState !== "done") {
|
if (request.readyState !== "done") {
|
||||||
request.readyState = "done"; // This will cancel execution of this request's operation
|
request.readyState = "done"; // This will cancel execution of this request's operation
|
||||||
if (request.source) {
|
if (request._source) {
|
||||||
request.result = undefined;
|
request.result = undefined;
|
||||||
request.error = new AbortError();
|
request.error = new AbortError();
|
||||||
|
|
||||||
@ -1796,7 +1874,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
});
|
});
|
||||||
event.eventPath = [this.db, this];
|
event.eventPath = [this._db, this];
|
||||||
request.dispatchEvent(event);
|
request.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1813,7 +1891,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: false,
|
cancelable: false,
|
||||||
});
|
});
|
||||||
event.eventPath = [this.db];
|
event.eventPath = [this._db];
|
||||||
this.dispatchEvent(event);
|
this.dispatchEvent(event);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1828,7 +1906,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
|
// http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
|
||||||
public objectStore(name: string) {
|
public objectStore(name: string): BridgeIDBObjectStore {
|
||||||
if (this._state !== "active") {
|
if (this._state !== "active") {
|
||||||
throw new InvalidStateError();
|
throw new InvalidStateError();
|
||||||
}
|
}
|
||||||
@ -1858,7 +1936,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
request = new BridgeIDBRequest();
|
request = new BridgeIDBRequest();
|
||||||
} else {
|
} else {
|
||||||
request = new BridgeIDBRequest();
|
request = new BridgeIDBRequest();
|
||||||
request.source = source;
|
request._source = source;
|
||||||
request.transaction = (source as any).transaction;
|
request.transaction = (source as any).transaction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1884,7 +1962,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
|
|
||||||
if (!this._backendTransaction) {
|
if (!this._backendTransaction) {
|
||||||
this._backendTransaction = await this._backend.beginTransaction(
|
this._backendTransaction = await this._backend.beginTransaction(
|
||||||
this.db._backendConnection,
|
this._db._backendConnection,
|
||||||
Array.from(this._scope),
|
Array.from(this._scope),
|
||||||
this.mode,
|
this.mode,
|
||||||
);
|
);
|
||||||
@ -1905,7 +1983,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request && operation) {
|
if (request && operation) {
|
||||||
if (!request.source) {
|
if (!request._source) {
|
||||||
// Special requests like indexes that just need to run some code, with error handling already built into
|
// Special requests like indexes that just need to run some code, with error handling already built into
|
||||||
// operation
|
// operation
|
||||||
await operation();
|
await operation();
|
||||||
@ -1933,7 +2011,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.eventPath = [request, this, this.db];
|
event.eventPath = [request, this, this._db];
|
||||||
request.dispatchEvent(event);
|
request.dispatchEvent(event);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (this._state !== "committing") {
|
if (this._state !== "committing") {
|
||||||
@ -1959,7 +2037,7 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
event.eventPath = [this.db, this];
|
event.eventPath = [this._db, this];
|
||||||
request.dispatchEvent(event);
|
request.dispatchEvent(event);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (this._state !== "committing") {
|
if (this._state !== "committing") {
|
||||||
@ -1994,20 +2072,20 @@ export class BridgeIDBTransaction extends FakeEventTarget {
|
|||||||
|
|
||||||
this._state = "finished";
|
this._state = "finished";
|
||||||
|
|
||||||
if (!this.error) {
|
if (!this._error) {
|
||||||
if (BridgeIDBFactory.enableTracing) {
|
if (BridgeIDBFactory.enableTracing) {
|
||||||
console.log("dispatching 'complete' event on transaction");
|
console.log("dispatching 'complete' event on transaction");
|
||||||
}
|
}
|
||||||
const event = new FakeEvent("complete");
|
const event = new FakeEvent("complete");
|
||||||
event.eventPath = [this, this.db];
|
event.eventPath = [this, this._db];
|
||||||
this.dispatchEvent(event);
|
this.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
const idx = this.db._transactions.indexOf(this);
|
const idx = this._db._transactions.indexOf(this);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
throw Error("invariant failed");
|
throw Error("invariant failed");
|
||||||
}
|
}
|
||||||
this.db._transactions.splice(idx, 1);
|
this._db._transactions.splice(idx, 1);
|
||||||
|
|
||||||
this._resolveWait();
|
this._resolveWait();
|
||||||
}
|
}
|
||||||
|
3
packages/idb-bridge/src/idb-wpt-ported/README
Normal file
3
packages/idb-bridge/src/idb-wpt-ported/README
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
This directory contains test cases from the W3C Web Platform Tests suite for IndexedDB.
|
||||||
|
|
||||||
|
The original code for these tests can be found here: https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
|
191
packages/idb-bridge/src/idb-wpt-ported/keypath.test.ts
Normal file
191
packages/idb-bridge/src/idb-wpt-ported/keypath.test.ts
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
import test from "ava";
|
||||||
|
import { assert_key_equals, createdb } from "./wptsupport";
|
||||||
|
|
||||||
|
test("WPT test keypath.htm", async (t) => {
|
||||||
|
function keypath(
|
||||||
|
keypath: any,
|
||||||
|
objects: any[],
|
||||||
|
expected_keys: any[],
|
||||||
|
desc?: string,
|
||||||
|
) {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
console.log("key path", keypath);
|
||||||
|
console.log("checking", desc);
|
||||||
|
let db: any;
|
||||||
|
const store_name = "store-" + Date.now() + Math.random();
|
||||||
|
|
||||||
|
var open_rq = createdb(t);
|
||||||
|
open_rq.onupgradeneeded = function (e) {
|
||||||
|
db = (e.target as any).result;
|
||||||
|
var objStore = db.createObjectStore(store_name, { keyPath: keypath });
|
||||||
|
|
||||||
|
for (var i = 0; i < objects.length; i++) objStore.add(objects[i]);
|
||||||
|
};
|
||||||
|
|
||||||
|
open_rq.onsuccess = function (e) {
|
||||||
|
var actual_keys: any[] = [],
|
||||||
|
rq = db.transaction(store_name).objectStore(store_name).openCursor();
|
||||||
|
|
||||||
|
rq.onsuccess = (e: any) => {
|
||||||
|
var cursor = e.target.result;
|
||||||
|
|
||||||
|
if (cursor) {
|
||||||
|
actual_keys.push(cursor.key.valueOf());
|
||||||
|
cursor.continue();
|
||||||
|
} else {
|
||||||
|
assert_key_equals(actual_keys, expected_keys, "keyorder array");
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await keypath("my.key", [{ my: { key: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath("my.køi", [{ my: { køi: 5 } }], [5]);
|
||||||
|
|
||||||
|
await keypath("my.key_ya", [{ my: { key_ya: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath("public.key$ya", [{ public: { key$ya: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath("true.$", [{ true: { $: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath("my._", [{ my: { _: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath("delete.a7", [{ delete: { a7: 10 } }], [10]);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
"p.p.p.p.p.p.p.p.p.p.p.p.p.p",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
p: {
|
||||||
|
p: {
|
||||||
|
p: {
|
||||||
|
p: {
|
||||||
|
p: {
|
||||||
|
p: { p: { p: { p: { p: { p: { p: { p: { p: 10 } } } } } } } },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[10],
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
"str.length",
|
||||||
|
[{ str: "pony" }, { str: "my" }, { str: "little" }, { str: "" }],
|
||||||
|
[0, 2, 4, 6],
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
"arr.length",
|
||||||
|
[
|
||||||
|
{ arr: [0, 0, 0, 0] },
|
||||||
|
{ arr: [{}, 0, "hei", "length", Infinity, []] },
|
||||||
|
{ arr: [10, 10] },
|
||||||
|
{ arr: [] },
|
||||||
|
],
|
||||||
|
[0, 2, 4, 6],
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath("length", [[10, 10], "123", { length: 20 }], [2, 3, 20]);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
"",
|
||||||
|
[["bags"], "bean", 10],
|
||||||
|
[10, "bean", ["bags"]],
|
||||||
|
"'' uses value as key",
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
[""],
|
||||||
|
[["bags"], "bean", 10],
|
||||||
|
[[10], ["bean"], [["bags"]]],
|
||||||
|
"[''] uses value as [key]",
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
["x", "y"],
|
||||||
|
[
|
||||||
|
{ x: 10, y: 20 },
|
||||||
|
{ y: 1.337, x: 100 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[10, 20],
|
||||||
|
[100, 1.337],
|
||||||
|
],
|
||||||
|
"['x', 'y']",
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
[["x"], ["y"]],
|
||||||
|
[
|
||||||
|
{ x: 10, y: 20 },
|
||||||
|
{ y: 1.337, x: 100 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[10, 20],
|
||||||
|
[100, 1.337],
|
||||||
|
],
|
||||||
|
"[['x'], 'y'] (stringifies)",
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
[
|
||||||
|
"x",
|
||||||
|
{
|
||||||
|
toString: function () {
|
||||||
|
return "y";
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ x: 10, y: 20 },
|
||||||
|
{ y: 1.337, x: 100 },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[10, 20],
|
||||||
|
[100, 1.337],
|
||||||
|
],
|
||||||
|
"['x', {toString->'y'}] (stringifies)",
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
["name", "type"],
|
||||||
|
[
|
||||||
|
{ name: "orange", type: "fruit" },
|
||||||
|
{ name: "orange", type: ["telecom", "french"] },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
["orange", "fruit"],
|
||||||
|
["orange", ["telecom", "french"]],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
await keypath(
|
||||||
|
["name", "type.name"],
|
||||||
|
[
|
||||||
|
{ name: "orange", type: { name: "fruit" } },
|
||||||
|
{ name: "orange", type: { name: "telecom" } },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
["orange", "fruit"],
|
||||||
|
["orange", "telecom"],
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const loop_array: any[] = [];
|
||||||
|
loop_array.push(loop_array);
|
||||||
|
await keypath(
|
||||||
|
loop_array,
|
||||||
|
["a", 1, ["k"]],
|
||||||
|
[[1], ["a"], [["k"]]],
|
||||||
|
"array loop -> stringify becomes ['']",
|
||||||
|
);
|
||||||
|
|
||||||
|
t.pass();
|
||||||
|
});
|
46
packages/idb-bridge/src/idb-wpt-ported/value.test.ts
Normal file
46
packages/idb-bridge/src/idb-wpt-ported/value.test.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import test from "ava";
|
||||||
|
import { IDBVersionChangeEvent } from "../idbtypes";
|
||||||
|
import { createdb } from "./wptsupport";
|
||||||
|
|
||||||
|
test.cb("WPT test value.htm, array", (t) => {
|
||||||
|
const value = new Array();
|
||||||
|
const _instanceof = Array;
|
||||||
|
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
createdb(t).onupgradeneeded = function (e: IDBVersionChangeEvent) {
|
||||||
|
(e.target as any).result.createObjectStore("store").add(value, 1);
|
||||||
|
(e.target as any).onsuccess = (e: any) => {
|
||||||
|
console.log("in first onsuccess");
|
||||||
|
e.target.result
|
||||||
|
.transaction("store")
|
||||||
|
.objectStore("store")
|
||||||
|
.get(1).onsuccess = (e: any) => {
|
||||||
|
t.assert(e.target.result instanceof _instanceof, "instanceof");
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test.cb("WPT test value.htm, date", (t) => {
|
||||||
|
const value = new Date();
|
||||||
|
const _instanceof = Date;
|
||||||
|
|
||||||
|
t.plan(1);
|
||||||
|
|
||||||
|
createdb(t).onupgradeneeded = function (e: IDBVersionChangeEvent) {
|
||||||
|
(e.target as any).result.createObjectStore("store").add(value, 1);
|
||||||
|
(e.target as any).onsuccess = (e: any) => {
|
||||||
|
console.log("in first onsuccess");
|
||||||
|
e.target.result
|
||||||
|
.transaction("store")
|
||||||
|
.objectStore("store")
|
||||||
|
.get(1).onsuccess = (e: any) => {
|
||||||
|
t.assert(e.target.result instanceof _instanceof, "instanceof");
|
||||||
|
t.end();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
30
packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
Normal file
30
packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { ExecutionContext } from "ava";
|
||||||
|
import { BridgeIDBFactory } from "..";
|
||||||
|
import { IDBOpenDBRequest } from "../idbtypes";
|
||||||
|
import MemoryBackend from "../MemoryBackend";
|
||||||
|
import compareKeys from "../util/cmp";
|
||||||
|
|
||||||
|
BridgeIDBFactory.enableTracing = true;
|
||||||
|
const idbFactory = new BridgeIDBFactory(new MemoryBackend());
|
||||||
|
|
||||||
|
const self = {
|
||||||
|
indexedDB: idbFactory,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createdb(
|
||||||
|
t: ExecutionContext<unknown>,
|
||||||
|
dbname?: string,
|
||||||
|
version?: number,
|
||||||
|
): IDBOpenDBRequest {
|
||||||
|
var rq_open: IDBOpenDBRequest;
|
||||||
|
dbname = dbname ? dbname : "testdb-" + new Date().getTime() + Math.random();
|
||||||
|
if (version) rq_open = self.indexedDB.open(dbname, version);
|
||||||
|
else rq_open = self.indexedDB.open(dbname);
|
||||||
|
return rq_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assert_key_equals(actual: any, expected: any, description?: string) {
|
||||||
|
if (0 != compareKeys(actual, expected)) {
|
||||||
|
throw Error("expected keys to be the same");
|
||||||
|
}
|
||||||
|
}
|
@ -16,10 +16,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { IDBKeyPath, IDBValidKey } from "../idbtypes";
|
import { IDBKeyPath, IDBValidKey } from "../idbtypes";
|
||||||
import structuredClone from "./structuredClone";
|
import { structuredClone } from "./structuredClone";
|
||||||
|
|
||||||
export function injectKey(
|
export function injectKey(
|
||||||
keyPath: IDBKeyPath,
|
keyPath: IDBKeyPath | IDBKeyPath[],
|
||||||
value: any,
|
value: any,
|
||||||
key: IDBValidKey,
|
key: IDBValidKey,
|
||||||
): any {
|
): any {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import extractKey from "./extractKey";
|
import extractKey from "./extractKey";
|
||||||
import { DataError } from "./errors";
|
import { DataError } from "./errors";
|
||||||
import valueToKey from "./valueToKey";
|
import valueToKey from "./valueToKey";
|
||||||
import structuredClone from "./structuredClone";
|
import { structuredClone } from "./structuredClone";
|
||||||
import injectKey from "./injectKey";
|
import injectKey from "./injectKey";
|
||||||
import { IDBKeyPath, IDBValidKey } from "../idbtypes";
|
import { IDBKeyPath, IDBValidKey } from "../idbtypes";
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ export function makeStoreKeyValue(
|
|||||||
key: IDBValidKey | undefined,
|
key: IDBValidKey | undefined,
|
||||||
currentKeyGenerator: number,
|
currentKeyGenerator: number,
|
||||||
autoIncrement: boolean,
|
autoIncrement: boolean,
|
||||||
keyPath: IDBKeyPath | null,
|
keyPath: IDBKeyPath | IDBKeyPath[] | null,
|
||||||
): StoreKeyResult {
|
): StoreKeyResult {
|
||||||
const haveKey = key !== null && key !== undefined;
|
const haveKey = key !== null && key !== undefined;
|
||||||
const haveKeyPath = keyPath !== null && keyPath !== undefined;
|
const haveKeyPath = keyPath !== null && keyPath !== undefined;
|
||||||
@ -63,7 +63,11 @@ export function makeStoreKeyValue(
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// (yes, no, no)
|
// (yes, no, no)
|
||||||
throw new DataError();
|
return {
|
||||||
|
key: key!,
|
||||||
|
value: value,
|
||||||
|
updatedKeyGenerator: currentKeyGenerator,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
41
packages/idb-bridge/src/util/normalizeKeyPath.ts
Normal file
41
packages/idb-bridge/src/util/normalizeKeyPath.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
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 { IDBKeyPath } from "../idbtypes";
|
||||||
|
|
||||||
|
export function normalizeKeyPath(
|
||||||
|
keyPath: IDBKeyPath | IDBKeyPath[],
|
||||||
|
): string | string[] {
|
||||||
|
if (Array.isArray(keyPath)) {
|
||||||
|
const path: string[] = [];
|
||||||
|
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
|
||||||
|
// comment in validateKeyPath)
|
||||||
|
if (
|
||||||
|
item !== undefined &&
|
||||||
|
item !== null &&
|
||||||
|
typeof item !== "string" &&
|
||||||
|
(item as any).toString
|
||||||
|
) {
|
||||||
|
item = (item as any).toString();
|
||||||
|
}
|
||||||
|
path.push(item);
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return keyPath;
|
||||||
|
}
|
@ -14,17 +14,24 @@
|
|||||||
permissions and limitations under the License.
|
permissions and limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function structuredCloneImpl(val: any, visited: WeakMap<any, boolean>): any {
|
// @ts-ignore
|
||||||
// FIXME: replace with real implementation!
|
import Typeson from "typeson";
|
||||||
return JSON.parse(JSON.stringify(val));
|
// @ts-ignore
|
||||||
|
import structuredCloningThrowing from "typeson-registry/dist/presets/structured-cloning-throwing";
|
||||||
|
|
||||||
|
const TSON = new Typeson().register(structuredCloningThrowing);
|
||||||
|
|
||||||
|
export function structuredEncapsulate(val: any): any {
|
||||||
|
return TSON.encapsulate(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function structuredRevive(val: any): any {
|
||||||
|
return TSON.revive(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structured clone for IndexedDB.
|
* Structured clone for IndexedDB.
|
||||||
*/
|
*/
|
||||||
export function structuredClone(val: any): any {
|
export function structuredClone(val: any): any {
|
||||||
const visited: WeakMap<any, boolean> = new WeakMap<any, boolean>();
|
return structuredRevive(structuredEncapsulate(val));
|
||||||
return structuredCloneImpl(val, visited);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default structuredClone;
|
|
||||||
|
@ -106,7 +106,7 @@ function transactionToPromise(tx: IDBTransaction): Promise<void> {
|
|||||||
};
|
};
|
||||||
tx.onerror = () => {
|
tx.onerror = () => {
|
||||||
console.error("Transaction failed:", stack);
|
console.error("Transaction failed:", stack);
|
||||||
reject(tx.error);
|
reject(tx._error);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -394,8 +394,8 @@ function runWithTransaction<T, StoreTypes extends Store<string, {}>>(
|
|||||||
logger.error(`${stack}`);
|
logger.error(`${stack}`);
|
||||||
};
|
};
|
||||||
tx.onabort = () => {
|
tx.onabort = () => {
|
||||||
if (tx.error) {
|
if (tx._error) {
|
||||||
logger.error("Transaction aborted with error:", tx.error);
|
logger.error("Transaction aborted with error:", tx._error);
|
||||||
} else {
|
} else {
|
||||||
logger.error("Trasaction aborted (no error)");
|
logger.error("Trasaction aborted (no error)");
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ importers:
|
|||||||
packages/idb-bridge:
|
packages/idb-bridge:
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib: 2.1.0
|
tslib: 2.1.0
|
||||||
|
typeson: 5.18.2
|
||||||
|
typeson-registry: 1.0.0-alpha.38
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/node': 14.14.22
|
'@types/node': 14.14.22
|
||||||
ava: 3.15.0
|
ava: 3.15.0
|
||||||
@ -21,6 +23,8 @@ importers:
|
|||||||
rollup: ^2.37.1
|
rollup: ^2.37.1
|
||||||
tslib: ^2.1.0
|
tslib: ^2.1.0
|
||||||
typescript: ^4.1.3
|
typescript: ^4.1.3
|
||||||
|
typeson: ^5.18.2
|
||||||
|
typeson-registry: ^1.0.0-alpha.38
|
||||||
packages/pogen:
|
packages/pogen:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 14.14.22
|
'@types/node': 14.14.22
|
||||||
@ -1193,6 +1197,14 @@ packages:
|
|||||||
/balanced-match/1.0.0:
|
/balanced-match/1.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||||
|
/base64-arraybuffer-es6/0.6.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
peerDependencies:
|
||||||
|
core-js-bundle: ^3.6.5
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-57nLqKj4ShsDwFJWJsM4sZx6u60WbCge35rWRSevUwqxDtRwwxiKAO800zD2upPv4CfdWjQp//wSLar35nDKvA==
|
||||||
/base64-js/1.5.1:
|
/base64-js/1.5.1:
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
@ -3283,6 +3295,9 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
integrity: sha1-QVxEePK8wwEgwizhDtMib30+GOA=
|
||||||
|
/lodash.sortby/4.7.0:
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||||
/lodash/4.17.20:
|
/lodash/4.17.20:
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
@ -4005,7 +4020,6 @@ packages:
|
|||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
|
||||||
/punycode/2.1.1:
|
/punycode/2.1.1:
|
||||||
dev: true
|
|
||||||
engines:
|
engines:
|
||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
@ -4764,6 +4778,13 @@ packages:
|
|||||||
node: '>=8.0'
|
node: '>=8.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
|
||||||
|
/tr46/2.0.2:
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.1.1
|
||||||
|
engines:
|
||||||
|
node: '>=8'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==
|
||||||
/trim-off-newlines/1.0.1:
|
/trim-off-newlines/1.0.1:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -4871,6 +4892,25 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
|
integrity: sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==
|
||||||
|
/typeson-registry/1.0.0-alpha.38:
|
||||||
|
dependencies:
|
||||||
|
base64-arraybuffer-es6: 0.6.0
|
||||||
|
typeson: 5.18.2
|
||||||
|
whatwg-url: 8.4.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10.0.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-6lt2IhbNT9hyow5hljZqjWtVDXBIaC1X8bBGlBva0Pod2f42g23bVqww09ruquwSC48I8BSSCPi+B2dFHM5ihQ==
|
||||||
|
/typeson/5.18.2:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.1.14'
|
||||||
|
peerDependencies:
|
||||||
|
core-js-bundle: ^3.6.4
|
||||||
|
regenerator-runtime: ^0.13.3
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-Vetd+OGX05P4qHyHiSLdHZ5Z5GuQDrHHwSdjkqho9NSCYVSLSfRMjklD/unpHH8tXBR9Z/R05rwJSuMpMFrdsw==
|
||||||
/uglify-js/3.12.5:
|
/uglify-js/3.12.5:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
@ -4974,12 +5014,27 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
integrity: sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=
|
||||||
|
/webidl-conversions/6.1.0:
|
||||||
|
engines:
|
||||||
|
node: '>=10.4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
|
||||||
/well-known-symbols/2.0.0:
|
/well-known-symbols/2.0.0:
|
||||||
dev: true
|
dev: true
|
||||||
engines:
|
engines:
|
||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==
|
integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==
|
||||||
|
/whatwg-url/8.4.0:
|
||||||
|
dependencies:
|
||||||
|
lodash.sortby: 4.7.0
|
||||||
|
tr46: 2.0.2
|
||||||
|
webidl-conversions: 6.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==
|
||||||
/which-module/2.0.0:
|
/which-module/2.0.0:
|
||||||
dev: true
|
dev: true
|
||||||
resolution:
|
resolution:
|
||||||
|
Loading…
Reference in New Issue
Block a user