| // META: title=IndexedDB: clone before key path evaluation |
| // META: global=window,worker |
| // META: script=resources/support.js |
| |
| 'use strict'; |
| |
| function ProbeObject() { |
| this.id_count = 0; |
| this.invalid_id_count = 0; |
| this.prop_count = 0; |
| Object.defineProperties(this, { |
| id: { |
| enumerable: true, |
| get() { |
| ++this.id_count; |
| return 1000 + this.id_count; |
| }, |
| }, |
| invalid_id: { |
| enumerable: true, |
| get() { |
| ++this.invalid_id_count; |
| return {}; |
| }, |
| }, |
| prop: { |
| enumerable: true, |
| get() { |
| ++this.prop_count; |
| return 2000 + this.prop_count; |
| }, |
| }, |
| }); |
| } |
| |
| function createObjectStoreWithKeyPath( |
| storeName, keyPath, autoIncrement = false) { |
| return (t, db) => { |
| db.createObjectStore(storeName, {keyPath, autoIncrement}); |
| }; |
| } |
| |
| function createObjectStoreWithIndex( |
| storeName, keyPath, indexName, indexKeyPath) { |
| return (t, db) => { |
| const storeOptions = keyPath ? {keyPath} : {}; |
| const store = db.createObjectStore(storeName, storeOptions); |
| |
| // If index parameters are provided, create the index. |
| if (indexName && indexKeyPath) { |
| store.createIndex(indexName, indexKeyPath); |
| } |
| }; |
| } |
| |
| function createTransactionAndReturnObjectStore(db, storeName) { |
| const tx = db.transaction(storeName, 'readwrite'); |
| const store = tx.objectStore(storeName); |
| return {tx, store}; |
| } |
| |
| indexeddb_test(createObjectStoreWithKeyPath('store', 'id', true), (t, db) => { |
| const {store} = createTransactionAndReturnObjectStore(db, 'store'); |
| const obj = new ProbeObject(); |
| store.put(obj); |
| assert_equals( |
| obj.id_count, 1, |
| 'put() operation should access primary key property once'); |
| assert_equals( |
| obj.prop_count, 1, 'put() operation should access other properties once'); |
| t.done(); |
| }, 'Key generator and key path validity check operates on a clone'); |
| |
| indexeddb_test( |
| createObjectStoreWithKeyPath('store', 'invalid_id', true), (t, db) => { |
| const {store} = createTransactionAndReturnObjectStore(db, 'store'); |
| const obj = new ProbeObject(); |
| assert_throws_dom('DataError', () => { |
| store.put(obj); |
| }, 'put() should throw if primary key cannot be injected'); |
| assert_equals( |
| obj.invalid_id_count, 1, |
| 'put() operation should access primary key property once'); |
| assert_equals( |
| obj.prop_count, 1, |
| 'put() operation should access other properties once'); |
| t.done(); |
| }, 'Failing key path validity check operates on a clone'); |
| |
| indexeddb_test( |
| createObjectStoreWithIndex('store', null, 'index', 'prop'), (t, db) => { |
| const {store} = createTransactionAndReturnObjectStore(db, 'store'); |
| const obj = new ProbeObject(); |
| store.put(obj, 'key'); |
| assert_equals( |
| obj.prop_count, 1, 'put() should access index key property once'); |
| assert_equals( |
| obj.id_count, 1, |
| 'put() operation should access other properties once'); |
| t.done(); |
| }, 'Index key path evaluations operate on a clone'); |
| |
| indexeddb_test( |
| createObjectStoreWithIndex('store', 'id', 'index', 'prop'), (t, db) => { |
| const {store} = createTransactionAndReturnObjectStore(db, 'store'); |
| const obj = new ProbeObject(); |
| store.put(obj); |
| assert_equals( |
| obj.id_count, 1, 'put() should access primary key property once'); |
| assert_equals( |
| obj.prop_count, 1, 'put() should access index key property once'); |
| t.done(); |
| }, 'Store and index key path evaluations operate on the same clone'); |
| |
| indexeddb_test( |
| createObjectStoreWithIndex('store', 'id', 'index', 'prop'), (t, db) => { |
| const {store} = createTransactionAndReturnObjectStore(db, 'store'); |
| store.put(new ProbeObject()); |
| |
| store.openCursor().onsuccess = t.step_func((event) => { |
| const cursor = event.target.result; |
| |
| const obj = new ProbeObject(); |
| cursor.update(obj); |
| assert_equals( |
| obj.id_count, 1, 'put() should access primary key property once'); |
| assert_equals( |
| obj.prop_count, 1, 'put() should access index key property once'); |
| |
| t.done(); |
| }); |
| }, 'Cursor update checks and keypath evaluations operate on a clone'); |