@db-bridge/mysql 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Berke Erdoğan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,356 @@
1
+ # @db-bridge/mysql
2
+
3
+ MySQL adapter for DB Bridge - A comprehensive database management library.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @db-bridge/mysql @db-bridge/core
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - Full MySQL and MariaDB support
14
+ - Connection pooling with mysql2
15
+ - Prepared statements
16
+ - Transaction management with savepoints
17
+ - Bulk operations
18
+ - TypeScript support
19
+ - Query builder integration
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { MySQLAdapter } from '@db-bridge/mysql';
25
+
26
+ const adapter = new MySQLAdapter();
27
+
28
+ // Connect
29
+ await adapter.connect({
30
+ host: 'localhost',
31
+ port: 3306,
32
+ user: 'root',
33
+ password: 'password',
34
+ database: 'myapp',
35
+ });
36
+
37
+ // Simple query
38
+ const users = await adapter.query('SELECT * FROM users WHERE active = ?', [true]);
39
+
40
+ // Query builder
41
+ const qb = adapter.createQueryBuilder();
42
+ const results = await qb
43
+ .select('*')
44
+ .from('users')
45
+ .where('age', '>', 18)
46
+ .orderBy('created_at', 'DESC')
47
+ .limit(10)
48
+ .execute();
49
+
50
+ // Disconnect
51
+ await adapter.disconnect();
52
+ ```
53
+
54
+ ## Configuration
55
+
56
+ ### Connection Options
57
+
58
+ ```typescript
59
+ interface MySQLConnectionConfig {
60
+ host: string;
61
+ port?: number;
62
+ user: string;
63
+ password: string;
64
+ database: string;
65
+ ssl?: SslOptions;
66
+ timezone?: string;
67
+ charset?: string;
68
+ connectionLimit?: number;
69
+ queueLimit?: number;
70
+ waitForConnections?: boolean;
71
+ connectTimeout?: number;
72
+ timeout?: number;
73
+ }
74
+ ```
75
+
76
+ ### Adapter Options
77
+
78
+ ```typescript
79
+ const adapter = new MySQLAdapter({
80
+ // Logger instance (optional)
81
+ logger: console,
82
+
83
+ // Retry options
84
+ retryOptions: {
85
+ maxRetries: 3,
86
+ retryDelay: 1000,
87
+ },
88
+
89
+ // MySQL2 specific options
90
+ mysql2Options: {
91
+ ssl: {
92
+ ca: fs.readFileSync('ca-cert.pem'),
93
+ rejectUnauthorized: true,
94
+ },
95
+ timezone: '+00:00',
96
+ connectionLimit: 10,
97
+ enableKeepAlive: true,
98
+ },
99
+ });
100
+ ```
101
+
102
+ ## Usage
103
+
104
+ ### Basic Queries
105
+
106
+ ```typescript
107
+ // Simple query
108
+ const result = await adapter.query('SELECT * FROM products WHERE price > ?', [100]);
109
+
110
+ // Named placeholders (converted to ?)
111
+ const users = await adapter.query('SELECT * FROM users WHERE role = :role AND status = :status', {
112
+ role: 'admin',
113
+ status: 'active',
114
+ });
115
+
116
+ // Insert with auto-generated ID
117
+ const insertResult = await adapter.execute('INSERT INTO users (name, email) VALUES (?, ?)', [
118
+ 'John Doe',
119
+ 'john@example.com',
120
+ ]);
121
+ console.log('Inserted ID:', insertResult.insertId);
122
+ ```
123
+
124
+ ### Query Builder
125
+
126
+ ```typescript
127
+ const qb = adapter.createQueryBuilder();
128
+
129
+ // SELECT with joins
130
+ const orders = await qb
131
+ .select('o.*', 'u.name as user_name', 'u.email')
132
+ .from('orders', 'o')
133
+ .join('users u', 'u.id = o.user_id')
134
+ .where('o.status', '=', 'pending')
135
+ .where('o.created_at', '>', '2024-01-01')
136
+ .orderBy('o.created_at', 'DESC')
137
+ .limit(20)
138
+ .execute();
139
+
140
+ // INSERT
141
+ await qb
142
+ .insert('products', {
143
+ name: 'New Product',
144
+ price: 99.99,
145
+ stock: 100,
146
+ })
147
+ .execute();
148
+
149
+ // UPDATE
150
+ await qb.update('products', { price: 89.99 }).where('id', '=', 123).execute();
151
+
152
+ // DELETE
153
+ await qb.delete('products').where('discontinued', '=', true).execute();
154
+ ```
155
+
156
+ ### Transactions
157
+
158
+ ```typescript
159
+ // Basic transaction
160
+ const transaction = await adapter.beginTransaction();
161
+
162
+ try {
163
+ await adapter.execute('INSERT INTO accounts (name, balance) VALUES (?, ?)', ['Checking', 1000], {
164
+ transaction,
165
+ });
166
+
167
+ await adapter.execute('INSERT INTO transactions (account_id, amount) VALUES (?, ?)', [1, 1000], {
168
+ transaction,
169
+ });
170
+
171
+ await transaction.commit();
172
+ } catch (error) {
173
+ await transaction.rollback();
174
+ throw error;
175
+ }
176
+
177
+ // Transaction with savepoints
178
+ const tx = await adapter.beginTransaction();
179
+
180
+ try {
181
+ await adapter.execute('INSERT INTO logs ...', [], { transaction: tx });
182
+
183
+ await tx.savepoint('sp1');
184
+
185
+ try {
186
+ await riskyOperation(tx);
187
+ } catch (error) {
188
+ await tx.rollbackToSavepoint('sp1');
189
+ // Continue with transaction
190
+ }
191
+
192
+ await tx.commit();
193
+ } catch (error) {
194
+ await tx.rollback();
195
+ }
196
+ ```
197
+
198
+ ### Prepared Statements
199
+
200
+ ```typescript
201
+ // Prepare statement
202
+ const stmt = await adapter.prepare('SELECT * FROM users WHERE department = ? AND role = ?');
203
+
204
+ // Execute multiple times
205
+ const sales = await stmt.execute(['sales', 'manager']);
206
+ const engineering = await stmt.execute(['engineering', 'developer']);
207
+ const hr = await stmt.execute(['hr', 'recruiter']);
208
+
209
+ // Release when done
210
+ await stmt.release();
211
+ ```
212
+
213
+ ### Bulk Operations
214
+
215
+ ```typescript
216
+ // Bulk insert
217
+ const users = [
218
+ { name: 'User 1', email: 'user1@example.com' },
219
+ { name: 'User 2', email: 'user2@example.com' },
220
+ { name: 'User 3', email: 'user3@example.com' },
221
+ ];
222
+
223
+ await adapter.createQueryBuilder().insert('users', users).execute();
224
+
225
+ // Bulk update
226
+ await adapter.execute(`
227
+ INSERT INTO products (id, price) VALUES
228
+ (1, 10.99), (2, 20.99), (3, 30.99)
229
+ ON DUPLICATE KEY UPDATE price = VALUES(price)
230
+ `);
231
+ ```
232
+
233
+ ### Connection Pool Management
234
+
235
+ ```typescript
236
+ // Monitor pool stats
237
+ const stats = adapter.getPoolStats();
238
+ console.log('Active connections:', stats.active);
239
+ console.log('Idle connections:', stats.idle);
240
+ console.log('Queue length:', stats.waiting);
241
+
242
+ // Check connection
243
+ const isAlive = await adapter.ping();
244
+ console.log('Connection alive:', isAlive);
245
+
246
+ // Force close all connections
247
+ await adapter.disconnect();
248
+ ```
249
+
250
+ ## Error Handling
251
+
252
+ ```typescript
253
+ import { ConnectionError, QueryError } from '@db-bridge/core';
254
+
255
+ try {
256
+ await adapter.connect(config);
257
+ } catch (error) {
258
+ if (error instanceof ConnectionError) {
259
+ console.error('Failed to connect:', error.message);
260
+ // Handle connection error
261
+ }
262
+ }
263
+
264
+ try {
265
+ await adapter.query('SELECT * FROM non_existent_table');
266
+ } catch (error) {
267
+ if (error instanceof QueryError) {
268
+ console.error('Query error:', {
269
+ code: error.code,
270
+ message: error.message,
271
+ sql: error.sql,
272
+ });
273
+ }
274
+ }
275
+ ```
276
+
277
+ ## MySQL-Specific Features
278
+
279
+ ### JSON Support
280
+
281
+ ```typescript
282
+ // Insert JSON data
283
+ await adapter.execute('INSERT INTO logs (data) VALUES (?)', [
284
+ JSON.stringify({ action: 'login', user: 123 }),
285
+ ]);
286
+
287
+ // Query JSON fields
288
+ const logs = await adapter.query("SELECT * FROM logs WHERE JSON_EXTRACT(data, '$.action') = ?", [
289
+ 'login',
290
+ ]);
291
+ ```
292
+
293
+ ### Full-Text Search
294
+
295
+ ```typescript
296
+ const results = await adapter.query(
297
+ 'SELECT * FROM articles WHERE MATCH(title, content) AGAINST(? IN NATURAL LANGUAGE MODE)',
298
+ ['database management'],
299
+ );
300
+ ```
301
+
302
+ ### Spatial Data
303
+
304
+ ```typescript
305
+ // Insert point
306
+ await adapter.execute('INSERT INTO locations (name, coords) VALUES (?, ST_GeomFromText(?))', [
307
+ 'Office',
308
+ 'POINT(40.7128 -74.0060)',
309
+ ]);
310
+
311
+ // Find nearby
312
+ const nearby = await adapter.query(
313
+ `
314
+ SELECT name, ST_Distance_Sphere(coords, ST_GeomFromText(?)) as distance
315
+ FROM locations
316
+ HAVING distance < 1000
317
+ ORDER BY distance
318
+ `,
319
+ ['POINT(40.7589 -73.9851)'],
320
+ );
321
+ ```
322
+
323
+ ## Best Practices
324
+
325
+ 1. **Use Connection Pooling**: Always use connection pooling in production
326
+ 2. **Handle Errors**: Implement proper error handling and retry logic
327
+ 3. **Use Prepared Statements**: For repeated queries with different parameters
328
+ 4. **Set Timeouts**: Configure appropriate connection and query timeouts
329
+ 5. **Monitor Pool Stats**: Keep track of connection pool health
330
+ 6. **Use Transactions**: For data consistency across multiple operations
331
+
332
+ ## TypeScript Support
333
+
334
+ ```typescript
335
+ interface User {
336
+ id: number;
337
+ name: string;
338
+ email: string;
339
+ created_at: Date;
340
+ }
341
+
342
+ // Type-safe queries
343
+ const users = await adapter.query<User>('SELECT * FROM users WHERE id = ?', [123]);
344
+
345
+ // Type-safe query builder
346
+ const user = await adapter
347
+ .createQueryBuilder<User>()
348
+ .select('*')
349
+ .from('users')
350
+ .where('id', '=', 123)
351
+ .first();
352
+ ```
353
+
354
+ ## License
355
+
356
+ MIT © Berke Erdoğan
@@ -0,0 +1,88 @@
1
+ import { BaseQueryBuilder, BaseAdapter, BaseAdapterOptions, ConnectionConfig, QueryParams, QueryOptions, QueryResult, TransactionOptions, Transaction, PreparedStatement, PoolStats } from '@db-bridge/core';
2
+ export { ConnectionConfig, DatabaseAdapter, PreparedStatement, QueryBuilder, QueryOptions, QueryResult, Transaction } from '@db-bridge/core';
3
+ import * as mysql from 'mysql2/promise';
4
+
5
+ declare class MySQLQueryBuilder<T = unknown> extends BaseQueryBuilder<T> {
6
+ protected buildSelectSQL(): {
7
+ sql: string;
8
+ bindings: unknown[];
9
+ };
10
+ protected buildInsertSQL(): {
11
+ sql: string;
12
+ bindings: unknown[];
13
+ };
14
+ protected buildUpdateSQL(): {
15
+ sql: string;
16
+ bindings: unknown[];
17
+ };
18
+ protected buildDeleteSQL(): {
19
+ sql: string;
20
+ bindings: unknown[];
21
+ };
22
+ }
23
+
24
+ interface MySQLAdapterOptions extends BaseAdapterOptions {
25
+ mysql2Options?: mysql.ConnectionOptions;
26
+ }
27
+ declare class MySQLAdapter extends BaseAdapter {
28
+ readonly name = "MySQL";
29
+ readonly version = "2.0.0";
30
+ private pool?;
31
+ private readonly mysql2Options?;
32
+ private poolConfig;
33
+ constructor(options?: MySQLAdapterOptions);
34
+ protected doConnect(config: ConnectionConfig): Promise<void>;
35
+ protected doDisconnect(): Promise<void>;
36
+ protected doQuery<T = unknown>(sql: string, params?: QueryParams, options?: QueryOptions): Promise<QueryResult<T>>;
37
+ beginTransaction(options?: TransactionOptions): Promise<Transaction>;
38
+ prepare<T = unknown>(sql: string, _name?: string): Promise<PreparedStatement<T>>;
39
+ getPoolStats(): PoolStats;
40
+ ping(): Promise<boolean>;
41
+ escape(value: unknown): string;
42
+ escapeIdentifier(identifier: string): string;
43
+ createQueryBuilder<T = unknown>(): MySQLQueryBuilder<T>;
44
+ private normalizeParams;
45
+ }
46
+
47
+ declare class MySQLTransaction implements Transaction {
48
+ private connection;
49
+ private options?;
50
+ readonly id: string;
51
+ private _isActive;
52
+ private savepoints;
53
+ constructor(connection: mysql.PoolConnection, options?: TransactionOptions | undefined);
54
+ get isActive(): boolean;
55
+ begin(): Promise<void>;
56
+ commit(): Promise<void>;
57
+ rollback(): Promise<void>;
58
+ savepoint(name: string): Promise<void>;
59
+ releaseSavepoint(name: string): Promise<void>;
60
+ rollbackToSavepoint(name: string): Promise<void>;
61
+ getConnection(): mysql.PoolConnection;
62
+ query<T = unknown>(sql: string, params?: QueryParams, _options?: QueryOptions): Promise<QueryResult<T>>;
63
+ execute<T = unknown>(sql: string, params?: QueryParams, options?: QueryOptions): Promise<QueryResult<T>>;
64
+ private setIsolationLevel;
65
+ private mapIsolationLevel;
66
+ }
67
+
68
+ declare class MySQLPreparedStatement<T = unknown> implements PreparedStatement<T> {
69
+ private connection;
70
+ private sql;
71
+ private released;
72
+ constructor(connection: mysql.PoolConnection, sql: string);
73
+ execute(params?: unknown[]): Promise<QueryResult<T>>;
74
+ release(): Promise<void>;
75
+ close(): Promise<void>;
76
+ }
77
+
78
+ declare class MySQLConnectionPool {
79
+ private options;
80
+ private pool?;
81
+ constructor(options: mysql.ConnectionOptions);
82
+ initialize(): Promise<void>;
83
+ getConnection(): Promise<mysql.PoolConnection>;
84
+ end(): Promise<void>;
85
+ getStats(): PoolStats;
86
+ }
87
+
88
+ export { MySQLAdapter, type MySQLAdapterOptions, MySQLConnectionPool, MySQLPreparedStatement, MySQLQueryBuilder, MySQLTransaction };
package/dist/index.js ADDED
@@ -0,0 +1,623 @@
1
+ import { QueryError, generateUUID, TransactionError, IsolationLevel, ConnectionError, BaseQueryBuilder, ValidationError, BaseAdapter, POOL_DEFAULTS, QueryTimeoutError } from '@db-bridge/core';
2
+ import * as mysql from 'mysql2/promise';
3
+
4
+ // src/adapter/mysql-adapter.ts
5
+ var MySQLPreparedStatement = class {
6
+ constructor(connection, sql) {
7
+ this.connection = connection;
8
+ this.sql = sql;
9
+ }
10
+ released = false;
11
+ async execute(params) {
12
+ if (this.released) {
13
+ throw new QueryError("Prepared statement has been released");
14
+ }
15
+ try {
16
+ const command = this.sql.trim().split(" ")[0]?.toUpperCase();
17
+ if (command === "INSERT" || command === "UPDATE" || command === "DELETE") {
18
+ const [result] = await this.connection.execute(
19
+ this.sql,
20
+ params || []
21
+ );
22
+ return {
23
+ rows: [],
24
+ rowCount: result.affectedRows || 0,
25
+ affectedRows: result.affectedRows || 0,
26
+ insertId: result.insertId,
27
+ fields: [],
28
+ command
29
+ };
30
+ }
31
+ const [rows, fields] = await this.connection.execute(
32
+ this.sql,
33
+ params || []
34
+ );
35
+ return {
36
+ rows,
37
+ rowCount: Array.isArray(rows) ? rows.length : 0,
38
+ affectedRows: Array.isArray(rows) ? rows.length : 0,
39
+ fields: fields?.map((field) => ({
40
+ name: field.name,
41
+ type: field.type?.toString() || "unknown",
42
+ nullable: field.flags ? !(Number(field.flags) & 1) : true,
43
+ primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,
44
+ autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,
45
+ defaultValue: field.default
46
+ })),
47
+ command
48
+ };
49
+ } catch (error) {
50
+ throw new QueryError(
51
+ `Prepared statement execution failed: ${error.message}`,
52
+ this.sql,
53
+ params,
54
+ error
55
+ );
56
+ }
57
+ }
58
+ async release() {
59
+ if (this.released) {
60
+ return;
61
+ }
62
+ try {
63
+ this.connection.release();
64
+ this.released = true;
65
+ } catch (error) {
66
+ throw new QueryError(
67
+ `Failed to release prepared statement: ${error.message}`,
68
+ this.sql,
69
+ void 0,
70
+ error
71
+ );
72
+ }
73
+ }
74
+ /**
75
+ * Alias for release() - industry standard naming
76
+ */
77
+ async close() {
78
+ return this.release();
79
+ }
80
+ };
81
+ var MySQLTransaction = class {
82
+ constructor(connection, options) {
83
+ this.connection = connection;
84
+ this.options = options;
85
+ this.id = generateUUID();
86
+ }
87
+ id;
88
+ _isActive = false;
89
+ savepoints = /* @__PURE__ */ new Set();
90
+ get isActive() {
91
+ return this._isActive;
92
+ }
93
+ async begin() {
94
+ if (this._isActive) {
95
+ throw new TransactionError("Transaction already active", this.id);
96
+ }
97
+ try {
98
+ if (this.options?.isolationLevel) {
99
+ await this.setIsolationLevel(this.options.isolationLevel);
100
+ }
101
+ await this.connection.beginTransaction();
102
+ this._isActive = true;
103
+ } catch (error) {
104
+ throw new TransactionError("Failed to begin transaction", this.id, error);
105
+ }
106
+ }
107
+ async commit() {
108
+ if (!this._isActive) {
109
+ throw new TransactionError("Transaction not active", this.id);
110
+ }
111
+ try {
112
+ await this.connection.commit();
113
+ this._isActive = false;
114
+ this.savepoints.clear();
115
+ } catch (error) {
116
+ throw new TransactionError("Failed to commit transaction", this.id, error);
117
+ } finally {
118
+ this.connection.release();
119
+ }
120
+ }
121
+ async rollback() {
122
+ if (!this._isActive) {
123
+ throw new TransactionError("Transaction not active", this.id);
124
+ }
125
+ try {
126
+ await this.connection.rollback();
127
+ this._isActive = false;
128
+ this.savepoints.clear();
129
+ } catch (error) {
130
+ throw new TransactionError("Failed to rollback transaction", this.id, error);
131
+ } finally {
132
+ this.connection.release();
133
+ }
134
+ }
135
+ async savepoint(name) {
136
+ if (!this._isActive) {
137
+ throw new TransactionError("Transaction not active", this.id);
138
+ }
139
+ if (this.savepoints.has(name)) {
140
+ throw new TransactionError(`Savepoint "${name}" already exists`, this.id);
141
+ }
142
+ try {
143
+ await this.connection.query(`SAVEPOINT ${mysql.escapeId(name)}`);
144
+ this.savepoints.add(name);
145
+ } catch (error) {
146
+ throw new TransactionError(`Failed to create savepoint "${name}"`, this.id, error);
147
+ }
148
+ }
149
+ async releaseSavepoint(name) {
150
+ if (!this._isActive) {
151
+ throw new TransactionError("Transaction not active", this.id);
152
+ }
153
+ if (!this.savepoints.has(name)) {
154
+ throw new TransactionError(`Savepoint "${name}" does not exist`, this.id);
155
+ }
156
+ try {
157
+ await this.connection.query(`RELEASE SAVEPOINT ${mysql.escapeId(name)}`);
158
+ this.savepoints.delete(name);
159
+ } catch (error) {
160
+ throw new TransactionError(`Failed to release savepoint "${name}"`, this.id, error);
161
+ }
162
+ }
163
+ async rollbackToSavepoint(name) {
164
+ if (!this._isActive) {
165
+ throw new TransactionError("Transaction not active", this.id);
166
+ }
167
+ if (!this.savepoints.has(name)) {
168
+ throw new TransactionError(`Savepoint "${name}" does not exist`, this.id);
169
+ }
170
+ try {
171
+ await this.connection.query(`ROLLBACK TO SAVEPOINT ${mysql.escapeId(name)}`);
172
+ } catch (error) {
173
+ throw new TransactionError(
174
+ `Failed to rollback to savepoint "${name}"`,
175
+ this.id,
176
+ error
177
+ );
178
+ }
179
+ }
180
+ getConnection() {
181
+ return this.connection;
182
+ }
183
+ async query(sql, params, _options) {
184
+ if (!this._isActive) {
185
+ throw new TransactionError("Transaction not active", this.id);
186
+ }
187
+ try {
188
+ const queryParams = Array.isArray(params) ? params : params ? Object.values(params) : [];
189
+ const command = sql.trim().split(" ")[0]?.toUpperCase();
190
+ if (command === "INSERT" || command === "UPDATE" || command === "DELETE") {
191
+ const [result2] = await this.connection.execute(sql, queryParams);
192
+ return {
193
+ rows: [],
194
+ rowCount: result2.affectedRows || 0,
195
+ affectedRows: result2.affectedRows || 0,
196
+ insertId: result2.insertId,
197
+ fields: [],
198
+ command
199
+ };
200
+ }
201
+ const [rows, fields] = await this.connection.execute(sql, queryParams);
202
+ const result = {
203
+ rows,
204
+ rowCount: Array.isArray(rows) ? rows.length : 0,
205
+ affectedRows: Array.isArray(rows) ? rows.length : 0,
206
+ fields: fields?.map((field) => ({
207
+ name: field.name,
208
+ type: field.type?.toString() || "unknown",
209
+ nullable: field.flags ? !(Number(field.flags) & 1) : true,
210
+ primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,
211
+ autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,
212
+ defaultValue: field.default
213
+ })),
214
+ command
215
+ };
216
+ return result;
217
+ } catch (error) {
218
+ throw new TransactionError(
219
+ `Query failed in transaction: ${error.message}`,
220
+ this.id,
221
+ error
222
+ );
223
+ }
224
+ }
225
+ /**
226
+ * Alias for query() to provide consistency with adapter's execute method
227
+ */
228
+ async execute(sql, params, options) {
229
+ return this.query(sql, params, options);
230
+ }
231
+ async setIsolationLevel(level) {
232
+ const mysqlLevel = this.mapIsolationLevel(level);
233
+ await this.connection.query(`SET TRANSACTION ISOLATION LEVEL ${mysqlLevel}`);
234
+ }
235
+ mapIsolationLevel(level) {
236
+ switch (level) {
237
+ case IsolationLevel.READ_UNCOMMITTED: {
238
+ return "READ UNCOMMITTED";
239
+ }
240
+ case IsolationLevel.READ_COMMITTED: {
241
+ return "READ COMMITTED";
242
+ }
243
+ case IsolationLevel.REPEATABLE_READ: {
244
+ return "REPEATABLE READ";
245
+ }
246
+ case IsolationLevel.SERIALIZABLE: {
247
+ return "SERIALIZABLE";
248
+ }
249
+ default: {
250
+ throw new TransactionError(`Invalid isolation level: ${level}`, this.id);
251
+ }
252
+ }
253
+ }
254
+ };
255
+ var MySQLConnectionPool = class {
256
+ constructor(options) {
257
+ this.options = options;
258
+ }
259
+ pool;
260
+ async initialize() {
261
+ try {
262
+ this.pool = mysql.createPool(this.options);
263
+ const connection = await this.pool.getConnection();
264
+ await connection.ping();
265
+ connection.release();
266
+ } catch (error) {
267
+ throw new ConnectionError("Failed to initialize MySQL connection pool", error);
268
+ }
269
+ }
270
+ async getConnection() {
271
+ if (!this.pool) {
272
+ throw new ConnectionError("Connection pool not initialized");
273
+ }
274
+ try {
275
+ return await this.pool.getConnection();
276
+ } catch (error) {
277
+ throw new ConnectionError("Failed to get connection from pool", error);
278
+ }
279
+ }
280
+ async end() {
281
+ if (this.pool) {
282
+ await this.pool.end();
283
+ this.pool = void 0;
284
+ }
285
+ }
286
+ getStats() {
287
+ if (!this.pool) {
288
+ return {
289
+ total: 0,
290
+ idle: 0,
291
+ active: 0,
292
+ waiting: 0
293
+ };
294
+ }
295
+ const pool = this.pool;
296
+ const poolConfig = pool.config;
297
+ const connectionLimit = poolConfig?.connectionLimit || 10;
298
+ const allConnections = pool._allConnections || [];
299
+ const freeConnections = pool._freeConnections || [];
300
+ const connectionQueue = pool._connectionQueue || [];
301
+ return {
302
+ total: connectionLimit,
303
+ idle: freeConnections.length,
304
+ active: allConnections.length - freeConnections.length,
305
+ waiting: connectionQueue.length
306
+ };
307
+ }
308
+ };
309
+ var MySQLQueryBuilder = class extends BaseQueryBuilder {
310
+ buildSelectSQL() {
311
+ if (!this.fromTable) {
312
+ throw new ValidationError("FROM table is required for SELECT query");
313
+ }
314
+ const parts = [];
315
+ parts.push("SELECT");
316
+ parts.push(this.selectColumns.join(", "));
317
+ parts.push("FROM");
318
+ if (this.fromAlias) {
319
+ parts.push(
320
+ `${this.escapeIdentifierFn(this.fromTable)} AS ${this.escapeIdentifierFn(this.fromAlias)}`
321
+ );
322
+ } else {
323
+ parts.push(this.escapeIdentifierFn(this.fromTable));
324
+ }
325
+ this.joins.forEach((join) => {
326
+ parts.push(`${join.type} JOIN ${join.table} ON ${join.on}`);
327
+ });
328
+ if (this.whereClauses.length > 0) {
329
+ parts.push("WHERE");
330
+ const whereConditions = this.whereClauses.map((clause, index) => {
331
+ const prefix = index === 0 ? "" : clause.type;
332
+ return `${prefix} ${clause.condition}`.trim();
333
+ });
334
+ parts.push(whereConditions.join(" "));
335
+ }
336
+ if (this.groupByColumns.length > 0) {
337
+ parts.push("GROUP BY");
338
+ parts.push(this.groupByColumns.map((col) => this.escapeIdentifierFn(col)).join(", "));
339
+ }
340
+ if (this.havingClause) {
341
+ parts.push("HAVING");
342
+ parts.push(this.havingClause);
343
+ }
344
+ if (this.orderByColumns.length > 0) {
345
+ parts.push("ORDER BY");
346
+ const orderClauses = this.orderByColumns.map(
347
+ ({ column, direction }) => `${this.escapeIdentifierFn(column)} ${direction}`
348
+ );
349
+ parts.push(orderClauses.join(", "));
350
+ }
351
+ if (this.limitValue !== void 0) {
352
+ parts.push(`LIMIT ${this.limitValue}`);
353
+ }
354
+ if (this.offsetValue !== void 0) {
355
+ parts.push(`OFFSET ${this.offsetValue}`);
356
+ }
357
+ return { sql: parts.join(" "), bindings: this.bindings };
358
+ }
359
+ buildInsertSQL() {
360
+ if (!this.insertTable || !this.insertData) {
361
+ throw new ValidationError("Table and data are required for INSERT query");
362
+ }
363
+ const dataArray = Array.isArray(this.insertData) ? this.insertData : [this.insertData];
364
+ if (dataArray.length === 0) {
365
+ throw new ValidationError("Cannot insert empty data");
366
+ }
367
+ const firstRow = dataArray[0];
368
+ const columns = Object.keys(firstRow);
369
+ const bindings = [];
370
+ const valueRows = dataArray.map((row) => {
371
+ const values = columns.map((col) => {
372
+ bindings.push(row[col]);
373
+ return "?";
374
+ });
375
+ return `(${values.join(", ")})`;
376
+ });
377
+ const sql = `INSERT INTO ${this.escapeIdentifierFn(this.insertTable)} (${columns.map((col) => this.escapeIdentifierFn(col)).join(", ")}) VALUES ${valueRows.join(", ")}`;
378
+ return { sql, bindings };
379
+ }
380
+ buildUpdateSQL() {
381
+ if (!this.updateTable || !this.updateData) {
382
+ throw new ValidationError("Table and data are required for UPDATE query");
383
+ }
384
+ const parts = [];
385
+ const bindings = [];
386
+ parts.push("UPDATE");
387
+ parts.push(this.escapeIdentifierFn(this.updateTable));
388
+ parts.push("SET");
389
+ const setClauses = Object.entries(this.updateData).map(([key, value]) => {
390
+ bindings.push(value);
391
+ return `${this.escapeIdentifierFn(key)} = ?`;
392
+ });
393
+ parts.push(setClauses.join(", "));
394
+ if (this.whereClauses.length > 0) {
395
+ parts.push("WHERE");
396
+ const whereConditions = this.whereClauses.map((clause, index) => {
397
+ const prefix = index === 0 ? "" : clause.type;
398
+ return `${prefix} ${clause.condition}`.trim();
399
+ });
400
+ parts.push(whereConditions.join(" "));
401
+ bindings.push(...this.bindings);
402
+ }
403
+ return { sql: parts.join(" "), bindings };
404
+ }
405
+ buildDeleteSQL() {
406
+ if (!this.deleteTable) {
407
+ throw new ValidationError("Table is required for DELETE query");
408
+ }
409
+ const parts = [];
410
+ const bindings = [];
411
+ parts.push("DELETE FROM");
412
+ parts.push(this.escapeIdentifierFn(this.deleteTable));
413
+ if (this.whereClauses.length > 0) {
414
+ parts.push("WHERE");
415
+ const whereConditions = this.whereClauses.map((clause, index) => {
416
+ const prefix = index === 0 ? "" : clause.type;
417
+ return `${prefix} ${clause.condition}`.trim();
418
+ });
419
+ parts.push(whereConditions.join(" "));
420
+ bindings.push(...this.bindings);
421
+ }
422
+ return { sql: parts.join(" "), bindings };
423
+ }
424
+ };
425
+
426
+ // src/adapter/mysql-adapter.ts
427
+ var MySQLAdapter = class extends BaseAdapter {
428
+ name = "MySQL";
429
+ version = "2.0.0";
430
+ pool;
431
+ mysql2Options;
432
+ poolConfig = {
433
+ min: POOL_DEFAULTS.min,
434
+ max: POOL_DEFAULTS.max,
435
+ acquireTimeout: POOL_DEFAULTS.acquireTimeout,
436
+ idleTimeout: POOL_DEFAULTS.idleTimeout,
437
+ queueLimit: POOL_DEFAULTS.queueLimit,
438
+ queryTimeout: POOL_DEFAULTS.queryTimeout
439
+ };
440
+ constructor(options = {}) {
441
+ super(options);
442
+ this.mysql2Options = options.mysql2Options;
443
+ }
444
+ async doConnect(config) {
445
+ this.poolConfig = {
446
+ min: config.pool?.min ?? POOL_DEFAULTS.min,
447
+ max: config.pool?.max ?? config.poolSize ?? POOL_DEFAULTS.max,
448
+ acquireTimeout: config.pool?.acquireTimeout ?? POOL_DEFAULTS.acquireTimeout,
449
+ idleTimeout: config.pool?.idleTimeout ?? POOL_DEFAULTS.idleTimeout,
450
+ queueLimit: config.pool?.queueLimit ?? POOL_DEFAULTS.queueLimit,
451
+ queryTimeout: config.pool?.queryTimeout ?? POOL_DEFAULTS.queryTimeout
452
+ };
453
+ const connectionOptions = {
454
+ host: config.host,
455
+ port: config.port || 3306,
456
+ user: config.user,
457
+ password: config.password,
458
+ database: config.database,
459
+ // Pool configuration with production-ready defaults
460
+ connectionLimit: this.poolConfig.max,
461
+ waitForConnections: true,
462
+ queueLimit: this.poolConfig.queueLimit,
463
+ connectTimeout: config.connectionTimeout || 1e4,
464
+ idleTimeout: this.poolConfig.idleTimeout,
465
+ // Additional pool options
466
+ ...config.pool?.enableKeepAlive !== false && {
467
+ enableKeepAlive: true,
468
+ keepAliveInitialDelay: config.pool?.keepAliveInitialDelay || 1e4
469
+ },
470
+ ...this.mysql2Options
471
+ };
472
+ if (config.ssl) {
473
+ connectionOptions.ssl = typeof config.ssl === "boolean" ? {} : config.ssl;
474
+ }
475
+ this.pool = new MySQLConnectionPool(connectionOptions);
476
+ await this.pool.initialize();
477
+ this.logger?.info("Connected to MySQL database", {
478
+ database: config.database,
479
+ poolSize: this.poolConfig.max,
480
+ queueLimit: this.poolConfig.queueLimit,
481
+ queryTimeout: this.poolConfig.queryTimeout
482
+ });
483
+ }
484
+ async doDisconnect() {
485
+ if (this.pool) {
486
+ await this.pool.end();
487
+ this.pool = void 0;
488
+ this.logger?.info("Disconnected from MySQL database");
489
+ }
490
+ }
491
+ async doQuery(sql, params, options) {
492
+ if (!this.pool) {
493
+ throw new ConnectionError("Database pool not initialized");
494
+ }
495
+ const connection = options?.transaction ? options.transaction.getConnection() : await this.pool.getConnection();
496
+ try {
497
+ const queryParams = this.normalizeParams(params);
498
+ const command = sql.trim().split(" ")[0]?.toUpperCase();
499
+ const timeout = options?.timeout ?? this.poolConfig.queryTimeout;
500
+ const executeWithTimeout = async (executor) => {
501
+ if (!timeout) {
502
+ return executor();
503
+ }
504
+ return Promise.race([
505
+ executor(),
506
+ new Promise(
507
+ (_, reject) => setTimeout(() => reject(new QueryTimeoutError(sql.slice(0, 100), timeout)), timeout)
508
+ )
509
+ ]);
510
+ };
511
+ if (command === "INSERT" || command === "UPDATE" || command === "DELETE") {
512
+ const [result] = await executeWithTimeout(
513
+ () => connection.execute(sql, queryParams)
514
+ );
515
+ return {
516
+ rows: [],
517
+ rowCount: result.affectedRows || 0,
518
+ affectedRows: result.affectedRows || 0,
519
+ insertId: result.insertId,
520
+ fields: [],
521
+ command
522
+ };
523
+ }
524
+ const [rows, fields] = await executeWithTimeout(
525
+ () => connection.execute(sql, queryParams)
526
+ );
527
+ return {
528
+ rows,
529
+ rowCount: Array.isArray(rows) ? rows.length : 0,
530
+ affectedRows: Array.isArray(rows) ? rows.length : 0,
531
+ fields: fields?.map((field) => ({
532
+ name: field.name,
533
+ type: field.type?.toString() || "unknown",
534
+ nullable: field.flags ? !(Number(field.flags) & 1) : true,
535
+ primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,
536
+ autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,
537
+ defaultValue: field.default
538
+ })),
539
+ command
540
+ };
541
+ } finally {
542
+ if (!options?.transaction) {
543
+ connection.release();
544
+ }
545
+ }
546
+ }
547
+ async beginTransaction(options) {
548
+ if (!this.pool) {
549
+ throw new ConnectionError("Database pool not initialized");
550
+ }
551
+ const connection = await this.pool.getConnection();
552
+ const transaction = new MySQLTransaction(connection, options);
553
+ try {
554
+ await transaction.begin();
555
+ this.logger?.debug("Transaction started", { id: transaction.id });
556
+ return transaction;
557
+ } catch (error) {
558
+ connection.release();
559
+ throw new TransactionError("Failed to begin transaction", void 0, error);
560
+ }
561
+ }
562
+ async prepare(sql, _name) {
563
+ if (!this.pool) {
564
+ throw new ConnectionError("Database pool not initialized");
565
+ }
566
+ const connection = await this.pool.getConnection();
567
+ return new MySQLPreparedStatement(connection, sql);
568
+ }
569
+ getPoolStats() {
570
+ if (!this.pool) {
571
+ return {
572
+ total: 0,
573
+ idle: 0,
574
+ active: 0,
575
+ waiting: 0
576
+ };
577
+ }
578
+ return this.pool.getStats();
579
+ }
580
+ async ping() {
581
+ if (!this.pool) {
582
+ return false;
583
+ }
584
+ try {
585
+ const connection = await this.pool.getConnection();
586
+ try {
587
+ await connection.ping();
588
+ return true;
589
+ } finally {
590
+ connection.release();
591
+ }
592
+ } catch {
593
+ return false;
594
+ }
595
+ }
596
+ escape(value) {
597
+ return mysql.escape(value);
598
+ }
599
+ escapeIdentifier(identifier) {
600
+ return mysql.escapeId(identifier);
601
+ }
602
+ createQueryBuilder() {
603
+ return new MySQLQueryBuilder({
604
+ adapter: this,
605
+ escapeIdentifier: (id) => this.escapeIdentifier(id),
606
+ parameterPlaceholder: () => "?",
607
+ crypto: this.crypto
608
+ });
609
+ }
610
+ normalizeParams(params) {
611
+ if (!params) {
612
+ return [];
613
+ }
614
+ if (Array.isArray(params)) {
615
+ return params;
616
+ }
617
+ return Object.values(params);
618
+ }
619
+ };
620
+
621
+ export { MySQLAdapter, MySQLConnectionPool, MySQLPreparedStatement, MySQLQueryBuilder, MySQLTransaction };
622
+ //# sourceMappingURL=index.js.map
623
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter/mysql-prepared-statement.ts","../src/adapter/mysql-transaction.ts","../src/pool/connection-pool.ts","../src/query-builder/mysql-query-builder.ts","../src/adapter/mysql-adapter.ts"],"names":["result","mysql2","ConnectionError","TransactionError","mysql3"],"mappings":"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","file":"index.js","sourcesContent":["import { QueryError } from '@db-bridge/core';\n\nimport type { PreparedStatement, QueryResult } from '@db-bridge/core';\nimport type * as mysql from 'mysql2/promise';\n\nexport class MySQLPreparedStatement<T = unknown> implements PreparedStatement<T> {\n private released = false;\n\n constructor(\n private connection: mysql.PoolConnection,\n private sql: string,\n ) {}\n\n async execute(params?: unknown[]): Promise<QueryResult<T>> {\n if (this.released) {\n throw new QueryError('Prepared statement has been released');\n }\n\n try {\n const command = this.sql.trim().split(' ')[0]?.toUpperCase();\n\n // For INSERT/UPDATE/DELETE, we get ResultSetHeader instead of RowDataPacket[]\n if (command === 'INSERT' || command === 'UPDATE' || command === 'DELETE') {\n const [result] = await this.connection.execute<mysql.ResultSetHeader>(\n this.sql,\n params || [],\n );\n return {\n rows: [] as T[],\n rowCount: result.affectedRows || 0,\n affectedRows: result.affectedRows || 0,\n insertId: result.insertId,\n fields: [],\n command,\n };\n }\n\n const [rows, fields] = await this.connection.execute<mysql.RowDataPacket[]>(\n this.sql,\n params || [],\n );\n\n return {\n rows: rows as T[],\n rowCount: Array.isArray(rows) ? rows.length : 0,\n affectedRows: Array.isArray(rows) ? rows.length : 0,\n fields: fields?.map((field) => ({\n name: field.name,\n type: field.type?.toString() || 'unknown',\n nullable: field.flags ? !(Number(field.flags) & 1) : true,\n primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,\n autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,\n defaultValue: field.default,\n })),\n command,\n };\n } catch (error) {\n throw new QueryError(\n `Prepared statement execution failed: ${(error as Error).message}`,\n this.sql,\n params,\n error as Error,\n );\n }\n }\n\n async release(): Promise<void> {\n if (this.released) {\n return;\n }\n\n try {\n // MySQL doesn't have unprepare, just release connection\n this.connection.release();\n this.released = true;\n } catch (error) {\n throw new QueryError(\n `Failed to release prepared statement: ${(error as Error).message}`,\n this.sql,\n undefined,\n error as Error,\n );\n }\n }\n\n /**\n * Alias for release() - industry standard naming\n */\n async close(): Promise<void> {\n return this.release();\n }\n}\n","import { IsolationLevel, TransactionError, generateUUID } from '@db-bridge/core';\nimport * as mysql from 'mysql2/promise';\n\nimport type {\n Transaction,\n TransactionOptions,\n QueryParams,\n QueryOptions,\n QueryResult,\n} from '@db-bridge/core';\n\nexport class MySQLTransaction implements Transaction {\n readonly id: string;\n private _isActive = false;\n private savepoints: Set<string> = new Set();\n\n constructor(\n private connection: mysql.PoolConnection,\n private options?: TransactionOptions,\n ) {\n this.id = generateUUID();\n }\n\n get isActive(): boolean {\n return this._isActive;\n }\n\n async begin(): Promise<void> {\n if (this._isActive) {\n throw new TransactionError('Transaction already active', this.id);\n }\n\n try {\n if (this.options?.isolationLevel) {\n await this.setIsolationLevel(this.options.isolationLevel);\n }\n\n await this.connection.beginTransaction();\n this._isActive = true;\n } catch (error) {\n throw new TransactionError('Failed to begin transaction', this.id, error as Error);\n }\n }\n\n async commit(): Promise<void> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n try {\n await this.connection.commit();\n this._isActive = false;\n this.savepoints.clear();\n } catch (error) {\n throw new TransactionError('Failed to commit transaction', this.id, error as Error);\n } finally {\n this.connection.release();\n }\n }\n\n async rollback(): Promise<void> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n try {\n await this.connection.rollback();\n this._isActive = false;\n this.savepoints.clear();\n } catch (error) {\n throw new TransactionError('Failed to rollback transaction', this.id, error as Error);\n } finally {\n this.connection.release();\n }\n }\n\n async savepoint(name: string): Promise<void> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n if (this.savepoints.has(name)) {\n throw new TransactionError(`Savepoint \"${name}\" already exists`, this.id);\n }\n\n try {\n await this.connection.query(`SAVEPOINT ${mysql.escapeId(name)}`);\n this.savepoints.add(name);\n } catch (error) {\n throw new TransactionError(`Failed to create savepoint \"${name}\"`, this.id, error as Error);\n }\n }\n\n async releaseSavepoint(name: string): Promise<void> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n if (!this.savepoints.has(name)) {\n throw new TransactionError(`Savepoint \"${name}\" does not exist`, this.id);\n }\n\n try {\n await this.connection.query(`RELEASE SAVEPOINT ${mysql.escapeId(name)}`);\n this.savepoints.delete(name);\n } catch (error) {\n throw new TransactionError(`Failed to release savepoint \"${name}\"`, this.id, error as Error);\n }\n }\n\n async rollbackToSavepoint(name: string): Promise<void> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n if (!this.savepoints.has(name)) {\n throw new TransactionError(`Savepoint \"${name}\" does not exist`, this.id);\n }\n\n try {\n await this.connection.query(`ROLLBACK TO SAVEPOINT ${mysql.escapeId(name)}`);\n } catch (error) {\n throw new TransactionError(\n `Failed to rollback to savepoint \"${name}\"`,\n this.id,\n error as Error,\n );\n }\n }\n\n getConnection(): mysql.PoolConnection {\n return this.connection;\n }\n\n async query<T = unknown>(\n sql: string,\n params?: QueryParams,\n _options?: QueryOptions,\n ): Promise<QueryResult<T>> {\n if (!this._isActive) {\n throw new TransactionError('Transaction not active', this.id);\n }\n\n try {\n const queryParams = Array.isArray(params) ? params : params ? Object.values(params) : [];\n const command = sql.trim().split(' ')[0]?.toUpperCase();\n\n // For INSERT/UPDATE/DELETE, we get ResultSetHeader instead of RowDataPacket[]\n if (command === 'INSERT' || command === 'UPDATE' || command === 'DELETE') {\n const [result] = await this.connection.execute<mysql.ResultSetHeader>(sql, queryParams);\n return {\n rows: [] as T[],\n rowCount: result.affectedRows || 0,\n affectedRows: result.affectedRows || 0,\n insertId: result.insertId,\n fields: [],\n command,\n };\n }\n\n const [rows, fields] = await this.connection.execute<mysql.RowDataPacket[]>(sql, queryParams);\n\n const result: QueryResult<T> = {\n rows: rows as T[],\n rowCount: Array.isArray(rows) ? rows.length : 0,\n affectedRows: Array.isArray(rows) ? rows.length : 0,\n fields: fields?.map((field) => ({\n name: field.name,\n type: field.type?.toString() || 'unknown',\n nullable: field.flags ? !(Number(field.flags) & 1) : true,\n primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,\n autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,\n defaultValue: field.default,\n })),\n command,\n };\n\n return result;\n } catch (error) {\n throw new TransactionError(\n `Query failed in transaction: ${(error as Error).message}`,\n this.id,\n error as Error,\n );\n }\n }\n\n /**\n * Alias for query() to provide consistency with adapter's execute method\n */\n async execute<T = unknown>(\n sql: string,\n params?: QueryParams,\n options?: QueryOptions,\n ): Promise<QueryResult<T>> {\n return this.query<T>(sql, params, options);\n }\n\n private async setIsolationLevel(level: IsolationLevel): Promise<void> {\n const mysqlLevel = this.mapIsolationLevel(level);\n await this.connection.query(`SET TRANSACTION ISOLATION LEVEL ${mysqlLevel}`);\n }\n\n private mapIsolationLevel(level: IsolationLevel): string {\n switch (level) {\n case IsolationLevel.READ_UNCOMMITTED: {\n return 'READ UNCOMMITTED';\n }\n case IsolationLevel.READ_COMMITTED: {\n return 'READ COMMITTED';\n }\n case IsolationLevel.REPEATABLE_READ: {\n return 'REPEATABLE READ';\n }\n case IsolationLevel.SERIALIZABLE: {\n return 'SERIALIZABLE';\n }\n default: {\n throw new TransactionError(`Invalid isolation level: ${level}`, this.id);\n }\n }\n }\n}\n","import { ConnectionError } from '@db-bridge/core';\nimport * as mysql from 'mysql2/promise';\n\nimport type { PoolStats } from '@db-bridge/core';\n\nexport class MySQLConnectionPool {\n private pool?: mysql.Pool;\n\n constructor(private options: mysql.ConnectionOptions) {}\n\n async initialize(): Promise<void> {\n try {\n this.pool = mysql.createPool(this.options);\n\n const connection = await this.pool.getConnection();\n await connection.ping();\n connection.release();\n } catch (error) {\n throw new ConnectionError('Failed to initialize MySQL connection pool', error as Error);\n }\n }\n\n async getConnection(): Promise<mysql.PoolConnection> {\n if (!this.pool) {\n throw new ConnectionError('Connection pool not initialized');\n }\n\n try {\n return await this.pool.getConnection();\n } catch (error) {\n throw new ConnectionError('Failed to get connection from pool', error as Error);\n }\n }\n\n async end(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = undefined;\n }\n }\n\n getStats(): PoolStats {\n if (!this.pool) {\n return {\n total: 0,\n idle: 0,\n active: 0,\n waiting: 0,\n };\n }\n\n // mysql2 doesn't expose pool stats directly, so we use internal properties\n // These may change in future versions of mysql2\n const pool = this.pool as any;\n const poolConfig = pool.config;\n\n // Get connection limit from config\n const connectionLimit = poolConfig?.connectionLimit || 10;\n\n // Try to access internal pool state\n const allConnections = pool._allConnections || [];\n const freeConnections = pool._freeConnections || [];\n const connectionQueue = pool._connectionQueue || [];\n\n return {\n total: connectionLimit,\n idle: freeConnections.length,\n active: allConnections.length - freeConnections.length,\n waiting: connectionQueue.length,\n };\n }\n}\n","import { BaseQueryBuilder, ValidationError } from '@db-bridge/core';\n\nexport class MySQLQueryBuilder<T = unknown> extends BaseQueryBuilder<T> {\n protected buildSelectSQL(): { sql: string; bindings: unknown[] } {\n if (!this.fromTable) {\n throw new ValidationError('FROM table is required for SELECT query');\n }\n\n const parts: string[] = [];\n\n parts.push('SELECT');\n parts.push(this.selectColumns.join(', '));\n\n parts.push('FROM');\n if (this.fromAlias) {\n parts.push(\n `${this.escapeIdentifierFn(this.fromTable)} AS ${this.escapeIdentifierFn(this.fromAlias)}`,\n );\n } else {\n parts.push(this.escapeIdentifierFn(this.fromTable));\n }\n\n this.joins.forEach((join) => {\n parts.push(`${join.type} JOIN ${join.table} ON ${join.on}`);\n });\n\n if (this.whereClauses.length > 0) {\n parts.push('WHERE');\n const whereConditions = this.whereClauses.map((clause, index) => {\n const prefix = index === 0 ? '' : clause.type;\n return `${prefix} ${clause.condition}`.trim();\n });\n parts.push(whereConditions.join(' '));\n }\n\n if (this.groupByColumns.length > 0) {\n parts.push('GROUP BY');\n parts.push(this.groupByColumns.map((col) => this.escapeIdentifierFn(col)).join(', '));\n }\n\n if (this.havingClause) {\n parts.push('HAVING');\n parts.push(this.havingClause);\n }\n\n if (this.orderByColumns.length > 0) {\n parts.push('ORDER BY');\n const orderClauses = this.orderByColumns.map(\n ({ column, direction }) => `${this.escapeIdentifierFn(column)} ${direction}`,\n );\n parts.push(orderClauses.join(', '));\n }\n\n if (this.limitValue !== undefined) {\n parts.push(`LIMIT ${this.limitValue}`);\n }\n\n if (this.offsetValue !== undefined) {\n parts.push(`OFFSET ${this.offsetValue}`);\n }\n\n return { sql: parts.join(' '), bindings: this.bindings };\n }\n\n protected buildInsertSQL(): { sql: string; bindings: unknown[] } {\n if (!this.insertTable || !this.insertData) {\n throw new ValidationError('Table and data are required for INSERT query');\n }\n\n const dataArray = Array.isArray(this.insertData) ? this.insertData : [this.insertData];\n if (dataArray.length === 0) {\n throw new ValidationError('Cannot insert empty data');\n }\n\n const firstRow = dataArray[0]!;\n const columns = Object.keys(firstRow);\n const bindings: unknown[] = [];\n\n const valueRows = dataArray.map((row) => {\n const values = columns.map((col) => {\n bindings.push(row[col]);\n return '?';\n });\n return `(${values.join(', ')})`;\n });\n\n const sql = `INSERT INTO ${this.escapeIdentifierFn(this.insertTable)} (${columns\n .map((col) => this.escapeIdentifierFn(col))\n .join(', ')}) VALUES ${valueRows.join(', ')}`;\n\n return { sql, bindings };\n }\n\n protected buildUpdateSQL(): { sql: string; bindings: unknown[] } {\n if (!this.updateTable || !this.updateData) {\n throw new ValidationError('Table and data are required for UPDATE query');\n }\n\n const parts: string[] = [];\n const bindings: unknown[] = [];\n\n parts.push('UPDATE');\n parts.push(this.escapeIdentifierFn(this.updateTable));\n parts.push('SET');\n\n const setClauses = Object.entries(this.updateData).map(([key, value]) => {\n bindings.push(value);\n return `${this.escapeIdentifierFn(key)} = ?`;\n });\n parts.push(setClauses.join(', '));\n\n if (this.whereClauses.length > 0) {\n parts.push('WHERE');\n const whereConditions = this.whereClauses.map((clause, index) => {\n const prefix = index === 0 ? '' : clause.type;\n return `${prefix} ${clause.condition}`.trim();\n });\n parts.push(whereConditions.join(' '));\n bindings.push(...this.bindings);\n }\n\n return { sql: parts.join(' '), bindings };\n }\n\n protected buildDeleteSQL(): { sql: string; bindings: unknown[] } {\n if (!this.deleteTable) {\n throw new ValidationError('Table is required for DELETE query');\n }\n\n const parts: string[] = [];\n const bindings: unknown[] = [];\n\n parts.push('DELETE FROM');\n parts.push(this.escapeIdentifierFn(this.deleteTable));\n\n if (this.whereClauses.length > 0) {\n parts.push('WHERE');\n const whereConditions = this.whereClauses.map((clause, index) => {\n const prefix = index === 0 ? '' : clause.type;\n return `${prefix} ${clause.condition}`.trim();\n });\n parts.push(whereConditions.join(' '));\n bindings.push(...this.bindings);\n }\n\n return { sql: parts.join(' '), bindings };\n }\n}\n","import {\n BaseAdapter,\n ConnectionError,\n TransactionError,\n QueryTimeoutError,\n POOL_DEFAULTS,\n} from '@db-bridge/core';\nimport * as mysql from 'mysql2/promise';\n\nimport { MySQLPreparedStatement } from './mysql-prepared-statement';\nimport { MySQLTransaction } from './mysql-transaction';\nimport { MySQLConnectionPool } from '../pool/connection-pool';\nimport { MySQLQueryBuilder } from '../query-builder/mysql-query-builder';\n\nimport type {\n BaseAdapterOptions,\n ConnectionConfig,\n PoolStats,\n PreparedStatement,\n QueryOptions,\n QueryParams,\n QueryResult,\n Transaction,\n TransactionOptions,\n} from '@db-bridge/core';\n\nexport interface MySQLAdapterOptions extends BaseAdapterOptions {\n mysql2Options?: mysql.ConnectionOptions;\n}\n\nexport class MySQLAdapter extends BaseAdapter {\n readonly name = 'MySQL';\n readonly version = '2.0.0';\n\n private pool?: MySQLConnectionPool;\n private readonly mysql2Options?: mysql.ConnectionOptions;\n private poolConfig: {\n min: number;\n max: number;\n acquireTimeout: number;\n idleTimeout: number;\n queueLimit: number;\n queryTimeout: number;\n } = {\n min: POOL_DEFAULTS.min,\n max: POOL_DEFAULTS.max,\n acquireTimeout: POOL_DEFAULTS.acquireTimeout,\n idleTimeout: POOL_DEFAULTS.idleTimeout,\n queueLimit: POOL_DEFAULTS.queueLimit,\n queryTimeout: POOL_DEFAULTS.queryTimeout,\n };\n\n constructor(options: MySQLAdapterOptions = {}) {\n super(options);\n this.mysql2Options = options.mysql2Options;\n }\n\n protected async doConnect(config: ConnectionConfig): Promise<void> {\n // Merge pool config with defaults\n this.poolConfig = {\n min: config.pool?.min ?? POOL_DEFAULTS.min,\n max: config.pool?.max ?? config.poolSize ?? POOL_DEFAULTS.max,\n acquireTimeout: config.pool?.acquireTimeout ?? POOL_DEFAULTS.acquireTimeout,\n idleTimeout: config.pool?.idleTimeout ?? POOL_DEFAULTS.idleTimeout,\n queueLimit: config.pool?.queueLimit ?? POOL_DEFAULTS.queueLimit,\n queryTimeout: config.pool?.queryTimeout ?? POOL_DEFAULTS.queryTimeout,\n };\n\n const connectionOptions: mysql.ConnectionOptions = {\n host: config.host,\n port: config.port || 3306,\n user: config.user,\n password: config.password,\n database: config.database,\n\n // Pool configuration with production-ready defaults\n connectionLimit: this.poolConfig.max,\n waitForConnections: true,\n queueLimit: this.poolConfig.queueLimit,\n connectTimeout: config.connectionTimeout || 10000,\n idleTimeout: this.poolConfig.idleTimeout,\n\n // Additional pool options\n ...(config.pool?.enableKeepAlive !== false && {\n enableKeepAlive: true,\n keepAliveInitialDelay: config.pool?.keepAliveInitialDelay || 10000,\n }),\n\n ...this.mysql2Options,\n };\n\n if (config.ssl) {\n connectionOptions.ssl = typeof config.ssl === 'boolean' ? {} : config.ssl;\n }\n\n this.pool = new MySQLConnectionPool(connectionOptions);\n await this.pool.initialize();\n\n this.logger?.info('Connected to MySQL database', {\n database: config.database,\n poolSize: this.poolConfig.max,\n queueLimit: this.poolConfig.queueLimit,\n queryTimeout: this.poolConfig.queryTimeout,\n });\n }\n\n protected async doDisconnect(): Promise<void> {\n if (this.pool) {\n await this.pool.end();\n this.pool = undefined;\n this.logger?.info('Disconnected from MySQL database');\n }\n }\n\n protected async doQuery<T = unknown>(\n sql: string,\n params?: QueryParams,\n options?: QueryOptions,\n ): Promise<QueryResult<T>> {\n if (!this.pool) {\n throw new ConnectionError('Database pool not initialized');\n }\n\n const connection = options?.transaction\n ? (options.transaction as MySQLTransaction).getConnection()\n : await this.pool.getConnection();\n\n try {\n const queryParams = this.normalizeParams(params);\n const command = sql.trim().split(' ')[0]?.toUpperCase();\n const timeout = options?.timeout ?? this.poolConfig.queryTimeout;\n\n // Execute with timeout\n const executeWithTimeout = async <R>(executor: () => Promise<R>): Promise<R> => {\n if (!timeout) {\n return executor();\n }\n\n return Promise.race([\n executor(),\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new QueryTimeoutError(sql.slice(0, 100), timeout)), timeout),\n ),\n ]);\n };\n\n // For INSERT/UPDATE/DELETE, we get ResultSetHeader instead of RowDataPacket[]\n if (command === 'INSERT' || command === 'UPDATE' || command === 'DELETE') {\n const [result] = await executeWithTimeout(() =>\n connection.execute<mysql.ResultSetHeader>(sql, queryParams),\n );\n return {\n rows: [] as T[],\n rowCount: result.affectedRows || 0,\n affectedRows: result.affectedRows || 0,\n insertId: result.insertId,\n fields: [],\n command,\n };\n }\n\n // For SELECT and other queries\n const [rows, fields] = await executeWithTimeout(() =>\n connection.execute<mysql.RowDataPacket[]>(sql, queryParams),\n );\n\n return {\n rows: rows as T[],\n rowCount: Array.isArray(rows) ? rows.length : 0,\n affectedRows: Array.isArray(rows) ? rows.length : 0,\n fields: fields?.map((field) => ({\n name: field.name,\n type: field.type?.toString() || 'unknown',\n nullable: field.flags ? !(Number(field.flags) & 1) : true,\n primaryKey: field.flags ? !!(Number(field.flags) & 2) : false,\n autoIncrement: field.flags ? !!(Number(field.flags) & 512) : false,\n defaultValue: field.default,\n })),\n command,\n };\n } finally {\n if (!options?.transaction) {\n connection.release();\n }\n }\n }\n\n override async beginTransaction(options?: TransactionOptions): Promise<Transaction> {\n if (!this.pool) {\n throw new ConnectionError('Database pool not initialized');\n }\n\n const connection = await this.pool.getConnection();\n const transaction = new MySQLTransaction(connection, options);\n\n try {\n await transaction.begin();\n this.logger?.debug('Transaction started', { id: transaction.id });\n return transaction;\n } catch (error) {\n connection.release();\n throw new TransactionError('Failed to begin transaction', undefined, error as Error);\n }\n }\n\n override async prepare<T = unknown>(sql: string, _name?: string): Promise<PreparedStatement<T>> {\n if (!this.pool) {\n throw new ConnectionError('Database pool not initialized');\n }\n\n const connection = await this.pool.getConnection();\n return new MySQLPreparedStatement<T>(connection, sql);\n }\n\n override getPoolStats(): PoolStats {\n if (!this.pool) {\n return {\n total: 0,\n idle: 0,\n active: 0,\n waiting: 0,\n };\n }\n\n return this.pool.getStats();\n }\n\n override async ping(): Promise<boolean> {\n if (!this.pool) {\n return false;\n }\n\n try {\n const connection = await this.pool.getConnection();\n try {\n await connection.ping();\n return true;\n } finally {\n connection.release();\n }\n } catch {\n return false;\n }\n }\n\n override escape(value: unknown): string {\n return mysql.escape(value);\n }\n\n override escapeIdentifier(identifier: string): string {\n return mysql.escapeId(identifier);\n }\n\n createQueryBuilder<T = unknown>(): MySQLQueryBuilder<T> {\n return new MySQLQueryBuilder<T>({\n adapter: this,\n escapeIdentifier: (id) => this.escapeIdentifier(id),\n parameterPlaceholder: () => '?',\n crypto: this.crypto,\n });\n }\n\n private normalizeParams(params?: QueryParams): unknown[] {\n if (!params) {\n return [];\n }\n\n if (Array.isArray(params)) {\n return params;\n }\n\n return Object.values(params);\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "type": "module",
3
+ "name": "@db-bridge/mysql",
4
+ "version": "1.0.0",
5
+ "description": "MySQL adapter for db-bridge",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "scripts": {
19
+ "build": "tsup",
20
+ "dev": "tsup --watch",
21
+ "test": "vitest",
22
+ "test:coverage": "vitest --coverage",
23
+ "lint": "eslint src --ext .ts",
24
+ "typecheck": "tsc --noEmit",
25
+ "clean": "rimraf dist"
26
+ },
27
+ "dependencies": {
28
+ "@db-bridge/core": "^1.0.0"
29
+ },
30
+ "peerDependencies": {
31
+ "mysql2": "^3.9.0 || ^4.0.0"
32
+ },
33
+ "peerDependenciesMeta": {
34
+ "mysql2": {
35
+ "optional": false
36
+ }
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.0.0",
40
+ "@vitest/coverage-v8": "^3.0.0",
41
+ "mysql2": "^3.16.0",
42
+ "tsup": "^8.0.1",
43
+ "typescript": "^5.3.0",
44
+ "vitest": "^3.0.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=16.0.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "license": "MIT",
53
+ "gitHead": "7aaca822d0d43120f453562de592e48e7d3e8d32"
54
+ }