jsql-neo 4.0.2 → 4.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/bin/jsql +69 -0
- package/bin/jsql-server +90 -0
- package/bin/jsql-server-control.js +177 -0
- package/lib/database.js +98 -9
- package/lib/errors.js +6 -0
- package/lib/jsql_format.js +33 -14
- package/lib/mod.js +43 -67
- package/lib/mysql_compat.js +134 -17
- package/lib/mysql_server.js +315 -22
- package/lib/native_client.js +95 -32
- package/lib/sql.js +646 -122
- package/lib/table.js +114 -12
- package/lib/wasm_client.js +59 -6
- package/native/jsql-neo-native.node +0 -0
- package/nativesrc/jsql-neo-core/Cargo.lock +455 -0
- package/nativesrc/jsql-neo-core/src/engine/hybrid.rs +12 -6
- package/nativesrc/jsql-neo-core/src/engine/memory.rs +28 -7
- package/nativesrc/jsql-neo-core/src/engine/mod.rs +22 -1
- package/nativesrc/jsql-neo-core/src/engine/table.rs +53 -23
- package/nativesrc/jsql-neo-core/src/storage/mod.rs +2 -1
- package/nativesrc/jsql-neo-core/src/storage/wal.rs +1 -0
- package/nativesrc/jsql-neo-native/build.rs +3 -0
- package/nativesrc/jsql-neo-native/jsql-neo-native.node +0 -0
- package/nativesrc/jsql-neo-native/src/lib.rs +75 -87
- package/nativesrc/jsql-neo-wasm/Cargo.lock +465 -0
- package/nativesrc/jsql-neo-wasm/Cargo.toml +15 -0
- package/nativesrc/jsql-neo-wasm/src/lib.rs +423 -0
- package/package.json +8 -1
- package/wasm/jsql_neo_wasm.d.ts +2 -0
- package/wasm/jsql_neo_wasm.js +5 -0
- package/wasm/jsql_neo_wasm_bg.wasm +0 -0
- package/wasm/jsql_neo_wasm_bg.wasm.d.ts +1 -0
package/lib/table.js
CHANGED
|
@@ -9,6 +9,102 @@ const BTree = require('./btree');
|
|
|
9
9
|
const { validateDateType, now } = require('./date-types');
|
|
10
10
|
const { createError } = require('./errors');
|
|
11
11
|
|
|
12
|
+
function isSafeRegex(pattern) {
|
|
13
|
+
if (typeof pattern !== 'string') return false;
|
|
14
|
+
if (pattern.length > 256) return false;
|
|
15
|
+
const groups = [];
|
|
16
|
+
let i = 0;
|
|
17
|
+
const n = pattern.length;
|
|
18
|
+
while (i < n) {
|
|
19
|
+
const c = pattern[i];
|
|
20
|
+
if (c === '\\') { i += 2; continue; }
|
|
21
|
+
if (c === '[') {
|
|
22
|
+
while (i < n && pattern[i] !== ']') i++;
|
|
23
|
+
i++;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (c === '(') {
|
|
27
|
+
const nxt = pattern[i + 1];
|
|
28
|
+
if (nxt === '?') {
|
|
29
|
+
const t = pattern[i + 2];
|
|
30
|
+
if (t === ':') {
|
|
31
|
+
groups.push({ hasQuant: false, hasAlt: false });
|
|
32
|
+
i += 3;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (t === '=' || t === '!') {
|
|
36
|
+
let depth = 1, j = i + 3;
|
|
37
|
+
for (; j < n && depth > 0; j++) {
|
|
38
|
+
if (pattern[j] === '\\') { j++; continue; }
|
|
39
|
+
if (pattern[j] === '(') depth++;
|
|
40
|
+
else if (pattern[j] === ')') depth--;
|
|
41
|
+
}
|
|
42
|
+
i = j;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (t === '<') {
|
|
46
|
+
const u = pattern[i + 3];
|
|
47
|
+
if (u === '=' || u === '!') {
|
|
48
|
+
let depth = 1, j = i + 4;
|
|
49
|
+
for (; j < n && depth > 0; j++) {
|
|
50
|
+
if (pattern[j] === '\\') { j++; continue; }
|
|
51
|
+
if (pattern[j] === '(') depth++;
|
|
52
|
+
else if (pattern[j] === ')') depth--;
|
|
53
|
+
}
|
|
54
|
+
i = j;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const gt = pattern.indexOf('>', i + 3);
|
|
58
|
+
if (gt === -1) return false;
|
|
59
|
+
groups.push({ hasQuant: false, hasAlt: false });
|
|
60
|
+
i = gt + 1;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
groups.push({ hasQuant: false, hasAlt: false });
|
|
66
|
+
i++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (c === ')') {
|
|
70
|
+
const g = groups.pop();
|
|
71
|
+
if (!g) return false;
|
|
72
|
+
let qi = i + 1;
|
|
73
|
+
let quant = null;
|
|
74
|
+
if (pattern[qi] === '+' || pattern[qi] === '*' || pattern[qi] === '?') {
|
|
75
|
+
quant = pattern[qi];
|
|
76
|
+
} else if (pattern[qi] === '{') {
|
|
77
|
+
const close = pattern.indexOf('}', qi);
|
|
78
|
+
if (close === -1) return false;
|
|
79
|
+
quant = pattern.slice(qi, close + 1);
|
|
80
|
+
qi = close + 1;
|
|
81
|
+
}
|
|
82
|
+
if (quant && (g.hasQuant || g.hasAlt)) return false;
|
|
83
|
+
i = qi;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (c === '+' || c === '*' || c === '?') {
|
|
87
|
+
if (groups.length > 0) groups[groups.length - 1].hasQuant = true;
|
|
88
|
+
i++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (c === '{' && /[0-9]/.test(pattern[i + 1] || '')) {
|
|
92
|
+
const close = pattern.indexOf('}', i);
|
|
93
|
+
if (close === -1) return false;
|
|
94
|
+
if (groups.length > 0) groups[groups.length - 1].hasQuant = true;
|
|
95
|
+
i = close + 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (c === '|') {
|
|
99
|
+
if (groups.length > 0) groups[groups.length - 1].hasAlt = true;
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
i++;
|
|
104
|
+
}
|
|
105
|
+
return groups.length === 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
12
108
|
class Table {
|
|
13
109
|
constructor(name, schema, db) {
|
|
14
110
|
this._name = name;
|
|
@@ -112,7 +208,7 @@ class Table {
|
|
|
112
208
|
this._rows.push({ ...data });
|
|
113
209
|
this._addToIndexes(rowIndex, data);
|
|
114
210
|
this._dirty = true;
|
|
115
|
-
this._db._markDirty();
|
|
211
|
+
this._db._markDirty(this._name);
|
|
116
212
|
|
|
117
213
|
for (const hook of this._hooks.afterInsert) {
|
|
118
214
|
hook(data);
|
|
@@ -131,7 +227,12 @@ class Table {
|
|
|
131
227
|
}
|
|
132
228
|
const N = items.length;
|
|
133
229
|
const uniqueTracker = {};
|
|
134
|
-
for (const field of this._cachedUniqueFields)
|
|
230
|
+
for (const field of this._cachedUniqueFields) {
|
|
231
|
+
uniqueTracker[field] = new Set();
|
|
232
|
+
for (const row of this._rows) {
|
|
233
|
+
if (row[field] !== undefined && row[field] !== null) uniqueTracker[field].add(row[field]);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
135
236
|
const dateFields = this._cachedDateFields;
|
|
136
237
|
const hasDateFields = dateFields.length > 0;
|
|
137
238
|
const autoIncField = this._autoIncrementField;
|
|
@@ -194,7 +295,7 @@ class Table {
|
|
|
194
295
|
items[i] = data;
|
|
195
296
|
}
|
|
196
297
|
this._dirty = true;
|
|
197
|
-
this._db._markDirty();
|
|
298
|
+
this._db._markDirty(this._name);
|
|
198
299
|
for (const hook of this._hooks.afterInsert) {
|
|
199
300
|
for (let i = 0; i < N; i++) hook(items[i]);
|
|
200
301
|
}
|
|
@@ -295,7 +396,7 @@ class Table {
|
|
|
295
396
|
|
|
296
397
|
if (count > 0) {
|
|
297
398
|
this._dirty = true;
|
|
298
|
-
this._db._markDirty();
|
|
399
|
+
this._db._markDirty(this._name);
|
|
299
400
|
for (const hook of this._hooks.afterUpdate) {
|
|
300
401
|
hook(query, updates, count);
|
|
301
402
|
}
|
|
@@ -333,7 +434,7 @@ class Table {
|
|
|
333
434
|
Object.assign(row, updates);
|
|
334
435
|
this._addToIndexes(rowIndex, row);
|
|
335
436
|
this._dirty = true;
|
|
336
|
-
this._db._markDirty();
|
|
437
|
+
this._db._markDirty(this._name);
|
|
337
438
|
for (const hook of this._hooks.afterUpdate) {
|
|
338
439
|
hook({ [this._primaryKey]: id }, updates, 1);
|
|
339
440
|
}
|
|
@@ -388,7 +489,7 @@ class Table {
|
|
|
388
489
|
this._rows.pop();
|
|
389
490
|
}
|
|
390
491
|
this._dirty = true;
|
|
391
|
-
this._db._markDirty();
|
|
492
|
+
this._db._markDirty(this._name);
|
|
392
493
|
for (const hook of this._hooks.afterRemove) {
|
|
393
494
|
hook(query, count);
|
|
394
495
|
}
|
|
@@ -434,7 +535,7 @@ class Table {
|
|
|
434
535
|
}
|
|
435
536
|
this._rows.pop();
|
|
436
537
|
this._dirty = true;
|
|
437
|
-
this._db._markDirty();
|
|
538
|
+
this._db._markDirty(this._name);
|
|
438
539
|
for (const hook of this._hooks.afterRemove) {
|
|
439
540
|
hook({ [this._primaryKey]: id }, 1);
|
|
440
541
|
}
|
|
@@ -485,7 +586,7 @@ class Table {
|
|
|
485
586
|
this._indexes = {};
|
|
486
587
|
this._autoIncrement = 0;
|
|
487
588
|
this._dirty = true;
|
|
488
|
-
this._db._markDirty();
|
|
589
|
+
this._db._markDirty(this._name);
|
|
489
590
|
return count;
|
|
490
591
|
}
|
|
491
592
|
|
|
@@ -523,7 +624,7 @@ class Table {
|
|
|
523
624
|
this._rebuildBTree(field);
|
|
524
625
|
}
|
|
525
626
|
this._dirty = true;
|
|
526
|
-
this._db._markDirty();
|
|
627
|
+
this._db._markDirty(this._name);
|
|
527
628
|
return this;
|
|
528
629
|
}
|
|
529
630
|
|
|
@@ -543,7 +644,7 @@ class Table {
|
|
|
543
644
|
if (this._primaryKey === field) this._primaryKey = null;
|
|
544
645
|
if (this._autoIncrementField === field) this._autoIncrementField = null;
|
|
545
646
|
this._dirty = true;
|
|
546
|
-
this._db._markDirty();
|
|
647
|
+
this._db._markDirty(this._name);
|
|
547
648
|
return this;
|
|
548
649
|
}
|
|
549
650
|
|
|
@@ -567,7 +668,7 @@ class Table {
|
|
|
567
668
|
if (this._primaryKey === oldName) this._primaryKey = newName;
|
|
568
669
|
if (this._autoIncrementField === oldName) this._autoIncrementField = newName;
|
|
569
670
|
this._dirty = true;
|
|
570
|
-
this._db._markDirty();
|
|
671
|
+
this._db._markDirty(this._name);
|
|
571
672
|
return this;
|
|
572
673
|
}
|
|
573
674
|
|
|
@@ -582,7 +683,7 @@ class Table {
|
|
|
582
683
|
this._rebuildBTree(field);
|
|
583
684
|
}
|
|
584
685
|
this._dirty = true;
|
|
585
|
-
this._db._markDirty();
|
|
686
|
+
this._db._markDirty(this._name);
|
|
586
687
|
return this;
|
|
587
688
|
}
|
|
588
689
|
|
|
@@ -811,6 +912,7 @@ class Table {
|
|
|
811
912
|
if (typeof value !== 'string' || typeof target !== 'string') return false;
|
|
812
913
|
return new RegExp('^' + target.replace(/%/g, '.*').replace(/_/g, '.') + '$', 'i').test(value);
|
|
813
914
|
case '$regex':
|
|
915
|
+
if (!isSafeRegex(target)) throw createError('ER_BAD_REGEX', String(target));
|
|
814
916
|
return new RegExp(target).test(String(value));
|
|
815
917
|
case '$exists':
|
|
816
918
|
return target ? value !== undefined : value === undefined;
|
package/lib/wasm_client.js
CHANGED
|
@@ -44,7 +44,15 @@ function encodeBatch(rows) {
|
|
|
44
44
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
45
45
|
off = buf.writeUInt32LE(sl, off);
|
|
46
46
|
off += buf.write(v, off, sl, 'utf8');
|
|
47
|
-
} else
|
|
47
|
+
} else if (typeof v === 'boolean') {
|
|
48
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
49
|
+
} else {
|
|
50
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
51
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
52
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
53
|
+
off = buf.writeUInt32LE(sl, off);
|
|
54
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
55
|
+
}
|
|
48
56
|
}
|
|
49
57
|
if (nFields >= 2) {
|
|
50
58
|
const v = row[fieldNames[1]];
|
|
@@ -57,7 +65,15 @@ function encodeBatch(rows) {
|
|
|
57
65
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
58
66
|
off = buf.writeUInt32LE(sl, off);
|
|
59
67
|
off += buf.write(v, off, sl, 'utf8');
|
|
60
|
-
} else
|
|
68
|
+
} else if (typeof v === 'boolean') {
|
|
69
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
70
|
+
} else {
|
|
71
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
72
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
73
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
74
|
+
off = buf.writeUInt32LE(sl, off);
|
|
75
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
76
|
+
}
|
|
61
77
|
}
|
|
62
78
|
if (nFields >= 3) {
|
|
63
79
|
const v = row[fieldNames[2]];
|
|
@@ -70,7 +86,15 @@ function encodeBatch(rows) {
|
|
|
70
86
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
71
87
|
off = buf.writeUInt32LE(sl, off);
|
|
72
88
|
off += buf.write(v, off, sl, 'utf8');
|
|
73
|
-
} else
|
|
89
|
+
} else if (typeof v === 'boolean') {
|
|
90
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
91
|
+
} else {
|
|
92
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
93
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
94
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
95
|
+
off = buf.writeUInt32LE(sl, off);
|
|
96
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
97
|
+
}
|
|
74
98
|
}
|
|
75
99
|
if (nFields >= 4) {
|
|
76
100
|
const v = row[fieldNames[3]];
|
|
@@ -83,7 +107,15 @@ function encodeBatch(rows) {
|
|
|
83
107
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
84
108
|
off = buf.writeUInt32LE(sl, off);
|
|
85
109
|
off += buf.write(v, off, sl, 'utf8');
|
|
86
|
-
} else
|
|
110
|
+
} else if (typeof v === 'boolean') {
|
|
111
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
112
|
+
} else {
|
|
113
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
114
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
115
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
116
|
+
off = buf.writeUInt32LE(sl, off);
|
|
117
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
118
|
+
}
|
|
87
119
|
}
|
|
88
120
|
if (nFields >= 5) {
|
|
89
121
|
const v = row[fieldNames[4]];
|
|
@@ -96,7 +128,15 @@ function encodeBatch(rows) {
|
|
|
96
128
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
97
129
|
off = buf.writeUInt32LE(sl, off);
|
|
98
130
|
off += buf.write(v, off, sl, 'utf8');
|
|
99
|
-
} else
|
|
131
|
+
} else if (typeof v === 'boolean') {
|
|
132
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
133
|
+
} else {
|
|
134
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
135
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
136
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
137
|
+
off = buf.writeUInt32LE(sl, off);
|
|
138
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
139
|
+
}
|
|
100
140
|
}
|
|
101
141
|
// fallback for >5 fields
|
|
102
142
|
for (let fi = 5; fi < nFields; fi++) {
|
|
@@ -110,7 +150,15 @@ function encodeBatch(rows) {
|
|
|
110
150
|
const sl = Buffer.byteLength(v, 'utf8');
|
|
111
151
|
off = buf.writeUInt32LE(sl, off);
|
|
112
152
|
off += buf.write(v, off, sl, 'utf8');
|
|
113
|
-
} else
|
|
153
|
+
} else if (typeof v === 'boolean') {
|
|
154
|
+
off = buf.writeUInt8(BOOL_TAG, off); off = buf.writeUInt8(v ? 1 : 0, off);
|
|
155
|
+
} else {
|
|
156
|
+
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
|
|
157
|
+
off = buf.writeUInt8(STR_TAG, off);
|
|
158
|
+
const sl = Buffer.byteLength(s, 'utf8');
|
|
159
|
+
off = buf.writeUInt32LE(sl, off);
|
|
160
|
+
off += buf.write(s, off, sl, 'utf8');
|
|
161
|
+
}
|
|
114
162
|
}
|
|
115
163
|
}
|
|
116
164
|
|
|
@@ -213,6 +261,7 @@ class JSQL {
|
|
|
213
261
|
}
|
|
214
262
|
|
|
215
263
|
async start() {
|
|
264
|
+
wasmBindings.jsql_reset();
|
|
216
265
|
this._runHooks('onStart', []);
|
|
217
266
|
this._emit('start', {});
|
|
218
267
|
}
|
|
@@ -264,6 +313,10 @@ class JSQL {
|
|
|
264
313
|
return flushed && flushed[table] ? flushed[table] : null;
|
|
265
314
|
}
|
|
266
315
|
|
|
316
|
+
async insertMany(table, data) {
|
|
317
|
+
return this.insert(table, data);
|
|
318
|
+
}
|
|
319
|
+
|
|
267
320
|
async createTable(name, schema) {
|
|
268
321
|
await this._flush();
|
|
269
322
|
if (!this._runHooks('beforeCreateTable', [name, schema])) return null;
|
|
Binary file
|