OLD | NEW |
(Empty) | |
| 1 <!DOCTYPE html> |
| 2 <title>IndexedDB: object store renaming support</title> |
| 3 <script src='../../resources/testharness.js'></script> |
| 4 <link rel="help" |
| 5 href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name"> |
| 6 <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> |
| 7 <script src='../../resources/testharnessreport.js'></script> |
| 8 <script src='resources/rename-common.js'></script> |
| 9 <script> |
| 10 |
| 11 // Renames the 'books' store to 'renamed_books'. |
| 12 // |
| 13 // Returns a promise that resolves to an IndexedDB database. The caller must |
| 14 // close the database. |
| 15 const renameBooksStore = (testCase) => { |
| 16 return migrateDatabase(testCase, 2, (database, transaction) => { |
| 17 const store = transaction.objectStore('books'); |
| 18 store.name = 'renamed_books'; |
| 19 }); |
| 20 }; |
| 21 |
| 22 promise_test(testCase => { |
| 23 let bookStore = null, bookStore2 = null; |
| 24 let renamedBookStore = null, renamedBookStore2 = null; |
| 25 return createDatabase(testCase, (database, transaction) => { |
| 26 bookStore = createBooksStore(testCase, database); |
| 27 }).then(database => { |
| 28 assert_array_equals( |
| 29 database.objectStoreNames, ['books'], |
| 30 'Test setup should have created a "books" object store'); |
| 31 const transaction = database.transaction('books', 'readonly'); |
| 32 bookStore2 = transaction.objectStore('books'); |
| 33 return checkStoreContents( |
| 34 testCase, bookStore2, |
| 35 'The store should have the expected contents before any renaming'). |
| 36 then(() => database.close()); |
| 37 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 38 renamedBookStore = transaction.objectStore('books'); |
| 39 renamedBookStore.name = 'renamed_books'; |
| 40 |
| 41 assert_equals( |
| 42 renamedBookStore.name, 'renamed_books', |
| 43 'IDBObjectStore name should change immediately after a rename'); |
| 44 assert_array_equals( |
| 45 database.objectStoreNames, ['renamed_books'], |
| 46 'IDBDatabase.objectStoreNames should immediately reflect the ' + |
| 47 'rename'); |
| 48 assert_array_equals( |
| 49 transaction.objectStoreNames, ['renamed_books'], |
| 50 'IDBTransaction.objectStoreNames should immediately reflect the ' + |
| 51 'rename'); |
| 52 assert_equals( |
| 53 transaction.objectStore('renamed_books'), renamedBookStore, |
| 54 'IDBTransaction.objectStore should return the renamed object ' + |
| 55 'store when queried using the new name immediately after the ' + |
| 56 'rename'); |
| 57 assert_throws( |
| 58 'NotFoundError', () => transaction.objectStore('books'), |
| 59 'IDBTransaction.objectStore should throw when queried using the ' + |
| 60 "renamed object store's old name immediately after the rename"); |
| 61 })).then(database => { |
| 62 assert_array_equals( |
| 63 database.objectStoreNames, ['renamed_books'], |
| 64 'IDBDatabase.objectStoreNames should still reflect the rename ' + |
| 65 'after the versionchange transaction commits'); |
| 66 const transaction = database.transaction('renamed_books', 'readonly'); |
| 67 renamedBookStore2 = transaction.objectStore('renamed_books'); |
| 68 return checkStoreContents( |
| 69 testCase, renamedBookStore2, |
| 70 'Renaming an object store should not change its records').then( |
| 71 () => database.close()); |
| 72 }).then(() => { |
| 73 assert_equals( |
| 74 bookStore.name, 'books', |
| 75 'IDBObjectStore obtained before the rename transaction should ' + |
| 76 'not reflect the rename'); |
| 77 assert_equals( |
| 78 bookStore2.name, 'books', |
| 79 'IDBObjectStore obtained before the rename transaction should ' + |
| 80 'not reflect the rename'); |
| 81 assert_equals( |
| 82 renamedBookStore.name, 'renamed_books', |
| 83 'IDBObjectStore used in the rename transaction should keep ' + |
| 84 'reflecting the new name after the transaction is committed'); |
| 85 assert_equals( |
| 86 renamedBookStore2.name, 'renamed_books', |
| 87 'IDBObjectStore obtained after the rename transaction should ' + |
| 88 'reflect the new name'); |
| 89 }); |
| 90 }, 'IndexedDB object store rename in new transaction'); |
| 91 |
| 92 promise_test(testCase => { |
| 93 let renamedBookStore = null, renamedBookStore2 = null; |
| 94 return createDatabase(testCase, (database, transaction) => { |
| 95 renamedBookStore = createBooksStore(testCase, database); |
| 96 renamedBookStore.name = 'renamed_books'; |
| 97 |
| 98 assert_equals( |
| 99 renamedBookStore.name, 'renamed_books', |
| 100 'IDBObjectStore name should change immediately after a rename'); |
| 101 assert_array_equals( |
| 102 database.objectStoreNames, ['renamed_books'], |
| 103 'IDBDatabase.objectStoreNames should immediately reflect the ' + |
| 104 'rename'); |
| 105 assert_array_equals( |
| 106 transaction.objectStoreNames, ['renamed_books'], |
| 107 'IDBTransaction.objectStoreNames should immediately reflect the ' + |
| 108 'rename'); |
| 109 assert_equals( |
| 110 transaction.objectStore('renamed_books'), renamedBookStore, |
| 111 'IDBTransaction.objectStore should return the renamed object ' + |
| 112 'store when queried using the new name immediately after the ' + |
| 113 'rename'); |
| 114 assert_throws( |
| 115 'NotFoundError', () => transaction.objectStore('books'), |
| 116 'IDBTransaction.objectStore should throw when queried using the ' + |
| 117 "renamed object store's old name immediately after the rename"); |
| 118 }).then(database => { |
| 119 assert_array_equals( |
| 120 database.objectStoreNames, ['renamed_books'], |
| 121 'IDBDatabase.objectStoreNames should still reflect the rename ' + |
| 122 'after the versionchange transaction commits'); |
| 123 const transaction = database.transaction('renamed_books', 'readonly'); |
| 124 renamedBookStore2 = transaction.objectStore('renamed_books'); |
| 125 return checkStoreContents( |
| 126 testCase, renamedBookStore2, |
| 127 'Renaming an object store should not change its records').then( |
| 128 () => database.close()); |
| 129 }).then(() => { |
| 130 assert_equals( |
| 131 renamedBookStore.name, 'renamed_books', |
| 132 'IDBObjectStore used in the rename transaction should keep ' + |
| 133 'reflecting the new name after the transaction is committed'); |
| 134 assert_equals( |
| 135 renamedBookStore2.name, 'renamed_books', |
| 136 'IDBObjectStore obtained after the rename transaction should ' + |
| 137 'reflect the new name'); |
| 138 }); |
| 139 }, 'IndexedDB object store rename in the transaction where it is created'); |
| 140 |
| 141 promise_test(testCase => { |
| 142 return createDatabase(testCase, (database, transaction) => { |
| 143 createBooksStore(testCase, database); |
| 144 }).then(database => { |
| 145 const transaction = database.transaction('books', 'readonly'); |
| 146 const store = transaction.objectStore('books'); |
| 147 return checkStoreIndexes( |
| 148 testCase, store, |
| 149 'The object store index should have the expected contens before ' + |
| 150 'any renaming').then( |
| 151 () => database.close()); |
| 152 }).then(() => renameBooksStore(testCase) |
| 153 ).then(database => { |
| 154 const transaction = database.transaction('renamed_books', 'readonly'); |
| 155 const store = transaction.objectStore('renamed_books'); |
| 156 return checkStoreIndexes( |
| 157 testCase, store, |
| 158 'Renaming an object store should not change its indexes').then( |
| 159 () => database.close()); |
| 160 }); |
| 161 }, 'IndexedDB object store rename covers index'); |
| 162 |
| 163 promise_test(testCase => { |
| 164 return createDatabase(testCase, (database, transaction) => { |
| 165 createBooksStore(testCase, database); |
| 166 }).then(database => { |
| 167 const transaction = database.transaction('books', 'readwrite'); |
| 168 const store = transaction.objectStore('books'); |
| 169 return checkStoreGenerator( |
| 170 testCase, store, 345679, |
| 171 'The object store key generator should have the expected state ' + |
| 172 'before any renaming').then(() => database.close()); |
| 173 }).then(() => renameBooksStore(testCase) |
| 174 ).then(database => { |
| 175 const transaction = database.transaction('renamed_books', 'readwrite'); |
| 176 const store = transaction.objectStore('renamed_books'); |
| 177 return checkStoreGenerator( |
| 178 testCase, store, 345680, |
| 179 'Renaming an object store should not change the state of its key ' + |
| 180 'generator').then(() => database.close()); |
| 181 }); |
| 182 }, 'IndexedDB object store rename covers key generator'); |
| 183 |
| 184 promise_test(testCase => { |
| 185 return createDatabase(testCase, (database, transaction) => { |
| 186 createBooksStore(testCase, database); |
| 187 }).then(database => { |
| 188 database.close(); |
| 189 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 190 const store = transaction.objectStore('books'); |
| 191 store.name = 'books'; |
| 192 assert_array_equals( |
| 193 database.objectStoreNames, ['books'], |
| 194 'Renaming a store to the same name should not change ' + |
| 195 "the store's IDBDatabase.objectStoreNames"); |
| 196 })).then(database => { |
| 197 assert_array_equals( |
| 198 database.objectStoreNames, ['books'], |
| 199 'Committing a transaction that renames a store to the same name ' + |
| 200 "should not change the store's IDBDatabase.objectStoreNames"); |
| 201 const transaction = database.transaction('books', 'readonly'); |
| 202 const store = transaction.objectStore('books'); |
| 203 return checkStoreContents( |
| 204 testCase, store, |
| 205 'Committing a transaction that renames a store to the same name ' + |
| 206 "should not change the store's contents").then( |
| 207 () => database.close()); |
| 208 }); |
| 209 }, 'IndexedDB object store rename to the same name succeeds'); |
| 210 |
| 211 promise_test(testCase => { |
| 212 return createDatabase(testCase, (database, transaction) => { |
| 213 createBooksStore(testCase, database); |
| 214 createNotBooksStore(testCase, database); |
| 215 }).then(database => { |
| 216 database.close(); |
| 217 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 218 const store = transaction.objectStore('books'); |
| 219 database.deleteObjectStore('not_books'); |
| 220 store.name = 'not_books'; |
| 221 assert_array_equals( |
| 222 database.objectStoreNames, ['not_books'], |
| 223 'IDBDatabase.objectStoreNames should immediately reflect the ' + |
| 224 'rename'); |
| 225 })).then(database => { |
| 226 assert_array_equals( |
| 227 database.objectStoreNames, ['not_books'], |
| 228 'IDBDatabase.objectStoreNames should still reflect the rename ' + |
| 229 'after the versionchange transaction commits'); |
| 230 const transaction = database.transaction('not_books', 'readonly'); |
| 231 const store = transaction.objectStore('not_books'); |
| 232 return checkStoreContents( |
| 233 testCase, store, |
| 234 'Renaming an object store should not change its records').then( |
| 235 () => database.close()); |
| 236 }); |
| 237 }, 'IndexedDB object store rename to the name of a deleted store succeeds'); |
| 238 |
| 239 promise_test(testCase => { |
| 240 return createDatabase(testCase, (database, transaction) => { |
| 241 createBooksStore(testCase, database); |
| 242 createNotBooksStore(testCase, database); |
| 243 }).then(database => { |
| 244 database.close(); |
| 245 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 246 const bookStore = transaction.objectStore('books'); |
| 247 const notBookStore = transaction.objectStore('not_books'); |
| 248 |
| 249 transaction.objectStore('books').name = 'tmp'; |
| 250 transaction.objectStore('not_books').name = 'books'; |
| 251 transaction.objectStore('tmp').name = 'not_books'; |
| 252 |
| 253 assert_array_equals( |
| 254 database.objectStoreNames, ['books', 'not_books'], |
| 255 'IDBDatabase.objectStoreNames should immediately reflect the swap'); |
| 256 |
| 257 assert_equals( |
| 258 transaction.objectStore('books'), notBookStore, |
| 259 'IDBTransaction.objectStore should return the original "books" ' + |
| 260 'store when queried with "not_books" after the swap'); |
| 261 assert_equals( |
| 262 transaction.objectStore('not_books'), bookStore, |
| 263 'IDBTransaction.objectStore should return the original ' + |
| 264 '"not_books" store when queried with "books" after the swap'); |
| 265 })).then(database => { |
| 266 assert_array_equals( |
| 267 database.objectStoreNames, ['books', 'not_books'], |
| 268 'IDBDatabase.objectStoreNames should still reflect the swap ' + |
| 269 'after the versionchange transaction commits'); |
| 270 const transaction = database.transaction('not_books', 'readonly'); |
| 271 const store = transaction.objectStore('not_books'); |
| 272 assert_array_equals( |
| 273 store.indexNames, ['by_author', 'by_title'], |
| 274 '"not_books" index names should still reflect the swap after the ' + |
| 275 'versionchange transaction commits'); |
| 276 return checkStoreContents( |
| 277 testCase, store, |
| 278 'Swapping two object stores should not change their records').then( |
| 279 () => database.close()); |
| 280 }); |
| 281 }, 'IndexedDB object store swapping via renames succeeds'); |
| 282 |
| 283 promise_test(testCase => { |
| 284 return createDatabase(testCase, (database, transaction) => { |
| 285 createBooksStore(testCase, database); |
| 286 }).then(database => { |
| 287 database.close(); |
| 288 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 289 const store = transaction.objectStore('books'); |
| 290 |
| 291 store.name = 42; |
| 292 assert_equals(store.name, '42', |
| 293 'IDBObjectStore name should change immediately after a ' + |
| 294 'rename to a number'); |
| 295 assert_array_equals( |
| 296 database.objectStoreNames, ['42'], |
| 297 'IDBDatabase.objectStoreNames should immediately reflect the ' + |
| 298 'stringifying rename'); |
| 299 |
| 300 store.name = true; |
| 301 assert_equals(store.name, 'true', |
| 302 'IDBObjectStore name should change immediately after a ' + |
| 303 'rename to a boolean'); |
| 304 |
| 305 store.name = {}; |
| 306 assert_equals(store.name, '[object Object]', |
| 307 'IDBObjectStore name should change immediately after a ' + |
| 308 'rename to an object'); |
| 309 |
| 310 store.name = () => null; |
| 311 assert_equals(store.name, '() => null', |
| 312 'IDBObjectStore name should change immediately after a ' + |
| 313 'rename to a function'); |
| 314 |
| 315 store.name = undefined; |
| 316 assert_equals(store.name, 'undefined', |
| 317 'IDBObjectStore name should change immediately after a ' + |
| 318 'rename to undefined'); |
| 319 })).then(database => { |
| 320 assert_array_equals( |
| 321 database.objectStoreNames, ['undefined'], |
| 322 'IDBDatabase.objectStoreNames should reflect the last rename ' + |
| 323 'after the versionchange transaction commits'); |
| 324 const transaction = database.transaction('undefined', 'readonly'); |
| 325 const store = transaction.objectStore('undefined'); |
| 326 return checkStoreContents( |
| 327 testCase, store, |
| 328 'Renaming an object store should not change its records').then( |
| 329 () => database.close()); |
| 330 }); |
| 331 }, 'IndexedDB object store rename stringifies non-string names'); |
| 332 |
| 333 for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => { |
| 334 const name = JSON.parse('"' + escapedName + '"'); |
| 335 promise_test(testCase => { |
| 336 return createDatabase(testCase, (database, transaction) => { |
| 337 createBooksStore(testCase, database); |
| 338 }).then(database => { |
| 339 database.close(); |
| 340 }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 341 const store = transaction.objectStore('books'); |
| 342 |
| 343 store.name = name; |
| 344 assert_equals(store.name, name, |
| 345 'IDBObjectStore name should change immediately after the ' + |
| 346 'rename'); |
| 347 assert_array_equals( |
| 348 database.objectStoreNames, [name], |
| 349 'IDBDatabase.objectStoreNames should immediately reflect the ' + |
| 350 'rename'); |
| 351 })).then(database => { |
| 352 assert_array_equals( |
| 353 database.objectStoreNames, [name], |
| 354 'IDBDatabase.objectStoreNames should reflect the rename ' + |
| 355 'after the versionchange transaction commits'); |
| 356 const transaction = database.transaction(name, 'readonly'); |
| 357 const store = transaction.objectStore(name); |
| 358 return checkStoreContents( |
| 359 testCase, store, |
| 360 'Renaming an object store should not change its records').then( |
| 361 () => database.close()); |
| 362 }); |
| 363 }, 'IndexedDB object store can be renamed to "' + escapedName + '"'); |
| 364 })(escapedName); |
| 365 |
| 366 </script> |
OLD | NEW |