@dangao/bun-server 3.0.5 → 3.2.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/dist/database/connection-manager.d.ts +2 -2
- package/dist/database/connection-manager.d.ts.map +1 -1
- package/dist/database/connection-pool.d.ts +4 -4
- package/dist/database/connection-pool.d.ts.map +1 -1
- package/dist/database/database-module.d.ts.map +1 -1
- package/dist/database/db-proxy.d.ts.map +1 -1
- package/dist/database/driver.d.ts +83 -0
- package/dist/database/driver.d.ts.map +1 -0
- package/dist/database/index.d.ts +2 -1
- package/dist/database/index.d.ts.map +1 -1
- package/dist/database/service.d.ts +0 -10
- package/dist/database/service.d.ts.map +1 -1
- package/dist/database/sql-manager.d.ts.map +1 -1
- package/dist/database/types.d.ts +26 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/di/module-registry.d.ts.map +1 -1
- package/dist/di/module.d.ts +9 -1
- package/dist/di/module.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5898 -5792
- package/dist/index.node.mjs +260 -114
- package/docs/database.md +44 -0
- package/docs/zh/database.md +44 -0
- package/package.json +1 -1
- package/src/database/connection-manager.ts +5 -46
- package/src/database/connection-pool.ts +26 -49
- package/src/database/database-module.ts +6 -0
- package/src/database/db-proxy.ts +3 -2
- package/src/database/driver.ts +368 -0
- package/src/database/index.ts +8 -0
- package/src/database/service.ts +3 -74
- package/src/database/sql-manager.ts +38 -24
- package/src/database/types.ts +27 -2
- package/src/di/module-registry.ts +15 -0
- package/src/di/module.ts +15 -1
- package/src/index.ts +1 -0
- package/tests/database/database-module.test.ts +4 -0
- package/tests/database/driver-mysql2.test.ts +95 -0
- package/tests/database/driver.test.ts +234 -0
- package/tests/database/orm.test.ts +4 -0
- package/tests/di/module.test.ts +74 -0
package/dist/index.node.mjs
CHANGED
|
@@ -5581,6 +5581,13 @@ class ModuleRegistry {
|
|
|
5581
5581
|
});
|
|
5582
5582
|
continue;
|
|
5583
5583
|
}
|
|
5584
|
+
if ("useExisting" in provider) {
|
|
5585
|
+
container.register(provider.provide, {
|
|
5586
|
+
lifecycle: provider.lifecycle ?? "singleton" /* Singleton */,
|
|
5587
|
+
factory: () => container.resolve(provider.useExisting)
|
|
5588
|
+
});
|
|
5589
|
+
continue;
|
|
5590
|
+
}
|
|
5584
5591
|
if ("useClass" in provider) {
|
|
5585
5592
|
const token = provider.provide ?? provider.useClass;
|
|
5586
5593
|
container.register(token, {
|
|
@@ -5660,6 +5667,12 @@ class ModuleRegistry {
|
|
|
5660
5667
|
seen.add(instance);
|
|
5661
5668
|
instances.push(instance);
|
|
5662
5669
|
}
|
|
5670
|
+
} else if ("useExisting" in provider) {
|
|
5671
|
+
const instance = ref.container.resolve(provider.provide);
|
|
5672
|
+
if (!seen.has(instance)) {
|
|
5673
|
+
seen.add(instance);
|
|
5674
|
+
instances.push(instance);
|
|
5675
|
+
}
|
|
5663
5676
|
}
|
|
5664
5677
|
} catch (_error) {}
|
|
5665
5678
|
}
|
|
@@ -10852,6 +10865,197 @@ init_decorators();
|
|
|
10852
10865
|
// src/database/connection-pool.ts
|
|
10853
10866
|
init_runtime();
|
|
10854
10867
|
|
|
10868
|
+
// src/database/driver.ts
|
|
10869
|
+
var DRIVER_TAG = Symbol.for("@dangao/bun-server:database:driver");
|
|
10870
|
+
function resolveDriver(dbType, option, engine) {
|
|
10871
|
+
const driver = option ?? "auto";
|
|
10872
|
+
switch (driver) {
|
|
10873
|
+
case "auto":
|
|
10874
|
+
if (engine === "bun") {
|
|
10875
|
+
return "bun-sql";
|
|
10876
|
+
}
|
|
10877
|
+
return dbType === "mysql" ? "mysql2" : "postgres";
|
|
10878
|
+
case "bun-sql":
|
|
10879
|
+
if (engine !== "bun") {
|
|
10880
|
+
throw new Error(`[bun-server] driver 'bun-sql' requires the Bun runtime, but the current platform engine is '${engine}'. ` + `Use driver 'auto' / 'mysql2' / 'postgres', or run on Bun.`);
|
|
10881
|
+
}
|
|
10882
|
+
return "bun-sql";
|
|
10883
|
+
case "mysql2":
|
|
10884
|
+
if (dbType !== "mysql") {
|
|
10885
|
+
throw new Error(`[bun-server] driver 'mysql2' is only valid for type 'mysql', but got type '${dbType}'.`);
|
|
10886
|
+
}
|
|
10887
|
+
return "mysql2";
|
|
10888
|
+
case "postgres":
|
|
10889
|
+
if (dbType !== "postgres") {
|
|
10890
|
+
throw new Error(`[bun-server] driver 'postgres' is only valid for type 'postgres', but got type '${dbType}'.`);
|
|
10891
|
+
}
|
|
10892
|
+
return "postgres";
|
|
10893
|
+
default:
|
|
10894
|
+
throw new Error(`[bun-server] unknown driver '${String(driver)}'.`);
|
|
10895
|
+
}
|
|
10896
|
+
}
|
|
10897
|
+
function tagConnection(connection, driver) {
|
|
10898
|
+
if (connection && (typeof connection === "object" || typeof connection === "function")) {
|
|
10899
|
+
try {
|
|
10900
|
+
Object.defineProperty(connection, DRIVER_TAG, {
|
|
10901
|
+
value: driver,
|
|
10902
|
+
enumerable: false,
|
|
10903
|
+
configurable: true,
|
|
10904
|
+
writable: true
|
|
10905
|
+
});
|
|
10906
|
+
} catch {}
|
|
10907
|
+
}
|
|
10908
|
+
return connection;
|
|
10909
|
+
}
|
|
10910
|
+
function getConnectionDriver(connection) {
|
|
10911
|
+
if (!connection) {
|
|
10912
|
+
return;
|
|
10913
|
+
}
|
|
10914
|
+
if (typeof connection === "object" || typeof connection === "function") {
|
|
10915
|
+
const tagged = connection[DRIVER_TAG];
|
|
10916
|
+
if (tagged === "bun-sql" || tagged === "mysql2" || tagged === "postgres") {
|
|
10917
|
+
return tagged;
|
|
10918
|
+
}
|
|
10919
|
+
}
|
|
10920
|
+
if (typeof connection === "function") {
|
|
10921
|
+
return "bun-sql";
|
|
10922
|
+
}
|
|
10923
|
+
return;
|
|
10924
|
+
}
|
|
10925
|
+
async function createPostgresConnection(config, driver) {
|
|
10926
|
+
const url = `postgres://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`;
|
|
10927
|
+
if (driver === "bun-sql") {
|
|
10928
|
+
const { SQL } = await import("bun");
|
|
10929
|
+
return tagConnection(new SQL({
|
|
10930
|
+
adapter: "postgres",
|
|
10931
|
+
hostname: config.host,
|
|
10932
|
+
port: config.port,
|
|
10933
|
+
username: config.user,
|
|
10934
|
+
password: config.password,
|
|
10935
|
+
database: config.database,
|
|
10936
|
+
max: 1,
|
|
10937
|
+
tls: config.ssl ?? false
|
|
10938
|
+
}), "bun-sql");
|
|
10939
|
+
}
|
|
10940
|
+
if (driver === "postgres") {
|
|
10941
|
+
const postgres = loadPostgres();
|
|
10942
|
+
return tagConnection(postgres(url, { max: 1, ssl: config.ssl ? "require" : false }), "postgres");
|
|
10943
|
+
}
|
|
10944
|
+
throw new Error(`[bun-server] driver '${driver}' cannot create a postgres connection.`);
|
|
10945
|
+
}
|
|
10946
|
+
async function createMysqlConnection(config, driver) {
|
|
10947
|
+
if (driver === "bun-sql") {
|
|
10948
|
+
const { SQL } = await import("bun");
|
|
10949
|
+
return tagConnection(new SQL({
|
|
10950
|
+
adapter: "mysql",
|
|
10951
|
+
hostname: config.host,
|
|
10952
|
+
port: config.port,
|
|
10953
|
+
username: config.user,
|
|
10954
|
+
password: config.password,
|
|
10955
|
+
database: config.database,
|
|
10956
|
+
max: 1,
|
|
10957
|
+
ssl: config.ssl ?? false
|
|
10958
|
+
}), "bun-sql");
|
|
10959
|
+
}
|
|
10960
|
+
if (driver === "mysql2") {
|
|
10961
|
+
const mysql2 = loadMysql2();
|
|
10962
|
+
const conn = await mysql2.createConnection({
|
|
10963
|
+
host: config.host,
|
|
10964
|
+
port: config.port,
|
|
10965
|
+
database: config.database,
|
|
10966
|
+
user: config.user,
|
|
10967
|
+
password: config.password
|
|
10968
|
+
});
|
|
10969
|
+
return tagConnection(conn, "mysql2");
|
|
10970
|
+
}
|
|
10971
|
+
throw new Error(`[bun-server] driver '${driver}' cannot create a mysql connection.`);
|
|
10972
|
+
}
|
|
10973
|
+
async function queryViaDriver(connection, sql, params) {
|
|
10974
|
+
const driver = getConnectionDriver(connection);
|
|
10975
|
+
if (driver === "mysql2") {
|
|
10976
|
+
const conn = connection;
|
|
10977
|
+
const [rows] = await conn.query(sql, params ?? []);
|
|
10978
|
+
return rows ?? [];
|
|
10979
|
+
}
|
|
10980
|
+
if (driver === "postgres") {
|
|
10981
|
+
const conn = connection;
|
|
10982
|
+
const rows = await conn.unsafe(sql, params ?? []);
|
|
10983
|
+
return rows ?? [];
|
|
10984
|
+
}
|
|
10985
|
+
if (typeof connection === "function") {
|
|
10986
|
+
const { strings, values } = buildTemplateFromSql(sql, params);
|
|
10987
|
+
const template = Object.assign(strings.slice(), {
|
|
10988
|
+
raw: strings.slice()
|
|
10989
|
+
});
|
|
10990
|
+
const result = await connection(template, ...values);
|
|
10991
|
+
return result;
|
|
10992
|
+
}
|
|
10993
|
+
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
10994
|
+
const result = await connection.query(sql, params ?? []);
|
|
10995
|
+
return Array.isArray(result) ? result[0] : result;
|
|
10996
|
+
}
|
|
10997
|
+
throw new Error("[bun-server] invalid SQL connection for query.");
|
|
10998
|
+
}
|
|
10999
|
+
async function templateQueryViaDriver(connection, strings, values) {
|
|
11000
|
+
const driver = getConnectionDriver(connection);
|
|
11001
|
+
if (driver === "mysql2") {
|
|
11002
|
+
const sql = strings.join("?");
|
|
11003
|
+
const conn = connection;
|
|
11004
|
+
const [rows] = await conn.query(sql, values);
|
|
11005
|
+
return rows;
|
|
11006
|
+
}
|
|
11007
|
+
return await connection(strings, ...values);
|
|
11008
|
+
}
|
|
11009
|
+
async function healthCheckViaDriver(connection) {
|
|
11010
|
+
try {
|
|
11011
|
+
const rows = await queryViaDriver(connection, "SELECT 1");
|
|
11012
|
+
return Array.isArray(rows);
|
|
11013
|
+
} catch {
|
|
11014
|
+
return false;
|
|
11015
|
+
}
|
|
11016
|
+
}
|
|
11017
|
+
async function closeViaDriver(connection) {
|
|
11018
|
+
if (!connection || typeof connection !== "object" && typeof connection !== "function") {
|
|
11019
|
+
return;
|
|
11020
|
+
}
|
|
11021
|
+
const driver = getConnectionDriver(connection);
|
|
11022
|
+
const conn = connection;
|
|
11023
|
+
if (driver === "mysql2" || driver === "postgres") {
|
|
11024
|
+
if (typeof conn.end === "function") {
|
|
11025
|
+
await conn.end();
|
|
11026
|
+
return;
|
|
11027
|
+
}
|
|
11028
|
+
}
|
|
11029
|
+
if (driver === "bun-sql") {
|
|
11030
|
+
if (typeof conn.close === "function") {
|
|
11031
|
+
await conn.close();
|
|
11032
|
+
return;
|
|
11033
|
+
}
|
|
11034
|
+
}
|
|
11035
|
+
if (typeof conn.close === "function") {
|
|
11036
|
+
await conn.close();
|
|
11037
|
+
} else if (typeof conn.end === "function") {
|
|
11038
|
+
await conn.end();
|
|
11039
|
+
}
|
|
11040
|
+
}
|
|
11041
|
+
function buildTemplateFromSql(sql, params) {
|
|
11042
|
+
if (!params || params.length === 0) {
|
|
11043
|
+
return { strings: [sql], values: [] };
|
|
11044
|
+
}
|
|
11045
|
+
const strings = sql.split("?");
|
|
11046
|
+
if (strings.length !== params.length + 1) {
|
|
11047
|
+
throw new Error("SQL placeholders count does not match parameters count");
|
|
11048
|
+
}
|
|
11049
|
+
return { strings, values: params };
|
|
11050
|
+
}
|
|
11051
|
+
function loadMysql2() {
|
|
11052
|
+
return __require("mysql2/promise");
|
|
11053
|
+
}
|
|
11054
|
+
function loadPostgres() {
|
|
11055
|
+
return __require("postgres");
|
|
11056
|
+
}
|
|
11057
|
+
|
|
11058
|
+
// src/database/connection-pool.ts
|
|
10855
11059
|
class ConnectionPool {
|
|
10856
11060
|
config;
|
|
10857
11061
|
options;
|
|
@@ -10966,29 +11170,12 @@ Install it with: bun add @vscode/sqlite3@5.1.12-vscode`);
|
|
|
10966
11170
|
return new sqlite3.Database(config.path);
|
|
10967
11171
|
}
|
|
10968
11172
|
async createPostgresConnection(config) {
|
|
10969
|
-
const
|
|
10970
|
-
|
|
10971
|
-
const { SQL } = await import("bun");
|
|
10972
|
-
return new SQL(url, { max: 1, tls: config.ssl ?? false });
|
|
10973
|
-
}
|
|
10974
|
-
const postgres = __require("postgres");
|
|
10975
|
-
return postgres(url, { max: 1, ssl: config.ssl ? "require" : false });
|
|
11173
|
+
const driver = resolveDriver("postgres", this.config.type === "postgres" ? this.config.driver : undefined, getRuntime().engine);
|
|
11174
|
+
return await createPostgresConnection(config, driver);
|
|
10976
11175
|
}
|
|
10977
11176
|
async createMysqlConnection(config) {
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
const { SQL } = await import("bun");
|
|
10981
|
-
return new SQL(url, { max: 1 });
|
|
10982
|
-
}
|
|
10983
|
-
const mysql2 = __require("mysql2/promise");
|
|
10984
|
-
const conn = await mysql2.createConnection({
|
|
10985
|
-
host: config.host,
|
|
10986
|
-
port: config.port,
|
|
10987
|
-
database: config.database,
|
|
10988
|
-
user: config.user,
|
|
10989
|
-
password: config.password
|
|
10990
|
-
});
|
|
10991
|
-
return conn;
|
|
11177
|
+
const driver = resolveDriver("mysql", this.config.type === "mysql" ? this.config.driver : undefined, getRuntime().engine);
|
|
11178
|
+
return await createMysqlConnection(config, driver);
|
|
10992
11179
|
}
|
|
10993
11180
|
async closeConnection(connection) {
|
|
10994
11181
|
const dbType = this.config.type;
|
|
@@ -11005,15 +11192,11 @@ Install it with: bun add @vscode/sqlite3@5.1.12-vscode`);
|
|
|
11005
11192
|
connection.close();
|
|
11006
11193
|
}
|
|
11007
11194
|
}
|
|
11008
|
-
async closePostgresConnection(
|
|
11009
|
-
|
|
11010
|
-
_connection.close();
|
|
11011
|
-
}
|
|
11195
|
+
async closePostgresConnection(connection) {
|
|
11196
|
+
await closeViaDriver(connection);
|
|
11012
11197
|
}
|
|
11013
|
-
async closeMysqlConnection(
|
|
11014
|
-
|
|
11015
|
-
_connection.close();
|
|
11016
|
-
}
|
|
11198
|
+
async closeMysqlConnection(connection) {
|
|
11199
|
+
await closeViaDriver(connection);
|
|
11017
11200
|
}
|
|
11018
11201
|
async waitForConnection() {
|
|
11019
11202
|
const startTime = Date.now();
|
|
@@ -11154,34 +11337,10 @@ class DatabaseConnectionManager {
|
|
|
11154
11337
|
}
|
|
11155
11338
|
}
|
|
11156
11339
|
async healthCheckPostgres(connection) {
|
|
11157
|
-
|
|
11158
|
-
if (connection && typeof connection === "function") {
|
|
11159
|
-
const result = await connection`SELECT 1`;
|
|
11160
|
-
return Array.isArray(result) && result.length > 0;
|
|
11161
|
-
}
|
|
11162
|
-
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
11163
|
-
await connection.query("SELECT 1");
|
|
11164
|
-
return true;
|
|
11165
|
-
}
|
|
11166
|
-
return false;
|
|
11167
|
-
} catch (_error) {
|
|
11168
|
-
return false;
|
|
11169
|
-
}
|
|
11340
|
+
return await healthCheckViaDriver(connection);
|
|
11170
11341
|
}
|
|
11171
11342
|
async healthCheckMysql(connection) {
|
|
11172
|
-
|
|
11173
|
-
if (connection && typeof connection === "function") {
|
|
11174
|
-
const result = await connection`SELECT 1`;
|
|
11175
|
-
return Array.isArray(result) && result.length > 0;
|
|
11176
|
-
}
|
|
11177
|
-
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
11178
|
-
await connection.query("SELECT 1");
|
|
11179
|
-
return true;
|
|
11180
|
-
}
|
|
11181
|
-
return false;
|
|
11182
|
-
} catch (_error) {
|
|
11183
|
-
return false;
|
|
11184
|
-
}
|
|
11343
|
+
return await healthCheckViaDriver(connection);
|
|
11185
11344
|
}
|
|
11186
11345
|
}
|
|
11187
11346
|
|
|
@@ -11252,7 +11411,7 @@ class DatabaseService2 {
|
|
|
11252
11411
|
if (dbType === "sqlite") {
|
|
11253
11412
|
return this.querySqlite(connection, sql, params);
|
|
11254
11413
|
} else if (dbType === "postgres" || dbType === "mysql") {
|
|
11255
|
-
return
|
|
11414
|
+
return queryViaDriver(connection, sql, params);
|
|
11256
11415
|
}
|
|
11257
11416
|
throw new Error(`Query not supported for database type: ${dbType}`);
|
|
11258
11417
|
}
|
|
@@ -11275,37 +11434,6 @@ class DatabaseService2 {
|
|
|
11275
11434
|
}
|
|
11276
11435
|
throw new Error("Invalid SQLite connection");
|
|
11277
11436
|
}
|
|
11278
|
-
async queryBunSQL(connection, sql, params) {
|
|
11279
|
-
if (connection && typeof connection === "function") {
|
|
11280
|
-
try {
|
|
11281
|
-
const { strings, values } = this.buildTemplateFromSql(sql, params);
|
|
11282
|
-
const template = Object.assign(strings, {
|
|
11283
|
-
raw: strings
|
|
11284
|
-
});
|
|
11285
|
-
const result = await connection(template, ...values);
|
|
11286
|
-
return result;
|
|
11287
|
-
} catch (error) {
|
|
11288
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11289
|
-
throw new Error(`Bun.SQL parameterized queries are not fully supported. Consider using template string queries. Original error: ${errorMessage}`);
|
|
11290
|
-
}
|
|
11291
|
-
}
|
|
11292
|
-
if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
|
|
11293
|
-
const db = connection;
|
|
11294
|
-
const result = await db.query(sql, ...params ?? []);
|
|
11295
|
-
return result;
|
|
11296
|
-
}
|
|
11297
|
-
throw new Error("Invalid Bun.SQL connection");
|
|
11298
|
-
}
|
|
11299
|
-
buildTemplateFromSql(sql, params) {
|
|
11300
|
-
if (!params || params.length === 0) {
|
|
11301
|
-
return { strings: [sql], values: [] };
|
|
11302
|
-
}
|
|
11303
|
-
const strings = sql.split("?");
|
|
11304
|
-
if (strings.length !== params.length + 1) {
|
|
11305
|
-
throw new Error("SQL placeholders count does not match parameters count");
|
|
11306
|
-
}
|
|
11307
|
-
return { strings, values: params };
|
|
11308
|
-
}
|
|
11309
11437
|
}
|
|
11310
11438
|
DatabaseService2 = __legacyDecorateClassTS([
|
|
11311
11439
|
Injectable(),
|
|
@@ -11319,7 +11447,6 @@ var ORM_SERVICE_TOKEN = Symbol("@dangao/bun-server:orm:service");
|
|
|
11319
11447
|
|
|
11320
11448
|
// src/database/sql-manager.ts
|
|
11321
11449
|
init_runtime();
|
|
11322
|
-
|
|
11323
11450
|
class BunSQLManager2 {
|
|
11324
11451
|
instances = new Map;
|
|
11325
11452
|
defaultTenantId = "default";
|
|
@@ -11329,34 +11456,49 @@ class BunSQLManager2 {
|
|
|
11329
11456
|
return existing;
|
|
11330
11457
|
}
|
|
11331
11458
|
const pool = config.pool ?? {};
|
|
11459
|
+
const driver = resolveDriver(config.type, config.driver, getRuntime().engine);
|
|
11332
11460
|
let sql;
|
|
11333
|
-
if (
|
|
11461
|
+
if (driver === "bun-sql") {
|
|
11334
11462
|
const { SQL } = __require("bun");
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11340
|
-
|
|
11341
|
-
|
|
11342
|
-
|
|
11343
|
-
|
|
11344
|
-
|
|
11345
|
-
|
|
11346
|
-
|
|
11347
|
-
|
|
11348
|
-
waitForConnections: true
|
|
11463
|
+
if (config.type === "mysql") {
|
|
11464
|
+
const parsed = new URL(config.url);
|
|
11465
|
+
sql = new SQL({
|
|
11466
|
+
adapter: "mysql",
|
|
11467
|
+
hostname: parsed.hostname,
|
|
11468
|
+
port: parsed.port ? Number(parsed.port) : 3306,
|
|
11469
|
+
username: decodeURIComponent(parsed.username),
|
|
11470
|
+
password: decodeURIComponent(parsed.password),
|
|
11471
|
+
database: parsed.pathname.replace(/^\//, ""),
|
|
11472
|
+
max: pool.max ?? 10,
|
|
11473
|
+
idleTimeout: pool.idleTimeout ?? 30,
|
|
11474
|
+
maxLifetime: pool.maxLifetime ?? 0,
|
|
11475
|
+
connectionTimeout: pool.connectionTimeout ?? 30000
|
|
11349
11476
|
});
|
|
11350
11477
|
} else {
|
|
11351
|
-
|
|
11352
|
-
sql = postgres(config.url, {
|
|
11478
|
+
sql = new SQL(config.url, {
|
|
11353
11479
|
max: pool.max ?? 10,
|
|
11354
|
-
|
|
11355
|
-
|
|
11356
|
-
|
|
11480
|
+
idleTimeout: pool.idleTimeout ?? 30,
|
|
11481
|
+
maxLifetime: pool.maxLifetime ?? 0,
|
|
11482
|
+
connectionTimeout: pool.connectionTimeout ?? 30000
|
|
11357
11483
|
});
|
|
11358
11484
|
}
|
|
11485
|
+
} else if (driver === "mysql2") {
|
|
11486
|
+
const mysql2 = __require("mysql2/promise");
|
|
11487
|
+
sql = mysql2.createPool({
|
|
11488
|
+
uri: config.url,
|
|
11489
|
+
connectionLimit: pool.max ?? 10,
|
|
11490
|
+
waitForConnections: true
|
|
11491
|
+
});
|
|
11492
|
+
} else {
|
|
11493
|
+
const postgres = __require("postgres");
|
|
11494
|
+
sql = postgres(config.url, {
|
|
11495
|
+
max: pool.max ?? 10,
|
|
11496
|
+
idle_timeout: pool.idleTimeout ?? 30,
|
|
11497
|
+
max_lifetime: pool.maxLifetime ?? 0,
|
|
11498
|
+
connect_timeout: (pool.connectionTimeout ?? 30000) / 1000
|
|
11499
|
+
});
|
|
11359
11500
|
}
|
|
11501
|
+
tagConnection(sql, driver);
|
|
11360
11502
|
this.instances.set(tenantId, sql);
|
|
11361
11503
|
return sql;
|
|
11362
11504
|
}
|
|
@@ -11567,10 +11709,10 @@ var baseDb = async (tenantId, strings, ...values) => {
|
|
|
11567
11709
|
if (tenantId) {
|
|
11568
11710
|
const tenantSql = sqlManager.get(tenantId);
|
|
11569
11711
|
if (tenantSql) {
|
|
11570
|
-
return await tenantSql
|
|
11712
|
+
return await templateQueryViaDriver(tenantSql, strings, values);
|
|
11571
11713
|
}
|
|
11572
11714
|
}
|
|
11573
|
-
return await sqlManager.getDefault()
|
|
11715
|
+
return await templateQueryViaDriver(sqlManager.getDefault(), strings, values);
|
|
11574
11716
|
};
|
|
11575
11717
|
function createDb(tenantId) {
|
|
11576
11718
|
const fn = async (strings, ...values) => baseDb(tenantId, strings, ...values);
|
|
@@ -11644,7 +11786,8 @@ class DatabaseModule {
|
|
|
11644
11786
|
config: {
|
|
11645
11787
|
type: db2.type,
|
|
11646
11788
|
url,
|
|
11647
|
-
pool: options.bunSqlPool
|
|
11789
|
+
pool: options.bunSqlPool,
|
|
11790
|
+
driver: db2.driver ?? options.driver
|
|
11648
11791
|
}
|
|
11649
11792
|
}
|
|
11650
11793
|
];
|
|
@@ -11669,7 +11812,8 @@ class DatabaseModule {
|
|
|
11669
11812
|
config: {
|
|
11670
11813
|
type: options.type,
|
|
11671
11814
|
url: options.url,
|
|
11672
|
-
pool: options.bunSqlPool
|
|
11815
|
+
pool: options.bunSqlPool,
|
|
11816
|
+
driver: options.driver
|
|
11673
11817
|
}
|
|
11674
11818
|
}
|
|
11675
11819
|
];
|
|
@@ -11683,7 +11827,8 @@ class DatabaseModule {
|
|
|
11683
11827
|
config: {
|
|
11684
11828
|
type: options.type,
|
|
11685
11829
|
url,
|
|
11686
|
-
pool: options.bunSqlPool
|
|
11830
|
+
pool: options.bunSqlPool,
|
|
11831
|
+
driver: options.driver
|
|
11687
11832
|
}
|
|
11688
11833
|
}
|
|
11689
11834
|
];
|
|
@@ -11767,7 +11912,8 @@ class DatabaseModule {
|
|
|
11767
11912
|
database: options.databasePath ?? "default",
|
|
11768
11913
|
user: options.username ?? "root",
|
|
11769
11914
|
password: options.password ?? ""
|
|
11770
|
-
}
|
|
11915
|
+
},
|
|
11916
|
+
driver: normalized[0]?.config?.driver ?? options.driver
|
|
11771
11917
|
}
|
|
11772
11918
|
};
|
|
11773
11919
|
const service = new DatabaseService2(legacyOptions);
|
package/docs/database.md
CHANGED
|
@@ -25,6 +25,50 @@ DatabaseModule.forRoot({
|
|
|
25
25
|
});
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## Driver selection (decoupled from the runtime platform)
|
|
29
|
+
|
|
30
|
+
> Added in v3.2.0.
|
|
31
|
+
|
|
32
|
+
By default the underlying driver for Postgres/MySQL is chosen by the runtime platform: the Bun runtime uses the built-in `Bun.SQL`, while Node.js uses the pure-JS `mysql2` / `postgres` drivers.
|
|
33
|
+
|
|
34
|
+
The optional `driver` field lets you **explicitly pick a pure-JS driver even under the Bun runtime**, decoupled from the platform engine (fs/crypto/http server, etc.):
|
|
35
|
+
|
|
36
|
+
| driver | Behavior |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `'auto'` (default) | Bun → `Bun.SQL`; Node → `mysql2` (MySQL) / `postgres` (PostgreSQL). Backward compatible. |
|
|
39
|
+
| `'mysql2'` | Always use `mysql2`, regardless of runtime (only for `type: 'mysql'`). |
|
|
40
|
+
| `'postgres'` | Always use `postgres`, regardless of runtime (only for `type: 'postgres'`). |
|
|
41
|
+
| `'bun-sql'` | Force `Bun.SQL` (valid on Bun only; throws a clear error on Node). |
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
DatabaseModule.forRoot({
|
|
45
|
+
database: {
|
|
46
|
+
type: 'mysql',
|
|
47
|
+
driver: 'mysql2', // uses mysql2 even on the Bun runtime
|
|
48
|
+
config: {
|
|
49
|
+
host: '127.0.0.1',
|
|
50
|
+
port: 3306,
|
|
51
|
+
database: 'app',
|
|
52
|
+
user: 'root',
|
|
53
|
+
password: process.env.DB_PASSWORD!,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// The V2 single-tenant form is supported too:
|
|
59
|
+
DatabaseModule.forRoot({
|
|
60
|
+
type: 'mysql',
|
|
61
|
+
url: process.env.DB_URL!,
|
|
62
|
+
driver: 'mysql2',
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Why? MySQL under `bun build --compile`
|
|
67
|
+
|
|
68
|
+
A single binary produced by `bun build --compile` freezes the Bun runtime at build time, and the built-in `Bun.SQL` MySQL adapter has several known issues. Setting `driver: 'mysql2'` lets the compiled binary connect using the statically bundled pure-JS `mysql2` driver, without falling back to SQLite and without switching the whole platform via `BUN_SERVER_PLATFORM=node` (which would also move the HTTP server to Node).
|
|
69
|
+
|
|
70
|
+
The `driver` switch is orthogonal to `BUN_SERVER_PLATFORM`: the former only selects the SQL driver, while the latter selects the entire platform engine.
|
|
71
|
+
|
|
28
72
|
## Route strategy
|
|
29
73
|
|
|
30
74
|
```ts
|
package/docs/zh/database.md
CHANGED
|
@@ -25,6 +25,50 @@ DatabaseModule.forRoot({
|
|
|
25
25
|
});
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## 驱动选择(driver,与运行时平台解耦)
|
|
29
|
+
|
|
30
|
+
> v3.2.0 新增。
|
|
31
|
+
|
|
32
|
+
默认情况下,Postgres/MySQL 连接的底层驱动由运行时平台决定:Bun 运行时使用内建 `Bun.SQL`,Node.js 运行时使用 `mysql2` / `postgres` 纯 JS 驱动。
|
|
33
|
+
|
|
34
|
+
通过可选的 `driver` 字段,可以**在 Bun 运行时下也显式选用纯 JS 驱动**,与平台引擎(fs/crypto/http server 等)解耦:
|
|
35
|
+
|
|
36
|
+
| driver | 行为 |
|
|
37
|
+
| --- | --- |
|
|
38
|
+
| `'auto'`(默认) | Bun → `Bun.SQL`;Node → `mysql2`(MySQL)/ `postgres`(PostgreSQL)。向后兼容。 |
|
|
39
|
+
| `'mysql2'` | 无论运行时如何,都使用 `mysql2`(仅 `type: 'mysql'`)。 |
|
|
40
|
+
| `'postgres'` | 无论运行时如何,都使用 `postgres`(仅 `type: 'postgres'`)。 |
|
|
41
|
+
| `'bun-sql'` | 强制使用 `Bun.SQL`(仅 Bun 合法,Node 会抛出清晰错误)。 |
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
DatabaseModule.forRoot({
|
|
45
|
+
database: {
|
|
46
|
+
type: 'mysql',
|
|
47
|
+
driver: 'mysql2', // 即使在 Bun 运行时也走 mysql2
|
|
48
|
+
config: {
|
|
49
|
+
host: '127.0.0.1',
|
|
50
|
+
port: 3306,
|
|
51
|
+
database: 'app',
|
|
52
|
+
user: 'root',
|
|
53
|
+
password: process.env.DB_PASSWORD!,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// V2 单租户写法同样支持:
|
|
59
|
+
DatabaseModule.forRoot({
|
|
60
|
+
type: 'mysql',
|
|
61
|
+
url: process.env.DB_URL!,
|
|
62
|
+
driver: 'mysql2',
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 为什么需要它?`bun build --compile` 下的 MySQL
|
|
67
|
+
|
|
68
|
+
`bun build --compile` 产出的单二进制会把当时的 Bun 运行时焊死,其中内建 `Bun.SQL` 的 MySQL 适配带有若干已知问题。显式设置 `driver: 'mysql2'` 即可让编译产物使用静态打包的纯 JS `mysql2` 驱动连库,无需为此回退到 SQLite,也无需用 `BUN_SERVER_PLATFORM=node` 整体切平台(那会把 HTTP server 也切到 Node)。
|
|
69
|
+
|
|
70
|
+
`driver` 开关与 `BUN_SERVER_PLATFORM` 正交:前者只决定 SQL 驱动,后者决定整个平台引擎。
|
|
71
|
+
|
|
28
72
|
## 路由策略示例
|
|
29
73
|
|
|
30
74
|
```ts
|
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
} from './types';
|
|
8
8
|
|
|
9
9
|
import { ConnectionPool } from './connection-pool';
|
|
10
|
+
import { healthCheckViaDriver } from './driver';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* 数据库连接管理器
|
|
@@ -189,58 +190,16 @@ export class DatabaseConnectionManager {
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
/**
|
|
192
|
-
* PostgreSQL
|
|
193
|
+
* PostgreSQL 健康检查(按连接 driver tag 分流)
|
|
193
194
|
*/
|
|
194
195
|
private async healthCheckPostgres(connection: unknown): Promise<boolean> {
|
|
195
|
-
|
|
196
|
-
// Bun.SQL 对象可以作为函数调用(模板字符串)
|
|
197
|
-
if (connection && typeof connection === 'function') {
|
|
198
|
-
const result = await (connection as (template: TemplateStringsArray, ...values: unknown[]) => Promise<unknown[]>)`SELECT 1`;
|
|
199
|
-
return Array.isArray(result) && result.length > 0;
|
|
200
|
-
}
|
|
201
|
-
// 或者使用 query 方法(如果存在)
|
|
202
|
-
if (
|
|
203
|
-
connection &&
|
|
204
|
-
typeof connection === 'object' &&
|
|
205
|
-
'query' in connection &&
|
|
206
|
-
typeof connection.query === 'function'
|
|
207
|
-
) {
|
|
208
|
-
await (connection as { query: (sql: string) => Promise<unknown> }).query(
|
|
209
|
-
'SELECT 1',
|
|
210
|
-
);
|
|
211
|
-
return true;
|
|
212
|
-
}
|
|
213
|
-
return false;
|
|
214
|
-
} catch (_error) {
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
196
|
+
return await healthCheckViaDriver(connection);
|
|
217
197
|
}
|
|
218
198
|
|
|
219
199
|
/**
|
|
220
|
-
* MySQL
|
|
200
|
+
* MySQL 健康检查(按连接 driver tag 分流)
|
|
221
201
|
*/
|
|
222
202
|
private async healthCheckMysql(connection: unknown): Promise<boolean> {
|
|
223
|
-
|
|
224
|
-
// Bun.SQL 对象可以作为函数调用(模板字符串)
|
|
225
|
-
if (connection && typeof connection === 'function') {
|
|
226
|
-
const result = await (connection as (template: TemplateStringsArray, ...values: unknown[]) => Promise<unknown[]>)`SELECT 1`;
|
|
227
|
-
return Array.isArray(result) && result.length > 0;
|
|
228
|
-
}
|
|
229
|
-
// 或者使用 query 方法(如果存在)
|
|
230
|
-
if (
|
|
231
|
-
connection &&
|
|
232
|
-
typeof connection === 'object' &&
|
|
233
|
-
'query' in connection &&
|
|
234
|
-
typeof connection.query === 'function'
|
|
235
|
-
) {
|
|
236
|
-
await (connection as { query: (sql: string) => Promise<unknown> }).query(
|
|
237
|
-
'SELECT 1',
|
|
238
|
-
);
|
|
239
|
-
return true;
|
|
240
|
-
}
|
|
241
|
-
return false;
|
|
242
|
-
} catch (_error) {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
203
|
+
return await healthCheckViaDriver(connection);
|
|
245
204
|
}
|
|
246
205
|
}
|