indexeddbshim 17.0.0 → 17.1.0
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 +62 -0
- package/badges/licenses-badge-dev.svg +1 -1
- package/badges/licenses-badge.svg +1 -1
- package/dist/CFG.d.ts +1 -0
- package/dist/CFG.d.ts.map +1 -1
- package/dist/IDBCursor.d.ts +9 -2
- package/dist/IDBCursor.d.ts.map +1 -1
- package/dist/IDBFactory.d.ts.map +1 -1
- package/dist/IDBIndex.d.ts.map +1 -1
- package/dist/IDBTransaction.d.ts +21 -0
- package/dist/IDBTransaction.d.ts.map +1 -1
- package/dist/Key.d.ts.map +1 -1
- package/dist/indexeddbshim-Key.js +25 -6
- 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 +1402 -818
- package/dist/indexeddbshim-UnicodeIdentifiers-node.cjs.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.js +467 -298
- package/dist/indexeddbshim-UnicodeIdentifiers.js.map +1 -1
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js +4 -4
- package/dist/indexeddbshim-UnicodeIdentifiers.min.js.map +1 -1
- package/dist/indexeddbshim-node.cjs +1402 -818
- package/dist/indexeddbshim-node.cjs.map +1 -1
- package/dist/indexeddbshim-noninvasive.js +467 -298
- package/dist/indexeddbshim-noninvasive.js.map +1 -1
- package/dist/indexeddbshim-noninvasive.min.js +4 -4
- package/dist/indexeddbshim-noninvasive.min.js.map +1 -1
- package/dist/indexeddbshim.js +471 -295
- package/dist/indexeddbshim.js.map +1 -1
- package/dist/indexeddbshim.min.js +4 -4
- package/dist/indexeddbshim.min.js.map +1 -1
- package/dist/node-UnicodeIdentifiers.d.ts.map +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/nodeSQLiteDatabase.d.ts +65 -0
- package/dist/nodeSQLiteDatabase.d.ts.map +1 -0
- package/dist/nodeWebSQL.d.ts.map +1 -1
- package/dist/util.d.ts +5 -0
- package/dist/util.d.ts.map +1 -1
- package/package.json +17 -13
- package/src/CFG.js +3 -0
- package/src/IDBCursor.js +136 -86
- package/src/IDBFactory.js +10 -6
- package/src/IDBIndex.js +1 -2
- package/src/IDBTransaction.js +32 -2
- package/src/Key.js +10 -2
- package/src/node-UnicodeIdentifiers.js +5 -1
- package/src/node.js +5 -1
- package/src/nodeSQLiteDatabase.js +174 -0
- package/src/nodeWebSQL.js +1 -3
- package/src/util.js +62 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-UnicodeIdentifiers.d.ts","sourceRoot":"","sources":["../src/node-UnicodeIdentifiers.js"],"names":[],"mappings":";AASA;;;;GAIG;AACH,sCAJW,OAAO,oBAAoB,EAAE,aAAa,wBAExC,OAAO,oBAAoB,EAAE,aAAa,GAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"node-UnicodeIdentifiers.d.ts","sourceRoot":"","sources":["../src/node-UnicodeIdentifiers.js"],"names":[],"mappings":";AASA;;;;GAIG;AACH,sCAJW,OAAO,oBAAoB,EAAE,aAAa,wBAExC,OAAO,oBAAoB,EAAE,aAAa,GAAC,MAAM,CAe7D"}
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.js"],"names":[],"mappings":";AAQA;;;;GAIG;AACH,sCAJW,OAAO,oBAAoB,EAAE,aAAa,wBAExC,OAAO,oBAAoB,EAAE,aAAa,GAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.js"],"names":[],"mappings":";AAQA;;;;GAIG;AACH,sCAJW,OAAO,oBAAoB,EAAE,aAAa,wBAExC,OAAO,oBAAoB,EAAE,aAAa,GAAC,MAAM,CAQ7D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export default SQLiteDatabase;
|
|
2
|
+
export type SQLProfileCallback = (sql: string, duration: number) => void;
|
|
3
|
+
export type SQLTraceCallback = ((sql: string) => void) | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {(sql: string, duration: number) => void} SQLProfileCallback
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {((sql: string) => void)|undefined} SQLTraceCallback
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} name
|
|
12
|
+
* @param {{busyTimeout?: number, trace?: (sql: string) => void, profile?: SQLProfileCallback}} [opts]
|
|
13
|
+
* @returns {void}
|
|
14
|
+
*/
|
|
15
|
+
declare function SQLiteDatabase(name: string, opts?: {
|
|
16
|
+
busyTimeout?: number;
|
|
17
|
+
trace?: (sql: string) => void;
|
|
18
|
+
profile?: SQLProfileCallback;
|
|
19
|
+
}): void;
|
|
20
|
+
declare class SQLiteDatabase {
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {(sql: string, duration: number) => void} SQLProfileCallback
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {((sql: string) => void)|undefined} SQLTraceCallback
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} name
|
|
29
|
+
* @param {{busyTimeout?: number, trace?: (sql: string) => void, profile?: SQLProfileCallback}} [opts]
|
|
30
|
+
* @returns {void}
|
|
31
|
+
*/
|
|
32
|
+
constructor(name: string, opts?: {
|
|
33
|
+
busyTimeout?: number;
|
|
34
|
+
trace?: (sql: string) => void;
|
|
35
|
+
profile?: SQLProfileCallback;
|
|
36
|
+
});
|
|
37
|
+
_db: any;
|
|
38
|
+
/**
|
|
39
|
+
* @param {{sql: string, args: unknown[]}[]} queries
|
|
40
|
+
* @param {boolean} readOnly
|
|
41
|
+
* @param {(err: Error|null, results?: SQLiteResult[]) => void} callback
|
|
42
|
+
* @returns {void}
|
|
43
|
+
*/
|
|
44
|
+
exec(queries: {
|
|
45
|
+
sql: string;
|
|
46
|
+
args: unknown[];
|
|
47
|
+
}[], readOnly: boolean, callback: (err: Error | null, results?: SQLiteResult[]) => void): void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
*/
|
|
52
|
+
declare class SQLiteResult {
|
|
53
|
+
/**
|
|
54
|
+
* @param {Error|null|undefined} error
|
|
55
|
+
* @param {number|undefined} [insertId]
|
|
56
|
+
* @param {number} [rowsAffected]
|
|
57
|
+
* @param {object[]} [rows]
|
|
58
|
+
*/
|
|
59
|
+
constructor(error: Error | null | undefined, insertId?: number | undefined, rowsAffected?: number, rows?: object[]);
|
|
60
|
+
error: Error | null | undefined;
|
|
61
|
+
insertId: number | undefined;
|
|
62
|
+
rowsAffected: number | undefined;
|
|
63
|
+
rows: object[] | undefined;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=nodeSQLiteDatabase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nodeSQLiteDatabase.d.ts","sourceRoot":"","sources":["../src/nodeSQLiteDatabase.js"],"names":[],"mappings":";iCAyBa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI;+BAIvC,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAC,SAAS;AAL9C;;GAEG;AAEH;;GAEG;AAEH;;;;GAIG;AACH,sCAJW,MAAM,SACN;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAAC,GACjF,IAAI,CAkEhB;;IA7ED;;OAEG;IAEH;;OAEG;IAEH;;;;OAIG;IACH,kBAJW,MAAM,SACN;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,OAAO,CAAC,EAAE,kBAAkB,CAAA;KAAC,EAmE7F;IA9CG,SA6CE;IAyBN;;;;;OAKG;IACH,cALW;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,EAAE,CAAA;KAAC,EAAE,YAChC,OAAO,YACP,CAAC,GAAG,EAAE,KAAK,GAAC,IAAI,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,KAAK,IAAI,GACjD,IAAI,CA0ChB;;AAzKD;;GAEG;AACH;IACI;;;;;OAKG;IACH,mBALW,KAAK,GAAC,IAAI,GAAC,SAAS,aACpB,MAAM,GAAC,SAAS,iBAChB,MAAM,SACN,MAAM,EAAE,EAOlB;IAJG,gCAAkB;IAClB,6BAAwB;IACxB,iCAAgC;IAChC,2BAAgB;CAEvB"}
|
package/dist/nodeWebSQL.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodeWebSQL.d.ts","sourceRoot":"","sources":["../src/nodeWebSQL.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"nodeWebSQL.d.ts","sourceRoot":"","sources":["../src/nodeWebSQL.js"],"names":[],"mappings":";AAsBA,iHAAiE"}
|
package/dist/util.d.ts
CHANGED
|
@@ -172,4 +172,9 @@ export function convertToSequenceDOMString(val: AnyValue): string | string[];
|
|
|
172
172
|
* @returns {v is null|undefined}
|
|
173
173
|
*/
|
|
174
174
|
export function isNullish(v: AnyValue): v is null | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* @param {() => void} fn
|
|
177
|
+
* @returns {void}
|
|
178
|
+
*/
|
|
179
|
+
export function runContinuationSafely(fn: () => void): void;
|
|
175
180
|
//# sourceMappingURL=util.d.ts.map
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.js"],"names":[],"mappings":"sBAKa,MAAM;;
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.js"],"names":[],"mappings":"sBAKa,MAAM;;uBA6fN,GAAG;AAndhB;;;;GAIG;AACH,2CAHW,MAAM,GACJ,MAAM,CASlB;AAED;;;GAGG;AACH,4CAHW,MAAM,GACJ,MAAM,CAclB;AAuBD;;;;GAIG;AACH,qDAJW,MAAM,GAEJ,MAAM,CAoClB;AAmBD;;;;GAIG;AACH,uDAHW,MAAM,GACJ,MAAM,CAkClB;AAED;;;GAGG;AACH,6CAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;GAGG;AACH,6CAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;GAGG;AACH,sDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;GAIG;AACH,mCAHW,MAAM,GACJ,MAAM,CAKlB;AAzID;;;GAGG;AACH,8BAHW,MAAM,GACJ,MAAM,CAIlB;AAqID;;GAEG;AAGH;;;;;GAKG;AACH,gCAJW,QAAQ,QACR,QAAQ,GACN,OAAO,CAInB;AAED;;;;GAIG;AACH,2BAHW,QAAQ,GACN,GAAG,IAAI,MAAM,CAIzB;AAED;;;;GAIG;AACH,4BAHW,MAAM,GACJ,OAAO,CAInB;AAED;;;;GAIG;AACH,4BAHW,MAAM,GACJ,OAAO,CAKnB;AAED;;;;GAIG;AACH,8BAHW,MAAM,GACJ,OAAO,CAKnB;AAED;;;;GAIG;AACH,4BAHW,MAAM,GACJ,OAAO,CAKnB;AAED;;;;GAIG;AACH,8BAHW,QAAQ,GACN,OAAO,CAOnB;AAED;;;;GAIG;AACH,gCAHW,QAAQ,GACN,OAAO,CAOnB;AAED;;;;;GAKG;AACH,0CAJW,MAAM,SACN,MAAM,EAAE,GACN,IAAI,CAkBhB;AAED;;;;;GAKG;AACH,kDAJW,MAAM,SACN,MAAM,EAAE,GACN,IAAI,CAchB;AAED;;;;;;;GAOG;AACH,8CANW,MAAM,GAAG;IACnB,CAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,aACO,MAAM,EAAE,GACN,IAAI,CA2BhB;AAED;;;;;;;;GAQG;AACH,8CAPW,MAAM,SACN,MAAM,GAAC,MAAM,EAAE,WACf,IAAI,GAAC;IACf,CAAK,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB,GACS,IAAI,CA8BhB;AAgCD;;;;GAIG;AACH,wCAHW,MAAM,GAAC,MAAM,EAAE,GACb,OAAO,CAWnB;AAED;;;;;GAKG;AACH,qCALW,MAAM,QACN,oBAAoB,GAAC,eAAe,GAElC,MAAM,CAyBlB;AAED;;GAEG;AAEH;;;;GAIG;AACH,sCAJW,QAAQ,gBACR,OAAO,GACL,MAAM,CAIlB;AAWD;;;;GAIG;AACH,gDAHW,QAAQ,GACN,MAAM,GAAC,MAAM,EAAE,CAW3B;AAED;;;GAGG;AACH,6BAHW,QAAQ,GACN,CAAC,IAAI,IAAI,GAAC,SAAS,CAI/B;AA6BD;;;GAGG;AACH,0CAHW,MAAM,IAAI,GACR,IAAI,CAmBhB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "indexeddbshim",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Parashuram <code@nparashuram.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -156,9 +156,11 @@
|
|
|
156
156
|
"node": "^22.18.0 || >= 24.11.0"
|
|
157
157
|
},
|
|
158
158
|
"dependencies": {
|
|
159
|
+
"@node-static/node-static": "^0.9.0",
|
|
160
|
+
"better-sqlite3": "^13.0.3",
|
|
159
161
|
"canvas": "^3.2.3",
|
|
160
162
|
"eventtargeter": "0.9.0",
|
|
161
|
-
"sync-promise-expanded": "^
|
|
163
|
+
"sync-promise-expanded": "^2.0.0",
|
|
162
164
|
"typeson": "10.0.0",
|
|
163
165
|
"typeson-registry": "13.0.0",
|
|
164
166
|
"websql-configurable": "^3.0.3"
|
|
@@ -166,7 +168,6 @@
|
|
|
166
168
|
"devDependencies": {
|
|
167
169
|
"@babel/core": "^8.0.1",
|
|
168
170
|
"@babel/preset-env": "^8.0.2",
|
|
169
|
-
"@brettz9/node-static": "^0.1.1",
|
|
170
171
|
"@es-joy/json-file-reporter": "^1.5.0",
|
|
171
172
|
"@rollup/plugin-babel": "^7.1.0",
|
|
172
173
|
"@rollup/plugin-commonjs": "^29.0.3",
|
|
@@ -174,6 +175,7 @@
|
|
|
174
175
|
"@rollup/plugin-json": "^6.1.0",
|
|
175
176
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
176
177
|
"@rollup/plugin-terser": "^1.0.0",
|
|
178
|
+
"@types/better-sqlite3": "^9.6.0",
|
|
177
179
|
"@types/node": "^26.1.2",
|
|
178
180
|
"@types/websql": "^0.0.30",
|
|
179
181
|
"@unicode/unicode-17.0.0": "^1.6.17",
|
|
@@ -185,25 +187,25 @@
|
|
|
185
187
|
"chokidar-cli": "^3.0.0",
|
|
186
188
|
"colors": "1.4.0",
|
|
187
189
|
"copyfiles": "^2.4.1",
|
|
188
|
-
"core-js-bundle": "^3.
|
|
190
|
+
"core-js-bundle": "^3.50.0",
|
|
189
191
|
"coveradge": "^0.8.2",
|
|
190
192
|
"cyclonejs": "1.1.4",
|
|
191
193
|
"delay-cli": "^3.0.0",
|
|
192
194
|
"eslint": "^10.8.0",
|
|
193
|
-
"eslint-config-ash-nazg": "^
|
|
194
|
-
"globals": "^17.
|
|
195
|
+
"eslint-config-ash-nazg": "^42.1.1",
|
|
196
|
+
"globals": "^17.9.0",
|
|
195
197
|
"is-date-object": "1.1.0",
|
|
196
198
|
"isomorphic-fetch": "^3.0.0",
|
|
197
|
-
"jsdom": "^30.0.
|
|
198
|
-
"license-badger": "^0.
|
|
199
|
+
"jsdom": "^30.0.1",
|
|
200
|
+
"license-badger": "^0.23.0",
|
|
199
201
|
"local-xmlhttprequest": "2.0.0",
|
|
200
|
-
"mocha": "^11.
|
|
202
|
+
"mocha": "^11.8.0",
|
|
201
203
|
"mocha-badge-generator": "^0.11.0",
|
|
202
204
|
"mocha-multi-reporters": "^1.5.1",
|
|
203
205
|
"npm-run-all": "^4.1.5",
|
|
204
206
|
"open-cli": "^9.0.0",
|
|
205
207
|
"rimraf": "^6.1.3",
|
|
206
|
-
"rollup": "^4.62.
|
|
208
|
+
"rollup": "^4.62.4",
|
|
207
209
|
"rollup-plugin-filesize": "^10.0.0",
|
|
208
210
|
"rollup-plugin-node-polyfills": "^0.2.1",
|
|
209
211
|
"sinon": "^22.1.0",
|
|
@@ -211,14 +213,16 @@
|
|
|
211
213
|
"sourcemap-transformer": "git+https://github.com/brettz9/sourcemap-transformer.git",
|
|
212
214
|
"typescript": "^6.0.3",
|
|
213
215
|
"w3c-blob": "0.0.1",
|
|
214
|
-
"ws": "^8.21.
|
|
216
|
+
"ws": "^8.21.2"
|
|
215
217
|
},
|
|
216
218
|
"allowScripts": {
|
|
217
219
|
"es5-ext@0.10.64": true,
|
|
218
220
|
"fsevents@2.3.3": true,
|
|
219
221
|
"sqlite3@5.1.7": true,
|
|
220
222
|
"canvas@3.2.3": true,
|
|
221
|
-
"
|
|
222
|
-
"
|
|
223
|
+
"unrs-resolver@1.12.2": true,
|
|
224
|
+
"better-sqlite3@13.0.3": true,
|
|
225
|
+
"core-js-bundle@3.50.0": true,
|
|
226
|
+
"is-hidden-file@1.1.2": true
|
|
223
227
|
}
|
|
224
228
|
}
|
package/src/CFG.js
CHANGED
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
* sqlBusyTimeout: number,
|
|
43
43
|
* sqlTrace: () => void,
|
|
44
44
|
* sqlProfile: () => void,
|
|
45
|
+
* escapeNULForSQLiteStatements: boolean,
|
|
45
46
|
* createIndexes: boolean
|
|
46
47
|
* }} ConfigValues
|
|
47
48
|
*/
|
|
@@ -215,6 +216,8 @@ const CFG = /** @type {ConfigValues} */ ({});
|
|
|
215
216
|
'sqlBusyTimeout', // Defaults to 1000
|
|
216
217
|
'sqlTrace', // Callback not used by default
|
|
217
218
|
'sqlProfile', // Callback not used by default
|
|
219
|
+
// Defaults to true except in Node builds where we can preserve literal NUL with better-sqlite3
|
|
220
|
+
'escapeNULForSQLiteStatements',
|
|
218
221
|
|
|
219
222
|
'createIndexes'
|
|
220
223
|
]).forEach((prop) => {
|
package/src/IDBCursor.js
CHANGED
|
@@ -46,6 +46,9 @@ import CFG from './CFG.js';
|
|
|
46
46
|
* __unique: boolean,
|
|
47
47
|
* __sqlDirection: "DESC"|"ASC",
|
|
48
48
|
* __matchedKeys: {[key: string]: true},
|
|
49
|
+
* __continuationKey: import('./Key.js').Key|undefined,
|
|
50
|
+
* __continuationPrimaryKey: import('./Key.js').Key|undefined,
|
|
51
|
+
* __multiEntryExhausted: boolean,
|
|
49
52
|
* __invalidateCache: () => void
|
|
50
53
|
* }} IDBCursorFull
|
|
51
54
|
*/
|
|
@@ -117,6 +120,9 @@ IDBCursor.__super = function IDBCursor (query, direction, store, source, keyColu
|
|
|
117
120
|
this.__valueDecoder = this.__keyOnly ? Key : Sca;
|
|
118
121
|
this.__count = count;
|
|
119
122
|
this.__prefetchedIndex = -1;
|
|
123
|
+
this.__continuationKey = undefined;
|
|
124
|
+
this.__continuationPrimaryKey = undefined;
|
|
125
|
+
this.__multiEntryExhausted = false;
|
|
120
126
|
this.__multiEntryIndex = this.__indexSource
|
|
121
127
|
? 'multiEntry' in source && source.multiEntry
|
|
122
128
|
: false;
|
|
@@ -270,77 +276,107 @@ const leftBracketRegex = /\[/gu;
|
|
|
270
276
|
* @param {SQLTransaction} tx
|
|
271
277
|
* @param {KeySuccess} success
|
|
272
278
|
* @param {FindError} error
|
|
273
|
-
* @param {Integer
|
|
279
|
+
* @param {Integer} [recordsToLoad]
|
|
274
280
|
* @this {IDBCursorFull}
|
|
275
281
|
* @returns {void}
|
|
276
282
|
*/
|
|
277
|
-
IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, error, recordsToLoad) {
|
|
283
|
+
IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, error, recordsToLoad = 1) {
|
|
278
284
|
const me = this;
|
|
279
285
|
|
|
280
|
-
if (me.
|
|
281
|
-
if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
|
|
286
|
+
if (me.__multiEntryExhausted) {
|
|
287
|
+
if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (already exhausted)'); }
|
|
282
288
|
success(undefined, undefined, undefined);
|
|
283
289
|
return;
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
const quotedKeyColumnName = util.sqlQuote(me.__keyColumnName);
|
|
287
|
-
const
|
|
288
|
-
/** @type {string[]} */
|
|
289
|
-
const sqlValues = [];
|
|
290
|
-
sql.push('WHERE', quotedKeyColumnName, 'NOT NULL');
|
|
291
|
-
if (me.__range && (me.__range.lower !== undefined && Array.isArray(me.__range.upper))) {
|
|
292
|
-
if (me.__range.upper.indexOf(me.__range.lower) === 0) {
|
|
293
|
-
sql.push('AND', quotedKeyColumnName, "LIKE ? ESCAPE '^'");
|
|
294
|
-
sqlValues.push(
|
|
295
|
-
'%' + util.sqlLIKEEscape(
|
|
296
|
-
/** @type {string} */ (me.__range.__lowerCached).slice(0, -1)
|
|
297
|
-
) + '%'
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
293
|
+
const quotedKey = util.sqlQuote('key');
|
|
301
294
|
|
|
302
295
|
// Determine the ORDER BY direction based on the cursor.
|
|
303
296
|
const direction = me.__sqlDirection;
|
|
304
297
|
const op = direction === 'ASC' ? '>' : '<';
|
|
305
|
-
const quotedKey = util.sqlQuote('key');
|
|
306
|
-
|
|
307
|
-
if (primaryKey !== undefined) {
|
|
308
|
-
sql.push('AND', quotedKey, op + '= ?');
|
|
309
|
-
// Key.convertValueToKey(primaryKey); // Already checked by `continuePrimaryKey`
|
|
310
|
-
sqlValues.push(/** @type {string} */ (Key.encode(primaryKey)));
|
|
311
|
-
}
|
|
312
|
-
if (key !== undefined) {
|
|
313
|
-
sql.push('AND', quotedKeyColumnName, op + '= ?');
|
|
314
|
-
// Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
|
|
315
|
-
sqlValues.push(/** @type {string} */ (Key.encode(key)));
|
|
316
|
-
} else if (me.__key !== undefined) {
|
|
317
|
-
sql.push('AND', quotedKeyColumnName, op + ' ?');
|
|
318
|
-
// Key.convertValueToKey(me.__key); // Already checked when entered
|
|
319
|
-
sqlValues.push(/** @type {string} */ (Key.encode(me.__key)));
|
|
320
|
-
}
|
|
321
298
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Runs (and, if a batch of underlying rows produces no matching
|
|
301
|
+
* multi-entry values, repeatedly re-runs) the query for the next batch
|
|
302
|
+
* of underlying rows, advancing `me.__continuationKey`/
|
|
303
|
+
* `me.__continuationPrimaryKey` (tracking the last *physical* row
|
|
304
|
+
* scanned) each time, until either some matches are found or the
|
|
305
|
+
* underlying table is exhausted.
|
|
306
|
+
* @returns {void}
|
|
307
|
+
*/
|
|
308
|
+
function runQuery () {
|
|
309
|
+
const sql = ['SELECT * FROM', util.escapeStoreNameForSQL(me.__store.__currentName)];
|
|
310
|
+
/** @type {string[]} */
|
|
311
|
+
const sqlValues = [];
|
|
312
|
+
sql.push('WHERE', quotedKeyColumnName, 'NOT NULL');
|
|
313
|
+
if (me.__range && (me.__range.lower !== undefined && Array.isArray(me.__range.upper))) {
|
|
314
|
+
if (me.__range.upper.indexOf(me.__range.lower) === 0) {
|
|
315
|
+
sql.push('AND', quotedKeyColumnName, "LIKE ? ESCAPE '^'");
|
|
316
|
+
sqlValues.push(
|
|
317
|
+
'%' + util.sqlLIKEEscape(
|
|
318
|
+
/** @type {string} */ (me.__range.__lowerCached).slice(0, -1)
|
|
319
|
+
) + '%'
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
325
323
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
if (primaryKey !== undefined) {
|
|
325
|
+
sql.push('AND', quotedKey, op + '= ?');
|
|
326
|
+
// Key.convertValueToKey(primaryKey); // Already checked by `continuePrimaryKey`
|
|
327
|
+
sqlValues.push(/** @type {string} */ (Key.encode(primaryKey)));
|
|
328
|
+
}
|
|
329
|
+
if (key !== undefined) {
|
|
330
|
+
sql.push('AND', quotedKeyColumnName, op + '= ?');
|
|
331
|
+
// Key.convertValueToKey(key); // Already checked by `continue` or `continuePrimaryKey`
|
|
332
|
+
sqlValues.push(/** @type {string} */ (Key.encode(key)));
|
|
333
|
+
} else if (me.__continuationKey !== undefined) {
|
|
334
|
+
// Resume from the last underlying (physical) row we scanned, not
|
|
335
|
+
// from the last *matching* multi-entry value (which lives in a
|
|
336
|
+
// different key-space than the raw index column and cannot be
|
|
337
|
+
// reliably compared against it, e.g. for array index keys).
|
|
338
|
+
sql.push(
|
|
339
|
+
'AND (', quotedKeyColumnName, op, '?',
|
|
340
|
+
'OR (', quotedKeyColumnName, '= ?', 'AND', quotedKey, op, '?))'
|
|
341
|
+
);
|
|
342
|
+
const encodedContinuationKey = /** @type {string} */ (
|
|
343
|
+
Key.encode(me.__continuationKey, true)
|
|
344
|
+
);
|
|
345
|
+
sqlValues.push(
|
|
346
|
+
encodedContinuationKey,
|
|
347
|
+
encodedContinuationKey,
|
|
348
|
+
/** @type {string} */ (Key.encode(me.__continuationPrimaryKey))
|
|
349
|
+
);
|
|
329
350
|
}
|
|
330
351
|
|
|
331
|
-
|
|
352
|
+
if (!me.__count) {
|
|
353
|
+
// 1. Sort by key
|
|
354
|
+
sql.push('ORDER BY', quotedKeyColumnName, direction);
|
|
332
355
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
356
|
+
// 2. Sort by primaryKey (if defined and not unique)
|
|
357
|
+
if (!me.__unique && me.__keyColumnName !== 'key') { // Avoid adding 'key' twice
|
|
358
|
+
sql.push(',', util.sqlQuote('key'), direction);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// 3. Sort by position (if defined)
|
|
362
|
+
|
|
363
|
+
if (!me.__unique && me.__indexSource) {
|
|
364
|
+
// 4. Sort by object store position (if defined and not unique)
|
|
365
|
+
sql.push(',', util.sqlQuote(me.__valueColumnName), direction);
|
|
366
|
+
}
|
|
367
|
+
sql.push('LIMIT', String(recordsToLoad));
|
|
336
368
|
}
|
|
337
|
-
sql.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
369
|
+
const sqlStr = sql.join(' ');
|
|
370
|
+
if (CFG.DEBUG) { console.log('[multiEntry] query', sqlStr, sqlValues); }
|
|
371
|
+
|
|
372
|
+
tx.executeSql(sqlStr, sqlValues, function (tx, data) {
|
|
373
|
+
if (data.rows.length === 0) {
|
|
374
|
+
me.__multiEntryExhausted = true;
|
|
375
|
+
if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (no more rows)'); }
|
|
376
|
+
success(undefined, undefined, undefined);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
341
379
|
|
|
342
|
-
tx.executeSql(sqlStr, sqlValues, function (tx, data) {
|
|
343
|
-
if (data.rows.length > 0) {
|
|
344
380
|
if (me.__count) { // Avoid caching and other processing below
|
|
345
381
|
let ct = 0;
|
|
346
382
|
for (let i = 0; i < data.rows.length; i++) {
|
|
@@ -352,6 +388,17 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
352
388
|
success(undefined, ct, undefined);
|
|
353
389
|
return;
|
|
354
390
|
}
|
|
391
|
+
|
|
392
|
+
// Track how far we've physically scanned, regardless of whether
|
|
393
|
+
// this batch produced any matches, so the next batch (if any)
|
|
394
|
+
// resumes after this one instead of re-scanning or stopping early.
|
|
395
|
+
const lastRawRow = data.rows.item(data.rows.length - 1);
|
|
396
|
+
me.__continuationKey = Key.decode(lastRawRow[me.__keyColumnName], true);
|
|
397
|
+
me.__continuationPrimaryKey = Key.decode(lastRawRow.key);
|
|
398
|
+
if (data.rows.length < recordsToLoad) {
|
|
399
|
+
me.__multiEntryExhausted = true;
|
|
400
|
+
}
|
|
401
|
+
|
|
355
402
|
const rows = [];
|
|
356
403
|
for (let i = 0; i < data.rows.length; i++) {
|
|
357
404
|
const rowItem = data.rows.item(i);
|
|
@@ -373,6 +420,18 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
373
420
|
rows.push(clone);
|
|
374
421
|
}
|
|
375
422
|
}
|
|
423
|
+
|
|
424
|
+
if (rows.length === 0) {
|
|
425
|
+
if (me.__multiEntryExhausted) {
|
|
426
|
+
if (CFG.DEBUG) { console.log('[multiEntry] Reached end of multiEntry cursor (last batch had no matches)'); }
|
|
427
|
+
success(undefined, undefined, undefined);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
if (CFG.DEBUG) { console.log('[multiEntry] batch had no matches; fetching next batch'); }
|
|
431
|
+
runQuery();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
376
435
|
const reverse = me.direction.indexOf('prev') === 0;
|
|
377
436
|
rows.sort(function (a, b) {
|
|
378
437
|
if (a.matchingKey.replaceAll(leftBracketRegex, 'z') < b.matchingKey.replaceAll(leftBracketRegex, 'z')) {
|
|
@@ -390,37 +449,28 @@ IDBCursor.prototype.__findMultiEntry = function (key, primaryKey, tx, success, e
|
|
|
390
449
|
return 0;
|
|
391
450
|
});
|
|
392
451
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
} else {
|
|
416
|
-
if (CFG.DEBUG) { console.log('Reached end of multiEntry cursor'); }
|
|
417
|
-
success(undefined, undefined, undefined);
|
|
418
|
-
}
|
|
419
|
-
}, function (tx, err) {
|
|
420
|
-
if (CFG.DEBUG) { console.log('Could not execute Cursor.continue', sqlStr, sqlValues); }
|
|
421
|
-
error(err);
|
|
422
|
-
return false;
|
|
423
|
-
});
|
|
452
|
+
me.__prefetchedIndex = 0;
|
|
453
|
+
me.__prefetchedData = {
|
|
454
|
+
data: rows,
|
|
455
|
+
length: rows.length,
|
|
456
|
+
/**
|
|
457
|
+
* @param {Integer} index
|
|
458
|
+
* @returns {RowItemNonNull}
|
|
459
|
+
*/
|
|
460
|
+
item (index) {
|
|
461
|
+
return this.data[index];
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
if (CFG.DEBUG) { console.log('[multiEntry] Preloaded ' + me.__prefetchedData.length + ' records for multiEntry cursor'); }
|
|
465
|
+
me.__decode(rows[0], success);
|
|
466
|
+
}, function (tx, err) {
|
|
467
|
+
if (CFG.DEBUG) { console.log('[multiEntry] Could not execute Cursor.continue', sqlStr, sqlValues); }
|
|
468
|
+
error(err);
|
|
469
|
+
return false;
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
runQuery();
|
|
424
474
|
};
|
|
425
475
|
|
|
426
476
|
/**
|
|
@@ -540,6 +590,7 @@ IDBCursor.prototype.__sourceOrEffectiveObjStoreDeleted = function () {
|
|
|
540
590
|
IDBCursor.prototype.__invalidateCache = function () {
|
|
541
591
|
// @ts-expect-error Why is this not being found?
|
|
542
592
|
this.__prefetchedData = null;
|
|
593
|
+
this.__multiEntryExhausted = false;
|
|
543
594
|
};
|
|
544
595
|
|
|
545
596
|
/**
|
|
@@ -599,9 +650,8 @@ IDBCursor.prototype.__continueFinish = function (key, primaryKey, advanceState)
|
|
|
599
650
|
me.__advanceCount--;
|
|
600
651
|
me.__key = k;
|
|
601
652
|
me.__continue(undefined, true);
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
)(); // We don't call success yet but do need to advance the transaction queue
|
|
653
|
+
// We don't call success yet but do need to advance the transaction queue
|
|
654
|
+
util.runContinuationSafely(/** @type {() => void} */ (executeNextRequest));
|
|
605
655
|
return;
|
|
606
656
|
}
|
|
607
657
|
me.__advanceCount = undefined;
|
|
@@ -627,12 +677,12 @@ IDBCursor.prototype.__continueFinish = function (key, primaryKey, advanceState)
|
|
|
627
677
|
return;
|
|
628
678
|
}
|
|
629
679
|
// @ts-expect-error Todo: Our bug to fix
|
|
630
|
-
cursorContinue(tx, args, success, error);
|
|
680
|
+
util.runContinuationSafely(() => cursorContinue(tx, args, success, error));
|
|
631
681
|
}
|
|
632
682
|
if (me.__unique && !me.__multiEntryIndex &&
|
|
633
683
|
encKey === Key.encode(me.key, me.__multiEntryIndex)) {
|
|
634
684
|
// @ts-expect-error Todo: Our bug to fix
|
|
635
|
-
cursorContinue(tx, args, success, error);
|
|
685
|
+
util.runContinuationSafely(() => cursorContinue(tx, args, success, error));
|
|
636
686
|
return;
|
|
637
687
|
}
|
|
638
688
|
checkKey();
|
package/src/IDBFactory.js
CHANGED
|
@@ -593,7 +593,7 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
593
593
|
req.__result
|
|
594
594
|
).__versionTransaction = null;
|
|
595
595
|
sysdbFinishedCb(systx, false, function () {
|
|
596
|
-
req.transaction.
|
|
596
|
+
req.transaction.__callTransFinishedCb(false, function () {
|
|
597
597
|
ev.complete();
|
|
598
598
|
req.__transaction = null;
|
|
599
599
|
});
|
|
@@ -716,6 +716,13 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
716
716
|
function openDB (oldVersion) {
|
|
717
717
|
/** @type {DatabaseFull} */
|
|
718
718
|
let db;
|
|
719
|
+
if (version === undefined) {
|
|
720
|
+
// Resolve before use as a cache key below, or a `open(name)` call
|
|
721
|
+
// (no explicit version) would cache/look up under `undefined`
|
|
722
|
+
// instead of the actual version, causing a second, separate
|
|
723
|
+
// connection to be opened for the same database on reopen.
|
|
724
|
+
version = oldVersion || 1;
|
|
725
|
+
}
|
|
719
726
|
if ((useMemoryDatabase || useDatabaseCache) && Object.hasOwn(websqlDBCache, name) && Object.hasOwn(websqlDBCache[name], version)) {
|
|
720
727
|
db = websqlDBCache[name][version];
|
|
721
728
|
} else {
|
|
@@ -733,9 +740,6 @@ IDBFactory.prototype.open = function (name /* , version */) {
|
|
|
733
740
|
}
|
|
734
741
|
}
|
|
735
742
|
|
|
736
|
-
if (version === undefined) {
|
|
737
|
-
version = oldVersion || 1;
|
|
738
|
-
}
|
|
739
743
|
if (oldVersion > version) {
|
|
740
744
|
const err = createDOMException('VersionError', 'An attempt was made to open a database using a lower version than the existing version.', version);
|
|
741
745
|
if (useDatabaseCache) {
|
|
@@ -905,7 +909,7 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
905
909
|
({version} = data.rows.item(0));
|
|
906
910
|
|
|
907
911
|
const openConnections = me.__connections[name] || [];
|
|
908
|
-
triggerAnyVersionChangeAndBlockedEvents(openConnections, req, version, null).then(function () {
|
|
912
|
+
triggerAnyVersionChangeAndBlockedEvents(openConnections, req, version, null).then(function () {
|
|
909
913
|
// Since we need two databases which can't be in a single transaction, we
|
|
910
914
|
// do this deleting from `dbVersions` first since the `__sys__` deleting
|
|
911
915
|
// only impacts file memory whereas this one is critical for avoiding it
|
|
@@ -934,7 +938,7 @@ IDBFactory.prototype.deleteDatabase = function (name) {
|
|
|
934
938
|
});
|
|
935
939
|
return undefined;
|
|
936
940
|
// @ts-expect-error It's ok
|
|
937
|
-
}
|
|
941
|
+
}).catch(dbError);
|
|
938
942
|
return undefined;
|
|
939
943
|
}, dbError);
|
|
940
944
|
});
|
package/src/IDBIndex.js
CHANGED
|
@@ -733,8 +733,7 @@ IDBIndex.prototype.__renameIndex = function (store, oldName, newName, colInfoToP
|
|
|
733
733
|
);
|
|
734
734
|
})
|
|
735
735
|
);
|
|
736
|
-
SyncPromise.all(indexCreations).then(
|
|
737
|
-
finish,
|
|
736
|
+
SyncPromise.all(indexCreations).then(finish).catch(
|
|
738
737
|
/** @type {(reason: any) => PromiseLike<never>} */
|
|
739
738
|
(error)
|
|
740
739
|
).catch((err) => {
|
package/src/IDBTransaction.js
CHANGED
|
@@ -50,6 +50,7 @@ const readonlyProperties = ['objectStoreNames', 'mode', 'db', 'error'];
|
|
|
50
50
|
* },
|
|
51
51
|
* __requestsFinished: boolean,
|
|
52
52
|
* __transFinishedCb: (err: boolean, cb: ((bool?: boolean) => void)) => void,
|
|
53
|
+
* __callTransFinishedCb: (err: boolean, cb: ((bool?: boolean) => void)) => void,
|
|
53
54
|
* __transactionEndCallback: () => void,
|
|
54
55
|
* __transactionFinished: boolean,
|
|
55
56
|
* __completed: boolean,
|
|
@@ -157,6 +158,35 @@ IDBTransaction.prototype = EventTargetFactory.createInstance({
|
|
|
157
158
|
IDBTransaction.prototype.__transFinishedCb = function (err, cb) {
|
|
158
159
|
cb(Boolean(err));
|
|
159
160
|
};
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* In Node, the real (SQL-commit-capable) `__transFinishedCb` is only
|
|
164
|
+
* installed once the underlying WebSQL driver's own SQL-queue-idle check
|
|
165
|
+
* has fired at least once for this transaction (asynchronously, via the
|
|
166
|
+
* `nonstandardTransCb` passed to `db.transaction`/`.readTransaction`).
|
|
167
|
+
* Since our own request processing can now finish synchronously (e.g., a
|
|
168
|
+
* trivial upgrade using a synchronous SQL driver), it is possible to reach
|
|
169
|
+
* transaction completion here before that has happened, in which case
|
|
170
|
+
* `__transFinishedCb` is still the non-committing default above. Calling
|
|
171
|
+
* that default directly would silently skip the actual SQL commit and
|
|
172
|
+
* leave the underlying WebSQL transaction "running" forever, hanging any
|
|
173
|
+
* later transaction on that same database connection. So, if the real
|
|
174
|
+
* callback isn't installed yet, defer and retry until it is.
|
|
175
|
+
* @this {IDBTransactionFull}
|
|
176
|
+
* @param {boolean} err
|
|
177
|
+
* @param {(bool?: boolean) => void} cb
|
|
178
|
+
* @returns {void}
|
|
179
|
+
*/
|
|
180
|
+
IDBTransaction.prototype.__callTransFinishedCb = function (err, cb) {
|
|
181
|
+
const me = this;
|
|
182
|
+
if (me.__transFinishedCb === IDBTransaction.prototype.__transFinishedCb) {
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
me.__callTransFinishedCb(err, cb);
|
|
185
|
+
}, 0);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
me.__transFinishedCb(err, cb);
|
|
189
|
+
};
|
|
160
190
|
/**
|
|
161
191
|
* @this {IDBTransactionFull}
|
|
162
192
|
* @returns {void}
|
|
@@ -214,7 +244,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
214
244
|
me.__abortTransaction(createDOMException('AbortError', 'A request was aborted (in user handler after success).'));
|
|
215
245
|
return;
|
|
216
246
|
}
|
|
217
|
-
executeNextRequest
|
|
247
|
+
util.runContinuationSafely(executeNextRequest);
|
|
218
248
|
}
|
|
219
249
|
|
|
220
250
|
/**
|
|
@@ -282,7 +312,7 @@ IDBTransaction.prototype.__executeRequests = function () {
|
|
|
282
312
|
try {
|
|
283
313
|
q = me.__requests[i];
|
|
284
314
|
if (!q.req) {
|
|
285
|
-
q.op(tx, q.args, executeNextRequest, error);
|
|
315
|
+
q.op(tx, q.args, () => util.runContinuationSafely(executeNextRequest), error);
|
|
286
316
|
return;
|
|
287
317
|
}
|
|
288
318
|
if (q.req.__done) { // Avoid continuing with aborted requests
|