@ductape/sdk 0.0.4-v42 → 0.0.4-v44

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 (85) hide show
  1. package/dist/apps/services/app.service.d.ts +10 -0
  2. package/dist/apps/services/app.service.js +38 -69
  3. package/dist/apps/services/app.service.js.map +1 -1
  4. package/dist/apps/validators/joi-validators/create.appWebhook.validator.d.ts +1 -2
  5. package/dist/apps/validators/joi-validators/create.appWebhook.validator.js +2 -15
  6. package/dist/apps/validators/joi-validators/create.appWebhook.validator.js.map +1 -1
  7. package/dist/apps/validators/joi-validators/update.appWebhook.validator.d.ts +1 -2
  8. package/dist/apps/validators/joi-validators/update.appWebhook.validator.js +2 -14
  9. package/dist/apps/validators/joi-validators/update.appWebhook.validator.js.map +1 -1
  10. package/dist/database/adapters/base.adapter.d.ts +176 -0
  11. package/dist/database/adapters/base.adapter.js +31 -0
  12. package/dist/database/adapters/base.adapter.js.map +1 -0
  13. package/dist/database/adapters/dynamodb.adapter.d.ts +91 -0
  14. package/dist/database/adapters/dynamodb.adapter.js +1469 -0
  15. package/dist/database/adapters/dynamodb.adapter.js.map +1 -0
  16. package/dist/database/adapters/mongodb.adapter.d.ts +71 -0
  17. package/dist/database/adapters/mongodb.adapter.js +882 -0
  18. package/dist/database/adapters/mongodb.adapter.js.map +1 -0
  19. package/dist/database/adapters/mysql.adapter.d.ts +146 -0
  20. package/dist/database/adapters/mysql.adapter.js +1417 -0
  21. package/dist/database/adapters/mysql.adapter.js.map +1 -0
  22. package/dist/database/adapters/postgresql.adapter.d.ts +147 -0
  23. package/dist/database/adapters/postgresql.adapter.js +1472 -0
  24. package/dist/database/adapters/postgresql.adapter.js.map +1 -0
  25. package/dist/database/database.service.d.ts +195 -0
  26. package/dist/database/database.service.js +502 -0
  27. package/dist/database/database.service.js.map +1 -0
  28. package/dist/database/index.d.ts +18 -0
  29. package/dist/database/index.js +98 -0
  30. package/dist/database/index.js.map +1 -0
  31. package/dist/database/types/aggregation.types.d.ts +202 -0
  32. package/dist/database/types/aggregation.types.js +21 -0
  33. package/dist/database/types/aggregation.types.js.map +1 -0
  34. package/dist/database/types/connection.types.d.ts +132 -0
  35. package/dist/database/types/connection.types.js +6 -0
  36. package/dist/database/types/connection.types.js.map +1 -0
  37. package/dist/database/types/database.types.d.ts +174 -0
  38. package/dist/database/types/database.types.js +74 -0
  39. package/dist/database/types/database.types.js.map +1 -0
  40. package/dist/database/types/index.d.ts +12 -0
  41. package/dist/database/types/index.js +37 -0
  42. package/dist/database/types/index.js.map +1 -0
  43. package/dist/database/types/index.types.d.ts +220 -0
  44. package/dist/database/types/index.types.js +27 -0
  45. package/dist/database/types/index.types.js.map +1 -0
  46. package/dist/database/types/migration.types.d.ts +205 -0
  47. package/dist/database/types/migration.types.js +44 -0
  48. package/dist/database/types/migration.types.js.map +1 -0
  49. package/dist/database/types/query.types.d.ts +305 -0
  50. package/dist/database/types/query.types.js +57 -0
  51. package/dist/database/types/query.types.js.map +1 -0
  52. package/dist/database/types/result.types.d.ts +218 -0
  53. package/dist/database/types/result.types.js +6 -0
  54. package/dist/database/types/result.types.js.map +1 -0
  55. package/dist/database/types/schema.types.d.ts +190 -0
  56. package/dist/database/types/schema.types.js +69 -0
  57. package/dist/database/types/schema.types.js.map +1 -0
  58. package/dist/database/utils/helpers.d.ts +66 -0
  59. package/dist/database/utils/helpers.js +501 -0
  60. package/dist/database/utils/helpers.js.map +1 -0
  61. package/dist/database/utils/migration.utils.d.ts +151 -0
  62. package/dist/database/utils/migration.utils.js +476 -0
  63. package/dist/database/utils/migration.utils.js.map +1 -0
  64. package/dist/database/utils/transaction.d.ts +64 -0
  65. package/dist/database/utils/transaction.js +130 -0
  66. package/dist/database/utils/transaction.js.map +1 -0
  67. package/dist/database/validators/connection.validator.d.ts +20 -0
  68. package/dist/database/validators/connection.validator.js +267 -0
  69. package/dist/database/validators/connection.validator.js.map +1 -0
  70. package/dist/database/validators/query.validator.d.ts +31 -0
  71. package/dist/database/validators/query.validator.js +305 -0
  72. package/dist/database/validators/query.validator.js.map +1 -0
  73. package/dist/database/validators/schema.validator.d.ts +31 -0
  74. package/dist/database/validators/schema.validator.js +334 -0
  75. package/dist/database/validators/schema.validator.js.map +1 -0
  76. package/dist/index.d.ts +194 -146
  77. package/dist/index.js +232 -173
  78. package/dist/index.js.map +1 -1
  79. package/dist/processor/services/processor.service.js +61 -43
  80. package/dist/processor/services/processor.service.js.map +1 -1
  81. package/dist/test/test.processor.js +1 -3
  82. package/dist/test/test.processor.js.map +1 -1
  83. package/dist/types/appBuilder.types.d.ts +1 -1
  84. package/dist/types/processor.types.d.ts +2 -2
  85. package/package.json +3 -1
