metal-orm 1.0.17 → 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 +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 +4 -1
- 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
package/dist/index.js
CHANGED
|
@@ -88,6 +88,30 @@ var col = {
|
|
|
88
88
|
* Creates a UUID column definition
|
|
89
89
|
*/
|
|
90
90
|
uuid: () => ({ name: "", type: "UUID" }),
|
|
91
|
+
/**
|
|
92
|
+
* Creates a binary large object column definition
|
|
93
|
+
*/
|
|
94
|
+
blob: () => ({ name: "", type: "BLOB" }),
|
|
95
|
+
/**
|
|
96
|
+
* Creates a fixed-length binary column definition
|
|
97
|
+
*/
|
|
98
|
+
binary: (length2) => ({
|
|
99
|
+
name: "",
|
|
100
|
+
type: "BINARY",
|
|
101
|
+
args: length2 !== void 0 ? [length2] : void 0
|
|
102
|
+
}),
|
|
103
|
+
/**
|
|
104
|
+
* Creates a variable-length binary column definition
|
|
105
|
+
*/
|
|
106
|
+
varbinary: (length2) => ({
|
|
107
|
+
name: "",
|
|
108
|
+
type: "VARBINARY",
|
|
109
|
+
args: length2 !== void 0 ? [length2] : void 0
|
|
110
|
+
}),
|
|
111
|
+
/**
|
|
112
|
+
* Creates a Postgres bytea column definition
|
|
113
|
+
*/
|
|
114
|
+
bytea: () => ({ name: "", type: "BYTEA" }),
|
|
91
115
|
/**
|
|
92
116
|
* Creates a timestamp column definition
|
|
93
117
|
*/
|
|
@@ -263,6 +287,11 @@ var toOperand = (val) => {
|
|
|
263
287
|
return toNode(val);
|
|
264
288
|
};
|
|
265
289
|
var columnOperand = (col2) => toNode(col2);
|
|
290
|
+
var outerRef = (col2) => ({
|
|
291
|
+
...columnOperand(col2),
|
|
292
|
+
scope: "outer"
|
|
293
|
+
});
|
|
294
|
+
var correlateBy = (table, column) => outerRef({ name: column, table });
|
|
266
295
|
var createBinaryExpression = (operator, left2, right2, escape) => {
|
|
267
296
|
const node = {
|
|
268
297
|
type: "BinaryExpression",
|
|
@@ -573,6 +602,45 @@ var toTableRef = (table) => ({
|
|
|
573
602
|
alias: table.alias
|
|
574
603
|
});
|
|
575
604
|
|
|
605
|
+
// src/core/ast/builders.ts
|
|
606
|
+
var buildColumnNode = (table, column) => {
|
|
607
|
+
if (column.type === "Column") {
|
|
608
|
+
return column;
|
|
609
|
+
}
|
|
610
|
+
const def = column;
|
|
611
|
+
const baseTable = def.table ? table.alias && def.table === table.name ? table.alias : def.table : table.alias || table.name;
|
|
612
|
+
return {
|
|
613
|
+
type: "Column",
|
|
614
|
+
table: baseTable,
|
|
615
|
+
name: def.name
|
|
616
|
+
};
|
|
617
|
+
};
|
|
618
|
+
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
619
|
+
type: "Column",
|
|
620
|
+
table: table.alias || table.name,
|
|
621
|
+
name
|
|
622
|
+
}));
|
|
623
|
+
var createTableNode = (table) => ({
|
|
624
|
+
type: "Table",
|
|
625
|
+
name: table.name
|
|
626
|
+
});
|
|
627
|
+
var fnTable = (name, args = [], alias, opts) => ({
|
|
628
|
+
type: "FunctionTable",
|
|
629
|
+
name,
|
|
630
|
+
args,
|
|
631
|
+
alias,
|
|
632
|
+
lateral: opts?.lateral,
|
|
633
|
+
withOrdinality: opts?.withOrdinality,
|
|
634
|
+
columnAliases: opts?.columnAliases,
|
|
635
|
+
schema: opts?.schema
|
|
636
|
+
});
|
|
637
|
+
var derivedTable = (query, alias, columnAliases) => ({
|
|
638
|
+
type: "DerivedTable",
|
|
639
|
+
query,
|
|
640
|
+
alias,
|
|
641
|
+
columnAliases
|
|
642
|
+
});
|
|
643
|
+
|
|
576
644
|
// src/core/functions/standard-strategy.ts
|
|
577
645
|
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
578
646
|
constructor() {
|
|
@@ -1262,7 +1330,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1262
1330
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1263
1331
|
}
|
|
1264
1332
|
compileInsertColumnList(columns) {
|
|
1265
|
-
return columns.map((column) =>
|
|
1333
|
+
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1266
1334
|
}
|
|
1267
1335
|
compileInsertValues(values, ctx) {
|
|
1268
1336
|
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
@@ -1288,7 +1356,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1288
1356
|
compileUpdateAssignments(assignments, ctx) {
|
|
1289
1357
|
return assignments.map((assignment) => {
|
|
1290
1358
|
const col2 = assignment.column;
|
|
1291
|
-
const target =
|
|
1359
|
+
const target = this.quoteIdentifier(col2.name);
|
|
1292
1360
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1293
1361
|
return `${target} = ${value}`;
|
|
1294
1362
|
}).join(", ");
|
|
@@ -1320,12 +1388,29 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1320
1388
|
if (tableSource.type === "FunctionTable") {
|
|
1321
1389
|
return this.compileFunctionTable(tableSource, ctx);
|
|
1322
1390
|
}
|
|
1391
|
+
if (tableSource.type === "DerivedTable") {
|
|
1392
|
+
return this.compileDerivedTable(tableSource, ctx);
|
|
1393
|
+
}
|
|
1323
1394
|
return this.compileTableSource(tableSource);
|
|
1324
1395
|
}
|
|
1325
1396
|
compileFunctionTable(fn4, ctx) {
|
|
1326
1397
|
return FunctionTableFormatter.format(fn4, ctx, this);
|
|
1327
1398
|
}
|
|
1399
|
+
compileDerivedTable(table, ctx) {
|
|
1400
|
+
if (!table.alias) {
|
|
1401
|
+
throw new Error("Derived tables must have an alias.");
|
|
1402
|
+
}
|
|
1403
|
+
const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
1404
|
+
const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
1405
|
+
return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
|
|
1406
|
+
}
|
|
1328
1407
|
compileTableSource(table) {
|
|
1408
|
+
if (table.type === "FunctionTable") {
|
|
1409
|
+
return this.compileFunctionTable(table);
|
|
1410
|
+
}
|
|
1411
|
+
if (table.type === "DerivedTable") {
|
|
1412
|
+
return this.compileDerivedTable(table);
|
|
1413
|
+
}
|
|
1329
1414
|
const base = this.compileTableName(table);
|
|
1330
1415
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1331
1416
|
}
|
|
@@ -1714,6 +1799,12 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
1714
1799
|
const columns = this.formatReturningColumns(returning);
|
|
1715
1800
|
return ` RETURNING ${columns}`;
|
|
1716
1801
|
}
|
|
1802
|
+
formatReturningColumns(returning) {
|
|
1803
|
+
return returning.map((column) => {
|
|
1804
|
+
const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
|
|
1805
|
+
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
1806
|
+
}).join(", ");
|
|
1807
|
+
}
|
|
1717
1808
|
supportsReturning() {
|
|
1718
1809
|
return true;
|
|
1719
1810
|
}
|
|
@@ -1880,6 +1971,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1880
1971
|
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
1881
1972
|
}
|
|
1882
1973
|
compileDeleteAst(ast, ctx) {
|
|
1974
|
+
if (ast.from.type !== "Table") {
|
|
1975
|
+
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
1976
|
+
}
|
|
1883
1977
|
const table = this.quoteIdentifier(ast.from.name);
|
|
1884
1978
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1885
1979
|
return `DELETE FROM ${table}${whereClause};`;
|
|
@@ -1903,9 +1997,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1903
1997
|
return expr;
|
|
1904
1998
|
}).join(", ");
|
|
1905
1999
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
1906
|
-
const from =
|
|
2000
|
+
const from = this.compileTableSource(ast.from, ctx);
|
|
1907
2001
|
const joins = ast.joins.map((j) => {
|
|
1908
|
-
const table = this.
|
|
2002
|
+
const table = this.compileTableSource(j.table, ctx);
|
|
1909
2003
|
const cond = this.compileExpression(j.condition, ctx);
|
|
1910
2004
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
1911
2005
|
}).join(" ");
|
|
@@ -1935,6 +2029,21 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1935
2029
|
}
|
|
1936
2030
|
return pagination;
|
|
1937
2031
|
}
|
|
2032
|
+
compileTableSource(table, ctx) {
|
|
2033
|
+
if (table.type === "FunctionTable") {
|
|
2034
|
+
return FunctionTableFormatter.format(table, ctx, this);
|
|
2035
|
+
}
|
|
2036
|
+
if (table.type === "DerivedTable") {
|
|
2037
|
+
return this.compileDerivedTable(table, ctx);
|
|
2038
|
+
}
|
|
2039
|
+
const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
|
|
2040
|
+
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2041
|
+
}
|
|
2042
|
+
compileDerivedTable(table, ctx) {
|
|
2043
|
+
const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2044
|
+
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2045
|
+
return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
2046
|
+
}
|
|
1938
2047
|
compileCtes(ast, ctx) {
|
|
1939
2048
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
1940
2049
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -2063,6 +2172,17 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
2063
2172
|
joins: [...this.ast.joins ?? [], join]
|
|
2064
2173
|
});
|
|
2065
2174
|
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Replaces the FROM clause.
|
|
2177
|
+
* @param from - Table source for the FROM clause
|
|
2178
|
+
* @returns New SelectQueryState with updated FROM
|
|
2179
|
+
*/
|
|
2180
|
+
withFrom(from) {
|
|
2181
|
+
return this.clone({
|
|
2182
|
+
...this.ast,
|
|
2183
|
+
from
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2066
2186
|
/**
|
|
2067
2187
|
* Adds a WHERE clause to the query
|
|
2068
2188
|
* @param predicate - WHERE predicate expression
|
|
@@ -2555,38 +2675,6 @@ var buildDefaultHydrationPlan = (table) => ({
|
|
|
2555
2675
|
relations: []
|
|
2556
2676
|
});
|
|
2557
2677
|
|
|
2558
|
-
// src/core/ast/builders.ts
|
|
2559
|
-
var buildColumnNode = (table, column) => {
|
|
2560
|
-
if (column.type === "Column") {
|
|
2561
|
-
return column;
|
|
2562
|
-
}
|
|
2563
|
-
const def = column;
|
|
2564
|
-
return {
|
|
2565
|
-
type: "Column",
|
|
2566
|
-
table: def.table || table.name,
|
|
2567
|
-
name: def.name
|
|
2568
|
-
};
|
|
2569
|
-
};
|
|
2570
|
-
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
2571
|
-
type: "Column",
|
|
2572
|
-
table: table.name,
|
|
2573
|
-
name
|
|
2574
|
-
}));
|
|
2575
|
-
var createTableNode = (table) => ({
|
|
2576
|
-
type: "Table",
|
|
2577
|
-
name: table.name
|
|
2578
|
-
});
|
|
2579
|
-
var fnTable = (name, args = [], alias, opts) => ({
|
|
2580
|
-
type: "FunctionTable",
|
|
2581
|
-
name,
|
|
2582
|
-
args,
|
|
2583
|
-
alias,
|
|
2584
|
-
lateral: opts?.lateral,
|
|
2585
|
-
withOrdinality: opts?.withOrdinality,
|
|
2586
|
-
columnAliases: opts?.columnAliases,
|
|
2587
|
-
schema: opts?.schema
|
|
2588
|
-
});
|
|
2589
|
-
|
|
2590
2678
|
// src/query-builder/raw-column-parser.ts
|
|
2591
2679
|
var parseRawColumn = (col2, tableName, ctes) => {
|
|
2592
2680
|
if (col2.includes("(")) {
|
|
@@ -2626,6 +2714,8 @@ var QueryAstService = class {
|
|
|
2626
2714
|
const existingAliases = new Set(
|
|
2627
2715
|
this.state.ast.columns.map((c) => c.alias || c.name)
|
|
2628
2716
|
);
|
|
2717
|
+
const from = this.state.ast.from;
|
|
2718
|
+
const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2629
2719
|
const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
|
|
2630
2720
|
if (existingAliases.has(alias)) return acc;
|
|
2631
2721
|
if (isExpressionSelectionNode(val)) {
|
|
@@ -2633,9 +2723,10 @@ var QueryAstService = class {
|
|
|
2633
2723
|
return acc;
|
|
2634
2724
|
}
|
|
2635
2725
|
const colDef = val;
|
|
2726
|
+
const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
|
|
2636
2727
|
acc.push({
|
|
2637
2728
|
type: "Column",
|
|
2638
|
-
table:
|
|
2729
|
+
table: resolvedTable,
|
|
2639
2730
|
name: colDef.name,
|
|
2640
2731
|
alias
|
|
2641
2732
|
});
|
|
@@ -2650,7 +2741,9 @@ var QueryAstService = class {
|
|
|
2650
2741
|
* @returns Column selection result with updated state and added columns
|
|
2651
2742
|
*/
|
|
2652
2743
|
selectRaw(cols) {
|
|
2653
|
-
const
|
|
2744
|
+
const from = this.state.ast.from;
|
|
2745
|
+
const defaultTable = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2746
|
+
const newCols = cols.map((col2) => parseRawColumn(col2, defaultTable, this.state.ast.ctes));
|
|
2654
2747
|
const nextState = this.state.withColumns(newCols);
|
|
2655
2748
|
return { state: nextState, addedColumns: newCols };
|
|
2656
2749
|
}
|
|
@@ -2686,6 +2779,14 @@ var QueryAstService = class {
|
|
|
2686
2779
|
};
|
|
2687
2780
|
return this.state.withSetOperation(op);
|
|
2688
2781
|
}
|
|
2782
|
+
/**
|
|
2783
|
+
* Replaces the FROM clause for the current query.
|
|
2784
|
+
* @param from - Table source to use in the FROM clause
|
|
2785
|
+
* @returns Updated query state with new FROM
|
|
2786
|
+
*/
|
|
2787
|
+
withFrom(from) {
|
|
2788
|
+
return this.state.withFrom(from);
|
|
2789
|
+
}
|
|
2689
2790
|
/**
|
|
2690
2791
|
* Selects a subquery as a column
|
|
2691
2792
|
* @param alias - Alias for the subquery
|
|
@@ -2719,7 +2820,9 @@ var QueryAstService = class {
|
|
|
2719
2820
|
* @returns Updated query state with GROUP BY clause
|
|
2720
2821
|
*/
|
|
2721
2822
|
withGroupBy(col2) {
|
|
2722
|
-
const
|
|
2823
|
+
const from = this.state.ast.from;
|
|
2824
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
2825
|
+
const node = buildColumnNode(tableRef, col2);
|
|
2723
2826
|
return this.state.withGroupBy([node]);
|
|
2724
2827
|
}
|
|
2725
2828
|
/**
|
|
@@ -2738,7 +2841,9 @@ var QueryAstService = class {
|
|
|
2738
2841
|
* @returns Updated query state with ORDER BY clause
|
|
2739
2842
|
*/
|
|
2740
2843
|
withOrderBy(col2, direction) {
|
|
2741
|
-
const
|
|
2844
|
+
const from = this.state.ast.from;
|
|
2845
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
2846
|
+
const node = buildColumnNode(tableRef, col2);
|
|
2742
2847
|
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
2743
2848
|
}
|
|
2744
2849
|
/**
|
|
@@ -2842,7 +2947,8 @@ var RelationProjectionHelper = class {
|
|
|
2842
2947
|
var assertNever = (value) => {
|
|
2843
2948
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
2844
2949
|
};
|
|
2845
|
-
var baseRelationCondition = (root, relation) => {
|
|
2950
|
+
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
2951
|
+
const rootTable = rootAlias || root.name;
|
|
2846
2952
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
2847
2953
|
const localKey = relation.localKey || defaultLocalKey;
|
|
2848
2954
|
switch (relation.type) {
|
|
@@ -2850,12 +2956,12 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2850
2956
|
case RelationKinds.HasOne:
|
|
2851
2957
|
return eq(
|
|
2852
2958
|
{ type: "Column", table: relation.target.name, name: relation.foreignKey },
|
|
2853
|
-
{ type: "Column", table:
|
|
2959
|
+
{ type: "Column", table: rootTable, name: localKey }
|
|
2854
2960
|
);
|
|
2855
2961
|
case RelationKinds.BelongsTo:
|
|
2856
2962
|
return eq(
|
|
2857
2963
|
{ type: "Column", table: relation.target.name, name: localKey },
|
|
2858
|
-
{ type: "Column", table:
|
|
2964
|
+
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
2859
2965
|
);
|
|
2860
2966
|
case RelationKinds.BelongsToMany:
|
|
2861
2967
|
throw new Error("BelongsToMany relations do not support the standard join condition builder");
|
|
@@ -2863,12 +2969,13 @@ var baseRelationCondition = (root, relation) => {
|
|
|
2863
2969
|
return assertNever(relation);
|
|
2864
2970
|
}
|
|
2865
2971
|
};
|
|
2866
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
|
|
2972
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
2867
2973
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
2868
2974
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
2975
|
+
const rootTable = rootAlias || root.name;
|
|
2869
2976
|
const pivotCondition = eq(
|
|
2870
2977
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
|
|
2871
|
-
{ type: "Column", table:
|
|
2978
|
+
{ type: "Column", table: rootTable, name: rootKey }
|
|
2872
2979
|
);
|
|
2873
2980
|
const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
|
|
2874
2981
|
let targetCondition = eq(
|
|
@@ -2886,12 +2993,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
|
|
|
2886
2993
|
);
|
|
2887
2994
|
return [pivotJoin, targetJoin];
|
|
2888
2995
|
};
|
|
2889
|
-
var buildRelationJoinCondition = (root, relation, extra) => {
|
|
2890
|
-
const base = baseRelationCondition(root, relation);
|
|
2996
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
2997
|
+
const base = baseRelationCondition(root, relation, rootAlias);
|
|
2891
2998
|
return extra ? and(base, extra) : base;
|
|
2892
2999
|
};
|
|
2893
|
-
var buildRelationCorrelation = (root, relation) => {
|
|
2894
|
-
return baseRelationCondition(root, relation);
|
|
3000
|
+
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
3001
|
+
return baseRelationCondition(root, relation, rootAlias);
|
|
2895
3002
|
};
|
|
2896
3003
|
|
|
2897
3004
|
// src/core/ast/join-metadata.ts
|
|
@@ -2935,7 +3042,7 @@ var RelationService = class {
|
|
|
2935
3042
|
match(relationName, predicate) {
|
|
2936
3043
|
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
2937
3044
|
const pk = findPrimaryKey(this.table);
|
|
2938
|
-
const distinctCols = [{ type: "Column", table: this.
|
|
3045
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
2939
3046
|
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
2940
3047
|
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
2941
3048
|
return { state: nextState, hydration: joined.hydration };
|
|
@@ -3022,9 +3129,13 @@ var RelationService = class {
|
|
|
3022
3129
|
* @param ast - Query AST to modify
|
|
3023
3130
|
* @returns Modified query AST with relation correlation
|
|
3024
3131
|
*/
|
|
3025
|
-
applyRelationCorrelation(relationName, ast) {
|
|
3132
|
+
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
3026
3133
|
const relation = this.getRelation(relationName);
|
|
3027
|
-
const
|
|
3134
|
+
const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
|
|
3135
|
+
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
3136
|
+
if (additionalCorrelation) {
|
|
3137
|
+
correlation = and(correlation, additionalCorrelation);
|
|
3138
|
+
}
|
|
3028
3139
|
const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
|
|
3029
3140
|
return {
|
|
3030
3141
|
...ast,
|
|
@@ -3041,17 +3152,19 @@ var RelationService = class {
|
|
|
3041
3152
|
*/
|
|
3042
3153
|
withJoin(state, relationName, joinKind, extraCondition) {
|
|
3043
3154
|
const relation = this.getRelation(relationName);
|
|
3155
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
3044
3156
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
3045
3157
|
const joins = buildBelongsToManyJoins(
|
|
3046
3158
|
this.table,
|
|
3047
3159
|
relationName,
|
|
3048
3160
|
relation,
|
|
3049
3161
|
joinKind,
|
|
3050
|
-
extraCondition
|
|
3162
|
+
extraCondition,
|
|
3163
|
+
rootAlias
|
|
3051
3164
|
);
|
|
3052
3165
|
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
3053
3166
|
}
|
|
3054
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
|
|
3167
|
+
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
3055
3168
|
const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
|
|
3056
3169
|
return this.astService(state).withJoin(joinNode);
|
|
3057
3170
|
}
|
|
@@ -3090,6 +3203,11 @@ var RelationService = class {
|
|
|
3090
3203
|
astService(state = this.state) {
|
|
3091
3204
|
return this.createQueryAstService(this.table, state);
|
|
3092
3205
|
}
|
|
3206
|
+
rootTableName() {
|
|
3207
|
+
const from = this.state.ast.from;
|
|
3208
|
+
if (from.type === "Table" && from.alias) return from.alias;
|
|
3209
|
+
return this.table.name;
|
|
3210
|
+
}
|
|
3093
3211
|
};
|
|
3094
3212
|
|
|
3095
3213
|
// src/query-builder/select-query-builder-deps.ts
|
|
@@ -3164,7 +3282,9 @@ var ColumnSelector = class {
|
|
|
3164
3282
|
* @returns Updated query context with DISTINCT clause
|
|
3165
3283
|
*/
|
|
3166
3284
|
distinct(context, columns) {
|
|
3167
|
-
const
|
|
3285
|
+
const from = context.state.ast.from;
|
|
3286
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
|
|
3287
|
+
const nodes = columns.map((col2) => buildColumnNode(tableRef, col2));
|
|
3168
3288
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
3169
3289
|
const nextState = astService.withDistinct(nodes);
|
|
3170
3290
|
return { state: nextState, hydration: context.hydration };
|
|
@@ -3221,8 +3341,8 @@ var RelationManager = class {
|
|
|
3221
3341
|
* @param ast - Query AST to modify
|
|
3222
3342
|
* @returns Modified query AST with relation correlation
|
|
3223
3343
|
*/
|
|
3224
|
-
applyRelationCorrelation(context, relationName, ast) {
|
|
3225
|
-
return this.createService(context).applyRelationCorrelation(relationName, ast);
|
|
3344
|
+
applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
|
|
3345
|
+
return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
|
|
3226
3346
|
}
|
|
3227
3347
|
/**
|
|
3228
3348
|
* Creates a relation service instance
|
|
@@ -4269,9 +4389,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4269
4389
|
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
4270
4390
|
return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
4271
4391
|
}
|
|
4392
|
+
/**
|
|
4393
|
+
* Applies an alias to the root FROM table.
|
|
4394
|
+
* @param alias - Alias to apply
|
|
4395
|
+
*/
|
|
4396
|
+
as(alias) {
|
|
4397
|
+
const from = this.context.state.ast.from;
|
|
4398
|
+
if (from.type !== "Table") {
|
|
4399
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
4400
|
+
}
|
|
4401
|
+
const nextFrom = { ...from, alias };
|
|
4402
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
4403
|
+
return this.clone(nextContext);
|
|
4404
|
+
}
|
|
4272
4405
|
resolveQueryNode(query) {
|
|
4273
4406
|
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
4274
4407
|
}
|
|
4408
|
+
applyCorrelation(ast, correlation) {
|
|
4409
|
+
if (!correlation) return ast;
|
|
4410
|
+
const combinedWhere = ast.where ? and(correlation, ast.where) : correlation;
|
|
4411
|
+
return {
|
|
4412
|
+
...ast,
|
|
4413
|
+
where: combinedWhere
|
|
4414
|
+
};
|
|
4415
|
+
}
|
|
4275
4416
|
createChildBuilder(table) {
|
|
4276
4417
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
4277
4418
|
}
|
|
@@ -4363,6 +4504,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4363
4504
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4364
4505
|
return this.clone(nextContext);
|
|
4365
4506
|
}
|
|
4507
|
+
/**
|
|
4508
|
+
* Replaces the FROM clause with a derived table (subquery with alias)
|
|
4509
|
+
* @param subquery - Subquery to use as the FROM source
|
|
4510
|
+
* @param alias - Alias for the derived table
|
|
4511
|
+
* @param columnAliases - Optional column alias list
|
|
4512
|
+
* @returns New query builder instance with updated FROM
|
|
4513
|
+
*/
|
|
4514
|
+
fromSubquery(subquery, alias, columnAliases) {
|
|
4515
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4516
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
4517
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
4518
|
+
return this.clone(nextContext);
|
|
4519
|
+
}
|
|
4366
4520
|
/**
|
|
4367
4521
|
|
|
4368
4522
|
* Selects a subquery as a column
|
|
@@ -4378,6 +4532,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4378
4532
|
const query = this.resolveQueryNode(sub);
|
|
4379
4533
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4380
4534
|
}
|
|
4535
|
+
/**
|
|
4536
|
+
* Adds a JOIN against a derived table (subquery with alias)
|
|
4537
|
+
* @param subquery - Subquery to join
|
|
4538
|
+
* @param alias - Alias for the derived table
|
|
4539
|
+
* @param condition - Join condition expression
|
|
4540
|
+
* @param joinKind - Join kind (defaults to INNER)
|
|
4541
|
+
* @param columnAliases - Optional column alias list for the derived table
|
|
4542
|
+
* @returns New query builder instance with the derived-table join
|
|
4543
|
+
*/
|
|
4544
|
+
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
4545
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4546
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
4547
|
+
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
4548
|
+
return this.clone(nextContext);
|
|
4549
|
+
}
|
|
4381
4550
|
/**
|
|
4382
4551
|
|
|
4383
4552
|
* Adds an INNER JOIN to the query
|
|
@@ -4677,9 +4846,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4677
4846
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4678
4847
|
|
|
4679
4848
|
*/
|
|
4680
|
-
whereExists(subquery) {
|
|
4849
|
+
whereExists(subquery, correlate) {
|
|
4681
4850
|
const subAst = this.resolveQueryNode(subquery);
|
|
4682
|
-
|
|
4851
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4852
|
+
return this.where(exists(correlated));
|
|
4683
4853
|
}
|
|
4684
4854
|
/**
|
|
4685
4855
|
|
|
@@ -4690,9 +4860,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4690
4860
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4691
4861
|
|
|
4692
4862
|
*/
|
|
4693
|
-
whereNotExists(subquery) {
|
|
4863
|
+
whereNotExists(subquery, correlate) {
|
|
4694
4864
|
const subAst = this.resolveQueryNode(subquery);
|
|
4695
|
-
|
|
4865
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
4866
|
+
return this.where(notExists(correlated));
|
|
4696
4867
|
}
|
|
4697
4868
|
/**
|
|
4698
4869
|
|
|
@@ -4705,17 +4876,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4705
4876
|
* @returns New query builder instance with the relationship existence check
|
|
4706
4877
|
|
|
4707
4878
|
*/
|
|
4708
|
-
whereHas(relationName,
|
|
4879
|
+
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
4709
4880
|
const relation = this.env.table.relations[relationName];
|
|
4710
4881
|
if (!relation) {
|
|
4711
4882
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4712
4883
|
}
|
|
4884
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4885
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4713
4886
|
let subQb = this.createChildBuilder(relation.target);
|
|
4714
4887
|
if (callback) {
|
|
4715
4888
|
subQb = callback(subQb);
|
|
4716
4889
|
}
|
|
4717
4890
|
const subAst = subQb.getAST();
|
|
4718
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4891
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4719
4892
|
return this.where(exists(finalSubAst));
|
|
4720
4893
|
}
|
|
4721
4894
|
/**
|
|
@@ -4729,17 +4902,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4729
4902
|
* @returns New query builder instance with the relationship non-existence check
|
|
4730
4903
|
|
|
4731
4904
|
*/
|
|
4732
|
-
whereHasNot(relationName,
|
|
4905
|
+
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
4733
4906
|
const relation = this.env.table.relations[relationName];
|
|
4734
4907
|
if (!relation) {
|
|
4735
4908
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4736
4909
|
}
|
|
4910
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
4911
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4737
4912
|
let subQb = this.createChildBuilder(relation.target);
|
|
4738
4913
|
if (callback) {
|
|
4739
4914
|
subQb = callback(subQb);
|
|
4740
4915
|
}
|
|
4741
4916
|
const subAst = subQb.getAST();
|
|
4742
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
4917
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4743
4918
|
return this.where(notExists(finalSubAst));
|
|
4744
4919
|
}
|
|
4745
4920
|
/**
|
|
@@ -6163,7 +6338,7 @@ var DefaultNamingStrategy = class {
|
|
|
6163
6338
|
* @returns Capitalized table name (handles schema-qualified names)
|
|
6164
6339
|
*/
|
|
6165
6340
|
tableToSymbol(table) {
|
|
6166
|
-
const tableName = typeof table === "string" ? table : table.name;
|
|
6341
|
+
const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.name;
|
|
6167
6342
|
if (tableName.includes(".")) {
|
|
6168
6343
|
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
6169
6344
|
}
|
|
@@ -7336,6 +7511,7 @@ export {
|
|
|
7336
7511
|
columnOperand,
|
|
7337
7512
|
concat,
|
|
7338
7513
|
concatWs,
|
|
7514
|
+
correlateBy,
|
|
7339
7515
|
cos,
|
|
7340
7516
|
cot,
|
|
7341
7517
|
count,
|
|
@@ -7426,6 +7602,7 @@ export {
|
|
|
7426
7602
|
now,
|
|
7427
7603
|
ntile,
|
|
7428
7604
|
or,
|
|
7605
|
+
outerRef,
|
|
7429
7606
|
pi,
|
|
7430
7607
|
position,
|
|
7431
7608
|
pow,
|