133 lines
4.9 KiB
JavaScript
133 lines
4.9 KiB
JavaScript
// 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');
|