@ductape/sdk 0.0.4-v42 → 0.0.4-v43

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 (76) hide show
  1. package/dist/apps/services/app.service.d.ts +10 -0
  2. package/dist/apps/services/app.service.js +22 -0
  3. package/dist/apps/services/app.service.js.map +1 -1
  4. package/dist/database/adapters/base.adapter.d.ts +176 -0
  5. package/dist/database/adapters/base.adapter.js +31 -0
  6. package/dist/database/adapters/base.adapter.js.map +1 -0
  7. package/dist/database/adapters/dynamodb.adapter.d.ts +83 -0
  8. package/dist/database/adapters/dynamodb.adapter.js +1237 -0
  9. package/dist/database/adapters/dynamodb.adapter.js.map +1 -0
  10. package/dist/database/adapters/mongodb.adapter.d.ts +70 -0
  11. package/dist/database/adapters/mongodb.adapter.js +717 -0
  12. package/dist/database/adapters/mongodb.adapter.js.map +1 -0
  13. package/dist/database/adapters/mysql.adapter.d.ts +141 -0
  14. package/dist/database/adapters/mysql.adapter.js +1221 -0
  15. package/dist/database/adapters/mysql.adapter.js.map +1 -0
  16. package/dist/database/adapters/postgresql.adapter.d.ts +142 -0
  17. package/dist/database/adapters/postgresql.adapter.js +1288 -0
  18. package/dist/database/adapters/postgresql.adapter.js.map +1 -0
  19. package/dist/database/database.service.d.ts +190 -0
  20. package/dist/database/database.service.js +552 -0
  21. package/dist/database/database.service.js.map +1 -0
  22. package/dist/database/index.d.ts +18 -0
  23. package/dist/database/index.js +98 -0
  24. package/dist/database/index.js.map +1 -0
  25. package/dist/database/types/aggregation.types.d.ts +202 -0
  26. package/dist/database/types/aggregation.types.js +21 -0
  27. package/dist/database/types/aggregation.types.js.map +1 -0
  28. package/dist/database/types/connection.types.d.ts +132 -0
  29. package/dist/database/types/connection.types.js +6 -0
  30. package/dist/database/types/connection.types.js.map +1 -0
  31. package/dist/database/types/database.types.d.ts +173 -0
  32. package/dist/database/types/database.types.js +73 -0
  33. package/dist/database/types/database.types.js.map +1 -0
  34. package/dist/database/types/index.d.ts +12 -0
  35. package/dist/database/types/index.js +37 -0
  36. package/dist/database/types/index.js.map +1 -0
  37. package/dist/database/types/index.types.d.ts +220 -0
  38. package/dist/database/types/index.types.js +27 -0
  39. package/dist/database/types/index.types.js.map +1 -0
  40. package/dist/database/types/migration.types.d.ts +205 -0
  41. package/dist/database/types/migration.types.js +44 -0
  42. package/dist/database/types/migration.types.js.map +1 -0
  43. package/dist/database/types/query.types.d.ts +274 -0
  44. package/dist/database/types/query.types.js +57 -0
  45. package/dist/database/types/query.types.js.map +1 -0
  46. package/dist/database/types/result.types.d.ts +218 -0
  47. package/dist/database/types/result.types.js +6 -0
  48. package/dist/database/types/result.types.js.map +1 -0
  49. package/dist/database/types/schema.types.d.ts +190 -0
  50. package/dist/database/types/schema.types.js +69 -0
  51. package/dist/database/types/schema.types.js.map +1 -0
  52. package/dist/database/utils/helpers.d.ts +66 -0
  53. package/dist/database/utils/helpers.js +501 -0
  54. package/dist/database/utils/helpers.js.map +1 -0
  55. package/dist/database/utils/migration.utils.d.ts +151 -0
  56. package/dist/database/utils/migration.utils.js +476 -0
  57. package/dist/database/utils/migration.utils.js.map +1 -0
  58. package/dist/database/utils/transaction.d.ts +64 -0
  59. package/dist/database/utils/transaction.js +130 -0
  60. package/dist/database/utils/transaction.js.map +1 -0
  61. package/dist/database/validators/connection.validator.d.ts +20 -0
  62. package/dist/database/validators/connection.validator.js +267 -0
  63. package/dist/database/validators/connection.validator.js.map +1 -0
  64. package/dist/database/validators/query.validator.d.ts +31 -0
  65. package/dist/database/validators/query.validator.js +305 -0
  66. package/dist/database/validators/query.validator.js.map +1 -0
  67. package/dist/database/validators/schema.validator.d.ts +31 -0
  68. package/dist/database/validators/schema.validator.js +334 -0
  69. package/dist/database/validators/schema.validator.js.map +1 -0
  70. package/dist/index.d.ts +25 -4
  71. package/dist/index.js +36 -4
  72. package/dist/index.js.map +1 -1
  73. package/dist/processor/services/processor.service.js +10 -8
  74. package/dist/processor/services/processor.service.js.map +1 -1
  75. package/dist/types/processor.types.d.ts +2 -2
  76. package/package.json +3 -1
