OLD | NEW |
| (Empty) |
1 <!DOCTYPE html> | |
2 <title>IndexedDB: object store renaming support</title> | |
3 <link rel="help" | |
4 href="https://w3c.github.io/IndexedDB/#dom-idbobjectstore-name"> | |
5 <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> | |
6 <script src="/resources/testharness.js"></script> | |
7 <script src="/resources/testharnessreport.js"></script> | |
8 <script src="support-promises.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 |