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.cjs
CHANGED
|
@@ -84,6 +84,7 @@ __export(index_exports, {
|
|
|
84
84
|
columnOperand: () => columnOperand,
|
|
85
85
|
concat: () => concat,
|
|
86
86
|
concatWs: () => concatWs,
|
|
87
|
+
correlateBy: () => correlateBy,
|
|
87
88
|
cos: () => cos,
|
|
88
89
|
cot: () => cot,
|
|
89
90
|
count: () => count,
|
|
@@ -174,6 +175,7 @@ __export(index_exports, {
|
|
|
174
175
|
now: () => now,
|
|
175
176
|
ntile: () => ntile,
|
|
176
177
|
or: () => or,
|
|
178
|
+
outerRef: () => outerRef,
|
|
177
179
|
pi: () => pi,
|
|
178
180
|
position: () => position,
|
|
179
181
|
pow: () => pow,
|
|
@@ -279,6 +281,30 @@ var col = {
|
|
|
279
281
|
* Creates a UUID column definition
|
|
280
282
|
*/
|
|
281
283
|
uuid: () => ({ name: "", type: "UUID" }),
|
|
284
|
+
/**
|
|
285
|
+
* Creates a binary large object column definition
|
|
286
|
+
*/
|
|
287
|
+
blob: () => ({ name: "", type: "BLOB" }),
|
|
288
|
+
/**
|
|
289
|
+
* Creates a fixed-length binary column definition
|
|
290
|
+
*/
|
|
291
|
+
binary: (length2) => ({
|
|
292
|
+
name: "",
|
|
293
|
+
type: "BINARY",
|
|
294
|
+
args: length2 !== void 0 ? [length2] : void 0
|
|
295
|
+
}),
|
|
296
|
+
/**
|
|
297
|
+
* Creates a variable-length binary column definition
|
|
298
|
+
*/
|
|
299
|
+
varbinary: (length2) => ({
|
|
300
|
+
name: "",
|
|
301
|
+
type: "VARBINARY",
|
|
302
|
+
args: length2 !== void 0 ? [length2] : void 0
|
|
303
|
+
}),
|
|
304
|
+
/**
|
|
305
|
+
* Creates a Postgres bytea column definition
|
|
306
|
+
*/
|
|
307
|
+
bytea: () => ({ name: "", type: "BYTEA" }),
|
|
282
308
|
/**
|
|
283
309
|
* Creates a timestamp column definition
|
|
284
310
|
*/
|
|
@@ -454,6 +480,11 @@ var toOperand = (val) => {
|
|
|
454
480
|
return toNode(val);
|
|
455
481
|
};
|
|
456
482
|
var columnOperand = (col2) => toNode(col2);
|
|
483
|
+
var outerRef = (col2) => ({
|
|
484
|
+
...columnOperand(col2),
|
|
485
|
+
scope: "outer"
|
|
486
|
+
});
|
|
487
|
+
var correlateBy = (table, column) => outerRef({ name: column, table });
|
|
457
488
|
var createBinaryExpression = (operator, left2, right2, escape) => {
|
|
458
489
|
const node = {
|
|
459
490
|
type: "BinaryExpression",
|
|
@@ -764,6 +795,45 @@ var toTableRef = (table) => ({
|
|
|
764
795
|
alias: table.alias
|
|
765
796
|
});
|
|
766
797
|
|
|
798
|
+
// src/core/ast/builders.ts
|
|
799
|
+
var buildColumnNode = (table, column) => {
|
|
800
|
+
if (column.type === "Column") {
|
|
801
|
+
return column;
|
|
802
|
+
}
|
|
803
|
+
const def = column;
|
|
804
|
+
const baseTable = def.table ? table.alias && def.table === table.name ? table.alias : def.table : table.alias || table.name;
|
|
805
|
+
return {
|
|
806
|
+
type: "Column",
|
|
807
|
+
table: baseTable,
|
|
808
|
+
name: def.name
|
|
809
|
+
};
|
|
810
|
+
};
|
|
811
|
+
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
812
|
+
type: "Column",
|
|
813
|
+
table: table.alias || table.name,
|
|
814
|
+
name
|
|
815
|
+
}));
|
|
816
|
+
var createTableNode = (table) => ({
|
|
817
|
+
type: "Table",
|
|
818
|
+
name: table.name
|
|
819
|
+
});
|
|
820
|
+
var fnTable = (name, args = [], alias, opts) => ({
|
|
821
|
+
type: "FunctionTable",
|
|
822
|
+
name,
|
|
823
|
+
args,
|
|
824
|
+
alias,
|
|
825
|
+
lateral: opts?.lateral,
|
|
826
|
+
withOrdinality: opts?.withOrdinality,
|
|
827
|
+
columnAliases: opts?.columnAliases,
|
|
828
|
+
schema: opts?.schema
|
|
829
|
+
});
|
|
830
|
+
var derivedTable = (query, alias, columnAliases) => ({
|
|
831
|
+
type: "DerivedTable",
|
|
832
|
+
query,
|
|
833
|
+
alias,
|
|
834
|
+
columnAliases
|
|
835
|
+
});
|
|
836
|
+
|
|
767
837
|
// src/core/functions/standard-strategy.ts
|
|
768
838
|
var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
769
839
|
constructor() {
|
|
@@ -1453,7 +1523,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1453
1523
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1454
1524
|
}
|
|
1455
1525
|
compileInsertColumnList(columns) {
|
|
1456
|
-
return columns.map((column) =>
|
|
1526
|
+
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1457
1527
|
}
|
|
1458
1528
|
compileInsertValues(values, ctx) {
|
|
1459
1529
|
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
@@ -1479,7 +1549,7 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1479
1549
|
compileUpdateAssignments(assignments, ctx) {
|
|
1480
1550
|
return assignments.map((assignment) => {
|
|
1481
1551
|
const col2 = assignment.column;
|
|
1482
|
-
const target =
|
|
1552
|
+
const target = this.quoteIdentifier(col2.name);
|
|
1483
1553
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1484
1554
|
return `${target} = ${value}`;
|
|
1485
1555
|
}).join(", ");
|
|
@@ -1511,12 +1581,29 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1511
1581
|
if (tableSource.type === "FunctionTable") {
|
|
1512
1582
|
return this.compileFunctionTable(tableSource, ctx);
|
|
1513
1583
|
}
|
|
1584
|
+
if (tableSource.type === "DerivedTable") {
|
|
1585
|
+
return this.compileDerivedTable(tableSource, ctx);
|
|
1586
|
+
}
|
|
1514
1587
|
return this.compileTableSource(tableSource);
|
|
1515
1588
|
}
|
|
1516
1589
|
compileFunctionTable(fn4, ctx) {
|
|
1517
1590
|
return FunctionTableFormatter.format(fn4, ctx, this);
|
|
1518
1591
|
}
|
|
1592
|
+
compileDerivedTable(table, ctx) {
|
|
1593
|
+
if (!table.alias) {
|
|
1594
|
+
throw new Error("Derived tables must have an alias.");
|
|
1595
|
+
}
|
|
1596
|
+
const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
1597
|
+
const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
1598
|
+
return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
|
|
1599
|
+
}
|
|
1519
1600
|
compileTableSource(table) {
|
|
1601
|
+
if (table.type === "FunctionTable") {
|
|
1602
|
+
return this.compileFunctionTable(table);
|
|
1603
|
+
}
|
|
1604
|
+
if (table.type === "DerivedTable") {
|
|
1605
|
+
return this.compileDerivedTable(table);
|
|
1606
|
+
}
|
|
1520
1607
|
const base = this.compileTableName(table);
|
|
1521
1608
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1522
1609
|
}
|
|
@@ -1905,6 +1992,12 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
1905
1992
|
const columns = this.formatReturningColumns(returning);
|
|
1906
1993
|
return ` RETURNING ${columns}`;
|
|
1907
1994
|
}
|
|
1995
|
+
formatReturningColumns(returning) {
|
|
1996
|
+
return returning.map((column) => {
|
|
1997
|
+
const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
|
|
1998
|
+
return `${this.quoteIdentifier(column.name)}${alias}`;
|
|
1999
|
+
}).join(", ");
|
|
2000
|
+
}
|
|
1908
2001
|
supportsReturning() {
|
|
1909
2002
|
return true;
|
|
1910
2003
|
}
|
|
@@ -2071,6 +2164,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2071
2164
|
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
2072
2165
|
}
|
|
2073
2166
|
compileDeleteAst(ast, ctx) {
|
|
2167
|
+
if (ast.from.type !== "Table") {
|
|
2168
|
+
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
2169
|
+
}
|
|
2074
2170
|
const table = this.quoteIdentifier(ast.from.name);
|
|
2075
2171
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2076
2172
|
return `DELETE FROM ${table}${whereClause};`;
|
|
@@ -2094,9 +2190,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2094
2190
|
return expr;
|
|
2095
2191
|
}).join(", ");
|
|
2096
2192
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
2097
|
-
const from =
|
|
2193
|
+
const from = this.compileTableSource(ast.from, ctx);
|
|
2098
2194
|
const joins = ast.joins.map((j) => {
|
|
2099
|
-
const table = this.
|
|
2195
|
+
const table = this.compileTableSource(j.table, ctx);
|
|
2100
2196
|
const cond = this.compileExpression(j.condition, ctx);
|
|
2101
2197
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
2102
2198
|
}).join(" ");
|
|
@@ -2126,6 +2222,21 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2126
2222
|
}
|
|
2127
2223
|
return pagination;
|
|
2128
2224
|
}
|
|
2225
|
+
compileTableSource(table, ctx) {
|
|
2226
|
+
if (table.type === "FunctionTable") {
|
|
2227
|
+
return FunctionTableFormatter.format(table, ctx, this);
|
|
2228
|
+
}
|
|
2229
|
+
if (table.type === "DerivedTable") {
|
|
2230
|
+
return this.compileDerivedTable(table, ctx);
|
|
2231
|
+
}
|
|
2232
|
+
const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
|
|
2233
|
+
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2234
|
+
}
|
|
2235
|
+
compileDerivedTable(table, ctx) {
|
|
2236
|
+
const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2237
|
+
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2238
|
+
return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
2239
|
+
}
|
|
2129
2240
|
compileCtes(ast, ctx) {
|
|
2130
2241
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
2131
2242
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -2254,6 +2365,17 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
2254
2365
|
joins: [...this.ast.joins ?? [], join]
|
|
2255
2366
|
});
|
|
2256
2367
|
}
|
|
2368
|
+
/**
|
|
2369
|
+
* Replaces the FROM clause.
|
|
2370
|
+
* @param from - Table source for the FROM clause
|
|
2371
|
+
* @returns New SelectQueryState with updated FROM
|
|
2372
|
+
*/
|
|
2373
|
+
withFrom(from) {
|
|
2374
|
+
return this.clone({
|
|
2375
|
+
...this.ast,
|
|
2376
|
+
from
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2257
2379
|
/**
|
|
2258
2380
|
* Adds a WHERE clause to the query
|
|
2259
2381
|
* @param predicate - WHERE predicate expression
|
|
@@ -2746,38 +2868,6 @@ var buildDefaultHydrationPlan = (table) => ({
|
|
|
2746
2868
|
relations: []
|
|
2747
2869
|
});
|
|
2748
2870
|
|
|
2749
|
-
// src/core/ast/builders.ts
|
|
2750
|
-
var buildColumnNode = (table, column) => {
|
|
2751
|
-
if (column.type === "Column") {
|
|
2752
|
-
return column;
|
|
2753
|
-
}
|
|
2754
|
-
const def = column;
|
|
2755
|
-
return {
|
|
2756
|
-
type: "Column",
|
|
2757
|
-
table: def.table || table.name,
|
|
2758
|
-
name: def.name
|
|
2759
|
-
};
|
|
2760
|
-
};
|
|
2761
|
-
var buildColumnNodes = (table, names) => names.map((name) => ({
|
|
2762
|
-
type: "Column",
|
|
2763
|
-
table: table.name,
|
|
2764
|
-
name
|
|
2765
|
-
}));
|
|
2766
|
-
var createTableNode = (table) => ({
|
|
2767
|
-
type: "Table",
|
|
2768
|
-
name: table.name
|
|
2769
|
-
});
|
|
2770
|
-
var fnTable = (name, args = [], alias, opts) => ({
|
|
2771
|
-
type: "FunctionTable",
|
|
2772
|
-
name,
|
|
2773
|
-
args,
|
|
2774
|
-
alias,
|
|
2775
|
-
lateral: opts?.lateral,
|
|
2776
|
-
withOrdinality: opts?.withOrdinality,
|
|
2777
|
-
columnAliases: opts?.columnAliases,
|
|
2778
|
-
schema: opts?.schema
|
|
2779
|
-
});
|
|
2780
|
-
|
|
2781
2871
|
// src/query-builder/raw-column-parser.ts
|
|
2782
2872
|
var parseRawColumn = (col2, tableName, ctes) => {
|
|
2783
2873
|
if (col2.includes("(")) {
|
|
@@ -2817,6 +2907,8 @@ var QueryAstService = class {
|
|
|
2817
2907
|
const existingAliases = new Set(
|
|
2818
2908
|
this.state.ast.columns.map((c) => c.alias || c.name)
|
|
2819
2909
|
);
|
|
2910
|
+
const from = this.state.ast.from;
|
|
2911
|
+
const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2820
2912
|
const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
|
|
2821
2913
|
if (existingAliases.has(alias)) return acc;
|
|
2822
2914
|
if (isExpressionSelectionNode(val)) {
|
|
@@ -2824,9 +2916,10 @@ var QueryAstService = class {
|
|
|
2824
2916
|
return acc;
|
|
2825
2917
|
}
|
|
2826
2918
|
const colDef = val;
|
|
2919
|
+
const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
|
|
2827
2920
|
acc.push({
|
|
2828
2921
|
type: "Column",
|
|
2829
|
-
table:
|
|
2922
|
+
table: resolvedTable,
|
|
2830
2923
|
name: colDef.name,
|
|
2831
2924
|
alias
|
|
2832
2925
|
});
|
|
@@ -2841,7 +2934,9 @@ var QueryAstService = class {
|
|
|
2841
2934
|
* @returns Column selection result with updated state and added columns
|
|
2842
2935
|
*/
|
|
2843
2936
|
selectRaw(cols) {
|
|
2844
|
-
const
|
|
2937
|
+
const from = this.state.ast.from;
|
|
2938
|
+
const defaultTable = from.type === "Table" && from.alias ? from.alias : this.table.name;
|
|
2939
|
+
const newCols = cols.map((col2) => parseRawColumn(col2, defaultTable, this.state.ast.ctes));
|
|
2845
2940
|
const nextState = this.state.withColumns(newCols);
|
|
2846
2941
|
return { state: nextState, addedColumns: newCols };
|
|
2847
2942
|
}
|
|
@@ -2877,6 +2972,14 @@ var QueryAstService = class {
|
|
|
2877
2972
|
};
|
|
2878
2973
|
return this.state.withSetOperation(op);
|
|
2879
2974
|
}
|
|
2975
|
+
/**
|
|
2976
|
+
* Replaces the FROM clause for the current query.
|
|
2977
|
+
* @param from - Table source to use in the FROM clause
|
|
2978
|
+
* @returns Updated query state with new FROM
|
|
2979
|
+
*/
|
|
2980
|
+
withFrom(from) {
|
|
2981
|
+
return this.state.withFrom(from);
|
|
2982
|
+
}
|
|
2880
2983
|
/**
|
|
2881
2984
|
* Selects a subquery as a column
|
|
2882
2985
|
* @param alias - Alias for the subquery
|
|
@@ -2910,7 +3013,9 @@ var QueryAstService = class {
|
|
|
2910
3013
|
* @returns Updated query state with GROUP BY clause
|
|
2911
3014
|
*/
|
|
2912
3015
|
withGroupBy(col2) {
|
|
2913
|
-
const
|
|
3016
|
+
const from = this.state.ast.from;
|
|
3017
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
3018
|
+
const node = buildColumnNode(tableRef, col2);
|
|
2914
3019
|
return this.state.withGroupBy([node]);
|
|
2915
3020
|
}
|
|
2916
3021
|
/**
|
|
@@ -2929,7 +3034,9 @@ var QueryAstService = class {
|
|
|
2929
3034
|
* @returns Updated query state with ORDER BY clause
|
|
2930
3035
|
*/
|
|
2931
3036
|
withOrderBy(col2, direction) {
|
|
2932
|
-
const
|
|
3037
|
+
const from = this.state.ast.from;
|
|
3038
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
3039
|
+
const node = buildColumnNode(tableRef, col2);
|
|
2933
3040
|
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
2934
3041
|
}
|
|
2935
3042
|
/**
|
|
@@ -3033,7 +3140,8 @@ var RelationProjectionHelper = class {
|
|
|
3033
3140
|
var assertNever = (value) => {
|
|
3034
3141
|
throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
|
|
3035
3142
|
};
|
|
3036
|
-
var baseRelationCondition = (root, relation) => {
|
|
3143
|
+
var baseRelationCondition = (root, relation, rootAlias) => {
|
|
3144
|
+
const rootTable = rootAlias || root.name;
|
|
3037
3145
|
const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
|
|
3038
3146
|
const localKey = relation.localKey || defaultLocalKey;
|
|
3039
3147
|
switch (relation.type) {
|
|
@@ -3041,12 +3149,12 @@ var baseRelationCondition = (root, relation) => {
|
|
|
3041
3149
|
case RelationKinds.HasOne:
|
|
3042
3150
|
return eq(
|
|
3043
3151
|
{ type: "Column", table: relation.target.name, name: relation.foreignKey },
|
|
3044
|
-
{ type: "Column", table:
|
|
3152
|
+
{ type: "Column", table: rootTable, name: localKey }
|
|
3045
3153
|
);
|
|
3046
3154
|
case RelationKinds.BelongsTo:
|
|
3047
3155
|
return eq(
|
|
3048
3156
|
{ type: "Column", table: relation.target.name, name: localKey },
|
|
3049
|
-
{ type: "Column", table:
|
|
3157
|
+
{ type: "Column", table: rootTable, name: relation.foreignKey }
|
|
3050
3158
|
);
|
|
3051
3159
|
case RelationKinds.BelongsToMany:
|
|
3052
3160
|
throw new Error("BelongsToMany relations do not support the standard join condition builder");
|
|
@@ -3054,12 +3162,13 @@ var baseRelationCondition = (root, relation) => {
|
|
|
3054
3162
|
return assertNever(relation);
|
|
3055
3163
|
}
|
|
3056
3164
|
};
|
|
3057
|
-
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
|
|
3165
|
+
var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
|
|
3058
3166
|
const rootKey = relation.localKey || findPrimaryKey(root);
|
|
3059
3167
|
const targetKey = relation.targetKey || findPrimaryKey(relation.target);
|
|
3168
|
+
const rootTable = rootAlias || root.name;
|
|
3060
3169
|
const pivotCondition = eq(
|
|
3061
3170
|
{ type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
|
|
3062
|
-
{ type: "Column", table:
|
|
3171
|
+
{ type: "Column", table: rootTable, name: rootKey }
|
|
3063
3172
|
);
|
|
3064
3173
|
const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
|
|
3065
3174
|
let targetCondition = eq(
|
|
@@ -3077,12 +3186,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
|
|
|
3077
3186
|
);
|
|
3078
3187
|
return [pivotJoin, targetJoin];
|
|
3079
3188
|
};
|
|
3080
|
-
var buildRelationJoinCondition = (root, relation, extra) => {
|
|
3081
|
-
const base = baseRelationCondition(root, relation);
|
|
3189
|
+
var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
|
|
3190
|
+
const base = baseRelationCondition(root, relation, rootAlias);
|
|
3082
3191
|
return extra ? and(base, extra) : base;
|
|
3083
3192
|
};
|
|
3084
|
-
var buildRelationCorrelation = (root, relation) => {
|
|
3085
|
-
return baseRelationCondition(root, relation);
|
|
3193
|
+
var buildRelationCorrelation = (root, relation, rootAlias) => {
|
|
3194
|
+
return baseRelationCondition(root, relation, rootAlias);
|
|
3086
3195
|
};
|
|
3087
3196
|
|
|
3088
3197
|
// src/core/ast/join-metadata.ts
|
|
@@ -3126,7 +3235,7 @@ var RelationService = class {
|
|
|
3126
3235
|
match(relationName, predicate) {
|
|
3127
3236
|
const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
|
|
3128
3237
|
const pk = findPrimaryKey(this.table);
|
|
3129
|
-
const distinctCols = [{ type: "Column", table: this.
|
|
3238
|
+
const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
|
|
3130
3239
|
const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
|
|
3131
3240
|
const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
|
|
3132
3241
|
return { state: nextState, hydration: joined.hydration };
|
|
@@ -3213,9 +3322,13 @@ var RelationService = class {
|
|
|
3213
3322
|
* @param ast - Query AST to modify
|
|
3214
3323
|
* @returns Modified query AST with relation correlation
|
|
3215
3324
|
*/
|
|
3216
|
-
applyRelationCorrelation(relationName, ast) {
|
|
3325
|
+
applyRelationCorrelation(relationName, ast, additionalCorrelation) {
|
|
3217
3326
|
const relation = this.getRelation(relationName);
|
|
3218
|
-
const
|
|
3327
|
+
const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
|
|
3328
|
+
let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
|
|
3329
|
+
if (additionalCorrelation) {
|
|
3330
|
+
correlation = and(correlation, additionalCorrelation);
|
|
3331
|
+
}
|
|
3219
3332
|
const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
|
|
3220
3333
|
return {
|
|
3221
3334
|
...ast,
|
|
@@ -3232,17 +3345,19 @@ var RelationService = class {
|
|
|
3232
3345
|
*/
|
|
3233
3346
|
withJoin(state, relationName, joinKind, extraCondition) {
|
|
3234
3347
|
const relation = this.getRelation(relationName);
|
|
3348
|
+
const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
|
|
3235
3349
|
if (relation.type === RelationKinds.BelongsToMany) {
|
|
3236
3350
|
const joins = buildBelongsToManyJoins(
|
|
3237
3351
|
this.table,
|
|
3238
3352
|
relationName,
|
|
3239
3353
|
relation,
|
|
3240
3354
|
joinKind,
|
|
3241
|
-
extraCondition
|
|
3355
|
+
extraCondition,
|
|
3356
|
+
rootAlias
|
|
3242
3357
|
);
|
|
3243
3358
|
return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
|
|
3244
3359
|
}
|
|
3245
|
-
const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
|
|
3360
|
+
const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
|
|
3246
3361
|
const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
|
|
3247
3362
|
return this.astService(state).withJoin(joinNode);
|
|
3248
3363
|
}
|
|
@@ -3281,6 +3396,11 @@ var RelationService = class {
|
|
|
3281
3396
|
astService(state = this.state) {
|
|
3282
3397
|
return this.createQueryAstService(this.table, state);
|
|
3283
3398
|
}
|
|
3399
|
+
rootTableName() {
|
|
3400
|
+
const from = this.state.ast.from;
|
|
3401
|
+
if (from.type === "Table" && from.alias) return from.alias;
|
|
3402
|
+
return this.table.name;
|
|
3403
|
+
}
|
|
3284
3404
|
};
|
|
3285
3405
|
|
|
3286
3406
|
// src/query-builder/select-query-builder-deps.ts
|
|
@@ -3355,7 +3475,9 @@ var ColumnSelector = class {
|
|
|
3355
3475
|
* @returns Updated query context with DISTINCT clause
|
|
3356
3476
|
*/
|
|
3357
3477
|
distinct(context, columns) {
|
|
3358
|
-
const
|
|
3478
|
+
const from = context.state.ast.from;
|
|
3479
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
|
|
3480
|
+
const nodes = columns.map((col2) => buildColumnNode(tableRef, col2));
|
|
3359
3481
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
3360
3482
|
const nextState = astService.withDistinct(nodes);
|
|
3361
3483
|
return { state: nextState, hydration: context.hydration };
|
|
@@ -3412,8 +3534,8 @@ var RelationManager = class {
|
|
|
3412
3534
|
* @param ast - Query AST to modify
|
|
3413
3535
|
* @returns Modified query AST with relation correlation
|
|
3414
3536
|
*/
|
|
3415
|
-
applyRelationCorrelation(context, relationName, ast) {
|
|
3416
|
-
return this.createService(context).applyRelationCorrelation(relationName, ast);
|
|
3537
|
+
applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
|
|
3538
|
+
return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
|
|
3417
3539
|
}
|
|
3418
3540
|
/**
|
|
3419
3541
|
* Creates a relation service instance
|
|
@@ -4460,9 +4582,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4460
4582
|
clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
|
|
4461
4583
|
return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
4462
4584
|
}
|
|
4585
|
+
/**
|
|
4586
|
+
* Applies an alias to the root FROM table.
|
|
4587
|
+
* @param alias - Alias to apply
|
|
4588
|
+
*/
|
|
4589
|
+
as(alias) {
|
|
4590
|
+
const from = this.context.state.ast.from;
|
|
4591
|
+
if (from.type !== "Table") {
|
|
4592
|
+
throw new Error("Cannot alias non-table FROM sources");
|
|
4593
|
+
}
|
|
4594
|
+
const nextFrom = { ...from, alias };
|
|
4595
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
|
|
4596
|
+
return this.clone(nextContext);
|
|
4597
|
+
}
|
|
4463
4598
|
resolveQueryNode(query) {
|
|
4464
4599
|
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
4465
4600
|
}
|
|
4601
|
+
applyCorrelation(ast, correlation) {
|
|
4602
|
+
if (!correlation) return ast;
|
|
4603
|
+
const combinedWhere = ast.where ? and(correlation, ast.where) : correlation;
|
|
4604
|
+
return {
|
|
4605
|
+
...ast,
|
|
4606
|
+
where: combinedWhere
|
|
4607
|
+
};
|
|
4608
|
+
}
|
|
4466
4609
|
createChildBuilder(table) {
|
|
4467
4610
|
return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
|
|
4468
4611
|
}
|
|
@@ -4554,6 +4697,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4554
4697
|
const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
|
|
4555
4698
|
return this.clone(nextContext);
|
|
4556
4699
|
}
|
|
4700
|
+
/**
|
|
4701
|
+
* Replaces the FROM clause with a derived table (subquery with alias)
|
|
4702
|
+
* @param subquery - Subquery to use as the FROM source
|
|
4703
|
+
* @param alias - Alias for the derived table
|
|
4704
|
+
* @param columnAliases - Optional column alias list
|
|
4705
|
+
* @returns New query builder instance with updated FROM
|
|
4706
|
+
*/
|
|
4707
|
+
fromSubquery(subquery, alias, columnAliases) {
|
|
4708
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4709
|
+
const fromNode = derivedTable(subAst, alias, columnAliases);
|
|
4710
|
+
const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
|
|
4711
|
+
return this.clone(nextContext);
|
|
4712
|
+
}
|
|
4557
4713
|
/**
|
|
4558
4714
|
|
|
4559
4715
|
* Selects a subquery as a column
|
|
@@ -4569,6 +4725,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4569
4725
|
const query = this.resolveQueryNode(sub);
|
|
4570
4726
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4571
4727
|
}
|
|
4728
|
+
/**
|
|
4729
|
+
* Adds a JOIN against a derived table (subquery with alias)
|
|
4730
|
+
* @param subquery - Subquery to join
|
|
4731
|
+
* @param alias - Alias for the derived table
|
|
4732
|
+
* @param condition - Join condition expression
|
|
4733
|
+
* @param joinKind - Join kind (defaults to INNER)
|
|
4734
|
+
* @param columnAliases - Optional column alias list for the derived table
|
|
4735
|
+
* @returns New query builder instance with the derived-table join
|
|
4736
|
+
*/
|
|
4737
|
+
joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
|
|
4738
|
+
const subAst = this.resolveQueryNode(subquery);
|
|
4739
|
+
const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
|
|
4740
|
+
const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
|
|
4741
|
+
return this.clone(nextContext);
|
|
4742
|
+
}
|
|
4572
4743
|
/**
|
|
4573
4744
|
|
|
4574
4745
|
* Adds an INNER JOIN to the query
|
|
@@ -4868,9 +5039,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4868
5039
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
4869
5040
|
|
|
4870
5041
|
*/
|
|
4871
|
-
whereExists(subquery) {
|
|
5042
|
+
whereExists(subquery, correlate) {
|
|
4872
5043
|
const subAst = this.resolveQueryNode(subquery);
|
|
4873
|
-
|
|
5044
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
5045
|
+
return this.where(exists(correlated));
|
|
4874
5046
|
}
|
|
4875
5047
|
/**
|
|
4876
5048
|
|
|
@@ -4881,9 +5053,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4881
5053
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
4882
5054
|
|
|
4883
5055
|
*/
|
|
4884
|
-
whereNotExists(subquery) {
|
|
5056
|
+
whereNotExists(subquery, correlate) {
|
|
4885
5057
|
const subAst = this.resolveQueryNode(subquery);
|
|
4886
|
-
|
|
5058
|
+
const correlated = this.applyCorrelation(subAst, correlate);
|
|
5059
|
+
return this.where(notExists(correlated));
|
|
4887
5060
|
}
|
|
4888
5061
|
/**
|
|
4889
5062
|
|
|
@@ -4896,17 +5069,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4896
5069
|
* @returns New query builder instance with the relationship existence check
|
|
4897
5070
|
|
|
4898
5071
|
*/
|
|
4899
|
-
whereHas(relationName,
|
|
5072
|
+
whereHas(relationName, callbackOrOptions, maybeOptions) {
|
|
4900
5073
|
const relation = this.env.table.relations[relationName];
|
|
4901
5074
|
if (!relation) {
|
|
4902
5075
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4903
5076
|
}
|
|
5077
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
5078
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4904
5079
|
let subQb = this.createChildBuilder(relation.target);
|
|
4905
5080
|
if (callback) {
|
|
4906
5081
|
subQb = callback(subQb);
|
|
4907
5082
|
}
|
|
4908
5083
|
const subAst = subQb.getAST();
|
|
4909
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
5084
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4910
5085
|
return this.where(exists(finalSubAst));
|
|
4911
5086
|
}
|
|
4912
5087
|
/**
|
|
@@ -4920,17 +5095,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4920
5095
|
* @returns New query builder instance with the relationship non-existence check
|
|
4921
5096
|
|
|
4922
5097
|
*/
|
|
4923
|
-
whereHasNot(relationName,
|
|
5098
|
+
whereHasNot(relationName, callbackOrOptions, maybeOptions) {
|
|
4924
5099
|
const relation = this.env.table.relations[relationName];
|
|
4925
5100
|
if (!relation) {
|
|
4926
5101
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
4927
5102
|
}
|
|
5103
|
+
const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
|
|
5104
|
+
const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
|
|
4928
5105
|
let subQb = this.createChildBuilder(relation.target);
|
|
4929
5106
|
if (callback) {
|
|
4930
5107
|
subQb = callback(subQb);
|
|
4931
5108
|
}
|
|
4932
5109
|
const subAst = subQb.getAST();
|
|
4933
|
-
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
5110
|
+
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
|
|
4934
5111
|
return this.where(notExists(finalSubAst));
|
|
4935
5112
|
}
|
|
4936
5113
|
/**
|
|
@@ -6354,7 +6531,7 @@ var DefaultNamingStrategy = class {
|
|
|
6354
6531
|
* @returns Capitalized table name (handles schema-qualified names)
|
|
6355
6532
|
*/
|
|
6356
6533
|
tableToSymbol(table) {
|
|
6357
|
-
const tableName = typeof table === "string" ? table : table.name;
|
|
6534
|
+
const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.name;
|
|
6358
6535
|
if (tableName.includes(".")) {
|
|
6359
6536
|
return tableName.split(".").map((part) => this.capitalize(part)).join("");
|
|
6360
6537
|
}
|
|
@@ -7528,6 +7705,7 @@ function createMssqlExecutor(client) {
|
|
|
7528
7705
|
columnOperand,
|
|
7529
7706
|
concat,
|
|
7530
7707
|
concatWs,
|
|
7708
|
+
correlateBy,
|
|
7531
7709
|
cos,
|
|
7532
7710
|
cot,
|
|
7533
7711
|
count,
|
|
@@ -7618,6 +7796,7 @@ function createMssqlExecutor(client) {
|
|
|
7618
7796
|
now,
|
|
7619
7797
|
ntile,
|
|
7620
7798
|
or,
|
|
7799
|
+
outerRef,
|
|
7621
7800
|
pi,
|
|
7622
7801
|
position,
|
|
7623
7802
|
pow,
|