@dangao/bun-server 3.0.0 → 3.0.1
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/dist/database/connection-manager.d.ts.map +1 -1
- package/dist/database/connection-pool.d.ts.map +1 -1
- package/dist/database/service.d.ts +2 -1
- package/dist/database/service.d.ts.map +1 -1
- package/dist/database/sqlite-adapter.d.ts +2 -2
- package/dist/database/sqlite-adapter.d.ts.map +1 -1
- package/dist/index.js +64 -795
- package/dist/index.node.mjs +51 -17
- package/package.json +3 -4
- package/src/database/connection-manager.ts +19 -12
- package/src/database/connection-pool.ts +4 -3
- package/src/database/service.ts +21 -5
- package/src/database/sqlite-adapter.ts +19 -11
- package/tests/platform/shared/database.cases.ts +9 -9
- package/docs/design/query-interceptor-design.md +0 -381
package/dist/index.node.mjs
CHANGED
|
@@ -10932,8 +10932,8 @@ class ConnectionPool {
|
|
|
10932
10932
|
const { Database } = await import("bun:sqlite");
|
|
10933
10933
|
return new Database(config.path);
|
|
10934
10934
|
}
|
|
10935
|
-
const
|
|
10936
|
-
return
|
|
10935
|
+
const sqlite3 = __require("@vscode/sqlite3");
|
|
10936
|
+
return new sqlite3.Database(config.path);
|
|
10937
10937
|
}
|
|
10938
10938
|
async createPostgresConnection(config) {
|
|
10939
10939
|
const url = `postgres://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`;
|
|
@@ -11099,11 +11099,25 @@ class DatabaseConnectionManager {
|
|
|
11099
11099
|
}
|
|
11100
11100
|
async healthCheckSqlite(connection) {
|
|
11101
11101
|
try {
|
|
11102
|
-
if (connection
|
|
11102
|
+
if (!connection || typeof connection !== "object") {
|
|
11103
|
+
return false;
|
|
11104
|
+
}
|
|
11105
|
+
if ("query" in connection && typeof connection.query === "function" && !(("all" in connection) && ("run" in connection))) {
|
|
11103
11106
|
const db = connection;
|
|
11104
11107
|
db.query("SELECT 1").all();
|
|
11105
11108
|
return true;
|
|
11106
11109
|
}
|
|
11110
|
+
if ("all" in connection && typeof connection.all === "function") {
|
|
11111
|
+
await new Promise((resolve2, reject) => {
|
|
11112
|
+
connection.all("SELECT 1", [], (err) => {
|
|
11113
|
+
if (err)
|
|
11114
|
+
reject(err);
|
|
11115
|
+
else
|
|
11116
|
+
resolve2();
|
|
11117
|
+
});
|
|
11118
|
+
});
|
|
11119
|
+
return true;
|
|
11120
|
+
}
|
|
11107
11121
|
return false;
|
|
11108
11122
|
} catch (_error) {
|
|
11109
11123
|
return false;
|
|
@@ -11213,12 +11227,22 @@ class DatabaseService2 {
|
|
|
11213
11227
|
throw new Error(`Query not supported for database type: ${dbType}`);
|
|
11214
11228
|
}
|
|
11215
11229
|
querySqlite(connection, sql, params) {
|
|
11216
|
-
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
11230
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function" && !(("all" in connection) && ("run" in connection))) {
|
|
11217
11231
|
const db = connection;
|
|
11218
11232
|
const statement = db.query(sql);
|
|
11219
11233
|
const result = params && params.length > 0 ? statement.all(...params) : statement.all();
|
|
11220
11234
|
return result;
|
|
11221
11235
|
}
|
|
11236
|
+
if (connection && typeof connection === "object" && "all" in connection && typeof connection.all === "function") {
|
|
11237
|
+
return new Promise((resolve2, reject) => {
|
|
11238
|
+
connection.all(sql, params ?? [], (err, rows) => {
|
|
11239
|
+
if (err)
|
|
11240
|
+
reject(err);
|
|
11241
|
+
else
|
|
11242
|
+
resolve2(rows ?? []);
|
|
11243
|
+
});
|
|
11244
|
+
});
|
|
11245
|
+
}
|
|
11222
11246
|
throw new Error("Invalid SQLite connection");
|
|
11223
11247
|
}
|
|
11224
11248
|
async queryBunSQL(connection, sql, params) {
|
|
@@ -11389,24 +11413,29 @@ class SqliteAdapter {
|
|
|
11389
11413
|
}
|
|
11390
11414
|
this.db = db;
|
|
11391
11415
|
} else {
|
|
11392
|
-
const
|
|
11393
|
-
const db =
|
|
11416
|
+
const sqlite3 = __require("@vscode/sqlite3");
|
|
11417
|
+
const db = new sqlite3.Database(config.database);
|
|
11394
11418
|
if (config.wal !== false) {
|
|
11395
|
-
db.
|
|
11419
|
+
db.run("PRAGMA journal_mode = WAL;");
|
|
11396
11420
|
}
|
|
11397
11421
|
this.db = db;
|
|
11398
11422
|
}
|
|
11399
11423
|
this.semaphore = new Semaphore(config.maxWriteConcurrency ?? 1);
|
|
11400
11424
|
}
|
|
11401
|
-
query(sql, params = []) {
|
|
11425
|
+
async query(sql, params = []) {
|
|
11402
11426
|
if (this.isBun) {
|
|
11403
|
-
const
|
|
11404
|
-
const
|
|
11405
|
-
return
|
|
11427
|
+
const db = this.db;
|
|
11428
|
+
const stmt = db.query(sql);
|
|
11429
|
+
return stmt.all(...params);
|
|
11406
11430
|
}
|
|
11407
|
-
|
|
11408
|
-
|
|
11409
|
-
|
|
11431
|
+
return new Promise((resolve2, reject) => {
|
|
11432
|
+
this.db.all(sql, params, (err, rows) => {
|
|
11433
|
+
if (err)
|
|
11434
|
+
reject(err);
|
|
11435
|
+
else
|
|
11436
|
+
resolve2(rows ?? []);
|
|
11437
|
+
});
|
|
11438
|
+
});
|
|
11410
11439
|
}
|
|
11411
11440
|
async execute(sql, params = []) {
|
|
11412
11441
|
if (this.isBun) {
|
|
@@ -11414,9 +11443,14 @@ class SqliteAdapter {
|
|
|
11414
11443
|
const stmt = db.query(sql);
|
|
11415
11444
|
stmt.run(...params);
|
|
11416
11445
|
} else {
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11446
|
+
return new Promise((resolve2, reject) => {
|
|
11447
|
+
this.db.run(sql, params, (err) => {
|
|
11448
|
+
if (err)
|
|
11449
|
+
reject(err);
|
|
11450
|
+
else
|
|
11451
|
+
resolve2();
|
|
11452
|
+
});
|
|
11453
|
+
});
|
|
11420
11454
|
}
|
|
11421
11455
|
}
|
|
11422
11456
|
close() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dangao/bun-server",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"test:platform": "bun run test:bun && bun run test:node",
|
|
51
51
|
"type-check": "tsc --noEmit",
|
|
52
52
|
"clean": "rm -rf dist",
|
|
53
|
-
"bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith --external @dangao/nacos-client",
|
|
53
|
+
"bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith --external @dangao/nacos-client --external @vscode/sqlite3",
|
|
54
54
|
"bundle:node": "bun build src/index.ts --target=node --packages=external --outfile=dist/index.node.mjs",
|
|
55
55
|
"dts": "tsc -p tsconfig.build.json",
|
|
56
56
|
"build": "bun run clean && bun run bundle && bun run bundle:node && bun run dts",
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"publish:package:github": "cp -r ../../README.md ../../LICENSE ../../docs . && bun pm pack --access public && npm publish *.tgz --provenance --access public && rm -rf ./README.md ./LICENSE ./docs"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
63
62
|
"@types/bun": "^1.3.10",
|
|
64
63
|
"@types/mime-types": "^3.0.1",
|
|
65
64
|
"@types/ws": "^8.18.1",
|
|
@@ -69,7 +68,7 @@
|
|
|
69
68
|
"dependencies": {
|
|
70
69
|
"@dangao/logsmith": "0.2.0",
|
|
71
70
|
"@dangao/nacos-client": "0.1.1",
|
|
72
|
-
"
|
|
71
|
+
"@vscode/sqlite3": "5.1.12-vscode",
|
|
73
72
|
"json5": "^2.2.3",
|
|
74
73
|
"jsonc-parser": "^3.3.1",
|
|
75
74
|
"marked": "^18.0.0",
|
|
@@ -160,21 +160,28 @@ export class DatabaseConnectionManager {
|
|
|
160
160
|
*/
|
|
161
161
|
private async healthCheckSqlite(connection: unknown): Promise<boolean> {
|
|
162
162
|
try {
|
|
163
|
-
if (
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
) {
|
|
169
|
-
|
|
170
|
-
const db = connection as {
|
|
171
|
-
query: (sql: string) => {
|
|
172
|
-
all: () => unknown[];
|
|
173
|
-
};
|
|
174
|
-
};
|
|
163
|
+
if (!connection || typeof connection !== 'object') {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// bun:sqlite Database(有 .query() 但没有 callback-based .all())
|
|
168
|
+
if ('query' in connection && typeof (connection as any).query === 'function' && !('all' in connection && 'run' in connection)) {
|
|
169
|
+
const db = connection as { query: (sql: string) => { all: () => unknown[] } };
|
|
175
170
|
db.query('SELECT 1').all();
|
|
176
171
|
return true;
|
|
177
172
|
}
|
|
173
|
+
|
|
174
|
+
// @vscode/sqlite3 Database(callback-based .all())
|
|
175
|
+
if ('all' in connection && typeof (connection as any).all === 'function') {
|
|
176
|
+
await new Promise<void>((resolve, reject) => {
|
|
177
|
+
(connection as any).all('SELECT 1', [], (err: Error | null) => {
|
|
178
|
+
if (err) reject(err);
|
|
179
|
+
else resolve();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
|
|
178
185
|
return false;
|
|
179
186
|
} catch (_error) {
|
|
180
187
|
return false;
|
|
@@ -185,9 +185,10 @@ export class ConnectionPool {
|
|
|
185
185
|
const { Database } = await import('bun:sqlite');
|
|
186
186
|
return new Database(config.path);
|
|
187
187
|
}
|
|
188
|
-
// Node.js:使用
|
|
189
|
-
|
|
190
|
-
|
|
188
|
+
// Node.js:使用 @vscode/sqlite3
|
|
189
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
190
|
+
const sqlite3 = require('@vscode/sqlite3') as any;
|
|
191
|
+
return new sqlite3.Database(config.path);
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
/**
|
package/src/database/service.ts
CHANGED
|
@@ -113,7 +113,7 @@ export class DatabaseService {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* 执行 SQL 查询
|
|
116
|
-
* SQLite
|
|
116
|
+
* SQLite (bun:sqlite) 返回同步结果;@vscode/sqlite3 / PostgreSQL / MySQL 返回异步结果
|
|
117
117
|
*/
|
|
118
118
|
public query<T = unknown>(sql: string, params?: unknown[]): T[] | Promise<T[]> {
|
|
119
119
|
const session = getCurrentSession();
|
|
@@ -139,18 +139,20 @@ export class DatabaseService {
|
|
|
139
139
|
|
|
140
140
|
/**
|
|
141
141
|
* SQLite 查询实现
|
|
142
|
+
* bun:sqlite 使用同步 .query().all();@vscode/sqlite3 使用异步 callback .all()
|
|
142
143
|
*/
|
|
143
144
|
private querySqlite<T = unknown>(
|
|
144
145
|
connection: unknown,
|
|
145
146
|
sql: string,
|
|
146
147
|
params?: unknown[],
|
|
147
|
-
): T[] {
|
|
148
|
-
//
|
|
148
|
+
): T[] | Promise<T[]> {
|
|
149
|
+
// bun:sqlite Database 对象(有 .query() 方法)
|
|
149
150
|
if (
|
|
150
151
|
connection &&
|
|
151
152
|
typeof connection === 'object' &&
|
|
152
153
|
'query' in connection &&
|
|
153
|
-
typeof connection.query === 'function'
|
|
154
|
+
typeof (connection as any).query === 'function' &&
|
|
155
|
+
!('all' in connection && 'run' in connection)
|
|
154
156
|
) {
|
|
155
157
|
const db = connection as {
|
|
156
158
|
query: (sql: string) => {
|
|
@@ -160,12 +162,26 @@ export class DatabaseService {
|
|
|
160
162
|
};
|
|
161
163
|
|
|
162
164
|
const statement = db.query(sql);
|
|
163
|
-
// Bun SQLite 的 all() 方法接受参数
|
|
164
165
|
const result =
|
|
165
166
|
params && params.length > 0 ? statement.all(...params) : statement.all();
|
|
166
167
|
return result;
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
// @vscode/sqlite3 Database 对象(有 .all() callback 方法)
|
|
171
|
+
if (
|
|
172
|
+
connection &&
|
|
173
|
+
typeof connection === 'object' &&
|
|
174
|
+
'all' in connection &&
|
|
175
|
+
typeof (connection as any).all === 'function'
|
|
176
|
+
) {
|
|
177
|
+
return new Promise<T[]>((resolve, reject) => {
|
|
178
|
+
(connection as any).all(sql, params ?? [], (err: Error | null, rows: T[]) => {
|
|
179
|
+
if (err) reject(err);
|
|
180
|
+
else resolve(rows ?? []);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
169
185
|
throw new Error('Invalid SQLite connection');
|
|
170
186
|
}
|
|
171
187
|
|
|
@@ -40,7 +40,7 @@ export class Semaphore {
|
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
42
|
* SQLite 适配器(自动感知运行时)
|
|
43
|
-
* Bun 平台下使用 bun:sqlite,Node.js 平台下使用
|
|
43
|
+
* Bun 平台下使用 bun:sqlite,Node.js 平台下使用 @vscode/sqlite3
|
|
44
44
|
*/
|
|
45
45
|
export class SqliteAdapter {
|
|
46
46
|
private readonly db: unknown;
|
|
@@ -58,10 +58,12 @@ export class SqliteAdapter {
|
|
|
58
58
|
}
|
|
59
59
|
this.db = db;
|
|
60
60
|
} else {
|
|
61
|
-
|
|
62
|
-
const
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
62
|
+
const sqlite3 = require('@vscode/sqlite3') as any;
|
|
63
|
+
const db: any = new sqlite3.Database(config.database);
|
|
63
64
|
if (config.wal !== false) {
|
|
64
|
-
|
|
65
|
+
// Operations are serialized internally; WAL is queued before any query runs
|
|
66
|
+
db.run('PRAGMA journal_mode = WAL;');
|
|
65
67
|
}
|
|
66
68
|
this.db = db;
|
|
67
69
|
}
|
|
@@ -69,15 +71,18 @@ export class SqliteAdapter {
|
|
|
69
71
|
this.semaphore = new Semaphore(config.maxWriteConcurrency ?? 1);
|
|
70
72
|
}
|
|
71
73
|
|
|
72
|
-
public query<T = unknown>(sql: string, params: unknown[] = []): T[] {
|
|
74
|
+
public async query<T = unknown>(sql: string, params: unknown[] = []): Promise<T[]> {
|
|
73
75
|
if (this.isBun) {
|
|
74
76
|
const db = this.db as import('bun:sqlite').Database;
|
|
75
77
|
const stmt = db.query(sql);
|
|
76
78
|
return stmt.all(...params as Parameters<typeof stmt.all>) as T[];
|
|
77
79
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
return new Promise<T[]>((resolve, reject) => {
|
|
81
|
+
(this.db as any).all(sql, params, (err: Error | null, rows: T[]) => {
|
|
82
|
+
if (err) reject(err);
|
|
83
|
+
else resolve(rows ?? []);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
public async execute(sql: string, params: unknown[] = []): Promise<void> {
|
|
@@ -86,9 +91,12 @@ export class SqliteAdapter {
|
|
|
86
91
|
const stmt = db.query(sql);
|
|
87
92
|
stmt.run(...params as Parameters<typeof stmt.run>);
|
|
88
93
|
} else {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
return new Promise<void>((resolve, reject) => {
|
|
95
|
+
(this.db as any).run(sql, params, (err: Error | null) => {
|
|
96
|
+
if (err) reject(err);
|
|
97
|
+
else resolve();
|
|
98
|
+
});
|
|
99
|
+
});
|
|
92
100
|
}
|
|
93
101
|
}
|
|
94
102
|
|
|
@@ -7,22 +7,22 @@ import { SqliteManager } from '../../../src/database/sqlite-adapter';
|
|
|
7
7
|
export function runDatabaseCases(suite: TestSuite, engine: PlatformEngine): void {
|
|
8
8
|
const { test, expect } = suite;
|
|
9
9
|
|
|
10
|
-
//
|
|
11
|
-
const
|
|
10
|
+
// @vscode/sqlite3 is a native Node.js addon; skip when Node-platform tests run under Bun runtime
|
|
11
|
+
const skipNodeSqlite = engine === 'node' && typeof (globalThis as any).Bun !== 'undefined';
|
|
12
12
|
|
|
13
|
-
test('SqliteAdapter: create table, insert and query', () => {
|
|
14
|
-
if (
|
|
15
|
-
//
|
|
16
|
-
console.log('[skip]
|
|
13
|
+
test('SqliteAdapter: create table, insert and query', async () => {
|
|
14
|
+
if (skipNodeSqlite) {
|
|
15
|
+
// @vscode/sqlite3 is not available in Bun — this test must run under Node.js
|
|
16
|
+
console.log('[skip] @vscode/sqlite3 not available in Bun runtime; run with vitest for Node platform');
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const dbPath = join(tmpdir(), `platform-db-test-${engine}-${Date.now()}.db`);
|
|
20
20
|
const manager = new SqliteManager();
|
|
21
21
|
const adapter = manager.getOrCreate('test', { database: dbPath, wal: false });
|
|
22
22
|
|
|
23
|
-
adapter.query('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
|
|
24
|
-
adapter.query("INSERT INTO users (name) VALUES ('Alice')");
|
|
25
|
-
const rows = adapter.query<{ id: number; name: string }>('SELECT * FROM users');
|
|
23
|
+
await adapter.query('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
|
|
24
|
+
await adapter.query("INSERT INTO users (name) VALUES ('Alice')");
|
|
25
|
+
const rows = await adapter.query<{ id: number; name: string }>('SELECT * FROM users');
|
|
26
26
|
|
|
27
27
|
expect(rows.length).toBeGreaterThanOrEqual(1);
|
|
28
28
|
expect(rows[0]!.name).toBe('Alice');
|