jsql-neo 5.5.0 → 6.0.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 (81) hide show
  1. package/LICENSE +202 -202
  2. package/README.md +8155 -8097
  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 +412 -385
  7. package/index.js +128 -124
  8. package/lib/ast.js +214 -214
  9. package/lib/btree.js +478 -413
  10. package/lib/cache.js +328 -328
  11. package/lib/client.js +125 -125
  12. package/lib/database.js +1741 -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 +722 -732
  23. package/lib/nedb_compat.js +506 -506
  24. package/lib/pg_server.js +864 -864
  25. package/lib/plugin.js +259 -35
  26. package/lib/plugins/audit.js +37 -0
  27. package/lib/plugins/index.js +72 -0
  28. package/lib/plugins/logger.js +35 -0
  29. package/lib/plugins/metrics.js +38 -0
  30. package/lib/plugins/timestamps.js +57 -0
  31. package/lib/plugins/validation.js +128 -0
  32. package/lib/prepared.js +37 -0
  33. package/lib/query.js +834 -815
  34. package/lib/redis_server.js +571 -571
  35. package/lib/sql.js +4053 -3460
  36. package/lib/sqlite_compat.js +323 -323
  37. package/lib/sqlite_worker.js +264 -264
  38. package/lib/table.js +1351 -1304
  39. package/lib/tui.js +502 -502
  40. package/lib/wasm.js +1 -1
  41. package/lib/wasm_client.js +715 -718
  42. package/lib/web_ui.js +257 -257
  43. package/native/jsql-neo-native.node +0 -0
  44. package/nativesrc/jsql-neo-core/Cargo.lock +462 -455
  45. package/nativesrc/jsql-neo-core/Cargo.toml +26 -24
  46. package/nativesrc/jsql-neo-core/src/engine/hybrid.rs +492 -455
  47. package/nativesrc/jsql-neo-core/src/engine/memory.rs +191 -168
  48. package/nativesrc/jsql-neo-core/src/engine/mod.rs +74 -62
  49. package/nativesrc/jsql-neo-core/src/engine/table.rs +996 -700
  50. package/nativesrc/jsql-neo-core/src/lib.rs +2 -2
  51. package/nativesrc/jsql-neo-core/src/storage/mod.rs +2 -2
  52. package/nativesrc/jsql-neo-core/src/storage/persistent.rs +1 -1
  53. package/nativesrc/jsql-neo-core/src/storage/wal.rs +298 -85
  54. package/nativesrc/jsql-neo-core/src/types.rs +93 -93
  55. package/nativesrc/jsql-neo-native/Cargo.lock +613 -606
  56. package/nativesrc/jsql-neo-native/Cargo.toml +24 -16
  57. package/nativesrc/jsql-neo-native/build.rs +3 -3
  58. package/nativesrc/jsql-neo-native/package.json +7 -7
  59. package/nativesrc/jsql-neo-native/src/lib.rs +281 -269
  60. package/nativesrc/jsql-neo-wasm/Cargo.lock +472 -465
  61. package/nativesrc/jsql-neo-wasm/Cargo.toml +22 -15
  62. package/nativesrc/jsql-neo-wasm/src/lib.rs +463 -447
  63. package/package.json +87 -87
  64. package/postinstall.js +158 -158
  65. package/test/btree.test.js +144 -128
  66. package/test/coverage.js +187 -187
  67. package/test/join.test.js +110 -110
  68. package/test/native.test.js +158 -158
  69. package/test/query-opt.test.js +109 -0
  70. package/test/regress-5.1.0.js +271 -271
  71. package/test/smoke.js +58 -58
  72. package/test/sql-parser.test.js +450 -273
  73. package/test/wasm.test.js +110 -110
  74. package/wasm/browser.d.ts +89 -89
  75. package/wasm/browser.mjs +591 -569
  76. package/wasm/browser_bg.mjs +618 -597
  77. package/wasm/jsql_neo_wasm.d.ts +44 -38
  78. package/wasm/jsql_neo_wasm.js +641 -520
  79. package/wasm/jsql_neo_wasm_bg.wasm +0 -0
  80. package/wasm/jsql_neo_wasm_bg.wasm.d.ts +26 -26
  81. package/wasm/package.json +11 -11
