jsql-neo 6.4.8 → 6.5.0-beta.3
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 +25 -19
- package/bin/jsql +23 -0
- package/index.js +1 -1
- package/lib/star-nag.js +206 -0
- package/lib/table.js +14 -0
- package/package.json +1 -1
- package/test/native.test.js +37 -0
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.
|
|
6
|
+
> **v6.5.0-beta.3** — pre-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
|

|
|
@@ -36,12 +36,18 @@ irm jsql.vexify.top/setup | iex
|
|
|
36
36
|
npm install jsql-neo
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
**JSQL-NEO** is a Rust-powered embedded database with **zero runtime dependencies
|
|
39
|
+
**JSQL-NEO** is a Rust-powered embedded database with **zero runtime dependencies**. It runs in Node.js, CLI, Web UI, and the browser (WASM).
|
|
40
40
|
|
|
41
|
-
- **
|
|
41
|
+
- **MySQL wire protocol, ready to use** — `jsql serve` starts it; `mysql2` / most MySQL clients connect directly
|
|
42
42
|
- **Zero dependencies** — no native libs to compile, no system deps to install
|
|
43
|
-
- **
|
|
44
|
-
- **~2× faster than better-sqlite3**
|
|
43
|
+
- **Three engines, same API** — `native` (Rust N-API), `wasm` (same Rust core), `js` (pure JS)
|
|
44
|
+
- **~2× faster than better-sqlite3** on indexed point lookups
|
|
45
|
+
|
|
46
|
+
> **About the other wire protocols** — PostgreSQL, MongoDB and Redis protocol stacks
|
|
47
|
+
> ship as libraries (`lib/pg_server`, `lib/mongo_server`, `lib/redis_server`) and each
|
|
48
|
+
> listens on its own port; there is **no single-port multi-protocol mode**, and the CLI
|
|
49
|
+
> exposes no entry point for them. MongoDB additionally does not yet complete a
|
|
50
|
+
> handshake with the modern official `mongodb` driver. Treat them as experimental.
|
|
45
51
|
|
|
46
52
|
---
|
|
47
53
|
|
|
@@ -88,36 +94,35 @@ console.log(rows); // [[1, 'Alice']]
|
|
|
88
94
|
db.stop();
|
|
89
95
|
```
|
|
90
96
|
|
|
91
|
-
###
|
|
97
|
+
### Wire protocol server
|
|
92
98
|
|
|
93
99
|
```bash
|
|
94
|
-
|
|
100
|
+
jsql serve --port 3306 --data-dir ./data
|
|
95
101
|
```
|
|
96
102
|
|
|
97
103
|
```bash
|
|
98
|
-
# MySQL
|
|
99
|
-
|
|
100
|
-
# MongoDB mongosh mongodb://127.0.0.1:3306
|
|
101
|
-
# Redis redis-cli -p 3306
|
|
104
|
+
# MySQL clients (mysql CLI, mysql2, DBeaver, DataGrip …) connect here
|
|
105
|
+
mysql -h 127.0.0.1 -P 3306
|
|
102
106
|
```
|
|
103
107
|
|
|
104
|
-
|
|
108
|
+
Only MySQL is served by the CLI today. The PostgreSQL / Redis / MongoDB stacks are
|
|
109
|
+
available as libraries — see the note near the top of this file.
|
|
105
110
|
|
|
106
111
|
### Browser / WASM
|
|
107
112
|
|
|
108
113
|
```js
|
|
109
|
-
import init, {
|
|
114
|
+
import init, { JSQL } from 'jsql-neo/wasm/browser.mjs';
|
|
110
115
|
await init();
|
|
111
|
-
const db = new
|
|
112
|
-
// same API as Node.js
|
|
116
|
+
const db = new JSQL();
|
|
117
|
+
// same API as the Node.js native client
|
|
113
118
|
```
|
|
114
119
|
|
|
115
120
|
### 🦀 NativeJSQL
|
|
116
121
|
|
|
117
122
|
Pure Rust native bindings — the highest-performance way to run JSQL-NEO:
|
|
118
123
|
|
|
119
|
-
- **
|
|
120
|
-
- **Batch operations** —
|
|
124
|
+
- **Low abstraction overhead** — direct calls into the Rust core
|
|
125
|
+
- **Batch operations** — ~700k rows/sec measured on 200k rows (`INSERT` in 5k batches)
|
|
121
126
|
- **Automatic memory management** with smart caching
|
|
122
127
|
|
|
123
128
|
**Install:**
|
|
@@ -129,8 +134,9 @@ npm install jsql-neo
|
|
|
129
134
|
**Usage:**
|
|
130
135
|
|
|
131
136
|
```javascript
|
|
132
|
-
|
|
133
|
-
const db = new
|
|
137
|
+
const { NativeJSQL } = require('jsql-neo');
|
|
138
|
+
const db = new NativeJSQL(); // :memory: — persist by passing a path
|
|
139
|
+
await db.start();
|
|
134
140
|
```
|
|
135
141
|
|
|
136
142
|
### Storage modes
|
package/bin/jsql
CHANGED
|
@@ -5,6 +5,12 @@ const yaggs = require('@vexify-org/yaggs');
|
|
|
5
5
|
const { ModuleManager } = require('../lib/mod');
|
|
6
6
|
const Database = require('../lib/database');
|
|
7
7
|
const migrate = require('../lib/migrate');
|
|
8
|
+
const { nag, setStarred, readConfig } = require('../lib/star-nag');
|
|
9
|
+
|
|
10
|
+
// star 提示:任何异常都不该挡住命令本身
|
|
11
|
+
if (!process.env.JSQL_NO_STAR_NAG && process.argv[2] !== 'star') {
|
|
12
|
+
try { nag(); } catch (e) { /* 提示失败与命令无关 */ }
|
|
13
|
+
}
|
|
8
14
|
|
|
9
15
|
function printModules(list) {
|
|
10
16
|
if (list.length === 0) {
|
|
@@ -168,6 +174,23 @@ const cli = yaggs({ pkg: require('../package.json') })
|
|
|
168
174
|
console.log(`jsql-neo MySQL server on ${options.host}:${options.port}${options.dataDir ? ' (data: ' + options.dataDir + ')' : ' (in-memory)'}`);
|
|
169
175
|
setInterval(() => {}, 1 << 30);
|
|
170
176
|
})
|
|
177
|
+
.command('star', 'Confirm whether you starred this repo (opens browser once)', (sub) => {
|
|
178
|
+
sub.option('reset', { type: 'boolean', description: 'Forget the saved star state and re-check' });
|
|
179
|
+
}, async (argv) => {
|
|
180
|
+
const sn = require('../lib/star-nag');
|
|
181
|
+
if (argv.reset) sn.setStarred(false);
|
|
182
|
+
const c = sn.readConfig();
|
|
183
|
+
if (c.starred) {
|
|
184
|
+
console.log('Already confirmed starred (config: ' + sn.configPath() + ')');
|
|
185
|
+
console.log('Run with --reset to re-check.');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
console.log('Opening browser to confirm your star…');
|
|
189
|
+
const nonceUrl = sn.startOauthCheck(); // 打开浏览器 + 后台轮询写回 ~/.jsqlmr
|
|
190
|
+
if (!process.stdout.isTTY) console.log(' ' + nonceUrl);
|
|
191
|
+
console.log('After you authorize, this config is updated: ' + sn.configPath());
|
|
192
|
+
console.log('Run `jsql star` again afterwards to see the result.');
|
|
193
|
+
})
|
|
171
194
|
.command('bench', 'Insert + query benchmark against a data directory', (sub) => {
|
|
172
195
|
sub.option('n', { type: 'number', description: 'Number of rows (default 10000)' });
|
|
173
196
|
sub.option('data-dir', { type: 'string', description: 'Data directory (default :memory:)' });
|
package/index.js
CHANGED
package/lib/star-nag.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* CLI 启动时的 star 提示。
|
|
4
|
+
*
|
|
5
|
+
* 行为:
|
|
6
|
+
* 1. 已确认 star 过 → 什么都不说
|
|
7
|
+
* 2. 距上次提示不足 N 天 → 什么都不说
|
|
8
|
+
* 3. 否则打印一行提示,并在配置里记下时间
|
|
9
|
+
*
|
|
10
|
+
* star 检测:若环境里有 GitHub token(GITHUB_TOKEN / GH_TOKEN),
|
|
11
|
+
* 就问 GitHub「这个用户 star 过没有」。查到了就记住,以后彻底闭嘴 ——
|
|
12
|
+
* 用户已经 star 过了,再提就是噪音。
|
|
13
|
+
*
|
|
14
|
+
* 配置文件:~/.jsqlmr(JSON)。可用 JSQL_MR_PATH 覆盖。
|
|
15
|
+
*
|
|
16
|
+
* 全程不影响命令本身:任何异常都吞掉,绝不因为提示语让 CLI 起不来。
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
|
|
23
|
+
const REPO = 'vexify-org/JSQL-neo';
|
|
24
|
+
const URL = `https://github.com/${REPO}`;
|
|
25
|
+
const NAG_INTERVAL_DAYS = 30;
|
|
26
|
+
|
|
27
|
+
const AUTH_BASE = process.env.JSQL_AUTH_BASE || 'https://auth.vexify.top';
|
|
28
|
+
const AUTH_START = AUTH_BASE + '/start.php';
|
|
29
|
+
const AUTH_RESULT = AUTH_BASE + '/result.php';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 发起 OAuth 浏览器流并在后台轮询结果。
|
|
33
|
+
*
|
|
34
|
+
* 绝不阻塞命令:开完浏览器就返回,轮询用 unref 过的定时器跑。
|
|
35
|
+
* 拿到结果写进 ~/.jsqlmr(starred: true/false)。
|
|
36
|
+
* 进程提前退出就放弃这一次,下次启动会再提示(30 天节流管频率)。
|
|
37
|
+
*/
|
|
38
|
+
function startOauthCheck() {
|
|
39
|
+
const crypto = require('crypto');
|
|
40
|
+
const nonce = crypto.randomBytes(24).toString('base64url');
|
|
41
|
+
const url = AUTH_START + '?nonce=' + nonce;
|
|
42
|
+
|
|
43
|
+
// 开浏览器:三平台各一个命令;失败就只打印链接让人手动点
|
|
44
|
+
const cmd = process.platform === 'win32' ? 'start'
|
|
45
|
+
: process.platform === 'darwin' ? 'open' : 'xdg-open';
|
|
46
|
+
try {
|
|
47
|
+
require('child_process').spawn(cmd, [url], {
|
|
48
|
+
detached: true, stdio: 'ignore', shell: process.platform === 'win32',
|
|
49
|
+
}).unref();
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.log(' Open this to confirm your star: ' + url);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 后台轮询,最多约 90 秒
|
|
55
|
+
let tries = 0;
|
|
56
|
+
const t = setInterval(() => {
|
|
57
|
+
if (++tries > 45) { clearInterval(t); return; }
|
|
58
|
+
const { execFile } = require('child_process');
|
|
59
|
+
execFile('curl', ['-sS', '-m', '5', AUTH_RESULT + '?nonce=' + nonce],
|
|
60
|
+
{ timeout: 6000, encoding: 'utf8' }, (err, stdout) => {
|
|
61
|
+
if (err) return;
|
|
62
|
+
let j = null;
|
|
63
|
+
try { j = JSON.parse(stdout); } catch (e) { return; }
|
|
64
|
+
if (!j || j.state !== 'done' || !j.result) return;
|
|
65
|
+
clearInterval(t);
|
|
66
|
+
const cfg = readConfig();
|
|
67
|
+
cfg.oauthCheckedAt = Date.now();
|
|
68
|
+
cfg.login = j.result.login || undefined;
|
|
69
|
+
cfg.starred = !!j.result.starred;
|
|
70
|
+
if (cfg.starred) cfg.starredAt = Date.now();
|
|
71
|
+
writeConfig(cfg);
|
|
72
|
+
});
|
|
73
|
+
}, 2000);
|
|
74
|
+
t.unref();
|
|
75
|
+
return url;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function configPath() {
|
|
79
|
+
return process.env.JSQL_MR_PATH || path.join(os.homedir(), '.jsqlmr');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readConfig() {
|
|
83
|
+
try {
|
|
84
|
+
const raw = fs.readFileSync(configPath(), 'utf8');
|
|
85
|
+
const c = JSON.parse(raw);
|
|
86
|
+
return (c && typeof c === 'object') ? c : {};
|
|
87
|
+
} catch (e) {
|
|
88
|
+
return {}; // 不存在 / 坏了 / 没权限,都当新用户
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function writeConfig(cfg) {
|
|
93
|
+
try {
|
|
94
|
+
fs.writeFileSync(configPath(), JSON.stringify(cfg, null, 2) + '\n');
|
|
95
|
+
} catch (e) {
|
|
96
|
+
/* 写不了就算了,不该因此报错 */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** 同步问一下 GitHub:这个身份 star 过没有。查不到就返回 null(三态)。 */
|
|
101
|
+
/**
|
|
102
|
+
* 找一个可用的 GitHub 凭据。
|
|
103
|
+
* 1. GITHUB_TOKEN / GH_TOKEN 环境变量
|
|
104
|
+
* 2. 官方 gh CLI(`gh auth token`)—— 多数开发机上它已经登录过了,
|
|
105
|
+
* 不该要求用户为了看一句提示语再去配环境变量
|
|
106
|
+
* 3. 都没有 → null
|
|
107
|
+
*/
|
|
108
|
+
function findToken() {
|
|
109
|
+
const env = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
|
|
110
|
+
if (env) return env;
|
|
111
|
+
try {
|
|
112
|
+
const { execFileSync } = require('child_process');
|
|
113
|
+
const t = execFileSync('gh', ['auth', 'token'], {
|
|
114
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
115
|
+
timeout: 2500,
|
|
116
|
+
encoding: 'utf8',
|
|
117
|
+
}).trim();
|
|
118
|
+
if (t) return t;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// 没装 gh / 没登录 / 太慢 —— 都当作没有
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* 尽力而为地问一次「这个身份 star 过没有」。查不到返回 null(三态)。
|
|
127
|
+
*
|
|
128
|
+
* 只在「真的准备显示提示语时」才发这个网络请求;已标记 starred 或被
|
|
129
|
+
* 30 天节流挡掉时一次请求都不会发。
|
|
130
|
+
*
|
|
131
|
+
* @returns {boolean|null} true=star 过 false=没 star null=无法确认
|
|
132
|
+
*/
|
|
133
|
+
function checkStarred() {
|
|
134
|
+
const token = findToken();
|
|
135
|
+
if (!token) return null; // 没有可用凭据 → 无法确认
|
|
136
|
+
// 用同步 API:CLI 启动阶段还没有 event loop 可用
|
|
137
|
+
try {
|
|
138
|
+
const { execFileSync } = require('child_process');
|
|
139
|
+
const out = execFileSync('curl', [
|
|
140
|
+
'-sS', '-m', '4',
|
|
141
|
+
'-H', `Authorization: Bearer ${token}`,
|
|
142
|
+
'-H', 'Accept: application/vnd.github+json',
|
|
143
|
+
'-H', 'X-GitHub-Api-Version: 2022-11-28',
|
|
144
|
+
`https://api.github.com/user/starred/${REPO}`,
|
|
145
|
+
], { stdio: ['ignore', 'pipe', 'ignore'], timeout: 5000 }).toString();
|
|
146
|
+
if (out.trim() === '') return true; // 200 + 空数组 = 列了但没有这个仓库
|
|
147
|
+
const j = JSON.parse(out);
|
|
148
|
+
// GitHub 出错时返回的是 {"message":"Bad credentials"} 之类,不是数组。
|
|
149
|
+
// 那说明 token 无效/过期 —— 属于「无法确认」,不能当成「没 star」,
|
|
150
|
+
// 否则会永远提示下去。
|
|
151
|
+
if (j && !Array.isArray(j) && typeof j.message === 'string') return null;
|
|
152
|
+
return Array.isArray(j) && j.length > 0;
|
|
153
|
+
} catch (e) {
|
|
154
|
+
return null; // 网络不通 / 401 / 没装 curl → 不确定
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* @param {object} [opts]
|
|
160
|
+
* @param {NodeJS.WritableStream} [opts.out] 输出流(默认 stdout)
|
|
161
|
+
* @param {boolean} [opts.force] 忽略节流,强制提示一次
|
|
162
|
+
* @returns {boolean} 是否真的打印了
|
|
163
|
+
*/
|
|
164
|
+
function nag(opts = {}) {
|
|
165
|
+
const out = opts.out || process.stdout;
|
|
166
|
+
const cfg = readConfig();
|
|
167
|
+
|
|
168
|
+
if (!opts.force && cfg.starred) return false;
|
|
169
|
+
|
|
170
|
+
const last = Number(cfg.lastNagAt) || 0;
|
|
171
|
+
if (!opts.force && last && Date.now() - last < NAG_INTERVAL_DAYS * 86400000) {
|
|
172
|
+
// 顺便有机会补记 star 状态(不打印)
|
|
173
|
+
const s = checkStarred();
|
|
174
|
+
if (s) { cfg.starred = true; writeConfig(cfg); }
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 有 token 就先查,省得对已经 star 的人重复啰嗦
|
|
179
|
+
const starred = checkStarred();
|
|
180
|
+
if (starred) {
|
|
181
|
+
cfg.starred = true;
|
|
182
|
+
cfg.starredAt = Date.now();
|
|
183
|
+
writeConfig(cfg);
|
|
184
|
+
return false; // 已 star,闭嘴
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
out.write(`\n If JSQL-NEO saved you time, a star helps others find it: ${URL}\n`);
|
|
188
|
+
out.write(` Run \`jsql star\` to confirm and stop seeing this (or set JSQL_NO_STAR_NAG=1 to hide)\n\n`);
|
|
189
|
+
startOauthCheck();
|
|
190
|
+
|
|
191
|
+
cfg.lastNagAt = Date.now();
|
|
192
|
+
writeConfig(cfg);
|
|
193
|
+
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** 供 `jsql star` 之类的命令用:手动确认 / 取消 */
|
|
198
|
+
function setStarred(v) {
|
|
199
|
+
const cfg = readConfig();
|
|
200
|
+
cfg.starred = !!v;
|
|
201
|
+
if (v) cfg.starredAt = Date.now();
|
|
202
|
+
writeConfig(cfg);
|
|
203
|
+
return cfg.starred;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = { nag, checkStarred, startOauthCheck, readConfig, setStarred, configPath, REPO, URL };
|
package/lib/table.js
CHANGED
|
@@ -146,6 +146,20 @@ class Table {
|
|
|
146
146
|
this._dateFields = {}; // { fieldName: 'date'|'datetime'|'timestamp' }
|
|
147
147
|
|
|
148
148
|
for (const [field, def] of Object.entries(schema)) {
|
|
149
|
+
// schema 字段名归一化:驼峰 primaryKey/autoIncrement 与下划线
|
|
150
|
+
// primary_key/auto_increment 两种写法都要认。
|
|
151
|
+
//
|
|
152
|
+
// 此前这里只认驼峰,而 native_client 在交给 Rust 之前会归一化
|
|
153
|
+
// (lib/native_client.js 里 primary_key → primaryKey)。结果:
|
|
154
|
+
// README 与官方示例用的下划线写法,在 native 下正常,在纯 JS 下
|
|
155
|
+
// **静默失效** —— 自增 id 不生成,find({id:1}) 永远返回空,
|
|
156
|
+
// 而且不报任何错。这是纯 JS 与 native 的行为分歧。
|
|
157
|
+
if (def && typeof def === 'object' && !Array.isArray(def)) {
|
|
158
|
+
if (def.primary_key !== undefined && def.primaryKey === undefined) def.primaryKey = def.primary_key;
|
|
159
|
+
if (def.auto_increment !== undefined && def.autoIncrement === undefined) def.autoIncrement = def.auto_increment;
|
|
160
|
+
if (def.primary_key !== undefined) delete def.primary_key;
|
|
161
|
+
if (def.auto_increment !== undefined) delete def.auto_increment;
|
|
162
|
+
}
|
|
149
163
|
const isPk = !!(def.primaryKey || def.primary === true);
|
|
150
164
|
if (isPk) this._primaryKey = field;
|
|
151
165
|
if (def.autoIncrement) {
|
package/package.json
CHANGED
package/test/native.test.js
CHANGED
|
@@ -151,6 +151,43 @@ function ok(name, cond, extra) {
|
|
|
151
151
|
await db.stop();
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
/* ---- schema 字段名下划线写法:两引擎必须一致(静默正确性 bug)---- */
|
|
155
|
+
/*
|
|
156
|
+
* README 与官方示例用下划线写法(primary_key / auto_increment)。
|
|
157
|
+
* native_client 交给 Rust 前会归一化,纯 JS 的 table.js 此前不认 ——
|
|
158
|
+
* 结果纯 JS 下自增 id 根本不生成、find({id:1}) 永远空,且**不报任何错**。
|
|
159
|
+
*/
|
|
160
|
+
{
|
|
161
|
+
const SNAKE = { id: { type: 'integer', primary_key: true, auto_increment: true }, name: { type: 'string' } };
|
|
162
|
+
|
|
163
|
+
// native
|
|
164
|
+
{
|
|
165
|
+
const d = new JSQL();
|
|
166
|
+
await d.start();
|
|
167
|
+
await d.createTable('snk', SNAKE);
|
|
168
|
+
await d.insert('snk', [{ name: 'a' }, { name: 'b' }]);
|
|
169
|
+
await new Promise(r => setTimeout(r, 200));
|
|
170
|
+
const rows = await d.find('snk', {});
|
|
171
|
+
const first = rows.find(r => r.name === 'a');
|
|
172
|
+
ok('schema 下划线写法 · native:自增 id 生成', !!(first && first.id !== undefined), rows);
|
|
173
|
+
const got = await d.findById('snk', first && first.id);
|
|
174
|
+
ok('schema 下划线写法 · native:findById 命中', !!(got && got.name === 'a'), got);
|
|
175
|
+
await d.stop();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// pure JS
|
|
179
|
+
{
|
|
180
|
+
const Database = require(path.join(ROOT, 'lib', 'database'));
|
|
181
|
+
const d = new Database(':memory:');
|
|
182
|
+
await d.createTable('snk', SNAKE);
|
|
183
|
+
await d.insert('snk', [{ name: 'a' }, { name: 'b' }]);
|
|
184
|
+
const rows = await d.find('snk', {});
|
|
185
|
+
const first = rows.find(r => r.name === 'a');
|
|
186
|
+
ok('schema 下划线写法 · pure-js:自增 id 生成', !!(first && first.id !== undefined), rows);
|
|
187
|
+
const got = await d.findById('snk', first && first.id);
|
|
188
|
+
ok('schema 下划线写法 · pure-js:findById 命中', !!(got && got.name === 'a'), got);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
154
191
|
console.log(`\n${passed} passed, ${failed} failed`);
|
|
155
192
|
process.exit(failed ? 1 : 0);
|
|
156
193
|
})().catch(e => {
|