@@ -0,0 +1,1221 @@
1
+ "use strict";
2
+ /**
3
+ * MySQL Database Adapter
4
+ * Implements database operations for MySQL/MariaDB
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.MySQLAdapter = void 0;
41
+ const base_adapter_1 = require("./base.adapter");
42
+ const database_types_1 = require("../types/database.types");
43
+ const schema_types_1 = require("../types/schema.types");
44
+ const migration_types_1 = require("../types/migration.types");
45
+ /**
46
+ * MySQL Connection wrapper
47
+ */
48
+ class MySQLConnection {
49
+ constructor(id, connection) {
50
+ this.id = id;
51
+ this.type = database_types_1.DatabaseType.MYSQL;
52
+ this.status = database_types_1.ConnectionStatus.CONNECTED;
53
+ this.connection = connection;
54
+ }
55
+ async connect() {
56
+ this.status = database_types_1.ConnectionStatus.CONNECTED;
57
+ }
58
+ async disconnect() {
59
+ if (this.connection) {
60
+ await this.connection.end();
61
+ this.status = database_types_1.ConnectionStatus.DISCONNECTED;
62
+ }
63
+ }
64
+ isConnected() {
65
+ return this.status === database_types_1.ConnectionStatus.CONNECTED;
66
+ }
67
+ getClient() {
68
+ return this.connection;
69
+ }
70
+ getType() {
71
+ return this.type;
72
+ }
73
+ getConfig() {
74
+ throw new Error('Config not stored in connection');
75
+ }
76
+ }
77
+ /**
78
+ * MySQL Database Adapter
79
+ */
80
+ class MySQLAdapter extends base_adapter_1.BaseDatabaseAdapter {
81
+ constructor() {
82
+ super(...arguments);
83
+ this.type = database_types_1.DatabaseType.MYSQL;
84
+ }
85
+ // ==================== Connection Methods ====================
86
+ async connect(config) {
87
+ var _a, _b, _c, _d, _e, _f;
88
+ try {
89
+ // Dynamic import of mysql2/promise
90
+ // @ts-ignore - mysql2 is an optional peer dependency
91
+ const mysql = await Promise.resolve().then(() => __importStar(require('mysql2/promise')));
92
+ const connection = await mysql.createConnection(Object.assign({ host: (_a = config.options) === null || _a === void 0 ? void 0 : _a.host, port: ((_b = config.options) === null || _b === void 0 ? void 0 : _b.port) || 3306, user: ((_c = config.options) === null || _c === void 0 ? void 0 : _c.username) || ((_d = config.options) === null || _d === void 0 ? void 0 : _d.user), password: (_e = config.options) === null || _e === void 0 ? void 0 : _e.password, database: config.database, ssl: (_f = config.options) === null || _f === void 0 ? void 0 : _f.ssl }, config.options));
93
+ return new MySQLConnection(`mysql-${Date.now()}`, connection);
94
+ }
95
+ catch (error) {
96
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.CONNECTION_ERROR, `Failed to connect to MySQL: ${error.message}`, error);
97
+ }
98
+ }
99
+ async disconnect(connection) {
100
+ await connection.disconnect();
101
+ }
102
+ async testConnection(connection) {
103
+ const startTime = Date.now();
104
+ try {
105
+ const conn = connection.getClient();
106
+ await conn.query('SELECT 1');
107
+ return {
108
+ connected: true,
109
+ message: 'MySQL connection successful',
110
+ databaseType: 'MySQL',
111
+ responseTime: Date.now() - startTime,
112
+ };
113
+ }
114
+ catch (error) {
115
+ return {
116
+ connected: false,
117
+ message: `MySQL connection failed: ${error.message}`,
118
+ databaseType: 'MySQL',
119
+ responseTime: Date.now() - startTime,
120
+ error: error.message,
121
+ };
122
+ }
123
+ }
124
+ // ==================== Transaction Methods ====================
125
+ async beginTransaction(connection, options) {
126
+ const conn = connection.getClient();
127
+ await conn.beginTransaction();
128
+ return { client: conn };
129
+ }
130
+ async commitTransaction(connection, transaction) {
131
+ await transaction.client.commit();
132
+ }
133
+ async rollbackTransaction(connection, transaction) {
134
+ await transaction.client.rollback();
135
+ }
136
+ async createSavepoint(connection, transaction, savepointName) {
137
+ await transaction.client.query(`SAVEPOINT ${this.escapeIdentifier(savepointName)}`);
138
+ }
139
+ async rollbackToSavepoint(connection, transaction, savepointName) {
140
+ await transaction.client.query(`ROLLBACK TO SAVEPOINT ${this.escapeIdentifier(savepointName)}`);
141
+ }
142
+ async releaseSavepoint(connection, transaction, savepointName) {
143
+ await transaction.client.query(`RELEASE SAVEPOINT ${this.escapeIdentifier(savepointName)}`);
144
+ }
145
+ // ==================== Query Methods ====================
146
+ async query(connection, options) {
147
+ const startTime = Date.now();
148
+ try {
149
+ const { query, params } = this.buildSelectQuery(options);
150
+ const conn = connection.getClient();
151
+ const [rows] = await conn.query(query, params);
152
+ const executionTime = Date.now() - startTime;
153
+ return {
154
+ data: rows,
155
+ count: Array.isArray(rows) ? rows.length : 0,
156
+ executionTime,
157
+ };
158
+ }
159
+ catch (error) {
160
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL query failed: ${error.message}`, error);
161
+ }
162
+ }
163
+ async insert(connection, options) {
164
+ const startTime = Date.now();
165
+ try {
166
+ const { query, params } = this.buildInsertQuery(options);
167
+ const conn = connection.getClient();
168
+ const [result] = await conn.query(query, params);
169
+ const executionTime = Date.now() - startTime;
170
+ return {
171
+ insertedCount: result.affectedRows,
172
+ insertedIds: [result.insertId],
173
+ data: undefined,
174
+ executionTime,
175
+ success: true,
176
+ };
177
+ }
178
+ catch (error) {
179
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL insert failed: ${error.message}`, error);
180
+ }
181
+ }
182
+ async update(connection, options) {
183
+ const startTime = Date.now();
184
+ try {
185
+ const { query, params } = this.buildUpdateQuery(options);
186
+ const conn = connection.getClient();
187
+ const [result] = await conn.query(query, params);
188
+ const executionTime = Date.now() - startTime;
189
+ return {
190
+ updatedCount: result.affectedRows,
191
+ matchedCount: result.affectedRows,
192
+ data: undefined,
193
+ executionTime,
194
+ success: true,
195
+ };
196
+ }
197
+ catch (error) {
198
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL update failed: ${error.message}`, error);
199
+ }
200
+ }
201
+ async delete(connection, options) {
202
+ const startTime = Date.now();
203
+ try {
204
+ const { query, params } = this.buildDeleteQuery(options);
205
+ const conn = connection.getClient();
206
+ const [result] = await conn.query(query, params);
207
+ const executionTime = Date.now() - startTime;
208
+ return {
209
+ deletedCount: result.affectedRows,
210
+ data: undefined,
211
+ executionTime,
212
+ success: true,
213
+ };
214
+ }
215
+ catch (error) {
216
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL delete failed: ${error.message}`, error);
217
+ }
218
+ }
219
+ async upsert(connection, options) {
220
+ const startTime = Date.now();
221
+ try {
222
+ const { query, params } = this.buildUpsertQuery(options);
223
+ const conn = connection.getClient();
224
+ const [result] = await conn.query(query, params);
225
+ const executionTime = Date.now() - startTime;
226
+ return {
227
+ insertedCount: 0,
228
+ updatedCount: 0,
229
+ affectedCount: result.affectedRows,
230
+ data: undefined,
231
+ executionTime,
232
+ success: true,
233
+ };
234
+ }
235
+ catch (error) {
236
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL upsert failed: ${error.message}`, error);
237
+ }
238
+ }
239
+ async executeRaw(connection, options) {
240
+ const startTime = Date.now();
241
+ try {
242
+ const conn = connection.getClient();
243
+ const [rows, fields] = await conn.query(options.query, options.params || []);
244
+ const executionTime = Date.now() - startTime;
245
+ return {
246
+ rows: rows,
247
+ rowCount: Array.isArray(rows) ? rows.length : 0,
248
+ fields: fields === null || fields === void 0 ? void 0 : fields.map((f) => ({
249
+ name: f.name,
250
+ type: f.type,
251
+ })),
252
+ executionTime,
253
+ };
254
+ }
255
+ catch (error) {
256
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL raw query failed: ${error.message}`, error);
257
+ }
258
+ }
259
+ // ==================== Aggregation Methods ====================
260
+ async count(connection, options) {
261
+ try {
262
+ const { query, params } = this.buildCountQuery(options);
263
+ const conn = connection.getClient();
264
+ const [rows] = await conn.query(query, params);
265
+ return parseInt(rows[0].count, 10);
266
+ }
267
+ catch (error) {
268
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL count failed: ${error.message}`, error);
269
+ }
270
+ }
271
+ async sum(connection, options) {
272
+ try {
273
+ const { query, params } = this.buildAggregateQuery('SUM', options.column, options);
274
+ const conn = connection.getClient();
275
+ const [rows] = await conn.query(query, params);
276
+ return parseFloat(rows[0].result) || 0;
277
+ }
278
+ catch (error) {
279
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL sum failed: ${error.message}`, error);
280
+ }
281
+ }
282
+ async avg(connection, options) {
283
+ try {
284
+ const { query, params } = this.buildAggregateQuery('AVG', options.column, options);
285
+ const conn = connection.getClient();
286
+ const [rows] = await conn.query(query, params);
287
+ return parseFloat(rows[0].result) || 0;
288
+ }
289
+ catch (error) {
290
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL avg failed: ${error.message}`, error);
291
+ }
292
+ }
293
+ async min(connection, options) {
294
+ try {
295
+ const { query, params } = this.buildAggregateQuery('MIN', options.column, options);
296
+ const conn = connection.getClient();
297
+ const [rows] = await conn.query(query, params);
298
+ return rows[0].result;
299
+ }
300
+ catch (error) {
301
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL min failed: ${error.message}`, error);
302
+ }
303
+ }
304
+ async max(connection, options) {
305
+ try {
306
+ const { query, params } = this.buildAggregateQuery('MAX', options.column, options);
307
+ const conn = connection.getClient();
308
+ const [rows] = await conn.query(query, params);
309
+ return rows[0].result;
310
+ }
311
+ catch (error) {
312
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL max failed: ${error.message}`, error);
313
+ }
314
+ }
315
+ async groupBy(connection, options) {
316
+ try {
317
+ const { query, params } = this.buildGroupByQuery(options);
318
+ const conn = connection.getClient();
319
+ const [rows] = await conn.query(query, params);
320
+ return rows;
321
+ }
322
+ catch (error) {
323
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL groupBy failed: ${error.message}`, error);
324
+ }
325
+ }
326
+ async aggregate(connection, options) {
327
+ try {
328
+ const { query, params } = this.buildMultiAggregateQuery(options);
329
+ const conn = connection.getClient();
330
+ const [rows] = await conn.query(query, params);
331
+ return rows[0] || {};
332
+ }
333
+ catch (error) {
334
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MySQL aggregate failed: ${error.message}`, error);
335
+ }
336
+ }
337
+ // ==================== Schema Methods ====================
338
+ async createTable(connection, schema, options) {
339
+ const startTime = Date.now();
340
+ try {
341
+ const query = this.buildCreateTableQuery(schema, options);
342
+ const conn = connection.getClient();
343
+ await conn.query(query);
344
+ const executionTime = Date.now() - startTime;
345
+ return {
346
+ success: true,
347
+ operation: 'create',
348
+ table: schema.name,
349
+ executionTime,
350
+ };
351
+ }
352
+ catch (error) {
353
+ return {
354
+ success: false,
355
+ operation: 'create',
356
+ table: schema.name,
357
+ error: error.message,
358
+ executionTime: Date.now() - startTime,
359
+ };
360
+ }
361
+ }
362
+ async dropTable(connection, tableName) {
363
+ const startTime = Date.now();
364
+ try {
365
+ const conn = connection.getClient();
366
+ await conn.query(`DROP TABLE IF EXISTS \`${tableName}\``);
367
+ return {
368
+ success: true,
369
+ operation: 'drop',
370
+ table: tableName,
371
+ executionTime: Date.now() - startTime,
372
+ };
373
+ }
374
+ catch (error) {
375
+ return {
376
+ success: false,
377
+ operation: 'drop',
378
+ table: tableName,
379
+ error: error.message,
380
+ executionTime: Date.now() - startTime,
381
+ };
382
+ }
383
+ }
384
+ async alterTable(connection, tableName, alterations, options) {
385
+ const startTime = Date.now();
386
+ try {
387
+ const conn = connection.getClient();
388
+ const queries = this.buildAlterTableQueries(tableName, alterations);
389
+ for (const query of queries) {
390
+ await conn.query(query);
391
+ }
392
+ return {
393
+ success: true,
394
+ operation: 'alter',
395
+ table: tableName,
396
+ executionTime: Date.now() - startTime,
397
+ };
398
+ }
399
+ catch (error) {
400
+ return {
401
+ success: false,
402
+ operation: 'alter',
403
+ table: tableName,
404
+ error: error.message,
405
+ executionTime: Date.now() - startTime,
406
+ };
407
+ }
408
+ }
409
+ async getTableSchema(connection, tableName) {
410
+ try {
411
+ const conn = connection.getClient();
412
+ const query = `
413
+ SELECT
414
+ COLUMN_NAME as column_name,
415
+ DATA_TYPE as data_type,
416
+ IS_NULLABLE as is_nullable,
417
+ COLUMN_DEFAULT as column_default,
418
+ CHARACTER_MAXIMUM_LENGTH as character_maximum_length,
419
+ NUMERIC_PRECISION as numeric_precision,
420
+ NUMERIC_SCALE as numeric_scale,
421
+ COLUMN_KEY as column_key
422
+ FROM INFORMATION_SCHEMA.COLUMNS
423
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
424
+ ORDER BY ORDINAL_POSITION
425
+ `;
426
+ const [rows] = await conn.query(query, [tableName]);
427
+ const columns = rows.map((row) => ({
428
+ name: row.column_name,
429
+ type: this.mapMySQLTypeToColumnType(row.data_type),
430
+ nullable: row.is_nullable === 'YES',
431
+ primaryKey: row.column_key === 'PRI',
432
+ unique: row.column_key === 'UNI',
433
+ defaultValue: row.column_default,
434
+ length: row.character_maximum_length,
435
+ precision: row.numeric_precision,
436
+ scale: row.numeric_scale,
437
+ }));
438
+ return {
439
+ name: tableName,
440
+ columns,
441
+ };
442
+ }
443
+ catch (error) {
444
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.SCHEMA_ERROR, `Failed to get MySQL table schema: ${error.message}`, error);
445
+ }
446
+ }
447
+ async listTables(connection) {
448
+ try {
449
+ const conn = connection.getClient();
450
+ const [rows] = await conn.query('SHOW TABLES');
451
+ return rows.map((row) => Object.values(row)[0]);
452
+ }
453
+ catch (error) {
454
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.SCHEMA_ERROR, `Failed to list MySQL tables: ${error.message}`, error);
455
+ }
456
+ }
457
+ async tableExists(connection, tableName) {
458
+ try {
459
+ const conn = connection.getClient();
460
+ const query = `
461
+ SELECT COUNT(*) as count
462
+ FROM INFORMATION_SCHEMA.TABLES
463
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
464
+ `;
465
+ const [rows] = await conn.query(query, [tableName]);
466
+ return rows[0].count > 0;
467
+ }
468
+ catch (error) {
469
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.SCHEMA_ERROR, `Failed to check MySQL table existence: ${error.message}`, error);
470
+ }
471
+ }
472
+ // ==================== Index Methods ====================
473
+ async createIndex(connection, options) {
474
+ const startTime = Date.now();
475
+ try {
476
+ const query = this.buildCreateIndexQuery(options);
477
+ const conn = connection.getClient();
478
+ await conn.query(query);
479
+ return {
480
+ success: true,
481
+ operation: 'create',
482
+ indexName: options.index.name,
483
+ table: options.table,
484
+ executionTime: Date.now() - startTime,
485
+ };
486
+ }
487
+ catch (error) {
488
+ return {
489
+ success: false,
490
+ operation: 'create',
491
+ indexName: options.index.name,
492
+ table: options.table,
493
+ error: error.message,
494
+ executionTime: Date.now() - startTime,
495
+ };
496
+ }
497
+ }
498
+ async dropIndex(connection, options) {
499
+ const startTime = Date.now();
500
+ try {
501
+ const conn = connection.getClient();
502
+ await conn.query(`DROP INDEX \`${options.indexName}\` ON \`${options.table}\``);
503
+ return {
504
+ success: true,
505
+ operation: 'drop',
506
+ indexName: options.indexName,
507
+ table: options.table,
508
+ executionTime: Date.now() - startTime,
509
+ };
510
+ }
511
+ catch (error) {
512
+ return {
513
+ success: false,
514
+ operation: 'drop',
515
+ indexName: options.indexName,
516
+ table: options.table,
517
+ error: error.message,
518
+ executionTime: Date.now() - startTime,
519
+ };
520
+ }
521
+ }
522
+ async listIndexes(connection, options) {
523
+ try {
524
+ const conn = connection.getClient();
525
+ const query = `
526
+ SELECT
527
+ INDEX_NAME as index_name,
528
+ COLUMN_NAME as column_name,
529
+ NON_UNIQUE as non_unique,
530
+ INDEX_TYPE as index_type
531
+ FROM INFORMATION_SCHEMA.STATISTICS
532
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
533
+ ORDER BY INDEX_NAME, SEQ_IN_INDEX
534
+ `;
535
+ const [rows] = await conn.query(query, [options.table]);
536
+ const indexMap = new Map();
537
+ rows.forEach((row) => {
538
+ if (!indexMap.has(row.index_name)) {
539
+ indexMap.set(row.index_name, {
540
+ name: row.index_name,
541
+ table: options.table,
542
+ columns: [],
543
+ columnDetails: [],
544
+ unique: row.non_unique === 0,
545
+ primaryKey: row.index_name === 'PRIMARY',
546
+ type: row.index_type,
547
+ });
548
+ }
549
+ const indexInfo = indexMap.get(row.index_name);
550
+ indexInfo.columns.push(row.column_name);
551
+ indexInfo.columnDetails.push({
552
+ name: row.column_name,
553
+ order: 'ASC',
554
+ });
555
+ });
556
+ return Array.from(indexMap.values());
557
+ }
558
+ catch (error) {
559
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.INDEX_ERROR, `Failed to list MySQL indexes: ${error.message}`, error);
560
+ }
561
+ }
562
+ async getIndexStatistics(connection, tableName, indexName) {
563
+ try {
564
+ const conn = connection.getClient();
565
+ let query = `
566
+ SELECT
567
+ INDEX_NAME as index_name,
568
+ CARDINALITY as cardinality
569
+ FROM INFORMATION_SCHEMA.STATISTICS
570
+ WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?
571
+ `;
572
+ const params = [tableName];
573
+ if (indexName) {
574
+ query += ' AND INDEX_NAME = ?';
575
+ params.push(indexName);
576
+ }
577
+ const [rows] = await conn.query(query, params);
578
+ return rows.map((row) => ({
579
+ indexName: row.index_name,
580
+ table: tableName,
581
+ size: 0, // MySQL doesn't provide this easily
582
+ tuplesRead: row.cardinality || 0,
583
+ }));
584
+ }
585
+ catch (error) {
586
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.INDEX_ERROR, `Failed to get MySQL index statistics: ${error.message}`, error);
587
+ }
588
+ }
589
+ // ==================== Migration Methods ====================
590
+ /**
591
+ * Build SQL for a migration operation
592
+ */
593
+ async buildMigrationOperationSQL(operation) {
594
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
595
+ switch (operation.type) {
596
+ case migration_types_1.MigrationOperationType.RAW_SQL:
597
+ return operation.sql || null;
598
+ case migration_types_1.MigrationOperationType.CREATE_TABLE:
599
+ if ((_a = operation.params) === null || _a === void 0 ? void 0 : _a.schema) {
600
+ const schema = operation.params.schema;
601
+ const columns = schema.columns
602
+ .map((col) => {
603
+ let def = `\`${col.name}\` ${this.mapColumnTypeToMySQL(col.type)}`;
604
+ if (col.primaryKey)
605
+ def += ' PRIMARY KEY';
606
+ if (col.autoIncrement)
607
+ def += ' AUTO_INCREMENT';
608
+ if (!col.nullable)
609
+ def += ' NOT NULL';
610
+ if (col.unique)
611
+ def += ' UNIQUE';
612
+ if (col.defaultValue !== undefined) {
613
+ def += ` DEFAULT ${this.escapeValue(col.defaultValue)}`;
614
+ }
615
+ return def;
616
+ })
617
+ .join(', ');
618
+ return `CREATE TABLE \`${schema.name}\` (${columns})`;
619
+ }
620
+ return null;
621
+ case migration_types_1.MigrationOperationType.DROP_TABLE:
622
+ return operation.table ? `DROP TABLE IF EXISTS \`${operation.table}\`` : null;
623
+ case migration_types_1.MigrationOperationType.ADD_COLUMN:
624
+ if (operation.table && ((_b = operation.params) === null || _b === void 0 ? void 0 : _b.column)) {
625
+ const col = operation.params.column;
626
+ let def = `ALTER TABLE \`${operation.table}\` ADD COLUMN \`${col.name}\` ${this.mapColumnTypeToMySQL(col.type)}`;
627
+ if (!col.nullable)
628
+ def += ' NOT NULL';
629
+ if (col.defaultValue !== undefined) {
630
+ def += ` DEFAULT ${this.escapeValue(col.defaultValue)}`;
631
+ }
632
+ return def;
633
+ }
634
+ return null;
635
+ case migration_types_1.MigrationOperationType.DROP_COLUMN:
636
+ return operation.table && ((_c = operation.params) === null || _c === void 0 ? void 0 : _c.columnName)
637
+ ? `ALTER TABLE \`${operation.table}\` DROP COLUMN \`${operation.params.columnName}\``
638
+ : null;
639
+ case migration_types_1.MigrationOperationType.MODIFY_COLUMN:
640
+ if (operation.table && ((_d = operation.params) === null || _d === void 0 ? void 0 : _d.column)) {
641
+ const col = operation.params.column;
642
+ return `ALTER TABLE \`${operation.table}\` MODIFY COLUMN \`${col.name}\` ${this.mapColumnTypeToMySQL(col.type)}`;
643
+ }
644
+ return null;
645
+ case migration_types_1.MigrationOperationType.RENAME_COLUMN:
646
+ return operation.table && ((_e = operation.params) === null || _e === void 0 ? void 0 : _e.oldName) && ((_f = operation.params) === null || _f === void 0 ? void 0 : _f.newName)
647
+ ? `ALTER TABLE \`${operation.table}\` RENAME COLUMN \`${operation.params.oldName}\` TO \`${operation.params.newName}\``
648
+ : null;
649
+ case migration_types_1.MigrationOperationType.ADD_INDEX:
650
+ if (operation.table && ((_g = operation.params) === null || _g === void 0 ? void 0 : _g.indexName) && ((_h = operation.params) === null || _h === void 0 ? void 0 : _h.columns)) {
651
+ const unique = operation.params.unique ? 'UNIQUE ' : '';
652
+ const columns = operation.params.columns.map((col) => `\`${col}\``).join(', ');
653
+ return `CREATE ${unique}INDEX \`${operation.params.indexName}\` ON \`${operation.table}\` (${columns})`;
654
+ }
655
+ return null;
656
+ case migration_types_1.MigrationOperationType.DROP_INDEX:
657
+ return ((_j = operation.params) === null || _j === void 0 ? void 0 : _j.indexName) && operation.table
658
+ ? `DROP INDEX \`${operation.params.indexName}\` ON \`${operation.table}\``
659
+ : null;
660
+ case migration_types_1.MigrationOperationType.ADD_CONSTRAINT:
661
+ if (operation.table && ((_k = operation.params) === null || _k === void 0 ? void 0 : _k.constraintName) && ((_l = operation.params) === null || _l === void 0 ? void 0 : _l.definition)) {
662
+ return `ALTER TABLE \`${operation.table}\` ADD CONSTRAINT \`${operation.params.constraintName}\` ${operation.params.definition}`;
663
+ }
664
+ return null;
665
+ case migration_types_1.MigrationOperationType.DROP_CONSTRAINT:
666
+ return operation.table && ((_m = operation.params) === null || _m === void 0 ? void 0 : _m.constraintName)
667
+ ? `ALTER TABLE \`${operation.table}\` DROP CONSTRAINT \`${operation.params.constraintName}\``
668
+ : null;
669
+ default:
670
+ return null;
671
+ }
672
+ }
673
+ async runMigration(connection, migration, options) {
674
+ const startTime = Date.now();
675
+ const statements = [];
676
+ try {
677
+ const conn = connection.getClient();
678
+ await conn.query('START TRANSACTION');
679
+ try {
680
+ // Execute migration operations
681
+ for (const operation of migration.up) {
682
+ const sql = await this.buildMigrationOperationSQL(operation);
683
+ if (sql) {
684
+ statements.push(sql);
685
+ await conn.query(sql);
686
+ }
687
+ }
688
+ // Record migration in history table
689
+ await this.recordMigration(conn, migration, migration_types_1.MigrationDirection.UP);
690
+ await conn.query('COMMIT');
691
+ return {
692
+ tag: migration.tag,
693
+ status: migration_types_1.MigrationStatus.COMPLETED,
694
+ direction: migration_types_1.MigrationDirection.UP,
695
+ executedAt: new Date(),
696
+ duration: Date.now() - startTime,
697
+ statements,
698
+ };
699
+ }
700
+ catch (error) {
701
+ await conn.query('ROLLBACK');
702
+ throw error;
703
+ }
704
+ }
705
+ catch (error) {
706
+ return {
707
+ tag: migration.tag,
708
+ status: migration_types_1.MigrationStatus.FAILED,
709
+ direction: migration_types_1.MigrationDirection.UP,
710
+ executedAt: new Date(),
711
+ duration: Date.now() - startTime,
712
+ error: error.message,
713
+ statements,
714
+ };
715
+ }
716
+ }
717
+ async rollbackMigration(connection, migration, options) {
718
+ const startTime = Date.now();
719
+ const statements = [];
720
+ try {
721
+ const conn = connection.getClient();
722
+ await conn.query('START TRANSACTION');
723
+ try {
724
+ // Execute rollback operations
725
+ for (const operation of migration.down) {
726
+ const sql = await this.buildMigrationOperationSQL(operation);
727
+ if (sql) {
728
+ statements.push(sql);
729
+ await conn.query(sql);
730
+ }
731
+ }
732
+ // Remove migration from history table
733
+ await this.removeMigration(conn, migration.tag);
734
+ await conn.query('COMMIT');
735
+ return {
736
+ tag: migration.tag,
737
+ status: migration_types_1.MigrationStatus.ROLLED_BACK,
738
+ direction: migration_types_1.MigrationDirection.DOWN,
739
+ executedAt: new Date(),
740
+ duration: Date.now() - startTime,
741
+ statements,
742
+ };
743
+ }
744
+ catch (error) {
745
+ await conn.query('ROLLBACK');
746
+ throw error;
747
+ }
748
+ }
749
+ catch (error) {
750
+ return {
751
+ tag: migration.tag,
752
+ status: migration_types_1.MigrationStatus.FAILED,
753
+ direction: migration_types_1.MigrationDirection.DOWN,
754
+ executedAt: new Date(),
755
+ duration: Date.now() - startTime,
756
+ error: error.message,
757
+ statements,
758
+ };
759
+ }
760
+ }
761
+ async getMigrationHistory(connection, options) {
762
+ try {
763
+ const conn = connection.getClient();
764
+ // Ensure migration table exists
765
+ await this.ensureMigrationTable(conn);
766
+ const query = `
767
+ SELECT tag, name, executed_at
768
+ FROM _ductape_migrations
769
+ ORDER BY executed_at DESC
770
+ `;
771
+ const [rows] = await conn.query(query);
772
+ return rows.map((row) => ({
773
+ tag: row.tag,
774
+ name: row.name,
775
+ env: options.env,
776
+ product: options.product,
777
+ database: options.database,
778
+ status: migration_types_1.MigrationStatus.COMPLETED,
779
+ direction: migration_types_1.MigrationDirection.UP,
780
+ appliedAt: row.executed_at,
781
+ }));
782
+ }
783
+ catch (error) {
784
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.MIGRATION_ERROR, `Failed to get MySQL migration history: ${error.message}`, error);
785
+ }
786
+ }
787
+ // ==================== Query Builder Helpers ====================
788
+ /**
789
+ * Build SELECT query from options
790
+ */
791
+ buildSelectQuery(options) {
792
+ const params = [];
793
+ // SELECT clause
794
+ const selectColumns = options.select
795
+ ? Array.isArray(options.select)
796
+ ? options.select.map((col) => `\`${col}\``)
797
+ : [options.select]
798
+ : ['*'];
799
+ let query = `SELECT ${selectColumns.join(', ')} FROM \`${options.table}\``;
800
+ // WHERE clause
801
+ if (options.where) {
802
+ const { clause, values } = this.buildWhereClause(options.where);
803
+ query += ` WHERE ${clause}`;
804
+ params.push(...values);
805
+ }
806
+ // ORDER BY clause
807
+ if (options.orderBy) {
808
+ const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];
809
+ const orderClauses = orderByArray.map((order) => `\`${order.column}\` ${order.order || 'ASC'}`);
810
+ query += ` ORDER BY ${orderClauses.join(', ')}`;
811
+ }
812
+ // LIMIT clause
813
+ if (options.limit) {
814
+ query += ` LIMIT ?`;
815
+ params.push(options.limit);
816
+ }
817
+ // OFFSET clause
818
+ if (options.offset) {
819
+ query += ` OFFSET ?`;
820
+ params.push(options.offset);
821
+ }
822
+ return { query, params };
823
+ }
824
+ /**
825
+ * Build WHERE clause from options
826
+ */
827
+ buildWhereClause(where) {
828
+ const values = [];
829
+ const buildCondition = (condition) => {
830
+ // Handle $and
831
+ if (condition.$and) {
832
+ const subConditions = condition.$and.map(buildCondition);
833
+ return `(${subConditions.join(' AND ')})`;
834
+ }
835
+ // Handle $or
836
+ if (condition.$or) {
837
+ const subConditions = condition.$or.map(buildCondition);
838
+ return `(${subConditions.join(' OR ')})`;
839
+ }
840
+ // Handle column conditions
841
+ const conditions = [];
842
+ for (const [key, value] of Object.entries(condition)) {
843
+ if (typeof value === 'object' && value !== null) {
844
+ // Handle operators
845
+ for (const [op, opValue] of Object.entries(value)) {
846
+ switch (op) {
847
+ case '$gt':
848
+ values.push(opValue);
849
+ conditions.push(`\`${key}\` > ?`);
850
+ break;
851
+ case '$gte':
852
+ values.push(opValue);
853
+ conditions.push(`\`${key}\` >= ?`);
854
+ break;
855
+ case '$lt':
856
+ values.push(opValue);
857
+ conditions.push(`\`${key}\` < ?`);
858
+ break;
859
+ case '$lte':
860
+ values.push(opValue);
861
+ conditions.push(`\`${key}\` <= ?`);
862
+ break;
863
+ case '$ne':
864
+ values.push(opValue);
865
+ conditions.push(`\`${key}\` != ?`);
866
+ break;
867
+ case '$in':
868
+ if (Array.isArray(opValue)) {
869
+ const placeholders = opValue.map(() => '?').join(', ');
870
+ values.push(...opValue);
871
+ conditions.push(`\`${key}\` IN (${placeholders})`);
872
+ }
873
+ break;
874
+ case '$like':
875
+ values.push(opValue);
876
+ conditions.push(`\`${key}\` LIKE ?`);
877
+ break;
878
+ }
879
+ }
880
+ }
881
+ else {
882
+ // Simple equality
883
+ values.push(value);
884
+ conditions.push(`\`${key}\` = ?`);
885
+ }
886
+ }
887
+ return conditions.join(' AND ');
888
+ };
889
+ const clause = buildCondition(where);
890
+ return { clause, values };
891
+ }
892
+ /**
893
+ * Build COUNT query
894
+ */
895
+ buildCountQuery(options) {
896
+ const params = [];
897
+ const column = options.column ? `\`${options.column}\`` : '*';
898
+ let query = `SELECT COUNT(${column}) as count FROM \`${options.table}\``;
899
+ if (options.where) {
900
+ const { clause, values } = this.buildWhereClause(options.where);
901
+ query += ` WHERE ${clause}`;
902
+ params.push(...values);
903
+ }
904
+ return { query, params };
905
+ }
906
+ /**
907
+ * Build aggregate query
908
+ */
909
+ buildAggregateQuery(fn, column, options) {
910
+ const params = [];
911
+ let query = `SELECT ${fn}(\`${column}\`) as result FROM \`${options.table}\``;
912
+ if (options.where) {
913
+ const { clause, values } = this.buildWhereClause(options.where);
914
+ query += ` WHERE ${clause}`;
915
+ params.push(...values);
916
+ }
917
+ return { query, params };
918
+ }
919
+ /**
920
+ * Build INSERT query
921
+ */
922
+ buildInsertQuery(options) {
923
+ const dataArray = Array.isArray(options.data) ? options.data : [options.data];
924
+ const columns = Object.keys(dataArray[0]);
925
+ const params = [];
926
+ let query = `INSERT INTO \`${options.table}\` (${columns.map((col) => `\`${col}\``).join(', ')}) VALUES `;
927
+ const valuesClauses = dataArray.map((data) => {
928
+ const placeholders = columns.map(() => '?');
929
+ params.push(...columns.map((col) => data[col]));
930
+ return `(${placeholders.join(', ')})`;
931
+ });
932
+ query += valuesClauses.join(', ');
933
+ return { query, params };
934
+ }
935
+ /**
936
+ * Build UPDATE query
937
+ */
938
+ buildUpdateQuery(options) {
939
+ const params = [];
940
+ const setClauses = Object.keys(options.data).map((key) => {
941
+ params.push(options.data[key]);
942
+ return `\`${key}\` = ?`;
943
+ });
944
+ let query = `UPDATE \`${options.table}\` SET ${setClauses.join(', ')}`;
945
+ if (options.where) {
946
+ const { clause, values } = this.buildWhereClause(options.where);
947
+ query += ` WHERE ${clause}`;
948
+ params.push(...values);
949
+ }
950
+ return { query, params };
951
+ }
952
+ /**
953
+ * Build DELETE query
954
+ */
955
+ buildDeleteQuery(options) {
956
+ const params = [];
957
+ let query = `DELETE FROM \`${options.table}\``;
958
+ if (options.where) {
959
+ const { clause, values } = this.buildWhereClause(options.where);
960
+ query += ` WHERE ${clause}`;
961
+ params.push(...values);
962
+ }
963
+ return { query, params };
964
+ }
965
+ /**
966
+ * Build UPSERT query (INSERT ... ON DUPLICATE KEY UPDATE)
967
+ */
968
+ buildUpsertQuery(options) {
969
+ const data = Array.isArray(options.data) ? options.data[0] : options.data;
970
+ const columns = Object.keys(data);
971
+ const params = [];
972
+ let query = `INSERT INTO \`${options.table}\` (${columns.map((col) => `\`${col}\``).join(', ')}) VALUES (`;
973
+ query += columns.map(() => '?').join(', ');
974
+ params.push(...columns.map((col) => data[col]));
975
+ query += ') ON DUPLICATE KEY UPDATE ';
976
+ const updateClauses = columns
977
+ .filter((col) => !options.uniqueColumns.includes(col))
978
+ .map((col) => `\`${col}\` = VALUES(\`${col}\`)`);
979
+ query += updateClauses.join(', ');
980
+ return { query, params };
981
+ }
982
+ /**
983
+ * Build GROUP BY query
984
+ */
985
+ buildGroupByQuery(options) {
986
+ const params = [];
987
+ const groupColumns = options.groupBy.map((col) => `\`${col}\``);
988
+ const selectColumns = [...groupColumns];
989
+ // Build aggregations
990
+ if (options.aggregate) {
991
+ Object.entries(options.aggregate).forEach(([alias, agg]) => {
992
+ selectColumns.push(`${agg.function}(\`${agg.column}\`) as \`${alias}\``);
993
+ });
994
+ }
995
+ let query = `SELECT ${selectColumns.join(', ')} FROM \`${options.table}\``;
996
+ if (options.where) {
997
+ const { clause, values } = this.buildWhereClause(options.where);
998
+ query += ` WHERE ${clause}`;
999
+ params.push(...values);
1000
+ }
1001
+ query += ` GROUP BY ${groupColumns.join(', ')}`;
1002
+ return { query, params };
1003
+ }
1004
+ /**
1005
+ * Build multi-aggregate query
1006
+ */
1007
+ buildMultiAggregateQuery(options) {
1008
+ const params = [];
1009
+ const aggregations = Object.entries(options.operations).map(([alias, agg]) => {
1010
+ return `${agg.function}(\`${agg.column}\`) as \`${alias}\``;
1011
+ });
1012
+ let query = `SELECT ${aggregations.join(', ')} FROM \`${options.table}\``;
1013
+ if (options.where) {
1014
+ const { clause, values } = this.buildWhereClause(options.where);
1015
+ query += ` WHERE ${clause}`;
1016
+ params.push(...values);
1017
+ }
1018
+ return { query, params };
1019
+ }
1020
+ /**
1021
+ * Build CREATE TABLE query
1022
+ */
1023
+ buildCreateTableQuery(schema, options) {
1024
+ const columnDefs = schema.columns.map((col) => {
1025
+ let def = `\`${col.name}\` ${this.mapColumnTypeToMySQL(col.type)}`;
1026
+ if (col.length) {
1027
+ def += `(${col.length})`;
1028
+ }
1029
+ if (col.primaryKey) {
1030
+ def += ' PRIMARY KEY';
1031
+ }
1032
+ if (col.autoIncrement) {
1033
+ def += ' AUTO_INCREMENT';
1034
+ }
1035
+ if (!col.nullable) {
1036
+ def += ' NOT NULL';
1037
+ }
1038
+ if (col.unique) {
1039
+ def += ' UNIQUE';
1040
+ }
1041
+ if (col.defaultValue !== undefined) {
1042
+ def += ` DEFAULT ${this.escapeValue(col.defaultValue)}`;
1043
+ }
1044
+ return def;
1045
+ });
1046
+ let query = `CREATE TABLE ${(options === null || options === void 0 ? void 0 : options.ifNotExists) ? 'IF NOT EXISTS ' : ''}\`${schema.name}\` (${columnDefs.join(', ')})`;
1047
+ return query;
1048
+ }
1049
+ /**
1050
+ * Build ALTER TABLE queries
1051
+ */
1052
+ buildAlterTableQueries(tableName, alterations) {
1053
+ return alterations.map((alt) => {
1054
+ let query = `ALTER TABLE \`${tableName}\` `;
1055
+ switch (alt.type) {
1056
+ case schema_types_1.ColumnAlterationType.ADD:
1057
+ query += `ADD COLUMN \`${alt.column.name}\` ${this.mapColumnTypeToMySQL(alt.column.type)}`;
1058
+ if (!alt.column.nullable) {
1059
+ query += ' NOT NULL';
1060
+ }
1061
+ break;
1062
+ case schema_types_1.ColumnAlterationType.DROP:
1063
+ query += `DROP COLUMN \`${alt.oldName}\``;
1064
+ break;
1065
+ case schema_types_1.ColumnAlterationType.MODIFY:
1066
+ query += `MODIFY COLUMN \`${alt.column.name}\` ${this.mapColumnTypeToMySQL(alt.column.type)}`;
1067
+ break;
1068
+ case schema_types_1.ColumnAlterationType.RENAME:
1069
+ query += `RENAME COLUMN \`${alt.oldName}\` TO \`${alt.newName}\``;
1070
+ break;
1071
+ }
1072
+ return query;
1073
+ });
1074
+ }
1075
+ /**
1076
+ * Build CREATE INDEX query
1077
+ */
1078
+ buildCreateIndexQuery(options) {
1079
+ const unique = options.index.unique ? 'UNIQUE ' : '';
1080
+ const columns = options.index.columns.map((col) => `\`${col.name}\``).join(', ');
1081
+ return `CREATE ${unique}INDEX \`${options.index.name}\` ON \`${options.table}\` (${columns})`;
1082
+ }
1083
+ /**
1084
+ * Map ColumnType to MySQL type
1085
+ */
1086
+ mapColumnTypeToMySQL(type) {
1087
+ const typeMap = {
1088
+ [schema_types_1.ColumnType.STRING]: 'VARCHAR',
1089
+ [schema_types_1.ColumnType.TEXT]: 'TEXT',
1090
+ [schema_types_1.ColumnType.VARCHAR]: 'VARCHAR',
1091
+ [schema_types_1.ColumnType.CHAR]: 'CHAR',
1092
+ [schema_types_1.ColumnType.INTEGER]: 'INT',
1093
+ [schema_types_1.ColumnType.BIGINT]: 'BIGINT',
1094
+ [schema_types_1.ColumnType.SMALLINT]: 'SMALLINT',
1095
+ [schema_types_1.ColumnType.DECIMAL]: 'DECIMAL',
1096
+ [schema_types_1.ColumnType.NUMERIC]: 'DECIMAL',
1097
+ [schema_types_1.ColumnType.FLOAT]: 'FLOAT',
1098
+ [schema_types_1.ColumnType.DOUBLE]: 'DOUBLE',
1099
+ [schema_types_1.ColumnType.REAL]: 'FLOAT',
1100
+ [schema_types_1.ColumnType.BOOLEAN]: 'TINYINT',
1101
+ [schema_types_1.ColumnType.DATE]: 'DATE',
1102
+ [schema_types_1.ColumnType.TIME]: 'TIME',
1103
+ [schema_types_1.ColumnType.DATETIME]: 'DATETIME',
1104
+ [schema_types_1.ColumnType.TIMESTAMP]: 'TIMESTAMP',
1105
+ [schema_types_1.ColumnType.JSON]: 'JSON',
1106
+ [schema_types_1.ColumnType.JSONB]: 'JSON',
1107
+ [schema_types_1.ColumnType.UUID]: 'CHAR(36)',
1108
+ [schema_types_1.ColumnType.BLOB]: 'BLOB',
1109
+ [schema_types_1.ColumnType.BINARY]: 'BINARY',
1110
+ [schema_types_1.ColumnType.ARRAY]: 'JSON',
1111
+ [schema_types_1.ColumnType.OBJECT]: 'JSON',
1112
+ [schema_types_1.ColumnType.ENUM]: 'VARCHAR',
1113
+ };
1114
+ return typeMap[type] || 'TEXT';
1115
+ }
1116
+ /**
1117
+ * Map MySQL type to ColumnType
1118
+ */
1119
+ mapMySQLTypeToColumnType(mysqlType) {
1120
+ const typeMap = {
1121
+ varchar: schema_types_1.ColumnType.VARCHAR,
1122
+ text: schema_types_1.ColumnType.TEXT,
1123
+ char: schema_types_1.ColumnType.CHAR,
1124
+ int: schema_types_1.ColumnType.INTEGER,
1125
+ bigint: schema_types_1.ColumnType.BIGINT,
1126
+ smallint: schema_types_1.ColumnType.SMALLINT,
1127
+ decimal: schema_types_1.ColumnType.DECIMAL,
1128
+ float: schema_types_1.ColumnType.FLOAT,
1129
+ double: schema_types_1.ColumnType.DOUBLE,
1130
+ tinyint: schema_types_1.ColumnType.BOOLEAN,
1131
+ date: schema_types_1.ColumnType.DATE,
1132
+ time: schema_types_1.ColumnType.TIME,
1133
+ datetime: schema_types_1.ColumnType.DATETIME,
1134
+ timestamp: schema_types_1.ColumnType.TIMESTAMP,
1135
+ json: schema_types_1.ColumnType.JSON,
1136
+ blob: schema_types_1.ColumnType.BLOB,
1137
+ binary: schema_types_1.ColumnType.BINARY,
1138
+ };
1139
+ return typeMap[mysqlType.toLowerCase()] || schema_types_1.ColumnType.TEXT;
1140
+ }
1141
+ /**
1142
+ * Ensure migration table exists
1143
+ */
1144
+ async ensureMigrationTable(conn) {
1145
+ const query = `
1146
+ CREATE TABLE IF NOT EXISTS _ductape_migrations (
1147
+ tag VARCHAR(255) PRIMARY KEY,
1148
+ name VARCHAR(255) NOT NULL,
1149
+ executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
1150
+ )
1151
+ `;
1152
+ await conn.query(query);
1153
+ }
1154
+ /**
1155
+ * Record migration execution
1156
+ */
1157
+ async recordMigration(conn, migration, direction) {
1158
+ await this.ensureMigrationTable(conn);
1159
+ const query = `
1160
+ INSERT INTO _ductape_migrations (tag, name, executed_at)
1161
+ VALUES (?, ?, CURRENT_TIMESTAMP)
1162
+ ON DUPLICATE KEY UPDATE executed_at = CURRENT_TIMESTAMP
1163
+ `;
1164
+ await conn.query(query, [migration.tag, migration.name]);
1165
+ }
1166
+ /**
1167
+ * Remove migration from history
1168
+ */
1169
+ async removeMigration(conn, tag) {
1170
+ await this.ensureMigrationTable(conn);
1171
+ const query = `DELETE FROM _ductape_migrations WHERE tag = ?`;
1172
+ await conn.query(query, [tag]);
1173
+ }
1174
+ // ==================== Utility Methods ====================
1175
+ /**
1176
+ * Escape identifier (table/column name)
1177
+ */
1178
+ escapeIdentifier(identifier) {
1179
+ return `\`${identifier.replace(/`/g, '``')}\``;
1180
+ }
1181
+ /**
1182
+ * Escape value for SQL
1183
+ */
1184
+ escapeValue(value) {
1185
+ if (value === null || value === undefined) {
1186
+ return 'NULL';
1187
+ }
1188
+ if (typeof value === 'string') {
1189
+ return `'${value.replace(/'/g, "''")}'`;
1190
+ }
1191
+ if (typeof value === 'boolean') {
1192
+ return value ? '1' : '0';
1193
+ }
1194
+ if (value instanceof Date) {
1195
+ return `'${value.toISOString().slice(0, 19).replace('T', ' ')}'`;
1196
+ }
1197
+ if (Array.isArray(value)) {
1198
+ return `'${JSON.stringify(value)}'`;
1199
+ }
1200
+ if (typeof value === 'object') {
1201
+ return `'${JSON.stringify(value)}'`;
1202
+ }
1203
+ return String(value);
1204
+ }
1205
+ /**
1206
+ * Get database version
1207
+ */
1208
+ async getDatabaseVersion(connection) {
1209
+ var _a;
1210
+ try {
1211
+ const conn = connection.getClient();
1212
+ const [rows] = await conn.query('SELECT VERSION() as version');
1213
+ return ((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.version) || 'Unknown';
1214
+ }
1215
+ catch (error) {
1216
+ return 'Unknown';
1217
+ }
1218
+ }
1219
+ }
1220
+ exports.MySQLAdapter = MySQLAdapter;
1221
+ //# sourceMappingURL=mysql.adapter.js.map