metal-orm 1.0.16 → 1.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -40
- package/dist/decorators/index.cjs +344 -69
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -1
- package/dist/decorators/index.d.ts +1 -1
- package/dist/decorators/index.js +344 -69
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +567 -181
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -30
- package/dist/index.d.ts +66 -30
- package/dist/index.js +559 -181
- package/dist/index.js.map +1 -1
- package/dist/{select-BKZrMRCQ.d.cts → select-BuMpVcVt.d.cts} +265 -74
- package/dist/{select-BKZrMRCQ.d.ts → select-BuMpVcVt.d.ts} +265 -74
- package/package.json +5 -1
- package/src/codegen/naming-strategy.ts +15 -10
- package/src/core/ast/aggregate-functions.ts +50 -4
- package/src/core/ast/builders.ts +23 -3
- package/src/core/ast/expression-builders.ts +36 -16
- package/src/core/ast/expression-nodes.ts +17 -9
- package/src/core/ast/join-node.ts +5 -3
- package/src/core/ast/join.ts +16 -16
- package/src/core/ast/query.ts +44 -29
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +18 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +11 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +9 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
- package/src/core/ddl/introspect/functions/postgres.ts +2 -6
- package/src/core/dialect/abstract.ts +12 -8
- package/src/core/dialect/base/sql-dialect.ts +58 -46
- package/src/core/dialect/mssql/functions.ts +24 -15
- package/src/core/dialect/mssql/index.ts +53 -28
- package/src/core/dialect/postgres/functions.ts +33 -24
- package/src/core/dialect/sqlite/functions.ts +19 -12
- package/src/core/dialect/sqlite/index.ts +22 -13
- package/src/core/functions/datetime.ts +2 -1
- package/src/core/functions/numeric.ts +2 -1
- package/src/core/functions/standard-strategy.ts +52 -12
- package/src/core/functions/text.ts +2 -1
- package/src/core/functions/types.ts +8 -8
- package/src/index.ts +5 -4
- package/src/orm/domain-event-bus.ts +43 -25
- package/src/orm/entity-meta.ts +40 -0
- package/src/orm/execution-context.ts +6 -0
- package/src/orm/hydration-context.ts +6 -4
- package/src/orm/orm-session.ts +35 -24
- package/src/orm/orm.ts +10 -10
- package/src/orm/query-logger.ts +15 -0
- package/src/orm/runtime-types.ts +60 -2
- package/src/orm/transaction-runner.ts +7 -0
- package/src/orm/unit-of-work.ts +1 -0
- package/src/query-builder/column-selector.ts +9 -7
- package/src/query-builder/insert-query-state.ts +13 -3
- package/src/query-builder/query-ast-service.ts +59 -38
- package/src/query-builder/relation-conditions.ts +38 -34
- package/src/query-builder/relation-manager.ts +8 -3
- package/src/query-builder/relation-service.ts +59 -46
- package/src/query-builder/select-helpers.ts +50 -0
- package/src/query-builder/select-query-state.ts +19 -7
- package/src/query-builder/select.ts +339 -167
- package/src/query-builder/update-query-state.ts +31 -9
- package/src/schema/column.ts +75 -39
- package/src/schema/types.ts +17 -6
package/dist/decorators/index.js
CHANGED
|
@@ -298,6 +298,15 @@ var isWindowFunctionNode = (node) => node?.type === "WindowFunction";
|
|
|
298
298
|
var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
|
|
299
299
|
|
|
300
300
|
// src/core/ast/expression-builders.ts
|
|
301
|
+
var valueToOperand = (value) => {
|
|
302
|
+
if (isOperandNode(value)) {
|
|
303
|
+
return value;
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
type: "Literal",
|
|
307
|
+
value
|
|
308
|
+
};
|
|
309
|
+
};
|
|
301
310
|
var toNode = (col) => {
|
|
302
311
|
if (isOperandNode(col)) return col;
|
|
303
312
|
const def = col;
|
|
@@ -307,10 +316,10 @@ var toLiteralNode = (value) => ({
|
|
|
307
316
|
type: "Literal",
|
|
308
317
|
value
|
|
309
318
|
});
|
|
319
|
+
var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
310
320
|
var toOperand = (val) => {
|
|
311
|
-
if (val
|
|
312
|
-
|
|
313
|
-
return { type: "Literal", value: val };
|
|
321
|
+
if (isLiteralValue(val)) {
|
|
322
|
+
return valueToOperand(val);
|
|
314
323
|
}
|
|
315
324
|
return toNode(val);
|
|
316
325
|
};
|
|
@@ -351,6 +360,24 @@ var notExists = (subquery) => ({
|
|
|
351
360
|
subquery
|
|
352
361
|
});
|
|
353
362
|
|
|
363
|
+
// src/core/sql/sql.ts
|
|
364
|
+
var JOIN_KINDS = {
|
|
365
|
+
/** INNER JOIN type */
|
|
366
|
+
INNER: "INNER",
|
|
367
|
+
/** LEFT JOIN type */
|
|
368
|
+
LEFT: "LEFT",
|
|
369
|
+
/** RIGHT JOIN type */
|
|
370
|
+
RIGHT: "RIGHT",
|
|
371
|
+
/** CROSS JOIN type */
|
|
372
|
+
CROSS: "CROSS"
|
|
373
|
+
};
|
|
374
|
+
var ORDER_DIRECTIONS = {
|
|
375
|
+
/** Ascending order */
|
|
376
|
+
ASC: "ASC",
|
|
377
|
+
/** Descending order */
|
|
378
|
+
DESC: "DESC"
|
|
379
|
+
};
|
|
380
|
+
|
|
354
381
|
// src/core/ast/aggregate-functions.ts
|
|
355
382
|
var buildAggregate = (name) => (col) => ({
|
|
356
383
|
type: "Function",
|
|
@@ -360,14 +387,41 @@ var buildAggregate = (name) => (col) => ({
|
|
|
360
387
|
var count = buildAggregate("COUNT");
|
|
361
388
|
var sum = buildAggregate("SUM");
|
|
362
389
|
var avg = buildAggregate("AVG");
|
|
390
|
+
var min = buildAggregate("MIN");
|
|
391
|
+
var max = buildAggregate("MAX");
|
|
392
|
+
|
|
393
|
+
// src/core/ast/builders.ts
|
|
394
|
+
var buildColumnNode = (table, column) => {
|
|
395
|
+
if (column.type === "Column") {
|
|
396
|
+
return column;
|
|
397
|
+
}
|
|
398
|
+
const def = column;
|
|
399
|
+
const baseTable = def.table ? table.alias && def.table === table.name ? table.alias : def.table : table.alias || table.name;
|
|
400
|
+
return {
|
|
401
|
+
type: "Column",
|
|
402
|
+
table: baseTable,
|
|
403
|
+
name: def.name
|
|
404
|
+
};
|
|
405
|
+
};
|
|
406
|
+
var derivedTable = (query, alias, columnAliases) => ({
|
|
407
|
+
type: "DerivedTable",
|
|
408
|
+
query,
|
|
409
|
+
alias,
|
|
410
|
+
columnAliases
|
|
411
|
+
});
|
|
363
412
|
|
|
364
413
|
// src/core/functions/standard-strategy.ts
|
|
365
|
-
var StandardFunctionStrategy = class {
|
|
414
|
+
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
366
415
|
constructor() {
|
|
367
416
|
this.renderers = /* @__PURE__ */ new Map();
|
|
368
417
|
this.registerStandard();
|
|
369
418
|
}
|
|
370
419
|
registerStandard() {
|
|
420
|
+
this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
|
|
421
|
+
this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
|
|
422
|
+
this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
|
|
423
|
+
this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
|
|
424
|
+
this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
|
|
371
425
|
this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
|
|
372
426
|
this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
|
|
373
427
|
this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
|
|
@@ -394,6 +448,7 @@ var StandardFunctionStrategy = class {
|
|
|
394
448
|
this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
|
|
395
449
|
this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
|
|
396
450
|
this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
|
|
451
|
+
this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
|
|
397
452
|
}
|
|
398
453
|
add(name, renderer) {
|
|
399
454
|
this.renderers.set(name, renderer);
|
|
@@ -401,6 +456,36 @@ var StandardFunctionStrategy = class {
|
|
|
401
456
|
getRenderer(name) {
|
|
402
457
|
return this.renderers.get(name);
|
|
403
458
|
}
|
|
459
|
+
renderGroupConcat(ctx) {
|
|
460
|
+
const arg = ctx.compiledArgs[0];
|
|
461
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
462
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
463
|
+
const separatorClause = this.formatGroupConcatSeparator(ctx);
|
|
464
|
+
return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
|
|
465
|
+
}
|
|
466
|
+
buildOrderByExpression(ctx) {
|
|
467
|
+
const orderBy = ctx.node.orderBy;
|
|
468
|
+
if (!orderBy || orderBy.length === 0) {
|
|
469
|
+
return "";
|
|
470
|
+
}
|
|
471
|
+
const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
|
|
472
|
+
return `ORDER BY ${parts.join(", ")}`;
|
|
473
|
+
}
|
|
474
|
+
formatGroupConcatSeparator(ctx) {
|
|
475
|
+
if (!ctx.node.separator) {
|
|
476
|
+
return "";
|
|
477
|
+
}
|
|
478
|
+
return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
|
|
479
|
+
}
|
|
480
|
+
getGroupConcatSeparatorOperand(ctx) {
|
|
481
|
+
return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
|
|
482
|
+
}
|
|
483
|
+
static {
|
|
484
|
+
this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
|
|
485
|
+
type: "Literal",
|
|
486
|
+
value: ","
|
|
487
|
+
};
|
|
488
|
+
}
|
|
404
489
|
};
|
|
405
490
|
|
|
406
491
|
// src/core/dialect/abstract.ts
|
|
@@ -747,7 +832,11 @@ var Dialect = class _Dialect {
|
|
|
747
832
|
const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
|
|
748
833
|
const renderer = this.functionStrategy.getRenderer(fnNode.name);
|
|
749
834
|
if (renderer) {
|
|
750
|
-
return renderer({
|
|
835
|
+
return renderer({
|
|
836
|
+
node: fnNode,
|
|
837
|
+
compiledArgs,
|
|
838
|
+
compileOperand: (operand) => this.compileOperand(operand, ctx)
|
|
839
|
+
});
|
|
751
840
|
}
|
|
752
841
|
return `${fnNode.name}(${compiledArgs.join(", ")})`;
|
|
753
842
|
}
|
|
@@ -1010,7 +1099,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1010
1099
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1011
1100
|
}
|
|
1012
1101
|
compileInsertColumnList(columns) {
|
|
1013
|
-
return columns.map((column) =>
|
|
1102
|
+
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1014
1103
|
}
|
|
1015
1104
|
compileInsertValues(values, ctx) {
|
|
1016
1105
|
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
@@ -1036,7 +1125,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1036
1125
|
compileUpdateAssignments(assignments, ctx) {
|
|
1037
1126
|
return assignments.map((assignment) => {
|
|
1038
1127
|
const col = assignment.column;
|
|
1039
|
-
const target =
|
|
1128
|
+
const target = this.quoteIdentifier(col.name);
|
|
1040
1129
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1041
1130
|
return `${target} = ${value}`;
|
|
1042
1131
|
}).join(", ");
|
|
@@ -1068,12 +1157,29 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1068
1157
|
if (tableSource.type === "FunctionTable") {
|
|
1069
1158
|
return this.compileFunctionTable(tableSource, ctx);
|
|
1070
1159
|
}
|
|
1160
|
+
if (tableSource.type === "DerivedTable") {
|
|
1161
|
+
return this.compileDerivedTable(tableSource, ctx);
|
|
1162
|
+
}
|
|
1071
1163
|
return this.compileTableSource(tableSource);
|
|
1072
1164
|
}
|
|
1073
1165
|
compileFunctionTable(fn, ctx) {
|
|
1074
1166
|
return FunctionTableFormatter.format(fn, ctx, this);
|
|
1075
1167
|
}
|
|
1168
|
+
compileDerivedTable(table, ctx) {
|
|
1169
|
+
if (!table.alias) {
|
|
1170
|
+
throw new Error("Derived tables must have an alias.");
|
|
1171
|
+
}
|
|
1172
|
+
const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
1173
|
+
const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
1174
|
+
return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
|
|
1175
|
+
}
|
|
1076
1176
|
compileTableSource(table) {
|
|
1177
|
+
if (table.type === "FunctionTable") {
|
|
1178
|
+
return this.compileFunctionTable(table);
|
|
1179
|
+
}
|
|
1180
|
+
if (table.type === "DerivedTable") {
|
|
1181
|
+
return this.compileDerivedTable(table);
|
|
1182
|
+
}
|
|
1077
1183
|
const base = this.compileTableName(table);
|
|
1078
1184
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1079
1185
|
}
|
|
@@ -1170,6 +1276,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1170
1276
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1171
1277
|
return `DATE_TRUNC('${partClean}', ${date})`;
|
|
1172
1278
|
});
|
|
1279
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1280
|
+
const arg = ctx.compiledArgs[0];
|
|
1281
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1282
|
+
const orderSegment = orderClause ? ` ${orderClause}` : "";
|
|
1283
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1284
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1285
|
+
return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
|
|
1286
|
+
});
|
|
1173
1287
|
}
|
|
1174
1288
|
};
|
|
1175
1289
|
|
|
@@ -1414,6 +1528,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1414
1528
|
}
|
|
1415
1529
|
return `date(${date}, 'start of ${partClean}')`;
|
|
1416
1530
|
});
|
|
1531
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1532
|
+
const arg = ctx.compiledArgs[0];
|
|
1533
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1534
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1535
|
+
return `GROUP_CONCAT(${arg}, ${separator})`;
|
|
1536
|
+
});
|
|
1417
1537
|
}
|
|
1418
1538
|
};
|
|
1419
1539
|
|
|
@@ -1448,6 +1568,12 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
1448
1568
|
const columns = this.formatReturningColumns(returning);
|
|
1449
1569
|
return ` RETURNING ${columns}`;
|
|
1450
1570
|
}
|
|
1571
|
+
formatReturningColumns(returning) {
|
|
1572
|
+
return returning.map((column) => {
|
|
1573
|
+
const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
|
|
1574
|
+
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
1575
|
+
}).join(", ");
|
|
1576
|
+
}
|
|
1451
1577
|
supportsReturning() {
|
|
1452
1578
|
return true;
|
|
1453
1579
|
}
|
|
@@ -1530,6 +1656,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
1530
1656
|
const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
|
|
1531
1657
|
return `DATETRUNC(${partClean}, ${date})`;
|
|
1532
1658
|
});
|
|
1659
|
+
this.add("GROUP_CONCAT", (ctx) => {
|
|
1660
|
+
const arg = ctx.compiledArgs[0];
|
|
1661
|
+
const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
|
|
1662
|
+
const separator = ctx.compileOperand(separatorOperand);
|
|
1663
|
+
const orderClause = this.buildOrderByExpression(ctx);
|
|
1664
|
+
const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
|
|
1665
|
+
return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
|
|
1666
|
+
});
|
|
1533
1667
|
}
|
|
1534
1668
|
};
|
|
1535
1669
|
|
|
@@ -1606,6 +1740,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1606
1740
|
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
1607
1741
|
}
|
|
1608
1742
|
compileDeleteAst(ast, ctx) {
|
|
1743
|
+
if (ast.from.type !== "Table") {
|
|
1744
|
+
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
1745
|
+
}
|
|
1609
1746
|
const table = this.quoteIdentifier(ast.from.name);
|
|
1610
1747
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1611
1748
|
return `DELETE FROM ${table}${whereClause};`;
|
|
@@ -1629,9 +1766,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1629
1766
|
return expr;
|
|
1630
1767
|
}).join(", ");
|
|
1631
1768
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
1632
|
-
const from =
|
|
1769
|
+
const from = this.compileTableSource(ast.from, ctx);
|
|
1633
1770
|
const joins = ast.joins.map((j) => {
|
|
1634
|
-
const table = this.
|
|
1771
|
+
const table = this.compileTableSource(j.table, ctx);
|
|
1635
1772
|
const cond = this.compileExpression(j.condition, ctx);
|
|
1636
1773
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
1637
1774
|
}).join(" ");
|
|
@@ -1661,6 +1798,21 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1661
1798
|
}
|
|
1662
1799
|
return pagination;
|
|
1663
1800
|
}
|
|
1801
|
+
compileTableSource(table, ctx) {
|
|
1802
|
+
if (table.type === "FunctionTable") {
|
|
1803
|
+
return FunctionTableFormatter.format(table, ctx, this);
|
|
1804
|
+
}
|
|
1805
|
+
if (table.type === "DerivedTable") {
|
|
1806
|
+
return this.compileDerivedTable(table, ctx);
|
|
1807
|
+
}
|
|
1808
|
+
const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
|
|
1809
|
+
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1810
|
+
}
|
|
1811
|
+
compileDerivedTable(table, ctx) {
|
|
1812
|
+
const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
1813
|
+
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
1814
|
+
return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
1815
|
+
}
|
|
1664
1816
|
compileCtes(ast, ctx) {
|
|
1665
1817
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
1666
1818
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -1789,6 +1941,17 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
1789
1941
|
joins: [...this.ast.joins ?? [], join]
|
|
1790
1942
|
});
|
|
1791
1943
|
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Replaces the FROM clause.
|
|
1946
|
+
* @param from - Table source for the FROM clause
|
|
1947
|
+
* @returns New SelectQueryState with updated FROM
|
|
1948
|
+
*/
|
|
1949
|
+
withFrom(from) {
|
|
1950
|
+
return this.clone({
|
|
1951
|
+
...this.ast,
|
|
1952
|
+
from
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1792
1955
|
/**
|
|
1793
1956
|
* Adds a WHERE clause to the query
|
|
1794
1957
|
* @param predicate - WHERE predicate expression
|
|
@@ -1899,24 +2062,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
|
|
|
1899
2062
|
meta: relationName ? { relationName } : void 0
|
|
1900
2063
|
});
|
|
1901
2064
|
|
|
1902
|
-
// src/core/sql/sql.ts
|
|
1903
|
-
var JOIN_KINDS = {
|
|
1904
|
-
/** INNER JOIN type */
|
|
1905
|
-
INNER: "INNER",
|
|
1906
|
-
/** LEFT JOIN type */
|
|
1907
|
-
LEFT: "LEFT",
|
|
1908
|
-
/** RIGHT JOIN type */
|
|
1909
|
-
RIGHT: "RIGHT",
|
|
1910
|
-
/** CROSS JOIN type */
|
|
1911
|
-
CROSS: "CROSS"
|
|
1912
|
-
};
|
|
1913
|
-
var ORDER_DIRECTIONS = {
|
|
1914
|
-
/** Ascending order */
|
|
1915
|
-
ASC: "ASC",
|
|
1916
|
-
/** Descending order */
|
|
1917
|
-
DESC: "DESC"
|
|
1918
|
-
};
|
|
1919
|
-
|
|
1920
2065
|
// src/query-builder/hydration-manager.ts
|
|
1921
2066
|
var HydrationManager = class _HydrationManager {
|
|
1922
2067
|
/**
|
|
@@ -2299,19 +2444,6 @@ var buildDefaultHydrationPlan = (table) => ({
|
|
|
2299
2444
|
relations: []
|
|
2300
2445
|
});
|
|
2301
2446
|
|
|
2302
|
-
// src/core/ast/builders.ts
|
|
2303
|
-
var buildColumnNode = (table, column) => {
|
|
2304
|
-
if (column.type === "Column") {
|
|
2305
|
-
return column;
|
|
2306
|
-
}
|
|
2307
|
-
const def = column;
|
|
2308
|
-
return {
|
|
2309
|
-
type: "Column",
|
|
2310
|
-
table: def.table || table.name,
|
|
2311
|
-
name: def.name
|
|
2312
|
-
};
|
|
2313
|
-
};
|
|
2314
|
-
|
|
2315
2447
|
// src/query-builder/raw-column-parser.ts
|
|
2316
2448
|
var parseRawColumn = (col, tableName, ctes) => {
|
|
2317
2449
|
if (col.includes("(")) {
|
|
@@ -2351,6 +2483,8 @@ var QueryAstService = class {
|
|
|
2351
2483
|
const existingAliases = new Set(
|
|
2352
2484
|
this.state.ast.columns.map((c) => c.alias || c.name)
|
|
2353
2485
|
);
|
|
2486
|
+
const from = this.state.ast.from;
|
|
2487
|
+
const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2354
2488
|
const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
|
|
2355
2489
|
if (existingAliases.has(alias)) return acc;
|
|
2356
2490
|
if (isExpressionSelectionNode(val)) {
|
|
@@ -2358,9 +2492,10 @@ var QueryAstService = class {
|
|
|
2358
2492
|
return acc;
|
|
2359
2493
|
}
|
|
2360
2494
|
const colDef = val;
|
|
2495
|
+
const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
|
|
2361
2496
|
acc.push({
|
|
2362
2497
|
type: "Column",
|
|
2363
|
-
table:
|
|
2498
|
+
table: resolvedTable,
|
|
2364
2499
|
name: colDef.name,
|
|
2365
2500
|
alias
|
|
2366
2501
|
});
|
|
@@ -2375,7 +2510,9 @@ var QueryAstService = class {
|
|
|
2375
2510
|
* @returns Column selection result with updated state and added columns
|
|
2376
2511
|
*/
|
|
2377
2512
|
selectRaw(cols) {
|
|
2378
|
-
const
|
|
2513
|
+
const from = this.state.ast.from;
|
|
2514
|
+
const defaultTable = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2515
|
+
const newCols = cols.map((col) => parseRawColumn(col, defaultTable, this.state.ast.ctes));
|
|
2379
2516
|
const nextState = this.state.withColumns(newCols);
|
|
2380
2517
|
return { state: nextState, addedColumns: newCols };
|
|
2381
2518
|
}
|
|
@@ -2411,6 +2548,14 @@ var QueryAstService = class {
|
|
|
2411
2548
|
};
|
|
2412
2549
|
return this.state.withSetOperation(op);
|
|
2413
2550
|
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Replaces the FROM clause for the current query.
|
|
2553
|
+
* @param from - Table source to use in the FROM clause
|
|
2554
|
+
* @returns Updated query state with new FROM
|
|
2555
|
+
*/
|
|
2556
|
+
withFrom(from) {
|
|
2557
|
+
return this.state.withFrom(from);
|
|
2558
|
+
}
|
|
2414
2559
|
/**
|
|
2415
2560
|
* Selects a subquery as a column
|
|
2416
2561
|
* @param alias - Alias for the subquery
|
|
@@ -2444,7 +2589,9 @@ var QueryAstService = class {
|
|
|
2444
2589
|
* @returns Updated query state with GROUP BY clause
|
|
2445
2590
|
*/
|
|
2446
2591
|
withGroupBy(col) {
|
|
2447
|
-
const
|
|
2592
|
+
const from = this.state.ast.from;
|
|
2593
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
2594
|
+
const node = buildColumnNode(tableRef, col);
|
|
2448
2595
|
return this.state.withGroupBy([node]);
|
|
2449
2596
|
}
|
|
2450
2597
|
/**
|
|
@@ -2463,7 +2610,9 @@ var QueryAstService = class {
|
|
|
2463
2610
|
* @returns Updated query state with ORDER BY clause
|
|
2464
2611
|
*/
|
|
2465
2612
|
withOrderBy(col, direction) {
|
|
2466
|
-
const
|
|
2613
|
+
const from = this.state.ast.from;
|
|
2614
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
2615
|
+
const node = buildColumnNode(tableRef, col);
|
|
2467
2616
|
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
2468
2617
|
}
|
|
2469
2618
|
/**
|
|
@@ -2567,7 +2716,8 @@ var RelationProjectionHelper = class {
|
|
|
2567
2716
|
var assertNever = (value) => {
|
|
2568
2717
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
2569
2718
|
};
|
|
2570
|
-
var baseRelationCondition = (root, relation) => {
|
|
2719
|
+
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
2720
|
+
const rootTable = rootAlias || root.name;
|
|
2571
2721
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
2572
2722
|
const localKey = relation.localKey || defaultLocalKey;
|
|
2573
2723
|
switch (relation.type) {
|
|
@@ -2575,12 +2725,12 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2575
2725
|
case RelationKinds.HasOne:
|
|
2576
2726
|
return eq(
|
|
2577
2727
|
{ type: "Column", table: relation.target.name, name: relation.foreignKey },
|
|
2578
|
-
{ type: "Column", table:
|
|
2728
|
+
{ type: "Column", table: rootTable, name: localKey }
|
|
2579
2729
|
);
|
|
2580
2730
|
case RelationKinds.BelongsTo:
|
|
2581
2731
|
return eq(
|
|
2582
2732
|
{ type: "Column", table: relation.target.name, name: localKey },
|
|
2583
|
-
{ type: "Column", table:
|
|
2733
|
+
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
2584
2734
|
);
|
|
2585
2735
|
case RelationKinds.BelongsToMany:
|
|
2586
2736
|
throw new Error("BelongsToMany relations do not support the standard join condition builder");
|
|
@@ -2588,12 +2738,13 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2588
2738
|
return assertNever(relation);
|
|
2589
2739
|
}
|
|
2590
2740
|
};
|
|
2591
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
|
|
2741
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
2592
2742
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
2593
2743
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
2744
|
+
const rootTable = rootAlias || root.name;
|
|
2594
2745
|
const pivotCondition = eq(
|
|
2595
2746
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
|
|
2596
|
-
{ type: "Column", table:
|
|
2747
|
+
{ type: "Column", table: rootTable, name: rootKey }
|
|
2597
2748
|
);
|
|
2598
2749
|
const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
|
|
2599
2750
|
let targetCondition = eq(
|
|
@@ -2611,12 +2762,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
|
|
|
2611
2762
|
);
|
|
2612
2763
|
return [pivotJoin, targetJoin];
|
|
2613
2764
|
};
|
|
2614
|
-
var buildRelationJoinCondition = (root, relation, extra) => {
|
|
2615
|
-
const base = baseRelationCondition(root, relation);
|
|
2765
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
2766
|
+
const base = baseRelationCondition(root, relation, rootAlias);
|
|
2616
2767
|
return extra ? and(base, extra) : base;
|
|
2617
2768
|
};
|
|
2618
|
-
var buildRelationCorrelation = (root, relation) => {
|
|
2619
|
-
return baseRelationCondition(root, relation);
|
|
2769
|
+
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
2770
|
+
return baseRelationCondition(root, relation, rootAlias);
|
|
2620
2771
|
};
|
|
2621
2772
|
|
|
2622
2773
|
// src/core/ast/join-metadata.ts
|
|
@@ -2660,7 +2811,7 @@ var RelationService = class {
|
|
|
2660
2811
|
match(relationName, predicate) {
|
|
2661
2812
|
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
2662
2813
|
const pk = findPrimaryKey(this.table);
|
|
2663
|
-
const distinctCols = [{ type: "Column", table: this.
|
|
2814
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
2664
2815
|
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
2665
2816
|
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
2666
2817
|
return { state: nextState, hydration: joined.hydration };
|
|
@@ -2747,9 +2898,13 @@ var RelationService = class {
|
|
|
2747
2898
|
* @param ast - Query AST to modify
|
|
2748
2899
|
* @returns Modified query AST with relation correlation
|
|
2749
2900
|
*/
|
|
2750
|
-
applyRelationCorrelation(relationName, ast) {
|
|
2901
|
+
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
2751
2902
|
const relation = this.getRelation(relationName);
|
|
2752
|
-
const
|
|
2903
|
+
const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
|
|
2904
|
+
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
2905
|
+
if (additionalCorrelation) {
|
|
2906
|
+
correlation = and(correlation, additionalCorrelation);
|
|
2907
|
+
}
|
|
2753
2908
|
const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
|
|
2754
2909
|
return {
|
|
2755
2910
|
...ast,
|
|
@@ -2766,17 +2921,19 @@ var RelationService = class {
|
|
|
2766
2921
|
*/
|
|
2767
2922
|
withJoin(state, relationName, joinKind, extraCondition) {
|
|
2768
2923
|
const relation = this.getRelation(relationName);
|
|
2924
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
2769
2925
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
2770
2926
|
const joins = buildBelongsToManyJoins(
|
|
2771
2927
|
this.table,
|
|
2772
2928
|
relationName,
|
|
2773
2929
|
relation,
|
|
2774
2930
|
joinKind,
|
|
2775
|
-
extraCondition
|
|
2931
|
+
extraCondition,
|
|
2932
|
+
rootAlias
|
|
2776
2933
|
);
|
|
2777
2934
|
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
2778
2935
|
}
|
|
2779
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
|
|
2936
|
+
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
2780
2937
|
const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
|
|
2781
2938
|
return this.astService(state).withJoin(joinNode);
|
|
2782
2939
|
}
|
|
@@ -2815,6 +2972,11 @@ var RelationService = class {
|
|
|
2815
2972
|
astService(state = this.state) {
|
|
2816
2973
|
return this.createQueryAstService(this.table, state);
|
|
2817
2974
|
}
|
|
2975
|
+
rootTableName() {
|
|
2976
|
+
const from = this.state.ast.from;
|
|
2977
|
+
if (from.type === "Table" && from.alias) return from.alias;
|
|
2978
|
+
return this.table.name;
|
|
2979
|
+
}
|
|
2818
2980
|
};
|
|
2819
2981
|
|
|
2820
2982
|
// src/query-builder/select-query-builder-deps.ts
|
|
@@ -2889,7 +3051,9 @@ var ColumnSelector = class {
|
|
|
2889
3051
|
* @returns Updated query context with DISTINCT clause
|
|
2890
3052
|
*/
|
|
2891
3053
|
distinct(context, columns) {
|
|
2892
|
-
const
|
|
3054
|
+
const from = context.state.ast.from;
|
|
3055
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
|
|
3056
|
+
const nodes = columns.map((col) => buildColumnNode(tableRef, col));
|
|
2893
3057
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
2894
3058
|
const nextState = astService.withDistinct(nodes);
|
|
2895
3059
|
return { state: nextState, hydration: context.hydration };
|
|
@@ -2946,8 +3110,8 @@ var RelationManager = class {
|
|
|
2946
3110
|
* @param ast - Query AST to modify
|
|
2947
3111
|
* @returns Modified query AST with relation correlation
|
|
2948
3112
|
*/
|
|
2949
|
-
applyRelationCorrelation(context, relationName, ast) {
|
|
2950
|
-
return this.createService(context).applyRelationCorrelation(relationName, ast);
|
|
3113
|
+
applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
|
|
3114
|
+
return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
|
|
2951
3115
|
}
|
|
2952
3116
|
/**
|
|
2953
3117
|
* Creates a relation service instance
|
|
@@ -3994,9 +4158,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
3994
4158
|
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
3995
4159
|
return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
3996
4160
|
}
|
|
4161
|
+
/**
|
|
4162
|
+
* Applies an alias to the root FROM table.
|
|
4163
|
+
* @param alias - Alias to apply
|
|
4164
|
+
*/
|
|
4165
|
+
as(alias) {
|
|
4166
|
+
const from = this.context.state.ast.from;
|
|
4167
|
+
if (from.type !== "Table") {
|
|
4168
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
4169
|
+
}
|
|
4170
|
+
const nextFrom = { ...from, alias };
|
|
4171
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
4172
|
+
return this.clone(nextContext);
|
|
4173
|
+
}
|
|
3997
4174
|
resolveQueryNode(query) {
|
|
3998
4175
|
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
3999
4176
|
}
|
|
4177
|
+
applyCorrelation(ast, correlation) {
|
|
4178
|
+
if (!correlation) return ast;
|
|
4179
|
+
const combinedWhere = ast.where ? and(correlation, ast.where) : correlation;
|
|
4180
|
+
return {
|
|
4181
|
+
...ast,
|
|
4182
|
+
where: combinedWhere
|
|
4183
|
+
};
|
|
4184
|
+
}
|
|
4000
4185
|
createChildBuilder(table) {
|
|
4001
4186
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
4002
4187
|
}
|
|
@@ -4025,6 +4210,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4025
4210
|
select(columns) {
|
|
4026
4211
|
return this.clone(this.columnSelector.select(this.context, columns));
|
|
4027
4212
|
}
|
|
4213
|
+
/**
|
|
4214
|
+
* Selects columns from the root table by name (typed).
|
|
4215
|
+
* @param cols - Column names on the root table
|
|
4216
|
+
*/
|
|
4217
|
+
selectColumns(...cols) {
|
|
4218
|
+
const selection = {};
|
|
4219
|
+
for (const key of cols) {
|
|
4220
|
+
const col = this.env.table.columns[key];
|
|
4221
|
+
if (!col) {
|
|
4222
|
+
throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
|
|
4223
|
+
}
|
|
4224
|
+
selection[key] = col;
|
|
4225
|
+
}
|
|
4226
|
+
return this.select(selection);
|
|
4227
|
+
}
|
|
4028
4228
|
/**
|
|
4029
4229
|
|
|
4030
4230
|
* Selects raw column expressions
|
|
@@ -4073,6 +4273,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4073
4273
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4074
4274
|
return this.clone(nextContext);
|
|
4075
4275
|
}
|
|
4276
|
+
/**
|
|
4277
|
+
* Replaces the FROM clause with a derived table (subquery with alias)
|
|
4278
|
+
* @param subquery - Subquery to use as the FROM source
|
|
4279
|
+
* @param alias - Alias for the derived table
|
|
4280
|
+
* @param columnAliases - Optional column alias list
|
|
4281
|
+
* @returns New query builder instance with updated FROM
|
|
4282
|
+
*/
|
|
4283
|
+
fromSubquery(subquery, alias, columnAliases) {
|
|
4284
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4285
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
4286
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
4287
|
+
return this.clone(nextContext);
|
|
4288
|
+
}
|
|
4076
4289
|
/**
|
|
4077
4290
|
|
|
4078
4291
|
* Selects a subquery as a column
|
|
@@ -4088,6 +4301,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4088
4301
|
const query = this.resolveQueryNode(sub);
|
|
4089
4302
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4090
4303
|
}
|
|
4304
|
+
/**
|
|
4305
|
+
* Adds a JOIN against a derived table (subquery with alias)
|
|
4306
|
+
* @param subquery - Subquery to join
|
|
4307
|
+
* @param alias - Alias for the derived table
|
|
4308
|
+
* @param condition - Join condition expression
|
|
4309
|
+
* @param joinKind - Join kind (defaults to INNER)
|
|
4310
|
+
* @param columnAliases - Optional column alias list for the derived table
|
|
4311
|
+
* @returns New query builder instance with the derived-table join
|
|
4312
|
+
*/
|
|
4313
|
+
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
4314
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4315
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
4316
|
+
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
4317
|
+
return this.clone(nextContext);
|
|
4318
|
+
}
|
|
4091
4319
|
/**
|
|
4092
4320
|
|
|
4093
4321
|
* Adds an INNER JOIN to the query
|
|
@@ -4185,6 +4413,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4185
4413
|
nextLazy.add(relationName);
|
|
4186
4414
|
return this.clone(this.context, nextLazy);
|
|
4187
4415
|
}
|
|
4416
|
+
/**
|
|
4417
|
+
* Selects columns for a related table in a single hop.
|
|
4418
|
+
*/
|
|
4419
|
+
selectRelationColumns(relationName, ...cols) {
|
|
4420
|
+
const relation = this.env.table.relations[relationName];
|
|
4421
|
+
if (!relation) {
|
|
4422
|
+
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4423
|
+
}
|
|
4424
|
+
const target = relation.target;
|
|
4425
|
+
for (const col of cols) {
|
|
4426
|
+
if (!target.columns[col]) {
|
|
4427
|
+
throw new Error(
|
|
4428
|
+
`Column '${col}' not found on related table '${target.name}' for relation '${relationName}'`
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
return this.include(relationName, { columns: cols });
|
|
4433
|
+
}
|
|
4434
|
+
/**
|
|
4435
|
+
* Convenience alias for selecting specific columns from a relation.
|
|
4436
|
+
*/
|
|
4437
|
+
includePick(relationName, cols) {
|
|
4438
|
+
return this.selectRelationColumns(relationName, ...cols);
|
|
4439
|
+
}
|
|
4440
|
+
/**
|
|
4441
|
+
* Selects columns for the root table and relations from a single config object.
|
|
4442
|
+
*/
|
|
4443
|
+
selectColumnsDeep(config) {
|
|
4444
|
+
let qb = this;
|
|
4445
|
+
if (config.root?.length) {
|
|
4446
|
+
qb = qb.selectColumns(...config.root);
|
|
4447
|
+
}
|
|
4448
|
+
for (const key of Object.keys(config)) {
|
|
4449
|
+
if (key === "root") continue;
|
|
4450
|
+
const relName = key;
|
|
4451
|
+
const cols = config[relName];
|
|
4452
|
+
if (!cols || !cols.length) continue;
|
|
4453
|
+
qb = qb.selectRelationColumns(relName, ...cols);
|
|
4454
|
+
}
|
|
4455
|
+
return qb;
|
|
4456
|
+
}
|
|
4188
4457
|
getLazyRelations() {
|
|
4189
4458
|
return Array.from(this.lazyRelations);
|
|
4190
4459
|
}
|
|
@@ -4346,9 +4615,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4346
4615
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4347
4616
|
|
|
4348
4617
|
*/
|
|
4349
|
-
whereExists(subquery) {
|
|
4618
|
+
whereExists(subquery, correlate) {
|
|
4350
4619
|
const subAst = this.resolveQueryNode(subquery);
|
|
4351
|
-
|
|
4620
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4621
|
+
return this.where(exists(correlated));
|
|
4352
4622
|
}
|
|
4353
4623
|
/**
|
|
4354
4624
|
|
|
@@ -4359,9 +4629,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4359
4629
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4360
4630
|
|
|
4361
4631
|
*/
|
|
4362
|
-
whereNotExists(subquery) {
|
|
4632
|
+
whereNotExists(subquery, correlate) {
|
|
4363
4633
|
const subAst = this.resolveQueryNode(subquery);
|
|
4364
|
-
|
|
4634
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4635
|
+
return this.where(notExists(correlated));
|
|
4365
4636
|
}
|
|
4366
4637
|
/**
|
|
4367
4638
|
|
|
@@ -4374,17 +4645,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4374
4645
|
* @returns New query builder instance with the relationship existence check
|
|
4375
4646
|
|
|
4376
4647
|
*/
|
|
4377
|
-
whereHas(relationName,
|
|
4648
|
+
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
4378
4649
|
const relation = this.env.table.relations[relationName];
|
|
4379
4650
|
if (!relation) {
|
|
4380
4651
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4381
4652
|
}
|
|
4653
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4654
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4382
4655
|
let subQb = this.createChildBuilder(relation.target);
|
|
4383
4656
|
if (callback) {
|
|
4384
4657
|
subQb = callback(subQb);
|
|
4385
4658
|
}
|
|
4386
4659
|
const subAst = subQb.getAST();
|
|
4387
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4660
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4388
4661
|
return this.where(exists(finalSubAst));
|
|
4389
4662
|
}
|
|
4390
4663
|
/**
|
|
@@ -4398,17 +4671,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4398
4671
|
* @returns New query builder instance with the relationship non-existence check
|
|
4399
4672
|
|
|
4400
4673
|
*/
|
|
4401
|
-
whereHasNot(relationName,
|
|
4674
|
+
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
4402
4675
|
const relation = this.env.table.relations[relationName];
|
|
4403
4676
|
if (!relation) {
|
|
4404
4677
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4405
4678
|
}
|
|
4679
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4680
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4406
4681
|
let subQb = this.createChildBuilder(relation.target);
|
|
4407
4682
|
if (callback) {
|
|
4408
4683
|
subQb = callback(subQb);
|
|
4409
4684
|
}
|
|
4410
4685
|
const subAst = subQb.getAST();
|
|
4411
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4686
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4412
4687
|
return this.where(notExists(finalSubAst));
|
|
4413
4688
|
}
|
|
4414
4689
|
/**
|