package/lib/ast.js CHANGED
@@ -1,214 +1,214 @@
1
- /**
2
- * lib/ast.js — JSQL-NEO AST 访问与改写
3
- *
4
- * parseSQL() 返回的是普通 JS 对象树。本模块提供在不了解每种节点类型的
5
- * 前提下遍历 / 查找 / 改写这棵树的能力:
6
- *
7
- * walk(ast, visitor[, opts]) 深度优先遍历(前序 + 可选后序)
8
- * collect(ast, predicate) 收集所有满足条件的节点
9
- * find(ast, predicate) 返回第一个满足条件的节点
10
- * transform(ast, fn) 不可变改写,返回新树
11
- * rewrite(ast, fn) 原地改写
12
- * tables(ast) 列出语句引用的所有表名
13
- * columns(ast) 列出语句引用的所有列名
14
- * StatementVisitor 基类,按节点类型分派 visitXxx 方法
15
- *
16
- * 设计约定:
17
- * - 「节点」指带字符串 type 字段的对象;但遍历会穿透所有普通对象与数组,
18
- * 因为 SELECT 列描述符({ expr, scalar, alias })这类中间结构没有 type。
19
- * - seen 集合防止共享子树被重复访问或死循环。
20
- * - transform 返回新树、不改入参;rewrite 原地修改。
21
- */
22
-
23
- const SKIP_KEYS = new Set(['pos']);
24
-
25
- function isNode(v) {
26
- return v !== null && typeof v === 'object' && !Array.isArray(v) && typeof v.type === 'string';
27
- }
28
-
29
- function childKeys(obj) {
30
- const out = [];
31
- for (const k of Object.keys(obj)) if (!SKIP_KEYS.has(k)) out.push(k);
32
- return out;
33
- }
34
-
35
- /** 深度优先遍历。visitor(node, parent, key) 返回 false 可跳过该子树。 */
36
- function walk(ast, visitor, opts = {}) {
37
- const seen = new Set();
38
- const post = opts.post || null;
39
- const fn = typeof visitor === 'function' ? visitor : null;
40
-
41
- const visit = (value, parent, key) => {
42
- if (value === null || typeof value !== 'object') return;
43
- if (seen.has(value)) return;
44
- seen.add(value);
45
-
46
- if (Array.isArray(value)) {
47
- for (const item of value) visit(item, parent, key);
48
- return;
49
- }
50
-
51
- const node = isNode(value);
52
- let descend = true;
53
- if (node && fn) {
54
- const r = fn(value, parent, key);
55
- if (r === false) descend = false;
56
- }
57
- if (descend) {
58
- for (const k of childKeys(value)) visit(value[k], value, k);
59
- }
60
- if (node && post) post(value, parent, key);
61
- };
62
-
63
- if (Array.isArray(ast)) { for (const n of ast) visit(n, null, null); }
64
- else visit(ast, null, null);
65
- return ast;
66
- }
67
-
68
- /** 收集所有满足 predicate 的节点。 */
69
- function collect(ast, predicate) {
70
- const out = [];
71
- walk(ast, (node) => { if (predicate(node)) out.push(node); });
72
- return out;
73
- }
74
-
75
- /** 返回第一个满足 predicate 的节点,找不到返回 null。 */
76
- function find(ast, predicate) {
77
- let hit = null;
78
- walk(ast, (node) => {
79
- if (hit) return false;
80
- if (predicate(node)) { hit = node; return false; }
81
- });
82
- return hit;
83
- }
84
-
85
- function cloneValue(v, seen) {
86
- if (v === null || typeof v !== 'object') return v;
87
- if (seen.has(v)) return v;
88
- seen.add(v);
89
- if (Array.isArray(v)) return v.map(x => cloneValue(x, seen));
90
- const out = {};
91
- for (const k of Object.keys(v)) out[k] = cloneValue(v[k], seen);
92
- return out;
93
- }
94
-
95
- function cloneNode(node) { return cloneValue(node, new Set()); }
96
-
97
- /**
98
- * 不可变改写:对每个节点调用 fn(node),返回值非 undefined 时替换该节点。
99
- * 返回新树,入参保持不变。
100
- */
101
- function transform(ast, fn) {
102
- const seen = new Set();
103
-
104
- const visit = (value) => {
105
- if (value === null || typeof value !== 'object') {
106
- const r = fn(value);
107
- return r === undefined ? value : r;
108
- }
109
- if (seen.has(value)) return value;
110
- seen.add(value);
111
-
112
- if (Array.isArray(value)) {
113
- const arr = value.map(visit);
114
- const rep = fn(arr);
115
- return rep === undefined ? arr : rep;
116
- }
117
-
118
- const out = {};
119
- for (const k of Object.keys(value)) out[k] = visit(value[k]);
120
-
121
- if (isNode(value)) {
122
- const rep = fn(out);
123
- return rep === undefined ? out : rep;
124
- }
125
- return out;
126
- };
127
-
128
- return visit(ast);
129
- }
130
-
131
- /** 原地改写:fn(node) 返回值非 undefined 时替换原节点。 */
132
- function rewrite(ast, fn) {
133
- const seen = new Set();
134
-
135
- const visit = (value, parent, key, index) => {
136
- if (value === null || typeof value !== 'object') {
137
- if (parent && key) {
138
- const r = fn(value);
139
- if (r !== undefined) {
140
- if (index === undefined) parent[key] = r; else parent[key][index] = r;
141
- }
142
- }
143
- return;
144
- }
145
- if (seen.has(value)) return;
146
- seen.add(value);
147
-
148
- if (Array.isArray(value)) {
149
- for (let i = 0; i < value.length; i++) visit(value[i], parent, key, i);
150
- return;
151
- }
152
-
153
- for (const k of childKeys(value)) visit(value[k], value, k);
154
-
155
- if (isNode(value) && parent && key) {
156
- const r = fn(value);
157
- if (r !== undefined) {
158
- if (index === undefined) parent[key] = r; else parent[key][index] = r;
159
- }
160
- }
161
- };
162
-
163
- visit(ast, null, null);
164
- return ast;
165
- }
166
-
167
- /** 语句引用的所有表名(含 JOIN / 子查询)。 */
168
- function tables(ast) {
169
- const out = new Set();
170
- walk(ast, (node) => {
171
- if (node.type === 'select' && node.from) {
172
- for (const t of (node.from.tables || [])) if (t && t.table) out.add(t.table);
173
- for (const j of (node.from.joins || [])) if (j.item && j.item.table) out.add(j.item.table);
174
- }
175
- if (node.type === 'insert' || node.type === 'update' || node.type === 'delete' ||
176
- node.type === 'createTable' || node.type === 'dropTable' || node.type === 'truncate') {
177
- if (node.name) out.add(node.name);
178
- if (node.table) out.add(node.table);
179
- }
180
- });
181
- return [...out];
182
- }
183
-
184
- /** 语句引用的所有列名(去重)。 */
185
- function columns(ast) {
186
- const out = new Set();
187
- walk(ast, (node) => {
188
- if (node.type === 'column' && node.name) out.add(node.name);
189
- });
190
- return [...out];
191
- }
192
-
193
- /**
194
- * 按节点类型分派的访问器基类。
195
- * 子类定义 visitSelect(node) / visitCompare(node) … 即可;未定义类型走 visitDefault。
196
- *
197
- * class MyVisitor extends StatementVisitor {
198
- * visitColumn(node) { node.name = String(node.name).toLowerCase(); }
199
- * }
200
- * new MyVisitor().run(ast);
201
- */
202
- class StatementVisitor {
203
- run(ast) {
204
- walk(ast, (node) => {
205
- const camel = String(node.type).replace(/(^|[-_])([a-z])/g, (_, __, ch) => ch.toUpperCase());
206
- const method = this['visit' + camel];
207
- if (typeof method === 'function') method.call(this, node);
208
- else if (typeof this.visitDefault === 'function') this.visitDefault(node);
209
- });
210
- return ast;
211
- }
212
- }
213
-
214
- module.exports = { walk, collect, find, transform, rewrite, tables, columns, StatementVisitor, isNode, cloneNode };
1
+ /**
2
+ * lib/ast.js — JSQL-NEO AST 访问与改写
3
+ *
4
+ * parseSQL() 返回的是普通 JS 对象树。本模块提供在不了解每种节点类型的
5
+ * 前提下遍历 / 查找 / 改写这棵树的能力:
6
+ *
7
+ * walk(ast, visitor[, opts]) 深度优先遍历(前序 + 可选后序)
8
+ * collect(ast, predicate) 收集所有满足条件的节点
9
+ * find(ast, predicate) 返回第一个满足条件的节点
10
+ * transform(ast, fn) 不可变改写,返回新树
11
+ * rewrite(ast, fn) 原地改写
12
+ * tables(ast) 列出语句引用的所有表名
13
+ * columns(ast) 列出语句引用的所有列名
14
+ * StatementVisitor 基类,按节点类型分派 visitXxx 方法
15
+ *
16
+ * 设计约定:
17
+ * - 「节点」指带字符串 type 字段的对象;但遍历会穿透所有普通对象与数组,
18
+ * 因为 SELECT 列描述符({ expr, scalar, alias })这类中间结构没有 type。
19
+ * - seen 集合防止共享子树被重复访问或死循环。
20
+ * - transform 返回新树、不改入参;rewrite 原地修改。
21
+ */
22
+
23
+ const SKIP_KEYS = new Set(['pos']);
24
+
25
+ function isNode(v) {
26
+ return v !== null && typeof v === 'object' && !Array.isArray(v) && typeof v.type === 'string';
27
+ }
28
+
29
+ function childKeys(obj) {
30
+ const out = [];
31
+ for (const k of Object.keys(obj)) if (!SKIP_KEYS.has(k)) out.push(k);
32
+ return out;
33
+ }
34
+
35
+ /** 深度优先遍历。visitor(node, parent, key) 返回 false 可跳过该子树。 */
36
+ function walk(ast, visitor, opts = {}) {
37
+ const seen = new Set();
38
+ const post = opts.post || null;
39
+ const fn = typeof visitor === 'function' ? visitor : null;
40
+
41
+ const visit = (value, parent, key) => {
42
+ if (value === null || typeof value !== 'object') return;
43
+ if (seen.has(value)) return;
44
+ seen.add(value);
45
+
46
+ if (Array.isArray(value)) {
47
+ for (const item of value) visit(item, parent, key);
48
+ return;
49
+ }
50
+
51
+ const node = isNode(value);
52
+ let descend = true;
53
+ if (node && fn) {
54
+ const r = fn(value, parent, key);
55
+ if (r === false) descend = false;
56
+ }
57
+ if (descend) {
58
+ for (const k of childKeys(value)) visit(value[k], value, k);
59
+ }
60
+ if (node && post) post(value, parent, key);
61
+ };
62
+
63
+ if (Array.isArray(ast)) { for (const n of ast) visit(n, null, null); }
64
+ else visit(ast, null, null);
65
+ return ast;
66
+ }
67
+
68
+ /** 收集所有满足 predicate 的节点。 */
69
+ function collect(ast, predicate) {
70
+ const out = [];
71
+ walk(ast, (node) => { if (predicate(node)) out.push(node); });
72
+ return out;
73
+ }
74
+
75
+ /** 返回第一个满足 predicate 的节点,找不到返回 null。 */
76
+ function find(ast, predicate) {
77
+ let hit = null;
78
+ walk(ast, (node) => {
79
+ if (hit) return false;
80
+ if (predicate(node)) { hit = node; return false; }
81
+ });
82
+ return hit;
83
+ }
84
+
85
+ function cloneValue(v, seen) {
86
+ if (v === null || typeof v !== 'object') return v;
87
+ if (seen.has(v)) return v;
88
+ seen.add(v);
89
+ if (Array.isArray(v)) return v.map(x => cloneValue(x, seen));
90
+ const out = {};
91
+ for (const k of Object.keys(v)) out[k] = cloneValue(v[k], seen);
92
+ return out;
93
+ }
94
+
95
+ function cloneNode(node) { return cloneValue(node, new Set()); }
96
+
97
+ /**
98
+ * 不可变改写:对每个节点调用 fn(node),返回值非 undefined 时替换该节点。
99
+ * 返回新树,入参保持不变。
100
+ */
101
+ function transform(ast, fn) {
102
+ const seen = new Set();
103
+
104
+ const visit = (value) => {
105
+ if (value === null || typeof value !== 'object') {
106
+ const r = fn(value);
107
+ return r === undefined ? value : r;
108
+ }
109
+ if (seen.has(value)) return value;
110
+ seen.add(value);
111
+
112
+ if (Array.isArray(value)) {
113
+ const arr = value.map(visit);
114
+ const rep = fn(arr);
115
+ return rep === undefined ? arr : rep;
116
+ }
117
+
118
+ const out = {};
119
+ for (const k of Object.keys(value)) out[k] = visit(value[k]);
120
+
121
+ if (isNode(value)) {
122
+ const rep = fn(out);
123
+ return rep === undefined ? out : rep;
124
+ }
125
+ return out;
126
+ };
127
+
128
+ return visit(ast);
129
+ }
130
+
131
+ /** 原地改写:fn(node) 返回值非 undefined 时替换原节点。 */
132
+ function rewrite(ast, fn) {
133
+ const seen = new Set();
134
+
135
+ const visit = (value, parent, key, index) => {
136
+ if (value === null || typeof value !== 'object') {
137
+ if (parent && key) {
138
+ const r = fn(value);
139
+ if (r !== undefined) {
140
+ if (index === undefined) parent[key] = r; else parent[key][index] = r;
141
+ }
142
+ }
143
+ return;
144
+ }
145
+ if (seen.has(value)) return;
146
+ seen.add(value);
147
+
148
+ if (Array.isArray(value)) {
149
+ for (let i = 0; i < value.length; i++) visit(value[i], parent, key, i);
150
+ return;
151
+ }
152
+
153
+ for (const k of childKeys(value)) visit(value[k], value, k);
154
+
155
+ if (isNode(value) && parent && key) {
156
+ const r = fn(value);
157
+ if (r !== undefined) {
158
+ if (index === undefined) parent[key] = r; else parent[key][index] = r;
159
+ }
160
+ }
161
+ };
162
+
163
+ visit(ast, null, null);
164
+ return ast;
165
+ }
166
+
167
+ /** 语句引用的所有表名(含 JOIN / 子查询)。 */
168
+ function tables(ast) {
169
+ const out = new Set();
170
+ walk(ast, (node) => {
171
+ if (node.type === 'select' && node.from) {
172
+ for (const t of (node.from.tables || [])) if (t && t.table) out.add(t.table);
173
+ for (const j of (node.from.joins || [])) if (j.item && j.item.table) out.add(j.item.table);
174
+ }
175
+ if (node.type === 'insert' || node.type === 'update' || node.type === 'delete' ||
176
+ node.type === 'createTable' || node.type === 'dropTable' || node.type === 'truncate') {
177
+ if (node.name) out.add(node.name);
178
+ if (node.table) out.add(node.table);
179
+ }
180
+ });
181
+ return [...out];
182
+ }
183
+
184
+ /** 语句引用的所有列名(去重)。 */
185
+ function columns(ast) {
186
+ const out = new Set();
187
+ walk(ast, (node) => {
188
+ if (node.type === 'column' && node.name) out.add(node.name);
189
+ });
190
+ return [...out];
191
+ }
192
+
193
+ /**
194
+ * 按节点类型分派的访问器基类。
195
+ * 子类定义 visitSelect(node) / visitCompare(node) … 即可;未定义类型走 visitDefault。
196
+ *
197
+ * class MyVisitor extends StatementVisitor {
198
+ * visitColumn(node) { node.name = String(node.name).toLowerCase(); }
199
+ * }
200
+ * new MyVisitor().run(ast);
201
+ */
202
+ class StatementVisitor {
203
+ run(ast) {
204
+ walk(ast, (node) => {
205
+ const camel = String(node.type).replace(/(^|[-_])([a-z])/g, (_, __, ch) => ch.toUpperCase());
206
+ const method = this['visit' + camel];
207
+ if (typeof method === 'function') method.call(this, node);
208
+ else if (typeof this.visitDefault === 'function') this.visitDefault(node);
209
+ });
210
+ return ast;
211
+ }
212
+ }
213
+
214
+ module.exports = { walk, collect, find, transform, rewrite, tables, columns, StatementVisitor, isNode, cloneNode };