@@ -0,0 +1,882 @@
1
+ "use strict";
2
+ /**
3
+ * MongoDB Database Adapter
4
+ * Implements database operations for MongoDB
5
+ */
6
+ var __rest = (this && this.__rest) || function (s, e) {
7
+ var t = {};
8
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
9
+ t[p] = s[p];
10
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
11
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
12
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
13
+ t[p[i]] = s[p[i]];
14
+ }
15
+ return t;
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.MongoDBAdapter = void 0;
19
+ const base_adapter_1 = require("./base.adapter");
20
+ const database_types_1 = require("../types/database.types");
21
+ const query_types_1 = require("../types/query.types");
22
+ /**
23
+ * MongoDB Connection wrapper
24
+ */
25
+ class MongoDBConnection {
26
+ constructor(id, client, db) {
27
+ this.id = id;
28
+ this.type = database_types_1.DatabaseType.MONGODB;
29
+ this.status = database_types_1.ConnectionStatus.CONNECTED;
30
+ this.client = client;
31
+ this.db = db;
32
+ }
33
+ async connect() {
34
+ var _a;
35
+ if (this.client && !((_a = this.client.topology) === null || _a === void 0 ? void 0 : _a.isConnected())) {
36
+ await this.client.connect();
37
+ this.status = database_types_1.ConnectionStatus.CONNECTED;
38
+ }
39
+ }
40
+ async disconnect() {
41
+ if (this.client) {
42
+ await this.client.close();
43
+ this.status = database_types_1.ConnectionStatus.DISCONNECTED;
44
+ }
45
+ }
46
+ isConnected() {
47
+ var _a, _b;
48
+ return this.status === database_types_1.ConnectionStatus.CONNECTED && ((_b = (_a = this.client) === null || _a === void 0 ? void 0 : _a.topology) === null || _b === void 0 ? void 0 : _b.isConnected());
49
+ }
50
+ getClient() {
51
+ return this.db;
52
+ }
53
+ }
54
+ /**
55
+ * MongoDB Adapter
56
+ */
57
+ class MongoDBAdapter extends base_adapter_1.BaseDatabaseAdapter {
58
+ constructor() {
59
+ super(...arguments);
60
+ this.type = database_types_1.DatabaseType.MONGODB;
61
+ this.connectionPool = new Map();
62
+ }
63
+ // ==================== Connection Methods ====================
64
+ async connect(config) {
65
+ try {
66
+ // TODO: Import mongodb library dynamically
67
+ // const { MongoClient } = await import('mongodb');
68
+ // TODO: Create connection URI
69
+ // const uri = config.connectionString ||
70
+ // `mongodb://${config.user}:${config.password}@${config.host}:${config.port || 27017}`;
71
+ // TODO: Create MongoDB client
72
+ // const client = new MongoClient(uri, {
73
+ // ...config.options,
74
+ // });
75
+ // TODO: Connect to MongoDB
76
+ // await client.connect();
77
+ // TODO: Get database
78
+ // const db = client.db(config.database);
79
+ // TODO: Create connection wrapper
80
+ // const connectionId = `mongodb-${config.database}-${Date.now()}`;
81
+ // const connection = new MongoDBConnection(connectionId, client, db);
82
+ // return connection;
83
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.CONNECTION_ERROR, 'MongoDB adapter not fully implemented yet');
84
+ }
85
+ catch (error) {
86
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.CONNECTION_ERROR, `Failed to connect to MongoDB: ${error.message}`, error);
87
+ }
88
+ }
89
+ async disconnect(connection) {
90
+ await connection.disconnect();
91
+ this.connectionPool.delete(connection.id);
92
+ }
93
+ async testConnection(connection) {
94
+ const startTime = Date.now();
95
+ try {
96
+ const db = connection.getClient();
97
+ // Test with a simple ping command
98
+ await db.admin().ping();
99
+ const responseTime = Date.now() - startTime;
100
+ return {
101
+ connected: true,
102
+ message: 'Successfully connected to MongoDB',
103
+ databaseType: 'mongodb',
104
+ responseTime,
105
+ };
106
+ }
107
+ catch (error) {
108
+ return {
109
+ connected: false,
110
+ message: 'Failed to connect to MongoDB',
111
+ databaseType: 'mongodb',
112
+ responseTime: Date.now() - startTime,
113
+ error: error.message,
114
+ };
115
+ }
116
+ }
117
+ // ==================== Transaction Methods ====================
118
+ async beginTransaction(connection) {
119
+ const client = connection.getClient();
120
+ const session = client.startSession();
121
+ session.startTransaction();
122
+ return session;
123
+ }
124
+ async commitTransaction(connection, transaction) {
125
+ await transaction.commitTransaction();
126
+ await transaction.endSession();
127
+ }
128
+ async rollbackTransaction(connection, transaction) {
129
+ await transaction.abortTransaction();
130
+ await transaction.endSession();
131
+ }
132
+ async createSavepoint(connection, transaction, savepointName) {
133
+ // MongoDB doesn't support savepoints in the same way as SQL databases
134
+ // We can simulate this by tracking state, but for now, this is a placeholder
135
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, 'MongoDB does not support savepoints');
136
+ }
137
+ async rollbackToSavepoint(connection, transaction, savepointName) {
138
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, 'MongoDB does not support savepoints');
139
+ }
140
+ async releaseSavepoint(connection, transaction, savepointName) {
141
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, 'MongoDB does not support savepoints');
142
+ }
143
+ // ==================== Query Methods ====================
144
+ async query(connection, options) {
145
+ const startTime = Date.now();
146
+ try {
147
+ const db = connection.getClient();
148
+ const collection = db.collection(options.table);
149
+ // Build MongoDB filter from where clause
150
+ const filter = this.buildMongoFilter(options.where);
151
+ // Build MongoDB query
152
+ let query = collection.find(filter);
153
+ // Apply projection (select)
154
+ if (options.select && options.select.length > 0) {
155
+ const projection = {};
156
+ options.select.forEach((field) => {
157
+ projection[field] = 1;
158
+ });
159
+ query = query.project(projection);
160
+ }
161
+ // Apply sorting
162
+ if (options.orderBy) {
163
+ const sort = {};
164
+ const orderByArray = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];
165
+ orderByArray.forEach((order) => {
166
+ sort[order.column] = order.order === query_types_1.SortOrder.DESC ? -1 : 1;
167
+ });
168
+ query = query.sort(sort);
169
+ }
170
+ // Apply limit and offset
171
+ if (options.limit) {
172
+ query = query.limit(options.limit);
173
+ }
174
+ if (options.offset) {
175
+ query = query.skip(options.offset);
176
+ }
177
+ const data = await query.toArray();
178
+ const executionTime = Date.now() - startTime;
179
+ return {
180
+ data,
181
+ count: data.length,
182
+ executionTime,
183
+ databaseType: 'mongodb',
184
+ };
185
+ }
186
+ catch (error) {
187
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB query failed: ${error.message}`, error);
188
+ }
189
+ }
190
+ async insert(connection, options) {
191
+ const startTime = Date.now();
192
+ try {
193
+ const db = connection.getClient();
194
+ const collection = db.collection(options.table);
195
+ const dataArray = Array.isArray(options.data) ? options.data : [options.data];
196
+ const result = await collection.insertMany(dataArray);
197
+ const executionTime = Date.now() - startTime;
198
+ return {
199
+ insertedCount: result.insertedCount,
200
+ insertedIds: Object.values(result.insertedIds).map((id) => id.toString()),
201
+ data: options.returning ? dataArray : undefined,
202
+ executionTime,
203
+ success: true,
204
+ };
205
+ }
206
+ catch (error) {
207
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB insert failed: ${error.message}`, error);
208
+ }
209
+ }
210
+ async update(connection, options) {
211
+ const startTime = Date.now();
212
+ try {
213
+ const db = connection.getClient();
214
+ const collection = db.collection(options.table);
215
+ const filter = this.buildMongoFilter(options.where);
216
+ const update = { $set: options.data };
217
+ const result = await collection.updateMany(filter, update);
218
+ const executionTime = Date.now() - startTime;
219
+ return {
220
+ updatedCount: result.modifiedCount,
221
+ matchedCount: result.matchedCount,
222
+ executionTime,
223
+ success: true,
224
+ };
225
+ }
226
+ catch (error) {
227
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB update failed: ${error.message}`, error);
228
+ }
229
+ }
230
+ async delete(connection, options) {
231
+ const startTime = Date.now();
232
+ try {
233
+ const db = connection.getClient();
234
+ const collection = db.collection(options.table);
235
+ const filter = this.buildMongoFilter(options.where);
236
+ const result = await collection.deleteMany(filter);
237
+ const executionTime = Date.now() - startTime;
238
+ return {
239
+ deletedCount: result.deletedCount,
240
+ executionTime,
241
+ success: true,
242
+ };
243
+ }
244
+ catch (error) {
245
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB delete failed: ${error.message}`, error);
246
+ }
247
+ }
248
+ async upsert(connection, options) {
249
+ const startTime = Date.now();
250
+ try {
251
+ const db = connection.getClient();
252
+ const collection = db.collection(options.table);
253
+ // Upsert only works with single records
254
+ const data = Array.isArray(options.data) ? options.data[0] : options.data;
255
+ // Build conflict filter
256
+ const filter = {};
257
+ options.uniqueColumns.forEach((col) => {
258
+ if (data[col] !== undefined) {
259
+ filter[col] = data[col];
260
+ }
261
+ });
262
+ const update = { $set: data };
263
+ const result = await collection.updateOne(filter, update, { upsert: true });
264
+ const executionTime = Date.now() - startTime;
265
+ return {
266
+ insertedCount: result.upsertedCount || 0,
267
+ updatedCount: result.modifiedCount,
268
+ affectedCount: result.upsertedCount + result.modifiedCount,
269
+ executionTime,
270
+ success: true,
271
+ };
272
+ }
273
+ catch (error) {
274
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB upsert failed: ${error.message}`, error);
275
+ }
276
+ }
277
+ async executeRaw(connection, options) {
278
+ const startTime = Date.now();
279
+ try {
280
+ const db = connection.getClient();
281
+ // For MongoDB, raw queries might be aggregation pipelines or commands
282
+ // This is a simplified implementation
283
+ const result = await db.command(options.query);
284
+ const executionTime = Date.now() - startTime;
285
+ return {
286
+ rows: Array.isArray(result) ? result : [result],
287
+ rowCount: Array.isArray(result) ? result.length : 1,
288
+ executionTime,
289
+ };
290
+ }
291
+ catch (error) {
292
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB raw query failed: ${error.message}`, error);
293
+ }
294
+ }
295
+ // ==================== Aggregation Methods ====================
296
+ async count(connection, options) {
297
+ try {
298
+ const db = connection.getClient();
299
+ const collection = db.collection(options.table);
300
+ const filter = this.buildMongoFilter(options.where);
301
+ return await collection.countDocuments(filter);
302
+ }
303
+ catch (error) {
304
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB count failed: ${error.message}`, error);
305
+ }
306
+ }
307
+ async sum(connection, options) {
308
+ var _a;
309
+ try {
310
+ const db = connection.getClient();
311
+ const collection = db.collection(options.table);
312
+ const matchStage = this.buildMongoFilter(options.where);
313
+ const pipeline = [
314
+ { $match: matchStage },
315
+ {
316
+ $group: {
317
+ _id: null,
318
+ total: { $sum: `$${options.column}` },
319
+ },
320
+ },
321
+ ];
322
+ const result = await collection.aggregate(pipeline).toArray();
323
+ return ((_a = result[0]) === null || _a === void 0 ? void 0 : _a.total) || 0;
324
+ }
325
+ catch (error) {
326
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB sum failed: ${error.message}`, error);
327
+ }
328
+ }
329
+ async avg(connection, options) {
330
+ var _a;
331
+ try {
332
+ const db = connection.getClient();
333
+ const collection = db.collection(options.table);
334
+ const matchStage = this.buildMongoFilter(options.where);
335
+ const pipeline = [
336
+ { $match: matchStage },
337
+ {
338
+ $group: {
339
+ _id: null,
340
+ average: { $avg: `$${options.column}` },
341
+ },
342
+ },
343
+ ];
344
+ const result = await collection.aggregate(pipeline).toArray();
345
+ return ((_a = result[0]) === null || _a === void 0 ? void 0 : _a.average) || 0;
346
+ }
347
+ catch (error) {
348
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB avg failed: ${error.message}`, error);
349
+ }
350
+ }
351
+ async min(connection, options) {
352
+ var _a;
353
+ try {
354
+ const db = connection.getClient();
355
+ const collection = db.collection(options.table);
356
+ const matchStage = this.buildMongoFilter(options.where);
357
+ const pipeline = [
358
+ { $match: matchStage },
359
+ {
360
+ $group: {
361
+ _id: null,
362
+ minimum: { $min: `$${options.column}` },
363
+ },
364
+ },
365
+ ];
366
+ const result = await collection.aggregate(pipeline).toArray();
367
+ return ((_a = result[0]) === null || _a === void 0 ? void 0 : _a.minimum) || 0;
368
+ }
369
+ catch (error) {
370
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB min failed: ${error.message}`, error);
371
+ }
372
+ }
373
+ async max(connection, options) {
374
+ var _a;
375
+ try {
376
+ const db = connection.getClient();
377
+ const collection = db.collection(options.table);
378
+ const matchStage = this.buildMongoFilter(options.where);
379
+ const pipeline = [
380
+ { $match: matchStage },
381
+ {
382
+ $group: {
383
+ _id: null,
384
+ maximum: { $max: `$${options.column}` },
385
+ },
386
+ },
387
+ ];
388
+ const result = await collection.aggregate(pipeline).toArray();
389
+ return ((_a = result[0]) === null || _a === void 0 ? void 0 : _a.maximum) || 0;
390
+ }
391
+ catch (error) {
392
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB max failed: ${error.message}`, error);
393
+ }
394
+ }
395
+ async groupBy(connection, options) {
396
+ try {
397
+ const db = connection.getClient();
398
+ const collection = db.collection(options.table);
399
+ const matchStage = this.buildMongoFilter(options.where);
400
+ // Build group ID from columns
401
+ const groupId = {};
402
+ options.groupBy.forEach((col) => {
403
+ groupId[col] = `$${col}`;
404
+ });
405
+ // Build aggregations
406
+ const aggregations = {};
407
+ if (options.aggregate) {
408
+ Object.entries(options.aggregate).forEach(([key, agg]) => {
409
+ // Support both old format { function: 'avg', column: 'price' }
410
+ // and new simplified format { $AVG: 'price' }
411
+ if (agg.function && agg.column) {
412
+ aggregations[key] = { [`$${agg.function.toLowerCase()}`]: `$${agg.column}` };
413
+ }
414
+ else {
415
+ // Check for $-prefixed aggregation functions
416
+ const aggObj = agg;
417
+ const aggFunctions = ['$COUNT', '$AVG', '$SUM', '$MIN', '$MAX', 'COUNT', 'AVG', 'SUM', 'MIN', 'MAX'];
418
+ for (const func of aggFunctions) {
419
+ if (aggObj[func] !== undefined) {
420
+ const funcName = func.replace('$', '').toLowerCase();
421
+ const column = aggObj[func];
422
+ aggregations[key] = { [`$${funcName}`]: column === '*' ? 1 : `$${column}` };
423
+ break;
424
+ }
425
+ }
426
+ }
427
+ });
428
+ }
429
+ const pipeline = [
430
+ { $match: matchStage },
431
+ {
432
+ $group: Object.assign({ _id: groupId }, aggregations),
433
+ },
434
+ ];
435
+ const result = await collection.aggregate(pipeline).toArray();
436
+ // Transform result to expected format
437
+ return result.map((doc) => (Object.assign(Object.assign(Object.assign({}, doc._id), doc), { _id: undefined })));
438
+ }
439
+ catch (error) {
440
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB groupBy failed: ${error.message}`, error);
441
+ }
442
+ }
443
+ async aggregate(connection, options) {
444
+ try {
445
+ const db = connection.getClient();
446
+ const collection = db.collection(options.table);
447
+ const matchStage = this.buildMongoFilter(options.where);
448
+ // Build aggregations
449
+ const aggregations = {};
450
+ Object.entries(options.operations).forEach(([key, agg]) => {
451
+ // Support both old format { function: 'avg', column: 'price' }
452
+ // and new simplified format { $AVG: 'price' }
453
+ if (agg.function && agg.column) {
454
+ aggregations[key] = { [`$${agg.function.toLowerCase()}`]: `$${agg.column}` };
455
+ }
456
+ else {
457
+ // Check for $-prefixed aggregation functions
458
+ const aggObj = agg;
459
+ const aggFunctions = ['$COUNT', '$AVG', '$SUM', '$MIN', '$MAX', 'COUNT', 'AVG', 'SUM', 'MIN', 'MAX'];
460
+ for (const func of aggFunctions) {
461
+ if (aggObj[func] !== undefined) {
462
+ const funcName = func.replace('$', '').toLowerCase();
463
+ const column = aggObj[func];
464
+ aggregations[key] = { [`$${funcName}`]: column === '*' ? 1 : `$${column}` };
465
+ break;
466
+ }
467
+ }
468
+ }
469
+ });
470
+ const pipeline = [
471
+ { $match: matchStage },
472
+ {
473
+ $group: Object.assign({ _id: null }, aggregations),
474
+ },
475
+ ];
476
+ const result = await collection.aggregate(pipeline).toArray();
477
+ const _a = result[0] || {}, { _id } = _a, aggregateResult = __rest(_a, ["_id"]);
478
+ return aggregateResult;
479
+ }
480
+ catch (error) {
481
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `MongoDB aggregate failed: ${error.message}`, error);
482
+ }
483
+ }
484
+ // ==================== Schema Methods ====================
485
+ async createTable(connection, schema, options) {
486
+ const startTime = Date.now();
487
+ try {
488
+ const db = connection.getClient();
489
+ // MongoDB creates collections automatically, but we can create it explicitly
490
+ await db.createCollection(schema.name);
491
+ // Create indexes if specified
492
+ if (schema.indexes && schema.indexes.length > 0) {
493
+ const collection = db.collection(schema.name);
494
+ for (const index of schema.indexes) {
495
+ const indexSpec = {};
496
+ index.columns.forEach((col) => {
497
+ indexSpec[col.name] = col.order === 'DESC' ? -1 : 1;
498
+ });
499
+ await collection.createIndex(indexSpec, { unique: index.unique });
500
+ }
501
+ }
502
+ const executionTime = Date.now() - startTime;
503
+ return {
504
+ success: true,
505
+ operation: 'create',
506
+ table: schema.name,
507
+ executionTime,
508
+ };
509
+ }
510
+ catch (error) {
511
+ return {
512
+ success: false,
513
+ operation: 'create',
514
+ table: schema.name,
515
+ error: error.message,
516
+ executionTime: Date.now() - startTime,
517
+ };
518
+ }
519
+ }
520
+ async dropTable(connection, tableName) {
521
+ const startTime = Date.now();
522
+ try {
523
+ const db = connection.getClient();
524
+ await db.dropCollection(tableName);
525
+ return {
526
+ success: true,
527
+ operation: 'drop',
528
+ table: tableName,
529
+ executionTime: Date.now() - startTime,
530
+ };
531
+ }
532
+ catch (error) {
533
+ return {
534
+ success: false,
535
+ operation: 'drop',
536
+ table: tableName,
537
+ error: error.message,
538
+ executionTime: Date.now() - startTime,
539
+ };
540
+ }
541
+ }
542
+ async alterTable(connection, tableName, alterations, options) {
543
+ // MongoDB doesn't have a schema alteration concept like SQL databases
544
+ // Schema changes happen implicitly when documents are inserted
545
+ return {
546
+ success: true,
547
+ operation: 'alter',
548
+ table: tableName,
549
+ executionTime: 0,
550
+ };
551
+ }
552
+ async getTableSchema(connection, tableName) {
553
+ try {
554
+ const db = connection.getClient();
555
+ const collection = db.collection(tableName);
556
+ // Get a sample document to infer schema
557
+ const sampleDoc = await collection.findOne({});
558
+ // TODO: Infer column definitions from sample document
559
+ // This is a simplified implementation
560
+ const columns = sampleDoc
561
+ ? Object.keys(sampleDoc).map((key) => ({
562
+ name: key,
563
+ type: typeof sampleDoc[key],
564
+ }))
565
+ : [];
566
+ return {
567
+ name: tableName,
568
+ columns,
569
+ };
570
+ }
571
+ catch (error) {
572
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.SCHEMA_ERROR, `Failed to get MongoDB collection schema: ${error.message}`, error);
573
+ }
574
+ }
575
+ async listTables(connection) {
576
+ try {
577
+ const db = connection.getClient();
578
+ const collections = await db.listCollections().toArray();
579
+ return collections.map((col) => col.name);
580
+ }
581
+ catch (error) {
582
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.QUERY_ERROR, `Failed to list MongoDB collections: ${error.message}`, error);
583
+ }
584
+ }
585
+ async tableExists(connection, tableName) {
586
+ try {
587
+ const tables = await this.listTables(connection);
588
+ return tables.includes(tableName);
589
+ }
590
+ catch (error) {
591
+ return false;
592
+ }
593
+ }
594
+ // ==================== Index Methods ====================
595
+ async createIndex(connection, options) {
596
+ const startTime = Date.now();
597
+ try {
598
+ const db = connection.getClient();
599
+ const collection = db.collection(options.table);
600
+ const indexSpec = {};
601
+ options.index.columns.forEach((col) => {
602
+ indexSpec[col.name] = col.order === 'DESC' ? -1 : 1;
603
+ });
604
+ await collection.createIndex(indexSpec, {
605
+ name: options.index.name,
606
+ unique: options.index.unique,
607
+ });
608
+ return {
609
+ success: true,
610
+ operation: 'create',
611
+ indexName: options.index.name,
612
+ table: options.table,
613
+ executionTime: Date.now() - startTime,
614
+ };
615
+ }
616
+ catch (error) {
617
+ return {
618
+ success: false,
619
+ operation: 'create',
620
+ indexName: options.index.name,
621
+ table: options.table,
622
+ error: error.message,
623
+ executionTime: Date.now() - startTime,
624
+ };
625
+ }
626
+ }
627
+ async dropIndex(connection, options) {
628
+ const startTime = Date.now();
629
+ try {
630
+ const db = connection.getClient();
631
+ const collection = db.collection(options.table);
632
+ await collection.dropIndex(options.indexName);
633
+ return {
634
+ success: true,
635
+ operation: 'drop',
636
+ indexName: options.indexName,
637
+ table: options.table,
638
+ executionTime: Date.now() - startTime,
639
+ };
640
+ }
641
+ catch (error) {
642
+ return {
643
+ success: false,
644
+ operation: 'drop',
645
+ indexName: options.indexName,
646
+ table: options.table,
647
+ error: error.message,
648
+ executionTime: Date.now() - startTime,
649
+ };
650
+ }
651
+ }
652
+ async listIndexes(connection, options) {
653
+ try {
654
+ const db = connection.getClient();
655
+ const collection = db.collection(options.table);
656
+ const indexes = await collection.listIndexes().toArray();
657
+ return indexes.map((index) => ({
658
+ name: index.name,
659
+ table: options.table,
660
+ columns: Object.keys(index.key),
661
+ unique: index.unique || false,
662
+ type: index.type || 'BTREE',
663
+ }));
664
+ }
665
+ catch (error) {
666
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.INDEX_ERROR, `Failed to list MongoDB indexes: ${error.message}`, error);
667
+ }
668
+ }
669
+ async getIndexStatistics(connection, tableName, indexName) {
670
+ try {
671
+ const db = connection.getClient();
672
+ const collection = db.collection(tableName);
673
+ const stats = await collection.stats();
674
+ // TODO: Parse and return index statistics
675
+ // This is a simplified implementation
676
+ return [];
677
+ }
678
+ catch (error) {
679
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.INDEX_ERROR, `Failed to get MongoDB index statistics: ${error.message}`, error);
680
+ }
681
+ }
682
+ // ==================== Migration Methods ====================
683
+ async runMigration(connection, migration, options) {
684
+ // TODO: Implement migration logic
685
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.MIGRATION_ERROR, 'MongoDB migration not implemented yet');
686
+ }
687
+ async rollbackMigration(connection, migration, options) {
688
+ // TODO: Implement rollback logic
689
+ throw new database_types_1.DatabaseError(database_types_1.DatabaseErrorType.MIGRATION_ERROR, 'MongoDB migration rollback not implemented yet');
690
+ }
691
+ async getMigrationHistory(connection, options) {
692
+ // TODO: Implement migration history
693
+ return [];
694
+ }
695
+ // ==================== Helper Methods ====================
696
+ /**
697
+ * Build MongoDB filter from where clause
698
+ * Supports both simplified syntax (GT, LT, AND, OR, etc.) and legacy $ prefix operators
699
+ */
700
+ buildMongoFilter(where) {
701
+ if (!where) {
702
+ return {};
703
+ }
704
+ if (typeof where !== 'object' || where === null) {
705
+ return where;
706
+ }
707
+ const buildCondition = (condition) => {
708
+ if (typeof condition !== 'object' || condition === null) {
709
+ return condition;
710
+ }
711
+ // Handle logical operators (supports $AND, AND, and legacy $and)
712
+ if (condition.$AND || condition.AND || condition.$and) {
713
+ const andConditions = condition.$AND || condition.AND || condition.$and;
714
+ if (typeof andConditions === 'object' && !Array.isArray(andConditions)) {
715
+ // New syntax: { $AND: { col1: val1, col2: val2 } }
716
+ return buildCondition(andConditions);
717
+ }
718
+ else {
719
+ // Array syntax: { $AND: [cond1, cond2] }
720
+ return { $and: andConditions.map(buildCondition) };
721
+ }
722
+ }
723
+ if (condition.$OR || condition.OR || condition.$or) {
724
+ const orConditions = condition.$OR || condition.OR || condition.$or;
725
+ if (typeof orConditions === 'object' && !Array.isArray(orConditions)) {
726
+ // New syntax: { $OR: { col1: val1, col2: val2 } }
727
+ const subConditions = [];
728
+ for (const [key, value] of Object.entries(orConditions)) {
729
+ if (key === '$AND' || key === 'AND' || key === '$and' || key === '$OR' || key === 'OR' || key === '$or') {
730
+ subConditions.push(buildCondition({ [key]: value }));
731
+ }
732
+ else {
733
+ subConditions.push(buildCondition({ [key]: value }));
734
+ }
735
+ }
736
+ return { $or: subConditions };
737
+ }
738
+ else {
739
+ // Array syntax: { $OR: [cond1, cond2] }
740
+ return { $or: orConditions.map(buildCondition) };
741
+ }
742
+ }
743
+ // Handle column conditions
744
+ const filter = {};
745
+ for (const [key, value] of Object.entries(condition)) {
746
+ // Skip logical operators at this level
747
+ if (key === '$AND' || key === 'AND' || key === '$and' || key === '$OR' || key === 'OR' || key === '$or') {
748
+ continue;
749
+ }
750
+ if (typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)) {
751
+ // Handle comparison operators
752
+ const operators = {};
753
+ for (const [op, opValue] of Object.entries(value)) {
754
+ switch (op) {
755
+ // Preferred $-prefixed syntax - map to MongoDB operators
756
+ case '$GT':
757
+ case 'GT':
758
+ operators.$gt = opValue;
759
+ break;
760
+ case '$GTE':
761
+ case 'GTE':
762
+ operators.$gte = opValue;
763
+ break;
764
+ case '$LT':
765
+ case 'LT':
766
+ operators.$lt = opValue;
767
+ break;
768
+ case '$LTE':
769
+ case 'LTE':
770
+ operators.$lte = opValue;
771
+ break;
772
+ case '$NE':
773
+ case '$NOT':
774
+ case 'NE':
775
+ case 'NOT':
776
+ operators.$ne = opValue;
777
+ break;
778
+ case '$IN':
779
+ case 'IN':
780
+ operators.$in = opValue;
781
+ break;
782
+ case '$NOT_IN':
783
+ case 'NOT_IN':
784
+ operators.$nin = opValue;
785
+ break;
786
+ case '$LIKE':
787
+ case 'LIKE':
788
+ // MongoDB uses regex for pattern matching
789
+ operators.$regex = opValue.replace(/%/g, '.*').replace(/_/g, '.');
790
+ operators.$options = 'i';
791
+ break;
792
+ case '$IS_NULL':
793
+ case 'IS_NULL':
794
+ operators.$eq = null;
795
+ break;
796
+ case '$IS_NOT_NULL':
797
+ case 'IS_NOT_NULL':
798
+ operators.$ne = null;
799
+ break;
800
+ case '$BETWEEN':
801
+ case 'BETWEEN':
802
+ if (Array.isArray(opValue) && opValue.length === 2) {
803
+ operators.$gte = opValue[0];
804
+ operators.$lte = opValue[1];
805
+ }
806
+ break;
807
+ // Legacy lowercase $ operators - pass through
808
+ case '$gt':
809
+ case '$gte':
810
+ case '$lt':
811
+ case '$lte':
812
+ case '$ne':
813
+ case '$in':
814
+ case '$nin':
815
+ case '$regex':
816
+ case '$options':
817
+ case '$exists':
818
+ case '$type':
819
+ case '$eq':
820
+ case '$elemMatch':
821
+ case '$size':
822
+ case '$all':
823
+ operators[op] = opValue;
824
+ break;
825
+ }
826
+ }
827
+ filter[key] = operators;
828
+ }
829
+ else {
830
+ // Simple equality
831
+ filter[key] = value;
832
+ }
833
+ }
834
+ return filter;
835
+ };
836
+ return buildCondition(where);
837
+ }
838
+ // ==================== Utility Methods ====================
839
+ /**
840
+ * Escape identifier (collection/field name)
841
+ */
842
+ escapeIdentifier(identifier) {
843
+ // MongoDB doesn't require escaping in the same way as SQL
844
+ // But we can sanitize the identifier
845
+ return identifier.replace(/[.$]/g, '_');
846
+ }
847
+ /**
848
+ * Escape value
849
+ */
850
+ escapeValue(value) {
851
+ // MongoDB uses BSON, not SQL, so escaping is different
852
+ // This is mainly for display/logging purposes
853
+ if (value === null || value === undefined) {
854
+ return 'null';
855
+ }
856
+ if (typeof value === 'string') {
857
+ return `"${value.replace(/"/g, '\\"')}"`;
858
+ }
859
+ if (value instanceof Date) {
860
+ return value.toISOString();
861
+ }
862
+ if (typeof value === 'object') {
863
+ return JSON.stringify(value);
864
+ }
865
+ return String(value);
866
+ }
867
+ /**
868
+ * Get database version
869
+ */
870
+ async getDatabaseVersion(connection) {
871
+ try {
872
+ const db = connection.getClient();
873
+ const info = await db.admin().serverInfo();
874
+ return info.version || 'Unknown';
875
+ }
876
+ catch (error) {
877
+ return 'Unknown';
878
+ }
879
+ }
880
+ }
881
+ exports.MongoDBAdapter = MongoDBAdapter;
882
+ //# sourceMappingURL=mongodb.adapter.js.map