@aetherframework/database 1.0.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +1 -2
  2. package/src/DatabaseManager.js +0 -565
  3. package/src/core/ConnectionManager.js +0 -351
  4. package/src/core/DatabaseFactory.js +0 -188
  5. package/src/core/MongoQueryBuilder.js +0 -576
  6. package/src/core/PluginManager.js +0 -968
  7. package/src/core/QueryBuilder.js +0 -4398
  8. package/src/core/TransactionManager.js +0 -40
  9. package/src/drivers/clickhouse-driver.js +0 -272
  10. package/src/drivers/index.js +0 -273
  11. package/src/drivers/mongodb-driver.js +0 -87
  12. package/src/drivers/mssql-driver.js +0 -117
  13. package/src/drivers/mysql-driver.js +0 -169
  14. package/src/drivers/oracle-driver.js +0 -101
  15. package/src/drivers/postgres-driver.js +0 -234
  16. package/src/drivers/redis-driver.js +0 -52
  17. package/src/drivers/sqlite-driver.js +0 -67
  18. package/src/middleware/connection-pool.js +0 -455
  19. package/src/middleware/performance-monitor.js +0 -652
  20. package/src/middleware/query-cache.js +0 -500
  21. package/src/middleware/query-logger.js +0 -262
  22. package/src/plugins/AuditPlugin.js +0 -447
  23. package/src/plugins/BasePlugin.js +0 -418
  24. package/src/plugins/BatchOperationPlugin.js +0 -165
  25. package/src/plugins/CachePlugin.js +0 -407
  26. package/src/plugins/CtePlugin.js +0 -523
  27. package/src/plugins/DistributedPlugin.js +0 -543
  28. package/src/plugins/EncryptionPlugin.js +0 -211
  29. package/src/plugins/FullTextSearchPlugin.js +0 -164
  30. package/src/plugins/GeospatialPlugin.js +0 -219
  31. package/src/plugins/GraphQLPlugin.js +0 -162
  32. package/src/plugins/HookPlugin.js +0 -211
  33. package/src/plugins/JsonPlugin.js +0 -366
  34. package/src/plugins/OptimisticLockPlugin.js +0 -374
  35. package/src/plugins/PerformancePlugin.js +0 -175
  36. package/src/plugins/ResiliencePlugin.js +0 -114
  37. package/src/plugins/ShardingPlugin.js +0 -227
  38. package/src/plugins/SoftDeletePlugin.js +0 -258
  39. package/src/plugins/SyncPlugin.js +0 -373
  40. package/src/plugins/VersioningPlugin.js +0 -314
  41. package/src/plugins/WindowFunctionPlugin.js +0 -343
  42. package/src/utils/config-loader.js +0 -632
  43. package/src/utils/error-handler.js +0 -724
  44. package/src/utils/migration-runner.js +0 -1066
