test_complex_keyPaths.js (11033B)
1 /** 2 * Any copyright is dedicated to the Public Domain. 3 * http://creativecommons.org/publicdomain/zero/1.0/ 4 */ 5 6 /* exported testGenerator */ 7 var testGenerator = testSteps(); 8 9 function* testSteps() { 10 // Test object stores 11 12 const name = "test_complex_keyPaths"; 13 const keyPaths = [ 14 { keyPath: "id", value: { id: 5 }, key: 5 }, 15 { keyPath: "id", value: { id: "14", iid: 12 }, key: "14" }, 16 { keyPath: "id", value: { iid: "14", id: 12 }, key: 12 }, 17 { keyPath: "id", value: {} }, 18 { keyPath: "id", value: { id: {} } }, 19 { keyPath: "id", value: { id: /x/ } }, 20 { keyPath: "id", value: 2 }, 21 { keyPath: "id", value: undefined }, 22 { keyPath: "foo.id", value: { foo: { id: 7 } }, key: 7 }, 23 { keyPath: "foo.id", value: { id: 7, foo: { id: "asdf" } }, key: "asdf" }, 24 { keyPath: "foo.id", value: { foo: { id: undefined } } }, 25 { keyPath: "foo.id", value: { foo: 47 } }, 26 { keyPath: "foo.id", value: {} }, 27 { keyPath: "", value: "foopy", key: "foopy" }, 28 { keyPath: "", value: 2, key: 2 }, 29 { keyPath: "", value: undefined }, 30 { keyPath: "", value: { id: 12 } }, 31 { keyPath: "", value: /x/ }, 32 { 33 keyPath: "foo.bar", 34 value: { baz: 1, foo: { baz2: 2, bar: "xo" } }, 35 key: "xo", 36 }, 37 { 38 keyPath: "foo.bar.baz", 39 value: { foo: { bar: { bazz: 16, baz: 17 } } }, 40 key: 17, 41 }, 42 { keyPath: "foo..id", exception: true }, 43 { keyPath: "foo.", exception: true }, 44 { keyPath: "fo o", exception: true }, 45 { keyPath: "foo ", exception: true }, 46 { keyPath: "foo[bar]", exception: true }, 47 { keyPath: "foo[1]", exception: true }, 48 { keyPath: "$('id').stuff", exception: true }, 49 { keyPath: "foo.2.bar", exception: true }, 50 { keyPath: "foo. .bar", exception: true }, 51 { keyPath: ".bar", exception: true }, 52 { keyPath: [], exception: true }, 53 54 { keyPath: ["foo", "bar"], value: { foo: 1, bar: 2 }, key: [1, 2] }, 55 { keyPath: ["foo"], value: { foo: 1, bar: 2 }, key: [1] }, 56 { 57 keyPath: ["foo", "bar", "bar"], 58 value: { foo: 1, bar: "x" }, 59 key: [1, "x", "x"], 60 }, 61 { keyPath: ["x", "y"], value: { x: [], y: "x" }, key: [[], "x"] }, 62 { keyPath: ["x", "y"], value: { x: [[1]], y: "x" }, key: [[[1]], "x"] }, 63 { 64 keyPath: ["x", "y"], 65 value: { x: [[1]], y: new Date(1) }, 66 key: [[[1]], new Date(1)], 67 }, 68 { 69 keyPath: ["x", "y"], 70 value: { x: [[1]], y: [new Date(3)] }, 71 key: [[[1]], [new Date(3)]], 72 }, 73 { 74 keyPath: ["x", "y.bar"], 75 value: { x: "hi", y: { bar: "x" } }, 76 key: ["hi", "x"], 77 }, 78 { 79 keyPath: ["x.y", "y.bar"], 80 value: { x: { y: "hello" }, y: { bar: "nurse" } }, 81 key: ["hello", "nurse"], 82 }, 83 { keyPath: ["", ""], value: 5, key: [5, 5] }, 84 { keyPath: ["x", "y"], value: { x: 1 } }, 85 { keyPath: ["x", "y"], value: { y: 1 } }, 86 { keyPath: ["x", "y"], value: { x: 1, y: undefined } }, 87 { keyPath: ["x", "y"], value: { x: null, y: 1 } }, 88 { keyPath: ["x", "y.bar"], value: { x: null, y: { bar: "x" } } }, 89 { keyPath: ["x", "y"], value: { x: 1, y: false } }, 90 { keyPath: ["x", "y", "z"], value: { x: 1, y: false, z: "a" } }, 91 { keyPath: [".x", "y", "z"], exception: true }, 92 { keyPath: ["x", "y ", "z"], exception: true }, 93 ]; 94 95 let openRequest = indexedDB.open(name, 1); 96 openRequest.onerror = errorHandler; 97 openRequest.onupgradeneeded = grabEventAndContinueHandler; 98 openRequest.onsuccess = unexpectedSuccessHandler; 99 let event = yield undefined; 100 let db = event.target.result; 101 102 let stores = {}; 103 104 // Test creating object stores and inserting data 105 for (let i = 0; i < keyPaths.length; i++) { 106 let info = keyPaths[i]; 107 108 let test = " for objectStore test " + JSON.stringify(info); 109 let indexName = JSON.stringify(info.keyPath); 110 if (!stores[indexName]) { 111 try { 112 let objectStore = db.createObjectStore(indexName, { 113 keyPath: info.keyPath, 114 }); 115 ok(!("exception" in info), "shouldn't throw" + test); 116 is( 117 JSON.stringify(objectStore.keyPath), 118 JSON.stringify(info.keyPath), 119 "correct keyPath property" + test 120 ); 121 ok( 122 // eslint-disable-next-line no-self-compare 123 objectStore.keyPath === objectStore.keyPath, 124 "object identity should be preserved" 125 ); 126 stores[indexName] = objectStore; 127 } catch (e) { 128 ok("exception" in info, "should throw" + test); 129 is(e.name, "SyntaxError", "expect a SyntaxError" + test); 130 ok(e instanceof DOMException, "Got a DOM Exception" + test); 131 is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); 132 continue; 133 } 134 } 135 136 let store = stores[indexName]; 137 138 try { 139 var request = store.add(info.value); 140 ok("key" in info, "successfully created request to insert value" + test); 141 } catch (e) { 142 ok(!("key" in info), "threw when attempted to insert" + test); 143 ok(e instanceof DOMException, "Got a DOMException" + test); 144 is(e.name, "DataError", "expect a DataError" + test); 145 is(e.code, 0, "expect zero" + test); 146 continue; 147 } 148 149 request.onerror = errorHandler; 150 request.onsuccess = grabEventAndContinueHandler; 151 152 let e = yield undefined; 153 is(e.type, "success", "inserted successfully" + test); 154 is(e.target, request, "expected target" + test); 155 ok(compareKeys(request.result, info.key), "found correct key" + test); 156 is( 157 indexedDB.cmp(request.result, info.key), 158 0, 159 "returned key compares correctly" + test 160 ); 161 162 store.get(info.key).onsuccess = grabEventAndContinueHandler; 163 e = yield undefined; 164 isnot(e.target.result, undefined, "Did find entry"); 165 166 // Check that cursor.update work as expected 167 request = store.openCursor(); 168 request.onerror = errorHandler; 169 request.onsuccess = grabEventAndContinueHandler; 170 e = yield undefined; 171 let cursor = e.target.result; 172 request = cursor.update(info.value); 173 request.onerror = errorHandler; 174 request.onsuccess = grabEventAndContinueHandler; 175 yield undefined; 176 ok(true, "Successfully updated cursor" + test); 177 178 // Check that cursor.update throws as expected when key is changed 179 let newValue = cursor.value; 180 let destProp = Array.isArray(info.keyPath) ? info.keyPath[0] : info.keyPath; 181 if (destProp) { 182 let splitDestProp = destProp.split("."); 183 if (splitDestProp.length == 1) { 184 newValue[splitDestProp[0]] = "newKeyValue"; 185 } else if (splitDestProp.length == 2) { 186 newValue[splitDestProp[0]][splitDestProp[1]] = "newKeyValue"; 187 } else { 188 newValue[splitDestProp[0]][splitDestProp[1]][splitDestProp[2]] = 189 "newKeyValue"; 190 } 191 } else { 192 newValue = "newKeyValue"; 193 } 194 let didThrow; 195 try { 196 cursor.update(newValue); 197 } catch (ex) { 198 didThrow = ex; 199 } 200 ok(didThrow instanceof DOMException, "Got a DOMException" + test); 201 is(didThrow.name, "DataError", "expect a DataError" + test); 202 is(didThrow.code, 0, "expect zero" + test); 203 204 // Clear object store to prepare for next test 205 store.clear().onsuccess = grabEventAndContinueHandler; 206 yield undefined; 207 } 208 209 // Attempt to create indexes and insert data 210 let store = db.createObjectStore("indexStore"); 211 let indexes = {}; 212 for (let i = 0; i < keyPaths.length; i++) { 213 let info = keyPaths[i]; 214 let test = " for index test " + JSON.stringify(info); 215 let indexName = JSON.stringify(info.keyPath); 216 if (!indexes[indexName]) { 217 try { 218 let index = store.createIndex(indexName, info.keyPath); 219 ok(!("exception" in info), "shouldn't throw" + test); 220 is( 221 JSON.stringify(index.keyPath), 222 JSON.stringify(info.keyPath), 223 "index has correct keyPath property" + test 224 ); 225 ok( 226 // eslint-disable-next-line no-self-compare 227 index.keyPath === index.keyPath, 228 "object identity should be preserved" 229 ); 230 indexes[indexName] = index; 231 } catch (e) { 232 ok("exception" in info, "should throw" + test); 233 is(e.name, "SyntaxError", "expect a SyntaxError" + test); 234 ok(e instanceof DOMException, "Got a DOM Exception" + test); 235 is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test); 236 continue; 237 } 238 } 239 240 let index = indexes[indexName]; 241 242 request = store.add(info.value, 1); 243 if ("key" in info) { 244 index.getKey(info.key).onsuccess = grabEventAndContinueHandler; 245 let e = yield undefined; 246 is(e.target.result, 1, "found value when reading" + test); 247 } else { 248 index.count().onsuccess = grabEventAndContinueHandler; 249 let e = yield undefined; 250 is(e.target.result, 0, "should be empty" + test); 251 } 252 253 store.clear().onsuccess = grabEventAndContinueHandler; 254 yield undefined; 255 } 256 257 // Autoincrement and complex key paths 258 let aitests = [ 259 { v: {}, k: 1, res: { foo: { id: 1 } } }, 260 { v: { value: "x" }, k: 2, res: { value: "x", foo: { id: 2 } } }, 261 { v: { value: "x", foo: {} }, k: 3, res: { value: "x", foo: { id: 3 } } }, 262 { 263 v: { v: "x", foo: { x: "y" } }, 264 k: 4, 265 res: { v: "x", foo: { x: "y", id: 4 } }, 266 }, 267 { v: { value: 2, foo: { id: 10 } }, k: 10 }, 268 { v: { value: 2 }, k: 11, res: { value: 2, foo: { id: 11 } } }, 269 { v: true }, 270 { v: { value: 2, foo: 12 } }, 271 { v: { foo: { id: true } } }, 272 { v: { foo: { x: 5, id: {} } } }, 273 { v: undefined }, 274 { v: { foo: undefined } }, 275 { v: { foo: { id: undefined } } }, 276 { v: null }, 277 { v: { foo: null } }, 278 { v: { foo: { id: null } } }, 279 ]; 280 281 store = db.createObjectStore("gen", { 282 keyPath: "foo.id", 283 autoIncrement: true, 284 }); 285 for (let i = 0; i < aitests.length; ++i) { 286 let info = aitests[i]; 287 let test = " for autoIncrement test " + JSON.stringify(info); 288 289 let preValue = JSON.stringify(info.v); 290 if ("k" in info) { 291 store.add(info.v).onsuccess = grabEventAndContinueHandler; 292 is(JSON.stringify(info.v), preValue, "put didn't modify value" + test); 293 } else { 294 try { 295 store.add(info.v); 296 ok(false, "should throw" + test); 297 } catch (e) { 298 ok(true, "did throw" + test); 299 ok(e instanceof DOMException, "Got a DOMException" + test); 300 is(e.name, "DataError", "expect a DataError" + test); 301 is(e.code, 0, "expect zero" + test); 302 303 is( 304 JSON.stringify(info.v), 305 preValue, 306 "failing put didn't modify value" + test 307 ); 308 309 continue; 310 } 311 } 312 313 let e = yield undefined; 314 is(e.target.result, info.k, "got correct return key" + test); 315 316 store.get(info.k).onsuccess = grabEventAndContinueHandler; 317 e = yield undefined; 318 is( 319 JSON.stringify(e.target.result), 320 JSON.stringify(info.res || info.v), 321 "expected value stored" + test 322 ); 323 } 324 325 openRequest.onsuccess = grabEventAndContinueHandler; 326 yield undefined; 327 328 finishTest(); 329 }