@aetherframework/database 1.0.9 → 1.1.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/package.json +1 -2
- package/src/DatabaseManager.js +0 -565
- package/src/core/ConnectionManager.js +0 -351
- package/src/core/DatabaseFactory.js +0 -188
- package/src/core/MongoQueryBuilder.js +0 -576
- package/src/core/PluginManager.js +0 -968
- package/src/core/QueryBuilder.js +0 -4398
- package/src/core/TransactionManager.js +0 -40
- package/src/drivers/clickhouse-driver.js +0 -272
- package/src/drivers/index.js +0 -273
- package/src/drivers/mongodb-driver.js +0 -87
- package/src/drivers/mssql-driver.js +0 -117
- package/src/drivers/mysql-driver.js +0 -169
- package/src/drivers/oracle-driver.js +0 -101
- package/src/drivers/postgres-driver.js +0 -234
- package/src/drivers/redis-driver.js +0 -52
- package/src/drivers/sqlite-driver.js +0 -67
- package/src/middleware/connection-pool.js +0 -455
- package/src/middleware/performance-monitor.js +0 -652
- package/src/middleware/query-cache.js +0 -500
- package/src/middleware/query-logger.js +0 -262
- package/src/plugins/AuditPlugin.js +0 -447
- package/src/plugins/BasePlugin.js +0 -418
- package/src/plugins/BatchOperationPlugin.js +0 -165
- package/src/plugins/CachePlugin.js +0 -407
- package/src/plugins/CtePlugin.js +0 -523
- package/src/plugins/DistributedPlugin.js +0 -543
- package/src/plugins/EncryptionPlugin.js +0 -211
- package/src/plugins/FullTextSearchPlugin.js +0 -164
- package/src/plugins/GeospatialPlugin.js +0 -219
- package/src/plugins/GraphQLPlugin.js +0 -162
- package/src/plugins/HookPlugin.js +0 -211
- package/src/plugins/JsonPlugin.js +0 -366
- package/src/plugins/OptimisticLockPlugin.js +0 -374
- package/src/plugins/PerformancePlugin.js +0 -175
- package/src/plugins/ResiliencePlugin.js +0 -114
- package/src/plugins/ShardingPlugin.js +0 -227
- package/src/plugins/SoftDeletePlugin.js +0 -258
- package/src/plugins/SyncPlugin.js +0 -373
- package/src/plugins/VersioningPlugin.js +0 -314
- package/src/plugins/WindowFunctionPlugin.js +0 -343
- package/src/utils/config-loader.js +0 -632
- package/src/utils/error-handler.js +0 -724
- package/src/utils/migration-runner.js +0 -1066
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/mssql-driver
|
|
6
|
-
*/
|
|
7
|
-
import sql from 'mssql';
|
|
8
|
-
|
|
9
|
-
class MSSQLDriver {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.pool = null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async connect(config) {
|
|
16
|
-
const connection = await sql.connect({
|
|
17
|
-
server: config.host,
|
|
18
|
-
port: config.port,
|
|
19
|
-
user: config.user,
|
|
20
|
-
password: config.password,
|
|
21
|
-
database: config.database,
|
|
22
|
-
options: {
|
|
23
|
-
encrypt: config.options?.encrypt || false,
|
|
24
|
-
trustServerCertificate: config.options?.trustServerCertificate || false,
|
|
25
|
-
enableArithAbort: true
|
|
26
|
-
},
|
|
27
|
-
pool: {
|
|
28
|
-
max: config.pool?.max || 10,
|
|
29
|
-
min: config.pool?.min || 2,
|
|
30
|
-
idleTimeoutMillis: config.pool?.idleTimeout || 30000,
|
|
31
|
-
acquireTimeoutMillis: config.pool?.acquireTimeout || 10000
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
return connection;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async createPool(config) {
|
|
38
|
-
this.pool = new sql.ConnectionPool({
|
|
39
|
-
server: config.host,
|
|
40
|
-
port: config.port,
|
|
41
|
-
user: config.user,
|
|
42
|
-
password: config.password,
|
|
43
|
-
database: config.database,
|
|
44
|
-
options: {
|
|
45
|
-
encrypt: config.options?.encrypt || false,
|
|
46
|
-
trustServerCertificate: config.options?.trustServerCertificate || false,
|
|
47
|
-
enableArithAbort: true
|
|
48
|
-
},
|
|
49
|
-
pool: {
|
|
50
|
-
max: config.pool?.max || 10,
|
|
51
|
-
min: config.pool?.min || 2,
|
|
52
|
-
idleTimeoutMillis: config.pool?.idleTimeout || 30000,
|
|
53
|
-
acquireTimeoutMillis: config.pool?.acquireTimeout || 10000
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
await this.pool.connect();
|
|
57
|
-
return this.pool;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async query(connection, sqlText, params = []) {
|
|
61
|
-
const request = connection.request();
|
|
62
|
-
|
|
63
|
-
// Add parameters if provided
|
|
64
|
-
params.forEach((param, index) => {
|
|
65
|
-
request.input(`param${index}`, param);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
const result = await request.query(sqlText);
|
|
69
|
-
return {
|
|
70
|
-
rows: result.recordset,
|
|
71
|
-
rowCount: result.rowsAffected,
|
|
72
|
-
recordsets: result.recordsets
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async execute(connection, sqlText, params = []) {
|
|
77
|
-
return this.query(connection, sqlText, params);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async beginTransaction(connection) {
|
|
81
|
-
const transaction = new sql.Transaction(connection);
|
|
82
|
-
await transaction.begin();
|
|
83
|
-
return transaction;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async commitTransaction(transaction) {
|
|
87
|
-
await transaction.commit();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async rollbackTransaction(transaction) {
|
|
91
|
-
await transaction.rollback();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async close(connection) {
|
|
95
|
-
await connection.close();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async closePool(pool) {
|
|
99
|
-
await pool.close();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
getPoolStats(pool) {
|
|
103
|
-
return {
|
|
104
|
-
size: pool.size,
|
|
105
|
-
available: pool.available,
|
|
106
|
-
pending: pool.pending,
|
|
107
|
-
borrowed: pool.borrowed
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async healthCheck(connection) {
|
|
112
|
-
const result = await connection.request().query('SELECT 1 as health');
|
|
113
|
-
return result.recordset.health === 1;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export default MSSQLDriver;
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/mysql-driver
|
|
6
|
-
*/
|
|
7
|
-
import mysql from "mysql2/promise";
|
|
8
|
-
|
|
9
|
-
class MySQLDriver {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.pool = null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** 创建单个连接(修正版:不要混入 pool 参数) */
|
|
16
|
-
async connect(config = this.config) {
|
|
17
|
-
const connConfig = {
|
|
18
|
-
host: config.host,
|
|
19
|
-
port: config.port || 3306,
|
|
20
|
-
user: config.user,
|
|
21
|
-
password: config.password,
|
|
22
|
-
database: config.database,
|
|
23
|
-
charset: config.charset || "utf8mb4",
|
|
24
|
-
timezone: config.timezone || "+00:00",
|
|
25
|
-
connectTimeout: config.connectTimeout || 10000,
|
|
26
|
-
// 只保留单连接需要的参数
|
|
27
|
-
supportBigNumbers: true,
|
|
28
|
-
bigNumberStrings: true,
|
|
29
|
-
dateStrings: true,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
return await mysql.createConnection(connConfig);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** 创建连接池 */
|
|
36
|
-
async createPool(config = this.config) {
|
|
37
|
-
this.pool = mysql.createPool({
|
|
38
|
-
host: config.host,
|
|
39
|
-
port: config.port || 3306,
|
|
40
|
-
user: config.user,
|
|
41
|
-
password: config.password,
|
|
42
|
-
database: config.database,
|
|
43
|
-
charset: config.charset || "utf8mb4",
|
|
44
|
-
timezone: config.timezone || "+00:00",
|
|
45
|
-
waitForConnections: true,
|
|
46
|
-
connectionLimit: config.pool?.max || 10,
|
|
47
|
-
queueLimit: config.pool?.queueLimit || 0,
|
|
48
|
-
idleTimeout: config.pool?.idleTimeout || 30000,
|
|
49
|
-
acquireTimeout: config.pool?.acquireTimeout || 10000,
|
|
50
|
-
enableKeepAlive: true,
|
|
51
|
-
keepAliveInitialDelay: 0,
|
|
52
|
-
supportBigNumbers: true,
|
|
53
|
-
bigNumberStrings: true,
|
|
54
|
-
dateStrings: true,
|
|
55
|
-
});
|
|
56
|
-
return this.pool;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** SELECT 查询 */
|
|
60
|
-
async query(connection, sql, params = []) {
|
|
61
|
-
const validatedParams = this._validateAndPrepareParams(sql, params);
|
|
62
|
-
const [rows, fields] = await connection.execute(sql, validatedParams);
|
|
63
|
-
return {
|
|
64
|
-
rows,
|
|
65
|
-
fields,
|
|
66
|
-
rowCount: rows.length,
|
|
67
|
-
insertId: null, // SELECT 不会有 insertId
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** INSERT/UPDATE/DELETE */
|
|
72
|
-
async execute(connection, sql, params = []) {
|
|
73
|
-
const validatedParams = this._validateAndPrepareParams(sql, params);
|
|
74
|
-
|
|
75
|
-
const [result] = await connection.execute(sql, validatedParams);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
affectedRows: result.affectedRows || 0,
|
|
79
|
-
insertId: result.insertId || null,
|
|
80
|
-
changedRows: result.changedRows || 0,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// mysql-driver.js中的_validateAndPrepareParams方法
|
|
85
|
-
_validateAndPrepareParams(sql, params) {
|
|
86
|
-
// 确保参数是数组
|
|
87
|
-
if (!Array.isArray(params)) {
|
|
88
|
-
console.warn("[MySQLDriver] params 不是数组,已强制转换", params);
|
|
89
|
-
params = [];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 过滤 undefined(mysql2 最容易出问题的点)
|
|
93
|
-
const filteredParams = params.map((p) => (p === undefined ? null : p));
|
|
94
|
-
|
|
95
|
-
// 计算SQL中的占位符数量
|
|
96
|
-
const placeholderCount = (sql.match(/\?/g) || []).length;
|
|
97
|
-
|
|
98
|
-
// 验证参数数量
|
|
99
|
-
if (filteredParams.length !== placeholderCount) {
|
|
100
|
-
console.error(
|
|
101
|
-
`[MySQLDriver] 参数数量不匹配!SQL有 ${placeholderCount} 个占位符,但提供了 ${filteredParams.length} 个参数`,
|
|
102
|
-
);
|
|
103
|
-
console.error(`[MySQLDriver] SQL: ${sql}`);
|
|
104
|
-
console.error(`[MySQLDriver] Params:`, filteredParams);
|
|
105
|
-
|
|
106
|
-
// 如果参数不足,用null填充
|
|
107
|
-
if (filteredParams.length < placeholderCount) {
|
|
108
|
-
const missingCount = placeholderCount - filteredParams.length;
|
|
109
|
-
console.warn(`[MySQLDriver] 缺少 ${missingCount} 个参数,用null填充`);
|
|
110
|
-
for (let i = 0; i < missingCount; i++) {
|
|
111
|
-
filteredParams.push(null);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// 如果参数过多,截断
|
|
115
|
-
else if (filteredParams.length > placeholderCount) {
|
|
116
|
-
console.warn(`[MySQLDriver] 参数过多,截断为 ${placeholderCount} 个`);
|
|
117
|
-
filteredParams.length = placeholderCount;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return filteredParams;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** 确保 params 一定是数组(保持向后兼容) */
|
|
125
|
-
_ensureArray(params) {
|
|
126
|
-
if (!Array.isArray(params)) {
|
|
127
|
-
console.warn("[MySQLDriver] params 不是数组,已强制转换", params);
|
|
128
|
-
return [];
|
|
129
|
-
}
|
|
130
|
-
// 过滤 undefined(mysql2 最容易出问题的点)
|
|
131
|
-
return params.map((p) => (p === undefined ? null : p));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async beginTransaction(connection) {
|
|
135
|
-
await connection.beginTransaction();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async commitTransaction(connection) {
|
|
139
|
-
await connection.commit();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async rollbackTransaction(connection) {
|
|
143
|
-
await connection.rollback();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async close(connection) {
|
|
147
|
-
await connection.end();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async closePool(pool) {
|
|
151
|
-
await pool.end();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
getPoolStats(pool) {
|
|
155
|
-
return {
|
|
156
|
-
totalConnections: pool._allConnections?.length || 0,
|
|
157
|
-
activeConnections: pool._acquiringConnections?.length || 0,
|
|
158
|
-
idleConnections: pool._freeConnections?.length || 0,
|
|
159
|
-
waitingClients: pool._connectionQueue?.length || 0,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async healthCheck(connection) {
|
|
164
|
-
const [rows] = await connection.execute("SELECT 1 as health");
|
|
165
|
-
return rows.health === 1;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export default MySQLDriver;
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/oracle-driver
|
|
6
|
-
*/
|
|
7
|
-
import oracledb from 'oracledb';
|
|
8
|
-
|
|
9
|
-
class OracleDriver {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.pool = null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async connect(config) {
|
|
16
|
-
const connection = await oracledb.getConnection({
|
|
17
|
-
user: config.user,
|
|
18
|
-
password: config.password,
|
|
19
|
-
connectString: config.connectString || `${config.host}:${config.port}/${config.serviceName}`,
|
|
20
|
-
poolMin: config.pool?.min || 2,
|
|
21
|
-
poolMax: config.pool?.max || 10,
|
|
22
|
-
poolIncrement: 1,
|
|
23
|
-
poolTimeout: config.pool?.idleTimeout || 30000,
|
|
24
|
-
queueTimeout: config.pool?.acquireTimeout || 10000
|
|
25
|
-
});
|
|
26
|
-
return connection;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async createPool(config) {
|
|
30
|
-
await oracledb.createPool({
|
|
31
|
-
user: config.user,
|
|
32
|
-
password: config.password,
|
|
33
|
-
connectString: config.connectString || `${config.host}:${config.port}/${config.serviceName}`,
|
|
34
|
-
poolMin: config.pool?.min || 2,
|
|
35
|
-
poolMax: config.pool?.max || 10,
|
|
36
|
-
poolIncrement: 1,
|
|
37
|
-
poolTimeout: config.pool?.idleTimeout || 30000,
|
|
38
|
-
queueTimeout: config.pool?.acquireTimeout || 10000
|
|
39
|
-
});
|
|
40
|
-
this.pool = oracledb.getPool();
|
|
41
|
-
return this.pool;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async query(connection, sql, params = []) {
|
|
45
|
-
const options = {
|
|
46
|
-
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const result = await connection.execute(sql, params, options);
|
|
50
|
-
return {
|
|
51
|
-
rows: result.rows,
|
|
52
|
-
rowCount: result.rows?.length || 0,
|
|
53
|
-
metaData: result.metaData,
|
|
54
|
-
outBinds: result.outBinds
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async execute(connection, sql, params = []) {
|
|
59
|
-
const result = await connection.execute(sql, params, { autoCommit: false });
|
|
60
|
-
return {
|
|
61
|
-
rowsAffected: result.rowsAffected,
|
|
62
|
-
lastRowid: result.lastRowid,
|
|
63
|
-
outBinds: result.outBinds
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async beginTransaction(connection) {
|
|
68
|
-
// Oracle automatically starts a transaction when DML is executed
|
|
69
|
-
return connection;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async commitTransaction(connection) {
|
|
73
|
-
await connection.commit();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async rollbackTransaction(connection) {
|
|
77
|
-
await connection.rollback();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async close(connection) {
|
|
81
|
-
await connection.close();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async closePool(pool) {
|
|
85
|
-
await pool.close();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
getPoolStats(pool) {
|
|
89
|
-
return {
|
|
90
|
-
connectionsInUse: pool.connectionsInUse,
|
|
91
|
-
connectionsOpen: pool.connectionsOpen
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async healthCheck(connection) {
|
|
96
|
-
const result = await connection.execute('SELECT 1 as health FROM DUAL');
|
|
97
|
-
return result.rows.HEALTH === 1;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default OracleDriver;
|
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/postgres-driver
|
|
6
|
-
*/
|
|
7
|
-
import pg from 'pg';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* PostgreSQL Driver (also supports CockroachDB)
|
|
11
|
-
* CockroachDB is PostgreSQL compatible, so we can reuse this driver
|
|
12
|
-
*/
|
|
13
|
-
class PostgreSQLDriver {
|
|
14
|
-
constructor(config) {
|
|
15
|
-
this.config = config;
|
|
16
|
-
this.pool = null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Create a single connection
|
|
21
|
-
* @param {Object} config - Connection configuration
|
|
22
|
-
* @returns {Promise<Object>} PostgreSQL client
|
|
23
|
-
*/
|
|
24
|
-
async connect(config) {
|
|
25
|
-
// Check if this is a CockroachDB connection
|
|
26
|
-
const isCockroachDB = config.type === 'cockroachdb' || config.type === 'cockroach';
|
|
27
|
-
|
|
28
|
-
// For CockroachDB, we need to enable specific options
|
|
29
|
-
const connectionConfig = {
|
|
30
|
-
host: config.host,
|
|
31
|
-
port: config.port,
|
|
32
|
-
user: config.user,
|
|
33
|
-
password: config.password,
|
|
34
|
-
database: config.database,
|
|
35
|
-
ssl: config.ssl ? { rejectUnauthorized: false } : false
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Add CockroachDB specific options if needed
|
|
39
|
-
if (isCockroachDB) {
|
|
40
|
-
// CockroachDB specific connection options
|
|
41
|
-
connectionConfig.application_name = 'cockroachdb-driver';
|
|
42
|
-
// CockroachDB often requires SSL
|
|
43
|
-
if (!config.ssl && process.env.NODE_ENV === 'production') {
|
|
44
|
-
console.warn('⚠️ CockroachDB in production should use SSL. Set ssl: true in config.');
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const client = new pg.Client(connectionConfig);
|
|
49
|
-
await client.connect();
|
|
50
|
-
return client;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Create connection pool
|
|
55
|
-
* @param {Object} config - Pool configuration
|
|
56
|
-
* @returns {Promise<Object>} PostgreSQL pool
|
|
57
|
-
*/
|
|
58
|
-
async createPool(config) {
|
|
59
|
-
// Check if this is a CockroachDB connection
|
|
60
|
-
const isCockroachDB = config.type === 'cockroachdb' || config.type === 'cockroach';
|
|
61
|
-
|
|
62
|
-
const poolConfig = {
|
|
63
|
-
host: config.host,
|
|
64
|
-
port: config.port,
|
|
65
|
-
user: config.user,
|
|
66
|
-
password: config.password,
|
|
67
|
-
database: config.database,
|
|
68
|
-
ssl: config.ssl ? { rejectUnauthorized: false } : false,
|
|
69
|
-
max: config.pool?.max || 10,
|
|
70
|
-
min: config.pool?.min || 2,
|
|
71
|
-
idleTimeoutMillis: config.pool?.idleTimeout || 30000,
|
|
72
|
-
connectionTimeoutMillis: config.pool?.acquireTimeout || 10000
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
// Add CockroachDB specific pool options
|
|
76
|
-
if (isCockroachDB) {
|
|
77
|
-
poolConfig.application_name = 'cockroachdb-pool';
|
|
78
|
-
// CockroachDB may need different pool settings
|
|
79
|
-
poolConfig.max = config.pool?.max || 20; // Higher max connections for CockroachDB
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this.pool = new pg.Pool(poolConfig);
|
|
83
|
-
return this.pool;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Execute SELECT query
|
|
88
|
-
* @param {Object} connection - PostgreSQL client or pool client
|
|
89
|
-
* @param {string} sql - SQL query
|
|
90
|
-
* @param {Array} params - Query parameters
|
|
91
|
-
* @returns {Promise<Object>} Query result
|
|
92
|
-
*/
|
|
93
|
-
async query(connection, sql, params = []) {
|
|
94
|
-
// Check if this is a CockroachDB connection
|
|
95
|
-
const isCockroachDB = this.config.type === 'cockroachdb' || this.config.type === 'cockroach';
|
|
96
|
-
|
|
97
|
-
// For CockroachDB, we might need to adjust some queries
|
|
98
|
-
if (isCockroachDB) {
|
|
99
|
-
// CockroachDB doesn't support some PostgreSQL features
|
|
100
|
-
// We can add compatibility adjustments here if needed
|
|
101
|
-
// For example, CockroachDB uses different serial types
|
|
102
|
-
sql = this.adaptSQLForCockroachDB(sql);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const result = await connection.query(sql, params);
|
|
106
|
-
return {
|
|
107
|
-
rows: result.rows,
|
|
108
|
-
rowCount: result.rowCount,
|
|
109
|
-
fields: result.fields,
|
|
110
|
-
command: result.command
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Execute INSERT/UPDATE/DELETE operation
|
|
116
|
-
* @param {Object} connection - PostgreSQL client or pool client
|
|
117
|
-
* @param {string} sql - SQL statement
|
|
118
|
-
* @param {Array} params - Query parameters
|
|
119
|
-
* @returns {Promise<Object>} Execution result
|
|
120
|
-
*/
|
|
121
|
-
async execute(connection, sql, params = []) {
|
|
122
|
-
// Check if this is a CockroachDB connection
|
|
123
|
-
const isCockroachDB = this.config.type === 'cockroachdb' || this.config.type === 'cockroach';
|
|
124
|
-
|
|
125
|
-
if (isCockroachDB) {
|
|
126
|
-
sql = this.adaptSQLForCockroachDB(sql);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const result = await connection.query(sql, params);
|
|
130
|
-
return {
|
|
131
|
-
rowCount: result.rowCount,
|
|
132
|
-
rows: result.rows
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Adapt SQL for CockroachDB compatibility
|
|
138
|
-
* @param {string} sql - Original SQL
|
|
139
|
-
* @returns {string} Adapted SQL
|
|
140
|
-
* @private
|
|
141
|
-
*/
|
|
142
|
-
adaptSQLForCockroachDB(sql) {
|
|
143
|
-
let adaptedSql = sql;
|
|
144
|
-
|
|
145
|
-
// CockroachDB uses different syntax for some features
|
|
146
|
-
// Add adaptations as needed
|
|
147
|
-
|
|
148
|
-
// Example: Replace SERIAL with INT DEFAULT unique_rowid()
|
|
149
|
-
// This is just an example - actual adaptations depend on your use case
|
|
150
|
-
if (sql.includes('SERIAL')) {
|
|
151
|
-
console.warn('⚠️ CockroachDB: SERIAL type is not supported. Consider using INT DEFAULT unique_rowid()');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return adaptedSql;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Begin transaction
|
|
159
|
-
* @param {Object} connection - PostgreSQL client
|
|
160
|
-
*/
|
|
161
|
-
async beginTransaction(connection) {
|
|
162
|
-
await connection.query('BEGIN');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Commit transaction
|
|
167
|
-
* @param {Object} connection - PostgreSQL client
|
|
168
|
-
*/
|
|
169
|
-
async commitTransaction(connection) {
|
|
170
|
-
await connection.query('COMMIT');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Rollback transaction
|
|
175
|
-
* @param {Object} connection - PostgreSQL client
|
|
176
|
-
*/
|
|
177
|
-
async rollbackTransaction(connection) {
|
|
178
|
-
await connection.query('ROLLBACK');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Close connection
|
|
183
|
-
* @param {Object} connection - PostgreSQL client
|
|
184
|
-
*/
|
|
185
|
-
async close(connection) {
|
|
186
|
-
await connection.end();
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Close connection pool
|
|
191
|
-
* @param {Object} pool - PostgreSQL pool
|
|
192
|
-
*/
|
|
193
|
-
async closePool(pool) {
|
|
194
|
-
await pool.end();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Get pool statistics
|
|
199
|
-
* @param {Object} pool - PostgreSQL pool
|
|
200
|
-
* @returns {Object} Pool statistics
|
|
201
|
-
*/
|
|
202
|
-
getPoolStats(pool) {
|
|
203
|
-
return {
|
|
204
|
-
totalCount: pool.totalCount,
|
|
205
|
-
idleCount: pool.idleCount,
|
|
206
|
-
waitingCount: pool.waitingCount
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Health check
|
|
212
|
-
* @param {Object} connection - PostgreSQL client
|
|
213
|
-
* @returns {Promise<boolean>} Health status
|
|
214
|
-
*/
|
|
215
|
-
async healthCheck(connection) {
|
|
216
|
-
try {
|
|
217
|
-
const result = await connection.query('SELECT 1 as health');
|
|
218
|
-
return result.rows.health === 1;
|
|
219
|
-
} catch (error) {
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Get dialect name
|
|
226
|
-
* @returns {string} Dialect name
|
|
227
|
-
*/
|
|
228
|
-
getDialect() {
|
|
229
|
-
const isCockroachDB = this.config.type === 'cockroachdb' || this.config.type === 'cockroach';
|
|
230
|
-
return isCockroachDB ? 'cockroachdb' : 'postgresql';
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
export default PostgreSQLDriver;
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/redis-driver
|
|
6
|
-
*/
|
|
7
|
-
import redis from 'redis';
|
|
8
|
-
|
|
9
|
-
class RedisDriver {
|
|
10
|
-
constructor(config) {
|
|
11
|
-
this.config = config;
|
|
12
|
-
this.client = null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async connect(config) {
|
|
16
|
-
this.client = redis.createClient({
|
|
17
|
-
socket: {
|
|
18
|
-
host: config.host,
|
|
19
|
-
port: config.port
|
|
20
|
-
},
|
|
21
|
-
password: config.password,
|
|
22
|
-
database: config.db || 0
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
await this.client.connect();
|
|
26
|
-
return this.client;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async query(connection, command, ...args) {
|
|
30
|
-
const result = await connection.sendCommand([command, ...args]);
|
|
31
|
-
return { result };
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async execute(connection, command, ...args) {
|
|
35
|
-
return this.query(connection, command, ...args);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async close(connection) {
|
|
39
|
-
await connection.quit();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async healthCheck(connection) {
|
|
43
|
-
try {
|
|
44
|
-
const result = await connection.ping();
|
|
45
|
-
return result === 'PONG';
|
|
46
|
-
} catch (error) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export default RedisDriver;
|