diff options
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/idb-bridge/src/MemoryBackend.test.ts | 2 | ||||
| -rw-r--r-- | packages/idb-bridge/src/MemoryBackend.ts | 14 | ||||
| -rw-r--r-- | packages/idb-bridge/src/bridge-idb.ts | 10 | ||||
| -rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/idbobjectstore_add.test.ts | 270 | ||||
| -rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts | 4 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/cmp.ts | 6 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/enforceRange.ts | 4 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/extractKey.ts | 6 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/getIndexKeys.ts | 6 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/injectKey.ts | 20 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/makeStoreKeyValue.ts | 6 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/openPromise.ts | 4 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/validateKeyPath.ts | 7 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/valueToKey.ts | 4 | 
14 files changed, 310 insertions, 53 deletions
| diff --git a/packages/idb-bridge/src/MemoryBackend.test.ts b/packages/idb-bridge/src/MemoryBackend.test.ts index 281a72e36..8f988bb99 100644 --- a/packages/idb-bridge/src/MemoryBackend.test.ts +++ b/packages/idb-bridge/src/MemoryBackend.test.ts @@ -23,7 +23,7 @@ import {    BridgeIDBRequest,    BridgeIDBTransaction,  } from "./bridge-idb"; -import MemoryBackend from "./MemoryBackend"; +import { MemoryBackend } from "./MemoryBackend";  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 2b4437bcf..9a9527729 100644 --- a/packages/idb-bridge/src/MemoryBackend.ts +++ b/packages/idb-bridge/src/MemoryBackend.ts @@ -29,7 +29,6 @@ import {  } from "./backend-interface";  import {    structuredClone, -  structuredEncapsulate,    structuredRevive,  } from "./util/structuredClone";  import { @@ -39,12 +38,11 @@ import {    DataError,  } from "./util/errors";  import BTree, { ISortedMapF } from "./tree/b+tree"; -import compareKeys from "./util/cmp"; +import { compareKeys } from "./util/cmp";  import { StoreKeyResult, makeStoreKeyValue } from "./util/makeStoreKeyValue"; -import getIndexKeys from "./util/getIndexKeys"; -import openPromise from "./util/openPromise"; +import { getIndexKeys } from "./util/getIndexKeys"; +import { openPromise } from "./util/openPromise";  import { -  IDBKeyPath,    IDBKeyRange,    IDBTransactionMode,    IDBValidKey, @@ -1440,7 +1438,7 @@ export class MemoryBackend implements Backend {        const hasKey = modifiedData.has(key);        if (hasKey && storeReq.storeLevel !== StoreLevel.AllowOverwrite) { -        throw Error("refusing to overwrite"); +        throw new ConstraintError("refusing to overwrite");        }      } @@ -1537,7 +1535,7 @@ export class MemoryBackend implements Backend {      }      const myConn = this.connectionsByTransaction[btx.transactionCookie];      if (!myConn) { -      throw Error("unknown connection"); +      throw Error("unknown transaction");      }      const db = this.databases[myConn.dbName];      if (!db) { @@ -1626,5 +1624,3 @@ export class MemoryBackend implements Backend {      }    }  } - -export default MemoryBackend; diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts index c4c589790..f519b9c24 100644 --- a/packages/idb-bridge/src/bridge-idb.ts +++ b/packages/idb-bridge/src/bridge-idb.ts @@ -42,8 +42,8 @@ import {    IDBTransactionMode,    IDBValidKey,  } from "./idbtypes"; -import compareKeys from "./util/cmp"; -import enforceRange from "./util/enforceRange"; +import { compareKeys } from "./util/cmp"; +import { enforceRange } from "./util/enforceRange";  import {    AbortError,    ConstraintError, @@ -59,15 +59,15 @@ import { fakeDOMStringList } from "./util/fakeDOMStringList";  import FakeEvent from "./util/FakeEvent";  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 {    structuredClone,    structuredEncapsulate,    structuredRevive,  } from "./util/structuredClone"; -import validateKeyPath from "./util/validateKeyPath"; -import valueToKey from "./util/valueToKey"; +import { validateKeyPath } from "./util/validateKeyPath"; +import { valueToKey } from "./util/valueToKey";  /** @public */  export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore; diff --git a/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore_add.test.ts b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore_add.test.ts new file mode 100644 index 000000000..b0c1de2d7 --- /dev/null +++ b/packages/idb-bridge/src/idb-wpt-ported/idbobjectstore_add.test.ts @@ -0,0 +1,270 @@ +import test from "ava"; +import { IDBDatabase } from "../idbtypes"; +import { createdb } from "./wptsupport"; + +// IDBObjectStore.add() - add with an inline key +test("WPT idbobjectstore_add.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: IDBDatabase | undefined; +    const record = { key: 1, property: "data" }; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db!.createObjectStore("store", { keyPath: "key" }); + +      objStore.add(record); +    }; + +    open_rq.onsuccess = function (e) { +      var rq = db!.transaction("store").objectStore("store").get(record.key); + +      rq.onsuccess = function (e: any) { +        t.deepEqual(e.target.result.property, record.property); +        t.deepEqual(e.target.result.key, record.key); +        resolve(); +      }; +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - add with an out-of-line key +test("WPT idbobjectstore_add2.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const key = 1; +    const record = { property: "data" }; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store"); + +      objStore.add(record, key); +    }; + +    open_rq.onsuccess = function (e) { +      var rq = db.transaction("store").objectStore("store").get(key); + +      rq.onsuccess = function (e: any) { +        t.deepEqual(e.target.result.property, record.property); +        resolve(); +      }; +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - record with same key already exists +test("WPT idbobjectstore_add3.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const record = { key: 1, property: "data" }; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { keyPath: "key" }); +      objStore.add(record); + +      var rq = objStore.add(record); +      rq.onsuccess = () => t.fail("success on adding duplicate record"); + +      rq.onerror = function (e: any) { +        t.deepEqual(e.target.error.name, "ConstraintError"); +        t.deepEqual(rq.error.name, "ConstraintError"); +        t.deepEqual(e.type, "error"); +        e.preventDefault(); +        e.stopPropagation(); +      }; +    }; + +    // Defer done, giving rq.onsuccess a chance to run +    open_rq.onsuccess = function (e) { +      resolve(); +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - add where an index has unique:true specified +test("WPT idbobjectstore_add4.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    let db: any; +    let record = { key: 1, property: "data" }; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { autoIncrement: true }); +      objStore.createIndex("i1", "property", { unique: true }); +      objStore.add(record); + +      var rq = objStore.add(record); +      rq.onsuccess = () => t.fail("success on adding duplicate indexed record"); + +      rq.onerror = function (e: any) { +        t.deepEqual(rq.error.name, "ConstraintError"); +        t.deepEqual(e.target.error.name, "ConstraintError"); +        t.deepEqual(e.type, "error"); +        e.preventDefault(); +        e.stopPropagation(); +      }; +    }; + +    // Defer done, giving a spurious rq.onsuccess a chance to run +    open_rq.onsuccess = function (e) { +      resolve(); +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - object store's key path is an object attribute +test("WPT idbobjectstore_add5.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const record = { test: { obj: { key: 1 } }, property: "data" }; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { keyPath: "test.obj.key" }); +      objStore.add(record); +    }; + +    open_rq.onsuccess = function (e: any) { +      var rq = db +        .transaction("store") +        .objectStore("store") +        .get(record.test.obj.key); + +      rq.onsuccess = function (e: any) { +        t.deepEqual(e.target.result.property, record.property); +        resolve(); +      }; +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - autoIncrement and inline keys +test("WPT idbobjectstore_add6.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const record = { property: "data" }; +    const expected_keys = [1, 2, 3, 4]; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { +        keyPath: "key", +        autoIncrement: true, +      }); + +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +    }; + +    open_rq.onsuccess = function (e) { +      var actual_keys: any[] = [], +        rq = db.transaction("store").objectStore("store").openCursor(); + +      rq.onsuccess = function (e: any) { +        var cursor = e.target.result; + +        if (cursor) { +          actual_keys.push(cursor.value.key); +          cursor.continue(); +        } else { +          t.deepEqual(actual_keys, expected_keys); +          resolve(); +        } +      }; +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - autoIncrement and out-of-line keys +test("WPT idbobjectstore_add7.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const record = { property: "data" }; +    const expected_keys = [1, 2, 3, 4]; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { autoIncrement: true }); + +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +    }; + +    open_rq.onsuccess = function (e) { +      var actual_keys: any[] = [], +        rq = db.transaction("store").objectStore("store").openCursor(); + +      rq.onsuccess = function (e: any) { +        var cursor = e.target.result; + +        if (cursor) { +          actual_keys.push(cursor.key); +          cursor.continue(); +        } else { +          t.deepEqual(actual_keys, expected_keys); +          resolve(); +        } +      }; +    }; +  }); +  t.pass(); +}); + +// IDBObjectStore.add() - object store has autoIncrement:true and the key path is an object attribute +test("WPT idbobjectstore_add8.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    const record = { property: "data" }; +    const expected_keys = [1, 2, 3, 4]; + +    var open_rq = createdb(t); +    open_rq.onupgradeneeded = function (e: any) { +      db = e.target.result; +      var objStore = db.createObjectStore("store", { +        keyPath: "test.obj.key", +        autoIncrement: true, +      }); + +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +      objStore.add(record); +    }; + +    open_rq.onsuccess = function (e) { +      var actual_keys: any[] = [], +        rq = db.transaction("store").objectStore("store").openCursor(); + +      rq.onsuccess = function (e: any) { +        var cursor = e.target.result; + +        if (cursor) { +          actual_keys.push(cursor.value.test.obj.key); +          cursor.continue(); +        } else { +          t.deepEqual(actual_keys, expected_keys); +          resolve(); +        } +      }; +    }; +  }); +  t.pass(); +}); diff --git a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts index f7b065f23..92e78a685 100644 --- a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts +++ b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts @@ -1,8 +1,8 @@  import { ExecutionContext } from "ava";  import { BridgeIDBFactory } from "..";  import { IDBOpenDBRequest } from "../idbtypes"; -import MemoryBackend from "../MemoryBackend"; -import compareKeys from "../util/cmp"; +import { MemoryBackend } from "../MemoryBackend"; +import { compareKeys } from "../util/cmp";  BridgeIDBFactory.enableTracing = true;  const idbFactory = new BridgeIDBFactory(new MemoryBackend()); diff --git a/packages/idb-bridge/src/util/cmp.ts b/packages/idb-bridge/src/util/cmp.ts index ddd43f2a6..e7f26bf1a 100644 --- a/packages/idb-bridge/src/util/cmp.ts +++ b/packages/idb-bridge/src/util/cmp.ts @@ -15,7 +15,7 @@   */  import { DataError } from "./errors"; -import valueToKey from "./valueToKey"; +import { valueToKey } from "./valueToKey";  const getType = (x: any) => {    if (typeof x === "number") { @@ -38,7 +38,7 @@ const getType = (x: any) => {  };  // https://w3c.github.io/IndexedDB/#compare-two-keys -const compareKeys = (first: any, second: any): -1 | 0 | 1 => { +export const compareKeys = (first: any, second: any): -1 | 0 | 1 => {    if (second === undefined) {      throw new TypeError();    } @@ -104,5 +104,3 @@ const compareKeys = (first: any, second: any): -1 | 0 | 1 => {    return first > second ? 1 : -1;  }; - -export default compareKeys; diff --git a/packages/idb-bridge/src/util/enforceRange.ts b/packages/idb-bridge/src/util/enforceRange.ts index 87e135798..ed463a330 100644 --- a/packages/idb-bridge/src/util/enforceRange.ts +++ b/packages/idb-bridge/src/util/enforceRange.ts @@ -17,7 +17,7 @@  // https://heycam.github.io/webidl/#EnforceRange -const enforceRange = ( +export const enforceRange = (    num: number,    type: "MAX_SAFE_INTEGER" | "unsigned long",  ) => { @@ -31,5 +31,3 @@ const enforceRange = (      return Math.floor(num);    }  }; - -export default enforceRange; diff --git a/packages/idb-bridge/src/util/extractKey.ts b/packages/idb-bridge/src/util/extractKey.ts index 7aa8bd173..09306ddec 100644 --- a/packages/idb-bridge/src/util/extractKey.ts +++ b/packages/idb-bridge/src/util/extractKey.ts @@ -16,10 +16,10 @@  */  import { IDBKeyPath, IDBValidKey } from "../idbtypes"; -import valueToKey from "./valueToKey"; +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: IDBKeyPath | IDBKeyPath[], value: any) => { +export const extractKey = (keyPath: IDBKeyPath | IDBKeyPath[], value: any) => {    if (Array.isArray(keyPath)) {      const result: IDBValidKey[] = []; @@ -68,5 +68,3 @@ const extractKey = (keyPath: IDBKeyPath | IDBKeyPath[], value: any) => {    return object;  }; - -export default extractKey; diff --git a/packages/idb-bridge/src/util/getIndexKeys.ts b/packages/idb-bridge/src/util/getIndexKeys.ts index 77b96b12f..8515d79ea 100644 --- a/packages/idb-bridge/src/util/getIndexKeys.ts +++ b/packages/idb-bridge/src/util/getIndexKeys.ts @@ -16,8 +16,8 @@  */  import { IDBKeyPath, IDBValidKey } from "../idbtypes"; -import extractKey from "./extractKey"; -import valueToKey from "./valueToKey"; +import { extractKey } from "./extractKey"; +import { valueToKey } from "./valueToKey";  export function getIndexKeys(    value: any, @@ -43,5 +43,3 @@ export function getIndexKeys(      throw Error(`unsupported key path: ${typeof keyPath}`);    }  } - -export default getIndexKeys; diff --git a/packages/idb-bridge/src/util/injectKey.ts b/packages/idb-bridge/src/util/injectKey.ts index 63c8deda4..02acfaa4c 100644 --- a/packages/idb-bridge/src/util/injectKey.ts +++ b/packages/idb-bridge/src/util/injectKey.ts @@ -30,6 +30,11 @@ export function injectKey(      );    } +  const newValue = structuredClone(value); + +  // Position inside the new value where we'll place the key eventually. +  let ptr = newValue; +    const identifiers = keyPath.split(".");    if (identifiers.length === 0) {      throw new Error("Assert: identifiers is not empty"); @@ -42,26 +47,23 @@ export function injectKey(    }    for (const identifier of identifiers) { -    if (typeof value !== "object" && !Array.isArray(value)) { -      return false; +    if (typeof ptr !== "object" && !Array.isArray(ptr)) { +      throw new Error("can't inject key");      }      const hop = value.hasOwnProperty(identifier);      if (!hop) { -      return true; +      ptr[identifier] = {};      } -    value = value[identifier]; +    ptr = ptr[identifier];    } -  if (!(typeof value === "object" || Array.isArray(value))) { +  if (!(typeof ptr === "object" || Array.isArray(ptr))) {      throw new Error("can't inject key");    } -  const newValue = structuredClone(value); -  newValue[lastIdentifier] = structuredClone(key); +  ptr[lastIdentifier] = structuredClone(key);    return newValue;  } - -export default injectKey; diff --git a/packages/idb-bridge/src/util/makeStoreKeyValue.ts b/packages/idb-bridge/src/util/makeStoreKeyValue.ts index 2281e983d..442a69ff5 100644 --- a/packages/idb-bridge/src/util/makeStoreKeyValue.ts +++ b/packages/idb-bridge/src/util/makeStoreKeyValue.ts @@ -14,11 +14,11 @@   permissions and limitations under the License.  */ -import extractKey from "./extractKey"; +import { extractKey } from "./extractKey";  import { DataError } from "./errors"; -import valueToKey from "./valueToKey"; +import { valueToKey } from "./valueToKey";  import { structuredClone } from "./structuredClone"; -import injectKey from "./injectKey"; +import { injectKey } from "./injectKey";  import { IDBKeyPath, IDBValidKey } from "../idbtypes";  export interface StoreKeyResult { diff --git a/packages/idb-bridge/src/util/openPromise.ts b/packages/idb-bridge/src/util/openPromise.ts index 915060deb..395d69e7b 100644 --- a/packages/idb-bridge/src/util/openPromise.ts +++ b/packages/idb-bridge/src/util/openPromise.ts @@ -14,7 +14,7 @@   permissions and limitations under the License.  */ -function openPromise<T>(): { +export function openPromise<T>(): {    promise: Promise<T>;    resolve: (v?: T | PromiseLike<T>) => void;    reject: (err?: any) => void; @@ -34,5 +34,3 @@ function openPromise<T>(): {    return { promise, resolve, reject };  } - -export default openPromise; diff --git a/packages/idb-bridge/src/util/validateKeyPath.ts b/packages/idb-bridge/src/util/validateKeyPath.ts index 2beb3c468..3bbe653b6 100644 --- a/packages/idb-bridge/src/util/validateKeyPath.ts +++ b/packages/idb-bridge/src/util/validateKeyPath.ts @@ -17,7 +17,10 @@  import { IDBKeyPath } from "../idbtypes";  // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-valid-key-path -const validateKeyPath = (keyPath: IDBKeyPath | IDBKeyPath[], parent?: "array" | "string") => { +export const validateKeyPath = ( +  keyPath: IDBKeyPath | 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; @@ -74,5 +77,3 @@ const validateKeyPath = (keyPath: IDBKeyPath | IDBKeyPath[], parent?: "array" |    throw new SyntaxError();  }; - -export default validateKeyPath; diff --git a/packages/idb-bridge/src/util/valueToKey.ts b/packages/idb-bridge/src/util/valueToKey.ts index c3661f9a1..cfef779fe 100644 --- a/packages/idb-bridge/src/util/valueToKey.ts +++ b/packages/idb-bridge/src/util/valueToKey.ts @@ -18,7 +18,7 @@ import { IDBValidKey } from "..";  import { DataError } from "./errors";  // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-input -function valueToKey( +export function valueToKey(    input: any,    seen?: Set<object>,  ): IDBValidKey | IDBValidKey[] { @@ -68,5 +68,3 @@ function valueToKey(      throw new DataError();    }  } - -export default valueToKey; | 
