tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

idbobjectstore_createIndex.any.js (20089B)


      1 // META: title=IDBObjectStore.createIndex()
      2 // META: global=window,worker
      3 // META: script=resources/support.js
      4 
      5 'use strict';
      6 
      7 async_test(t => {
      8    let db;
      9 
     10    let open_rq = createdb(t);
     11    open_rq.onupgradeneeded = function (e) {
     12        db = e.target.result;
     13        let objStore = db.createObjectStore("store");
     14        let index = objStore.createIndex("index", "indexedProperty", { unique: true });
     15 
     16        assert_true(index instanceof IDBIndex, "IDBIndex");
     17        assert_equals(index.name, "index", "name");
     18        assert_equals(index.objectStore, objStore, "objectStore");
     19        assert_equals(index.keyPath, "indexedProperty", "keyPath");
     20        assert_true(index.unique, "unique");
     21        assert_false(index.multiEntry, "multiEntry");
     22 
     23        t.done();
     24    };
     25 }, "Returns an IDBIndex and the properties are set correctly");
     26 
     27 async_test(t => {
     28    let db, aborted,
     29        record = { indexedProperty: "bar" };
     30 
     31    let open_rq = createdb(t);
     32    open_rq.onupgradeneeded = function (e) {
     33        db = e.target.result;
     34        let txn = e.target.transaction,
     35            objStore = db.createObjectStore("store");
     36 
     37        objStore.add(record, 1);
     38        objStore.add(record, 2);
     39        let index = objStore.createIndex("index", "indexedProperty", { unique: true });
     40 
     41        assert_true(index instanceof IDBIndex, "IDBIndex");
     42 
     43        e.target.transaction.onabort = t.step_func(function (e) {
     44            aborted = true;
     45            assert_equals(e.type, "abort", "event type");
     46        });
     47 
     48        db.onabort = function (e) {
     49            assert_true(aborted, "transaction.abort event has fired");
     50            t.done();
     51        };
     52 
     53        e.target.transaction.oncomplete = fail(t, "got complete, expected abort");
     54    };
     55 }, "Attempt to create an index that requires unique values on an object store already contains duplicates");
     56 
     57 async_test(t => {
     58    let db, aborted;
     59 
     60    let open_rq = createdb(t);
     61    open_rq.onupgradeneeded = function (e) {
     62        db = e.target.result;
     63        let txn = e.target.transaction,
     64            objStore = db.createObjectStore("store", { keyPath: 'key' });
     65 
     66        for (let i = 0; i < 100; i++)
     67            objStore.add({ key: "key_" + i, indexedProperty: "indexed_" + i });
     68 
     69         let idx = objStore.createIndex("index", "indexedProperty")
     70 
     71        idx.get('indexed_99').onsuccess = t.step_func(function (e) {
     72            assert_equals(e.target.result.key, 'key_99', 'key');
     73        });
     74        idx.get('indexed_9').onsuccess = t.step_func(function (e) {
     75            assert_equals(e.target.result.key, 'key_9', 'key');
     76        });
     77    }
     78 
     79    open_rq.onsuccess = function () {
     80        t.done();
     81    }
     82 }, "The index is usable right after being made");
     83 
     84 async_test(t => {
     85    let db,
     86        events = [];
     87 
     88    let open_rq = createdb(t);
     89    open_rq.onupgradeneeded = function (e) {
     90        db = e.target.result;
     91        e.target.transaction.oncomplete = log("transaction.complete");
     92 
     93        let txn = e.target.transaction,
     94            objStore = db.createObjectStore("store");
     95 
     96        let rq_add1 = objStore.add({ animal: "Unicorn" }, 1);
     97        rq_add1.onsuccess = log("rq_add1.success");
     98        rq_add1.onerror = log("rq_add1.error");
     99 
    100        objStore.createIndex("index", "animal", { unique: true });
    101 
    102        let rq_add2 = objStore.add({ animal: "Unicorn" }, 2);
    103        rq_add2.onsuccess = log("rq_add2.success");
    104        rq_add2.onerror = function (e) {
    105            log("rq_add2.error")(e);
    106            e.preventDefault();
    107            e.stopPropagation();
    108        }
    109 
    110        objStore.deleteIndex("index");
    111 
    112        let rq_add3 = objStore.add({ animal: "Unicorn" }, 3);
    113        rq_add3.onsuccess = log("rq_add3.success");
    114        rq_add3.onerror = log("rq_add3.error");
    115    }
    116 
    117    open_rq.onsuccess = function (e) {
    118        log("open_rq.success")(e);
    119        assert_array_equals(events, ["rq_add1.success",
    120            "rq_add2.error: ConstraintError",
    121            "rq_add3.success",
    122 
    123            "transaction.complete",
    124 
    125            "open_rq.success"],
    126            "events");
    127        t.done();
    128    }
    129 
    130    function log(msg) {
    131        return function (e) {
    132            if (e && e.target && e.target.error)
    133                events.push(msg + ": " + e.target.error.name);
    134            else
    135                events.push(msg);
    136        };
    137    }
    138 }, "Event ordering for a later deleted index");
    139 
    140 async_test(t => {
    141    let db, aborted;
    142 
    143    let open_rq = createdb(t);
    144    open_rq.onupgradeneeded = function (e) {
    145        db = e.target.result;
    146        let txn = e.target.transaction,
    147            objStore = db.createObjectStore("store");
    148 
    149        for (let i = 0; i < 5; i++)
    150            objStore.add("object_" + i, i);
    151 
    152        let rq = objStore.createIndex("index", "")
    153        rq.onerror = function () { assert_unreached("error: " + rq.error.name); }
    154        rq.onsuccess = function () { }
    155 
    156        objStore.index("index")
    157            .get('object_4')
    158            .onsuccess = t.step_func(function (e) {
    159                assert_equals(e.target.result, 'object_4', 'result');
    160            });
    161    }
    162 
    163    open_rq.onsuccess = function () {
    164        t.done();
    165    }
    166 }, "Empty keyPath");
    167 
    168 async_test(t => {
    169    // Transaction may fire window.onerror in some implementations.
    170    setup({ allow_uncaught_exception: true });
    171 
    172    let db,
    173        events = [];
    174 
    175    let open_rq = createdb(t);
    176    open_rq.onupgradeneeded = function (e) {
    177        db = e.target.result;
    178        db.onerror = log("db.error");
    179        db.onabort = log("db.abort");
    180        e.target.transaction.onabort = log("transaction.abort")
    181        e.target.transaction.onerror = log("transaction.error")
    182        e.target.transaction.oncomplete = log("transaction.complete")
    183 
    184        let txn = e.target.transaction,
    185            objStore = db.createObjectStore("store");
    186 
    187        let rq_add1 = objStore.add({ animal: "Unicorn" }, 1);
    188        rq_add1.onsuccess = log("rq_add1.success");
    189        rq_add1.onerror = log("rq_add1.error");
    190 
    191        let rq_add2 = objStore.add({ animal: "Unicorn" }, 2);
    192        rq_add2.onsuccess = log("rq_add2.success");
    193        rq_add2.onerror = log("rq_add2.error");
    194 
    195        objStore.createIndex("index", "animal", { unique: true })
    196 
    197        let rq_add3 = objStore.add({ animal: "Unicorn" }, 3);
    198        rq_add3.onsuccess = log("rq_add3.success");
    199        rq_add3.onerror = log("rq_add3.error");
    200    }
    201 
    202    open_rq.onerror = function (e) {
    203        log("open_rq.error")(e);
    204        assert_array_equals(events, ["rq_add1.success",
    205            "rq_add2.success",
    206 
    207            "rq_add3.error: AbortError",
    208            "transaction.error: AbortError",
    209            "db.error: AbortError",
    210 
    211            "transaction.abort: ConstraintError",
    212            "db.abort: ConstraintError",
    213 
    214            "open_rq.error: AbortError"],
    215            "events");
    216        t.done();
    217    }
    218 
    219    function log(msg) {
    220        return function (e) {
    221            if (e && e.target && e.target.error)
    222                events.push(msg + ": " + e.target.error.name);
    223            else
    224                events.push(msg);
    225        };
    226    }
    227 }, "Event order when unique constraint is triggered");
    228 
    229 async_test(t => {
    230    setup({ allow_uncaught_exception: true });
    231 
    232    let db,
    233        events = [];
    234 
    235    const open_rq = createdb(t);
    236    open_rq.onupgradeneeded = function (e) {
    237        db = e.target.result;
    238        let txn = e.target.transaction;
    239        db.onerror = log("db.error");
    240        db.onabort = log("db.abort");
    241        txn.onabort = log("transaction.abort")
    242        txn.onerror = log("transaction.error")
    243        txn.oncomplete = log("transaction.complete")
    244 
    245        let objStore = db.createObjectStore("store");
    246 
    247        let rq_add1 = objStore.add({ animal: "Unicorn" }, 1);
    248        rq_add1.onsuccess = log("rq_add1.success");
    249        rq_add1.onerror = log("rq_add1.error");
    250 
    251        objStore.createIndex("index", "animal", { unique: true })
    252 
    253        let rq_add2 = objStore.add({ animal: "Unicorn" }, 2);
    254        rq_add2.onsuccess = log("rq_add2.success");
    255        rq_add2.onerror = log("rq_add2.error");
    256 
    257        let rq_add3 = objStore.add({ animal: "Horse" }, 3);
    258        rq_add3.onsuccess = log("rq_add3.success");
    259        rq_add3.onerror = log("rq_add3.error");
    260    }
    261 
    262    open_rq.onerror = function (e) {
    263        log("open_rq.error")(e);
    264        assert_array_equals(events, ["rq_add1.success",
    265 
    266            "rq_add2.error: ConstraintError",
    267            "transaction.error: ConstraintError",
    268            "db.error: ConstraintError",
    269 
    270            "rq_add3.error: AbortError",
    271            "transaction.error: AbortError",
    272            "db.error: AbortError",
    273 
    274            "transaction.abort: ConstraintError",
    275            "db.abort: ConstraintError",
    276 
    277            "open_rq.error: AbortError"],
    278            "events");
    279        t.done();
    280    }
    281 
    282    function log(msg) {
    283        return function (e) {
    284            if (e && e.target && e.target.error)
    285                events.push(msg + ": " + e.target.error.name);
    286            else
    287                events.push(msg);
    288        };
    289    }
    290 }, "Event ordering for ConstraintError on request");
    291 
    292 async_test(t => {
    293    let db,
    294        now = new Date(),
    295        mar18 = new Date(1111111111111),
    296        ar = ["Yay", 2, -Infinity],
    297        num = 1337;
    298 
    299    const open_rq = createdb(t);
    300    open_rq.onupgradeneeded = function (e) {
    301        db = e.target.result;
    302        let txn = e.target.transaction,
    303            objStore = db.createObjectStore("store", { keyPath: 'key' });
    304 
    305        objStore.add({ key: "now", i: now });
    306        objStore.add({ key: "mar18", i: mar18 });
    307        objStore.add({ key: "array", i: ar });
    308        objStore.add({ key: "number", i: num });
    309 
    310        let idx = objStore.createIndex("index", "i")
    311 
    312        idx.get(now).onsuccess = t.step_func(function (e) {
    313            assert_equals(e.target.result.key, 'now', 'key');
    314            assert_equals(e.target.result.i.getTime(), now.getTime(), 'getTime');
    315        });
    316        idx.get(mar18).onsuccess = t.step_func(function (e) {
    317            assert_equals(e.target.result.key, 'mar18', 'key');
    318            assert_equals(e.target.result.i.getTime(), mar18.getTime(), 'getTime');
    319        });
    320        idx.get(ar).onsuccess = t.step_func(function (e) {
    321            assert_equals(e.target.result.key, 'array', 'key');
    322            assert_array_equals(e.target.result.i, ar, 'array is the same');
    323        });
    324        idx.get(num).onsuccess = t.step_func(function (e) {
    325            assert_equals(e.target.result.key, 'number', 'key');
    326            assert_equals(e.target.result.i, num, 'number is the same');
    327        });
    328    }
    329 
    330    open_rq.onsuccess = function () {
    331        t.done();
    332    }
    333 }, "Index can be valid keys");
    334 
    335 async_test(t => {
    336    let db;
    337 
    338    const open_rq = createdb(t);
    339    open_rq.onupgradeneeded = function (e) {
    340        db = e.target.result
    341        let store = db.createObjectStore("store")
    342 
    343        for (let i = 0; i < 5; i++)
    344            store.add({ idx: "object_" + i }, i)
    345 
    346        store.createIndex("", "idx")
    347 
    348        store.index("")
    349            .get('object_4')
    350            .onsuccess = t.step_func(function (e) {
    351                assert_equals(e.target.result.idx, 'object_4', 'result')
    352            })
    353        assert_equals(store.indexNames[0], "", "indexNames[0]")
    354        assert_equals(store.indexNames.length, 1, "indexNames.length")
    355    }
    356 
    357    open_rq.onsuccess = function () {
    358        let store = db.transaction("store", "readonly").objectStore("store")
    359 
    360        assert_equals(store.indexNames[0], "", "indexNames[0]")
    361        assert_equals(store.indexNames.length, 1, "indexNames.length")
    362 
    363        t.done()
    364    }
    365 }, "IDBObjectStore.createIndex() - empty name");
    366 
    367 async_test(t => {
    368    const open_rq = createdb(t);
    369 
    370    open_rq.onupgradeneeded = function (e) {
    371        let db = e.target.result;
    372        let ostore = db.createObjectStore("store");
    373        ostore.createIndex("a", "a");
    374        assert_throws_dom("ConstraintError", function () {
    375            ostore.createIndex("a", "a");
    376        });
    377        t.done();
    378    }
    379 }, "If an index with the name name already exists in this object store, the implementation must throw a DOMException of type ConstraintError");
    380 
    381 async_test(t => {
    382    const open_rq = createdb(t);
    383 
    384    open_rq.onupgradeneeded = function (e) {
    385        let db = e.target.result;
    386        let ostore = db.createObjectStore("store");
    387        assert_throws_dom("SyntaxError", function () {
    388            ostore.createIndex("ab", ".");
    389        });
    390        t.done();
    391    }
    392 }, "If keyPath is not a valid key path, the implementation must throw a DOMException of type SyntaxError");
    393 
    394 async_test(t => {
    395    let db, ostore;
    396 
    397    let open_rq = createdb(t);
    398    open_rq.onupgradeneeded = function (event) {
    399        db = event.target.result;
    400        ostore = db.createObjectStore("store");
    401        db.deleteObjectStore("store");
    402    }
    403 
    404    open_rq.onsuccess = function (event) {
    405        t.step(function () {
    406            assert_throws_dom("InvalidStateError", function () {
    407                ostore.createIndex("index", "indexedProperty");
    408            });
    409        });
    410        t.done();
    411    }
    412 }, "If the object store has been deleted, the implementation must throw a DOMException of type InvalidStateError");
    413 
    414 async_test(t => {
    415    let db;
    416 
    417    const open_rq = createdb(t);
    418    open_rq.onupgradeneeded = function (event) {
    419        db = event.target.result;
    420        db.createObjectStore("store");
    421    }
    422 
    423    open_rq.onsuccess = function (event) {
    424        let txn = db.transaction("store", "readwrite");
    425        let ostore = txn.objectStore("store");
    426        t.step(function () {
    427            assert_throws_dom("InvalidStateError", function () {
    428                ostore.createIndex("index", "indexedProperty");
    429            });
    430        });
    431        t.done();
    432    }
    433 }, "Operate out versionchange throw InvalidStateError");
    434 
    435 /* IndexedDB: Exception Order of IDBObjectStore.createIndex() */
    436 indexeddb_test(
    437    function (t, db, txn) {
    438        let store = db.createObjectStore("s");
    439    },
    440    function (t, db) {
    441        let txn = db.transaction("s", "readonly");
    442        let store = txn.objectStore("s");
    443        txn.oncomplete = function () {
    444            assert_throws_dom("InvalidStateError", function () {
    445                store.createIndex("index", "foo");
    446            });
    447            t.done();
    448        };
    449    },
    450    "InvalidStateError(Incorrect mode) vs. TransactionInactiveError. Mode check should precede state check of the transaction."
    451 );
    452 
    453 let gDeletedObjectStore;
    454 indexeddb_test(
    455    function (t, db, txn) {
    456        gDeletedObjectStore = db.createObjectStore("s");
    457        db.deleteObjectStore("s");
    458        txn.oncomplete = function () {
    459            assert_throws_dom("InvalidStateError", function () {
    460                gDeletedObjectStore.createIndex("index", "foo");
    461            });
    462            t.done();
    463        };
    464    },
    465    null,
    466    "InvalidStateError(Deleted ObjectStore) vs. TransactionInactiveError. Deletion check should precede transaction-state check."
    467 );
    468 
    469 indexeddb_test(
    470    function (t, db, txn) {
    471        let store = db.createObjectStore("s");
    472        store.createIndex("index", "foo");
    473        txn.oncomplete = function () {
    474            assert_throws_dom("TransactionInactiveError", function () {
    475                store.createIndex("index", "foo");
    476            });
    477            t.done();
    478        };
    479    },
    480    null,
    481    "TransactionInactiveError vs. ConstraintError. Transaction-state check should precede index name check."
    482 );
    483 
    484 indexeddb_test(
    485    function (t, db) {
    486        let store = db.createObjectStore("s");
    487        store.createIndex("index", "foo");
    488        assert_throws_dom("ConstraintError", function () {
    489            store.createIndex("index", "invalid key path");
    490        });
    491        assert_throws_dom("ConstraintError", function () {
    492            store.createIndex("index",
    493                ["invalid key path 1", "invalid key path 2"]);
    494        });
    495        t.done();
    496    },
    497    null,
    498    "ConstraintError vs. SyntaxError. Index name check should precede syntax check of the key path"
    499 );
    500 
    501 indexeddb_test(
    502    function (t, db) {
    503        let store = db.createObjectStore("s");
    504        assert_throws_dom("SyntaxError", function () {
    505            store.createIndex("index",
    506                ["invalid key path 1", "invalid key path 2"],
    507                { multiEntry: true });
    508        });
    509        t.done();
    510    },
    511    null,
    512    "SyntaxError vs. InvalidAccessError. Syntax check should precede multiEntry check of the key path."
    513 );
    514 
    515 /* AutoIncrement in Compound Index */
    516 indexeddb_test(
    517    function (t, db, txn) {
    518        // No auto-increment
    519        let store = db.createObjectStore("Store1", { keyPath: "id" });
    520        store.createIndex("CompoundKey", ["num", "id"]);
    521 
    522        // Add data
    523        store.put({ id: 1, num: 100 });
    524    },
    525    function (t, db) {
    526        let store = db.transaction("Store1", "readwrite").objectStore("Store1");
    527 
    528        store.openCursor().onsuccess = t.step_func(function (e) {
    529            let item = e.target.result.value;
    530            store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function (e) {
    531                assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.');
    532                t.done();
    533            });
    534        });
    535    },
    536    "Explicit Primary Key"
    537 );
    538 
    539 indexeddb_test(
    540    function (t, db, txn) {
    541        // Auto-increment
    542        let store = db.createObjectStore("Store2", { keyPath: "id", autoIncrement: true });
    543        store.createIndex("CompoundKey", ["num", "id"]);
    544 
    545        // Add data
    546        store.put({ num: 100 });
    547    },
    548    function (t, db) {
    549        let store = db.transaction("Store2", "readwrite").objectStore("Store2");
    550        store.openCursor().onsuccess = t.step_func(function (e) {
    551            let item = e.target.result.value;
    552            store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function (e) {
    553                assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.');
    554                t.done();
    555            });
    556        });
    557    },
    558    "Auto-Increment Primary Key"
    559 );
    560 
    561 indexeddb_test(
    562    function (t, db, txn) {
    563        // Auto-increment
    564        let store = db.createObjectStore("Store3", { keyPath: "id", autoIncrement: true });
    565        store.createIndex("CompoundKey", ["num", "id", "other"]);
    566 
    567        let num = 100;
    568 
    569        // Add data to Store3 - valid keys
    570        // Objects will be stored in Store3 and keys will get added
    571        // to the CompoundKeys index.
    572        store.put({ num: num++, other: 0 });
    573        store.put({ num: num++, other: [0] });
    574 
    575        // Add data - missing key
    576        // Objects will be stored in Store3 but keys won't get added to
    577        // the CompoundKeys index because the 'other' keypath doesn't
    578        // resolve to a value.
    579        store.put({ num: num++ });
    580 
    581        // Add data to Store3 - invalid keys
    582        // Objects will be stored in Store3 but keys won't get added to
    583        // the CompoundKeys index because the 'other' property values
    584        // aren't valid keys.
    585        store.put({ num: num++, other: null });
    586        store.put({ num: num++, other: {} });
    587        store.put({ num: num++, other: [null] });
    588        store.put({ num: num++, other: [{}] });
    589    },
    590    function (t, db) {
    591        let store = db.transaction("Store3", "readwrite").objectStore("Store3");
    592        const keys = [];
    593        let count;
    594        store.count().onsuccess = t.step_func(e => { count = e.target.result; });
    595        store.index("CompoundKey").openCursor().onsuccess = t.step_func(function (e) {
    596            const cursor = e.target.result;
    597            if (cursor !== null) {
    598                keys.push(cursor.key);
    599                cursor.continue();
    600                return;
    601            }
    602 
    603            // Done iteration, check results.
    604            assert_equals(count, 7, 'Expected all 7 records to be stored.');
    605            assert_equals(keys.length, 2, 'Expected exactly two index entries.');
    606            assert_array_equals(keys[0], [100, 1, 0]);
    607            assert_object_equals(keys[1], [101, 2, [0]]);
    608            t.done();
    609        });
    610    },
    611    "Auto-Increment Primary Key - invalid key values elsewhere"
    612 );