jsql-neo 6.4.4 → 6.4.5
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 +1 -1
- package/index.js +1 -1
- package/package.json +2 -2
- package/test/mongo-group.test.js +14 -0
- package/test/native.test.js +15 -15
- package/test/regress-5.1.0.js +32 -32
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **One engine to rule them all** — a Rust-powered embedded database that speaks your language:
|
|
4
4
|
> MySQL, PostgreSQL, MongoDB, Redis, SQL, TypeScript, **and the browser**.
|
|
5
5
|
|
|
6
|
-
> **v6.4.
|
|
6
|
+
> **v6.4.5** — official release build · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|

|
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsql-neo",
|
|
3
|
-
"version": "6.4.
|
|
3
|
+
"version": "6.4.5",
|
|
4
4
|
"description": "JSQL-NEO — Rust-powered embedded database with WASM, REST API, B-Tree indexes, WAL, crash recovery",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
],
|
|
47
47
|
"scripts": {
|
|
48
48
|
"postinstall": "node postinstall.js",
|
|
49
|
-
"test": "node test/smoke.js && node test/json-functions.test.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/query-opt.test.js && node test/wal-recovery.test.js && node test/mysql-compat-hijack.test.js && node test/dml-constraints.test.js",
|
|
49
|
+
"test": "node test/smoke.js && node test/native.test.js && node test/json-functions.test.js && node test/sql-parser.test.js && node test/readme-audit.test.js && node test/query-opt.test.js && node test/wal-recovery.test.js && node test/mysql-compat-hijack.test.js && node test/dml-constraints.test.js",
|
|
50
50
|
"test:parser": "node test/sql-parser.test.js",
|
|
51
51
|
"test:btree": "node test/btree.test.js",
|
|
52
52
|
"test:native": "node test/native.test.js",
|
package/test/mongo-group.test.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/* ⚠️ 已知损坏,未纳入任何 CI 套件(test:all / npm test 都不含本文件)
|
|
2
|
+
*
|
|
3
|
+
* 现状:本文件会崩在 `rows is not iterable`(lib/mongo_server.js:541)。
|
|
4
|
+
* 另外 MongoDB 协议栈与**官方现代 driver 的握手尚未打通** ——
|
|
5
|
+
* 用官方 mongodb driver 连不上。
|
|
6
|
+
*
|
|
7
|
+
* 因此「四协议」目前实际是「一个半」:MySQL 可用;PG / Redis 以库形式
|
|
8
|
+
* 提供、需自行装配;MongoDB 仅供实验。
|
|
9
|
+
* 文档已按此更正(doc/why.md、doc/cli.md)。
|
|
10
|
+
*
|
|
11
|
+
* 修好前请勿把本文件加进 CI —— 它一崩就会像之前那样掐断 `&&` 链。
|
|
12
|
+
* 修 MongoDB 需要单独排期,不属于性能/打包类改动。
|
|
13
|
+
*/
|
|
14
|
+
|
|
1
15
|
// Test: MongoDB $group aggregation operators
|
|
2
16
|
// Directly tests the _dispatch method of createMongoServer
|
|
3
17
|
const { createMongoServer } = require('../lib/mongo_server.js');
|
package/test/native.test.js
CHANGED
|
@@ -26,7 +26,7 @@ function ok(name, cond, extra) {
|
|
|
26
26
|
const ids = await db.insert('users', [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }]);
|
|
27
27
|
ok('batch insert returns ids', Array.isArray(ids) && ids.length === 2, ids);
|
|
28
28
|
|
|
29
|
-
const row = db.findById('users', 1);
|
|
29
|
+
const row = await db.findById('users', 1);
|
|
30
30
|
ok('findById returns flat row', row && row.id === 1 && row.name === 'Alice' && row.age === 30 && !('fields' in row), row);
|
|
31
31
|
|
|
32
32
|
const rows = await db.find('users', {});
|
|
@@ -35,11 +35,11 @@ function ok(name, cond, extra) {
|
|
|
35
35
|
ok('filter no match', (await db.find('users', { age: 99 })).length === 0);
|
|
36
36
|
ok('count', (await db.count('users')) === 2);
|
|
37
37
|
|
|
38
|
-
db.updateByIds('users', [[1, { age: 99 }]]);
|
|
38
|
+
await db.updateByIds('users', [[1, { age: 99 }]]);
|
|
39
39
|
await new Promise(r => setTimeout(r, 150));
|
|
40
|
-
ok('updateByIds applied', db.findById('users', 1).age === 99, db.findById('users', 1));
|
|
40
|
+
ok('updateByIds applied', (await db.findById('users', 1)).age === 99, await db.findById('users', 1));
|
|
41
41
|
|
|
42
|
-
db.removeByIds('users', [2]);
|
|
42
|
+
await db.removeByIds('users', [2]);
|
|
43
43
|
await new Promise(r => setTimeout(r, 150));
|
|
44
44
|
ok('removeByIds applied', (await db.count('users')) === 1, await db.count('users'));
|
|
45
45
|
await db.stop();
|
|
@@ -57,12 +57,12 @@ function ok(name, cond, extra) {
|
|
|
57
57
|
await db.createTable('t3', { id: { type: 'integer', primary_key: true, auto_increment: true }, name: { type: 'string' } });
|
|
58
58
|
await db.insert('t3', { name: 'a' });
|
|
59
59
|
await db.insert('t3', { id: 7, name: 'b' });
|
|
60
|
-
ok('snake_case pk respected', db.findById('t3', 7).name === 'b', db.findById('t3', 7));
|
|
61
|
-
ok('explicit pk bumps next id', db.findById('t3', 1).name === 'a');
|
|
60
|
+
ok('snake_case pk respected', (await db.findById('t3', 7)).name === 'b', await db.findById('t3', 7));
|
|
61
|
+
ok('explicit pk bumps next id', (await db.findById('t3', 1)).name === 'a');
|
|
62
62
|
|
|
63
63
|
await db.createTable('cfg', 'key string primary key, value string');
|
|
64
64
|
const cfgIds = await db.insert('cfg', { key: 'a', value: '1' });
|
|
65
|
-
ok('full shorthand string schema', cfgIds[0] === 'a' && db.findById('cfg', 'a').value === '1', cfgIds);
|
|
65
|
+
ok('full shorthand string schema', cfgIds[0] === 'a' && (await db.findById('cfg', 'a')).value === '1', cfgIds);
|
|
66
66
|
await db.stop();
|
|
67
67
|
}
|
|
68
68
|
|
|
@@ -112,23 +112,23 @@ function ok(name, cond, extra) {
|
|
|
112
112
|
const ids = await db.insert('config', [{ key: 'a', value: '1' }, { key: 'b', value: '2' }]);
|
|
113
113
|
ok('non-auto pk insert returns pk values', JSON.stringify(ids) === JSON.stringify(['a', 'b']), ids);
|
|
114
114
|
|
|
115
|
-
const a = db.findById('config', 'a');
|
|
115
|
+
const a = await db.findById('config', 'a');
|
|
116
116
|
ok('findById resolves string pk', a && a.value === '1' && !('fields' in a), a);
|
|
117
|
-
ok('findById pk miss returns null', db.findById('config', 'nope') === null);
|
|
117
|
+
ok('findById pk miss returns null', await db.findById('config', 'nope') === null);
|
|
118
118
|
|
|
119
|
-
db.updateById('config', 'b', { value: '22' });
|
|
119
|
+
await db.updateById('config', 'b', { value: '22' });
|
|
120
120
|
await new Promise(r => setTimeout(r, 150));
|
|
121
|
-
ok('updateById resolves string pk', db.findById('config', 'b').value === '22', db.findById('config', 'b'));
|
|
121
|
+
ok('updateById resolves string pk', (await db.findById('config', 'b')).value === '22', await db.findById('config', 'b'));
|
|
122
122
|
|
|
123
|
-
db.removeById('config', 'a');
|
|
123
|
+
await db.removeById('config', 'a');
|
|
124
124
|
await new Promise(r => setTimeout(r, 150));
|
|
125
125
|
ok('removeById resolves string pk', (await db.count('config')) === 1, await db.count('config'));
|
|
126
126
|
|
|
127
|
-
db.updateByIds('config', [['b', { value: '222' }]]);
|
|
127
|
+
await db.updateByIds('config', [['b', { value: '222' }]]);
|
|
128
128
|
await new Promise(r => setTimeout(r, 150));
|
|
129
|
-
ok('updateByIds resolves string pk', db.findById('config', 'b').value === '222', db.findById('config', 'b'));
|
|
129
|
+
ok('updateByIds resolves string pk', (await db.findById('config', 'b')).value === '222', await db.findById('config', 'b'));
|
|
130
130
|
|
|
131
|
-
db.removeByIds('config', ['b']);
|
|
131
|
+
await db.removeByIds('config', ['b']);
|
|
132
132
|
await new Promise(r => setTimeout(r, 150));
|
|
133
133
|
ok('removeByIds resolves string pk', (await db.count('config')) === 0, await db.count('config'));
|
|
134
134
|
await db.stop();
|
package/test/regress-5.1.0.js
CHANGED
|
@@ -90,50 +90,50 @@ function respClient(port) {
|
|
|
90
90
|
/* ============ Core engine ============ */
|
|
91
91
|
const db = new Database(':memory:', { autoSave: false });
|
|
92
92
|
await db.start();
|
|
93
|
-
db.createTable('users', { id: 'integer primary key auto_increment', name: 'string', email: 'string unique', age: 'integer' });
|
|
94
|
-
for (const [n, a] of [['A', 10], ['B', 20], ['C', 30]]) db.insert('users', { name: n, email: n.toLowerCase() + '@x', age: a });
|
|
93
|
+
await db.createTable('users', { id: 'integer primary key auto_increment', name: 'string', email: 'string unique', age: 'integer' });
|
|
94
|
+
for (const [n, a] of [['A', 10], ['B', 20], ['C', 30]]) await db.insert('users', { name: n, email: n.toLowerCase() + '@x', age: a });
|
|
95
95
|
|
|
96
96
|
{
|
|
97
|
-
const gt = db.find('users', { age: { $gt: 20 } }).map(r => r.name);
|
|
97
|
+
const gt = (await db.find('users', { age: { $gt: 20 } })).map(r => r.name);
|
|
98
98
|
ok('find $gt excludes boundary', JSON.stringify(gt) === '["C"]', gt);
|
|
99
|
-
const lt = db.find('users', { age: { $lt: 20 } }).map(r => r.name);
|
|
99
|
+
const lt = (await db.find('users', { age: { $lt: 20 } })).map(r => r.name);
|
|
100
100
|
ok('find $lt excludes boundary', JSON.stringify(lt) === '["A"]', lt);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
{
|
|
104
|
-
db.removeById('users', 2); // B (id=2) removed, C still id=3
|
|
105
|
-
ok('removeById with PK count', db.count('users') === 2, db.count('users'));
|
|
106
|
-
ok('removeById PK lookup null', db.findById('users', 2) === null);
|
|
107
|
-
ok('removeById B-Tree still consistent', db.find('users', { age: { $gt: 15 } }).length === 1);
|
|
104
|
+
await db.removeById('users', 2); // B (id=2) removed, C still id=3
|
|
105
|
+
ok('removeById with PK count', await db.count('users') === 2, await db.count('users'));
|
|
106
|
+
ok('removeById PK lookup null', await db.findById('users', 2) === null);
|
|
107
|
+
ok('removeById B-Tree still consistent', (await db.find('users', { age: { $gt: 15 } })).length === 1);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
{
|
|
111
|
-
db.createTable('np', { v: 'string', n: 'integer' });
|
|
112
|
-
for (let i = 0; i < 10; i++) db.insert('np', { v: 'v' + i, n: i });
|
|
113
|
-
db.createTable('h', { id: 'integer primary key auto_increment', grp: 'string', val: 'integer' });
|
|
114
|
-
for (let i = 0; i < 12; i++) db.insert('h', { grp: 'g' + (i % 4), val: i });
|
|
111
|
+
await db.createTable('np', { v: 'string', n: 'integer' });
|
|
112
|
+
for (let i = 0; i < 10; i++) await db.insert('np', { v: 'v' + i, n: i });
|
|
113
|
+
await db.createTable('h', { id: 'integer primary key auto_increment', grp: 'string', val: 'integer' });
|
|
114
|
+
for (let i = 0; i < 12; i++) await db.insert('h', { grp: 'g' + (i % 4), val: i });
|
|
115
115
|
db._tables.h.createIndex('grp');
|
|
116
116
|
|
|
117
|
-
db.removeByIds('np', [1, 2]);
|
|
118
|
-
ok('removeByIds no-PK rebuilds indexes', db.find('np').length === 8, db.find('np').length);
|
|
117
|
+
await db.removeByIds('np', [1, 2]);
|
|
118
|
+
ok('removeByIds no-PK rebuilds indexes', (await db.find('np')).length === 8, (await db.find('np')).length);
|
|
119
119
|
|
|
120
|
-
const pre = db.find('h', { grp: 'g1' }).map(r => r.id).sort((a, b) => a - b);
|
|
121
|
-
db.removeById('h', 1); db.removeById('h', 5); db.removeById('h', 9); // the g0 rows
|
|
122
|
-
const post = db.find('h', { grp: 'g1' }).map(r => r.id).sort((a, b) => a - b);
|
|
120
|
+
const pre = (await db.find('h', { grp: 'g1' })).map(r => r.id).sort((a, b) => a - b);
|
|
121
|
+
await db.removeById('h', 1); await db.removeById('h', 5); await db.removeById('h', 9); // the g0 rows
|
|
122
|
+
const post = (await db.find('h', { grp: 'g1' })).map(r => r.id).sort((a, b) => a - b);
|
|
123
123
|
ok('hash index survives swap-pop (g1 intact)', JSON.stringify(post) === JSON.stringify(pre), { pre, post });
|
|
124
|
-
ok('hash index has no stale g0 rows', db.find('h', { grp: 'g0' }).length === 0);
|
|
124
|
+
ok('hash index has no stale g0 rows', (await db.find('h', { grp: 'g0' })).length === 0);
|
|
125
125
|
let stale = 0;
|
|
126
126
|
for (const list of db._tables.h._indexes.grp.values()) for (const i of list) if (!db._tables.h._rows[i]) stale++;
|
|
127
127
|
ok('hash index zero stale entries', stale === 0, stale);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
{
|
|
131
|
-
db.createTable('docs', { id: 'integer primary key', data: 'string' });
|
|
132
|
-
db.insert('docs', { id: 1, data: JSON.stringify({ a: { b: 1 }, list: [1, 2, 3] }) });
|
|
131
|
+
await db.createTable('docs', { id: 'integer primary key', data: 'string' });
|
|
132
|
+
await db.insert('docs', { id: 1, data: JSON.stringify({ a: { b: 1 }, list: [1, 2, 3] }) });
|
|
133
133
|
db.begin();
|
|
134
|
-
db.updateById('docs', 1, { data: JSON.stringify({ a: { b: 2 }, list: [9] }) });
|
|
134
|
+
await db.updateById('docs', 1, { data: JSON.stringify({ a: { b: 2 }, list: [9] }) });
|
|
135
135
|
db.rollback();
|
|
136
|
-
const d = JSON.parse(db.findById('docs', 1).data);
|
|
136
|
+
const d = JSON.parse((await db.findById('docs', 1)).data);
|
|
137
137
|
ok('transaction snapshot deep-copies nested object', d.a.b === 1, d);
|
|
138
138
|
ok('transaction snapshot deep-copies arrays', JSON.stringify(d.list) === '[1,2,3]', d.list);
|
|
139
139
|
}
|
|
@@ -148,31 +148,31 @@ function respClient(port) {
|
|
|
148
148
|
ok('parseFieldShorthand default', s3.default === 'x' && s3.type === 'string', s3);
|
|
149
149
|
|
|
150
150
|
let e = null;
|
|
151
|
-
try { db.insert('users', { name: 'X', email: 'a@x', age: 1 }); } catch (err) { e = err; }
|
|
151
|
+
try { await db.insert('users', { name: 'X', email: 'a@x', age: 1 }); } catch (err) { e = err; }
|
|
152
152
|
ok('duplicate unique throws ER_DUP_ENTRY', e && (e.code === 1062 || String(e).includes('1062')), e && (e.code || e.message));
|
|
153
|
-
db.createTable('pk2', { a: 'integer primary key', b: 'string' });
|
|
154
|
-
db.insert('pk2', { a: 1, b: 'x' });
|
|
153
|
+
await db.createTable('pk2', { a: 'integer primary key', b: 'string' });
|
|
154
|
+
await db.insert('pk2', { a: 1, b: 'x' });
|
|
155
155
|
e = null;
|
|
156
|
-
try { db.insert('pk2', { a: 1, b: 'y' }); } catch (err) { e = err; }
|
|
156
|
+
try { await db.insert('pk2', { a: 1, b: 'y' }); } catch (err) { e = err; }
|
|
157
157
|
ok('duplicate primary key throws ER_DUP_ENTRY', e && (e.code === 1062 || String(e).includes('1062')), e && (e.code || e.message));
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
{
|
|
161
161
|
const r = await migrate.importFromJSON(db, { table: 't1', schema: { id: 'integer primary key' }, rows: [{ id: 1 }, { id: 2 }] });
|
|
162
|
-
ok('importFromJSON single-table shape', r && db.count('t1') === 2);
|
|
162
|
+
ok('importFromJSON single-table shape', r && await db.count('t1') === 2);
|
|
163
163
|
let threw = null;
|
|
164
164
|
try { await migrate.importFromJSON(db, { table: 't1', schema: { id: 'integer primary key' }, rows: [{ id: 3 }] }); } catch (err) { threw = err; }
|
|
165
165
|
ok('importFromJSON refuses existing table without overwrite', !!threw, threw && (threw.message || String(threw)));
|
|
166
166
|
await migrate.importFromJSON(db, { table: 't1', schema: { id: 'integer primary key' }, rows: [{ id: 3 }] }, { overwrite: true });
|
|
167
|
-
ok('importFromJSON overwrite replaces table', db.count('t1') === 1, db.count('t1'));
|
|
167
|
+
ok('importFromJSON overwrite replaces table', await db.count('t1') === 1, await db.count('t1'));
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
{
|
|
171
|
-
db.createTable('lk', { s: 'string' });
|
|
172
|
-
for (const s of ['a.b', 'axb', 'aXb', 'abc']) db.insert('lk', { s });
|
|
173
|
-
const m = db.find('lk', { s: { $like: 'a.b' } }).map(r => r.s);
|
|
171
|
+
await db.createTable('lk', { s: 'string' });
|
|
172
|
+
for (const s of ['a.b', 'axb', 'aXb', 'abc']) await db.insert('lk', { s });
|
|
173
|
+
const m = (await db.find('lk', { s: { $like: 'a.b' } })).map(r => r.s);
|
|
174
174
|
ok('$like escapes regex metacharacters', JSON.stringify(m) === '["a.b"]', m);
|
|
175
|
-
const m2 = db.find('lk', { s: { $like: 'a%b' } }).map(r => r.s);
|
|
175
|
+
const m2 = (await db.find('lk', { s: { $like: 'a%b' } })).map(r => r.s);
|
|
176
176
|
ok('$like % wildcard still works', JSON.stringify(m2) === '["a.b","axb","aXb"]', m2);
|
|
177
177
|
}
|
|
178
178
|
await db.stop();
|