@fett/sql-translator 0.0.1-beta
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 +191 -0
- package/lib/client/client.d.ts +59 -0
- package/lib/client/client.d.ts.map +1 -0
- package/lib/client/client.js +201 -0
- package/lib/client/client.js.map +1 -0
- package/lib/client/index.d.ts +15 -0
- package/lib/client/index.d.ts.map +1 -0
- package/lib/client/index.js +15 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/manager.d.ts +27 -0
- package/lib/client/manager.d.ts.map +1 -0
- package/lib/client/manager.js +73 -0
- package/lib/client/manager.js.map +1 -0
- package/lib/client/registry.d.ts +31 -0
- package/lib/client/registry.d.ts.map +1 -0
- package/lib/client/registry.js +128 -0
- package/lib/client/registry.js.map +1 -0
- package/lib/core/cache.d.ts +28 -0
- package/lib/core/cache.d.ts.map +1 -0
- package/lib/core/cache.js +58 -0
- package/lib/core/cache.js.map +1 -0
- package/lib/core/config.d.ts +16 -0
- package/lib/core/config.d.ts.map +1 -0
- package/lib/core/config.js +47 -0
- package/lib/core/config.js.map +1 -0
- package/lib/core/field-mapper/mysql.d.ts +42 -0
- package/lib/core/field-mapper/mysql.d.ts.map +1 -0
- package/lib/core/field-mapper/mysql.js +129 -0
- package/lib/core/field-mapper/mysql.js.map +1 -0
- package/lib/core/field-mapper/postgresql.d.ts +25 -0
- package/lib/core/field-mapper/postgresql.d.ts.map +1 -0
- package/lib/core/field-mapper/postgresql.js +121 -0
- package/lib/core/field-mapper/postgresql.js.map +1 -0
- package/lib/core/sql/normalize.d.ts +10 -0
- package/lib/core/sql/normalize.d.ts.map +1 -0
- package/lib/core/sql/normalize.js +121 -0
- package/lib/core/sql/normalize.js.map +1 -0
- package/lib/core/sql/pagination.d.ts +22 -0
- package/lib/core/sql/pagination.d.ts.map +1 -0
- package/lib/core/sql/pagination.js +61 -0
- package/lib/core/sql/pagination.js.map +1 -0
- package/lib/core/sql/statement.d.ts +28 -0
- package/lib/core/sql/statement.d.ts.map +1 -0
- package/lib/core/sql/statement.js +155 -0
- package/lib/core/sql/statement.js.map +1 -0
- package/lib/core/sql/table-mapper.d.ts +24 -0
- package/lib/core/sql/table-mapper.d.ts.map +1 -0
- package/lib/core/sql/table-mapper.js +113 -0
- package/lib/core/sql/table-mapper.js.map +1 -0
- package/lib/core/task-queue.d.ts +31 -0
- package/lib/core/task-queue.d.ts.map +1 -0
- package/lib/core/task-queue.js +185 -0
- package/lib/core/task-queue.js.map +1 -0
- package/lib/core/worker/bun-worker.d.ts +21 -0
- package/lib/core/worker/bun-worker.d.ts.map +1 -0
- package/lib/core/worker/bun-worker.js +93 -0
- package/lib/core/worker/bun-worker.js.map +1 -0
- package/lib/core/worker/index.d.ts +16 -0
- package/lib/core/worker/index.d.ts.map +1 -0
- package/lib/core/worker/index.js +16 -0
- package/lib/core/worker/index.js.map +1 -0
- package/lib/core/worker/node-worker.d.ts +19 -0
- package/lib/core/worker/node-worker.d.ts.map +1 -0
- package/lib/core/worker/node-worker.js +94 -0
- package/lib/core/worker/node-worker.js.map +1 -0
- package/lib/core/worker/task-runner-bun.d.ts +2 -0
- package/lib/core/worker/task-runner-bun.d.ts.map +1 -0
- package/lib/core/worker/task-runner-bun.js +18 -0
- package/lib/core/worker/task-runner-bun.js.map +1 -0
- package/lib/core/worker/task-runner.d.ts +2 -0
- package/lib/core/worker/task-runner.d.ts.map +1 -0
- package/lib/core/worker/task-runner.js +21 -0
- package/lib/core/worker/task-runner.js.map +1 -0
- package/lib/driver/index.d.ts +3 -0
- package/lib/driver/index.d.ts.map +1 -0
- package/lib/driver/index.js +16 -0
- package/lib/driver/index.js.map +1 -0
- package/lib/driver/interface.d.ts +39 -0
- package/lib/driver/interface.d.ts.map +1 -0
- package/lib/driver/interface.js +2 -0
- package/lib/driver/interface.js.map +1 -0
- package/lib/driver/mongodb/dml-translator.d.ts +21 -0
- package/lib/driver/mongodb/dml-translator.d.ts.map +1 -0
- package/lib/driver/mongodb/dml-translator.js +127 -0
- package/lib/driver/mongodb/dml-translator.js.map +1 -0
- package/lib/driver/mongodb/index.d.ts +27 -0
- package/lib/driver/mongodb/index.d.ts.map +1 -0
- package/lib/driver/mongodb/index.js +263 -0
- package/lib/driver/mongodb/index.js.map +1 -0
- package/lib/driver/mongodb/pool.d.ts +31 -0
- package/lib/driver/mongodb/pool.d.ts.map +1 -0
- package/lib/driver/mongodb/pool.js +96 -0
- package/lib/driver/mongodb/pool.js.map +1 -0
- package/lib/driver/mongodb/schema.d.ts +37 -0
- package/lib/driver/mongodb/schema.d.ts.map +1 -0
- package/lib/driver/mongodb/schema.js +238 -0
- package/lib/driver/mongodb/schema.js.map +1 -0
- package/lib/driver/mongodb/sql-translator.d.ts +19 -0
- package/lib/driver/mongodb/sql-translator.d.ts.map +1 -0
- package/lib/driver/mongodb/sql-translator.js +30 -0
- package/lib/driver/mongodb/sql-translator.js.map +1 -0
- package/lib/driver/mysql/index.d.ts +41 -0
- package/lib/driver/mysql/index.d.ts.map +1 -0
- package/lib/driver/mysql/index.js +338 -0
- package/lib/driver/mysql/index.js.map +1 -0
- package/lib/driver/mysql/pool.d.ts +46 -0
- package/lib/driver/mysql/pool.d.ts.map +1 -0
- package/lib/driver/mysql/pool.js +141 -0
- package/lib/driver/mysql/pool.js.map +1 -0
- package/lib/driver/mysql/version.d.ts +27 -0
- package/lib/driver/mysql/version.d.ts.map +1 -0
- package/lib/driver/mysql/version.js +77 -0
- package/lib/driver/mysql/version.js.map +1 -0
- package/lib/driver/postgresql/index.d.ts +34 -0
- package/lib/driver/postgresql/index.d.ts.map +1 -0
- package/lib/driver/postgresql/index.js +383 -0
- package/lib/driver/postgresql/index.js.map +1 -0
- package/lib/driver/postgresql/pool.d.ts +33 -0
- package/lib/driver/postgresql/pool.d.ts.map +1 -0
- package/lib/driver/postgresql/pool.js +104 -0
- package/lib/driver/postgresql/pool.js.map +1 -0
- package/lib/driver/registry.d.ts +16 -0
- package/lib/driver/registry.d.ts.map +1 -0
- package/lib/driver/registry.js +27 -0
- package/lib/driver/registry.js.map +1 -0
- package/lib/driver/sqlite/backend.d.ts +19 -0
- package/lib/driver/sqlite/backend.d.ts.map +1 -0
- package/lib/driver/sqlite/backend.js +5 -0
- package/lib/driver/sqlite/backend.js.map +1 -0
- package/lib/driver/sqlite/bun.d.ts +10 -0
- package/lib/driver/sqlite/bun.d.ts.map +1 -0
- package/lib/driver/sqlite/bun.js +36 -0
- package/lib/driver/sqlite/bun.js.map +1 -0
- package/lib/driver/sqlite/index.d.ts +49 -0
- package/lib/driver/sqlite/index.d.ts.map +1 -0
- package/lib/driver/sqlite/index.js +421 -0
- package/lib/driver/sqlite/index.js.map +1 -0
- package/lib/driver/sqlite/node.d.ts +10 -0
- package/lib/driver/sqlite/node.d.ts.map +1 -0
- package/lib/driver/sqlite/node.js +37 -0
- package/lib/driver/sqlite/node.js.map +1 -0
- package/lib/driver/sqlite/store.d.ts +13 -0
- package/lib/driver/sqlite/store.d.ts.map +1 -0
- package/lib/driver/sqlite/store.js +57 -0
- package/lib/driver/sqlite/store.js.map +1 -0
- package/lib/errors.d.ts +18 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +24 -0
- package/lib/errors.js.map +1 -0
- package/lib/facade/engine.d.ts +29 -0
- package/lib/facade/engine.d.ts.map +1 -0
- package/lib/facade/engine.js +107 -0
- package/lib/facade/engine.js.map +1 -0
- package/lib/index.d.ts +41 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +40 -0
- package/lib/index.js.map +1 -0
- package/lib/optional/static-source.d.ts +36 -0
- package/lib/optional/static-source.d.ts.map +1 -0
- package/lib/optional/static-source.js +141 -0
- package/lib/optional/static-source.js.map +1 -0
- package/lib/runtime.d.ts +12 -0
- package/lib/runtime.d.ts.map +1 -0
- package/lib/runtime.js +26 -0
- package/lib/runtime.js.map +1 -0
- package/lib/types/config.d.ts +146 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +5 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +7 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/manager.d.ts +37 -0
- package/lib/types/manager.d.ts.map +1 -0
- package/lib/types/manager.js +5 -0
- package/lib/types/manager.js.map +1 -0
- package/lib/types/queue.d.ts +45 -0
- package/lib/types/queue.d.ts.map +1 -0
- package/lib/types/queue.js +5 -0
- package/lib/types/queue.js.map +1 -0
- package/lib/types/result.d.ts +61 -0
- package/lib/types/result.d.ts.map +1 -0
- package/lib/types/result.js +16 -0
- package/lib/types/result.js.map +1 -0
- package/lib/types/schema.d.ts +51 -0
- package/lib/types/schema.d.ts.map +1 -0
- package/lib/types/schema.js +5 -0
- package/lib/types/schema.js.map +1 -0
- package/lib/types/task.d.ts +48 -0
- package/lib/types/task.d.ts.map +1 -0
- package/lib/types/task.js +136 -0
- package/lib/types/task.js.map +1 -0
- package/lib/types/transaction.d.ts +13 -0
- package/lib/types/transaction.d.ts.map +1 -0
- package/lib/types/transaction.js +2 -0
- package/lib/types/transaction.js.map +1 -0
- package/package.json +93 -0
- package/patches/bson@7.3.2.patch +105 -0
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# @fett/sql-translator
|
|
2
|
+
|
|
3
|
+
以 SQL 为统一查询语言的数据库兼容层。支持 **MySQL 5.7 / 8.x / PostgreSQL / SQLite / MongoDB**(MongoDB 为 SQL→Query 翻译),双运行时 **Node ≥ 22.5 / Bun ≥ 1.1**,内置连接池、任务队列(多线程)、结构 JSON 检出。
|
|
4
|
+
|
|
5
|
+
> 状态:**全部完成**(双运行时 Node ≥ 22.5 / Bun ≥ 1.1 全部 202 用例通过):SQLite / MySQL 5.7/8 / **MariaDB** / PostgreSQL / MongoDB(含**副本集事务**)驱动 + 连接池 + 任务队列(多线程)+ 事务 + **查询结果缓存** + **selectOnly 只读模式** + **耗时返回** + 结构 JSON 检出 + 静态数据源 + CI。
|
|
6
|
+
|
|
7
|
+
## 快速开始
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createClient } from '@fett/sql-translator';
|
|
11
|
+
|
|
12
|
+
// 唯一入参:连接配置
|
|
13
|
+
const db = createClient({ type: 'sqlite', database: ':memory:' });
|
|
14
|
+
|
|
15
|
+
await db.testConnection(); // { success, message }
|
|
16
|
+
await db.execute(
|
|
17
|
+
'CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, age INTEGER)',
|
|
18
|
+
);
|
|
19
|
+
await db.execute('INSERT INTO users (name, age) VALUES (?, ?)', ['alice', 30]);
|
|
20
|
+
|
|
21
|
+
const result = await db.query('SELECT * FROM users WHERE age > ?', [18]);
|
|
22
|
+
// { rows: [...], fields: [...], total: 1, offset: 0, limit: 100, duration: 3.42 }
|
|
23
|
+
// duration:执行耗时(ms),client.run / query / execute / 函数式 runSql 均返回
|
|
24
|
+
|
|
25
|
+
const schema = await db.getTableSchema('users'); // 结构 JSON
|
|
26
|
+
const json = await db.exportSchemaAsJson(); // 全库结构 → JSON 字符串
|
|
27
|
+
|
|
28
|
+
await db.destroy(); // 释放引用(共享池引用归零后回收)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## MySQL(5.7 / 8.x 双版本)
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const db = createClient({
|
|
35
|
+
type: 'mysql',
|
|
36
|
+
host: '127.0.0.1', port: 3306,
|
|
37
|
+
user: 'root', password: '...', database: 'test',
|
|
38
|
+
version: 'auto', // '5' | '8' | 'auto'(auto = SELECT VERSION() 探测)
|
|
39
|
+
dml: { requireWhereForUpdateDelete: true },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await db.query('SELECT * FROM users WHERE age > ?', [18]); // 自动分页包装
|
|
43
|
+
await db.execute('UPDATE users SET age = ? WHERE id = ?', [31, 1]);
|
|
44
|
+
const schema = await db.getTableSchema('users'); // 结构 JSON
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- 分页包装按版本能力矩阵自动选择:MySQL 8 用 CTE,5.7 用派生表
|
|
48
|
+
- 无 WHERE 的 UPDATE/DELETE 默认拦截(DML_BLOCKED)
|
|
49
|
+
|
|
50
|
+
## MongoDB(SQL → Query / DML 翻译)
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
const db = createClient({ type: 'mongodb', uri: 'mongodb://127.0.0.1:27017', database: 'test' });
|
|
54
|
+
|
|
55
|
+
// SQL → find / aggregate(@synatic/noql)
|
|
56
|
+
const res = await db.query('SELECT * FROM users WHERE age > ?', [18]);
|
|
57
|
+
await db.query('SELECT status, COUNT(*) AS n FROM orders GROUP BY status');
|
|
58
|
+
|
|
59
|
+
// SQL → insert/update/delete(node-sql-parser + noql WHERE 翻译)
|
|
60
|
+
await db.execute("INSERT INTO users (name, age) VALUES ('dave', 40)");
|
|
61
|
+
await db.execute("UPDATE users SET age = age + 1 WHERE name = 'dave'");
|
|
62
|
+
await db.execute("DELETE FROM users WHERE name = 'dave'");
|
|
63
|
+
|
|
64
|
+
// 结构检出:采样(嵌套对象/数组/ObjectId),长任务可取消
|
|
65
|
+
const schema = await db.getTableSchema('users');
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- WHERE 条件翻译与 SELECT 路径一致(=, >, <, LIKE, IN, BETWEEN, AND/OR, IS NULL)
|
|
69
|
+
- SET 支持 `$set` 与算术自增 `$inc`;无 WHERE 的 UPDATE/DELETE 默认拦截
|
|
70
|
+
- 结构检出为长任务(分批采样 + 进度 + 取消 + TTL 缓存)
|
|
71
|
+
|
|
72
|
+
## 本地测试数据库(docker compose)
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pnpm db:up # 启动 mysql5(33061) / mysql8(33062) / postgres(54321) / mongodb(27017)
|
|
76
|
+
pnpm db:init # 初始化种子数据(MySQL 走 utf8mb4 脚本,Mongo 注入)
|
|
77
|
+
|
|
78
|
+
# 跑全部集成测试(含 4 种数据库)
|
|
79
|
+
SQLENGINE_TEST_MYSQL5_HOST=127.0.0.1 SQLENGINE_TEST_MYSQL5_PORT=33061 \
|
|
80
|
+
SQLENGINE_TEST_MYSQL5_USER=root SQLENGINE_TEST_MYSQL5_PASSWORD=root \
|
|
81
|
+
SQLENGINE_TEST_MYSQL8_HOST=127.0.0.1 SQLENGINE_TEST_MYSQL8_PORT=33062 \
|
|
82
|
+
SQLENGINE_TEST_MYSQL8_USER=root SQLENGINE_TEST_MYSQL8_PASSWORD=root \
|
|
83
|
+
SQLENGINE_TEST_PG_HOST=127.0.0.1 SQLENGINE_TEST_PG_PORT=54321 \
|
|
84
|
+
SQLENGINE_TEST_MONGO_URI=mongodb://127.0.0.1:27017 \
|
|
85
|
+
pnpm test
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> 国内网络镜像慢时:`MYSQL5_IMAGE=docker.m.daocloud.io/library/mysql:5.7 MYSQL8_IMAGE=docker.m.daocloud.io/library/mysql:8.0 MONGO_IMAGE=docker.m.daocloud.io/library/mongo:7 pnpm db:up`
|
|
89
|
+
> 说明:bson@7.3.2 已打补丁(Bun 下 node:v8 兼容),见 `patches/` + package.json `pnpm.patchedDependencies`
|
|
90
|
+
|
|
91
|
+
## 多数据源平台
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { createClientManager } from '@fett/sql-translator';
|
|
95
|
+
|
|
96
|
+
const manager = createClientManager({ maxClients: 200, lru: { maxIdlePools: 50 } });
|
|
97
|
+
|
|
98
|
+
async function handleSql(dsConfig, sql, params) {
|
|
99
|
+
const db = manager.getClient(dsConfig); // 命中共享池,零成本
|
|
100
|
+
return db.query(sql, params);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await manager.invalidate(dsId); // 数据源配置更新:销毁旧池
|
|
104
|
+
await manager.release(dsId); // 数据源删除:释放引用
|
|
105
|
+
await manager.destroyAll(); // 应用退出
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 函数式 API
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { runSql, getTableSchema, exportSchemaAsJson } from '@fett/sql-translator';
|
|
112
|
+
|
|
113
|
+
const result = await runSql(dsConfig, { sql, offset: 0, limit: 10 });
|
|
114
|
+
const schema = await exportSchemaAsJson(dsConfig);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 任务队列(多线程)
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const db = createClient(config);
|
|
121
|
+
|
|
122
|
+
// 进程内异步并发(I/O 密集)
|
|
123
|
+
await db.tasks.enqueue(() => fetch('...'));
|
|
124
|
+
|
|
125
|
+
// CPU 密集任务 offload 到 worker 线程(需可序列化规格)
|
|
126
|
+
await db.tasks.enqueue({ module: '/abs/path/to/fn.mjs', fn: 'heavyCompute', args: [1e7] }, { worker: true });
|
|
127
|
+
|
|
128
|
+
// 长任务:进度 + 取消
|
|
129
|
+
const task = db.getAllTableSchemas({ onProgress: (p) => console.log(p) });
|
|
130
|
+
await task.promise;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 事务
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
await db.withTransaction(async (tx) => {
|
|
137
|
+
await tx.execute('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
|
|
138
|
+
await tx.execute('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
|
|
139
|
+
// fn 抛错自动回滚;也可手动 tx.commit() / tx.rollback()
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
SQLite/PG/MySQL/MariaDB 真事务;MongoDB 走 session(**需副本集**——docker compose 提供单节点副本集 `mongo-rs`(27018),`node scripts/init-mongo-rs.mjs` 初始化)。
|
|
143
|
+
|
|
144
|
+
## 查询结果缓存
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
const db = createClient({ type: 'sqlite', database: ':memory:', cache: { enabled: true, ttlMs: 60000, maxEntries: 1000 } });
|
|
148
|
+
// 幂等 SELECT 结果缓存(TTL + LRU);DML/DDL 后自动失效
|
|
149
|
+
```
|
|
150
|
+
仅缓存 SELECT;写操作后本 client 缓存整库失效。
|
|
151
|
+
|
|
152
|
+
## selectOnly 只读模式
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
const db = createClient({ type: 'sqlite', database: ':memory:', selectOnly: true });
|
|
156
|
+
await db.query('SELECT * FROM t'); // ✅
|
|
157
|
+
await db.execute('UPDATE t SET v = 1'); // ❌ READ_ONLY
|
|
158
|
+
await db.withTransaction(async (tx) => {}); // ❌ READ_ONLY
|
|
159
|
+
```
|
|
160
|
+
只读模式下仅允许 SELECT,DML/DDL/事务一律拒绝(错误码 `READ_ONLY`)。
|
|
161
|
+
|
|
162
|
+
## MariaDB
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const db = createClient({ type: 'mariadb', host, port: 3306, user, password, database, version: 'auto' });
|
|
166
|
+
// MySQL 协议兼容;能力矩阵独立(10.2+ CTE → 分页走 CTE 包装;慢查询兜底用 max_statement_time)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## 静态数据源(JSON/CSV/Excel → SQLite)
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { createStaticSqlitePool, importDataToSqlite, runStaticSql } from '@fett/sql-engine';
|
|
173
|
+
|
|
174
|
+
const pool = await createStaticSqlitePool({ type: 'sqlite', database: ':memory:' });
|
|
175
|
+
await importDataToSqlite(pool, 'json_data_1_1', [{ id: 1, name: 'alice' }]);
|
|
176
|
+
|
|
177
|
+
// 用户 SQL 用逻辑表名,自动映射为 SQLite 物理表名
|
|
178
|
+
const res = await runStaticSql(
|
|
179
|
+
pool,
|
|
180
|
+
{ sql: 'SELECT * FROM 用户表 WHERE price > ?', params: [5] },
|
|
181
|
+
[{ name: '用户表', datasourceName: '数据源A', sqliteTableName: 'json_data_1_1' }],
|
|
182
|
+
);
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## CI
|
|
186
|
+
|
|
187
|
+
GitHub Actions(.github/workflows/test.yml):Node + Bun 双运行时,docker 起 4 种数据库跑全量集成测试。
|
|
188
|
+
|
|
189
|
+
## 文档
|
|
190
|
+
|
|
191
|
+
架构设计见 [.docs/architecture.md](.docs/architecture.md)。
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ConnectionConfig, SchemaOptions } from '../types/config.js';
|
|
2
|
+
import { type ExecResult, type Field, type QueryResult, type RunSqlRequest, type TestResult, type WriteResult } from '../types/result.js';
|
|
3
|
+
import type { TableSchema } from '../types/schema.js';
|
|
4
|
+
import type { IntrospectTask } from '../types/task.js';
|
|
5
|
+
import type { TaskQueue } from '../types/queue.js';
|
|
6
|
+
import type { TransactionHandle } from '../types/transaction.js';
|
|
7
|
+
import type { PoolRegistry } from './registry.js';
|
|
8
|
+
export declare class DbClient {
|
|
9
|
+
readonly config: ConnectionConfig;
|
|
10
|
+
readonly fingerprint: string;
|
|
11
|
+
/** 任务队列(多线程) */
|
|
12
|
+
readonly tasks: TaskQueue;
|
|
13
|
+
private registry;
|
|
14
|
+
private driverCache;
|
|
15
|
+
private handlePromise;
|
|
16
|
+
private destroyed;
|
|
17
|
+
private queryCache;
|
|
18
|
+
constructor(registry: PoolRegistry, config: ConnectionConfig);
|
|
19
|
+
private get driver();
|
|
20
|
+
private getHandle;
|
|
21
|
+
/** 连接测试(一次性连接,不入池) */
|
|
22
|
+
testConnection(): Promise<TestResult>;
|
|
23
|
+
/** 池内探活:失败触发池重建 */
|
|
24
|
+
ping(): Promise<void>;
|
|
25
|
+
/** 释放引用(引用归零且空闲超限时池被回收);不是「立即销毁共享池」 */
|
|
26
|
+
destroy(): Promise<void>;
|
|
27
|
+
/** 完整执行入口(SELECT → QueryResult,DML → WriteResult)
|
|
28
|
+
* dml 选项按本 client 配置注入(池共享时 handle 配置不可靠)
|
|
29
|
+
* 查询结果缓存:仅幂等 SELECT;写操作(DML/DDL)后整库失效
|
|
30
|
+
* selectOnly 只读模式:拒绝一切非 SELECT 语句
|
|
31
|
+
* 返回结果统一携带 duration(执行耗时 ms,含缓存命中) */
|
|
32
|
+
run(request: RunSqlRequest): Promise<ExecResult>;
|
|
33
|
+
/** selectOnly 只读模式护栏:拒绝非 SELECT 语句 */
|
|
34
|
+
private assertWritable;
|
|
35
|
+
private getQueryCache;
|
|
36
|
+
/** SELECT 查询 */
|
|
37
|
+
query<T = any>(sql: string, params?: unknown[]): Promise<QueryResult>;
|
|
38
|
+
/** 写操作:DML(INSERT/UPDATE/DELETE)+ DDL(CREATE/ALTER/DROP 透传) */
|
|
39
|
+
execute(sql: string, params?: unknown[]): Promise<WriteResult>;
|
|
40
|
+
/** 透传原始驱动结果(不包装)——M2 提供方言原生透传 */
|
|
41
|
+
raw(sql: string, params?: unknown[]): Promise<unknown>;
|
|
42
|
+
getTables(): Promise<string[]>;
|
|
43
|
+
getTableDDL(table: string): Promise<string>;
|
|
44
|
+
getColumns(table: string): Promise<Field[]>;
|
|
45
|
+
getRowsCount(table: string, whereClause?: string, params?: unknown[]): Promise<number>;
|
|
46
|
+
getPreviewRows(table: string, offset?: number, limit?: number, whereClause?: string): Promise<any[]>;
|
|
47
|
+
/** 单表结构 JSON 检出 */
|
|
48
|
+
getTableSchema(table: string, opts?: SchemaOptions): Promise<TableSchema>;
|
|
49
|
+
/** 全库批量结构导出(长任务:进度/取消)
|
|
50
|
+
* 引用语义:client 持有池引用直到 destroy(),任务期间不额外计 ref */
|
|
51
|
+
getAllTableSchemas(opts?: SchemaOptions): IntrospectTask<TableSchema[]>;
|
|
52
|
+
/** 全库结构 → JSON 字符串 */
|
|
53
|
+
exportSchemaAsJson(opts?: SchemaOptions): Promise<string>;
|
|
54
|
+
/** 事务:fn 内所有查询在同一事务/连接内执行;fn 抛错自动回滚 */
|
|
55
|
+
withTransaction<T>(fn: (tx: TransactionHandle) => Promise<T>): Promise<T>;
|
|
56
|
+
}
|
|
57
|
+
/** 判断 SQL 是否为写操作(供上层语义判断) */
|
|
58
|
+
export declare function isWriteSql(sql: string): boolean;
|
|
59
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DbClient:绑定 config 的极简 API
|
|
3
|
+
* 外部唯一入口:createClient(config)
|
|
4
|
+
*/
|
|
5
|
+
import { SqlEngineError } from '../errors.js';
|
|
6
|
+
import { configKey } from '../core/config.js';
|
|
7
|
+
import { TtlCache, queryCacheKey } from '../core/cache.js';
|
|
8
|
+
import { getDriver } from '../driver/registry.js';
|
|
9
|
+
import { roundDuration, } from '../types/result.js';
|
|
10
|
+
import { wrapTask } from '../types/task.js';
|
|
11
|
+
import { TaskQueueImpl } from '../core/task-queue.js';
|
|
12
|
+
import { detectStatementType } from '../core/sql/statement.js';
|
|
13
|
+
import { normalizeSql } from '../core/sql/normalize.js';
|
|
14
|
+
export class DbClient {
|
|
15
|
+
config;
|
|
16
|
+
fingerprint;
|
|
17
|
+
/** 任务队列(多线程) */
|
|
18
|
+
tasks;
|
|
19
|
+
registry;
|
|
20
|
+
driverCache = null;
|
|
21
|
+
handlePromise = null;
|
|
22
|
+
destroyed = false;
|
|
23
|
+
queryCache = null;
|
|
24
|
+
constructor(registry, config) {
|
|
25
|
+
this.registry = registry;
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.fingerprint = configKey(config);
|
|
28
|
+
// driver 懒加载:createClient 不抛 UNSUPPORTED_DIALECT,首次操作才校验
|
|
29
|
+
this.tasks = new TaskQueueImpl(config.queue ?? {});
|
|
30
|
+
}
|
|
31
|
+
get driver() {
|
|
32
|
+
this.driverCache ??= getDriver(this.config.type);
|
|
33
|
+
return this.driverCache;
|
|
34
|
+
}
|
|
35
|
+
// ==================== 连接生命周期 ====================
|
|
36
|
+
getHandle() {
|
|
37
|
+
if (this.destroyed) {
|
|
38
|
+
return Promise.reject(new SqlEngineError('CONNECTION_FAILED', 'client 已销毁(destroy 后不可再使用)'));
|
|
39
|
+
}
|
|
40
|
+
this.handlePromise ??= this.registry.getPool(this.config);
|
|
41
|
+
return this.handlePromise;
|
|
42
|
+
}
|
|
43
|
+
/** 连接测试(一次性连接,不入池) */
|
|
44
|
+
testConnection() {
|
|
45
|
+
return this.driver.testConnection(this.config);
|
|
46
|
+
}
|
|
47
|
+
/** 池内探活:失败触发池重建 */
|
|
48
|
+
async ping() {
|
|
49
|
+
const handle = await this.getHandle();
|
|
50
|
+
try {
|
|
51
|
+
await handle.ping();
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
// 探活失败 → 销毁并重建池
|
|
55
|
+
await this.registry.invalidate(this.fingerprint).catch(() => undefined);
|
|
56
|
+
this.handlePromise = null;
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** 释放引用(引用归零且空闲超限时池被回收);不是「立即销毁共享池」 */
|
|
61
|
+
async destroy() {
|
|
62
|
+
if (this.destroyed)
|
|
63
|
+
return;
|
|
64
|
+
this.destroyed = true;
|
|
65
|
+
this.registry.release(this.fingerprint);
|
|
66
|
+
if (this.tasks && typeof this.tasks.close === 'function') {
|
|
67
|
+
await this.tasks.close();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// ==================== SQL 执行 ====================
|
|
71
|
+
/** 完整执行入口(SELECT → QueryResult,DML → WriteResult)
|
|
72
|
+
* dml 选项按本 client 配置注入(池共享时 handle 配置不可靠)
|
|
73
|
+
* 查询结果缓存:仅幂等 SELECT;写操作(DML/DDL)后整库失效
|
|
74
|
+
* selectOnly 只读模式:拒绝一切非 SELECT 语句
|
|
75
|
+
* 返回结果统一携带 duration(执行耗时 ms,含缓存命中) */
|
|
76
|
+
async run(request) {
|
|
77
|
+
const start = performance.now();
|
|
78
|
+
const finish = (result) => {
|
|
79
|
+
if (result && typeof result === 'object') {
|
|
80
|
+
result.duration = roundDuration(performance.now() - start);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
};
|
|
84
|
+
const type = detectStatementType(request.sql);
|
|
85
|
+
this.assertWritable(type);
|
|
86
|
+
const handle = await this.getHandle();
|
|
87
|
+
const req = request.dml ? request : { ...request, dml: this.config.dml };
|
|
88
|
+
const cacheOpts = this.config.cache;
|
|
89
|
+
const cache = cacheOpts?.enabled ? this.getQueryCache() : null;
|
|
90
|
+
if (cache && type === 'SELECT') {
|
|
91
|
+
const key = queryCacheKey(this.fingerprint, request.sql, request);
|
|
92
|
+
const hit = cache.get(key);
|
|
93
|
+
if (hit !== undefined)
|
|
94
|
+
return finish(hit);
|
|
95
|
+
const result = await this.driver.runSql(handle, req);
|
|
96
|
+
cache.set(key, structuredClone(result));
|
|
97
|
+
return finish(result);
|
|
98
|
+
}
|
|
99
|
+
const result = await this.driver.runSql(handle, req);
|
|
100
|
+
// 写操作后失效(粗粒度:本 client 缓存全清;精确按表失效留后续)
|
|
101
|
+
if (cache && type !== 'SELECT')
|
|
102
|
+
cache.clear();
|
|
103
|
+
return finish(result);
|
|
104
|
+
}
|
|
105
|
+
/** selectOnly 只读模式护栏:拒绝非 SELECT 语句 */
|
|
106
|
+
assertWritable(type) {
|
|
107
|
+
if (this.config.selectOnly && type !== 'SELECT') {
|
|
108
|
+
throw new SqlEngineError('READ_ONLY', `只读模式(selectOnly: true)禁止 ${type} 语句,仅允许 SELECT`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
getQueryCache() {
|
|
112
|
+
const opts = this.config.cache;
|
|
113
|
+
this.queryCache ??= new TtlCache(opts?.ttlMs ?? 60000, opts?.maxEntries ?? 1000);
|
|
114
|
+
return this.queryCache;
|
|
115
|
+
}
|
|
116
|
+
/** SELECT 查询 */
|
|
117
|
+
async query(sql, params) {
|
|
118
|
+
const type = detectStatementType(sql);
|
|
119
|
+
if (type !== 'SELECT') {
|
|
120
|
+
throw new SqlEngineError('QUERY_FAILED', `query() 仅支持 SELECT,收到 ${type}(写操作请用 execute())`);
|
|
121
|
+
}
|
|
122
|
+
const result = await this.run({ sql, params });
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
/** 写操作:DML(INSERT/UPDATE/DELETE)+ DDL(CREATE/ALTER/DROP 透传) */
|
|
126
|
+
async execute(sql, params) {
|
|
127
|
+
const type = detectStatementType(sql);
|
|
128
|
+
if (type !== 'INSERT' && type !== 'UPDATE' && type !== 'DELETE' && type !== 'DDL') {
|
|
129
|
+
throw new SqlEngineError('QUERY_FAILED', `execute() 仅支持写操作(INSERT/UPDATE/DELETE/DDL),收到 ${type}(查询请用 query())`);
|
|
130
|
+
}
|
|
131
|
+
const result = await this.run({ sql, params });
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
/** 透传原始驱动结果(不包装)——M2 提供方言原生透传 */
|
|
135
|
+
async raw(sql, params) {
|
|
136
|
+
void sql;
|
|
137
|
+
void params;
|
|
138
|
+
throw new SqlEngineError('QUERY_FAILED', 'raw() 暂未在驱动层暴露(M2 提供方言原生透传)');
|
|
139
|
+
}
|
|
140
|
+
// ==================== 元信息检出 ====================
|
|
141
|
+
async getTables() {
|
|
142
|
+
const handle = await this.getHandle();
|
|
143
|
+
return this.driver.getTableList(handle);
|
|
144
|
+
}
|
|
145
|
+
async getTableDDL(table) {
|
|
146
|
+
const handle = await this.getHandle();
|
|
147
|
+
if (!this.driver.getTableDDL) {
|
|
148
|
+
throw new SqlEngineError('QUERY_FAILED', `方言 ${this.driver.dialect} 不支持 getTableDDL`);
|
|
149
|
+
}
|
|
150
|
+
return this.driver.getTableDDL(handle, table);
|
|
151
|
+
}
|
|
152
|
+
async getColumns(table) {
|
|
153
|
+
const handle = await this.getHandle();
|
|
154
|
+
return this.driver.getColumns(handle, table);
|
|
155
|
+
}
|
|
156
|
+
async getRowsCount(table, whereClause, params) {
|
|
157
|
+
void params;
|
|
158
|
+
const handle = await this.getHandle();
|
|
159
|
+
return this.driver.getRowsCount(handle, table, whereClause);
|
|
160
|
+
}
|
|
161
|
+
async getPreviewRows(table, offset = 0, limit = 100, whereClause) {
|
|
162
|
+
const handle = await this.getHandle();
|
|
163
|
+
return this.driver.getPreviewRows(handle, table, offset, limit, whereClause);
|
|
164
|
+
}
|
|
165
|
+
/** 单表结构 JSON 检出 */
|
|
166
|
+
getTableSchema(table, opts) {
|
|
167
|
+
return this.getHandle().then((handle) => this.driver.getTableSchema(handle, table, opts));
|
|
168
|
+
}
|
|
169
|
+
/** 全库批量结构导出(长任务:进度/取消)
|
|
170
|
+
* 引用语义:client 持有池引用直到 destroy(),任务期间不额外计 ref */
|
|
171
|
+
getAllTableSchemas(opts) {
|
|
172
|
+
return wrapTask(() => this.getHandle().then((handle) => {
|
|
173
|
+
if (!this.driver.getAllTableSchemas) {
|
|
174
|
+
throw new SqlEngineError('QUERY_FAILED', `方言 ${this.driver.dialect} 不支持 getAllTableSchemas`);
|
|
175
|
+
}
|
|
176
|
+
return this.driver.getAllTableSchemas(handle, opts);
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
/** 全库结构 → JSON 字符串 */
|
|
180
|
+
async exportSchemaAsJson(opts) {
|
|
181
|
+
const task = this.getAllTableSchemas(opts);
|
|
182
|
+
const schemas = await task.promise;
|
|
183
|
+
return JSON.stringify(schemas, null, 2);
|
|
184
|
+
}
|
|
185
|
+
/** 事务:fn 内所有查询在同一事务/连接内执行;fn 抛错自动回滚 */
|
|
186
|
+
async withTransaction(fn) {
|
|
187
|
+
if (this.config.selectOnly) {
|
|
188
|
+
throw new SqlEngineError('READ_ONLY', '只读模式(selectOnly: true)禁止事务');
|
|
189
|
+
}
|
|
190
|
+
if (!this.driver.withTransaction) {
|
|
191
|
+
throw new SqlEngineError('QUERY_FAILED', `方言 ${this.driver.dialect} 不支持事务`);
|
|
192
|
+
}
|
|
193
|
+
const handle = await this.getHandle();
|
|
194
|
+
return this.driver.withTransaction(handle, fn);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/** 判断 SQL 是否为写操作(供上层语义判断) */
|
|
198
|
+
export function isWriteSql(sql) {
|
|
199
|
+
return detectStatementType(normalizeSql(sql)) !== 'SELECT';
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 极简客户端入口:createClient(config)
|
|
3
|
+
* 零成本轻量操作(不建连接);底层连接池全局共享(defaultRegistry)
|
|
4
|
+
*/
|
|
5
|
+
import type { ConnectionConfig } from '../types/config.js';
|
|
6
|
+
import { DbClient } from './client.js';
|
|
7
|
+
import { ClientManager } from './manager.js';
|
|
8
|
+
/** 创建绑定 config 的 client(懒建池:首次真实调用才建立连接) */
|
|
9
|
+
export declare function createClient(config: ConnectionConfig): DbClient;
|
|
10
|
+
/** 创建多数据源管理器 */
|
|
11
|
+
export declare function createClientManager(options?: ConstructorParameters<typeof ClientManager>[0]): ClientManager;
|
|
12
|
+
export { DbClient } from './client.js';
|
|
13
|
+
export { ClientManager } from './manager.js';
|
|
14
|
+
export { PoolRegistry, defaultRegistry } from './registry.js';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,4CAA4C;AAC5C,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,CAE/D;AAED,gBAAgB;AAChB,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAE3G;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DbClient } from './client.js';
|
|
2
|
+
import { defaultRegistry } from './registry.js';
|
|
3
|
+
import { ClientManager } from './manager.js';
|
|
4
|
+
/** 创建绑定 config 的 client(懒建池:首次真实调用才建立连接) */
|
|
5
|
+
export function createClient(config) {
|
|
6
|
+
return new DbClient(defaultRegistry, config);
|
|
7
|
+
}
|
|
8
|
+
/** 创建多数据源管理器 */
|
|
9
|
+
export function createClientManager(options) {
|
|
10
|
+
return new ClientManager(options);
|
|
11
|
+
}
|
|
12
|
+
export { DbClient } from './client.js';
|
|
13
|
+
export { ClientManager } from './manager.js';
|
|
14
|
+
export { PoolRegistry, defaultRegistry } from './registry.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,4CAA4C;AAC5C,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,OAAO,IAAI,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,gBAAgB;AAChB,MAAM,UAAU,mBAAmB,CAAC,OAAwD;IAC1F,OAAO,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ConnectionConfig } from '../types/config.js';
|
|
2
|
+
import type { ClientManagerOptions, PoolMetrics } from '../types/manager.js';
|
|
3
|
+
import { DbClient } from './client.js';
|
|
4
|
+
export declare class ClientManager {
|
|
5
|
+
private registry;
|
|
6
|
+
private byId;
|
|
7
|
+
private maxClients;
|
|
8
|
+
constructor(options?: ClientManagerOptions);
|
|
9
|
+
/**
|
|
10
|
+
* 获取/创建绑定 config 的 client(首次懒建池,之后命中共享池)
|
|
11
|
+
* 创建本身零成本:不建立连接,首次调用才真实建连
|
|
12
|
+
*/
|
|
13
|
+
getClient(config: ConnectionConfig): DbClient;
|
|
14
|
+
/** 注册业务 ID → client(避免每次从库读 config 后重复计算指纹) */
|
|
15
|
+
register(dsId: string, config: ConnectionConfig): Promise<DbClient>;
|
|
16
|
+
getClientById(dsId: string): DbClient | undefined;
|
|
17
|
+
getConfigById(dsId: string): ConnectionConfig | undefined;
|
|
18
|
+
/** 释放 client 引用(数据源删除:引用归零即回收池) */
|
|
19
|
+
release(dsId: string): Promise<void>;
|
|
20
|
+
/** 强制销毁池(数据源配置更新:下次按新 config 重建) */
|
|
21
|
+
invalidate(target: string | ConnectionConfig): Promise<void>;
|
|
22
|
+
/** 应用退出清理 */
|
|
23
|
+
destroyAll(): Promise<void>;
|
|
24
|
+
/** 池指标 */
|
|
25
|
+
metrics(): PoolMetrics;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAQvC,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,IAAI,CAAuC;IACnD,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,GAAE,oBAAyB;IAK9C;;;OAGG;IACH,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ;IAM7C,+CAA+C;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAczE,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIjD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIzD,mCAAmC;IAC7B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1C,oCAAoC;IAC9B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlE,aAAa;IACP,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC,UAAU;IACV,OAAO,IAAI,WAAW;CAGvB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClientManager:多数据源注册表
|
|
3
|
+
* 核心:连接池按 config 指纹全局共享,client 是廉价句柄;每请求 getClient 命中缓存,不建新池
|
|
4
|
+
*/
|
|
5
|
+
import { SqlEngineError } from '../errors.js';
|
|
6
|
+
import { configKey } from '../core/config.js';
|
|
7
|
+
import { DbClient } from './client.js';
|
|
8
|
+
import { PoolRegistry } from './registry.js';
|
|
9
|
+
export class ClientManager {
|
|
10
|
+
registry;
|
|
11
|
+
byId = new Map();
|
|
12
|
+
maxClients;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
this.registry = new PoolRegistry(options);
|
|
15
|
+
this.maxClients = options.maxClients ?? 500;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 获取/创建绑定 config 的 client(首次懒建池,之后命中共享池)
|
|
19
|
+
* 创建本身零成本:不建立连接,首次调用才真实建连
|
|
20
|
+
*/
|
|
21
|
+
getClient(config) {
|
|
22
|
+
// 立即抛错校验方言(避免把错误延迟到首次调用)
|
|
23
|
+
void configKey(config);
|
|
24
|
+
return new DbClient(this.registry, config);
|
|
25
|
+
}
|
|
26
|
+
/** 注册业务 ID → client(避免每次从库读 config 后重复计算指纹) */
|
|
27
|
+
async register(dsId, config) {
|
|
28
|
+
if (this.byId.size >= this.maxClients) {
|
|
29
|
+
throw new SqlEngineError('CLIENT_LIMIT_EXCEEDED', `已注册 client 数达到上限 ${this.maxClients}(ClientManagerOptions.maxClients 可调)`);
|
|
30
|
+
}
|
|
31
|
+
const client = this.getClient(config);
|
|
32
|
+
// 预热:立即建池并探活,让后续请求零延迟命中
|
|
33
|
+
await client.ping();
|
|
34
|
+
this.byId.set(dsId, { config, client });
|
|
35
|
+
return client;
|
|
36
|
+
}
|
|
37
|
+
getClientById(dsId) {
|
|
38
|
+
return this.byId.get(dsId)?.client;
|
|
39
|
+
}
|
|
40
|
+
getConfigById(dsId) {
|
|
41
|
+
return this.byId.get(dsId)?.config;
|
|
42
|
+
}
|
|
43
|
+
/** 释放 client 引用(数据源删除:引用归零即回收池) */
|
|
44
|
+
async release(dsId) {
|
|
45
|
+
const rec = this.byId.get(dsId);
|
|
46
|
+
this.byId.delete(dsId);
|
|
47
|
+
if (rec) {
|
|
48
|
+
await rec.client.destroy();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** 强制销毁池(数据源配置更新:下次按新 config 重建) */
|
|
52
|
+
async invalidate(target) {
|
|
53
|
+
if (typeof target === 'string') {
|
|
54
|
+
const rec = this.byId.get(target);
|
|
55
|
+
if (rec) {
|
|
56
|
+
await this.registry.invalidate(configKey(rec.config));
|
|
57
|
+
this.byId.delete(target);
|
|
58
|
+
}
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
await this.registry.invalidate(configKey(target));
|
|
62
|
+
}
|
|
63
|
+
/** 应用退出清理 */
|
|
64
|
+
async destroyAll() {
|
|
65
|
+
await this.registry.destroyAll();
|
|
66
|
+
this.byId.clear();
|
|
67
|
+
}
|
|
68
|
+
/** 池指标 */
|
|
69
|
+
metrics() {
|
|
70
|
+
return this.registry.metrics();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/client/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { PoolHandle } from '../driver/interface.js';
|
|
2
|
+
import type { ConnectionConfig } from '../types/config.js';
|
|
3
|
+
import type { ClientManagerOptions, PoolMetrics } from '../types/manager.js';
|
|
4
|
+
export declare class PoolRegistry {
|
|
5
|
+
private pools;
|
|
6
|
+
private totalRefs;
|
|
7
|
+
private maxClients;
|
|
8
|
+
private lruEnabled;
|
|
9
|
+
private maxIdlePools;
|
|
10
|
+
constructor(options?: ClientManagerOptions);
|
|
11
|
+
/**
|
|
12
|
+
* 获取/创建连接池并 +1 引用
|
|
13
|
+
* 首次遇到某指纹时懒创建池;之后复用(不按请求建池)
|
|
14
|
+
*/
|
|
15
|
+
getPool(config: ConnectionConfig): Promise<PoolHandle>;
|
|
16
|
+
/** -1 引用;归零的池进入空闲集合(LRU 超限时回收) */
|
|
17
|
+
release(fingerprint: string): void;
|
|
18
|
+
/** 强制销毁池(数据源 update/remove 时调用) */
|
|
19
|
+
invalidate(fingerprint: string): Promise<void>;
|
|
20
|
+
/** 全局清理(应用退出) */
|
|
21
|
+
destroyAll(): Promise<void>;
|
|
22
|
+
/** 池指标(监控/容量规划) */
|
|
23
|
+
metrics(): PoolMetrics;
|
|
24
|
+
/** 空闲池 LRU 淘汰:引用归零的池超过 maxIdlePools 时,回收最久未用者 */
|
|
25
|
+
private maybeCollectIdle;
|
|
26
|
+
/** 测试辅助:清空注册表 */
|
|
27
|
+
reset(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/** 模块级默认注册表(所有入口共享) */
|
|
30
|
+
export declare const defaultRegistry: PoolRegistry;
|
|
31
|
+
//# sourceMappingURL=registry.d.ts.map
|