| // META: title=IndexedDB: scoping for database / object store / index names, and index keys |
| // META: global=window,worker |
| // META: script=resources/support-promises.js |
| |
| // Spec: https://w3c.github.io/IndexedDB/#constructs |
| |
| 'use strict'; |
| |
| // Creates the structure inside a test database. |
| // |
| // The structure includes two stores with identical indexes and nearly-similar |
| // records. The records differ in the "path" attribute values, which are used to |
| // verify that IndexedDB returns the correct records when queried. |
| // |
| // databaseName appears redundant, but we don't want to rely on database.name. |
| const buildStores = (database, databaseName, useUniqueKeys) => { |
| for (let storeName of ['x', 'y']) { |
| const store = database.createObjectStore( |
| storeName, {keyPath: 'pKey', autoIncrement: true}); |
| for (let indexName of ['x', 'y']) { |
| store.createIndex(indexName, `${indexName}Key`, {unique: useUniqueKeys}); |
| } |
| |
| for (let xKeyRoot of ['x', 'y']) { |
| for (let yKeyRoot of ['x', 'y']) { |
| let xKey, yKey; |
| if (useUniqueKeys) { |
| xKey = `${xKeyRoot}${yKeyRoot}`; |
| yKey = `${yKeyRoot}${xKeyRoot}`; |
| } else { |
| xKey = xKeyRoot; |
| yKey = yKeyRoot; |
| } |
| const path = `${databaseName}-${storeName}-${xKeyRoot}-${yKeyRoot}`; |
| store.put({xKey: xKey, yKey: yKey, path: path}); |
| } |
| } |
| } |
| }; |
| |
| // Creates two databases with identical structures. |
| const buildDatabases = (testCase, useUniqueKeys) => { |
| return createNamedDatabase( |
| testCase, 'x', |
| database => buildStores(database, 'x', useUniqueKeys)) |
| .then(database => database.close()) |
| .then( |
| () => createNamedDatabase( |
| testCase, 'y', |
| database => buildStores(database, 'y', useUniqueKeys))) |
| .then(database => database.close()); |
| }; |
| |
| // Reads all the store's values using an index. |
| // |
| // Returns a Promise that resolves with an array of values. |
| const readIndex = |
| (testCase, index) => { |
| return new Promise((resolve, reject) => { |
| const results = []; |
| const request = index.openCursor(IDBKeyRange.bound('a', 'z'), 'next'); |
| request.onsuccess = testCase.step_func(() => { |
| const cursor = request.result; |
| if (cursor) { |
| results.push(cursor.value); |
| cursor.continue(); |
| } else { |
| resolve(results); |
| } |
| }); |
| }); |
| } |
| |
| // Verifies that a database contains the expected records. |
| const checkDatabaseContent = |
| (testCase, database, databaseName, usedUniqueKeys) => { |
| const promises = []; |
| const transaction = database.transaction(['x', 'y'], 'readonly'); |
| for (let storeName of ['x', 'y']) { |
| const store = transaction.objectStore(storeName); |
| for (let indexName of ['x', 'y']) { |
| const index = store.index(indexName); |
| |
| const promise = readIndex(testCase, index).then((results) => { |
| assert_array_equals( |
| results.map(result => `${result.path}:${result.pKey}`).sort(), |
| [ |
| `${databaseName}-${storeName}-x-x:1`, |
| `${databaseName}-${storeName}-x-y:2`, |
| `${databaseName}-${storeName}-y-x:3`, |
| `${databaseName}-${storeName}-y-y:4` |
| ], |
| 'The results should include all records put into the store'); |
| |
| let expectedKeys = (usedUniqueKeys) ? |
| ['xx:xx', 'xy:yx', 'yx:xy', 'yy:yy'] : |
| ['x:x', 'x:y', 'y:x', 'y:y']; |
| assert_array_equals( |
| results.map(result => `${result.xKey}:${result.yKey}`).sort(), |
| expectedKeys, |
| 'The results should include all the index keys put in the store'); |
| |
| assert_array_equals( |
| results.map(result => result[`${indexName}Key`]), |
| results.map(result => result[`${indexName}Key`]).sort(), |
| 'The results should be sorted by the index key'); |
| }); |
| promises.push(promise); |
| } |
| } |
| |
| return Promise.all(promises).then(() => database); |
| } |
| |
| promise_test(testCase => { |
| return buildDatabases(testCase, false) |
| .then(() => openNamedDatabase(testCase, 'x', 1)) |
| .then(database => checkDatabaseContent(testCase, database, 'x', false)) |
| .then(database => database.close()) |
| .then(() => openNamedDatabase(testCase, 'y', 1)) |
| .then(database => checkDatabaseContent(testCase, database, 'y', false)) |
| .then(database => database.close()); |
| }, 'Non-unique index keys'); |
| |
| promise_test(testCase => { |
| return buildDatabases(testCase, true) |
| .then(() => openNamedDatabase(testCase, 'x', 1)) |
| .then(database => checkDatabaseContent(testCase, database, 'x', true)) |
| .then(database => database.close()) |
| .then(() => openNamedDatabase(testCase, 'y', 1)) |
| .then(database => checkDatabaseContent(testCase, database, 'y', true)) |
| .then(database => database.close()); |
| }, 'Unique index keys'); |