<!doctype html> <meta charset="utf-8"> <title> IndexedDB: scoping for database / object store / index names, and index keys </title> <link rel="help" href="https://w3c.github.io/IndexedDB/#constructs"> <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> <script src="/resources/testharness.js"></script> <script src="/resources/testharnessreport.js"></script> <script src="resources/support-promises.js"></script> <script> '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 = () => { 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'); </script>