metal-orm 1.0.39 → 1.0.40
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/dist/index.cjs +230 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -24
- package/dist/index.d.ts +71 -24
- package/dist/index.js +225 -75
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/typescript.ts +60 -3
- package/src/core/ast/aggregate-functions.ts +15 -15
- package/src/core/ast/expression-builders.ts +357 -316
- package/src/core/ast/expression-nodes.ts +208 -186
- package/src/core/ast/expression-visitor.ts +40 -30
- package/src/core/ast/query.ts +142 -132
- package/src/core/ast/window-functions.ts +86 -86
- package/src/core/dialect/abstract.ts +505 -479
- package/src/core/dialect/base/groupby-compiler.ts +6 -6
- package/src/core/dialect/base/orderby-compiler.ts +20 -6
- package/src/core/dialect/base/sql-dialect.ts +154 -136
- package/src/core/dialect/mssql/index.ts +172 -161
- package/src/core/functions/standard-strategy.ts +46 -37
- package/src/query-builder/hydration-manager.ts +93 -79
- package/src/query-builder/query-ast-service.ts +207 -170
- package/src/query-builder/select-query-state.ts +169 -162
- package/src/query-builder/select.ts +15 -23
package/dist/index.js
CHANGED
|
@@ -245,6 +245,7 @@ var belongsToMany = (target, pivotTable, options) => ({
|
|
|
245
245
|
|
|
246
246
|
// src/core/ast/expression-nodes.ts
|
|
247
247
|
var operandTypes = /* @__PURE__ */ new Set([
|
|
248
|
+
"AliasRef",
|
|
248
249
|
"Column",
|
|
249
250
|
"Literal",
|
|
250
251
|
"Function",
|
|
@@ -291,6 +292,10 @@ var outerRef = (col2) => ({
|
|
|
291
292
|
...columnOperand(col2),
|
|
292
293
|
scope: "outer"
|
|
293
294
|
});
|
|
295
|
+
var aliasRef = (name) => ({
|
|
296
|
+
type: "AliasRef",
|
|
297
|
+
name
|
|
298
|
+
});
|
|
294
299
|
var correlateBy = (table, column) => outerRef({ name: column, table });
|
|
295
300
|
var createBinaryExpression = (operator, left2, right2, escape) => {
|
|
296
301
|
const node = {
|
|
@@ -349,6 +354,16 @@ var createBetweenExpression = (operator, left2, lower2, upper2) => ({
|
|
|
349
354
|
});
|
|
350
355
|
var between = (left2, lower2, upper2) => createBetweenExpression("BETWEEN", left2, lower2, upper2);
|
|
351
356
|
var notBetween = (left2, lower2, upper2) => createBetweenExpression("NOT BETWEEN", left2, lower2, upper2);
|
|
357
|
+
var createArithmeticExpression = (operator, left2, right2) => ({
|
|
358
|
+
type: "ArithmeticExpression",
|
|
359
|
+
left: toOperand(left2),
|
|
360
|
+
operator,
|
|
361
|
+
right: toOperand(right2)
|
|
362
|
+
});
|
|
363
|
+
var add = (left2, right2) => createArithmeticExpression("+", left2, right2);
|
|
364
|
+
var sub = (left2, right2) => createArithmeticExpression("-", left2, right2);
|
|
365
|
+
var mul = (left2, right2) => createArithmeticExpression("*", left2, right2);
|
|
366
|
+
var div = (left2, right2) => createArithmeticExpression("/", left2, right2);
|
|
352
367
|
var jsonPath = (col2, path) => ({
|
|
353
368
|
type: "JsonPath",
|
|
354
369
|
column: columnOperand(col2),
|
|
@@ -427,7 +442,7 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
|
427
442
|
const partitionNodes = partitionBy?.map((col2) => columnOperand(col2)) ?? void 0;
|
|
428
443
|
const orderNodes = orderBy?.map((o) => ({
|
|
429
444
|
type: "OrderBy",
|
|
430
|
-
|
|
445
|
+
term: columnOperand(o.column),
|
|
431
446
|
direction: o.direction
|
|
432
447
|
}));
|
|
433
448
|
return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
|
|
@@ -502,7 +517,7 @@ var min = buildAggregate("MIN");
|
|
|
502
517
|
var max = buildAggregate("MAX");
|
|
503
518
|
var toOrderByNode = (order) => ({
|
|
504
519
|
type: "OrderBy",
|
|
505
|
-
|
|
520
|
+
term: columnOperand(order.column),
|
|
506
521
|
direction: order.direction ?? ORDER_DIRECTIONS.ASC
|
|
507
522
|
});
|
|
508
523
|
var groupConcat = (col2, options) => ({
|
|
@@ -552,6 +567,9 @@ var visitExpression = (node, visitor) => {
|
|
|
552
567
|
case "BetweenExpression":
|
|
553
568
|
if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node);
|
|
554
569
|
break;
|
|
570
|
+
case "ArithmeticExpression":
|
|
571
|
+
if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
|
|
572
|
+
break;
|
|
555
573
|
default:
|
|
556
574
|
break;
|
|
557
575
|
}
|
|
@@ -583,6 +601,9 @@ var visitOperand = (node, visitor) => {
|
|
|
583
601
|
case "WindowFunction":
|
|
584
602
|
if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node);
|
|
585
603
|
break;
|
|
604
|
+
case "AliasRef":
|
|
605
|
+
if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
|
|
606
|
+
break;
|
|
586
607
|
default:
|
|
587
608
|
break;
|
|
588
609
|
}
|
|
@@ -699,7 +720,14 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
699
720
|
if (!orderBy || orderBy.length === 0) {
|
|
700
721
|
return "";
|
|
701
722
|
}
|
|
702
|
-
const parts = orderBy.map((order) =>
|
|
723
|
+
const parts = orderBy.map((order) => {
|
|
724
|
+
const term = isOperandNode(order.term) ? ctx.compileOperand(order.term) : (() => {
|
|
725
|
+
throw new Error("ORDER BY expressions inside functions must be operands");
|
|
726
|
+
})();
|
|
727
|
+
const collation = order.collation ? ` COLLATE ${order.collation}` : "";
|
|
728
|
+
const nulls = order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
729
|
+
return `${term} ${order.direction}${collation}${nulls}`;
|
|
730
|
+
});
|
|
703
731
|
return `ORDER BY ${parts.join(", ")}`;
|
|
704
732
|
}
|
|
705
733
|
formatGroupConcatSeparator(ctx) {
|
|
@@ -964,6 +992,16 @@ var Dialect = class _Dialect {
|
|
|
964
992
|
}
|
|
965
993
|
return compiler(node, ctx);
|
|
966
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* Compiles an ordering term (operand, expression, or alias reference).
|
|
997
|
+
*/
|
|
998
|
+
compileOrderingTerm(term, ctx) {
|
|
999
|
+
if (isOperandNode(term)) {
|
|
1000
|
+
return this.compileOperand(term, ctx);
|
|
1001
|
+
}
|
|
1002
|
+
const expr = this.compileExpression(term, ctx);
|
|
1003
|
+
return `(${expr})`;
|
|
1004
|
+
}
|
|
967
1005
|
registerDefaultExpressionCompilers() {
|
|
968
1006
|
this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
|
|
969
1007
|
const left2 = this.compileOperand(binary.left, ctx);
|
|
@@ -1002,9 +1040,15 @@ var Dialect = class _Dialect {
|
|
|
1002
1040
|
const upper2 = this.compileOperand(betweenExpr.upper, ctx);
|
|
1003
1041
|
return `${left2} ${betweenExpr.operator} ${lower2} AND ${upper2}`;
|
|
1004
1042
|
});
|
|
1043
|
+
this.registerExpressionCompiler("ArithmeticExpression", (arith, ctx) => {
|
|
1044
|
+
const left2 = this.compileOperand(arith.left, ctx);
|
|
1045
|
+
const right2 = this.compileOperand(arith.right, ctx);
|
|
1046
|
+
return `${left2} ${arith.operator} ${right2}`;
|
|
1047
|
+
});
|
|
1005
1048
|
}
|
|
1006
1049
|
registerDefaultOperandCompilers() {
|
|
1007
1050
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
1051
|
+
this.registerOperandCompiler("AliasRef", (alias, _ctx) => this.quoteIdentifier(alias.name));
|
|
1008
1052
|
this.registerOperandCompiler("Column", (column, _ctx) => {
|
|
1009
1053
|
return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
|
|
1010
1054
|
});
|
|
@@ -1042,9 +1086,12 @@ var Dialect = class _Dialect {
|
|
|
1042
1086
|
parts.push(partitionClause);
|
|
1043
1087
|
}
|
|
1044
1088
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
1045
|
-
const orderClause = "ORDER BY " + node.orderBy.map(
|
|
1046
|
-
|
|
1047
|
-
|
|
1089
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => {
|
|
1090
|
+
const term = this.compileOrderingTerm(o.term, ctx);
|
|
1091
|
+
const collation = o.collation ? ` COLLATE ${o.collation}` : "";
|
|
1092
|
+
const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
1093
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
1094
|
+
}).join(", ");
|
|
1048
1095
|
parts.push(orderClause);
|
|
1049
1096
|
}
|
|
1050
1097
|
result += parts.join(" ");
|
|
@@ -1263,12 +1310,12 @@ var GroupByCompiler = class {
|
|
|
1263
1310
|
/**
|
|
1264
1311
|
* Compiles GROUP BY clause from a SELECT query AST.
|
|
1265
1312
|
* @param ast - The SELECT query AST containing grouping columns.
|
|
1266
|
-
* @param
|
|
1313
|
+
* @param renderTerm - Function to render a grouping term.
|
|
1267
1314
|
* @returns SQL GROUP BY clause (e.g., " GROUP BY table.col1, table.col2") or empty string if no grouping.
|
|
1268
1315
|
*/
|
|
1269
|
-
static compileGroupBy(ast,
|
|
1316
|
+
static compileGroupBy(ast, renderTerm) {
|
|
1270
1317
|
if (!ast.groupBy || ast.groupBy.length === 0) return "";
|
|
1271
|
-
const cols = ast.groupBy.map(
|
|
1318
|
+
const cols = ast.groupBy.map(renderTerm).join(", ");
|
|
1272
1319
|
return ` GROUP BY ${cols}`;
|
|
1273
1320
|
}
|
|
1274
1321
|
};
|
|
@@ -1278,12 +1325,19 @@ var OrderByCompiler = class {
|
|
|
1278
1325
|
/**
|
|
1279
1326
|
* Compiles ORDER BY clause from a SELECT query AST.
|
|
1280
1327
|
* @param ast - The SELECT query AST containing sort specifications.
|
|
1281
|
-
* @param
|
|
1328
|
+
* @param renderTerm - Function to render an ordering term.
|
|
1329
|
+
* @param renderNulls - Optional function to render NULLS FIRST/LAST.
|
|
1330
|
+
* @param renderCollation - Optional function to render COLLATE clause.
|
|
1282
1331
|
* @returns SQL ORDER BY clause (e.g., " ORDER BY table.col1 ASC, table.col2 DESC") or empty string if no ordering.
|
|
1283
1332
|
*/
|
|
1284
|
-
static compileOrderBy(ast,
|
|
1333
|
+
static compileOrderBy(ast, renderTerm, renderNulls, renderCollation) {
|
|
1285
1334
|
if (!ast.orderBy || ast.orderBy.length === 0) return "";
|
|
1286
|
-
const parts = ast.orderBy.map((o) =>
|
|
1335
|
+
const parts = ast.orderBy.map((o) => {
|
|
1336
|
+
const term = renderTerm(o.term);
|
|
1337
|
+
const collation = renderCollation ? renderCollation(o) : o.collation ? ` COLLATE ${o.collation}` : "";
|
|
1338
|
+
const nulls = renderNulls ? renderNulls(o) : o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
1339
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
1340
|
+
}).join(", ");
|
|
1287
1341
|
return ` ORDER BY ${parts}`;
|
|
1288
1342
|
}
|
|
1289
1343
|
};
|
|
@@ -1314,7 +1368,12 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1314
1368
|
}
|
|
1315
1369
|
compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
|
|
1316
1370
|
const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
|
|
1317
|
-
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1371
|
+
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1372
|
+
ast,
|
|
1373
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
1374
|
+
this.renderOrderByNulls.bind(this),
|
|
1375
|
+
this.renderOrderByCollation.bind(this)
|
|
1376
|
+
);
|
|
1318
1377
|
const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
|
|
1319
1378
|
const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
|
|
1320
1379
|
return `${ctes}${combined}${orderBy}${pagination}`;
|
|
@@ -1340,9 +1399,14 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1340
1399
|
const from = this.compileFrom(ast.from, ctx);
|
|
1341
1400
|
const joins = JoinCompiler.compileJoins(ast, ctx, this.compileFrom.bind(this), this.compileExpression.bind(this));
|
|
1342
1401
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1343
|
-
const groupBy = GroupByCompiler.compileGroupBy(ast, this.
|
|
1402
|
+
const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
|
|
1344
1403
|
const having = this.compileHaving(ast, ctx);
|
|
1345
|
-
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1404
|
+
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1405
|
+
ast,
|
|
1406
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
1407
|
+
this.renderOrderByNulls.bind(this),
|
|
1408
|
+
this.renderOrderByCollation.bind(this)
|
|
1409
|
+
);
|
|
1346
1410
|
const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
|
|
1347
1411
|
return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
|
|
1348
1412
|
}
|
|
@@ -1431,6 +1495,12 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1431
1495
|
const trimmed = this.stripTrailingSemicolon(sql);
|
|
1432
1496
|
return `(${trimmed})`;
|
|
1433
1497
|
}
|
|
1498
|
+
renderOrderByNulls(order) {
|
|
1499
|
+
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
1500
|
+
}
|
|
1501
|
+
renderOrderByCollation(order) {
|
|
1502
|
+
return order.collation ? ` COLLATE ${order.collation}` : "";
|
|
1503
|
+
}
|
|
1434
1504
|
};
|
|
1435
1505
|
|
|
1436
1506
|
// src/core/dialect/postgres/functions.ts
|
|
@@ -1947,7 +2017,7 @@ var SqlServerDialect = class extends Dialect {
|
|
|
1947
2017
|
return `${ctes}${baseSelect}`;
|
|
1948
2018
|
}
|
|
1949
2019
|
const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
|
|
1950
|
-
const orderBy = this.compileOrderBy(ast);
|
|
2020
|
+
const orderBy = this.compileOrderBy(ast, ctx);
|
|
1951
2021
|
const pagination = this.compilePagination(ast, orderBy);
|
|
1952
2022
|
const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
|
|
1953
2023
|
const tail = pagination || orderBy;
|
|
@@ -2004,18 +2074,22 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2004
2074
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
2005
2075
|
}).join(" ");
|
|
2006
2076
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2007
|
-
const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((
|
|
2077
|
+
const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((term) => this.compileOrderingTerm(term, ctx)).join(", ") : "";
|
|
2008
2078
|
const having = ast.having ? ` HAVING ${this.compileExpression(ast.having, ctx)}` : "";
|
|
2009
|
-
const orderBy = this.compileOrderBy(ast);
|
|
2079
|
+
const orderBy = this.compileOrderBy(ast, ctx);
|
|
2010
2080
|
const pagination = this.compilePagination(ast, orderBy);
|
|
2011
2081
|
if (pagination) {
|
|
2012
2082
|
return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${pagination}`;
|
|
2013
2083
|
}
|
|
2014
2084
|
return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${orderBy}`;
|
|
2015
2085
|
}
|
|
2016
|
-
compileOrderBy(ast) {
|
|
2017
|
-
|
|
2018
|
-
|
|
2086
|
+
compileOrderBy(ast, ctx) {
|
|
2087
|
+
return OrderByCompiler.compileOrderBy(
|
|
2088
|
+
ast,
|
|
2089
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
2090
|
+
this.renderOrderByNulls.bind(this),
|
|
2091
|
+
this.renderOrderByCollation.bind(this)
|
|
2092
|
+
);
|
|
2019
2093
|
}
|
|
2020
2094
|
compilePagination(ast, orderBy) {
|
|
2021
2095
|
const hasLimit = ast.limit !== void 0;
|
|
@@ -2029,6 +2103,12 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2029
2103
|
}
|
|
2030
2104
|
return pagination;
|
|
2031
2105
|
}
|
|
2106
|
+
renderOrderByNulls(order) {
|
|
2107
|
+
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
2108
|
+
}
|
|
2109
|
+
renderOrderByCollation(order) {
|
|
2110
|
+
return order.collation ? ` COLLATE ${order.collation}` : "";
|
|
2111
|
+
}
|
|
2032
2112
|
compileTableSource(table, ctx) {
|
|
2033
2113
|
if (table.type === "FunctionTable") {
|
|
2034
2114
|
return FunctionTableFormatter.format(table, ctx, this);
|
|
@@ -2040,9 +2120,9 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2040
2120
|
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2041
2121
|
}
|
|
2042
2122
|
compileDerivedTable(table, ctx) {
|
|
2043
|
-
const
|
|
2123
|
+
const sub2 = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2044
2124
|
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2045
|
-
return `(${
|
|
2125
|
+
return `(${sub2}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
2046
2126
|
}
|
|
2047
2127
|
compileCtes(ast, ctx) {
|
|
2048
2128
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
@@ -2207,7 +2287,7 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
2207
2287
|
}
|
|
2208
2288
|
/**
|
|
2209
2289
|
* Adds GROUP BY columns to the query
|
|
2210
|
-
* @param columns -
|
|
2290
|
+
* @param columns - Terms to group by
|
|
2211
2291
|
* @returns New SelectQueryState with GROUP BY clause
|
|
2212
2292
|
*/
|
|
2213
2293
|
withGroupBy(columns) {
|
|
@@ -2490,31 +2570,38 @@ var HydrationManager = class _HydrationManager {
|
|
|
2490
2570
|
}
|
|
2491
2571
|
const mapped = [];
|
|
2492
2572
|
for (const ob of orderBy) {
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
}
|
|
2496
|
-
const alias = projectionAliases.get(`${ob.column.table}.${ob.column.name}`) ?? ob.column.name;
|
|
2497
|
-
if (!availableColumns.has(alias)) {
|
|
2498
|
-
return null;
|
|
2499
|
-
}
|
|
2500
|
-
mapped.push({
|
|
2501
|
-
type: "OrderBy",
|
|
2502
|
-
column: { type: "Column", table: baseAlias, name: alias },
|
|
2503
|
-
direction: ob.direction
|
|
2504
|
-
});
|
|
2573
|
+
const mappedTerm = this.mapOrderingTerm(ob.term, plan, projectionAliases, baseAlias, availableColumns);
|
|
2574
|
+
if (!mappedTerm) return null;
|
|
2575
|
+
mapped.push({ ...ob, term: mappedTerm });
|
|
2505
2576
|
}
|
|
2506
2577
|
return mapped;
|
|
2507
2578
|
}
|
|
2579
|
+
mapOrderingTerm(term, plan, projectionAliases, baseAlias, availableColumns) {
|
|
2580
|
+
if (term.type === "Column") {
|
|
2581
|
+
const col2 = term;
|
|
2582
|
+
if (col2.table !== plan.rootTable) return null;
|
|
2583
|
+
const alias = projectionAliases.get(`${col2.table}.${col2.name}`) ?? col2.name;
|
|
2584
|
+
if (!availableColumns.has(alias)) return null;
|
|
2585
|
+
return { type: "Column", table: baseAlias, name: alias };
|
|
2586
|
+
}
|
|
2587
|
+
if (term.type === "AliasRef") {
|
|
2588
|
+
const aliasName = term.name;
|
|
2589
|
+
if (!availableColumns.has(aliasName)) return null;
|
|
2590
|
+
return { type: "Column", table: baseAlias, name: aliasName };
|
|
2591
|
+
}
|
|
2592
|
+
return null;
|
|
2593
|
+
}
|
|
2508
2594
|
buildPagingColumns(primaryKey, orderBy, tableAlias) {
|
|
2509
2595
|
const columns = [{ type: "Column", table: tableAlias, name: primaryKey, alias: primaryKey }];
|
|
2510
2596
|
if (!orderBy) return columns;
|
|
2511
2597
|
for (const ob of orderBy) {
|
|
2512
|
-
|
|
2598
|
+
const term = ob.term;
|
|
2599
|
+
if (!columns.some((col2) => col2.name === term.name)) {
|
|
2513
2600
|
columns.push({
|
|
2514
2601
|
type: "Column",
|
|
2515
2602
|
table: tableAlias,
|
|
2516
|
-
name:
|
|
2517
|
-
alias:
|
|
2603
|
+
name: term.name,
|
|
2604
|
+
alias: term.name
|
|
2518
2605
|
});
|
|
2519
2606
|
}
|
|
2520
2607
|
}
|
|
@@ -2820,10 +2907,8 @@ var QueryAstService = class {
|
|
|
2820
2907
|
* @returns Updated query state with GROUP BY clause
|
|
2821
2908
|
*/
|
|
2822
2909
|
withGroupBy(col2) {
|
|
2823
|
-
const
|
|
2824
|
-
|
|
2825
|
-
const node = buildColumnNode(tableRef, col2);
|
|
2826
|
-
return this.state.withGroupBy([node]);
|
|
2910
|
+
const term = this.normalizeOrderingTerm(col2);
|
|
2911
|
+
return this.state.withGroupBy([term]);
|
|
2827
2912
|
}
|
|
2828
2913
|
/**
|
|
2829
2914
|
* Adds a HAVING clause to the query
|
|
@@ -2840,11 +2925,9 @@ var QueryAstService = class {
|
|
|
2840
2925
|
* @param direction - Order direction (ASC/DESC)
|
|
2841
2926
|
* @returns Updated query state with ORDER BY clause
|
|
2842
2927
|
*/
|
|
2843
|
-
withOrderBy(
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
const node = buildColumnNode(tableRef, col2);
|
|
2847
|
-
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
2928
|
+
withOrderBy(term, direction, nulls, collation) {
|
|
2929
|
+
const normalized = this.normalizeOrderingTerm(term);
|
|
2930
|
+
return this.state.withOrderBy([{ type: "OrderBy", term: normalized, direction, nulls, collation }]);
|
|
2848
2931
|
}
|
|
2849
2932
|
/**
|
|
2850
2933
|
* Adds a DISTINCT clause to the query
|
|
@@ -2879,6 +2962,24 @@ var QueryAstService = class {
|
|
|
2879
2962
|
combineExpressions(existing, next) {
|
|
2880
2963
|
return existing ? and(existing, next) : next;
|
|
2881
2964
|
}
|
|
2965
|
+
normalizeOrderingTerm(term) {
|
|
2966
|
+
const from = this.state.ast.from;
|
|
2967
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
2968
|
+
const termType = term?.type;
|
|
2969
|
+
if (termType === "Column") {
|
|
2970
|
+
return term;
|
|
2971
|
+
}
|
|
2972
|
+
if (termType === "AliasRef") {
|
|
2973
|
+
return term;
|
|
2974
|
+
}
|
|
2975
|
+
if (isOperandNode(term)) {
|
|
2976
|
+
return term;
|
|
2977
|
+
}
|
|
2978
|
+
if (termType === "BinaryExpression" || termType === "LogicalExpression" || termType === "NullExpression" || termType === "InExpression" || termType === "ExistsExpression" || termType === "BetweenExpression" || termType === "ArithmeticExpression") {
|
|
2979
|
+
return term;
|
|
2980
|
+
}
|
|
2981
|
+
return buildColumnNode(tableRef, term);
|
|
2982
|
+
}
|
|
2882
2983
|
};
|
|
2883
2984
|
|
|
2884
2985
|
// src/query-builder/relation-projection-helper.ts
|
|
@@ -4528,8 +4629,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4528
4629
|
* @returns New query builder instance with the subquery selection
|
|
4529
4630
|
|
|
4530
4631
|
*/
|
|
4531
|
-
selectSubquery(alias,
|
|
4532
|
-
const query = this.resolveQueryNode(
|
|
4632
|
+
selectSubquery(alias, sub2) {
|
|
4633
|
+
const query = this.resolveQueryNode(sub2);
|
|
4533
4634
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4534
4635
|
}
|
|
4535
4636
|
/**
|
|
@@ -4711,16 +4812,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4711
4812
|
return this.clone(nextContext);
|
|
4712
4813
|
}
|
|
4713
4814
|
/**
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
*/
|
|
4722
|
-
groupBy(col2) {
|
|
4723
|
-
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
4815
|
+
* Adds a GROUP BY clause to the query
|
|
4816
|
+
* @param term - Column definition or ordering term to group by
|
|
4817
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
4818
|
+
*/
|
|
4819
|
+
groupBy(term) {
|
|
4820
|
+
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(term));
|
|
4724
4821
|
return this.clone(nextContext);
|
|
4725
4822
|
}
|
|
4726
4823
|
/**
|
|
@@ -4737,18 +4834,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4737
4834
|
return this.clone(nextContext);
|
|
4738
4835
|
}
|
|
4739
4836
|
/**
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4837
|
+
* Adds an ORDER BY clause to the query
|
|
4838
|
+
* @param term - Column definition or ordering term to order by
|
|
4839
|
+
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
4840
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
4841
|
+
*/
|
|
4842
|
+
orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
|
|
4843
|
+
const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
|
|
4844
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
4845
|
+
const nextContext = this.applyAst(
|
|
4846
|
+
this.context,
|
|
4847
|
+
(service) => service.withOrderBy(term, dir, options.nulls, options.collation)
|
|
4848
|
+
);
|
|
4752
4849
|
return this.clone(nextContext);
|
|
4753
4850
|
}
|
|
4754
4851
|
/**
|
|
@@ -6576,7 +6673,7 @@ var TypeScriptGenerator = class {
|
|
|
6576
6673
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
6577
6674
|
}
|
|
6578
6675
|
if (ast.groupBy && ast.groupBy.length) {
|
|
6579
|
-
const cols = ast.groupBy.map((
|
|
6676
|
+
const cols = ast.groupBy.map((term) => this.printOrderingTerm(term)).join(", ");
|
|
6580
6677
|
lines.push(`.groupBy(${cols})`);
|
|
6581
6678
|
}
|
|
6582
6679
|
if (ast.having) {
|
|
@@ -6584,7 +6681,16 @@ var TypeScriptGenerator = class {
|
|
|
6584
6681
|
}
|
|
6585
6682
|
if (ast.orderBy && ast.orderBy.length) {
|
|
6586
6683
|
ast.orderBy.forEach((o) => {
|
|
6587
|
-
|
|
6684
|
+
const term = this.printOrderingTerm(o.term);
|
|
6685
|
+
const opts = [`direction: '${o.direction}'`];
|
|
6686
|
+
if (o.nulls) opts.push(`nulls: '${o.nulls}'`);
|
|
6687
|
+
if (o.collation) opts.push(`collation: '${o.collation}'`);
|
|
6688
|
+
const hasOpts = opts.length > 1;
|
|
6689
|
+
if (hasOpts) {
|
|
6690
|
+
lines.push(`.orderBy(${term}, { ${opts.join(", ")} })`);
|
|
6691
|
+
} else {
|
|
6692
|
+
lines.push(`.orderBy(${term}, '${o.direction}')`);
|
|
6693
|
+
}
|
|
6588
6694
|
});
|
|
6589
6695
|
}
|
|
6590
6696
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -6607,6 +6713,29 @@ var TypeScriptGenerator = class {
|
|
|
6607
6713
|
printOperand(node) {
|
|
6608
6714
|
return visitOperand(node, this);
|
|
6609
6715
|
}
|
|
6716
|
+
/**
|
|
6717
|
+
* Prints an ordering term (operand/expression/alias) to TypeScript code.
|
|
6718
|
+
*/
|
|
6719
|
+
printOrderingTerm(term) {
|
|
6720
|
+
if (!term || !term.type) {
|
|
6721
|
+
throw new Error("Unsupported ordering term");
|
|
6722
|
+
}
|
|
6723
|
+
switch (term.type) {
|
|
6724
|
+
case "Column":
|
|
6725
|
+
return `${this.namingStrategy.tableToSymbol(term.table)}.${term.name}`;
|
|
6726
|
+
case "AliasRef":
|
|
6727
|
+
return this.visitAliasRef(term);
|
|
6728
|
+
case "Literal":
|
|
6729
|
+
case "Function":
|
|
6730
|
+
case "JsonPath":
|
|
6731
|
+
case "ScalarSubquery":
|
|
6732
|
+
case "CaseExpression":
|
|
6733
|
+
case "WindowFunction":
|
|
6734
|
+
return this.printOperand(term);
|
|
6735
|
+
default:
|
|
6736
|
+
return this.printExpression(term);
|
|
6737
|
+
}
|
|
6738
|
+
}
|
|
6610
6739
|
visitBinaryExpression(binary) {
|
|
6611
6740
|
return this.printBinaryExpression(binary);
|
|
6612
6741
|
}
|
|
@@ -6625,6 +6754,9 @@ var TypeScriptGenerator = class {
|
|
|
6625
6754
|
visitBetweenExpression(betweenExpr) {
|
|
6626
6755
|
return this.printBetweenExpression(betweenExpr);
|
|
6627
6756
|
}
|
|
6757
|
+
visitArithmeticExpression(arithExpr) {
|
|
6758
|
+
return this.printArithmeticExpression(arithExpr);
|
|
6759
|
+
}
|
|
6628
6760
|
visitColumn(node) {
|
|
6629
6761
|
return this.printColumnOperand(node);
|
|
6630
6762
|
}
|
|
@@ -6646,6 +6778,9 @@ var TypeScriptGenerator = class {
|
|
|
6646
6778
|
visitWindowFunction(node) {
|
|
6647
6779
|
return this.printWindowFunctionOperand(node);
|
|
6648
6780
|
}
|
|
6781
|
+
visitAliasRef(node) {
|
|
6782
|
+
return `aliasRef('${node.name}')`;
|
|
6783
|
+
}
|
|
6649
6784
|
/**
|
|
6650
6785
|
* Prints a binary expression to TypeScript code
|
|
6651
6786
|
* @param binary - Binary expression node
|
|
@@ -6676,6 +6811,11 @@ var TypeScriptGenerator = class {
|
|
|
6676
6811
|
${parts.join(",\n ")}
|
|
6677
6812
|
)`;
|
|
6678
6813
|
}
|
|
6814
|
+
printArithmeticExpression(expr) {
|
|
6815
|
+
const left2 = this.printOperand(expr.left);
|
|
6816
|
+
const right2 = this.printOperand(expr.right);
|
|
6817
|
+
return `${left2} ${expr.operator} ${right2}`;
|
|
6818
|
+
}
|
|
6679
6819
|
/**
|
|
6680
6820
|
* Prints an IN expression to TypeScript code
|
|
6681
6821
|
* @param inExpr - IN expression node
|
|
@@ -6789,7 +6929,12 @@ var TypeScriptGenerator = class {
|
|
|
6789
6929
|
parts.push(partitionClause);
|
|
6790
6930
|
}
|
|
6791
6931
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6792
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) =>
|
|
6932
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => {
|
|
6933
|
+
const term = this.printOrderingTerm(o.term);
|
|
6934
|
+
const collation = o.collation ? ` COLLATE ${o.collation}` : "";
|
|
6935
|
+
const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
6936
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
6937
|
+
}).join(", ");
|
|
6793
6938
|
parts.push(orderClause);
|
|
6794
6939
|
}
|
|
6795
6940
|
result += parts.join(" ");
|
|
@@ -7966,7 +8111,9 @@ export {
|
|
|
7966
8111
|
UpdateQueryBuilder,
|
|
7967
8112
|
abs,
|
|
7968
8113
|
acos,
|
|
8114
|
+
add,
|
|
7969
8115
|
addDomainEvent,
|
|
8116
|
+
aliasRef,
|
|
7970
8117
|
and,
|
|
7971
8118
|
ascii,
|
|
7972
8119
|
asin,
|
|
@@ -8017,6 +8164,7 @@ export {
|
|
|
8017
8164
|
degrees,
|
|
8018
8165
|
denseRank,
|
|
8019
8166
|
diffSchema,
|
|
8167
|
+
div,
|
|
8020
8168
|
endOfMonth,
|
|
8021
8169
|
eq,
|
|
8022
8170
|
esel,
|
|
@@ -8074,6 +8222,7 @@ export {
|
|
|
8074
8222
|
min,
|
|
8075
8223
|
mod,
|
|
8076
8224
|
month,
|
|
8225
|
+
mul,
|
|
8077
8226
|
neq,
|
|
8078
8227
|
notBetween,
|
|
8079
8228
|
notExists,
|
|
@@ -8109,6 +8258,7 @@ export {
|
|
|
8109
8258
|
sin,
|
|
8110
8259
|
space,
|
|
8111
8260
|
sqrt,
|
|
8261
|
+
sub,
|
|
8112
8262
|
substr,
|
|
8113
8263
|
sum,
|
|
8114
8264
|
synchronizeSchema,
|