| // Returns the "name" property written to the object with the given ID. |
| function nameForId(id) { |
| return `Object ${id}`; |
| } |
| |
| // Initial database setup used by all the reading-autoincrement tests. |
| async function setupAutoincrementDatabase(testCase) { |
| const database = await createDatabase(testCase, database => { |
| const store = database.createObjectStore( |
| 'store', { autoIncrement: true, keyPath: 'id' }); |
| store.createIndex('by_name', 'name', { unique: true }); |
| store.createIndex('by_id', 'id', { unique: true }); |
| |
| // Cover writing from the initial upgrade transaction. |
| for (let i = 1; i <= 16; ++i) { |
| if (i % 2 == 0) { |
| store.put({name: nameForId(i), id: i}); |
| } else { |
| store.put({name: nameForId(i)}); |
| } |
| } |
| }); |
| |
| // Cover writing from a subsequent transaction. |
| const transaction = database.transaction(['store'], 'readwrite'); |
| const store = transaction.objectStore('store'); |
| for (let i = 17; i <= 32; ++i) { |
| if (i % 2 == 0) { |
| store.put({name: nameForId(i), id: i}); |
| } else { |
| store.put({name: nameForId(i)}); |
| } |
| } |
| await promiseForTransaction(testCase, transaction); |
| |
| return database; |
| } |
| |
| // Returns the IDs used by the object store, sorted as strings. |
| // |
| // This is used to determine the correct order of records when retrieved from an |
| // index that uses stringified IDs. |
| function idsSortedByStringCompare() { |
| const stringIds = []; |
| for (let i = 1; i <= 32; ++i) |
| stringIds.push(i); |
| stringIds.sort((a, b) => indexedDB.cmp(`${a}`, `${b}`)); |
| return stringIds; |
| } |
| |
| async function iterateCursor(testCase, cursorRequest, callback) { |
| // This uses requestWatcher() directly instead of using promiseForRequest() |
| // inside the loop to avoid creating multiple EventWatcher instances. In turn, |
| // this avoids ending up with O(N) listeners for the request and O(N^2) |
| // dispatched events. |
| const eventWatcher = requestWatcher(testCase, cursorRequest); |
| while (true) { |
| const event = await eventWatcher.wait_for('success'); |
| const cursor = event.target.result; |
| if (cursor === null) |
| return; |
| callback(cursor); |
| cursor.continue(); |
| } |
| } |
| |
| // Returns equivalent information to getAllKeys() by iterating a cursor. |
| // |
| // Returns an array with one dictionary per entry in the source. The dictionary |
| // has the properties "key" and "primaryKey". |
| async function getAllKeysViaCursor(testCase, cursorSource) { |
| const results = []; |
| await iterateCursor(testCase, cursorSource.openKeyCursor(), cursor => { |
| results.push({ key: cursor.key, primaryKey: cursor.primaryKey }); |
| }); |
| return results; |
| } |
| |
| // Returns equivalent information to getAll() by iterating a cursor. |
| // |
| // Returns an array with one dictionary per entry in the source. The dictionary |
| // has the properties "key", "primaryKey" and "value". |
| async function getAllViaCursor(testCase, cursorSource) { |
| const results = []; |
| await iterateCursor(testCase, cursorSource.openCursor(), cursor => { |
| results.push({ |
| key: cursor.key, |
| primaryKey: cursor.primaryKey, |
| value: cursor.value, |
| }); |
| }); |
| return results; |
| } |