jsql-neo 5.4.2 → 5.5.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.
Files changed (72) hide show
  1. package/LICENSE +202 -202
  2. package/README.md +8097 -7971
  3. package/bin/jsql +320 -320
  4. package/bin/jsql-server +90 -90
  5. package/bin/jsql-server-control.js +177 -177
  6. package/index.d.ts +385 -357
  7. package/index.js +124 -118
  8. package/lib/ast.js +214 -0
  9. package/lib/btree.js +413 -413
  10. package/lib/cache.js +328 -328
  11. package/lib/client.js +125 -125
  12. package/lib/database.js +1744 -1744
  13. package/lib/date-types.js +182 -182
  14. package/lib/errors.js +89 -89
  15. package/lib/jsql_format.js +497 -497
  16. package/lib/migrate.js +254 -254
  17. package/lib/mod.js +292 -292
  18. package/lib/mongo_server.js +607 -607
  19. package/lib/multiserver.js +140 -140
  20. package/lib/mysql_compat.js +413 -413
  21. package/lib/mysql_server.js +1237 -1237
  22. package/lib/native_client.js +732 -732
  23. package/lib/nedb_compat.js +506 -506
  24. package/lib/pg_server.js +864 -864
  25. package/lib/plugin.js +34 -34
  26. package/lib/query.js +815 -815
  27. package/lib/redis_server.js +571 -571
  28. package/lib/sql.js +3460 -2925
  29. package/lib/sqlite_compat.js +323 -323
  30. package/lib/sqlite_worker.js +264 -264
  31. package/lib/table.js +1304 -1304
  32. package/lib/tui.js +502 -502
  33. package/lib/wasm.js +1 -1
  34. package/lib/wasm_client.js +718 -718
  35. package/lib/web_ui.js +257 -257
  36. package/native/jsql-neo-native.node +0 -0
  37. package/nativesrc/jsql-neo-core/Cargo.lock +455 -455
  38. package/nativesrc/jsql-neo-core/Cargo.toml +24 -24
  39. package/nativesrc/jsql-neo-core/src/engine/hybrid.rs +455 -455
  40. package/nativesrc/jsql-neo-core/src/engine/memory.rs +168 -168
  41. package/nativesrc/jsql-neo-core/src/engine/mod.rs +62 -62
  42. package/nativesrc/jsql-neo-core/src/engine/table.rs +700 -700
  43. package/nativesrc/jsql-neo-core/src/lib.rs +2 -2
  44. package/nativesrc/jsql-neo-core/src/storage/mod.rs +2 -2
  45. package/nativesrc/jsql-neo-core/src/storage/persistent.rs +1 -1
  46. package/nativesrc/jsql-neo-core/src/storage/wal.rs +85 -85
  47. package/nativesrc/jsql-neo-core/src/types.rs +93 -93
  48. package/nativesrc/jsql-neo-native/Cargo.lock +606 -606
  49. package/nativesrc/jsql-neo-native/Cargo.toml +16 -16
  50. package/nativesrc/jsql-neo-native/build.rs +3 -3
  51. package/nativesrc/jsql-neo-native/package.json +7 -7
  52. package/nativesrc/jsql-neo-native/src/lib.rs +269 -269
  53. package/nativesrc/jsql-neo-wasm/Cargo.lock +465 -465
  54. package/nativesrc/jsql-neo-wasm/Cargo.toml +15 -15
  55. package/nativesrc/jsql-neo-wasm/src/lib.rs +447 -447
  56. package/package.json +87 -86
  57. package/postinstall.js +158 -158
  58. package/test/btree.test.js +128 -128
  59. package/test/coverage.js +187 -187
  60. package/test/join.test.js +110 -110
  61. package/test/native.test.js +158 -158
  62. package/test/regress-5.1.0.js +271 -271
  63. package/test/smoke.js +58 -58
  64. package/test/sql-parser.test.js +273 -0
  65. package/test/wasm.test.js +110 -110
  66. package/wasm/browser.d.ts +89 -89
  67. package/wasm/browser.mjs +569 -569
  68. package/wasm/browser_bg.mjs +597 -597
  69. package/wasm/jsql_neo_wasm.d.ts +38 -38
  70. package/wasm/jsql_neo_wasm.js +520 -520
  71. package/wasm/jsql_neo_wasm_bg.wasm.d.ts +26 -26
  72. package/wasm/package.json +11 -11
