| Victor Costan | eeecf3e | 2017-01-05 19:37:08 | [diff] [blame] | 1 | <!doctype html> |
| 2 | <meta charset="utf8"> |
| Bevis Tseng | 8751ea9 | 2017-01-03 14:28:44 | [diff] [blame] | 3 | <meta name="timeout" content="long"> |
| Victor Costan | 27af3dd | 2016-10-06 21:28:35 | [diff] [blame] | 4 | <title>IndexedDB: index renaming support</title> |
| 5 | <link rel="help" |
| 6 | href="https://w3c.github.io/IndexedDB/#dom-idbindex-name"> |
| 7 | <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> |
| 8 | <script src="/resources/testharness.js"></script> |
| 9 | <script src="/resources/testharnessreport.js"></script> |
| 10 | <script src="support-promises.js"></script> |
| 11 | <script> |
| Victor Costan | eeecf3e | 2017-01-05 19:37:08 | [diff] [blame] | 12 | 'use strict'; |
| Victor Costan | 27af3dd | 2016-10-06 21:28:35 | [diff] [blame] | 13 | |
| 14 | promise_test(testCase => { |
| 15 | let authorIndex = null, authorIndex2 = null; |
| 16 | let renamedAuthorIndex = null, renamedAuthorIndex2 = null; |
| 17 | return createDatabase(testCase, (database, transaction) => { |
| 18 | const store = createBooksStore(testCase, database); |
| 19 | authorIndex = store.index('by_author'); |
| 20 | }).then(database => { |
| 21 | const transaction = database.transaction('books', 'readonly'); |
| 22 | const store = transaction.objectStore('books'); |
| 23 | assert_array_equals( |
| 24 | store.indexNames, ['by_author', 'by_title'], |
| 25 | 'Test setup should have created two indexes'); |
| 26 | authorIndex2 = store.index('by_author'); |
| 27 | return checkAuthorIndexContents( |
| 28 | testCase, authorIndex2, |
| 29 | 'The index should have the expected contents before any renaming'). |
| 30 | then(() => database.close()); |
| 31 | }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 32 | const store = transaction.objectStore('books'); |
| 33 | renamedAuthorIndex = store.index('by_author'); |
| 34 | renamedAuthorIndex.name = 'renamed_by_author'; |
| 35 | |
| 36 | assert_equals( |
| 37 | renamedAuthorIndex.name, 'renamed_by_author', |
| 38 | 'IDBIndex name should change immediately after a rename'); |
| 39 | assert_array_equals( |
| 40 | store.indexNames, ['by_title', 'renamed_by_author'], |
| 41 | 'IDBObjectStore.indexNames should immediately reflect the rename'); |
| 42 | assert_equals( |
| 43 | store.index('renamed_by_author'), renamedAuthorIndex, |
| 44 | 'IDBObjectStore.index should return the renamed index store when ' + |
| 45 | 'queried using the new name immediately after the rename'); |
| Stephen McGruer | d510304 | 2020-01-23 21:45:45 | [diff] [blame] | 46 | assert_throws_dom( |
| Victor Costan | 27af3dd | 2016-10-06 21:28:35 | [diff] [blame] | 47 | 'NotFoundError', () => store.index('by_author'), |
| 48 | 'IDBObjectStore.index should throw when queried using the ' + |
| 49 | "renamed index's old name immediately after the rename"); |
| 50 | })).then(database => { |
| 51 | const transaction = database.transaction('books', 'readonly'); |
| 52 | const store = transaction.objectStore('books'); |
| 53 | assert_array_equals( |
| 54 | store.indexNames, ['by_title', 'renamed_by_author'], |
| 55 | 'IDBObjectStore.indexNames should still reflect the rename after ' + |
| 56 | 'the versionchange transaction commits'); |
| 57 | renamedAuthorIndex2 = store.index('renamed_by_author'); |
| 58 | return checkAuthorIndexContents( |
| 59 | testCase, renamedAuthorIndex2, |
| 60 | 'Renaming an index should not change its contents').then( |
| 61 | () => database.close()); |
| 62 | }).then(() => { |
| 63 | assert_equals( |
| 64 | authorIndex.name, 'by_author', |
| 65 | 'IDBIndex obtained before the rename transaction should not ' + |
| 66 | 'reflect the rename'); |
| 67 | assert_equals( |
| 68 | authorIndex2.name, 'by_author', |
| 69 | 'IDBIndex obtained before the rename transaction should not ' + |
| 70 | 'reflect the rename'); |
| 71 | assert_equals( |
| 72 | renamedAuthorIndex.name, 'renamed_by_author', |
| 73 | 'IDBIndex used in the rename transaction should keep reflecting ' + |
| 74 | 'the new name after the transaction is committed'); |
| 75 | assert_equals( |
| 76 | renamedAuthorIndex2.name, 'renamed_by_author', |
| 77 | 'IDBIndex obtained after the rename transaction should reflect ' + |
| 78 | 'the new name'); |
| 79 | }); |
| 80 | }, 'IndexedDB index rename in new transaction'); |
| 81 | |
| 82 | promise_test(testCase => { |
| 83 | let renamedAuthorIndex = null, renamedAuthorIndex2 = null; |
| 84 | return createDatabase(testCase, (database, transaction) => { |
| 85 | const store = createBooksStore(testCase, database); |
| 86 | renamedAuthorIndex = store.index('by_author'); |
| 87 | renamedAuthorIndex.name = 'renamed_by_author'; |
| 88 | |
| 89 | assert_equals( |
| 90 | renamedAuthorIndex.name, 'renamed_by_author', |
| 91 | 'IDBIndex name should change immediately after a rename'); |
| 92 | assert_array_equals( |
| 93 | store.indexNames, ['by_title', 'renamed_by_author'], |
| 94 | 'IDBObjectStore.indexNames should immediately reflect the rename'); |
| 95 | assert_equals( |
| 96 | store.index('renamed_by_author'), renamedAuthorIndex, |
| 97 | 'IDBObjectStore.index should return the renamed index store when ' + |
| 98 | 'queried using the new name immediately after the rename'); |
| Stephen McGruer | d510304 | 2020-01-23 21:45:45 | [diff] [blame] | 99 | assert_throws_dom( |
| Victor Costan | 27af3dd | 2016-10-06 21:28:35 | [diff] [blame] | 100 | 'NotFoundError', () => store.index('by_author'), |
| 101 | 'IDBObjectStore.index should throw when queried using the ' + |
| 102 | "renamed index's old name immediately after the rename"); |
| 103 | }).then(database => { |
| 104 | const transaction = database.transaction('books', 'readonly'); |
| 105 | const store = transaction.objectStore('books'); |
| 106 | assert_array_equals( |
| 107 | store.indexNames, ['by_title', 'renamed_by_author'], |
| 108 | 'IDBObjectStore.indexNames should still reflect the rename after ' + |
| 109 | 'the versionchange transaction commits'); |
| 110 | renamedAuthorIndex2 = store.index('renamed_by_author'); |
| 111 | return checkAuthorIndexContents( |
| 112 | testCase, renamedAuthorIndex2, |
| 113 | 'Renaming an index should not change its contents').then( |
| 114 | () => database.close()); |
| 115 | }).then(() => { |
| 116 | assert_equals( |
| 117 | renamedAuthorIndex.name, 'renamed_by_author', |
| 118 | 'IDBIndex used in the rename transaction should keep reflecting ' + |
| 119 | 'the new name after the transaction is committed'); |
| 120 | assert_equals( |
| 121 | renamedAuthorIndex2.name, 'renamed_by_author', |
| 122 | 'IDBIndex obtained after the rename transaction should reflect ' + |
| 123 | 'the new name'); |
| 124 | }); |
| 125 | }, 'IndexedDB index rename in the transaction where it is created'); |
| 126 | |
| 127 | promise_test(testCase => { |
| 128 | return createDatabase(testCase, (database, transaction) => { |
| 129 | createBooksStore(testCase, database); |
| 130 | }).then(database => { |
| 131 | database.close(); |
| 132 | }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 133 | const store = transaction.objectStore('books'); |
| 134 | const index = store.index('by_author'); |
| 135 | index.name = 'by_author'; |
| 136 | assert_array_equals( |
| 137 | store.indexNames, ['by_author', 'by_title'], |
| 138 | 'Renaming an index to the same name should not change the ' + |
| 139 | "index's IDBObjectStore.indexNames"); |
| 140 | })).then(database => { |
| 141 | const transaction = database.transaction('books', 'readonly'); |
| 142 | const store = transaction.objectStore('books'); |
| 143 | assert_array_equals( |
| 144 | store.indexNames, ['by_author', 'by_title'], |
| 145 | 'Committing a transaction that renames a store to the same name ' + |
| 146 | "should not change the index's IDBObjectStore.indexNames"); |
| 147 | const index = store.index('by_author'); |
| 148 | return checkAuthorIndexContents( |
| 149 | testCase, index, |
| 150 | 'Committing a transaction that renames an index to the same name ' + |
| 151 | "should not change the index's contents").then( |
| 152 | () => database.close()); |
| 153 | }); |
| 154 | }, 'IndexedDB index rename to the same name succeeds'); |
| 155 | |
| 156 | promise_test(testCase => { |
| 157 | return createDatabase(testCase, (database, transaction) => { |
| 158 | createBooksStore(testCase, database); |
| 159 | }).then(database => { |
| 160 | database.close(); |
| 161 | }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 162 | const store = transaction.objectStore('books'); |
| 163 | const index = store.index('by_author'); |
| 164 | store.deleteIndex('by_title'); |
| 165 | index.name = 'by_title'; |
| 166 | assert_array_equals( |
| 167 | store.indexNames, ['by_title'], |
| 168 | 'IDBObjectStore.indexNames should immediately reflect the rename'); |
| 169 | })).then(database => { |
| 170 | const transaction = database.transaction('books', 'readonly'); |
| 171 | const store = transaction.objectStore('books'); |
| 172 | assert_array_equals( |
| 173 | store.indexNames, ['by_title'], |
| 174 | 'IDBObjectStore.indexNames should still reflect the rename after ' + |
| 175 | 'the versionchange transaction commits'); |
| 176 | const index = store.index('by_title'); |
| 177 | return checkAuthorIndexContents( |
| 178 | testCase, index, |
| 179 | 'Renaming an index should not change its contents').then( |
| 180 | () => database.close()); |
| 181 | }); |
| 182 | }, 'IndexedDB index rename to the name of a deleted index succeeds'); |
| 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.index('by_author').name = 'tmp'; |
| 192 | store.index('by_title').name = 'by_author'; |
| 193 | store.index('tmp').name = 'by_title'; |
| 194 | assert_array_equals( |
| 195 | store.indexNames, ['by_author', 'by_title'], |
| 196 | 'IDBObjectStore.indexNames should reflect the swap immediately ' + |
| 197 | 'after the renames'); |
| 198 | return checkTitleIndexContents( |
| 199 | testCase, store.index('by_author'), |
| 200 | 'Renaming an index should not change its contents'); |
| 201 | })).then(database => { |
| 202 | const transaction = database.transaction('books', 'readonly'); |
| 203 | const store = transaction.objectStore('books'); |
| 204 | assert_array_equals( |
| 205 | store.indexNames, ['by_author', 'by_title'], |
| 206 | 'IDBObjectStore.indexNames should still reflect the swap after ' + |
| 207 | 'the versionchange transaction commits'); |
| 208 | const index = store.index('by_title'); |
| 209 | return checkAuthorIndexContents( |
| 210 | testCase, index, |
| 211 | 'Renaming an index should not change its contents').then( |
| 212 | () => database.close()); |
| 213 | }); |
| 214 | }, 'IndexedDB index swapping via renames succeeds'); |
| 215 | |
| 216 | promise_test(testCase => { |
| 217 | return createDatabase(testCase, (database, transaction) => { |
| 218 | createBooksStore(testCase, database); |
| 219 | }).then(database => { |
| 220 | database.close(); |
| 221 | }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 222 | const store = transaction.objectStore('books'); |
| 223 | const index = store.index('by_author'); |
| 224 | |
| 225 | index.name = 42; |
| 226 | assert_equals(index.name, '42', |
| 227 | 'IDBIndex name should change immediately after a rename to a ' + |
| 228 | 'number'); |
| 229 | assert_array_equals( |
| 230 | store.indexNames, ['42', 'by_title'], |
| 231 | 'IDBObjectStore.indexNames should immediately reflect the ' + |
| 232 | 'stringifying rename'); |
| 233 | |
| 234 | index.name = true; |
| 235 | assert_equals(index.name, 'true', |
| 236 | 'IDBIndex name should change immediately after a rename to a ' + |
| 237 | 'boolean'); |
| 238 | |
| 239 | index.name = {}; |
| 240 | assert_equals(index.name, '[object Object]', |
| 241 | 'IDBIndex name should change immediately after a rename to an ' + |
| 242 | 'object'); |
| 243 | |
| 244 | index.name = () => null; |
| 245 | assert_equals(index.name, '() => null', |
| 246 | 'IDBIndex name should change immediately after a rename to a ' + |
| 247 | 'function'); |
| 248 | |
| 249 | index.name = undefined; |
| 250 | assert_equals(index.name, 'undefined', |
| 251 | 'IDBIndex name should change immediately after a rename to ' + |
| 252 | 'undefined'); |
| 253 | })).then(database => { |
| 254 | const transaction = database.transaction('books', 'readonly'); |
| 255 | const store = transaction.objectStore('books'); |
| 256 | assert_array_equals( |
| 257 | store.indexNames, ['by_title', 'undefined'], |
| 258 | 'IDBObjectStore.indexNames should reflect the last rename ' + |
| 259 | 'after the versionchange transaction commits'); |
| 260 | const index = store.index('undefined'); |
| 261 | return checkAuthorIndexContents( |
| 262 | testCase, index, |
| 263 | 'Renaming an index should not change its contents').then( |
| 264 | () => database.close()); |
| 265 | }); |
| 266 | }, 'IndexedDB index rename stringifies non-string names'); |
| 267 | |
| 268 | for (let escapedName of ['', '\\u0000', '\\uDC00\\uD800']) ((escapedName) => { |
| 269 | const name = JSON.parse('"' + escapedName + '"'); |
| 270 | promise_test(testCase => { |
| 271 | return createDatabase(testCase, (database, transaction) => { |
| 272 | createBooksStore(testCase, database); |
| 273 | }).then(database => { |
| 274 | database.close(); |
| 275 | }).then(() => migrateDatabase(testCase, 2, (database, transaction) => { |
| 276 | const store = transaction.objectStore('books'); |
| 277 | const index = store.index('by_author'); |
| 278 | |
| 279 | index.name = name; |
| 280 | assert_equals(index.name, name, |
| 281 | 'IDBIndex name should change immediately after the rename'); |
| 282 | assert_array_equals( |
| 283 | store.indexNames, [name, 'by_title'].sort(), |
| 284 | 'IDBObjectStore.indexNames should immediately reflect the rename'); |
| 285 | })).then(database => { |
| 286 | const transaction = database.transaction('books', 'readonly'); |
| 287 | const store = transaction.objectStore('books'); |
| 288 | assert_array_equals( |
| 289 | store.indexNames, [name, 'by_title'].sort(), |
| 290 | 'IDBObjectStore.indexNames should reflect the rename ' + |
| 291 | 'after the versionchange transaction commits'); |
| 292 | const index = store.index(name); |
| 293 | return checkAuthorIndexContents( |
| 294 | testCase, index, |
| 295 | 'Renaming an index should not change its contents').then( |
| 296 | () => database.close()); |
| 297 | }); |
| 298 | }, 'IndexedDB index can be renamed to "' + escapedName + '"'); |
| 299 | })(escapedName); |
| 300 | |
| 301 | </script> |