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