@@ -1,264 +1,264 @@
1
- // © Vexify 2026 All Rights Reserved.
2
- /**
3
- * better-sqlite3 兼容层 — worker 线程
4
- * 在 worker 中持有一个持久 Database,主线程通过 postMessage + Atomics 同步桥调用。
5
- */
6
-
7
- const { workerData } = require('worker_threads');
8
- const Database = require('./database');
9
- const { executeSQL, parseSQL, applyParams } = require('./sql');
10
-
11
- const PARENT = require('worker_threads').parentPort;
12
- const PORT = workerData.port || PARENT;
13
- let db = null;
14
- let sab = null;
15
- let ctrl = null;
16
- const userFunctions = {};
17
- const userAggregates = {};
18
-
19
- function startEngine(filename, options) {
20
- const opts = options || {};
21
- const isMemory = filename === ':memory:' || !filename;
22
- if (opts.engine === 'native') {
23
- const { JSQL: NativeJSQL } = require('./native_client');
24
- const engine = new NativeJSQL({ mode: 'memory' });
25
- db = {
26
- start: async () => { await engine.start(); },
27
- stop: async () => { await engine.stop(); },
28
- hasTable: name => engine._tableNames.has(name),
29
- createTable: (n, s) => engine.createTable(n, s),
30
- dropTable: n => engine.dropTable(n),
31
- insert: (n, rows) => engine.insert(n, rows),
32
- find: (n, f, o) => engine.find(n, f, o),
33
- updateById: (n, id, data) => engine.updateById(n, id, data),
34
- updateByIds: (n, e) => engine.updateByIds(n, e),
35
- removeByIds: (n, ids) => engine.removeByIds(n, ids),
36
- count: (n, f) => engine.count ? engine.count(n, f) : engine.find(n, f || {}, {}).then(rs => rs.length),
37
- getTableSchema: n => engine._schemas[n] || null,
38
- beginTx: () => engine.beginTx(),
39
- commitTx: id => engine.commitTx(id),
40
- rollbackTx: id => engine.rollbackTx(id),
41
- truncate: async () => { throw new Error('truncate not supported on native engine'); },
42
- flush: async () => { if (engine.flush) await engine.flush(); },
43
- listTables: () => Array.from(engine._tableNames || []),
44
- _schemas: engine._schemas,
45
- };
46
- return db;
47
- }
48
- // 纯 JS 引擎
49
- db = new Database(isMemory ? ':memory:' : filename, opts.mode === 'hybrid' ? { mode: 'hybrid' } : {});
50
- return db;
51
- }
52
-
53
- function toRows(result) {
54
- // 把 executeSQL 的 select 结果转成 better-sqlite3 风格的对象行数组
55
- if (result && result.type === 'select' && Array.isArray(result.rows)) {
56
- const cols = Array.isArray(result.columns) ? result.columns : [];
57
- return result.rows.map(r => {
58
- const o = {};
59
- for (let i = 0; i < cols.length; i++) o[cols[i]] = r[i];
60
- return o;
61
- });
62
- }
63
- if (result && result.type === 'pragma' && result.value !== undefined) {
64
- return result.value;
65
- }
66
- return undefined;
67
- }
68
-
69
- let _lastInsertId = 0;
70
-
71
- async function executeStatement(sql, params) {
72
- if (params && typeof params === 'object' && !Array.isArray(params)) {
73
- sql = applyParams(sql, params);
74
- params = null;
75
- }
76
- const result = await executeSQL(db, sql, params, {
77
- session: {
78
- get lastInsertId() { return _lastInsertId; },
79
- set lastInsertId(v) { _lastInsertId = Number(v); },
80
- },
81
- functions: userFunctions,
82
- aggregates: userAggregates,
83
- });
84
- if (result && result.type === 'insert' && result.insertId !== null && result.insertId !== undefined) {
85
- _lastInsertId = Number(result.insertId);
86
- }
87
- return result;
88
- }
89
-
90
- function cleanResult(r) {
91
- if (!r || typeof r !== 'object') return r;
92
- if (Array.isArray(r)) return r.map(cleanResult);
93
- if (Buffer.isBuffer(r) || r instanceof Uint8Array || r instanceof ArrayBuffer || ArrayBuffer.isView(r)) return r;
94
- const out = {};
95
- for (const [k, v] of Object.entries(r)) {
96
- if (k === 'result' || k === 'engine') continue;
97
- if (v instanceof Date) out[k] = v.toISOString();
98
- else if (v === undefined) out[k] = null;
99
- else if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
100
- // 仅保留可 JSON 化的值(防止 Table/内部对象循环引用)
101
- try { JSON.stringify(v); out[k] = v; } catch (e) { out[k] = null; }
102
- } else out[k] = v;
103
- }
104
- return out;
105
- }
106
-
107
- async function handleOp(op, args) {
108
- let result;
109
- switch (op) {
110
- case 'start': {
111
- await startEngine(args[0], args[1]).start();
112
- result = { ok: true };
113
- break;
114
- }
115
- case 'close': {
116
- if (db && typeof db.stop === 'function') await db.stop();
117
- result = { ok: true };
118
- break;
119
- }
120
- case 'exec': {
121
- result = await executeStatement(args[0], args[1]);
122
- break;
123
- }
124
- case 'run': {
125
- const r = await executeStatement(args[0], args[1]);
126
- result = {
127
- changes: r ? (r.affectedRows || 0) : 0,
128
- lastInsertRowid: r && r.type === 'insert' ? Number(r.insertId || 0) : _lastInsertId,
129
- };
130
- break;
131
- }
132
- case 'get': {
133
- const r = await executeStatement(args[0], args[1]);
134
- const rows = toRows(r);
135
- result = Array.isArray(rows) ? (rows.length > 0 ? rows[0] : undefined) : rows;
136
- break;
137
- }
138
- case 'all': {
139
- const r = await executeStatement(args[0], args[1]);
140
- const rows = toRows(r);
141
- result = rows === undefined || rows === null ? [] : rows;
142
- break;
143
- }
144
- case 'raw': {
145
- const r = await executeStatement(args[0], args[1]);
146
- let rows = r && r.type === 'select' ? (r.rows || []) : (toRows(r) || []);
147
- const cols = r && Array.isArray(r.columns) ? r.columns : (rows.length > 0 ? Object.keys(rows[0]) : []);
148
- if (Array.isArray(rows) && rows.length > 0 && typeof rows[0] === 'object' && !Array.isArray(rows[0])) {
149
- rows = rows.map(row => cols.map(c => row[c]));
150
- }
151
- result = rows;
152
- break;
153
- }
154
- case 'columns': {
155
- const r = await executeStatement(args[0], args[1]);
156
- const cols = r && r.type === 'select' && Array.isArray(r.columns) ? r.columns : [];
157
- result = cols.map((name, i) => ({
158
- name,
159
- type: 'TEXT',
160
- column: name,
161
- table: r && r.table ? r.table : null,
162
- database: null,
163
- }));
164
- break;
165
- }
166
- case 'parse': {
167
- const stmt = parseSQL(args[0]);
168
- result = { type: stmt.type, name: stmt.name || stmt.table || null };
169
- break;
170
- }
171
- case 'hasTable': {
172
- result = typeof db.hasTable === 'function' ? db.hasTable(args[0]) : false;
173
- break;
174
- }
175
- case 'registerFunction': {
176
- const [name, fnStr, deterministic] = args;
177
- // 用函数源码在 worker 中重建(无闭包依赖的纯函数)
178
- try {
179
- // eslint-disable-next-line no-new-func
180
- const fn = new Function('return (' + fnStr + ')')();
181
- userFunctions[String(name).toUpperCase()] = fn;
182
- result = { ok: true };
183
- } catch (e) {
184
- throw new Error('Failed to register function ' + name + ': ' + e.message);
185
- }
186
- break;
187
- }
188
- case 'clearFunctions': {
189
- for (const k of Object.keys(userFunctions)) delete userFunctions[k];
190
- result = { ok: true };
191
- break;
192
- }
193
- case 'registerAggregate': {
194
- const [name, specStr, deterministic] = args;
195
- try {
196
- // eslint-disable-next-line no-new-func
197
- const spec = new Function('return (' + specStr + ')')();
198
- userAggregates[String(name).toUpperCase()] = spec;
199
- result = { ok: true };
200
- } catch (e) {
201
- throw new Error('Failed to register aggregate ' + name + ': ' + e.message);
202
- }
203
- break;
204
- }
205
- case 'serialize': {
206
- const { exportAllToJSON } = require('./migrate');
207
- const tables = db.listTables ? db.listTables() : Array.from(db._tableNames || []);
208
- const dump = await exportAllToJSON(db, tables);
209
- result = Buffer.from(JSON.stringify(dump), 'utf8');
210
- break;
211
- }
212
- case 'deserialize': {
213
- const { importFromJSON } = require('./migrate');
214
- const dump = JSON.parse(Buffer.from(args[0]).toString('utf8'));
215
- await importFromJSON(db, dump, { overwrite: true });
216
- if (typeof db.save === 'function') db.save();
217
- result = { ok: true };
218
- break;
219
- }
220
- case 'backup': {
221
- // 复制到另一个 sqlite 兼容库
222
- const { exportAllToJSON } = require('./migrate');
223
- const target = args[0];
224
- const tables = db.listTables ? db.listTables() : Array.from(db._tableNames || []);
225
- const dump = await exportAllToJSON(db, tables);
226
- // 目标由主线程用另一个 Database 加载,此处返回 dump
227
- result = Buffer.from(JSON.stringify(dump), 'utf8');
228
- break;
229
- }
230
- case 'clearAggregates': {
231
- for (const k of Object.keys(userAggregates)) delete userAggregates[k];
232
- result = { ok: true };
233
- break;
234
- }
235
- default:
236
- throw new Error(`Unknown op: ${op}`);
237
- }
238
- return result;
239
- }
240
-
241
- PARENT.on('message', async (msg) => {
242
- const { id, op, args, sab: sabArr } = msg;
243
- if (sabArr) {
244
- sab = sabArr;
245
- ctrl = new Int32Array(sab);
246
- }
247
- let payload;
248
- try {
249
- payload = { ok: true, result: cleanResult(await handleOp(op, args)) };
250
- } catch (e) {
251
- payload = { ok: false, error: { message: e.message, code: e.code || 'SQLITE_ERROR' } };
252
- }
253
- PORT.postMessage({ id, ...payload });
254
- if (ctrl) {
255
- Atomics.store(ctrl, 0, id);
256
- Atomics.notify(ctrl, 0);
257
- }
258
- });
259
-
260
- PARENT.on('close', async () => {
261
- try {
262
- if (db && typeof db.stop === 'function') await db.stop();
263
- } catch (e) { /* ignore */ }
264
- });
1
+ // © Vexify 2026 All Rights Reserved.
2
+ /**
3
+ * better-sqlite3 兼容层 — worker 线程
4
+ * 在 worker 中持有一个持久 Database,主线程通过 postMessage + Atomics 同步桥调用。
5
+ */
6
+
7
+ const { workerData } = require('worker_threads');
8
+ const Database = require('./database');
9
+ const { executeSQL, parseSQL, applyParams } = require('./sql');
10
+
11
+ const PARENT = require('worker_threads').parentPort;
12
+ const PORT = workerData.port || PARENT;
13
+ let db = null;
14
+ let sab = null;
15
+ let ctrl = null;
16
+ const userFunctions = {};
17
+ const userAggregates = {};
18
+
19
+ function startEngine(filename, options) {
20
+ const opts = options || {};
21
+ const isMemory = filename === ':memory:' || !filename;
22
+ if (opts.engine === 'native') {
23
+ const { JSQL: NativeJSQL } = require('./native_client');
24
+ const engine = new NativeJSQL({ mode: 'memory' });
25
+ db = {
26
+ start: async () => { await engine.start(); },
27
+ stop: async () => { await engine.stop(); },
28
+ hasTable: name => engine._tableNames.has(name),
29
+ createTable: (n, s) => engine.createTable(n, s),
30
+ dropTable: n => engine.dropTable(n),
31
+ insert: (n, rows) => engine.insert(n, rows),
32
+ find: (n, f, o) => engine.find(n, f, o),
33
+ updateById: (n, id, data) => engine.updateById(n, id, data),
34
+ updateByIds: (n, e) => engine.updateByIds(n, e),
35
+ removeByIds: (n, ids) => engine.removeByIds(n, ids),
36
+ count: (n, f) => engine.count ? engine.count(n, f) : engine.find(n, f || {}, {}).then(rs => rs.length),
37
+ getTableSchema: n => engine._schemas[n] || null,
38
+ beginTx: () => engine.beginTx(),
39
+ commitTx: id => engine.commitTx(id),
40
+ rollbackTx: id => engine.rollbackTx(id),
41
+ truncate: async () => { throw new Error('truncate not supported on native engine'); },
42
+ flush: async () => { if (engine.flush) await engine.flush(); },
43
+ listTables: () => Array.from(engine._tableNames || []),
44
+ _schemas: engine._schemas,
45
+ };
46
+ return db;
47
+ }
48
+ // 纯 JS 引擎
49
+ db = new Database(isMemory ? ':memory:' : filename, opts.mode === 'hybrid' ? { mode: 'hybrid' } : {});
50
+ return db;
51
+ }
52
+
53
+ function toRows(result) {
54
+ // 把 executeSQL 的 select 结果转成 better-sqlite3 风格的对象行数组
55
+ if (result && result.type === 'select' && Array.isArray(result.rows)) {
56
+ const cols = Array.isArray(result.columns) ? result.columns : [];
57
+ return result.rows.map(r => {
58
+ const o = {};
59
+ for (let i = 0; i < cols.length; i++) o[cols[i]] = r[i];
60
+ return o;
61
+ });
62
+ }
63
+ if (result && result.type === 'pragma' && result.value !== undefined) {
64
+ return result.value;
65
+ }
66
+ return undefined;
67
+ }
68
+
69
+ let _lastInsertId = 0;
70
+
71
+ async function executeStatement(sql, params) {
72
+ if (params && typeof params === 'object' && !Array.isArray(params)) {
73
+ sql = applyParams(sql, params);
74
+ params = null;
75
+ }
76
+ const result = await executeSQL(db, sql, params, {
77
+ session: {
78
+ get lastInsertId() { return _lastInsertId; },
79
+ set lastInsertId(v) { _lastInsertId = Number(v); },
80
+ },
81
+ functions: userFunctions,
82
+ aggregates: userAggregates,
83
+ });
84
+ if (result && result.type === 'insert' && result.insertId !== null && result.insertId !== undefined) {
85
+ _lastInsertId = Number(result.insertId);
86
+ }
87
+ return result;
88
+ }
89
+
90
+ function cleanResult(r) {
91
+ if (!r || typeof r !== 'object') return r;
92
+ if (Array.isArray(r)) return r.map(cleanResult);
93
+ if (Buffer.isBuffer(r) || r instanceof Uint8Array || r instanceof ArrayBuffer || ArrayBuffer.isView(r)) return r;
94
+ const out = {};
95
+ for (const [k, v] of Object.entries(r)) {
96
+ if (k === 'result' || k === 'engine') continue;
97
+ if (v instanceof Date) out[k] = v.toISOString();
98
+ else if (v === undefined) out[k] = null;
99
+ else if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
100
+ // 仅保留可 JSON 化的值(防止 Table/内部对象循环引用)
101
+ try { JSON.stringify(v); out[k] = v; } catch (e) { out[k] = null; }
102
+ } else out[k] = v;
103
+ }
104
+ return out;
105
+ }
106
+
107
+ async function handleOp(op, args) {
108
+ let result;
109
+ switch (op) {
110
+ case 'start': {
111
+ await startEngine(args[0], args[1]).start();
112
+ result = { ok: true };
113
+ break;
114
+ }
115
+ case 'close': {
116
+ if (db && typeof db.stop === 'function') await db.stop();
117
+ result = { ok: true };
118
+ break;
119
+ }
120
+ case 'exec': {
121
+ result = await executeStatement(args[0], args[1]);
122
+ break;
123
+ }
124
+ case 'run': {
125
+ const r = await executeStatement(args[0], args[1]);
126
+ result = {
127
+ changes: r ? (r.affectedRows || 0) : 0,
128
+ lastInsertRowid: r && r.type === 'insert' ? Number(r.insertId || 0) : _lastInsertId,
129
+ };
130
+ break;
131
+ }
132
+ case 'get': {
133
+ const r = await executeStatement(args[0], args[1]);
134
+ const rows = toRows(r);
135
+ result = Array.isArray(rows) ? (rows.length > 0 ? rows[0] : undefined) : rows;
136
+ break;
137
+ }
138
+ case 'all': {
139
+ const r = await executeStatement(args[0], args[1]);
140
+ const rows = toRows(r);
141
+ result = rows === undefined || rows === null ? [] : rows;
142
+ break;
143
+ }
144
+ case 'raw': {
145
+ const r = await executeStatement(args[0], args[1]);
146
+ let rows = r && r.type === 'select' ? (r.rows || []) : (toRows(r) || []);
147
+ const cols = r && Array.isArray(r.columns) ? r.columns : (rows.length > 0 ? Object.keys(rows[0]) : []);
148
+ if (Array.isArray(rows) && rows.length > 0 && typeof rows[0] === 'object' && !Array.isArray(rows[0])) {
149
+ rows = rows.map(row => cols.map(c => row[c]));
150
+ }
151
+ result = rows;
152
+ break;
153
+ }
154
+ case 'columns': {
155
+ const r = await executeStatement(args[0], args[1]);
156
+ const cols = r && r.type === 'select' && Array.isArray(r.columns) ? r.columns : [];
157
+ result = cols.map((name, i) => ({
158
+ name,
159
+ type: 'TEXT',
160
+ column: name,
161
+ table: r && r.table ? r.table : null,
162
+ database: null,
163
+ }));
164
+ break;
165
+ }
166
+ case 'parse': {
167
+ const stmt = parseSQL(args[0]);
168
+ result = { type: stmt.type, name: stmt.name || stmt.table || null };
169
+ break;
170
+ }
171
+ case 'hasTable': {
172
+ result = typeof db.hasTable === 'function' ? db.hasTable(args[0]) : false;
173
+ break;
174
+ }
175
+ case 'registerFunction': {
176
+ const [name, fnStr, deterministic] = args;
177
+ // 用函数源码在 worker 中重建(无闭包依赖的纯函数)
178
+ try {
179
+ // eslint-disable-next-line no-new-func
180
+ const fn = new Function('return (' + fnStr + ')')();
181
+ userFunctions[String(name).toUpperCase()] = fn;
182
+ result = { ok: true };
183
+ } catch (e) {
184
+ throw new Error('Failed to register function ' + name + ': ' + e.message);
185
+ }
186
+ break;
187
+ }
188
+ case 'clearFunctions': {
189
+ for (const k of Object.keys(userFunctions)) delete userFunctions[k];
190
+ result = { ok: true };
191
+ break;
192
+ }
193
+ case 'registerAggregate': {
194
+ const [name, specStr, deterministic] = args;
195
+ try {
196
+ // eslint-disable-next-line no-new-func
197
+ const spec = new Function('return (' + specStr + ')')();
198
+ userAggregates[String(name).toUpperCase()] = spec;
199
+ result = { ok: true };
200
+ } catch (e) {
201
+ throw new Error('Failed to register aggregate ' + name + ': ' + e.message);
202
+ }
203
+ break;
204
+ }
205
+ case 'serialize': {
206
+ const { exportAllToJSON } = require('./migrate');
207
+ const tables = db.listTables ? db.listTables() : Array.from(db._tableNames || []);
208
+ const dump = await exportAllToJSON(db, tables);
209
+ result = Buffer.from(JSON.stringify(dump), 'utf8');
210
+ break;
211
+ }
212
+ case 'deserialize': {
213
+ const { importFromJSON } = require('./migrate');
214
+ const dump = JSON.parse(Buffer.from(args[0]).toString('utf8'));
215
+ await importFromJSON(db, dump, { overwrite: true });
216
+ if (typeof db.save === 'function') db.save();
217
+ result = { ok: true };
218
+ break;
219
+ }
220
+ case 'backup': {
221
+ // 复制到另一个 sqlite 兼容库
222
+ const { exportAllToJSON } = require('./migrate');
223
+ const target = args[0];
224
+ const tables = db.listTables ? db.listTables() : Array.from(db._tableNames || []);
225
+ const dump = await exportAllToJSON(db, tables);
226
+ // 目标由主线程用另一个 Database 加载,此处返回 dump
227
+ result = Buffer.from(JSON.stringify(dump), 'utf8');
228
+ break;
229
+ }
230
+ case 'clearAggregates': {
231
+ for (const k of Object.keys(userAggregates)) delete userAggregates[k];
232
+ result = { ok: true };
233
+ break;
234
+ }
235
+ default:
236
+ throw new Error(`Unknown op: ${op}`);
237
+ }
238
+ return result;
239
+ }
240
+
241
+ PARENT.on('message', async (msg) => {
242
+ const { id, op, args, sab: sabArr } = msg;
243
+ if (sabArr) {
244
+ sab = sabArr;
245
+ ctrl = new Int32Array(sab);
246
+ }
247
+ let payload;
248
+ try {
249
+ payload = { ok: true, result: cleanResult(await handleOp(op, args)) };
250
+ } catch (e) {
251
+ payload = { ok: false, error: { message: e.message, code: e.code || 'SQLITE_ERROR' } };
252
+ }
253
+ PORT.postMessage({ id, ...payload });
254
+ if (ctrl) {
255
+ Atomics.store(ctrl, 0, id);
256
+ Atomics.notify(ctrl, 0);
257
+ }
258
+ });
259
+
260
+ PARENT.on('close', async () => {
261
+ try {
262
+ if (db && typeof db.stop === 'function') await db.stop();
263
+ } catch (e) { /* ignore */ }
264
+ });