@aetherframework/database 1.1.1 → 1.1.2

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.
Files changed (47) hide show
  1. package/examples/mysql-test-pressure.js +1530 -0
  2. package/examples/test-direct.js +116 -0
  3. package/examples/transaction_example.js +127 -0
  4. package/package.json +3 -1
  5. package/src/DatabaseManager.js +565 -0
  6. package/src/core/ConnectionManager.js +351 -0
  7. package/src/core/DatabaseFactory.js +188 -0
  8. package/src/core/MongoQueryBuilder.js +576 -0
  9. package/src/core/PluginManager.js +968 -0
  10. package/src/core/QueryBuilder.js +4394 -0
  11. package/src/core/TransactionManager.js +40 -0
  12. package/src/drivers/clickhouse-driver.js +272 -0
  13. package/src/drivers/index.js +273 -0
  14. package/src/drivers/mongodb-driver.js +87 -0
  15. package/src/drivers/mssql-driver.js +117 -0
  16. package/src/drivers/mysql-driver.js +169 -0
  17. package/src/drivers/oracle-driver.js +101 -0
  18. package/src/drivers/postgres-driver.js +234 -0
  19. package/src/drivers/redis-driver.js +52 -0
  20. package/src/drivers/sqlite-driver.js +67 -0
  21. package/src/middleware/connection-pool.js +455 -0
  22. package/src/middleware/performance-monitor.js +652 -0
  23. package/src/middleware/query-cache.js +500 -0
  24. package/src/middleware/query-logger.js +262 -0
  25. package/src/plugins/AuditPlugin.js +447 -0
  26. package/src/plugins/BasePlugin.js +418 -0
  27. package/src/plugins/BatchOperationPlugin.js +165 -0
  28. package/src/plugins/CachePlugin.js +407 -0
  29. package/src/plugins/CtePlugin.js +523 -0
  30. package/src/plugins/DistributedPlugin.js +543 -0
  31. package/src/plugins/EncryptionPlugin.js +211 -0
  32. package/src/plugins/FullTextSearchPlugin.js +164 -0
  33. package/src/plugins/GeospatialPlugin.js +219 -0
  34. package/src/plugins/GraphQLPlugin.js +162 -0
  35. package/src/plugins/HookPlugin.js +211 -0
  36. package/src/plugins/JsonPlugin.js +366 -0
  37. package/src/plugins/OptimisticLockPlugin.js +374 -0
  38. package/src/plugins/PerformancePlugin.js +175 -0
  39. package/src/plugins/ResiliencePlugin.js +114 -0
  40. package/src/plugins/ShardingPlugin.js +227 -0
  41. package/src/plugins/SoftDeletePlugin.js +258 -0
  42. package/src/plugins/SyncPlugin.js +373 -0
  43. package/src/plugins/VersioningPlugin.js +314 -0
  44. package/src/plugins/WindowFunctionPlugin.js +343 -0
  45. package/src/utils/config-loader.js +632 -0
  46. package/src/utils/error-handler.js +724 -0
  47. package/src/utils/migration-runner.js +1066 -0
@@ -0,0 +1,117 @@
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;
@@ -0,0 +1,169 @@
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;
@@ -0,0 +1,101 @@
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;
@@ -0,0 +1,234 @@
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;
@@ -0,0 +1,52 @@
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;