@@ -1,523 +0,0 @@
1
- /**
2
- * @license MIT
3
- * Copyright (c) 2026-present AetherFramework Contributors.
4
- * SPDX-License-Identifier: MIT
5
- * @module @aetherframework/database/plugin/CtePlugin
6
- */
7
- import { BasePlugin } from "./BasePlugin.js";
8
-
9
- /**
10
- * Common Table Expression Plugin - Manages CTE construction and correctly adds WITH clause when generating SQL
11
- */
12
- export class CtePlugin extends BasePlugin {
13
- constructor(queryBuilder) {
14
- super(queryBuilder);
15
- this.pluginName = "CtePlugin";
16
- }
17
-
18
- _registerMethods() {
19
- // Register CTE methods to QueryBuilder
20
- this.queryBuilder.with = this.with.bind(this);
21
- this.queryBuilder.withRecursive = this.withRecursive.bind(this);
22
- this.queryBuilder.fromCte = this.fromCte.bind(this);
23
- }
24
-
25
- /**
26
- * Define a Common Table Expression (CTE)
27
- * @param {string} name - CTE name
28
- * @param {Function} callback - CTE query callback
29
- * @param {Array} columns - CTE column names
30
- * @returns {QueryBuilder} QueryBuilder instance
31
- */
32
- with(name, callback, columns = []) {
33
- const cteQuery = new this.queryBuilder.constructor("", this.queryBuilder.connection, this.queryBuilder.dialect);
34
- callback(cteQuery);
35
- const { sql, bindings } = cteQuery.toSQL();
36
-
37
- this.queryBuilder.query.cte.push({
38
- name,
39
- sql,
40
- columns,
41
- recursive: false,
42
- });
43
-
44
- this.queryBuilder.bindings.unshift(...bindings);
45
- return this.queryBuilder;
46
- }
47
-
48
- /**
49
- * Define a Recursive Common Table Expression (CTE)
50
- * @param {string} name - CTE name
51
- * @param {Function} anchorCallback - Anchor query callback
52
- * @param {Function} recursiveCallback - Recursive query callback
53
- * @param {Array} columns - CTE column names
54
- * @returns {QueryBuilder} QueryBuilder instance
55
- */
56
- withRecursive(name, anchorCallback, recursiveCallback, columns = []) {
57
- const anchorQuery = new this.queryBuilder.constructor("", this.queryBuilder.connection, this.queryBuilder.dialect);
58
- anchorCallback(anchorQuery);
59
- const { sql: anchorSql, bindings: anchorBindings } = anchorQuery.toSQL();
60
-
61
- const recursiveQuery = new this.queryBuilder.constructor("", this.queryBuilder.connection, this.queryBuilder.dialect);
62
- recursiveCallback(recursiveQuery);
63
- const { sql: recursiveSql, bindings: recursiveBindings } = recursiveQuery.toSQL();
64
-
65
- const cteSql = `${anchorSql} UNION ALL ${recursiveSql}`;
66
-
67
- this.queryBuilder.query.cte.push({
68
- name,
69
- sql: cteSql,
70
- columns,
71
- recursive: true,
72
- });
73
-
74
- this.queryBuilder.bindings.unshift(...anchorBindings, ...recursiveBindings);
75
- return this.queryBuilder;
76
- }
77
-
78
- /**
79
- * Use CTE in FROM clause
80
- * @param {string} cteName - CTE name
81
- * @param {string} alias - Table alias
82
- * @returns {QueryBuilder} QueryBuilder instance
83
- */
84
- fromCte(cteName, alias = null) {
85
- const tableName = alias ? `${cteName} as ${alias}` : cteName;
86
- this.queryBuilder.tableName = tableName;
87
- return this.queryBuilder;
88
- }
89
-
90
- /**
91
- * Build CTE clause
92
- * @returns {string} CTE SQL fragment
93
- */
94
- buildCteClause() {
95
- if (this.queryBuilder.query.cte.length === 0) {
96
- return "";
97
- }
98
-
99
- const cteClauses = this.queryBuilder.query.cte.map((cte) => {
100
- const columns = cte.columns.length > 0 ? `(${cte.columns.join(", ")})` : "";
101
- const recursive = cte.recursive ? "RECURSIVE " : "";
102
- return `${recursive}${cte.name}${columns} AS (${cte.sql})`;
103
- });
104
-
105
- return `WITH ${cteClauses.join(", ")} `;
106
- }
107
-
108
- /**
109
- * Check if database supports CTE
110
- * @returns {boolean} Whether supported
111
- */
112
- isCteSupported() {
113
- const supportedDialects = [
114
- "postgresql",
115
- "postgres",
116
- "pg",
117
- "mysql", // MySQL 8.0+
118
- "mariadb", // MariaDB 10.2+
119
- "sqlite", // SQLite 3.8.3+
120
- "mssql", // SQL Server 2005+
121
- "sqlserver",
122
- "cockroachdb",
123
- "cockroach",
124
- ];
125
-
126
- return supportedDialects.includes(this.queryBuilder.dialect);
127
- }
128
-
129
- /**
130
- * Check if database supports recursive CTE
131
- * @returns {boolean} Whether supported
132
- */
133
- isRecursiveCteSupported() {
134
- const supportedDialects = [
135
- "postgresql",
136
- "postgres",
137
- "pg",
138
- "mysql", // MySQL 8.0+
139
- "mariadb", // MariaDB 10.2+
140
- "sqlite", // SQLite 3.8.3+
141
- "mssql", // SQL Server 2005+
142
- "sqlserver",
143
- "cockroachdb",
144
- "cockroach",
145
- ];
146
-
147
- return supportedDialects.includes(this.queryBuilder.dialect);
148
- }
149
-
150
- /**
151
- * Create hierarchical query (common use case for recursive CTE)
152
- * @param {string} idColumn - ID column name
153
- * @param {string} parentColumn - Parent ID column name
154
- * @param {string} levelColumn - Level column name (default: 'level')
155
- * @param {string} pathColumn - Path column name (default: 'path')
156
- * @returns {QueryBuilder} QueryBuilder instance
157
- */
158
- hierarchical(idColumn = "id", parentColumn = "parent_id", levelColumn = "level", pathColumn = "path") {
159
- if (!this.isRecursiveCteSupported()) {
160
- throw new Error("Hierarchical queries are only supported in databases that support recursive CTEs");
161
- }
162
-
163
- const cteName = "hierarchy";
164
-
165
- return this.withRecursive(
166
- cteName,
167
- (anchor) => {
168
- anchor
169
- .select(
170
- `${idColumn}`,
171
- `${parentColumn}`,
172
- `1 as ${levelColumn}`,
173
- `${idColumn}::text as ${pathColumn}`
174
- )
175
- .whereNull(parentColumn);
176
- },
177
- (recursive) => {
178
- recursive
179
- .select(
180
- `t.${idColumn}`,
181
- `t.${parentColumn}`,
182
- `h.${levelColumn} + 1 as ${levelColumn}`,
183
- `h.${pathColumn} || '.' || t.${idColumn}::text as ${pathColumn}`
184
- )
185
- .from(`${this.queryBuilder.tableName} as t`)
186
- .join(`${cteName} as h`, `t.${parentColumn}`, "=", `h.${idColumn}`);
187
- },
188
- [idColumn, parentColumn, levelColumn, pathColumn]
189
- ).fromCte(cteName);
190
- }
191
-
192
- /**
193
- * Create materialized path query
194
- * @param {string} idColumn - ID column name
195
- * @param {string} parentColumn - Parent ID column name
196
- * @param {string} nameColumn - Name column name
197
- * @param {string} separator - Path separator (default: '/')
198
- * @returns {QueryBuilder} QueryBuilder instance
199
- */
200
- materializedPath(idColumn = "id", parentColumn = "parent_id", nameColumn = "name", separator = "/") {
201
- if (!this.isRecursiveCteSupported()) {
202
- throw new Error("Materialized path queries are only supported in databases that support recursive CTEs");
203
- }
204
-
205
- const cteName = "materialized_path";
206
-
207
- return this.withRecursive(
208
- cteName,
209
- (anchor) => {
210
- anchor
211
- .select(
212
- `${idColumn}`,
213
- `${parentColumn}`,
214
- `${nameColumn}`,
215
- `CAST(${nameColumn} AS VARCHAR(1000)) as path`,
216
- `1 as depth`
217
- )
218
- .whereNull(parentColumn);
219
- },
220
- (recursive) => {
221
- recursive
222
- .select(
223
- `t.${idColumn}`,
224
- `t.${parentColumn}`,
225
- `t.${nameColumn}`,
226
- `CONCAT(h.path, '${separator}', t.${nameColumn}) as path`,
227
- `h.depth + 1 as depth`
228
- )
229
- .from(`${this.queryBuilder.tableName} as t`)
230
- .join(`${cteName} as h`, `t.${parentColumn}`, "=", `h.${idColumn}`);
231
- },
232
- [idColumn, parentColumn, nameColumn, "path", "depth"]
233
- ).fromCte(cteName);
234
- }
235
-
236
- /**
237
- * Create organizational chart query
238
- * @param {string} idColumn - ID column name
239
- * @param {string} parentColumn - Parent ID column name
240
- * @param {string} nameColumn - Name column name
241
- * @param {string} titleColumn - Title column name
242
- * @returns {QueryBuilder} QueryBuilder instance
243
- */
244
- orgChart(idColumn = "id", parentColumn = "parent_id", nameColumn = "name", titleColumn = "title") {
245
- if (!this.isRecursiveCteSupported()) {
246
- throw new Error("Organizational chart queries are only supported in databases that support recursive CTEs");
247
- }
248
-
249
- const cteName = "org_chart";
250
-
251
- return this.withRecursive(
252
- cteName,
253
- (anchor) => {
254
- anchor
255
- .select(
256
- `${idColumn}`,
257
- `${parentColumn}`,
258
- `${nameColumn}`,
259
- `${titleColumn}`,
260
- `1 as level`,
261
- `CAST(${nameColumn} AS VARCHAR(1000)) as hierarchy_path`
262
- )
263
- .whereNull(parentColumn);
264
- },
265
- (recursive) => {
266
- recursive
267
- .select(
268
- `t.${idColumn}`,
269
- `t.${parentColumn}`,
270
- `t.${nameColumn}`,
271
- `t.${titleColumn}`,
272
- `h.level + 1 as level`,
273
- `CONCAT(h.hierarchy_path, ' > ', t.${nameColumn}) as hierarchy_path`
274
- )
275
- .from(`${this.queryBuilder.tableName} as t`)
276
- .join(`${cteName} as h`, `t.${parentColumn}`, "=", `h.${idColumn}`);
277
- },
278
- [idColumn, parentColumn, nameColumn, titleColumn, "level", "hierarchy_path"]
279
- ).fromCte(cteName);
280
- }
281
-
282
- /**
283
- * Create bill of materials (BOM) query
284
- * @param {string} componentIdColumn - Component ID column name
285
- * @param {string} parentComponentIdColumn - Parent component ID column name
286
- * @param {string} quantityColumn - Quantity column name
287
- * @param {string} costColumn - Cost column name
288
- * @returns {QueryBuilder} QueryBuilder instance
289
- */
290
- billOfMaterials(componentIdColumn = "component_id", parentComponentIdColumn = "parent_component_id", quantityColumn = "quantity", costColumn = "cost") {
291
- if (!this.isRecursiveCteSupported()) {
292
- throw new Error("Bill of materials queries are only supported in databases that support recursive CTEs");
293
- }
294
-
295
- const cteName = "bom";
296
-
297
- return this.withRecursive(
298
- cteName,
299
- (anchor) => {
300
- anchor
301
- .select(
302
- `${componentIdColumn}`,
303
- `${parentComponentIdColumn}`,
304
- `${quantityColumn}`,
305
- `${costColumn}`,
306
- `${quantityColumn} as total_quantity`,
307
- `${costColumn} as total_cost`,
308
- `1 as level`
309
- )
310
- .whereNull(parentComponentIdColumn);
311
- },
312
- (recursive) => {
313
- recursive
314
- .select(
315
- `t.${componentIdColumn}`,
316
- `t.${parentComponentIdColumn}`,
317
- `t.${quantityColumn}`,
318
- `t.${costColumn}`,
319
- `h.total_quantity * t.${quantityColumn} as total_quantity`,
320
- `h.total_cost + (h.total_quantity * t.${costColumn}) as total_cost`,
321
- `h.level + 1 as level`
322
- )
323
- .from(`${this.queryBuilder.tableName} as t`)
324
- .join(`${cteName} as h`, `t.${parentComponentIdColumn}`, "=", `h.${componentIdColumn}`);
325
- },
326
- [componentIdColumn, parentComponentIdColumn, quantityColumn, costColumn, "total_quantity", "total_cost", "level"]
327
- ).fromCte(cteName);
328
- }
329
-
330
- /**
331
- * Create category tree query
332
- * @param {string} categoryIdColumn - Category ID column name
333
- * @param {string} parentCategoryIdColumn - Parent category ID column name
334
- * @param {string} categoryNameColumn - Category name column name
335
- * @param {string} sortOrderColumn - Sort order column name
336
- * @returns {QueryBuilder} QueryBuilder instance
337
- */
338
- categoryTree(categoryIdColumn = "category_id", parentCategoryIdColumn = "parent_category_id", categoryNameColumn = "category_name", sortOrderColumn = "sort_order") {
339
- if (!this.isRecursiveCteSupported()) {
340
- throw new Error("Category tree queries are only supported in databases that support recursive CTEs");
341
- }
342
-
343
- const cteName = "category_tree";
344
-
345
- return this.withRecursive(
346
- cteName,
347
- (anchor) => {
348
- anchor
349
- .select(
350
- `${categoryIdColumn}`,
351
- `${parentCategoryIdColumn}`,
352
- `${categoryNameColumn}`,
353
- `${sortOrderColumn}`,
354
- `CAST(${categoryNameColumn} AS VARCHAR(1000)) as full_path`,
355
- `1 as depth`
356
- )
357
- .whereNull(parentCategoryIdColumn)
358
- .orderBy(sortOrderColumn);
359
- },
360
- (recursive) => {
361
- recursive
362
- .select(
363
- `t.${categoryIdColumn}`,
364
- `t.${parentCategoryIdColumn}`,
365
- `t.${categoryNameColumn}`,
366
- `t.${sortOrderColumn}`,
367
- `CONCAT(h.full_path, ' > ', t.${categoryNameColumn}) as full_path`,
368
- `h.depth + 1 as depth`
369
- )
370
- .from(`${this.queryBuilder.tableName} as t`)
371
- .join(`${cteName} as h`, `t.${parentCategoryIdColumn}`, "=", `h.${categoryIdColumn}`)
372
- .orderBy(sortOrderColumn);
373
- },
374
- [categoryIdColumn, parentCategoryIdColumn, categoryNameColumn, sortOrderColumn, "full_path", "depth"]
375
- ).fromCte(cteName);
376
- }
377
-
378
- /**
379
- * Create graph traversal query (for adjacency lists)
380
- * @param {string} nodeIdColumn - Node ID column name
381
- * @param {string} edgeColumn - Edge column name
382
- * @param {string} costColumn - Cost column name (optional)
383
- * @returns {QueryBuilder} QueryBuilder instance
384
- */
385
- graphTraversal(nodeIdColumn = "node_id", edgeColumn = "edge_to", costColumn = null) {
386
- if (!this.isRecursiveCteSupported()) {
387
- throw new Error("Graph traversal queries are only supported in databases that support recursive CTEs");
388
- }
389
-
390
- const cteName = "graph_traversal";
391
-
392
- const anchorSelect = [
393
- `${nodeIdColumn}`,
394
- `${edgeColumn}`,
395
- `0 as distance`,
396
- `CAST(${nodeIdColumn} AS VARCHAR(1000)) as path`
397
- ];
398
-
399
- const recursiveSelect = [
400
- `t.${nodeIdColumn}`,
401
- `t.${edgeColumn}`,
402
- `h.distance + 1 as distance`,
403
- `CONCAT(h.path, ' -> ', t.${nodeIdColumn}) as path`
404
- ];
405
-
406
- if (costColumn) {
407
- anchorSelect.push(`${costColumn} as total_cost`);
408
- recursiveSelect.push(`h.total_cost + t.${costColumn} as total_cost`);
409
- }
410
-
411
- return this.withRecursive(
412
- cteName,
413
- (anchor) => {
414
- anchor
415
- .select(...anchorSelect)
416
- .where(`${edgeColumn}`, "=", this.queryBuilder.bindings || null);
417
- },
418
- (recursive) => {
419
- recursive
420
- .select(...recursiveSelect)
421
- .from(`${this.queryBuilder.tableName} as t`)
422
- .join(`${cteName} as h`, `t.${nodeIdColumn}`, "=", `h.${edgeColumn}`);
423
- },
424
- costColumn
425
- ? [nodeIdColumn, edgeColumn, "distance", "path", "total_cost"]
426
- : [nodeIdColumn, edgeColumn, "distance", "path"]
427
- ).fromCte(cteName);
428
- }
429
-
430
- /**
431
- * Create number sequence CTE
432
- * @param {number} start - Start number
433
- * @param {number} end - End number
434
- * @param {number} step - Step size (default: 1)
435
- * @param {string} columnName - Column name for sequence (default: 'n')
436
- * @returns {QueryBuilder} QueryBuilder instance
437
- */
438
- numberSequence(start = 1, end = 10, step = 1, columnName = "n") {
439
- if (!this.isRecursiveCteSupported()) {
440
- throw new Error("Number sequence queries are only supported in databases that support recursive CTEs");
441
- }
442
-
443
- const cteName = "numbers";
444
-
445
- return this.withRecursive(
446
- cteName,
447
- (anchor) => {
448
- anchor.selectRaw(`${start} as ${columnName}`);
449
- },
450
- (recursive) => {
451
- recursive
452
- .selectRaw(`${columnName} + ${step} as ${columnName}`)
453
- .fromCte(cteName)
454
- .where(columnName, "<", end);
455
- },
456
- [columnName]
457
- ).fromCte(cteName);
458
- }
459
-
460
- /**
461
- * Create date range CTE
462
- * @param {string} startDate - Start date (YYYY-MM-DD)
463
- * @param {string} endDate - End date (YYYY-MM-DD)
464
- * @param {string} dateColumn - Date column name (default: 'date')
465
- * @returns {QueryBuilder} QueryBuilder instance
466
- */
467
- dateRange(startDate, endDate, dateColumn = "date") {
468
- if (!this.isRecursiveCteSupported()) {
469
- throw new Error("Date range queries are only supported in databases that support recursive CTEs");
470
- }
471
-
472
- const cteName = "dates";
473
-
474
- return this.withRecursive(
475
- cteName,
476
- (anchor) => {
477
- anchor.selectRaw(`'${startDate}'::date as ${dateColumn}`);
478
- },
479
- (recursive) => {
480
- recursive
481
- .selectRaw(`${dateColumn} + INTERVAL '1 day' as ${dateColumn}`)
482
- .fromCte(cteName)
483
- .where(dateColumn, "<", endDate);
484
- },
485
- [dateColumn]
486
- ).fromCte(cteName);
487
- }
488
-
489
- /**
490
- * Create calendar CTE
491
- * @param {string} startDate - Start date (YYYY-MM-DD)
492
- * @param {string} endDate - End date (YYYY-MM-DD)
493
- * @returns {QueryBuilder} QueryBuilder instance
494
- */
495
- calendar(startDate, endDate) {
496
- if (!this.isRecursiveCteSupported()) {
497
- throw new Error("Calendar queries are only supported in databases that support recursive CTEs");
498
- }
499
-
500
- const cteName = "calendar";
501
-
502
- return this.withRecursive(
503
- cteName,
504
- (anchor) => {
505
- anchor.selectRaw(`'${startDate}'::date as date`);
506
- },
507
- (recursive) => {
508
- recursive
509
- .selectRaw("date + INTERVAL '1 day' as date")
510
- .fromCte(cteName)
511
- .where("date", "<", endDate);
512
- },
513
- ["date"]
514
- ).fromCte(cteName)
515
- .selectRaw("date")
516
- .selectRaw("EXTRACT(YEAR FROM date) as year")
517
- .selectRaw("EXTRACT(MONTH FROM date) as month")
518
- .selectRaw("EXTRACT(DAY FROM date) as day")
519
- .selectRaw("EXTRACT(DOW FROM date) as day_of_week")
520
- .selectRaw("EXTRACT(WEEK FROM date) as week")
521
- .selectRaw("EXTRACT(QUARTER FROM date) as quarter");
522
- }
523
- }