indexeddbshim 19.0.5 → 19.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -1
- package/dist/CFG.d.ts.map +1 -1
- package/dist/DOMException.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBDatabase.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts +1 -2
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts +2 -6
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBKeyRange.d.ts.map +1 -1
- package/dist/IDBObjectStore.d.ts.map +1 -1
- package/dist/IDBRecord.d.ts.map +1 -1
- package/dist/IDBRequest.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/Sca.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +73 -33
- package/dist/indexeddbshim-Key.js.map +1 -1
- package/dist/indexeddbshim-Key.min.js +2 -2
- package/dist/indexeddbshim-Key.min.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs +543 -221
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +572 -249
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +3 -3
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +543 -221
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +572 -249
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +3 -3
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +572 -249
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +3 -3
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/setGlobalVars.d.ts +1 -1
- package/dist/setGlobalVars.d.ts.map +1 -1
- package/dist/util.d.ts.map +1 -1
- package/licenseInfo.json +8 -0
- package/package.json +106 -102
- package/src/CFG.js +18 -4
- package/src/DOMException.js +6 -0
- package/src/DOMStringList.js +3 -0
- package/src/IDBCursor.js +36 -3
- package/src/IDBDatabase.js +26 -10
- package/src/IDBFactory.js +105 -5
- package/src/IDBIndex.js +49 -32
- package/src/IDBKeyRange.js +8 -7
- package/src/IDBObjectStore.js +25 -2
- package/src/IDBRecord.js +2 -0
- package/src/IDBRequest.js +7 -4
- package/src/IDBTransaction.js +97 -26
- package/src/Key.js +53 -22
- package/src/Sca.js +9 -4
- package/src/nodeWebSQL.js +1 -0
- package/src/setGlobalVars.js +86 -77
- package/src/util.js +5 -6
package/src/IDBFactory.js
CHANGED
|
@@ -148,6 +148,7 @@ function triggerAnyVersionChangeAndBlockedEvents (openConnections, req, oldVersi
|
|
|
148
148
|
return undefined;
|
|
149
149
|
}
|
|
150
150
|
const e = /** @type {Event & IDBVersionChangeEvent} */ (
|
|
151
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
151
152
|
// @ts-ignore It's ok; needed under some TS versions
|
|
152
153
|
new IDBVersionChangeEvent('versionchange', {oldVersion, newVersion})
|
|
153
154
|
);
|
|
@@ -193,6 +194,7 @@ function triggerAnyVersionChangeAndBlockedEvents (openConnections, req, oldVersi
|
|
|
193
194
|
}
|
|
194
195
|
};
|
|
195
196
|
const e = /** @type {Event & IDBVersionChangeEvent} */ (
|
|
197
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
196
198
|
// @ts-ignore It's ok; needed under some TS versions
|
|
197
199
|
new IDBVersionChangeEvent('blocked', {oldVersion, newVersion})
|
|
198
200
|
);
|
|
@@ -251,6 +253,13 @@ const pendingVersionChanges = new Map();
|
|
|
251
253
|
|
|
252
254
|
/** @type {import('websql-configurable/lib/websql/WebSQLDatabase.js').default} */
|
|
253
255
|
let sysdb;
|
|
256
|
+
// Tracks which `CFG.memoryDatabase` value `sysdb` was opened against, so a
|
|
257
|
+
// later change to that config (e.g. toggling in-memory mode on and back
|
|
258
|
+
// off) causes `sysdb` to be recreated for the new setting rather than
|
|
259
|
+
// staying pinned, forever, to whatever it was the first time any database
|
|
260
|
+
// was created in the process.
|
|
261
|
+
/** @type {string|null|undefined} */
|
|
262
|
+
let sysdbMemoryDatabaseSetting;
|
|
254
263
|
let nameCounter = 0;
|
|
255
264
|
|
|
256
265
|
/**
|
|
@@ -337,12 +346,20 @@ function closeCachedWebSQLConnections (name, cb) {
|
|
|
337
346
|
function cleanupDatabaseResources (__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError) {
|
|
338
347
|
const useMemoryDatabase = typeof CFG.memoryDatabase === 'string';
|
|
339
348
|
if (useMemoryDatabase) {
|
|
349
|
+
/* c8 ignore start -- Defensive: only reachable if `websqlDBCache[name]`
|
|
350
|
+
was initialized as an empty placeholder by `open()`'s connection-queue
|
|
351
|
+
setup (`addRequestToConnectionQueue`, above `openDB`) but never
|
|
352
|
+
populated with an actual instance -- e.g. `__openDatabase` throwing
|
|
353
|
+
after a `dbVersions` row already existed for `name` from an earlier,
|
|
354
|
+
successful `open()` -- or if `name` was never added to the cache at
|
|
355
|
+
all. Not reachable via normal, non-tampered API usage. */
|
|
340
356
|
const latestSQLiteDBCached = Object.hasOwn(websqlDBCache, name) ? getLatestCachedWebSQLDB(name) : null;
|
|
341
357
|
if (!latestSQLiteDBCached) {
|
|
342
358
|
console.warn('Could not find a memory database instance to delete.');
|
|
343
359
|
databaseDeleted();
|
|
344
360
|
return;
|
|
345
361
|
}
|
|
362
|
+
/* c8 ignore stop -- see comment above */
|
|
346
363
|
const sqliteDB = latestSQLiteDBCached._db;
|
|
347
364
|
if (!sqliteDB || !sqliteDB.close) {
|
|
348
365
|
console.error('The `openDatabase` implementation does not have the expected `._db.close` method for closing the database');
|
|
@@ -404,15 +421,24 @@ function cleanupDatabaseResources (__openDatabase, name, escapedDatabaseName, da
|
|
|
404
421
|
), [], function () {
|
|
405
422
|
deleteTables(i + 1);
|
|
406
423
|
}, function () {
|
|
424
|
+
/* c8 ignore start -- Defensive: continues deleting the rest
|
|
425
|
+
even if this specific store's table is already gone (e.g.
|
|
426
|
+
duplicate `__sys__` rows for the same escaped table name, or
|
|
427
|
+
external tampering); not reachable via normal API usage. */
|
|
407
428
|
deleteTables(i + 1);
|
|
408
429
|
return false;
|
|
430
|
+
/* c8 ignore stop -- see comment above */
|
|
409
431
|
});
|
|
410
432
|
}
|
|
411
433
|
}(0));
|
|
412
434
|
}, function () {
|
|
413
|
-
|
|
435
|
+
/* c8 ignore start -- `__sys__` is always created by `openDB` before this
|
|
436
|
+
database's `dbVersions` row (a prerequisite for reaching this code at
|
|
437
|
+
all) is ever inserted; only reachable if the file was tampered with/
|
|
438
|
+
removed externally afterward. */
|
|
414
439
|
databaseDeleted();
|
|
415
440
|
return false;
|
|
441
|
+
/* c8 ignore stop -- see comment above */
|
|
416
442
|
});
|
|
417
443
|
});
|
|
418
444
|
}
|
|
@@ -442,9 +468,11 @@ function createSysDB (__openDatabase, success, failure) {
|
|
|
442
468
|
failure(er);
|
|
443
469
|
}
|
|
444
470
|
|
|
445
|
-
if (sysdb) {
|
|
471
|
+
if (sysdb && sysdbMemoryDatabaseSetting === CFG.memoryDatabase) {
|
|
446
472
|
success();
|
|
447
473
|
} else {
|
|
474
|
+
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Needed
|
|
475
|
+
sysdbMemoryDatabaseSetting = CFG.memoryDatabase;
|
|
448
476
|
// eslint-disable-next-line unicorn/no-top-level-assignment-in-function -- Necessary?
|
|
449
477
|
sysdb = __openDatabase(
|
|
450
478
|
typeof CFG.memoryDatabase === 'string'
|
|
@@ -643,6 +671,17 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
643
671
|
* @returns {void}
|
|
644
672
|
*/
|
|
645
673
|
let sysdbFinishedCb = function (systx, err, cb) {
|
|
674
|
+
/* c8 ignore start -- This initial definition is always
|
|
675
|
+
superseded before ever being invoked: the `sysdb.transaction(...)`
|
|
676
|
+
call below always reaches its `nonstandardTransCb` (4th arg)
|
|
677
|
+
after this same SQL batch finishes running (since `dbCreateError`
|
|
678
|
+
always reports errors as "handled" and this call site is never
|
|
679
|
+
a `readTransaction`), which unconditionally reassigns
|
|
680
|
+
`sysdbFinishedCb` to a version using the library's own
|
|
681
|
+
`rollback`/`commit` -- well before any real invocation from
|
|
682
|
+
`on__beforecomplete`/`on__preabort`/`on__abort` below (those only
|
|
683
|
+
fire once the upgrade transaction itself later completes/aborts).
|
|
684
|
+
Kept as a defensive fallback in case that invariant ever changes. */
|
|
646
685
|
if (err) {
|
|
647
686
|
/**
|
|
648
687
|
* @param {unknown} [errorToShow]
|
|
@@ -709,6 +748,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
709
748
|
}
|
|
710
749
|
// In browser, should auto-commit
|
|
711
750
|
cb(); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
751
|
+
/* c8 ignore stop -- see comment above */
|
|
712
752
|
};
|
|
713
753
|
|
|
714
754
|
sysdb.transaction(function (systx) {
|
|
@@ -717,6 +757,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
717
757
|
*/
|
|
718
758
|
function versionSet () {
|
|
719
759
|
const e = /** @type {import('eventtargeter').EventWithProps & Event & IDBVersionChangeEvent} */ (
|
|
760
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
720
761
|
// @ts-ignore It's ok; needed under some TS versions
|
|
721
762
|
new IDBVersionChangeEvent('upgradeneeded', {oldVersion, newVersion: version})
|
|
722
763
|
);
|
|
@@ -850,9 +891,16 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
850
891
|
// eslint-disable-next-line camelcase -- Clear API
|
|
851
892
|
req.transaction.on__complete = function () {
|
|
852
893
|
const pos = connection.__transactions.indexOf(req.transaction);
|
|
894
|
+
// `req.transaction` (the versionchange transaction) is created
|
|
895
|
+
// directly via `IDBTransaction.__createInstance` above, never
|
|
896
|
+
// via `IDBDatabase.prototype.transaction()` (the only place
|
|
897
|
+
// that pushes onto `connection.__transactions`), so `pos` is
|
|
898
|
+
// always -1 here.
|
|
899
|
+
/* c8 ignore start -- see comment above */
|
|
853
900
|
if (pos !== -1) {
|
|
854
901
|
connection.__transactions.splice(pos, 1);
|
|
855
902
|
}
|
|
903
|
+
/* c8 ignore stop -- see comment above */
|
|
856
904
|
|
|
857
905
|
if (/** @type {import('./IDBDatabase.js').IDBDatabaseFull} */ (
|
|
858
906
|
req.__result
|
|
@@ -890,9 +938,16 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
890
938
|
systx.executeSql('UPDATE dbVersions SET "version" = ? WHERE "name" = ?', [version, sqlSafeName], versionSet, dbCreateError);
|
|
891
939
|
}
|
|
892
940
|
}, dbCreateError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
941
|
+
// Defensive fallback, not reachable in practice: same reasoning
|
|
942
|
+
// as `deleteDatabase`'s own `nonstandardTransCb` below
|
|
943
|
+
// (`currentTask.readOnly` is always false here, and
|
|
944
|
+
// `dbCreateError` always returns `false`, so `err` is never
|
|
945
|
+
// truthy either).
|
|
946
|
+
/* c8 ignore start -- see comment above */
|
|
893
947
|
if (currentTask.readOnly || err) {
|
|
894
948
|
return true;
|
|
895
949
|
}
|
|
950
|
+
/* c8 ignore stop -- see comment above */
|
|
896
951
|
sysdbFinishedCb = function (systx, err, cb) {
|
|
897
952
|
if (err) {
|
|
898
953
|
rollback(err,
|
|
@@ -915,7 +970,16 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
915
970
|
);
|
|
916
971
|
}
|
|
917
972
|
},
|
|
973
|
+
// Deeply-nested defensive path: only reached if
|
|
974
|
+
// the *revert* SQL (undoing the `dbVersions`
|
|
975
|
+
// INSERT/UPDATE after the original version-
|
|
976
|
+
// upgrade itself already failed) fails a
|
|
977
|
+
// *second* time. Not feasibly triggerable
|
|
978
|
+
// without fault-injecting the underlying SQL
|
|
979
|
+
// driver on this specific, already-failing
|
|
980
|
+
// revert statement.
|
|
918
981
|
function (sqlErr) {
|
|
982
|
+
/* c8 ignore next 2 -- see comment above */
|
|
919
983
|
isRevertingSysdb = false;
|
|
920
984
|
cb(sqlErr); // eslint-disable-line promise/no-callback-in-promise -- Convenient
|
|
921
985
|
},
|
|
@@ -933,8 +997,20 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
933
997
|
});
|
|
934
998
|
return undefined;
|
|
935
999
|
}).catch((err) => {
|
|
1000
|
+
/* c8 ignore start -- Purely defensive: nothing in
|
|
1001
|
+
`triggerAnyVersionChangeAndBlockedEvents`'s promise chain
|
|
1002
|
+
(or this `.then()` continuation above) ever rejects/throws
|
|
1003
|
+
under any reachable application-level condition -- all of
|
|
1004
|
+
its continuations resolve cleanly, and its `dispatchEvent`
|
|
1005
|
+
calls are deliberately fire-and-forget ("No need to catch
|
|
1006
|
+
errors"), running inside a `setTimeout` where a listener
|
|
1007
|
+
throwing becomes an uncaught exception in that macrotask
|
|
1008
|
+
rather than a promise rejection here. This exists solely
|
|
1009
|
+
to surface a truly-unexpected internal bug via the console
|
|
1010
|
+
before rethrowing, not to handle a real, testable error path. */
|
|
936
1011
|
console.log('Error within `triggerAnyVersionChangeAndBlockedEvents`');
|
|
937
1012
|
throw err;
|
|
1013
|
+
/* c8 ignore stop -- see comment above */
|
|
938
1014
|
});
|
|
939
1015
|
} else {
|
|
940
1016
|
finishRequest();
|
|
@@ -964,15 +1040,25 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
964
1040
|
db = websqlDBCache[name][version];
|
|
965
1041
|
} else {
|
|
966
1042
|
db = /** @type {DatabaseFull} */ (me.__openDatabase(
|
|
967
|
-
useMemoryDatabase
|
|
1043
|
+
useMemoryDatabase
|
|
1044
|
+
? /** @type {string} */ (CFG.memoryDatabase)
|
|
1045
|
+
: util.joinPath(CFG.databaseBasePath || '', escapedDatabaseName),
|
|
968
1046
|
'1',
|
|
969
1047
|
name,
|
|
970
1048
|
CFG.DEFAULT_DB_SIZE
|
|
971
1049
|
));
|
|
972
1050
|
if (useDatabaseCache) {
|
|
1051
|
+
/* c8 ignore start -- Defensive: by the time `openDB` runs,
|
|
1052
|
+
`websqlDBCache[name]` has always already been created by
|
|
1053
|
+
`addRequestToConnectionQueue`'s own callback above (guarded
|
|
1054
|
+
by this same `useDatabaseCache` condition), which always
|
|
1055
|
+
runs first and unconditionally ensures the entry exists
|
|
1056
|
+
before ever calling `openDB`. Kept as a safety net in case
|
|
1057
|
+
that invariant ever changes. */
|
|
973
1058
|
if (!(Object.hasOwn(websqlDBCache, name))) {
|
|
974
1059
|
websqlDBCache[name] = {};
|
|
975
1060
|
}
|
|
1061
|
+
/* c8 ignore stop -- see comment above */
|
|
976
1062
|
websqlDBCache[name][version] = db;
|
|
977
1063
|
}
|
|
978
1064
|
}
|
|
@@ -1128,6 +1214,7 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
1128
1214
|
req.__result = undefined;
|
|
1129
1215
|
req.__done = true;
|
|
1130
1216
|
const e = /** @type {Event & IDBVersionChangeEvent} */ (
|
|
1217
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
1131
1218
|
// @ts-ignore It's ok; needed under some TS versions
|
|
1132
1219
|
new IDBVersionChangeEvent('success', {oldVersion: version, newVersion: null})
|
|
1133
1220
|
);
|
|
@@ -1169,9 +1256,23 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
1169
1256
|
cleanupDatabaseResources(me.__openDatabase, name, escapedDatabaseName, databaseDeleted, dbError);
|
|
1170
1257
|
}, dbError);
|
|
1171
1258
|
}, dbError, undefined, function (currentTask, err, done, rollback, commit) {
|
|
1259
|
+
/* c8 ignore start -- Defensive fallback, not reachable in
|
|
1260
|
+
practice: `currentTask.readOnly` is always `false` here
|
|
1261
|
+
(this callback is only ever attached to the writable
|
|
1262
|
+
`sysdb.transaction(...)` call above, never to a
|
|
1263
|
+
`sysdb.readTransaction(...)`), and `err` can only be
|
|
1264
|
+
truthy if the `DELETE FROM dbVersions` statement's own
|
|
1265
|
+
error callback (`dbError`) reports the failure back to
|
|
1266
|
+
`websql-configurable` as unhandled -- but `dbError`
|
|
1267
|
+
deliberately always `return`s `false`, which tells the
|
|
1268
|
+
library the error was already handled (and to keep
|
|
1269
|
+
`err` falsy here), precisely so this custom
|
|
1270
|
+
`sysdbFinishedCbDelete` rollback/commit path below is
|
|
1271
|
+
used instead of the library's own default rollback. */
|
|
1172
1272
|
if (currentTask.readOnly || err) {
|
|
1173
1273
|
return true;
|
|
1174
1274
|
}
|
|
1275
|
+
/* c8 ignore stop -- see comment above */
|
|
1175
1276
|
sysdbFinishedCbDelete = function (err, cb) {
|
|
1176
1277
|
if (err) {
|
|
1177
1278
|
rollback(err, cb);
|
|
@@ -1289,10 +1390,9 @@ IDBFactory.prototype.databases = function () {
|
|
|
1289
1390
|
};
|
|
1290
1391
|
|
|
1291
1392
|
/**
|
|
1292
|
-
* @todo forceClose: Test
|
|
1293
1393
|
* This is provided to facilitate unit-testing of the
|
|
1294
1394
|
* closing of a database connection with a forced flag:
|
|
1295
|
-
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection
|
|
1395
|
+
* <https://w3c.github.io/IndexedDB/#steps-for-closing-a-database-connection>.
|
|
1296
1396
|
* @param {string} dbName
|
|
1297
1397
|
* @param {Integer} connIdx
|
|
1298
1398
|
* @param {string} msg
|
package/src/IDBIndex.js
CHANGED
|
@@ -66,7 +66,6 @@ const IDBIndexAlias = IDBIndex;
|
|
|
66
66
|
* __unique: boolean,
|
|
67
67
|
* __objectStore: import('./IDBObjectStore.js').IDBObjectStoreFull,
|
|
68
68
|
* __keyPath: import('./Key.js').KeyPath,
|
|
69
|
-
* __recreated?: boolean,
|
|
70
69
|
* __fetchIndexData: (
|
|
71
70
|
* range: Query,
|
|
72
71
|
* opType: "value"|"key"|"count",
|
|
@@ -173,6 +172,7 @@ IDBIndex.__createInstance = function (store, indexProperties) {
|
|
|
173
172
|
['key', 'BLOB ' + (objectStore.autoIncrement ? 'UNIQUE, inc INTEGER PRIMARY KEY AUTOINCREMENT' : 'PRIMARY KEY')],
|
|
174
173
|
['value', 'BLOB']
|
|
175
174
|
].concat(
|
|
175
|
+
// eslint-disable-next-line jsdoc/ts-ban-ts-comment -- TS 6/7
|
|
176
176
|
// @ts-ignore Has numeric indexes instead of iterator; needed under some TS versions
|
|
177
177
|
[...objectStore.indexNames]
|
|
178
178
|
.filter((indexName) => indexName !== newName)
|
|
@@ -230,7 +230,7 @@ IDBIndex.__clone = function (index, store) {
|
|
|
230
230
|
});
|
|
231
231
|
/** @type {const} */ ([
|
|
232
232
|
'__pendingCreate', '__pendingDelete', '__deleted',
|
|
233
|
-
'__originalName'
|
|
233
|
+
'__originalName'
|
|
234
234
|
]).forEach((p) => {
|
|
235
235
|
// @ts-expect-error Why is this type "never"?
|
|
236
236
|
idx[p] = index[p];
|
|
@@ -270,11 +270,12 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
270
270
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
|
|
271
271
|
transaction
|
|
272
272
|
).__addNonRequestToTransactionQueue(function createIndex (tx, args, success, failure) {
|
|
273
|
-
const columnExists = idx &&
|
|
273
|
+
const columnExists = idx && idx.__deleted; // This check must occur here rather than earlier as properties may not have been set yet otherwise
|
|
274
274
|
|
|
275
275
|
/** @type {{[key: string]: boolean}} */
|
|
276
276
|
let indexValues = {};
|
|
277
277
|
|
|
278
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
278
279
|
/**
|
|
279
280
|
* @param {WebSQLTransaction} tx
|
|
280
281
|
* @param {(Error & {code?: number})} err
|
|
@@ -283,6 +284,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
283
284
|
function error (tx, err) {
|
|
284
285
|
failure(createDOMException('UnknownError', 'Could not create index "' + indexName + '"' + err.code + '::' + err.message, err));
|
|
285
286
|
}
|
|
287
|
+
/* c8 ignore stop -- see comment above */
|
|
286
288
|
|
|
287
289
|
/**
|
|
288
290
|
* @param {WebSQLTransaction} tx
|
|
@@ -343,12 +345,6 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
343
345
|
} else {
|
|
344
346
|
delete index.__pendingCreate;
|
|
345
347
|
delete indexHandle.__pendingCreate;
|
|
346
|
-
if (index.__deleted) {
|
|
347
|
-
delete index.__deleted;
|
|
348
|
-
delete indexHandle.__deleted;
|
|
349
|
-
index.__recreated = true;
|
|
350
|
-
indexHandle.__recreated = true;
|
|
351
|
-
}
|
|
352
348
|
indexValues = {};
|
|
353
349
|
success(store);
|
|
354
350
|
}
|
|
@@ -358,7 +354,7 @@ IDBIndex.__createIndex = function (store, index) {
|
|
|
358
354
|
}
|
|
359
355
|
|
|
360
356
|
const escapedStoreNameSQL = util.escapeStoreNameForSQL(storeName);
|
|
361
|
-
const escapedIndexNameSQL = util.escapeIndexNameForSQL(
|
|
357
|
+
const escapedIndexNameSQL = util.escapeIndexNameForSQL(indexName);
|
|
362
358
|
|
|
363
359
|
/**
|
|
364
360
|
* @param {WebSQLTransaction} tx
|
|
@@ -419,6 +415,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
419
415
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
|
|
420
416
|
transaction
|
|
421
417
|
).__addNonRequestToTransactionQueue(function deleteIndex (tx, args, success, failure) {
|
|
418
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
422
419
|
/**
|
|
423
420
|
* @param {WebSQLTransaction} tx
|
|
424
421
|
* @param {(Error & {code?: number})} err
|
|
@@ -427,6 +424,7 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
427
424
|
function error (tx, err) {
|
|
428
425
|
failure(createDOMException('UnknownError', 'Could not delete index "' + index.name + '"', err));
|
|
429
426
|
}
|
|
427
|
+
/* c8 ignore stop -- see comment above */
|
|
430
428
|
|
|
431
429
|
/**
|
|
432
430
|
* @returns {void}
|
|
@@ -435,7 +433,6 @@ IDBIndex.__deleteIndex = function (store, index) {
|
|
|
435
433
|
// Update the object store's index list
|
|
436
434
|
IDBIndex.__updateIndexList(store, tx, function (store) {
|
|
437
435
|
delete index.__pendingDelete;
|
|
438
|
-
delete index.__recreated;
|
|
439
436
|
index.__deleted = true;
|
|
440
437
|
if (indexHandle) {
|
|
441
438
|
indexHandle.__deleted = true;
|
|
@@ -505,21 +502,19 @@ IDBIndex.__updateIndexList = function (store, tx, success, failure) {
|
|
|
505
502
|
* @param {Query} range
|
|
506
503
|
* @param {"value"|"key"|"count"} opType
|
|
507
504
|
* @param {boolean} nullDisallowed
|
|
508
|
-
* @param {number} [count]
|
|
509
505
|
* @this {IDBIndexFull}
|
|
510
506
|
* @returns {import('./IDBRequest.js').IDBRequestFull}
|
|
511
507
|
*/
|
|
512
|
-
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed
|
|
508
|
+
IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed) {
|
|
513
509
|
const me = this;
|
|
514
|
-
if (count !== undefined) {
|
|
515
|
-
count = util.enforceRange(count, 'unsigned long');
|
|
516
|
-
}
|
|
517
510
|
|
|
518
511
|
IDBIndex.__invalidStateIfDeleted(me);
|
|
519
512
|
IDBObjectStore.__invalidStateIfDeleted(me.objectStore);
|
|
513
|
+
/* c8 ignore start -- Defensive: `IDBObjectStore.__invalidStateIfDeleted` just above already throws when `me.objectStore.__deleted` is true, so this identical check can never be reached. */
|
|
520
514
|
if (me.objectStore.__deleted) {
|
|
521
515
|
throw createDOMException('InvalidStateError', "This index's object store has been deleted");
|
|
522
516
|
}
|
|
517
|
+
/* c8 ignore stop -- see comment above */
|
|
523
518
|
IDBTransaction.__assertActive(me.objectStore.transaction);
|
|
524
519
|
|
|
525
520
|
if (nullDisallowed && util.isNullish(range)) {
|
|
@@ -531,7 +526,6 @@ IDBIndex.prototype.__fetchIndexData = function (range, opType, nullDisallowed, c
|
|
|
531
526
|
me.objectStore.transaction
|
|
532
527
|
).__addToTransactionQueue(function (...args) {
|
|
533
528
|
executeFetchIndexData(
|
|
534
|
-
count,
|
|
535
529
|
...fetchArgs,
|
|
536
530
|
// @ts-expect-error It's ok
|
|
537
531
|
...args
|
|
@@ -666,7 +660,9 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
666
660
|
const escapedTmpStoreNameSQL = util.sqlQuote('tmp_' + util.escapeStoreNameForSQL(storeName).slice(1, -1));
|
|
667
661
|
const colNamesToPreserve = colInfoToPreserveArr.map((colInfo) => colInfo[0]);
|
|
668
662
|
const colInfoToPreserve = colInfoToPreserveArr.map((colInfo) => colInfo.join(' '));
|
|
663
|
+
/* c8 ignore next -- Defensive: the sole caller always supplies a non-empty `colInfoToPreserveArr` (seeded with `key`/`value` column info), so the empty-array fallback is unreachable. */
|
|
669
664
|
const listColInfoToPreserve = (colInfoToPreserve.length ? (colInfoToPreserve.join(', ') + ', ') : '');
|
|
665
|
+
/* c8 ignore next -- Defensive: see comment above. */
|
|
670
666
|
const listColsToPreserve = (colNamesToPreserve.length ? (colNamesToPreserve.join(', ') + ', ') : '');
|
|
671
667
|
|
|
672
668
|
// We could adapt the approach at https://stackoverflow.com/a/8430746/271577
|
|
@@ -674,6 +670,7 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
674
670
|
/** @type {import('./IDBTransaction.js').IDBTransactionFull} */ (
|
|
675
671
|
store.transaction
|
|
676
672
|
).__addNonRequestToTransactionQueue(function renameIndex (tx, args, success, error) {
|
|
673
|
+
/* c8 ignore start -- Defensive: only reached if one of the chained `CREATE TABLE`/`INSERT`/`DROP TABLE`/`ALTER TABLE` statements below fails, which is not reliably reproducible without mocking the SQL layer. */
|
|
677
674
|
/**
|
|
678
675
|
* @param {WebSQLTransaction} tx
|
|
679
676
|
* @param {(Error & {code?: number})} err
|
|
@@ -682,6 +679,7 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
682
679
|
function sqlError (tx, err) {
|
|
683
680
|
error(err);
|
|
684
681
|
}
|
|
682
|
+
/* c8 ignore stop -- see comment above */
|
|
685
683
|
/**
|
|
686
684
|
* @returns {void}
|
|
687
685
|
*/
|
|
@@ -690,8 +688,14 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
690
688
|
cb(tx, success);
|
|
691
689
|
return;
|
|
692
690
|
}
|
|
691
|
+
/* c8 ignore start -- Defensive: `__renameIndex`'s only caller (the `IDBIndex.prototype.name` setter) always supplies a `cb`, so this fallback is dead with the current call graph. */
|
|
693
692
|
success();
|
|
694
693
|
}
|
|
694
|
+
/* c8 ignore stop -- see comment above */
|
|
695
|
+
if (!CFG.useSQLiteIndexes) {
|
|
696
|
+
finish();
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
695
699
|
// See https://www.sqlite.org/lang_altertable.html#otheralter
|
|
696
700
|
// We don't query for indexes as we already have the info
|
|
697
701
|
// This approach has the advantage of auto-deleting indexes via the DROP TABLE
|
|
@@ -710,10 +714,6 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
710
714
|
const sql = 'ALTER TABLE ' + escapedTmpStoreNameSQL + ' RENAME TO ' + escapedStoreNameSQL;
|
|
711
715
|
if (CFG.DEBUG) { console.log(sql); }
|
|
712
716
|
tx.executeSql(sql, [], function (tx) {
|
|
713
|
-
if (!CFG.useSQLiteIndexes) {
|
|
714
|
-
finish();
|
|
715
|
-
return;
|
|
716
|
-
}
|
|
717
717
|
const indexCreations = colNamesToPreserve
|
|
718
718
|
.slice(2) // Doing `key` separately and no need for index on `value`
|
|
719
719
|
.map((escapedIndexNameSQL) => new SyncPromise(function (resolve, reject) {
|
|
@@ -725,15 +725,18 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
725
725
|
// tx.executeSql(sql, [], function () {
|
|
726
726
|
const sql = 'CREATE INDEX ' +
|
|
727
727
|
escapedIndexToRecreate + ' ON ' + escapedStoreNameSQL + '(' + escapedIndexNameSQL + ')';
|
|
728
|
+
/* c8 ignore next -- Debug-only log; no test sets `CFG.DEBUG`. */
|
|
728
729
|
if (CFG.DEBUG) { console.log(sql); }
|
|
729
730
|
tx.executeSql(
|
|
730
731
|
sql,
|
|
731
732
|
[],
|
|
732
733
|
resolve,
|
|
734
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
733
735
|
/** @type {SqlErrorCallback} */
|
|
734
736
|
(function (tx, err) {
|
|
735
737
|
reject(err);
|
|
736
738
|
})
|
|
739
|
+
/* c8 ignore stop -- see comment above */
|
|
737
740
|
);
|
|
738
741
|
// }, function (tx, err) {
|
|
739
742
|
// reject(err);
|
|
@@ -752,16 +755,20 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
752
755
|
if (CFG.DEBUG) { console.log(sql); }
|
|
753
756
|
tx.executeSql(
|
|
754
757
|
sql, [], resolve,
|
|
758
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
755
759
|
/** @type {SqlErrorCallback} */
|
|
756
760
|
(function (tx, err) {
|
|
757
761
|
reject(err);
|
|
758
762
|
})
|
|
763
|
+
/* c8 ignore stop -- see comment above */
|
|
759
764
|
);
|
|
760
765
|
},
|
|
766
|
+
/* c8 ignore start -- Defensive: SQL execution error, not reliably reproducible without mocking the SQL layer. */
|
|
761
767
|
/** @type {SqlErrorCallback} */
|
|
762
768
|
(function (tx, err) {
|
|
763
769
|
reject(err);
|
|
764
770
|
})
|
|
771
|
+
/* c8 ignore stop -- see comment above */
|
|
765
772
|
);
|
|
766
773
|
})
|
|
767
774
|
);
|
|
@@ -769,8 +776,10 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
769
776
|
/** @type {(reason: unknown) => PromiseLike<never>} */
|
|
770
777
|
(error)
|
|
771
778
|
).catch((err) => {
|
|
779
|
+
/* c8 ignore start -- Defensive: only reached if `finish` or the outer `error` callback itself throws; not reliably reproducible. */
|
|
772
780
|
console.log('Index rename error');
|
|
773
781
|
throw err;
|
|
782
|
+
/* c8 ignore stop -- see comment above */
|
|
774
783
|
});
|
|
775
784
|
}, /** @type {SqlErrorCallback} */ (sqlError));
|
|
776
785
|
}, /** @type {SqlErrorCallback} */ (sqlError));
|
|
@@ -804,7 +813,6 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
804
813
|
/* eslint-enable unicorn/no-top-level-side-effects -- Would be good */
|
|
805
814
|
|
|
806
815
|
/**
|
|
807
|
-
* @param {number|null} count
|
|
808
816
|
* @param {boolean} unboundedDisallowed
|
|
809
817
|
* @param {IDBIndexFull} index
|
|
810
818
|
* @param {boolean} hasKey
|
|
@@ -822,14 +830,11 @@ Object.defineProperty(IDBIndex, 'prototype', {
|
|
|
822
830
|
* @returns {void}
|
|
823
831
|
*/
|
|
824
832
|
function executeFetchIndexData (
|
|
825
|
-
|
|
833
|
+
unboundedDisallowed, index, hasKey, range, opType,
|
|
826
834
|
multiChecks, sql, sqlValues, tx, args, success, error
|
|
827
835
|
) {
|
|
828
836
|
if (unboundedDisallowed) {
|
|
829
|
-
|
|
830
|
-
}
|
|
831
|
-
if (count) {
|
|
832
|
-
sql.push('LIMIT', String(count));
|
|
837
|
+
sql.push('LIMIT', '1');
|
|
833
838
|
}
|
|
834
839
|
const isCount = opType === 'count';
|
|
835
840
|
if (CFG.DEBUG) { console.log('Trying to fetch data for Index', sql.join(' '), sqlValues); }
|
|
@@ -895,11 +900,15 @@ function executeFetchIndexData (
|
|
|
895
900
|
record = row;
|
|
896
901
|
}
|
|
897
902
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
+
/* c8 ignore start -- Defensive: the SQL `LIKE` clause is a coarse pre-filter and this precise re-check in JS is meant to catch its false positives, but the encoding's per-character dash-prefix plus trailing-space delimiter (see `Key.js` string encoding) and fixed-length number encoding prevent one encoded value from ever being a spurious substring of another, so a `LIKE` hit always also passes this check in practice. */
|
|
904
|
+
if (!record) {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
/* c8 ignore stop -- see comment above */
|
|
908
|
+
|
|
909
|
+
records.push(decode(record));
|
|
910
|
+
if (unboundedDisallowed) {
|
|
911
|
+
break;
|
|
903
912
|
}
|
|
904
913
|
}
|
|
905
914
|
} else {
|
|
@@ -914,8 +923,16 @@ function executeFetchIndexData (
|
|
|
914
923
|
if (isCount) {
|
|
915
924
|
success(recordCount);
|
|
916
925
|
} else if (recordCount === 0) {
|
|
926
|
+
// `unboundedDisallowed` is always `true` here: this function is only reached (for
|
|
927
|
+
// non-`count` `opType`s) via `get`/`getKey`, which always pass `nullDisallowed: true`
|
|
928
|
+
// through as `unboundedDisallowed`. `getAll`/`getAllKeys`/`getAllRecords` use a
|
|
929
|
+
// different (cursor-based) code path, so the `unboundedDisallowed`-`false` case
|
|
930
|
+
// (returning `[]` here) is unreachable given current callers.
|
|
931
|
+
/* c8 ignore next -- see comment above */
|
|
917
932
|
success(unboundedDisallowed ? undefined : []);
|
|
918
933
|
} else {
|
|
934
|
+
// `unboundedDisallowed` is always `true` here; see comment above.
|
|
935
|
+
/* c8 ignore next -- see comment above */
|
|
919
936
|
success(unboundedDisallowed ? records[0] : records);
|
|
920
937
|
}
|
|
921
938
|
}, /** @type {SqlErrorCallback} */ (error));
|
package/src/IDBKeyRange.js
CHANGED
|
@@ -223,10 +223,12 @@ function setSQLForKeyRange (
|
|
|
223
223
|
sql.push(quotedKeyColumnName, (range.lowerOpen ? '>' : '>='), '?');
|
|
224
224
|
}
|
|
225
225
|
if (hasLower && hasUpper) { sql.push('AND'); }
|
|
226
|
-
if (hasUpper) {
|
|
227
|
-
|
|
228
|
-
sqlValues.push(util.escapeSQLiteStatement(/** @type {string} */ (encodedUpperKey)));
|
|
226
|
+
if (!hasUpper) {
|
|
227
|
+
return;
|
|
229
228
|
}
|
|
229
|
+
|
|
230
|
+
sql.push(quotedKeyColumnName, (range.upperOpen ? '<' : '<='), '?');
|
|
231
|
+
sqlValues.push(util.escapeSQLiteStatement(/** @type {string} */ (encodedUpperKey)));
|
|
230
232
|
}
|
|
231
233
|
|
|
232
234
|
/**
|
|
@@ -239,10 +241,9 @@ function convertValueToKeyRange (value, nullDisallowed) {
|
|
|
239
241
|
if (util.instanceOf(value, IDBKeyRange)) {
|
|
240
242
|
// We still need to validate IDBKeyRange-like objects (the above check is based on loose duck-typing)
|
|
241
243
|
const range = /** @type {IDBKeyRangeFull} */ (value);
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return range;
|
|
244
|
+
return range.toString() !== '[object IDBKeyRange]'
|
|
245
|
+
? IDBKeyRange.__createInstance(range.lower, range.upper, range.lowerOpen, range.upperOpen)
|
|
246
|
+
: range;
|
|
246
247
|
}
|
|
247
248
|
if (util.isNullish(value)) {
|
|
248
249
|
if (nullDisallowed) {
|