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