metal-orm 1.0.17 → 1.0.19
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 +4 -3
- package/dist/decorators/index.cjs +192 -46
- 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 +192 -46
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +245 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -29
- package/dist/index.d.ts +16 -29
- package/dist/index.js +243 -66
- package/dist/index.js.map +1 -1
- package/dist/{select-BPCn6MOH.d.cts → select-BuMpVcVt.d.cts} +83 -11
- package/dist/{select-BPCn6MOH.d.ts → select-BuMpVcVt.d.ts} +83 -11
- package/package.json +61 -54
- package/src/codegen/naming-strategy.ts +15 -10
- package/src/core/ast/builders.ts +23 -3
- package/src/core/ast/expression-builders.ts +14 -1
- package/src/core/ast/expression-nodes.ts +11 -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/dialect/base/sql-dialect.ts +58 -46
- package/src/core/dialect/mssql/index.ts +53 -28
- package/src/core/dialect/sqlite/index.ts +22 -13
- package/src/query-builder/column-selector.ts +9 -7
- 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-query-state.ts +19 -7
- package/src/query-builder/select.ts +215 -135
- package/src/schema/column.ts +75 -39
- package/src/schema/types.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a2 as TableHooks, a4 as ColumnType, h as ColumnDef, aV as EntityOrTableTargetResolver, ab as CascadeMode, i as TableDef, aW as EntityConstructor, Z as SelectQueryBuilder } from '../select-BuMpVcVt.cjs';
|
|
2
2
|
|
|
3
3
|
interface EntityOptions {
|
|
4
4
|
tableName?: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a2 as TableHooks, a4 as ColumnType, h as ColumnDef, aV as EntityOrTableTargetResolver, ab as CascadeMode, i as TableDef, aW as EntityConstructor, Z as SelectQueryBuilder } from '../select-BuMpVcVt.js';
|
|
2
2
|
|
|
3
3
|
interface EntityOptions {
|
|
4
4
|
tableName?: string;
|
package/dist/decorators/index.js
CHANGED
|
@@ -390,6 +390,26 @@ var avg = buildAggregate("AVG");
|
|
|
390
390
|
var min = buildAggregate("MIN");
|
|
391
391
|
var max = buildAggregate("MAX");
|
|
392
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
|
+
});
|
|
412
|
+
|
|
393
413
|
// src/core/functions/standard-strategy.ts
|
|
394
414
|
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
395
415
|
constructor() {
|
|
@@ -1079,7 +1099,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1079
1099
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1080
1100
|
}
|
|
1081
1101
|
compileInsertColumnList(columns) {
|
|
1082
|
-
return columns.map((column) =>
|
|
1102
|
+
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1083
1103
|
}
|
|
1084
1104
|
compileInsertValues(values, ctx) {
|
|
1085
1105
|
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
@@ -1105,7 +1125,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1105
1125
|
compileUpdateAssignments(assignments, ctx) {
|
|
1106
1126
|
return assignments.map((assignment) => {
|
|
1107
1127
|
const col = assignment.column;
|
|
1108
|
-
const target =
|
|
1128
|
+
const target = this.quoteIdentifier(col.name);
|
|
1109
1129
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1110
1130
|
return `${target} = ${value}`;
|
|
1111
1131
|
}).join(", ");
|
|
@@ -1137,12 +1157,29 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1137
1157
|
if (tableSource.type === "FunctionTable") {
|
|
1138
1158
|
return this.compileFunctionTable(tableSource, ctx);
|
|
1139
1159
|
}
|
|
1160
|
+
if (tableSource.type === "DerivedTable") {
|
|
1161
|
+
return this.compileDerivedTable(tableSource, ctx);
|
|
1162
|
+
}
|
|
1140
1163
|
return this.compileTableSource(tableSource);
|
|
1141
1164
|
}
|
|
1142
1165
|
compileFunctionTable(fn, ctx) {
|
|
1143
1166
|
return FunctionTableFormatter.format(fn, ctx, this);
|
|
1144
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
|
+
}
|
|
1145
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
|
+
}
|
|
1146
1183
|
const base = this.compileTableName(table);
|
|
1147
1184
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1148
1185
|
}
|
|
@@ -1531,6 +1568,12 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
1531
1568
|
const columns = this.formatReturningColumns(returning);
|
|
1532
1569
|
return ` RETURNING ${columns}`;
|
|
1533
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
|
+
}
|
|
1534
1577
|
supportsReturning() {
|
|
1535
1578
|
return true;
|
|
1536
1579
|
}
|
|
@@ -1697,6 +1740,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1697
1740
|
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
1698
1741
|
}
|
|
1699
1742
|
compileDeleteAst(ast, ctx) {
|
|
1743
|
+
if (ast.from.type !== "Table") {
|
|
1744
|
+
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
1745
|
+
}
|
|
1700
1746
|
const table = this.quoteIdentifier(ast.from.name);
|
|
1701
1747
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1702
1748
|
return `DELETE FROM ${table}${whereClause};`;
|
|
@@ -1720,9 +1766,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1720
1766
|
return expr;
|
|
1721
1767
|
}).join(", ");
|
|
1722
1768
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
1723
|
-
const from =
|
|
1769
|
+
const from = this.compileTableSource(ast.from, ctx);
|
|
1724
1770
|
const joins = ast.joins.map((j) => {
|
|
1725
|
-
const table = this.
|
|
1771
|
+
const table = this.compileTableSource(j.table, ctx);
|
|
1726
1772
|
const cond = this.compileExpression(j.condition, ctx);
|
|
1727
1773
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
1728
1774
|
}).join(" ");
|
|
@@ -1752,6 +1798,21 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1752
1798
|
}
|
|
1753
1799
|
return pagination;
|
|
1754
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
|
+
}
|
|
1755
1816
|
compileCtes(ast, ctx) {
|
|
1756
1817
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
1757
1818
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -1880,6 +1941,17 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
1880
1941
|
joins: [...this.ast.joins ?? [], join]
|
|
1881
1942
|
});
|
|
1882
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
|
+
}
|
|
1883
1955
|
/**
|
|
1884
1956
|
* Adds a WHERE clause to the query
|
|
1885
1957
|
* @param predicate - WHERE predicate expression
|
|
@@ -2372,19 +2444,6 @@ var buildDefaultHydrationPlan = (table) => ({
|
|
|
2372
2444
|
relations: []
|
|
2373
2445
|
});
|
|
2374
2446
|
|
|
2375
|
-
// src/core/ast/builders.ts
|
|
2376
|
-
var buildColumnNode = (table, column) => {
|
|
2377
|
-
if (column.type === "Column") {
|
|
2378
|
-
return column;
|
|
2379
|
-
}
|
|
2380
|
-
const def = column;
|
|
2381
|
-
return {
|
|
2382
|
-
type: "Column",
|
|
2383
|
-
table: def.table || table.name,
|
|
2384
|
-
name: def.name
|
|
2385
|
-
};
|
|
2386
|
-
};
|
|
2387
|
-
|
|
2388
2447
|
// src/query-builder/raw-column-parser.ts
|
|
2389
2448
|
var parseRawColumn = (col, tableName, ctes) => {
|
|
2390
2449
|
if (col.includes("(")) {
|
|
@@ -2424,6 +2483,8 @@ var QueryAstService = class {
|
|
|
2424
2483
|
const existingAliases = new Set(
|
|
2425
2484
|
this.state.ast.columns.map((c) => c.alias || c.name)
|
|
2426
2485
|
);
|
|
2486
|
+
const from = this.state.ast.from;
|
|
2487
|
+
const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2427
2488
|
const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
|
|
2428
2489
|
if (existingAliases.has(alias)) return acc;
|
|
2429
2490
|
if (isExpressionSelectionNode(val)) {
|
|
@@ -2431,9 +2492,10 @@ var QueryAstService = class {
|
|
|
2431
2492
|
return acc;
|
|
2432
2493
|
}
|
|
2433
2494
|
const colDef = val;
|
|
2495
|
+
const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
|
|
2434
2496
|
acc.push({
|
|
2435
2497
|
type: "Column",
|
|
2436
|
-
table:
|
|
2498
|
+
table: resolvedTable,
|
|
2437
2499
|
name: colDef.name,
|
|
2438
2500
|
alias
|
|
2439
2501
|
});
|
|
@@ -2448,7 +2510,9 @@ var QueryAstService = class {
|
|
|
2448
2510
|
* @returns Column selection result with updated state and added columns
|
|
2449
2511
|
*/
|
|
2450
2512
|
selectRaw(cols) {
|
|
2451
|
-
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));
|
|
2452
2516
|
const nextState = this.state.withColumns(newCols);
|
|
2453
2517
|
return { state: nextState, addedColumns: newCols };
|
|
2454
2518
|
}
|
|
@@ -2484,6 +2548,14 @@ var QueryAstService = class {
|
|
|
2484
2548
|
};
|
|
2485
2549
|
return this.state.withSetOperation(op);
|
|
2486
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
|
+
}
|
|
2487
2559
|
/**
|
|
2488
2560
|
* Selects a subquery as a column
|
|
2489
2561
|
* @param alias - Alias for the subquery
|
|
@@ -2517,7 +2589,9 @@ var QueryAstService = class {
|
|
|
2517
2589
|
* @returns Updated query state with GROUP BY clause
|
|
2518
2590
|
*/
|
|
2519
2591
|
withGroupBy(col) {
|
|
2520
|
-
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);
|
|
2521
2595
|
return this.state.withGroupBy([node]);
|
|
2522
2596
|
}
|
|
2523
2597
|
/**
|
|
@@ -2536,7 +2610,9 @@ var QueryAstService = class {
|
|
|
2536
2610
|
* @returns Updated query state with ORDER BY clause
|
|
2537
2611
|
*/
|
|
2538
2612
|
withOrderBy(col, direction) {
|
|
2539
|
-
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);
|
|
2540
2616
|
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
2541
2617
|
}
|
|
2542
2618
|
/**
|
|
@@ -2640,7 +2716,8 @@ var RelationProjectionHelper = class {
|
|
|
2640
2716
|
var assertNever = (value) => {
|
|
2641
2717
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
2642
2718
|
};
|
|
2643
|
-
var baseRelationCondition = (root, relation) => {
|
|
2719
|
+
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
2720
|
+
const rootTable = rootAlias || root.name;
|
|
2644
2721
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
2645
2722
|
const localKey = relation.localKey || defaultLocalKey;
|
|
2646
2723
|
switch (relation.type) {
|
|
@@ -2648,12 +2725,12 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2648
2725
|
case RelationKinds.HasOne:
|
|
2649
2726
|
return eq(
|
|
2650
2727
|
{ type: "Column", table: relation.target.name, name: relation.foreignKey },
|
|
2651
|
-
{ type: "Column", table:
|
|
2728
|
+
{ type: "Column", table: rootTable, name: localKey }
|
|
2652
2729
|
);
|
|
2653
2730
|
case RelationKinds.BelongsTo:
|
|
2654
2731
|
return eq(
|
|
2655
2732
|
{ type: "Column", table: relation.target.name, name: localKey },
|
|
2656
|
-
{ type: "Column", table:
|
|
2733
|
+
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
2657
2734
|
);
|
|
2658
2735
|
case RelationKinds.BelongsToMany:
|
|
2659
2736
|
throw new Error("BelongsToMany relations do not support the standard join condition builder");
|
|
@@ -2661,12 +2738,13 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2661
2738
|
return assertNever(relation);
|
|
2662
2739
|
}
|
|
2663
2740
|
};
|
|
2664
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
|
|
2741
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
2665
2742
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
2666
2743
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
2744
|
+
const rootTable = rootAlias || root.name;
|
|
2667
2745
|
const pivotCondition = eq(
|
|
2668
2746
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
|
|
2669
|
-
{ type: "Column", table:
|
|
2747
|
+
{ type: "Column", table: rootTable, name: rootKey }
|
|
2670
2748
|
);
|
|
2671
2749
|
const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
|
|
2672
2750
|
let targetCondition = eq(
|
|
@@ -2684,12 +2762,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
|
|
|
2684
2762
|
);
|
|
2685
2763
|
return [pivotJoin, targetJoin];
|
|
2686
2764
|
};
|
|
2687
|
-
var buildRelationJoinCondition = (root, relation, extra) => {
|
|
2688
|
-
const base = baseRelationCondition(root, relation);
|
|
2765
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
2766
|
+
const base = baseRelationCondition(root, relation, rootAlias);
|
|
2689
2767
|
return extra ? and(base, extra) : base;
|
|
2690
2768
|
};
|
|
2691
|
-
var buildRelationCorrelation = (root, relation) => {
|
|
2692
|
-
return baseRelationCondition(root, relation);
|
|
2769
|
+
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
2770
|
+
return baseRelationCondition(root, relation, rootAlias);
|
|
2693
2771
|
};
|
|
2694
2772
|
|
|
2695
2773
|
// src/core/ast/join-metadata.ts
|
|
@@ -2733,7 +2811,7 @@ var RelationService = class {
|
|
|
2733
2811
|
match(relationName, predicate) {
|
|
2734
2812
|
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
2735
2813
|
const pk = findPrimaryKey(this.table);
|
|
2736
|
-
const distinctCols = [{ type: "Column", table: this.
|
|
2814
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
2737
2815
|
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
2738
2816
|
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
2739
2817
|
return { state: nextState, hydration: joined.hydration };
|
|
@@ -2820,9 +2898,13 @@ var RelationService = class {
|
|
|
2820
2898
|
* @param ast - Query AST to modify
|
|
2821
2899
|
* @returns Modified query AST with relation correlation
|
|
2822
2900
|
*/
|
|
2823
|
-
applyRelationCorrelation(relationName, ast) {
|
|
2901
|
+
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
2824
2902
|
const relation = this.getRelation(relationName);
|
|
2825
|
-
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
|
+
}
|
|
2826
2908
|
const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
|
|
2827
2909
|
return {
|
|
2828
2910
|
...ast,
|
|
@@ -2839,17 +2921,19 @@ var RelationService = class {
|
|
|
2839
2921
|
*/
|
|
2840
2922
|
withJoin(state, relationName, joinKind, extraCondition) {
|
|
2841
2923
|
const relation = this.getRelation(relationName);
|
|
2924
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
2842
2925
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
2843
2926
|
const joins = buildBelongsToManyJoins(
|
|
2844
2927
|
this.table,
|
|
2845
2928
|
relationName,
|
|
2846
2929
|
relation,
|
|
2847
2930
|
joinKind,
|
|
2848
|
-
extraCondition
|
|
2931
|
+
extraCondition,
|
|
2932
|
+
rootAlias
|
|
2849
2933
|
);
|
|
2850
2934
|
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
2851
2935
|
}
|
|
2852
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
|
|
2936
|
+
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
2853
2937
|
const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
|
|
2854
2938
|
return this.astService(state).withJoin(joinNode);
|
|
2855
2939
|
}
|
|
@@ -2888,6 +2972,11 @@ var RelationService = class {
|
|
|
2888
2972
|
astService(state = this.state) {
|
|
2889
2973
|
return this.createQueryAstService(this.table, state);
|
|
2890
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
|
+
}
|
|
2891
2980
|
};
|
|
2892
2981
|
|
|
2893
2982
|
// src/query-builder/select-query-builder-deps.ts
|
|
@@ -2962,7 +3051,9 @@ var ColumnSelector = class {
|
|
|
2962
3051
|
* @returns Updated query context with DISTINCT clause
|
|
2963
3052
|
*/
|
|
2964
3053
|
distinct(context, columns) {
|
|
2965
|
-
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));
|
|
2966
3057
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
2967
3058
|
const nextState = astService.withDistinct(nodes);
|
|
2968
3059
|
return { state: nextState, hydration: context.hydration };
|
|
@@ -3019,8 +3110,8 @@ var RelationManager = class {
|
|
|
3019
3110
|
* @param ast - Query AST to modify
|
|
3020
3111
|
* @returns Modified query AST with relation correlation
|
|
3021
3112
|
*/
|
|
3022
|
-
applyRelationCorrelation(context, relationName, ast) {
|
|
3023
|
-
return this.createService(context).applyRelationCorrelation(relationName, ast);
|
|
3113
|
+
applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
|
|
3114
|
+
return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
|
|
3024
3115
|
}
|
|
3025
3116
|
/**
|
|
3026
3117
|
* Creates a relation service instance
|
|
@@ -4067,9 +4158,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4067
4158
|
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
4068
4159
|
return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
4069
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
|
+
}
|
|
4070
4174
|
resolveQueryNode(query) {
|
|
4071
4175
|
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
4072
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
|
+
}
|
|
4073
4185
|
createChildBuilder(table) {
|
|
4074
4186
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
4075
4187
|
}
|
|
@@ -4161,6 +4273,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4161
4273
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4162
4274
|
return this.clone(nextContext);
|
|
4163
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
|
+
}
|
|
4164
4289
|
/**
|
|
4165
4290
|
|
|
4166
4291
|
* Selects a subquery as a column
|
|
@@ -4176,6 +4301,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4176
4301
|
const query = this.resolveQueryNode(sub);
|
|
4177
4302
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4178
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
|
+
}
|
|
4179
4319
|
/**
|
|
4180
4320
|
|
|
4181
4321
|
* Adds an INNER JOIN to the query
|
|
@@ -4475,9 +4615,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4475
4615
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4476
4616
|
|
|
4477
4617
|
*/
|
|
4478
|
-
whereExists(subquery) {
|
|
4618
|
+
whereExists(subquery, correlate) {
|
|
4479
4619
|
const subAst = this.resolveQueryNode(subquery);
|
|
4480
|
-
|
|
4620
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4621
|
+
return this.where(exists(correlated));
|
|
4481
4622
|
}
|
|
4482
4623
|
/**
|
|
4483
4624
|
|
|
@@ -4488,9 +4629,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4488
4629
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4489
4630
|
|
|
4490
4631
|
*/
|
|
4491
|
-
whereNotExists(subquery) {
|
|
4632
|
+
whereNotExists(subquery, correlate) {
|
|
4492
4633
|
const subAst = this.resolveQueryNode(subquery);
|
|
4493
|
-
|
|
4634
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4635
|
+
return this.where(notExists(correlated));
|
|
4494
4636
|
}
|
|
4495
4637
|
/**
|
|
4496
4638
|
|
|
@@ -4503,17 +4645,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4503
4645
|
* @returns New query builder instance with the relationship existence check
|
|
4504
4646
|
|
|
4505
4647
|
*/
|
|
4506
|
-
whereHas(relationName,
|
|
4648
|
+
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
4507
4649
|
const relation = this.env.table.relations[relationName];
|
|
4508
4650
|
if (!relation) {
|
|
4509
4651
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4510
4652
|
}
|
|
4653
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4654
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4511
4655
|
let subQb = this.createChildBuilder(relation.target);
|
|
4512
4656
|
if (callback) {
|
|
4513
4657
|
subQb = callback(subQb);
|
|
4514
4658
|
}
|
|
4515
4659
|
const subAst = subQb.getAST();
|
|
4516
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4660
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4517
4661
|
return this.where(exists(finalSubAst));
|
|
4518
4662
|
}
|
|
4519
4663
|
/**
|
|
@@ -4527,17 +4671,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4527
4671
|
* @returns New query builder instance with the relationship non-existence check
|
|
4528
4672
|
|
|
4529
4673
|
*/
|
|
4530
|
-
whereHasNot(relationName,
|
|
4674
|
+
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
4531
4675
|
const relation = this.env.table.relations[relationName];
|
|
4532
4676
|
if (!relation) {
|
|
4533
4677
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4534
4678
|
}
|
|
4679
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4680
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4535
4681
|
let subQb = this.createChildBuilder(relation.target);
|
|
4536
4682
|
if (callback) {
|
|
4537
4683
|
subQb = callback(subQb);
|
|
4538
4684
|
}
|
|
4539
4685
|
const subAst = subQb.getAST();
|
|
4540
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4686
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4541
4687
|
return this.where(notExists(finalSubAst));
|
|
4542
4688
|
}
|
|
4543
4689
|
/**
|