metal-orm 1.0.39 → 1.0.41
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 +1466 -189
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +723 -51
- package/dist/index.d.ts +723 -51
- package/dist/index.js +1457 -189
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/codegen/typescript.ts +66 -5
- package/src/core/ast/aggregate-functions.ts +15 -15
- package/src/core/ast/expression-builders.ts +378 -316
- package/src/core/ast/expression-nodes.ts +210 -186
- package/src/core/ast/expression-visitor.ts +40 -30
- package/src/core/ast/query.ts +164 -132
- package/src/core/ast/window-functions.ts +86 -86
- package/src/core/dialect/abstract.ts +509 -479
- package/src/core/dialect/base/groupby-compiler.ts +6 -6
- package/src/core/dialect/base/join-compiler.ts +9 -12
- package/src/core/dialect/base/orderby-compiler.ts +20 -6
- package/src/core/dialect/base/sql-dialect.ts +237 -138
- package/src/core/dialect/mssql/index.ts +164 -185
- package/src/core/dialect/sqlite/index.ts +39 -34
- package/src/core/execution/db-executor.ts +46 -6
- package/src/core/execution/executors/mssql-executor.ts +39 -22
- package/src/core/execution/executors/mysql-executor.ts +23 -6
- package/src/core/execution/executors/sqlite-executor.ts +29 -3
- package/src/core/execution/pooling/pool-types.ts +30 -0
- package/src/core/execution/pooling/pool.ts +268 -0
- package/src/core/functions/standard-strategy.ts +46 -37
- package/src/decorators/bootstrap.ts +7 -7
- package/src/index.ts +6 -0
- package/src/orm/domain-event-bus.ts +49 -0
- package/src/orm/entity-metadata.ts +9 -9
- package/src/orm/entity.ts +58 -0
- package/src/orm/orm-session.ts +465 -270
- package/src/orm/orm.ts +61 -11
- package/src/orm/pooled-executor-factory.ts +131 -0
- package/src/orm/query-logger.ts +6 -12
- package/src/orm/relation-change-processor.ts +75 -0
- package/src/orm/relations/many-to-many.ts +4 -2
- package/src/orm/save-graph.ts +303 -0
- package/src/orm/transaction-runner.ts +3 -3
- package/src/orm/unit-of-work.ts +128 -0
- package/src/query-builder/delete-query-state.ts +67 -38
- package/src/query-builder/delete.ts +37 -1
- package/src/query-builder/hydration-manager.ts +93 -79
- package/src/query-builder/insert-query-state.ts +131 -61
- package/src/query-builder/insert.ts +27 -1
- 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/src/query-builder/update-query-state.ts +114 -77
- package/src/query-builder/update.ts +38 -1
package/dist/index.cjs
CHANGED
|
@@ -60,6 +60,7 @@ __export(index_exports, {
|
|
|
60
60
|
MySqlDialect: () => MySqlDialect,
|
|
61
61
|
Orm: () => Orm,
|
|
62
62
|
OrmSession: () => OrmSession,
|
|
63
|
+
Pool: () => Pool,
|
|
63
64
|
PostgresDialect: () => PostgresDialect,
|
|
64
65
|
PrimaryKey: () => PrimaryKey,
|
|
65
66
|
RelationKinds: () => RelationKinds,
|
|
@@ -70,7 +71,9 @@ __export(index_exports, {
|
|
|
70
71
|
UpdateQueryBuilder: () => UpdateQueryBuilder,
|
|
71
72
|
abs: () => abs,
|
|
72
73
|
acos: () => acos,
|
|
74
|
+
add: () => add,
|
|
73
75
|
addDomainEvent: () => addDomainEvent,
|
|
76
|
+
aliasRef: () => aliasRef,
|
|
74
77
|
and: () => and,
|
|
75
78
|
ascii: () => ascii,
|
|
76
79
|
asin: () => asin,
|
|
@@ -103,6 +106,7 @@ __export(index_exports, {
|
|
|
103
106
|
createLiteral: () => createLiteral,
|
|
104
107
|
createMssqlExecutor: () => createMssqlExecutor,
|
|
105
108
|
createMysqlExecutor: () => createMysqlExecutor,
|
|
109
|
+
createPooledExecutorFactory: () => createPooledExecutorFactory,
|
|
106
110
|
createPostgresExecutor: () => createPostgresExecutor,
|
|
107
111
|
createQueryLoggingExecutor: () => createQueryLoggingExecutor,
|
|
108
112
|
createSqliteExecutor: () => createSqliteExecutor,
|
|
@@ -121,6 +125,7 @@ __export(index_exports, {
|
|
|
121
125
|
degrees: () => degrees,
|
|
122
126
|
denseRank: () => denseRank,
|
|
123
127
|
diffSchema: () => diffSchema,
|
|
128
|
+
div: () => div,
|
|
124
129
|
endOfMonth: () => endOfMonth,
|
|
125
130
|
eq: () => eq,
|
|
126
131
|
esel: () => esel,
|
|
@@ -143,6 +148,7 @@ __export(index_exports, {
|
|
|
143
148
|
hasOne: () => hasOne,
|
|
144
149
|
hydrateRows: () => hydrateRows,
|
|
145
150
|
inList: () => inList,
|
|
151
|
+
inSubquery: () => inSubquery,
|
|
146
152
|
instr: () => instr,
|
|
147
153
|
introspectSchema: () => introspectSchema,
|
|
148
154
|
isCaseExpressionNode: () => isCaseExpressionNode,
|
|
@@ -178,10 +184,12 @@ __export(index_exports, {
|
|
|
178
184
|
min: () => min,
|
|
179
185
|
mod: () => mod,
|
|
180
186
|
month: () => month,
|
|
187
|
+
mul: () => mul,
|
|
181
188
|
neq: () => neq,
|
|
182
189
|
notBetween: () => notBetween,
|
|
183
190
|
notExists: () => notExists,
|
|
184
191
|
notInList: () => notInList,
|
|
192
|
+
notInSubquery: () => notInSubquery,
|
|
185
193
|
notLike: () => notLike,
|
|
186
194
|
now: () => now,
|
|
187
195
|
ntile: () => ntile,
|
|
@@ -213,6 +221,7 @@ __export(index_exports, {
|
|
|
213
221
|
sin: () => sin,
|
|
214
222
|
space: () => space,
|
|
215
223
|
sqrt: () => sqrt,
|
|
224
|
+
sub: () => sub,
|
|
216
225
|
substr: () => substr,
|
|
217
226
|
sum: () => sum,
|
|
218
227
|
synchronizeSchema: () => synchronizeSchema,
|
|
@@ -450,6 +459,7 @@ var belongsToMany = (target, pivotTable, options) => ({
|
|
|
450
459
|
|
|
451
460
|
// src/core/ast/expression-nodes.ts
|
|
452
461
|
var operandTypes = /* @__PURE__ */ new Set([
|
|
462
|
+
"AliasRef",
|
|
453
463
|
"Column",
|
|
454
464
|
"Literal",
|
|
455
465
|
"Function",
|
|
@@ -491,11 +501,21 @@ var toOperand = (val) => {
|
|
|
491
501
|
}
|
|
492
502
|
return toNode(val);
|
|
493
503
|
};
|
|
504
|
+
var hasQueryAst = (value) => typeof value.getAST === "function";
|
|
505
|
+
var resolveSelectQueryNode = (query) => hasQueryAst(query) ? query.getAST() : query;
|
|
506
|
+
var toScalarSubqueryNode = (query) => ({
|
|
507
|
+
type: "ScalarSubquery",
|
|
508
|
+
query: resolveSelectQueryNode(query)
|
|
509
|
+
});
|
|
494
510
|
var columnOperand = (col2) => toNode(col2);
|
|
495
511
|
var outerRef = (col2) => ({
|
|
496
512
|
...columnOperand(col2),
|
|
497
513
|
scope: "outer"
|
|
498
514
|
});
|
|
515
|
+
var aliasRef = (name) => ({
|
|
516
|
+
type: "AliasRef",
|
|
517
|
+
name
|
|
518
|
+
});
|
|
499
519
|
var correlateBy = (table, column) => outerRef({ name: column, table });
|
|
500
520
|
var createBinaryExpression = (operator, left2, right2, escape) => {
|
|
501
521
|
const node = {
|
|
@@ -537,14 +557,16 @@ var isNotNull = (left2) => ({
|
|
|
537
557
|
left: toNode(left2),
|
|
538
558
|
operator: "IS NOT NULL"
|
|
539
559
|
});
|
|
540
|
-
var createInExpression = (operator, left2,
|
|
560
|
+
var createInExpression = (operator, left2, right2) => ({
|
|
541
561
|
type: "InExpression",
|
|
542
562
|
left: toNode(left2),
|
|
543
563
|
operator,
|
|
544
|
-
right:
|
|
564
|
+
right: right2
|
|
545
565
|
});
|
|
546
|
-
var inList = (left2, values) => createInExpression("IN", left2, values);
|
|
547
|
-
var notInList = (left2, values) => createInExpression("NOT IN", left2, values);
|
|
566
|
+
var inList = (left2, values) => createInExpression("IN", left2, values.map((v) => toOperand(v)));
|
|
567
|
+
var notInList = (left2, values) => createInExpression("NOT IN", left2, values.map((v) => toOperand(v)));
|
|
568
|
+
var inSubquery = (left2, subquery) => createInExpression("IN", left2, toScalarSubqueryNode(subquery));
|
|
569
|
+
var notInSubquery = (left2, subquery) => createInExpression("NOT IN", left2, toScalarSubqueryNode(subquery));
|
|
548
570
|
var createBetweenExpression = (operator, left2, lower2, upper2) => ({
|
|
549
571
|
type: "BetweenExpression",
|
|
550
572
|
left: toNode(left2),
|
|
@@ -554,6 +576,16 @@ var createBetweenExpression = (operator, left2, lower2, upper2) => ({
|
|
|
554
576
|
});
|
|
555
577
|
var between = (left2, lower2, upper2) => createBetweenExpression("BETWEEN", left2, lower2, upper2);
|
|
556
578
|
var notBetween = (left2, lower2, upper2) => createBetweenExpression("NOT BETWEEN", left2, lower2, upper2);
|
|
579
|
+
var createArithmeticExpression = (operator, left2, right2) => ({
|
|
580
|
+
type: "ArithmeticExpression",
|
|
581
|
+
left: toOperand(left2),
|
|
582
|
+
operator,
|
|
583
|
+
right: toOperand(right2)
|
|
584
|
+
});
|
|
585
|
+
var add = (left2, right2) => createArithmeticExpression("+", left2, right2);
|
|
586
|
+
var sub = (left2, right2) => createArithmeticExpression("-", left2, right2);
|
|
587
|
+
var mul = (left2, right2) => createArithmeticExpression("*", left2, right2);
|
|
588
|
+
var div = (left2, right2) => createArithmeticExpression("/", left2, right2);
|
|
557
589
|
var jsonPath = (col2, path) => ({
|
|
558
590
|
type: "JsonPath",
|
|
559
591
|
column: columnOperand(col2),
|
|
@@ -632,7 +664,7 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
|
|
|
632
664
|
const partitionNodes = partitionBy?.map((col2) => columnOperand(col2)) ?? void 0;
|
|
633
665
|
const orderNodes = orderBy?.map((o) => ({
|
|
634
666
|
type: "OrderBy",
|
|
635
|
-
|
|
667
|
+
term: columnOperand(o.column),
|
|
636
668
|
direction: o.direction
|
|
637
669
|
}));
|
|
638
670
|
return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
|
|
@@ -707,7 +739,7 @@ var min = buildAggregate("MIN");
|
|
|
707
739
|
var max = buildAggregate("MAX");
|
|
708
740
|
var toOrderByNode = (order) => ({
|
|
709
741
|
type: "OrderBy",
|
|
710
|
-
|
|
742
|
+
term: columnOperand(order.column),
|
|
711
743
|
direction: order.direction ?? ORDER_DIRECTIONS.ASC
|
|
712
744
|
});
|
|
713
745
|
var groupConcat = (col2, options) => ({
|
|
@@ -757,6 +789,9 @@ var visitExpression = (node, visitor) => {
|
|
|
757
789
|
case "BetweenExpression":
|
|
758
790
|
if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node);
|
|
759
791
|
break;
|
|
792
|
+
case "ArithmeticExpression":
|
|
793
|
+
if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
|
|
794
|
+
break;
|
|
760
795
|
default:
|
|
761
796
|
break;
|
|
762
797
|
}
|
|
@@ -788,6 +823,9 @@ var visitOperand = (node, visitor) => {
|
|
|
788
823
|
case "WindowFunction":
|
|
789
824
|
if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node);
|
|
790
825
|
break;
|
|
826
|
+
case "AliasRef":
|
|
827
|
+
if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
|
|
828
|
+
break;
|
|
791
829
|
default:
|
|
792
830
|
break;
|
|
793
831
|
}
|
|
@@ -904,7 +942,14 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
|
|
|
904
942
|
if (!orderBy || orderBy.length === 0) {
|
|
905
943
|
return "";
|
|
906
944
|
}
|
|
907
|
-
const parts = orderBy.map((order) =>
|
|
945
|
+
const parts = orderBy.map((order) => {
|
|
946
|
+
const term = isOperandNode(order.term) ? ctx.compileOperand(order.term) : (() => {
|
|
947
|
+
throw new Error("ORDER BY expressions inside functions must be operands");
|
|
948
|
+
})();
|
|
949
|
+
const collation = order.collation ? ` COLLATE ${order.collation}` : "";
|
|
950
|
+
const nulls = order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
951
|
+
return `${term} ${order.direction}${collation}${nulls}`;
|
|
952
|
+
});
|
|
908
953
|
return `ORDER BY ${parts.join(", ")}`;
|
|
909
954
|
}
|
|
910
955
|
formatGroupConcatSeparator(ctx) {
|
|
@@ -1169,6 +1214,16 @@ var Dialect = class _Dialect {
|
|
|
1169
1214
|
}
|
|
1170
1215
|
return compiler(node, ctx);
|
|
1171
1216
|
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Compiles an ordering term (operand, expression, or alias reference).
|
|
1219
|
+
*/
|
|
1220
|
+
compileOrderingTerm(term, ctx) {
|
|
1221
|
+
if (isOperandNode(term)) {
|
|
1222
|
+
return this.compileOperand(term, ctx);
|
|
1223
|
+
}
|
|
1224
|
+
const expr = this.compileExpression(term, ctx);
|
|
1225
|
+
return `(${expr})`;
|
|
1226
|
+
}
|
|
1172
1227
|
registerDefaultExpressionCompilers() {
|
|
1173
1228
|
this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
|
|
1174
1229
|
const left2 = this.compileOperand(binary.left, ctx);
|
|
@@ -1194,8 +1249,12 @@ var Dialect = class _Dialect {
|
|
|
1194
1249
|
});
|
|
1195
1250
|
this.registerExpressionCompiler("InExpression", (inExpr, ctx) => {
|
|
1196
1251
|
const left2 = this.compileOperand(inExpr.left, ctx);
|
|
1197
|
-
|
|
1198
|
-
|
|
1252
|
+
if (Array.isArray(inExpr.right)) {
|
|
1253
|
+
const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
|
|
1254
|
+
return `${left2} ${inExpr.operator} (${values})`;
|
|
1255
|
+
}
|
|
1256
|
+
const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
|
|
1257
|
+
return `${left2} ${inExpr.operator} (${subquerySql})`;
|
|
1199
1258
|
});
|
|
1200
1259
|
this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
|
|
1201
1260
|
const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
|
|
@@ -1207,9 +1266,15 @@ var Dialect = class _Dialect {
|
|
|
1207
1266
|
const upper2 = this.compileOperand(betweenExpr.upper, ctx);
|
|
1208
1267
|
return `${left2} ${betweenExpr.operator} ${lower2} AND ${upper2}`;
|
|
1209
1268
|
});
|
|
1269
|
+
this.registerExpressionCompiler("ArithmeticExpression", (arith, ctx) => {
|
|
1270
|
+
const left2 = this.compileOperand(arith.left, ctx);
|
|
1271
|
+
const right2 = this.compileOperand(arith.right, ctx);
|
|
1272
|
+
return `${left2} ${arith.operator} ${right2}`;
|
|
1273
|
+
});
|
|
1210
1274
|
}
|
|
1211
1275
|
registerDefaultOperandCompilers() {
|
|
1212
1276
|
this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
|
|
1277
|
+
this.registerOperandCompiler("AliasRef", (alias, _ctx) => this.quoteIdentifier(alias.name));
|
|
1213
1278
|
this.registerOperandCompiler("Column", (column, _ctx) => {
|
|
1214
1279
|
return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
|
|
1215
1280
|
});
|
|
@@ -1247,9 +1312,12 @@ var Dialect = class _Dialect {
|
|
|
1247
1312
|
parts.push(partitionClause);
|
|
1248
1313
|
}
|
|
1249
1314
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
1250
|
-
const orderClause = "ORDER BY " + node.orderBy.map(
|
|
1251
|
-
|
|
1252
|
-
|
|
1315
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => {
|
|
1316
|
+
const term = this.compileOrderingTerm(o.term, ctx);
|
|
1317
|
+
const collation = o.collation ? ` COLLATE ${o.collation}` : "";
|
|
1318
|
+
const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
1319
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
1320
|
+
}).join(", ");
|
|
1253
1321
|
parts.push(orderClause);
|
|
1254
1322
|
}
|
|
1255
1323
|
result += parts.join(" ");
|
|
@@ -1444,17 +1512,9 @@ var NoReturningStrategy = class {
|
|
|
1444
1512
|
|
|
1445
1513
|
// src/core/dialect/base/join-compiler.ts
|
|
1446
1514
|
var JoinCompiler = class {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
* @param ctx - The compiler context for expression compilation.
|
|
1451
|
-
* @param compileFrom - Function to compile table sources (tables or subqueries).
|
|
1452
|
-
* @param compileExpression - Function to compile join condition expressions.
|
|
1453
|
-
* @returns SQL JOIN clauses (e.g., " LEFT JOIN table ON condition") or empty string if no joins.
|
|
1454
|
-
*/
|
|
1455
|
-
static compileJoins(ast, ctx, compileFrom, compileExpression) {
|
|
1456
|
-
if (!ast.joins || ast.joins.length === 0) return "";
|
|
1457
|
-
const parts = ast.joins.map((j) => {
|
|
1515
|
+
static compileJoins(joins, ctx, compileFrom, compileExpression) {
|
|
1516
|
+
if (!joins || joins.length === 0) return "";
|
|
1517
|
+
const parts = joins.map((j) => {
|
|
1458
1518
|
const table = compileFrom(j.table, ctx);
|
|
1459
1519
|
const cond = compileExpression(j.condition, ctx);
|
|
1460
1520
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
@@ -1468,12 +1528,12 @@ var GroupByCompiler = class {
|
|
|
1468
1528
|
/**
|
|
1469
1529
|
* Compiles GROUP BY clause from a SELECT query AST.
|
|
1470
1530
|
* @param ast - The SELECT query AST containing grouping columns.
|
|
1471
|
-
* @param
|
|
1531
|
+
* @param renderTerm - Function to render a grouping term.
|
|
1472
1532
|
* @returns SQL GROUP BY clause (e.g., " GROUP BY table.col1, table.col2") or empty string if no grouping.
|
|
1473
1533
|
*/
|
|
1474
|
-
static compileGroupBy(ast,
|
|
1534
|
+
static compileGroupBy(ast, renderTerm) {
|
|
1475
1535
|
if (!ast.groupBy || ast.groupBy.length === 0) return "";
|
|
1476
|
-
const cols = ast.groupBy.map(
|
|
1536
|
+
const cols = ast.groupBy.map(renderTerm).join(", ");
|
|
1477
1537
|
return ` GROUP BY ${cols}`;
|
|
1478
1538
|
}
|
|
1479
1539
|
};
|
|
@@ -1483,12 +1543,19 @@ var OrderByCompiler = class {
|
|
|
1483
1543
|
/**
|
|
1484
1544
|
* Compiles ORDER BY clause from a SELECT query AST.
|
|
1485
1545
|
* @param ast - The SELECT query AST containing sort specifications.
|
|
1486
|
-
* @param
|
|
1546
|
+
* @param renderTerm - Function to render an ordering term.
|
|
1547
|
+
* @param renderNulls - Optional function to render NULLS FIRST/LAST.
|
|
1548
|
+
* @param renderCollation - Optional function to render COLLATE clause.
|
|
1487
1549
|
* @returns SQL ORDER BY clause (e.g., " ORDER BY table.col1 ASC, table.col2 DESC") or empty string if no ordering.
|
|
1488
1550
|
*/
|
|
1489
|
-
static compileOrderBy(ast,
|
|
1551
|
+
static compileOrderBy(ast, renderTerm, renderNulls, renderCollation) {
|
|
1490
1552
|
if (!ast.orderBy || ast.orderBy.length === 0) return "";
|
|
1491
|
-
const parts = ast.orderBy.map((o) =>
|
|
1553
|
+
const parts = ast.orderBy.map((o) => {
|
|
1554
|
+
const term = renderTerm(o.term);
|
|
1555
|
+
const collation = renderCollation ? renderCollation(o) : o.collation ? ` COLLATE ${o.collation}` : "";
|
|
1556
|
+
const nulls = renderNulls ? renderNulls(o) : o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
1557
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
1558
|
+
}).join(", ");
|
|
1492
1559
|
return ` ORDER BY ${parts}`;
|
|
1493
1560
|
}
|
|
1494
1561
|
};
|
|
@@ -1519,58 +1586,96 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1519
1586
|
}
|
|
1520
1587
|
compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
|
|
1521
1588
|
const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
|
|
1522
|
-
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1589
|
+
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1590
|
+
ast,
|
|
1591
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
1592
|
+
this.renderOrderByNulls.bind(this),
|
|
1593
|
+
this.renderOrderByCollation.bind(this)
|
|
1594
|
+
);
|
|
1523
1595
|
const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
|
|
1524
1596
|
const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
|
|
1525
1597
|
return `${ctes}${combined}${orderBy}${pagination}`;
|
|
1526
1598
|
}
|
|
1527
1599
|
compileInsertAst(ast, ctx) {
|
|
1600
|
+
if (!ast.columns.length) {
|
|
1601
|
+
throw new Error("INSERT queries must specify columns.");
|
|
1602
|
+
}
|
|
1528
1603
|
const table = this.compileTableName(ast.into);
|
|
1529
1604
|
const columnList = this.compileInsertColumnList(ast.columns);
|
|
1530
|
-
const
|
|
1605
|
+
const source = this.compileInsertSource(ast.source, ctx);
|
|
1531
1606
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1532
|
-
return `INSERT INTO ${table} (${columnList})
|
|
1607
|
+
return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
|
|
1533
1608
|
}
|
|
1534
1609
|
compileReturning(returning, ctx) {
|
|
1535
1610
|
return this.returningStrategy.compileReturning(returning, ctx);
|
|
1536
1611
|
}
|
|
1612
|
+
compileInsertSource(source, ctx) {
|
|
1613
|
+
if (source.type === "InsertValues") {
|
|
1614
|
+
if (!source.rows.length) {
|
|
1615
|
+
throw new Error("INSERT ... VALUES requires at least one row.");
|
|
1616
|
+
}
|
|
1617
|
+
const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
1618
|
+
return `VALUES ${values}`;
|
|
1619
|
+
}
|
|
1620
|
+
const normalized = this.normalizeSelectAst(source.query);
|
|
1621
|
+
return this.compileSelectAst(normalized, ctx).trim();
|
|
1622
|
+
}
|
|
1537
1623
|
compileInsertColumnList(columns) {
|
|
1538
1624
|
return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
|
|
1539
1625
|
}
|
|
1540
|
-
compileInsertValues(values, ctx) {
|
|
1541
|
-
return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
1542
|
-
}
|
|
1543
1626
|
compileSelectCore(ast, ctx) {
|
|
1544
1627
|
const columns = this.compileSelectColumns(ast, ctx);
|
|
1545
1628
|
const from = this.compileFrom(ast.from, ctx);
|
|
1546
|
-
const joins = JoinCompiler.compileJoins(
|
|
1629
|
+
const joins = JoinCompiler.compileJoins(
|
|
1630
|
+
ast.joins,
|
|
1631
|
+
ctx,
|
|
1632
|
+
this.compileFrom.bind(this),
|
|
1633
|
+
this.compileExpression.bind(this)
|
|
1634
|
+
);
|
|
1547
1635
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1548
|
-
const groupBy = GroupByCompiler.compileGroupBy(ast, this.
|
|
1636
|
+
const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
|
|
1549
1637
|
const having = this.compileHaving(ast, ctx);
|
|
1550
|
-
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1638
|
+
const orderBy = OrderByCompiler.compileOrderBy(
|
|
1639
|
+
ast,
|
|
1640
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
1641
|
+
this.renderOrderByNulls.bind(this),
|
|
1642
|
+
this.renderOrderByCollation.bind(this)
|
|
1643
|
+
);
|
|
1551
1644
|
const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
|
|
1552
1645
|
return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
|
|
1553
1646
|
}
|
|
1554
1647
|
compileUpdateAst(ast, ctx) {
|
|
1555
|
-
const
|
|
1556
|
-
const assignments = this.compileUpdateAssignments(ast.set, ctx);
|
|
1648
|
+
const target = this.compileTableReference(ast.table);
|
|
1649
|
+
const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
|
|
1650
|
+
const fromClause = this.compileUpdateFromClause(ast, ctx);
|
|
1557
1651
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1558
1652
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1559
|
-
return `UPDATE ${
|
|
1653
|
+
return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
|
|
1560
1654
|
}
|
|
1561
|
-
compileUpdateAssignments(assignments, ctx) {
|
|
1655
|
+
compileUpdateAssignments(assignments, table, ctx) {
|
|
1562
1656
|
return assignments.map((assignment) => {
|
|
1563
1657
|
const col2 = assignment.column;
|
|
1564
|
-
const target = this.
|
|
1658
|
+
const target = this.compileQualifiedColumn(col2, table);
|
|
1565
1659
|
const value = this.compileOperand(assignment.value, ctx);
|
|
1566
1660
|
return `${target} = ${value}`;
|
|
1567
1661
|
}).join(", ");
|
|
1568
1662
|
}
|
|
1663
|
+
compileQualifiedColumn(column, table) {
|
|
1664
|
+
const baseTableName = table.name;
|
|
1665
|
+
const alias = table.alias;
|
|
1666
|
+
const columnTable = column.table ?? alias ?? baseTableName;
|
|
1667
|
+
const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
|
|
1668
|
+
if (!tableQualifier) {
|
|
1669
|
+
return this.quoteIdentifier(column.name);
|
|
1670
|
+
}
|
|
1671
|
+
return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
|
|
1672
|
+
}
|
|
1569
1673
|
compileDeleteAst(ast, ctx) {
|
|
1570
|
-
const
|
|
1674
|
+
const target = this.compileTableReference(ast.from);
|
|
1675
|
+
const usingClause = this.compileDeleteUsingClause(ast, ctx);
|
|
1571
1676
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
1572
1677
|
const returning = this.compileReturning(ast.returning, ctx);
|
|
1573
|
-
return `DELETE FROM ${
|
|
1678
|
+
return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
|
|
1574
1679
|
}
|
|
1575
1680
|
formatReturningColumns(returning) {
|
|
1576
1681
|
return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
|
|
@@ -1625,6 +1730,38 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1625
1730
|
}
|
|
1626
1731
|
return this.quoteIdentifier(table.name);
|
|
1627
1732
|
}
|
|
1733
|
+
compileTableReference(table) {
|
|
1734
|
+
const base = this.compileTableName(table);
|
|
1735
|
+
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
1736
|
+
}
|
|
1737
|
+
compileUpdateFromClause(ast, ctx) {
|
|
1738
|
+
if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
|
|
1739
|
+
if (!ast.from) {
|
|
1740
|
+
throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
|
|
1741
|
+
}
|
|
1742
|
+
const from = this.compileFrom(ast.from, ctx);
|
|
1743
|
+
const joins = JoinCompiler.compileJoins(
|
|
1744
|
+
ast.joins,
|
|
1745
|
+
ctx,
|
|
1746
|
+
this.compileFrom.bind(this),
|
|
1747
|
+
this.compileExpression.bind(this)
|
|
1748
|
+
);
|
|
1749
|
+
return ` FROM ${from}${joins}`;
|
|
1750
|
+
}
|
|
1751
|
+
compileDeleteUsingClause(ast, ctx) {
|
|
1752
|
+
if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
|
|
1753
|
+
if (!ast.using) {
|
|
1754
|
+
throw new Error("DELETE with JOINs requires a USING clause.");
|
|
1755
|
+
}
|
|
1756
|
+
const usingTable = this.compileFrom(ast.using, ctx);
|
|
1757
|
+
const joins = JoinCompiler.compileJoins(
|
|
1758
|
+
ast.joins,
|
|
1759
|
+
ctx,
|
|
1760
|
+
this.compileFrom.bind(this),
|
|
1761
|
+
this.compileExpression.bind(this)
|
|
1762
|
+
);
|
|
1763
|
+
return ` USING ${usingTable}${joins}`;
|
|
1764
|
+
}
|
|
1628
1765
|
compileHaving(ast, ctx) {
|
|
1629
1766
|
if (!ast.having) return "";
|
|
1630
1767
|
return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
|
|
@@ -1636,6 +1773,12 @@ var SqlDialectBase = class extends Dialect {
|
|
|
1636
1773
|
const trimmed = this.stripTrailingSemicolon(sql);
|
|
1637
1774
|
return `(${trimmed})`;
|
|
1638
1775
|
}
|
|
1776
|
+
renderOrderByNulls(order) {
|
|
1777
|
+
return order.nulls ? ` NULLS ${order.nulls}` : "";
|
|
1778
|
+
}
|
|
1779
|
+
renderOrderByCollation(order) {
|
|
1780
|
+
return order.collation ? ` COLLATE ${order.collation}` : "";
|
|
1781
|
+
}
|
|
1639
1782
|
};
|
|
1640
1783
|
|
|
1641
1784
|
// src/core/dialect/postgres/functions.ts
|
|
@@ -1999,6 +2142,9 @@ var SqliteDialect = class extends SqlDialectBase {
|
|
|
1999
2142
|
const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
2000
2143
|
return `json_extract(${col2}, '${node.path}')`;
|
|
2001
2144
|
}
|
|
2145
|
+
compileQualifiedColumn(column, _table) {
|
|
2146
|
+
return this.quoteIdentifier(column.name);
|
|
2147
|
+
}
|
|
2002
2148
|
compileReturning(returning, ctx) {
|
|
2003
2149
|
if (!returning || returning.length === 0) return "";
|
|
2004
2150
|
const columns = this.formatReturningColumns(returning);
|
|
@@ -2104,7 +2250,7 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
|
|
|
2104
2250
|
};
|
|
2105
2251
|
|
|
2106
2252
|
// src/core/dialect/mssql/index.ts
|
|
2107
|
-
var SqlServerDialect = class extends
|
|
2253
|
+
var SqlServerDialect = class extends SqlDialectBase {
|
|
2108
2254
|
/**
|
|
2109
2255
|
* Creates a new SqlServerDialect instance
|
|
2110
2256
|
*/
|
|
@@ -2147,43 +2293,37 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2147
2293
|
const hasSetOps = !!(ast.setOps && ast.setOps.length);
|
|
2148
2294
|
const ctes = this.compileCtes(ast, ctx);
|
|
2149
2295
|
const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
|
|
2150
|
-
const baseSelect = this.
|
|
2296
|
+
const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
|
|
2151
2297
|
if (!hasSetOps) {
|
|
2152
2298
|
return `${ctes}${baseSelect}`;
|
|
2153
2299
|
}
|
|
2154
2300
|
const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
|
|
2155
|
-
const orderBy = this.compileOrderBy(ast);
|
|
2301
|
+
const orderBy = this.compileOrderBy(ast, ctx);
|
|
2156
2302
|
const pagination = this.compilePagination(ast, orderBy);
|
|
2157
2303
|
const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
|
|
2158
2304
|
const tail = pagination || orderBy;
|
|
2159
2305
|
return `${ctes}${combined}${tail}`;
|
|
2160
2306
|
}
|
|
2161
|
-
compileInsertAst(ast, ctx) {
|
|
2162
|
-
const table = this.quoteIdentifier(ast.into.name);
|
|
2163
|
-
const columnList = ast.columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
|
|
2164
|
-
const values = ast.values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
|
|
2165
|
-
return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
|
|
2166
|
-
}
|
|
2167
|
-
compileUpdateAst(ast, ctx) {
|
|
2168
|
-
const table = this.quoteIdentifier(ast.table.name);
|
|
2169
|
-
const assignments = ast.set.map((assignment) => {
|
|
2170
|
-
const col2 = assignment.column;
|
|
2171
|
-
const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
|
|
2172
|
-
const value = this.compileOperand(assignment.value, ctx);
|
|
2173
|
-
return `${target} = ${value}`;
|
|
2174
|
-
}).join(", ");
|
|
2175
|
-
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2176
|
-
return `UPDATE ${table} SET ${assignments}${whereClause};`;
|
|
2177
|
-
}
|
|
2178
2307
|
compileDeleteAst(ast, ctx) {
|
|
2308
|
+
if (ast.using) {
|
|
2309
|
+
throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
|
|
2310
|
+
}
|
|
2179
2311
|
if (ast.from.type !== "Table") {
|
|
2180
2312
|
throw new Error("DELETE only supports base tables in the MSSQL dialect.");
|
|
2181
2313
|
}
|
|
2182
|
-
const
|
|
2314
|
+
const alias = ast.from.alias ?? ast.from.name;
|
|
2315
|
+
const target = this.compileTableReference(ast.from);
|
|
2316
|
+
const joins = JoinCompiler.compileJoins(
|
|
2317
|
+
ast.joins,
|
|
2318
|
+
ctx,
|
|
2319
|
+
this.compileFrom.bind(this),
|
|
2320
|
+
this.compileExpression.bind(this)
|
|
2321
|
+
);
|
|
2183
2322
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2184
|
-
|
|
2323
|
+
const returning = this.compileReturning(ast.returning, ctx);
|
|
2324
|
+
return `DELETE ${this.quoteIdentifier(alias)} FROM ${target}${joins}${whereClause}${returning}`;
|
|
2185
2325
|
}
|
|
2186
|
-
|
|
2326
|
+
compileSelectCoreForMssql(ast, ctx) {
|
|
2187
2327
|
const columns = ast.columns.map((c) => {
|
|
2188
2328
|
let expr = "";
|
|
2189
2329
|
if (c.type === "Function") {
|
|
@@ -2202,25 +2342,29 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2202
2342
|
return expr;
|
|
2203
2343
|
}).join(", ");
|
|
2204
2344
|
const distinct = ast.distinct ? "DISTINCT " : "";
|
|
2205
|
-
const from = this.compileTableSource(ast.from
|
|
2345
|
+
const from = this.compileTableSource(ast.from);
|
|
2206
2346
|
const joins = ast.joins.map((j) => {
|
|
2207
|
-
const table = this.compileTableSource(j.table
|
|
2347
|
+
const table = this.compileTableSource(j.table);
|
|
2208
2348
|
const cond = this.compileExpression(j.condition, ctx);
|
|
2209
2349
|
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
2210
2350
|
}).join(" ");
|
|
2211
2351
|
const whereClause = this.compileWhere(ast.where, ctx);
|
|
2212
|
-
const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((
|
|
2352
|
+
const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((term) => this.compileOrderingTerm(term, ctx)).join(", ") : "";
|
|
2213
2353
|
const having = ast.having ? ` HAVING ${this.compileExpression(ast.having, ctx)}` : "";
|
|
2214
|
-
const orderBy = this.compileOrderBy(ast);
|
|
2354
|
+
const orderBy = this.compileOrderBy(ast, ctx);
|
|
2215
2355
|
const pagination = this.compilePagination(ast, orderBy);
|
|
2216
2356
|
if (pagination) {
|
|
2217
2357
|
return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${pagination}`;
|
|
2218
2358
|
}
|
|
2219
2359
|
return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${orderBy}`;
|
|
2220
2360
|
}
|
|
2221
|
-
compileOrderBy(ast) {
|
|
2222
|
-
|
|
2223
|
-
|
|
2361
|
+
compileOrderBy(ast, ctx) {
|
|
2362
|
+
return OrderByCompiler.compileOrderBy(
|
|
2363
|
+
ast,
|
|
2364
|
+
(term) => this.compileOrderingTerm(term, ctx),
|
|
2365
|
+
this.renderOrderByNulls.bind(this),
|
|
2366
|
+
this.renderOrderByCollation.bind(this)
|
|
2367
|
+
);
|
|
2224
2368
|
}
|
|
2225
2369
|
compilePagination(ast, orderBy) {
|
|
2226
2370
|
const hasLimit = ast.limit !== void 0;
|
|
@@ -2234,21 +2378,6 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2234
2378
|
}
|
|
2235
2379
|
return pagination;
|
|
2236
2380
|
}
|
|
2237
|
-
compileTableSource(table, ctx) {
|
|
2238
|
-
if (table.type === "FunctionTable") {
|
|
2239
|
-
return FunctionTableFormatter.format(table, ctx, this);
|
|
2240
|
-
}
|
|
2241
|
-
if (table.type === "DerivedTable") {
|
|
2242
|
-
return this.compileDerivedTable(table, ctx);
|
|
2243
|
-
}
|
|
2244
|
-
const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
|
|
2245
|
-
return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
|
|
2246
|
-
}
|
|
2247
|
-
compileDerivedTable(table, ctx) {
|
|
2248
|
-
const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
|
|
2249
|
-
const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
|
|
2250
|
-
return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
|
|
2251
|
-
}
|
|
2252
2381
|
compileCtes(ast, ctx) {
|
|
2253
2382
|
if (!ast.ctes || ast.ctes.length === 0) return "";
|
|
2254
2383
|
const defs = ast.ctes.map((cte) => {
|
|
@@ -2259,10 +2388,6 @@ var SqlServerDialect = class extends Dialect {
|
|
|
2259
2388
|
}).join(", ");
|
|
2260
2389
|
return `WITH ${defs} `;
|
|
2261
2390
|
}
|
|
2262
|
-
wrapSetOperand(sql) {
|
|
2263
|
-
const trimmed = sql.trim().replace(/;$/, "");
|
|
2264
|
-
return `(${trimmed})`;
|
|
2265
|
-
}
|
|
2266
2391
|
};
|
|
2267
2392
|
|
|
2268
2393
|
// src/core/dialect/dialect-factory.ts
|
|
@@ -2412,7 +2537,7 @@ var SelectQueryState = class _SelectQueryState {
|
|
|
2412
2537
|
}
|
|
2413
2538
|
/**
|
|
2414
2539
|
* Adds GROUP BY columns to the query
|
|
2415
|
-
* @param columns -
|
|
2540
|
+
* @param columns - Terms to group by
|
|
2416
2541
|
* @returns New SelectQueryState with GROUP BY clause
|
|
2417
2542
|
*/
|
|
2418
2543
|
withGroupBy(columns) {
|
|
@@ -2695,31 +2820,38 @@ var HydrationManager = class _HydrationManager {
|
|
|
2695
2820
|
}
|
|
2696
2821
|
const mapped = [];
|
|
2697
2822
|
for (const ob of orderBy) {
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
}
|
|
2701
|
-
const alias = projectionAliases.get(`${ob.column.table}.${ob.column.name}`) ?? ob.column.name;
|
|
2702
|
-
if (!availableColumns.has(alias)) {
|
|
2703
|
-
return null;
|
|
2704
|
-
}
|
|
2705
|
-
mapped.push({
|
|
2706
|
-
type: "OrderBy",
|
|
2707
|
-
column: { type: "Column", table: baseAlias, name: alias },
|
|
2708
|
-
direction: ob.direction
|
|
2709
|
-
});
|
|
2823
|
+
const mappedTerm = this.mapOrderingTerm(ob.term, plan, projectionAliases, baseAlias, availableColumns);
|
|
2824
|
+
if (!mappedTerm) return null;
|
|
2825
|
+
mapped.push({ ...ob, term: mappedTerm });
|
|
2710
2826
|
}
|
|
2711
2827
|
return mapped;
|
|
2712
2828
|
}
|
|
2829
|
+
mapOrderingTerm(term, plan, projectionAliases, baseAlias, availableColumns) {
|
|
2830
|
+
if (term.type === "Column") {
|
|
2831
|
+
const col2 = term;
|
|
2832
|
+
if (col2.table !== plan.rootTable) return null;
|
|
2833
|
+
const alias = projectionAliases.get(`${col2.table}.${col2.name}`) ?? col2.name;
|
|
2834
|
+
if (!availableColumns.has(alias)) return null;
|
|
2835
|
+
return { type: "Column", table: baseAlias, name: alias };
|
|
2836
|
+
}
|
|
2837
|
+
if (term.type === "AliasRef") {
|
|
2838
|
+
const aliasName = term.name;
|
|
2839
|
+
if (!availableColumns.has(aliasName)) return null;
|
|
2840
|
+
return { type: "Column", table: baseAlias, name: aliasName };
|
|
2841
|
+
}
|
|
2842
|
+
return null;
|
|
2843
|
+
}
|
|
2713
2844
|
buildPagingColumns(primaryKey, orderBy, tableAlias) {
|
|
2714
2845
|
const columns = [{ type: "Column", table: tableAlias, name: primaryKey, alias: primaryKey }];
|
|
2715
2846
|
if (!orderBy) return columns;
|
|
2716
2847
|
for (const ob of orderBy) {
|
|
2717
|
-
|
|
2848
|
+
const term = ob.term;
|
|
2849
|
+
if (!columns.some((col2) => col2.name === term.name)) {
|
|
2718
2850
|
columns.push({
|
|
2719
2851
|
type: "Column",
|
|
2720
2852
|
table: tableAlias,
|
|
2721
|
-
name:
|
|
2722
|
-
alias:
|
|
2853
|
+
name: term.name,
|
|
2854
|
+
alias: term.name
|
|
2723
2855
|
});
|
|
2724
2856
|
}
|
|
2725
2857
|
}
|
|
@@ -3025,10 +3157,8 @@ var QueryAstService = class {
|
|
|
3025
3157
|
* @returns Updated query state with GROUP BY clause
|
|
3026
3158
|
*/
|
|
3027
3159
|
withGroupBy(col2) {
|
|
3028
|
-
const
|
|
3029
|
-
|
|
3030
|
-
const node = buildColumnNode(tableRef, col2);
|
|
3031
|
-
return this.state.withGroupBy([node]);
|
|
3160
|
+
const term = this.normalizeOrderingTerm(col2);
|
|
3161
|
+
return this.state.withGroupBy([term]);
|
|
3032
3162
|
}
|
|
3033
3163
|
/**
|
|
3034
3164
|
* Adds a HAVING clause to the query
|
|
@@ -3045,11 +3175,9 @@ var QueryAstService = class {
|
|
|
3045
3175
|
* @param direction - Order direction (ASC/DESC)
|
|
3046
3176
|
* @returns Updated query state with ORDER BY clause
|
|
3047
3177
|
*/
|
|
3048
|
-
withOrderBy(
|
|
3049
|
-
const
|
|
3050
|
-
|
|
3051
|
-
const node = buildColumnNode(tableRef, col2);
|
|
3052
|
-
return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
|
|
3178
|
+
withOrderBy(term, direction, nulls, collation) {
|
|
3179
|
+
const normalized = this.normalizeOrderingTerm(term);
|
|
3180
|
+
return this.state.withOrderBy([{ type: "OrderBy", term: normalized, direction, nulls, collation }]);
|
|
3053
3181
|
}
|
|
3054
3182
|
/**
|
|
3055
3183
|
* Adds a DISTINCT clause to the query
|
|
@@ -3084,6 +3212,24 @@ var QueryAstService = class {
|
|
|
3084
3212
|
combineExpressions(existing, next) {
|
|
3085
3213
|
return existing ? and(existing, next) : next;
|
|
3086
3214
|
}
|
|
3215
|
+
normalizeOrderingTerm(term) {
|
|
3216
|
+
const from = this.state.ast.from;
|
|
3217
|
+
const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
|
|
3218
|
+
const termType = term?.type;
|
|
3219
|
+
if (termType === "Column") {
|
|
3220
|
+
return term;
|
|
3221
|
+
}
|
|
3222
|
+
if (termType === "AliasRef") {
|
|
3223
|
+
return term;
|
|
3224
|
+
}
|
|
3225
|
+
if (isOperandNode(term)) {
|
|
3226
|
+
return term;
|
|
3227
|
+
}
|
|
3228
|
+
if (termType === "BinaryExpression" || termType === "LogicalExpression" || termType === "NullExpression" || termType === "InExpression" || termType === "ExistsExpression" || termType === "BetweenExpression" || termType === "ArithmeticExpression") {
|
|
3229
|
+
return term;
|
|
3230
|
+
}
|
|
3231
|
+
return buildColumnNode(tableRef, term);
|
|
3232
|
+
}
|
|
3087
3233
|
};
|
|
3088
3234
|
|
|
3089
3235
|
// src/query-builder/relation-projection-helper.ts
|
|
@@ -4036,8 +4182,10 @@ var DefaultManyToManyCollection = class {
|
|
|
4036
4182
|
attach(target) {
|
|
4037
4183
|
const entity = this.ensureEntity(target);
|
|
4038
4184
|
const id = this.extractId(entity);
|
|
4039
|
-
if (id
|
|
4040
|
-
|
|
4185
|
+
if (id != null && this.items.some((item) => this.extractId(item) === id)) {
|
|
4186
|
+
return;
|
|
4187
|
+
}
|
|
4188
|
+
if (id == null && this.items.includes(entity)) {
|
|
4041
4189
|
return;
|
|
4042
4190
|
}
|
|
4043
4191
|
this.items.push(entity);
|
|
@@ -4733,8 +4881,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4733
4881
|
* @returns New query builder instance with the subquery selection
|
|
4734
4882
|
|
|
4735
4883
|
*/
|
|
4736
|
-
selectSubquery(alias,
|
|
4737
|
-
const query = this.resolveQueryNode(
|
|
4884
|
+
selectSubquery(alias, sub2) {
|
|
4885
|
+
const query = this.resolveQueryNode(sub2);
|
|
4738
4886
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
4739
4887
|
}
|
|
4740
4888
|
/**
|
|
@@ -4916,16 +5064,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4916
5064
|
return this.clone(nextContext);
|
|
4917
5065
|
}
|
|
4918
5066
|
/**
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
*/
|
|
4927
|
-
groupBy(col2) {
|
|
4928
|
-
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
|
|
5067
|
+
* Adds a GROUP BY clause to the query
|
|
5068
|
+
* @param term - Column definition or ordering term to group by
|
|
5069
|
+
* @returns New query builder instance with the GROUP BY clause
|
|
5070
|
+
*/
|
|
5071
|
+
groupBy(term) {
|
|
5072
|
+
const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(term));
|
|
4929
5073
|
return this.clone(nextContext);
|
|
4930
5074
|
}
|
|
4931
5075
|
/**
|
|
@@ -4942,18 +5086,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
|
|
|
4942
5086
|
return this.clone(nextContext);
|
|
4943
5087
|
}
|
|
4944
5088
|
/**
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
5089
|
+
* Adds an ORDER BY clause to the query
|
|
5090
|
+
* @param term - Column definition or ordering term to order by
|
|
5091
|
+
* @param directionOrOptions - Order direction or options (defaults to ASC)
|
|
5092
|
+
* @returns New query builder instance with the ORDER BY clause
|
|
5093
|
+
*/
|
|
5094
|
+
orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
|
|
5095
|
+
const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
|
|
5096
|
+
const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
|
|
5097
|
+
const nextContext = this.applyAst(
|
|
5098
|
+
this.context,
|
|
5099
|
+
(service) => service.withOrderBy(term, dir, options.nulls, options.collation)
|
|
5100
|
+
);
|
|
4957
5101
|
return this.clone(nextContext);
|
|
4958
5102
|
}
|
|
4959
5103
|
/**
|
|
@@ -5364,15 +5508,36 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
5364
5508
|
type: "InsertQuery",
|
|
5365
5509
|
into: createTableNode(table),
|
|
5366
5510
|
columns: [],
|
|
5367
|
-
|
|
5511
|
+
source: {
|
|
5512
|
+
type: "InsertValues",
|
|
5513
|
+
rows: []
|
|
5514
|
+
}
|
|
5368
5515
|
};
|
|
5369
5516
|
}
|
|
5370
5517
|
clone(nextAst) {
|
|
5371
5518
|
return new _InsertQueryState(this.table, nextAst);
|
|
5372
5519
|
}
|
|
5520
|
+
ensureColumnsFromRow(rows) {
|
|
5521
|
+
if (this.ast.columns.length) return this.ast.columns;
|
|
5522
|
+
return buildColumnNodes(this.table, Object.keys(rows[0]));
|
|
5523
|
+
}
|
|
5524
|
+
appendValues(rows) {
|
|
5525
|
+
if (this.ast.source.type === "InsertValues") {
|
|
5526
|
+
return [...this.ast.source.rows, ...rows];
|
|
5527
|
+
}
|
|
5528
|
+
return rows;
|
|
5529
|
+
}
|
|
5530
|
+
getTableColumns() {
|
|
5531
|
+
const names = Object.keys(this.table.columns);
|
|
5532
|
+
if (!names.length) return [];
|
|
5533
|
+
return buildColumnNodes(this.table, names);
|
|
5534
|
+
}
|
|
5373
5535
|
withValues(rows) {
|
|
5374
5536
|
if (!rows.length) return this;
|
|
5375
|
-
|
|
5537
|
+
if (this.ast.source.type === "InsertSelect") {
|
|
5538
|
+
throw new Error("Cannot mix INSERT ... VALUES with INSERT ... SELECT source.");
|
|
5539
|
+
}
|
|
5540
|
+
const definedColumns = this.ensureColumnsFromRow(rows);
|
|
5376
5541
|
const newRows = rows.map(
|
|
5377
5542
|
(row, rowIndex) => definedColumns.map((column) => {
|
|
5378
5543
|
const rawValue = row[column.name];
|
|
@@ -5387,7 +5552,34 @@ var InsertQueryState = class _InsertQueryState {
|
|
|
5387
5552
|
return this.clone({
|
|
5388
5553
|
...this.ast,
|
|
5389
5554
|
columns: definedColumns,
|
|
5390
|
-
|
|
5555
|
+
source: {
|
|
5556
|
+
type: "InsertValues",
|
|
5557
|
+
rows: this.appendValues(newRows)
|
|
5558
|
+
}
|
|
5559
|
+
});
|
|
5560
|
+
}
|
|
5561
|
+
withColumns(columns) {
|
|
5562
|
+
if (!columns.length) return this;
|
|
5563
|
+
return this.clone({
|
|
5564
|
+
...this.ast,
|
|
5565
|
+
columns: [...columns]
|
|
5566
|
+
});
|
|
5567
|
+
}
|
|
5568
|
+
withSelect(query, columns) {
|
|
5569
|
+
const targetColumns = columns.length ? columns : this.ast.columns.length ? this.ast.columns : this.getTableColumns();
|
|
5570
|
+
if (!targetColumns.length) {
|
|
5571
|
+
throw new Error("INSERT ... SELECT requires specifying destination columns.");
|
|
5572
|
+
}
|
|
5573
|
+
if (this.ast.source.type === "InsertValues" && this.ast.source.rows.length) {
|
|
5574
|
+
throw new Error("Cannot mix INSERT ... SELECT with INSERT ... VALUES source.");
|
|
5575
|
+
}
|
|
5576
|
+
return this.clone({
|
|
5577
|
+
...this.ast,
|
|
5578
|
+
columns: [...targetColumns],
|
|
5579
|
+
source: {
|
|
5580
|
+
type: "InsertSelect",
|
|
5581
|
+
query
|
|
5582
|
+
}
|
|
5391
5583
|
});
|
|
5392
5584
|
}
|
|
5393
5585
|
withReturning(columns) {
|
|
@@ -5412,11 +5604,27 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
|
|
|
5412
5604
|
if (!rows.length) return this;
|
|
5413
5605
|
return this.clone(this.state.withValues(rows));
|
|
5414
5606
|
}
|
|
5607
|
+
columns(...columns) {
|
|
5608
|
+
if (!columns.length) return this;
|
|
5609
|
+
return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
|
|
5610
|
+
}
|
|
5611
|
+
fromSelect(query, columns = []) {
|
|
5612
|
+
const ast = this.resolveSelectQuery(query);
|
|
5613
|
+
const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
|
|
5614
|
+
return this.clone(this.state.withSelect(ast, nodes));
|
|
5615
|
+
}
|
|
5415
5616
|
returning(...columns) {
|
|
5416
5617
|
if (!columns.length) return this;
|
|
5417
5618
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5418
5619
|
return this.clone(this.state.withReturning(nodes));
|
|
5419
5620
|
}
|
|
5621
|
+
// Helpers for column/AST resolution
|
|
5622
|
+
resolveColumnNodes(columns) {
|
|
5623
|
+
return columns.map((column) => buildColumnNode(this.table, column));
|
|
5624
|
+
}
|
|
5625
|
+
resolveSelectQuery(query) {
|
|
5626
|
+
return typeof query.getAST === "function" ? query.getAST() : query;
|
|
5627
|
+
}
|
|
5420
5628
|
compile(arg) {
|
|
5421
5629
|
if (typeof arg.compileInsert === "function") {
|
|
5422
5630
|
return arg.compileInsert(this.state.ast);
|
|
@@ -5450,7 +5658,8 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
5450
5658
|
this.ast = ast ?? {
|
|
5451
5659
|
type: "UpdateQuery",
|
|
5452
5660
|
table: createTableNode(table),
|
|
5453
|
-
set: []
|
|
5661
|
+
set: [],
|
|
5662
|
+
joins: []
|
|
5454
5663
|
};
|
|
5455
5664
|
}
|
|
5456
5665
|
clone(nextAst) {
|
|
@@ -5489,6 +5698,27 @@ var UpdateQueryState = class _UpdateQueryState {
|
|
|
5489
5698
|
returning: [...columns]
|
|
5490
5699
|
});
|
|
5491
5700
|
}
|
|
5701
|
+
withFrom(from) {
|
|
5702
|
+
return this.clone({
|
|
5703
|
+
...this.ast,
|
|
5704
|
+
from
|
|
5705
|
+
});
|
|
5706
|
+
}
|
|
5707
|
+
withJoin(join) {
|
|
5708
|
+
return this.clone({
|
|
5709
|
+
...this.ast,
|
|
5710
|
+
joins: [...this.ast.joins ?? [], join]
|
|
5711
|
+
});
|
|
5712
|
+
}
|
|
5713
|
+
withTableAlias(alias) {
|
|
5714
|
+
return this.clone({
|
|
5715
|
+
...this.ast,
|
|
5716
|
+
table: {
|
|
5717
|
+
...this.ast.table,
|
|
5718
|
+
alias
|
|
5719
|
+
}
|
|
5720
|
+
});
|
|
5721
|
+
}
|
|
5492
5722
|
};
|
|
5493
5723
|
|
|
5494
5724
|
// src/query-builder/update.ts
|
|
@@ -5500,6 +5730,18 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5500
5730
|
clone(state) {
|
|
5501
5731
|
return new _UpdateQueryBuilder(this.table, state);
|
|
5502
5732
|
}
|
|
5733
|
+
as(alias) {
|
|
5734
|
+
return this.clone(this.state.withTableAlias(alias));
|
|
5735
|
+
}
|
|
5736
|
+
from(source) {
|
|
5737
|
+
const tableSource = this.resolveTableSource(source);
|
|
5738
|
+
return this.clone(this.state.withFrom(tableSource));
|
|
5739
|
+
}
|
|
5740
|
+
join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
|
|
5741
|
+
const joinTarget = this.resolveJoinTarget(table);
|
|
5742
|
+
const joinNode = createJoinNode(kind, joinTarget, condition, relationName);
|
|
5743
|
+
return this.clone(this.state.withJoin(joinNode));
|
|
5744
|
+
}
|
|
5503
5745
|
set(values) {
|
|
5504
5746
|
return this.clone(this.state.withSet(values));
|
|
5505
5747
|
}
|
|
@@ -5511,6 +5753,16 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5511
5753
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5512
5754
|
return this.clone(this.state.withReturning(nodes));
|
|
5513
5755
|
}
|
|
5756
|
+
resolveTableSource(source) {
|
|
5757
|
+
if (isTableSourceNode(source)) {
|
|
5758
|
+
return source;
|
|
5759
|
+
}
|
|
5760
|
+
return { type: "Table", name: source.name, schema: source.schema };
|
|
5761
|
+
}
|
|
5762
|
+
resolveJoinTarget(table) {
|
|
5763
|
+
if (typeof table === "string") return table;
|
|
5764
|
+
return this.resolveTableSource(table);
|
|
5765
|
+
}
|
|
5514
5766
|
compile(arg) {
|
|
5515
5767
|
if (typeof arg.compileUpdate === "function") {
|
|
5516
5768
|
return arg.compileUpdate(this.state.ast);
|
|
@@ -5525,6 +5777,7 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
|
|
|
5525
5777
|
return this.state.ast;
|
|
5526
5778
|
}
|
|
5527
5779
|
};
|
|
5780
|
+
var isTableSourceNode = (source) => typeof source.type === "string";
|
|
5528
5781
|
|
|
5529
5782
|
// src/query-builder/delete-query-state.ts
|
|
5530
5783
|
var DeleteQueryState = class _DeleteQueryState {
|
|
@@ -5532,7 +5785,8 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
5532
5785
|
this.table = table;
|
|
5533
5786
|
this.ast = ast ?? {
|
|
5534
5787
|
type: "DeleteQuery",
|
|
5535
|
-
from: createTableNode(table)
|
|
5788
|
+
from: createTableNode(table),
|
|
5789
|
+
joins: []
|
|
5536
5790
|
};
|
|
5537
5791
|
}
|
|
5538
5792
|
clone(nextAst) {
|
|
@@ -5550,6 +5804,27 @@ var DeleteQueryState = class _DeleteQueryState {
|
|
|
5550
5804
|
returning: [...columns]
|
|
5551
5805
|
});
|
|
5552
5806
|
}
|
|
5807
|
+
withUsing(source) {
|
|
5808
|
+
return this.clone({
|
|
5809
|
+
...this.ast,
|
|
5810
|
+
using: source
|
|
5811
|
+
});
|
|
5812
|
+
}
|
|
5813
|
+
withJoin(join) {
|
|
5814
|
+
return this.clone({
|
|
5815
|
+
...this.ast,
|
|
5816
|
+
joins: [...this.ast.joins ?? [], join]
|
|
5817
|
+
});
|
|
5818
|
+
}
|
|
5819
|
+
withTableAlias(alias) {
|
|
5820
|
+
return this.clone({
|
|
5821
|
+
...this.ast,
|
|
5822
|
+
from: {
|
|
5823
|
+
...this.ast.from,
|
|
5824
|
+
alias
|
|
5825
|
+
}
|
|
5826
|
+
});
|
|
5827
|
+
}
|
|
5553
5828
|
};
|
|
5554
5829
|
|
|
5555
5830
|
// src/query-builder/delete.ts
|
|
@@ -5564,11 +5839,32 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
5564
5839
|
where(expr) {
|
|
5565
5840
|
return this.clone(this.state.withWhere(expr));
|
|
5566
5841
|
}
|
|
5842
|
+
as(alias) {
|
|
5843
|
+
return this.clone(this.state.withTableAlias(alias));
|
|
5844
|
+
}
|
|
5845
|
+
using(source) {
|
|
5846
|
+
return this.clone(this.state.withUsing(this.resolveTableSource(source)));
|
|
5847
|
+
}
|
|
5848
|
+
join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
|
|
5849
|
+
const target = this.resolveJoinTarget(table);
|
|
5850
|
+
const joinNode = createJoinNode(kind, target, condition, relationName);
|
|
5851
|
+
return this.clone(this.state.withJoin(joinNode));
|
|
5852
|
+
}
|
|
5567
5853
|
returning(...columns) {
|
|
5568
5854
|
if (!columns.length) return this;
|
|
5569
5855
|
const nodes = columns.map((column) => buildColumnNode(this.table, column));
|
|
5570
5856
|
return this.clone(this.state.withReturning(nodes));
|
|
5571
5857
|
}
|
|
5858
|
+
resolveTableSource(source) {
|
|
5859
|
+
if (isTableSourceNode2(source)) {
|
|
5860
|
+
return source;
|
|
5861
|
+
}
|
|
5862
|
+
return { type: "Table", name: source.name, schema: source.schema };
|
|
5863
|
+
}
|
|
5864
|
+
resolveJoinTarget(table) {
|
|
5865
|
+
if (typeof table === "string") return table;
|
|
5866
|
+
return this.resolveTableSource(table);
|
|
5867
|
+
}
|
|
5572
5868
|
compile(arg) {
|
|
5573
5869
|
if (typeof arg.compileDelete === "function") {
|
|
5574
5870
|
return arg.compileDelete(this.state.ast);
|
|
@@ -5583,6 +5879,7 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
|
|
|
5583
5879
|
return this.state.ast;
|
|
5584
5880
|
}
|
|
5585
5881
|
};
|
|
5882
|
+
var isTableSourceNode2 = (source) => typeof source.type === "string";
|
|
5586
5883
|
|
|
5587
5884
|
// src/core/ddl/sql-writing.ts
|
|
5588
5885
|
var resolvePrimaryKey = (table) => {
|
|
@@ -6781,7 +7078,7 @@ var TypeScriptGenerator = class {
|
|
|
6781
7078
|
lines.push(`.where(${this.printExpression(ast.where)})`);
|
|
6782
7079
|
}
|
|
6783
7080
|
if (ast.groupBy && ast.groupBy.length) {
|
|
6784
|
-
const cols = ast.groupBy.map((
|
|
7081
|
+
const cols = ast.groupBy.map((term) => this.printOrderingTerm(term)).join(", ");
|
|
6785
7082
|
lines.push(`.groupBy(${cols})`);
|
|
6786
7083
|
}
|
|
6787
7084
|
if (ast.having) {
|
|
@@ -6789,7 +7086,16 @@ var TypeScriptGenerator = class {
|
|
|
6789
7086
|
}
|
|
6790
7087
|
if (ast.orderBy && ast.orderBy.length) {
|
|
6791
7088
|
ast.orderBy.forEach((o) => {
|
|
6792
|
-
|
|
7089
|
+
const term = this.printOrderingTerm(o.term);
|
|
7090
|
+
const opts = [`direction: '${o.direction}'`];
|
|
7091
|
+
if (o.nulls) opts.push(`nulls: '${o.nulls}'`);
|
|
7092
|
+
if (o.collation) opts.push(`collation: '${o.collation}'`);
|
|
7093
|
+
const hasOpts = opts.length > 1;
|
|
7094
|
+
if (hasOpts) {
|
|
7095
|
+
lines.push(`.orderBy(${term}, { ${opts.join(", ")} })`);
|
|
7096
|
+
} else {
|
|
7097
|
+
lines.push(`.orderBy(${term}, '${o.direction}')`);
|
|
7098
|
+
}
|
|
6793
7099
|
});
|
|
6794
7100
|
}
|
|
6795
7101
|
if (ast.limit) lines.push(`.limit(${ast.limit})`);
|
|
@@ -6812,6 +7118,29 @@ var TypeScriptGenerator = class {
|
|
|
6812
7118
|
printOperand(node) {
|
|
6813
7119
|
return visitOperand(node, this);
|
|
6814
7120
|
}
|
|
7121
|
+
/**
|
|
7122
|
+
* Prints an ordering term (operand/expression/alias) to TypeScript code.
|
|
7123
|
+
*/
|
|
7124
|
+
printOrderingTerm(term) {
|
|
7125
|
+
if (!term || !term.type) {
|
|
7126
|
+
throw new Error("Unsupported ordering term");
|
|
7127
|
+
}
|
|
7128
|
+
switch (term.type) {
|
|
7129
|
+
case "Column":
|
|
7130
|
+
return `${this.namingStrategy.tableToSymbol(term.table)}.${term.name}`;
|
|
7131
|
+
case "AliasRef":
|
|
7132
|
+
return this.visitAliasRef(term);
|
|
7133
|
+
case "Literal":
|
|
7134
|
+
case "Function":
|
|
7135
|
+
case "JsonPath":
|
|
7136
|
+
case "ScalarSubquery":
|
|
7137
|
+
case "CaseExpression":
|
|
7138
|
+
case "WindowFunction":
|
|
7139
|
+
return this.printOperand(term);
|
|
7140
|
+
default:
|
|
7141
|
+
return this.printExpression(term);
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
6815
7144
|
visitBinaryExpression(binary) {
|
|
6816
7145
|
return this.printBinaryExpression(binary);
|
|
6817
7146
|
}
|
|
@@ -6830,6 +7159,9 @@ var TypeScriptGenerator = class {
|
|
|
6830
7159
|
visitBetweenExpression(betweenExpr) {
|
|
6831
7160
|
return this.printBetweenExpression(betweenExpr);
|
|
6832
7161
|
}
|
|
7162
|
+
visitArithmeticExpression(arithExpr) {
|
|
7163
|
+
return this.printArithmeticExpression(arithExpr);
|
|
7164
|
+
}
|
|
6833
7165
|
visitColumn(node) {
|
|
6834
7166
|
return this.printColumnOperand(node);
|
|
6835
7167
|
}
|
|
@@ -6851,6 +7183,9 @@ var TypeScriptGenerator = class {
|
|
|
6851
7183
|
visitWindowFunction(node) {
|
|
6852
7184
|
return this.printWindowFunctionOperand(node);
|
|
6853
7185
|
}
|
|
7186
|
+
visitAliasRef(node) {
|
|
7187
|
+
return `aliasRef('${node.name}')`;
|
|
7188
|
+
}
|
|
6854
7189
|
/**
|
|
6855
7190
|
* Prints a binary expression to TypeScript code
|
|
6856
7191
|
* @param binary - Binary expression node
|
|
@@ -6881,6 +7216,11 @@ var TypeScriptGenerator = class {
|
|
|
6881
7216
|
${parts.join(",\n ")}
|
|
6882
7217
|
)`;
|
|
6883
7218
|
}
|
|
7219
|
+
printArithmeticExpression(expr) {
|
|
7220
|
+
const left2 = this.printOperand(expr.left);
|
|
7221
|
+
const right2 = this.printOperand(expr.right);
|
|
7222
|
+
return `${left2} ${expr.operator} ${right2}`;
|
|
7223
|
+
}
|
|
6884
7224
|
/**
|
|
6885
7225
|
* Prints an IN expression to TypeScript code
|
|
6886
7226
|
* @param inExpr - IN expression node
|
|
@@ -6888,9 +7228,13 @@ var TypeScriptGenerator = class {
|
|
|
6888
7228
|
*/
|
|
6889
7229
|
printInExpression(inExpr) {
|
|
6890
7230
|
const left2 = this.printOperand(inExpr.left);
|
|
6891
|
-
const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
|
|
6892
7231
|
const fn4 = this.mapOp(inExpr.operator);
|
|
6893
|
-
|
|
7232
|
+
if (Array.isArray(inExpr.right)) {
|
|
7233
|
+
const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
|
|
7234
|
+
return `${fn4}(${left2}, [${values}])`;
|
|
7235
|
+
}
|
|
7236
|
+
const subquery = this.inlineChain(this.buildSelectLines(inExpr.right.query));
|
|
7237
|
+
return `${fn4}(${left2}, (${subquery}))`;
|
|
6894
7238
|
}
|
|
6895
7239
|
/**
|
|
6896
7240
|
* Prints a null expression to TypeScript code
|
|
@@ -6994,7 +7338,12 @@ var TypeScriptGenerator = class {
|
|
|
6994
7338
|
parts.push(partitionClause);
|
|
6995
7339
|
}
|
|
6996
7340
|
if (node.orderBy && node.orderBy.length > 0) {
|
|
6997
|
-
const orderClause = "ORDER BY " + node.orderBy.map((o) =>
|
|
7341
|
+
const orderClause = "ORDER BY " + node.orderBy.map((o) => {
|
|
7342
|
+
const term = this.printOrderingTerm(o.term);
|
|
7343
|
+
const collation = o.collation ? ` COLLATE ${o.collation}` : "";
|
|
7344
|
+
const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
|
|
7345
|
+
return `${term} ${o.direction}${collation}${nulls}`;
|
|
7346
|
+
}).join(", ");
|
|
6998
7347
|
parts.push(orderClause);
|
|
6999
7348
|
}
|
|
7000
7349
|
result += parts.join(" ");
|
|
@@ -7070,6 +7419,13 @@ var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
|
|
|
7070
7419
|
|
|
7071
7420
|
// src/orm/unit-of-work.ts
|
|
7072
7421
|
var UnitOfWork = class {
|
|
7422
|
+
/**
|
|
7423
|
+
* Creates a new UnitOfWork instance.
|
|
7424
|
+
* @param dialect - The database dialect
|
|
7425
|
+
* @param executor - The database executor
|
|
7426
|
+
* @param identityMap - The identity map
|
|
7427
|
+
* @param hookContext - Function to get the hook context
|
|
7428
|
+
*/
|
|
7073
7429
|
constructor(dialect, executor, identityMap, hookContext) {
|
|
7074
7430
|
this.dialect = dialect;
|
|
7075
7431
|
this.executor = executor;
|
|
@@ -7077,21 +7433,50 @@ var UnitOfWork = class {
|
|
|
7077
7433
|
this.hookContext = hookContext;
|
|
7078
7434
|
this.trackedEntities = /* @__PURE__ */ new Map();
|
|
7079
7435
|
}
|
|
7436
|
+
/**
|
|
7437
|
+
* Gets the identity buckets map.
|
|
7438
|
+
*/
|
|
7080
7439
|
get identityBuckets() {
|
|
7081
7440
|
return this.identityMap.bucketsMap;
|
|
7082
7441
|
}
|
|
7442
|
+
/**
|
|
7443
|
+
* Gets all tracked entities.
|
|
7444
|
+
* @returns Array of tracked entities
|
|
7445
|
+
*/
|
|
7083
7446
|
getTracked() {
|
|
7084
7447
|
return Array.from(this.trackedEntities.values());
|
|
7085
7448
|
}
|
|
7449
|
+
/**
|
|
7450
|
+
* Gets an entity by table and primary key.
|
|
7451
|
+
* @param table - The table definition
|
|
7452
|
+
* @param pk - The primary key value
|
|
7453
|
+
* @returns The entity or undefined if not found
|
|
7454
|
+
*/
|
|
7086
7455
|
getEntity(table, pk) {
|
|
7087
7456
|
return this.identityMap.getEntity(table, pk);
|
|
7088
7457
|
}
|
|
7458
|
+
/**
|
|
7459
|
+
* Gets all tracked entities for a specific table.
|
|
7460
|
+
* @param table - The table definition
|
|
7461
|
+
* @returns Array of tracked entities
|
|
7462
|
+
*/
|
|
7089
7463
|
getEntitiesForTable(table) {
|
|
7090
7464
|
return this.identityMap.getEntitiesForTable(table);
|
|
7091
7465
|
}
|
|
7466
|
+
/**
|
|
7467
|
+
* Finds a tracked entity.
|
|
7468
|
+
* @param entity - The entity to find
|
|
7469
|
+
* @returns The tracked entity or undefined if not found
|
|
7470
|
+
*/
|
|
7092
7471
|
findTracked(entity) {
|
|
7093
7472
|
return this.trackedEntities.get(entity);
|
|
7094
7473
|
}
|
|
7474
|
+
/**
|
|
7475
|
+
* Sets an entity in the identity map.
|
|
7476
|
+
* @param table - The table definition
|
|
7477
|
+
* @param pk - The primary key value
|
|
7478
|
+
* @param entity - The entity instance
|
|
7479
|
+
*/
|
|
7095
7480
|
setEntity(table, pk, entity) {
|
|
7096
7481
|
if (pk === null || pk === void 0) return;
|
|
7097
7482
|
let tracked = this.trackedEntities.get(entity);
|
|
@@ -7109,6 +7494,12 @@ var UnitOfWork = class {
|
|
|
7109
7494
|
}
|
|
7110
7495
|
this.registerIdentity(tracked);
|
|
7111
7496
|
}
|
|
7497
|
+
/**
|
|
7498
|
+
* Tracks a new entity.
|
|
7499
|
+
* @param table - The table definition
|
|
7500
|
+
* @param entity - The entity instance
|
|
7501
|
+
* @param pk - Optional primary key value
|
|
7502
|
+
*/
|
|
7112
7503
|
trackNew(table, entity, pk) {
|
|
7113
7504
|
const tracked = {
|
|
7114
7505
|
table,
|
|
@@ -7122,6 +7513,12 @@ var UnitOfWork = class {
|
|
|
7122
7513
|
this.registerIdentity(tracked);
|
|
7123
7514
|
}
|
|
7124
7515
|
}
|
|
7516
|
+
/**
|
|
7517
|
+
* Tracks a managed entity.
|
|
7518
|
+
* @param table - The table definition
|
|
7519
|
+
* @param pk - The primary key value
|
|
7520
|
+
* @param entity - The entity instance
|
|
7521
|
+
*/
|
|
7125
7522
|
trackManaged(table, pk, entity) {
|
|
7126
7523
|
const tracked = {
|
|
7127
7524
|
table,
|
|
@@ -7133,17 +7530,28 @@ var UnitOfWork = class {
|
|
|
7133
7530
|
this.trackedEntities.set(entity, tracked);
|
|
7134
7531
|
this.registerIdentity(tracked);
|
|
7135
7532
|
}
|
|
7533
|
+
/**
|
|
7534
|
+
* Marks an entity as dirty (modified).
|
|
7535
|
+
* @param entity - The entity to mark as dirty
|
|
7536
|
+
*/
|
|
7136
7537
|
markDirty(entity) {
|
|
7137
7538
|
const tracked = this.trackedEntities.get(entity);
|
|
7138
7539
|
if (!tracked) return;
|
|
7139
7540
|
if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
|
|
7140
7541
|
tracked.status = "dirty" /* Dirty */;
|
|
7141
7542
|
}
|
|
7543
|
+
/**
|
|
7544
|
+
* Marks an entity as removed.
|
|
7545
|
+
* @param entity - The entity to mark as removed
|
|
7546
|
+
*/
|
|
7142
7547
|
markRemoved(entity) {
|
|
7143
7548
|
const tracked = this.trackedEntities.get(entity);
|
|
7144
7549
|
if (!tracked) return;
|
|
7145
7550
|
tracked.status = "removed" /* Removed */;
|
|
7146
7551
|
}
|
|
7552
|
+
/**
|
|
7553
|
+
* Flushes pending changes to the database.
|
|
7554
|
+
*/
|
|
7147
7555
|
async flush() {
|
|
7148
7556
|
const toFlush = Array.from(this.trackedEntities.values());
|
|
7149
7557
|
for (const tracked of toFlush) {
|
|
@@ -7162,10 +7570,17 @@ var UnitOfWork = class {
|
|
|
7162
7570
|
}
|
|
7163
7571
|
}
|
|
7164
7572
|
}
|
|
7573
|
+
/**
|
|
7574
|
+
* Resets the unit of work by clearing all tracked entities and identity map.
|
|
7575
|
+
*/
|
|
7165
7576
|
reset() {
|
|
7166
7577
|
this.trackedEntities.clear();
|
|
7167
7578
|
this.identityMap.clear();
|
|
7168
7579
|
}
|
|
7580
|
+
/**
|
|
7581
|
+
* Flushes an insert operation for a new entity.
|
|
7582
|
+
* @param tracked - The tracked entity to insert
|
|
7583
|
+
*/
|
|
7169
7584
|
async flushInsert(tracked) {
|
|
7170
7585
|
await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
|
|
7171
7586
|
const payload = this.extractColumns(tracked.table, tracked.entity);
|
|
@@ -7182,6 +7597,10 @@ var UnitOfWork = class {
|
|
|
7182
7597
|
this.registerIdentity(tracked);
|
|
7183
7598
|
await this.runHook(tracked.table.hooks?.afterInsert, tracked);
|
|
7184
7599
|
}
|
|
7600
|
+
/**
|
|
7601
|
+
* Flushes an update operation for a modified entity.
|
|
7602
|
+
* @param tracked - The tracked entity to update
|
|
7603
|
+
*/
|
|
7185
7604
|
async flushUpdate(tracked) {
|
|
7186
7605
|
if (tracked.pk == null) return;
|
|
7187
7606
|
const changes = this.computeChanges(tracked);
|
|
@@ -7204,6 +7623,10 @@ var UnitOfWork = class {
|
|
|
7204
7623
|
this.registerIdentity(tracked);
|
|
7205
7624
|
await this.runHook(tracked.table.hooks?.afterUpdate, tracked);
|
|
7206
7625
|
}
|
|
7626
|
+
/**
|
|
7627
|
+
* Flushes a delete operation for a removed entity.
|
|
7628
|
+
* @param tracked - The tracked entity to delete
|
|
7629
|
+
*/
|
|
7207
7630
|
async flushDelete(tracked) {
|
|
7208
7631
|
if (tracked.pk == null) return;
|
|
7209
7632
|
await this.runHook(tracked.table.hooks?.beforeDelete, tracked);
|
|
@@ -7217,10 +7640,20 @@ var UnitOfWork = class {
|
|
|
7217
7640
|
this.identityMap.remove(tracked);
|
|
7218
7641
|
await this.runHook(tracked.table.hooks?.afterDelete, tracked);
|
|
7219
7642
|
}
|
|
7643
|
+
/**
|
|
7644
|
+
* Runs a table hook if defined.
|
|
7645
|
+
* @param hook - The hook function
|
|
7646
|
+
* @param tracked - The tracked entity
|
|
7647
|
+
*/
|
|
7220
7648
|
async runHook(hook, tracked) {
|
|
7221
7649
|
if (!hook) return;
|
|
7222
7650
|
await hook(this.hookContext(), tracked.entity);
|
|
7223
7651
|
}
|
|
7652
|
+
/**
|
|
7653
|
+
* Computes changes between current entity state and original snapshot.
|
|
7654
|
+
* @param tracked - The tracked entity
|
|
7655
|
+
* @returns Object with changed column values
|
|
7656
|
+
*/
|
|
7224
7657
|
computeChanges(tracked) {
|
|
7225
7658
|
const snapshot = tracked.original ?? {};
|
|
7226
7659
|
const changes = {};
|
|
@@ -7232,6 +7665,12 @@ var UnitOfWork = class {
|
|
|
7232
7665
|
}
|
|
7233
7666
|
return changes;
|
|
7234
7667
|
}
|
|
7668
|
+
/**
|
|
7669
|
+
* Extracts column values from an entity.
|
|
7670
|
+
* @param table - The table definition
|
|
7671
|
+
* @param entity - The entity instance
|
|
7672
|
+
* @returns Object with column values
|
|
7673
|
+
*/
|
|
7235
7674
|
extractColumns(table, entity) {
|
|
7236
7675
|
const payload = {};
|
|
7237
7676
|
for (const column of Object.keys(table.columns)) {
|
|
@@ -7240,9 +7679,19 @@ var UnitOfWork = class {
|
|
|
7240
7679
|
}
|
|
7241
7680
|
return payload;
|
|
7242
7681
|
}
|
|
7682
|
+
/**
|
|
7683
|
+
* Executes a compiled query.
|
|
7684
|
+
* @param compiled - The compiled query
|
|
7685
|
+
* @returns Query results
|
|
7686
|
+
*/
|
|
7243
7687
|
async executeCompiled(compiled) {
|
|
7244
7688
|
return this.executor.executeSql(compiled.sql, compiled.params);
|
|
7245
7689
|
}
|
|
7690
|
+
/**
|
|
7691
|
+
* Gets columns for RETURNING clause.
|
|
7692
|
+
* @param table - The table definition
|
|
7693
|
+
* @returns Array of column nodes
|
|
7694
|
+
*/
|
|
7246
7695
|
getReturningColumns(table) {
|
|
7247
7696
|
return Object.values(table.columns).map((column) => ({
|
|
7248
7697
|
type: "Column",
|
|
@@ -7251,6 +7700,11 @@ var UnitOfWork = class {
|
|
|
7251
7700
|
alias: column.name
|
|
7252
7701
|
}));
|
|
7253
7702
|
}
|
|
7703
|
+
/**
|
|
7704
|
+
* Applies RETURNING clause results to the tracked entity.
|
|
7705
|
+
* @param tracked - The tracked entity
|
|
7706
|
+
* @param results - Query results
|
|
7707
|
+
*/
|
|
7254
7708
|
applyReturningResults(tracked, results) {
|
|
7255
7709
|
if (!this.dialect.supportsReturning()) return;
|
|
7256
7710
|
const first = results[0];
|
|
@@ -7262,15 +7716,30 @@ var UnitOfWork = class {
|
|
|
7262
7716
|
tracked.entity[columnName] = row[i];
|
|
7263
7717
|
}
|
|
7264
7718
|
}
|
|
7719
|
+
/**
|
|
7720
|
+
* Normalizes a column name by removing quotes and table prefixes.
|
|
7721
|
+
* @param column - The column name to normalize
|
|
7722
|
+
* @returns Normalized column name
|
|
7723
|
+
*/
|
|
7265
7724
|
normalizeColumnName(column) {
|
|
7266
7725
|
const parts = column.split(".");
|
|
7267
7726
|
const candidate = parts[parts.length - 1];
|
|
7268
7727
|
return candidate.replace(/^["`[\]]+|["`[\]]+$/g, "");
|
|
7269
7728
|
}
|
|
7729
|
+
/**
|
|
7730
|
+
* Registers an entity in the identity map.
|
|
7731
|
+
* @param tracked - The tracked entity to register
|
|
7732
|
+
*/
|
|
7270
7733
|
registerIdentity(tracked) {
|
|
7271
7734
|
if (tracked.pk == null) return;
|
|
7272
7735
|
this.identityMap.register(tracked);
|
|
7273
7736
|
}
|
|
7737
|
+
/**
|
|
7738
|
+
* Creates a snapshot of an entity's current state.
|
|
7739
|
+
* @param table - The table definition
|
|
7740
|
+
* @param entity - The entity instance
|
|
7741
|
+
* @returns Object with entity state
|
|
7742
|
+
*/
|
|
7274
7743
|
createSnapshot(table, entity) {
|
|
7275
7744
|
const snapshot = {};
|
|
7276
7745
|
for (const column of Object.keys(table.columns)) {
|
|
@@ -7278,6 +7747,11 @@ var UnitOfWork = class {
|
|
|
7278
7747
|
}
|
|
7279
7748
|
return snapshot;
|
|
7280
7749
|
}
|
|
7750
|
+
/**
|
|
7751
|
+
* Gets the primary key value from a tracked entity.
|
|
7752
|
+
* @param tracked - The tracked entity
|
|
7753
|
+
* @returns Primary key value or null
|
|
7754
|
+
*/
|
|
7281
7755
|
getPrimaryKeyValue(tracked) {
|
|
7282
7756
|
const key = findPrimaryKey(tracked.table);
|
|
7283
7757
|
const val = tracked.entity[key];
|
|
@@ -7288,6 +7762,10 @@ var UnitOfWork = class {
|
|
|
7288
7762
|
|
|
7289
7763
|
// src/orm/domain-event-bus.ts
|
|
7290
7764
|
var DomainEventBus = class {
|
|
7765
|
+
/**
|
|
7766
|
+
* Creates a new DomainEventBus instance.
|
|
7767
|
+
* @param initialHandlers - Optional initial event handlers
|
|
7768
|
+
*/
|
|
7291
7769
|
constructor(initialHandlers) {
|
|
7292
7770
|
this.handlers = /* @__PURE__ */ new Map();
|
|
7293
7771
|
if (initialHandlers) {
|
|
@@ -7298,15 +7776,32 @@ var DomainEventBus = class {
|
|
|
7298
7776
|
}
|
|
7299
7777
|
}
|
|
7300
7778
|
}
|
|
7779
|
+
/**
|
|
7780
|
+
* Registers an event handler for a specific event type.
|
|
7781
|
+
* @template TType - The event type
|
|
7782
|
+
* @param type - The event type
|
|
7783
|
+
* @param handler - The event handler
|
|
7784
|
+
*/
|
|
7301
7785
|
on(type, handler) {
|
|
7302
7786
|
const key = type;
|
|
7303
7787
|
const existing = this.handlers.get(key) ?? [];
|
|
7304
7788
|
existing.push(handler);
|
|
7305
7789
|
this.handlers.set(key, existing);
|
|
7306
7790
|
}
|
|
7791
|
+
/**
|
|
7792
|
+
* Registers an event handler for a specific event type (alias for on).
|
|
7793
|
+
* @template TType - The event type
|
|
7794
|
+
* @param type - The event type
|
|
7795
|
+
* @param handler - The event handler
|
|
7796
|
+
*/
|
|
7307
7797
|
register(type, handler) {
|
|
7308
7798
|
this.on(type, handler);
|
|
7309
7799
|
}
|
|
7800
|
+
/**
|
|
7801
|
+
* Dispatches domain events for tracked entities.
|
|
7802
|
+
* @param trackedEntities - Iterable of tracked entities
|
|
7803
|
+
* @param ctx - The context to pass to handlers
|
|
7804
|
+
*/
|
|
7310
7805
|
async dispatch(trackedEntities, ctx) {
|
|
7311
7806
|
for (const tracked of trackedEntities) {
|
|
7312
7807
|
const entity = tracked.entity;
|
|
@@ -7331,18 +7826,34 @@ var addDomainEvent = (entity, event) => {
|
|
|
7331
7826
|
|
|
7332
7827
|
// src/orm/relation-change-processor.ts
|
|
7333
7828
|
var RelationChangeProcessor = class {
|
|
7829
|
+
/**
|
|
7830
|
+
* Creates a new RelationChangeProcessor instance.
|
|
7831
|
+
* @param unitOfWork - The unit of work instance
|
|
7832
|
+
* @param dialect - The database dialect
|
|
7833
|
+
* @param executor - The database executor
|
|
7834
|
+
*/
|
|
7334
7835
|
constructor(unitOfWork, dialect, executor) {
|
|
7335
7836
|
this.unitOfWork = unitOfWork;
|
|
7336
7837
|
this.dialect = dialect;
|
|
7337
7838
|
this.executor = executor;
|
|
7338
7839
|
this.relationChanges = [];
|
|
7339
7840
|
}
|
|
7841
|
+
/**
|
|
7842
|
+
* Registers a relation change for processing.
|
|
7843
|
+
* @param entry - The relation change entry
|
|
7844
|
+
*/
|
|
7340
7845
|
registerChange(entry) {
|
|
7341
7846
|
this.relationChanges.push(entry);
|
|
7342
7847
|
}
|
|
7848
|
+
/**
|
|
7849
|
+
* Resets the relation change processor by clearing all pending changes.
|
|
7850
|
+
*/
|
|
7343
7851
|
reset() {
|
|
7344
7852
|
this.relationChanges.length = 0;
|
|
7345
7853
|
}
|
|
7854
|
+
/**
|
|
7855
|
+
* Processes all pending relation changes.
|
|
7856
|
+
*/
|
|
7346
7857
|
async process() {
|
|
7347
7858
|
if (!this.relationChanges.length) return;
|
|
7348
7859
|
const entries = [...this.relationChanges];
|
|
@@ -7364,6 +7875,10 @@ var RelationChangeProcessor = class {
|
|
|
7364
7875
|
}
|
|
7365
7876
|
}
|
|
7366
7877
|
}
|
|
7878
|
+
/**
|
|
7879
|
+
* Handles changes for has-many relations.
|
|
7880
|
+
* @param entry - The relation change entry
|
|
7881
|
+
*/
|
|
7367
7882
|
async handleHasManyChange(entry) {
|
|
7368
7883
|
const relation = entry.relation;
|
|
7369
7884
|
const target = entry.change.entity;
|
|
@@ -7382,6 +7897,10 @@ var RelationChangeProcessor = class {
|
|
|
7382
7897
|
this.detachHasManyChild(tracked.entity, relation);
|
|
7383
7898
|
}
|
|
7384
7899
|
}
|
|
7900
|
+
/**
|
|
7901
|
+
* Handles changes for has-one relations.
|
|
7902
|
+
* @param entry - The relation change entry
|
|
7903
|
+
*/
|
|
7385
7904
|
async handleHasOneChange(entry) {
|
|
7386
7905
|
const relation = entry.relation;
|
|
7387
7906
|
const target = entry.change.entity;
|
|
@@ -7400,8 +7919,16 @@ var RelationChangeProcessor = class {
|
|
|
7400
7919
|
this.detachHasOneChild(tracked.entity, relation);
|
|
7401
7920
|
}
|
|
7402
7921
|
}
|
|
7922
|
+
/**
|
|
7923
|
+
* Handles changes for belongs-to relations.
|
|
7924
|
+
* @param _entry - The relation change entry (reserved for future use)
|
|
7925
|
+
*/
|
|
7403
7926
|
async handleBelongsToChange(_entry) {
|
|
7404
7927
|
}
|
|
7928
|
+
/**
|
|
7929
|
+
* Handles changes for belongs-to-many relations.
|
|
7930
|
+
* @param entry - The relation change entry
|
|
7931
|
+
*/
|
|
7405
7932
|
async handleBelongsToManyChange(entry) {
|
|
7406
7933
|
const relation = entry.relation;
|
|
7407
7934
|
const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
|
|
@@ -7420,11 +7947,22 @@ var RelationChangeProcessor = class {
|
|
|
7420
7947
|
}
|
|
7421
7948
|
}
|
|
7422
7949
|
}
|
|
7950
|
+
/**
|
|
7951
|
+
* Assigns a foreign key for has-many relations.
|
|
7952
|
+
* @param child - The child entity
|
|
7953
|
+
* @param relation - The has-many relation
|
|
7954
|
+
* @param rootValue - The root entity's primary key value
|
|
7955
|
+
*/
|
|
7423
7956
|
assignHasManyForeignKey(child, relation, rootValue) {
|
|
7424
7957
|
const current = child[relation.foreignKey];
|
|
7425
7958
|
if (current === rootValue) return;
|
|
7426
7959
|
child[relation.foreignKey] = rootValue;
|
|
7427
7960
|
}
|
|
7961
|
+
/**
|
|
7962
|
+
* Detaches a child entity from has-many relations.
|
|
7963
|
+
* @param child - The child entity
|
|
7964
|
+
* @param relation - The has-many relation
|
|
7965
|
+
*/
|
|
7428
7966
|
detachHasManyChild(child, relation) {
|
|
7429
7967
|
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7430
7968
|
this.unitOfWork.markRemoved(child);
|
|
@@ -7433,11 +7971,22 @@ var RelationChangeProcessor = class {
|
|
|
7433
7971
|
child[relation.foreignKey] = null;
|
|
7434
7972
|
this.unitOfWork.markDirty(child);
|
|
7435
7973
|
}
|
|
7974
|
+
/**
|
|
7975
|
+
* Assigns a foreign key for has-one relations.
|
|
7976
|
+
* @param child - The child entity
|
|
7977
|
+
* @param relation - The has-one relation
|
|
7978
|
+
* @param rootValue - The root entity's primary key value
|
|
7979
|
+
*/
|
|
7436
7980
|
assignHasOneForeignKey(child, relation, rootValue) {
|
|
7437
7981
|
const current = child[relation.foreignKey];
|
|
7438
7982
|
if (current === rootValue) return;
|
|
7439
7983
|
child[relation.foreignKey] = rootValue;
|
|
7440
7984
|
}
|
|
7985
|
+
/**
|
|
7986
|
+
* Detaches a child entity from has-one relations.
|
|
7987
|
+
* @param child - The child entity
|
|
7988
|
+
* @param relation - The has-one relation
|
|
7989
|
+
*/
|
|
7441
7990
|
detachHasOneChild(child, relation) {
|
|
7442
7991
|
if (relation.cascade === "all" || relation.cascade === "remove") {
|
|
7443
7992
|
this.unitOfWork.markRemoved(child);
|
|
@@ -7446,6 +7995,12 @@ var RelationChangeProcessor = class {
|
|
|
7446
7995
|
child[relation.foreignKey] = null;
|
|
7447
7996
|
this.unitOfWork.markDirty(child);
|
|
7448
7997
|
}
|
|
7998
|
+
/**
|
|
7999
|
+
* Inserts a pivot row for belongs-to-many relations.
|
|
8000
|
+
* @param relation - The belongs-to-many relation
|
|
8001
|
+
* @param rootId - The root entity's primary key value
|
|
8002
|
+
* @param targetId - The target entity's primary key value
|
|
8003
|
+
*/
|
|
7449
8004
|
async insertPivotRow(relation, rootId, targetId) {
|
|
7450
8005
|
const payload = {
|
|
7451
8006
|
[relation.pivotForeignKeyToRoot]: rootId,
|
|
@@ -7455,6 +8010,12 @@ var RelationChangeProcessor = class {
|
|
|
7455
8010
|
const compiled = builder.compile(this.dialect);
|
|
7456
8011
|
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7457
8012
|
}
|
|
8013
|
+
/**
|
|
8014
|
+
* Deletes a pivot row for belongs-to-many relations.
|
|
8015
|
+
* @param relation - The belongs-to-many relation
|
|
8016
|
+
* @param rootId - The root entity's primary key value
|
|
8017
|
+
* @param targetId - The target entity's primary key value
|
|
8018
|
+
*/
|
|
7458
8019
|
async deletePivotRow(relation, rootId, targetId) {
|
|
7459
8020
|
const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
|
|
7460
8021
|
const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
|
|
@@ -7465,6 +8026,12 @@ var RelationChangeProcessor = class {
|
|
|
7465
8026
|
const compiled = builder.compile(this.dialect);
|
|
7466
8027
|
await this.executor.executeSql(compiled.sql, compiled.params);
|
|
7467
8028
|
}
|
|
8029
|
+
/**
|
|
8030
|
+
* Resolves the primary key value from an entity.
|
|
8031
|
+
* @param entity - The entity
|
|
8032
|
+
* @param table - The table definition
|
|
8033
|
+
* @returns The primary key value or null
|
|
8034
|
+
*/
|
|
7468
8035
|
resolvePrimaryKeyValue(entity, table) {
|
|
7469
8036
|
if (!entity) return null;
|
|
7470
8037
|
const key = findPrimaryKey(table);
|
|
@@ -7480,42 +8047,231 @@ var createQueryLoggingExecutor = (executor, logger) => {
|
|
|
7480
8047
|
return executor;
|
|
7481
8048
|
}
|
|
7482
8049
|
const wrapped = {
|
|
8050
|
+
capabilities: executor.capabilities,
|
|
7483
8051
|
async executeSql(sql, params) {
|
|
7484
8052
|
logger({ sql, params });
|
|
7485
8053
|
return executor.executeSql(sql, params);
|
|
7486
|
-
}
|
|
8054
|
+
},
|
|
8055
|
+
beginTransaction: () => executor.beginTransaction(),
|
|
8056
|
+
commitTransaction: () => executor.commitTransaction(),
|
|
8057
|
+
rollbackTransaction: () => executor.rollbackTransaction(),
|
|
8058
|
+
dispose: () => executor.dispose()
|
|
7487
8059
|
};
|
|
7488
|
-
if (executor.beginTransaction) {
|
|
7489
|
-
wrapped.beginTransaction = executor.beginTransaction.bind(executor);
|
|
7490
|
-
}
|
|
7491
|
-
if (executor.commitTransaction) {
|
|
7492
|
-
wrapped.commitTransaction = executor.commitTransaction.bind(executor);
|
|
7493
|
-
}
|
|
7494
|
-
if (executor.rollbackTransaction) {
|
|
7495
|
-
wrapped.rollbackTransaction = executor.rollbackTransaction.bind(executor);
|
|
7496
|
-
}
|
|
7497
8060
|
return wrapped;
|
|
7498
8061
|
};
|
|
7499
8062
|
|
|
7500
8063
|
// src/orm/transaction-runner.ts
|
|
7501
8064
|
var runInTransaction = async (executor, action) => {
|
|
7502
|
-
if (!executor.
|
|
8065
|
+
if (!executor.capabilities.transactions) {
|
|
7503
8066
|
await action();
|
|
7504
8067
|
return;
|
|
7505
8068
|
}
|
|
7506
8069
|
await executor.beginTransaction();
|
|
7507
8070
|
try {
|
|
7508
8071
|
await action();
|
|
7509
|
-
await executor.commitTransaction
|
|
8072
|
+
await executor.commitTransaction();
|
|
7510
8073
|
} catch (error) {
|
|
7511
|
-
await executor.rollbackTransaction
|
|
8074
|
+
await executor.rollbackTransaction();
|
|
7512
8075
|
throw error;
|
|
7513
8076
|
}
|
|
7514
8077
|
};
|
|
7515
8078
|
|
|
8079
|
+
// src/orm/save-graph.ts
|
|
8080
|
+
var toKey8 = (value) => value === null || value === void 0 ? "" : String(value);
|
|
8081
|
+
var pickColumns = (table, payload) => {
|
|
8082
|
+
const columns = {};
|
|
8083
|
+
for (const key of Object.keys(table.columns)) {
|
|
8084
|
+
if (payload[key] !== void 0) {
|
|
8085
|
+
columns[key] = payload[key];
|
|
8086
|
+
}
|
|
8087
|
+
}
|
|
8088
|
+
return columns;
|
|
8089
|
+
};
|
|
8090
|
+
var ensureEntity = (session, table, payload) => {
|
|
8091
|
+
const pk = findPrimaryKey(table);
|
|
8092
|
+
const row = pickColumns(table, payload);
|
|
8093
|
+
const pkValue = payload[pk];
|
|
8094
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8095
|
+
const tracked = session.getEntity(table, pkValue);
|
|
8096
|
+
if (tracked) {
|
|
8097
|
+
return tracked;
|
|
8098
|
+
}
|
|
8099
|
+
if (row[pk] === void 0) {
|
|
8100
|
+
row[pk] = pkValue;
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
8103
|
+
return createEntityFromRow(session, table, row);
|
|
8104
|
+
};
|
|
8105
|
+
var assignColumns = (table, entity, payload) => {
|
|
8106
|
+
for (const key of Object.keys(table.columns)) {
|
|
8107
|
+
if (payload[key] !== void 0) {
|
|
8108
|
+
entity[key] = payload[key];
|
|
8109
|
+
}
|
|
8110
|
+
}
|
|
8111
|
+
};
|
|
8112
|
+
var isEntityInCollection = (items, pkName, entity) => {
|
|
8113
|
+
if (items.includes(entity)) return true;
|
|
8114
|
+
const entityPk = entity[pkName];
|
|
8115
|
+
if (entityPk === void 0 || entityPk === null) return false;
|
|
8116
|
+
return items.some((item) => toKey8(item[pkName]) === toKey8(entityPk));
|
|
8117
|
+
};
|
|
8118
|
+
var findInCollectionByPk = (items, pkName, pkValue) => {
|
|
8119
|
+
if (pkValue === void 0 || pkValue === null) return void 0;
|
|
8120
|
+
return items.find((item) => toKey8(item[pkName]) === toKey8(pkValue));
|
|
8121
|
+
};
|
|
8122
|
+
var handleHasMany = async (session, root, relationName, relation, payload, options) => {
|
|
8123
|
+
if (!Array.isArray(payload)) return;
|
|
8124
|
+
const collection = root[relationName];
|
|
8125
|
+
await collection.load();
|
|
8126
|
+
const targetTable = relation.target;
|
|
8127
|
+
const targetPk = findPrimaryKey(targetTable);
|
|
8128
|
+
const existing = collection.getItems();
|
|
8129
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8130
|
+
for (const item of payload) {
|
|
8131
|
+
if (item === null || item === void 0) continue;
|
|
8132
|
+
const asObj = typeof item === "object" ? item : { [targetPk]: item };
|
|
8133
|
+
const pkValue = asObj[targetPk];
|
|
8134
|
+
const current = findInCollectionByPk(existing, targetPk, pkValue) ?? (pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) : void 0);
|
|
8135
|
+
const entity = current ?? ensureEntity(session, targetTable, asObj);
|
|
8136
|
+
assignColumns(targetTable, entity, asObj);
|
|
8137
|
+
await applyGraphToEntity(session, targetTable, entity, asObj, options);
|
|
8138
|
+
if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
|
|
8139
|
+
collection.attach(entity);
|
|
8140
|
+
}
|
|
8141
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8142
|
+
seen.add(toKey8(pkValue));
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
if (options.pruneMissing) {
|
|
8146
|
+
for (const item of [...collection.getItems()]) {
|
|
8147
|
+
const pkValue = item[targetPk];
|
|
8148
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
|
|
8149
|
+
collection.remove(item);
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
8153
|
+
};
|
|
8154
|
+
var handleHasOne = async (session, root, relationName, relation, payload, options) => {
|
|
8155
|
+
const ref = root[relationName];
|
|
8156
|
+
if (payload === void 0) return;
|
|
8157
|
+
if (payload === null) {
|
|
8158
|
+
ref.set(null);
|
|
8159
|
+
return;
|
|
8160
|
+
}
|
|
8161
|
+
const pk = findPrimaryKey(relation.target);
|
|
8162
|
+
if (typeof payload === "number" || typeof payload === "string") {
|
|
8163
|
+
const entity = ref.set({ [pk]: payload });
|
|
8164
|
+
if (entity) {
|
|
8165
|
+
await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
|
|
8166
|
+
}
|
|
8167
|
+
return;
|
|
8168
|
+
}
|
|
8169
|
+
const attached = ref.set(payload);
|
|
8170
|
+
if (attached) {
|
|
8171
|
+
await applyGraphToEntity(session, relation.target, attached, payload, options);
|
|
8172
|
+
}
|
|
8173
|
+
};
|
|
8174
|
+
var handleBelongsTo = async (session, root, relationName, relation, payload, options) => {
|
|
8175
|
+
const ref = root[relationName];
|
|
8176
|
+
if (payload === void 0) return;
|
|
8177
|
+
if (payload === null) {
|
|
8178
|
+
ref.set(null);
|
|
8179
|
+
return;
|
|
8180
|
+
}
|
|
8181
|
+
const pk = relation.localKey || findPrimaryKey(relation.target);
|
|
8182
|
+
if (typeof payload === "number" || typeof payload === "string") {
|
|
8183
|
+
const entity = ref.set({ [pk]: payload });
|
|
8184
|
+
if (entity) {
|
|
8185
|
+
await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
|
|
8186
|
+
}
|
|
8187
|
+
return;
|
|
8188
|
+
}
|
|
8189
|
+
const attached = ref.set(payload);
|
|
8190
|
+
if (attached) {
|
|
8191
|
+
await applyGraphToEntity(session, relation.target, attached, payload, options);
|
|
8192
|
+
}
|
|
8193
|
+
};
|
|
8194
|
+
var handleBelongsToMany = async (session, root, relationName, relation, payload, options) => {
|
|
8195
|
+
if (!Array.isArray(payload)) return;
|
|
8196
|
+
const collection = root[relationName];
|
|
8197
|
+
await collection.load();
|
|
8198
|
+
const targetTable = relation.target;
|
|
8199
|
+
const targetPk = relation.targetKey || findPrimaryKey(targetTable);
|
|
8200
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8201
|
+
for (const item of payload) {
|
|
8202
|
+
if (item === null || item === void 0) continue;
|
|
8203
|
+
if (typeof item === "number" || typeof item === "string") {
|
|
8204
|
+
const id = item;
|
|
8205
|
+
collection.attach(id);
|
|
8206
|
+
seen.add(toKey8(id));
|
|
8207
|
+
continue;
|
|
8208
|
+
}
|
|
8209
|
+
const asObj = item;
|
|
8210
|
+
const pkValue = asObj[targetPk];
|
|
8211
|
+
const entity = pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) ?? ensureEntity(session, targetTable, asObj) : ensureEntity(session, targetTable, asObj);
|
|
8212
|
+
assignColumns(targetTable, entity, asObj);
|
|
8213
|
+
await applyGraphToEntity(session, targetTable, entity, asObj, options);
|
|
8214
|
+
if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
|
|
8215
|
+
collection.attach(entity);
|
|
8216
|
+
}
|
|
8217
|
+
if (pkValue !== void 0 && pkValue !== null) {
|
|
8218
|
+
seen.add(toKey8(pkValue));
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
if (options.pruneMissing) {
|
|
8222
|
+
for (const item of [...collection.getItems()]) {
|
|
8223
|
+
const pkValue = item[targetPk];
|
|
8224
|
+
if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
|
|
8225
|
+
collection.detach(item);
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8228
|
+
}
|
|
8229
|
+
};
|
|
8230
|
+
var applyRelation = async (session, table, entity, relationName, relation, payload, options) => {
|
|
8231
|
+
switch (relation.type) {
|
|
8232
|
+
case RelationKinds.HasMany:
|
|
8233
|
+
return handleHasMany(session, entity, relationName, relation, payload, options);
|
|
8234
|
+
case RelationKinds.HasOne:
|
|
8235
|
+
return handleHasOne(session, entity, relationName, relation, payload, options);
|
|
8236
|
+
case RelationKinds.BelongsTo:
|
|
8237
|
+
return handleBelongsTo(session, entity, relationName, relation, payload, options);
|
|
8238
|
+
case RelationKinds.BelongsToMany:
|
|
8239
|
+
return handleBelongsToMany(session, entity, relationName, relation, payload, options);
|
|
8240
|
+
}
|
|
8241
|
+
};
|
|
8242
|
+
var applyGraphToEntity = async (session, table, entity, payload, options) => {
|
|
8243
|
+
assignColumns(table, entity, payload);
|
|
8244
|
+
for (const [relationName, relation] of Object.entries(table.relations)) {
|
|
8245
|
+
if (!(relationName in payload)) continue;
|
|
8246
|
+
await applyRelation(session, table, entity, relationName, relation, payload[relationName], options);
|
|
8247
|
+
}
|
|
8248
|
+
};
|
|
8249
|
+
var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
|
|
8250
|
+
const table = getTableDefFromEntity(entityClass);
|
|
8251
|
+
if (!table) {
|
|
8252
|
+
throw new Error("Entity metadata has not been bootstrapped");
|
|
8253
|
+
}
|
|
8254
|
+
const root = ensureEntity(session, table, payload);
|
|
8255
|
+
await applyGraphToEntity(session, table, root, payload, options);
|
|
8256
|
+
return root;
|
|
8257
|
+
};
|
|
8258
|
+
|
|
7516
8259
|
// src/orm/orm-session.ts
|
|
7517
8260
|
var OrmSession = class {
|
|
8261
|
+
/**
|
|
8262
|
+
* Creates a new OrmSession instance.
|
|
8263
|
+
* @param opts - Session options
|
|
8264
|
+
*/
|
|
7518
8265
|
constructor(opts) {
|
|
8266
|
+
/**
|
|
8267
|
+
* Registers a relation change.
|
|
8268
|
+
* @param root - The root entity
|
|
8269
|
+
* @param relationKey - The relation key
|
|
8270
|
+
* @param rootTable - The root table definition
|
|
8271
|
+
* @param relationName - The relation name
|
|
8272
|
+
* @param relation - The relation definition
|
|
8273
|
+
* @param change - The relation change
|
|
8274
|
+
*/
|
|
7519
8275
|
this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
|
|
7520
8276
|
this.relationChanges.registerChange(
|
|
7521
8277
|
buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
|
|
@@ -7529,42 +8285,117 @@ var OrmSession = class {
|
|
|
7529
8285
|
this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
|
|
7530
8286
|
this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
|
|
7531
8287
|
}
|
|
8288
|
+
/**
|
|
8289
|
+
* Releases resources associated with this session (executor/pool leases) and resets tracking.
|
|
8290
|
+
* Must be safe to call multiple times.
|
|
8291
|
+
*/
|
|
8292
|
+
async dispose() {
|
|
8293
|
+
try {
|
|
8294
|
+
await this.executor.dispose();
|
|
8295
|
+
} finally {
|
|
8296
|
+
this.unitOfWork.reset();
|
|
8297
|
+
this.relationChanges.reset();
|
|
8298
|
+
}
|
|
8299
|
+
}
|
|
8300
|
+
/**
|
|
8301
|
+
* Gets the database dialect.
|
|
8302
|
+
*/
|
|
7532
8303
|
get dialect() {
|
|
7533
8304
|
return this.orm.dialect;
|
|
7534
8305
|
}
|
|
8306
|
+
/**
|
|
8307
|
+
* Gets the identity buckets map.
|
|
8308
|
+
*/
|
|
7535
8309
|
get identityBuckets() {
|
|
7536
8310
|
return this.unitOfWork.identityBuckets;
|
|
7537
8311
|
}
|
|
8312
|
+
/**
|
|
8313
|
+
* Gets all tracked entities.
|
|
8314
|
+
*/
|
|
7538
8315
|
get tracked() {
|
|
7539
8316
|
return this.unitOfWork.getTracked();
|
|
7540
8317
|
}
|
|
8318
|
+
/**
|
|
8319
|
+
* Gets an entity by table and primary key.
|
|
8320
|
+
* @param table - The table definition
|
|
8321
|
+
* @param pk - The primary key value
|
|
8322
|
+
* @returns The entity or undefined if not found
|
|
8323
|
+
*/
|
|
7541
8324
|
getEntity(table, pk) {
|
|
7542
8325
|
return this.unitOfWork.getEntity(table, pk);
|
|
7543
8326
|
}
|
|
8327
|
+
/**
|
|
8328
|
+
* Sets an entity in the identity map.
|
|
8329
|
+
* @param table - The table definition
|
|
8330
|
+
* @param pk - The primary key value
|
|
8331
|
+
* @param entity - The entity instance
|
|
8332
|
+
*/
|
|
7544
8333
|
setEntity(table, pk, entity) {
|
|
7545
8334
|
this.unitOfWork.setEntity(table, pk, entity);
|
|
7546
8335
|
}
|
|
8336
|
+
/**
|
|
8337
|
+
* Tracks a new entity.
|
|
8338
|
+
* @param table - The table definition
|
|
8339
|
+
* @param entity - The entity instance
|
|
8340
|
+
* @param pk - Optional primary key value
|
|
8341
|
+
*/
|
|
7547
8342
|
trackNew(table, entity, pk) {
|
|
7548
8343
|
this.unitOfWork.trackNew(table, entity, pk);
|
|
7549
8344
|
}
|
|
8345
|
+
/**
|
|
8346
|
+
* Tracks a managed entity.
|
|
8347
|
+
* @param table - The table definition
|
|
8348
|
+
* @param pk - The primary key value
|
|
8349
|
+
* @param entity - The entity instance
|
|
8350
|
+
*/
|
|
7550
8351
|
trackManaged(table, pk, entity) {
|
|
7551
8352
|
this.unitOfWork.trackManaged(table, pk, entity);
|
|
7552
8353
|
}
|
|
8354
|
+
/**
|
|
8355
|
+
* Marks an entity as dirty (modified).
|
|
8356
|
+
* @param entity - The entity to mark as dirty
|
|
8357
|
+
*/
|
|
7553
8358
|
markDirty(entity) {
|
|
7554
8359
|
this.unitOfWork.markDirty(entity);
|
|
7555
8360
|
}
|
|
8361
|
+
/**
|
|
8362
|
+
* Marks an entity as removed.
|
|
8363
|
+
* @param entity - The entity to mark as removed
|
|
8364
|
+
*/
|
|
7556
8365
|
markRemoved(entity) {
|
|
7557
8366
|
this.unitOfWork.markRemoved(entity);
|
|
7558
8367
|
}
|
|
8368
|
+
/**
|
|
8369
|
+
* Gets all tracked entities for a specific table.
|
|
8370
|
+
* @param table - The table definition
|
|
8371
|
+
* @returns Array of tracked entities
|
|
8372
|
+
*/
|
|
7559
8373
|
getEntitiesForTable(table) {
|
|
7560
8374
|
return this.unitOfWork.getEntitiesForTable(table);
|
|
7561
8375
|
}
|
|
8376
|
+
/**
|
|
8377
|
+
* Registers an interceptor for flush lifecycle hooks.
|
|
8378
|
+
* @param interceptor - The interceptor to register
|
|
8379
|
+
*/
|
|
7562
8380
|
registerInterceptor(interceptor) {
|
|
7563
8381
|
this.interceptors.push(interceptor);
|
|
7564
8382
|
}
|
|
8383
|
+
/**
|
|
8384
|
+
* Registers a domain event handler.
|
|
8385
|
+
* @param type - The event type
|
|
8386
|
+
* @param handler - The event handler
|
|
8387
|
+
*/
|
|
7565
8388
|
registerDomainEventHandler(type, handler) {
|
|
7566
8389
|
this.domainEvents.on(type, handler);
|
|
7567
8390
|
}
|
|
8391
|
+
/**
|
|
8392
|
+
* Finds an entity by its primary key.
|
|
8393
|
+
* @template TCtor - The entity constructor type
|
|
8394
|
+
* @param entityClass - The entity constructor
|
|
8395
|
+
* @param id - The primary key value
|
|
8396
|
+
* @returns The entity instance or null if not found
|
|
8397
|
+
* @throws If entity metadata is not bootstrapped or table has no primary key
|
|
8398
|
+
*/
|
|
7568
8399
|
async find(entityClass, id) {
|
|
7569
8400
|
const table = getTableDefFromEntity(entityClass);
|
|
7570
8401
|
if (!table) {
|
|
@@ -7583,14 +8414,46 @@ var OrmSession = class {
|
|
|
7583
8414
|
const rows = await executeHydrated(this, qb);
|
|
7584
8415
|
return rows[0] ?? null;
|
|
7585
8416
|
}
|
|
8417
|
+
/**
|
|
8418
|
+
* Finds a single entity using a query builder.
|
|
8419
|
+
* @template TTable - The table type
|
|
8420
|
+
* @param qb - The query builder
|
|
8421
|
+
* @returns The first entity instance or null if not found
|
|
8422
|
+
*/
|
|
7586
8423
|
async findOne(qb) {
|
|
7587
8424
|
const limited = qb.limit(1);
|
|
7588
8425
|
const rows = await executeHydrated(this, limited);
|
|
7589
8426
|
return rows[0] ?? null;
|
|
7590
8427
|
}
|
|
8428
|
+
/**
|
|
8429
|
+
* Finds multiple entities using a query builder.
|
|
8430
|
+
* @template TTable - The table type
|
|
8431
|
+
* @param qb - The query builder
|
|
8432
|
+
* @returns Array of entity instances
|
|
8433
|
+
*/
|
|
7591
8434
|
async findMany(qb) {
|
|
7592
8435
|
return executeHydrated(this, qb);
|
|
7593
8436
|
}
|
|
8437
|
+
/**
|
|
8438
|
+
* Saves an entity graph (root + nested relations) based on a DTO-like payload.
|
|
8439
|
+
* @param entityClass - Root entity constructor
|
|
8440
|
+
* @param payload - DTO payload containing column values and nested relations
|
|
8441
|
+
* @param options - Graph save options
|
|
8442
|
+
* @returns The root entity instance
|
|
8443
|
+
*/
|
|
8444
|
+
async saveGraph(entityClass, payload, options) {
|
|
8445
|
+
const { transactional = true, ...graphOptions } = options ?? {};
|
|
8446
|
+
const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
|
|
8447
|
+
if (!transactional) {
|
|
8448
|
+
return execute();
|
|
8449
|
+
}
|
|
8450
|
+
return this.transaction(() => execute());
|
|
8451
|
+
}
|
|
8452
|
+
/**
|
|
8453
|
+
* Persists an entity (either inserts or updates).
|
|
8454
|
+
* @param entity - The entity to persist
|
|
8455
|
+
* @throws If entity metadata is not bootstrapped
|
|
8456
|
+
*/
|
|
7594
8457
|
async persist(entity) {
|
|
7595
8458
|
if (this.unitOfWork.findTracked(entity)) {
|
|
7596
8459
|
return;
|
|
@@ -7607,12 +8470,22 @@ var OrmSession = class {
|
|
|
7607
8470
|
this.trackNew(table, entity);
|
|
7608
8471
|
}
|
|
7609
8472
|
}
|
|
8473
|
+
/**
|
|
8474
|
+
* Marks an entity for removal.
|
|
8475
|
+
* @param entity - The entity to remove
|
|
8476
|
+
*/
|
|
7610
8477
|
async remove(entity) {
|
|
7611
8478
|
this.markRemoved(entity);
|
|
7612
8479
|
}
|
|
8480
|
+
/**
|
|
8481
|
+
* Flushes pending changes to the database.
|
|
8482
|
+
*/
|
|
7613
8483
|
async flush() {
|
|
7614
8484
|
await this.unitOfWork.flush();
|
|
7615
8485
|
}
|
|
8486
|
+
/**
|
|
8487
|
+
* Flushes pending changes with interceptors and relation processing.
|
|
8488
|
+
*/
|
|
7616
8489
|
async flushWithHooks() {
|
|
7617
8490
|
for (const interceptor of this.interceptors) {
|
|
7618
8491
|
await interceptor.beforeFlush?.(this);
|
|
@@ -7624,14 +8497,24 @@ var OrmSession = class {
|
|
|
7624
8497
|
await interceptor.afterFlush?.(this);
|
|
7625
8498
|
}
|
|
7626
8499
|
}
|
|
8500
|
+
/**
|
|
8501
|
+
* Commits the current transaction.
|
|
8502
|
+
*/
|
|
7627
8503
|
async commit() {
|
|
7628
8504
|
await runInTransaction(this.executor, async () => {
|
|
7629
8505
|
await this.flushWithHooks();
|
|
7630
8506
|
});
|
|
7631
8507
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
7632
8508
|
}
|
|
8509
|
+
/**
|
|
8510
|
+
* Executes a function within a transaction.
|
|
8511
|
+
* @template T - The return type
|
|
8512
|
+
* @param fn - The function to execute
|
|
8513
|
+
* @returns The result of the function
|
|
8514
|
+
* @throws If the transaction fails
|
|
8515
|
+
*/
|
|
7633
8516
|
async transaction(fn4) {
|
|
7634
|
-
if (!this.executor.
|
|
8517
|
+
if (!this.executor.capabilities.transactions) {
|
|
7635
8518
|
const result = await fn4(this);
|
|
7636
8519
|
await this.commit();
|
|
7637
8520
|
return result;
|
|
@@ -7640,7 +8523,7 @@ var OrmSession = class {
|
|
|
7640
8523
|
try {
|
|
7641
8524
|
const result = await fn4(this);
|
|
7642
8525
|
await this.flushWithHooks();
|
|
7643
|
-
await this.executor.commitTransaction
|
|
8526
|
+
await this.executor.commitTransaction();
|
|
7644
8527
|
await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
|
|
7645
8528
|
return result;
|
|
7646
8529
|
} catch (err) {
|
|
@@ -7648,11 +8531,20 @@ var OrmSession = class {
|
|
|
7648
8531
|
throw err;
|
|
7649
8532
|
}
|
|
7650
8533
|
}
|
|
8534
|
+
/**
|
|
8535
|
+
* Rolls back the current transaction.
|
|
8536
|
+
*/
|
|
7651
8537
|
async rollback() {
|
|
7652
|
-
|
|
8538
|
+
if (this.executor.capabilities.transactions) {
|
|
8539
|
+
await this.executor.rollbackTransaction();
|
|
8540
|
+
}
|
|
7653
8541
|
this.unitOfWork.reset();
|
|
7654
8542
|
this.relationChanges.reset();
|
|
7655
8543
|
}
|
|
8544
|
+
/**
|
|
8545
|
+
* Gets the execution context.
|
|
8546
|
+
* @returns The execution context
|
|
8547
|
+
*/
|
|
7656
8548
|
getExecutionContext() {
|
|
7657
8549
|
return {
|
|
7658
8550
|
dialect: this.orm.dialect,
|
|
@@ -7660,6 +8552,10 @@ var OrmSession = class {
|
|
|
7660
8552
|
interceptors: this.orm.interceptors
|
|
7661
8553
|
};
|
|
7662
8554
|
}
|
|
8555
|
+
/**
|
|
8556
|
+
* Gets the hydration context.
|
|
8557
|
+
* @returns The hydration context
|
|
8558
|
+
*/
|
|
7663
8559
|
getHydrationContext() {
|
|
7664
8560
|
return {
|
|
7665
8561
|
identityMap: this.identityMap,
|
|
@@ -7702,29 +8598,49 @@ var InterceptorPipeline = class {
|
|
|
7702
8598
|
|
|
7703
8599
|
// src/orm/orm.ts
|
|
7704
8600
|
var Orm = class {
|
|
8601
|
+
/**
|
|
8602
|
+
* Creates a new ORM instance.
|
|
8603
|
+
* @param opts - ORM options
|
|
8604
|
+
*/
|
|
7705
8605
|
constructor(opts) {
|
|
7706
8606
|
this.dialect = opts.dialect;
|
|
7707
8607
|
this.interceptors = opts.interceptors ?? new InterceptorPipeline();
|
|
7708
8608
|
this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
|
|
7709
8609
|
this.executorFactory = opts.executorFactory;
|
|
7710
8610
|
}
|
|
7711
|
-
|
|
7712
|
-
|
|
8611
|
+
/**
|
|
8612
|
+
* Creates a new ORM session.
|
|
8613
|
+
* @param options - Optional session options
|
|
8614
|
+
* @returns The ORM session
|
|
8615
|
+
*/
|
|
8616
|
+
createSession() {
|
|
8617
|
+
const executor = this.executorFactory.createExecutor();
|
|
7713
8618
|
return new OrmSession({ orm: this, executor });
|
|
7714
8619
|
}
|
|
8620
|
+
/**
|
|
8621
|
+
* Executes a function within a transaction.
|
|
8622
|
+
* @template T - The return type
|
|
8623
|
+
* @param fn - The function to execute
|
|
8624
|
+
* @returns The result of the function
|
|
8625
|
+
* @throws If the transaction fails
|
|
8626
|
+
*/
|
|
7715
8627
|
async transaction(fn4) {
|
|
7716
8628
|
const executor = this.executorFactory.createTransactionalExecutor();
|
|
7717
8629
|
const session = new OrmSession({ orm: this, executor });
|
|
7718
8630
|
try {
|
|
7719
|
-
|
|
7720
|
-
await session.commit();
|
|
7721
|
-
return result;
|
|
8631
|
+
return await session.transaction(() => fn4(session));
|
|
7722
8632
|
} catch (err) {
|
|
7723
|
-
await session.rollback();
|
|
7724
8633
|
throw err;
|
|
7725
8634
|
} finally {
|
|
8635
|
+
await session.dispose();
|
|
7726
8636
|
}
|
|
7727
8637
|
}
|
|
8638
|
+
/**
|
|
8639
|
+
* Shuts down the ORM and releases underlying resources (pools, timers).
|
|
8640
|
+
*/
|
|
8641
|
+
async dispose() {
|
|
8642
|
+
await this.executorFactory.dispose();
|
|
8643
|
+
}
|
|
7728
8644
|
};
|
|
7729
8645
|
|
|
7730
8646
|
// src/decorators/decorator-metadata.ts
|
|
@@ -7983,18 +8899,245 @@ function rowsToQueryResult(rows) {
|
|
|
7983
8899
|
return { columns, values };
|
|
7984
8900
|
}
|
|
7985
8901
|
function createExecutorFromQueryRunner(runner) {
|
|
8902
|
+
const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
|
|
7986
8903
|
return {
|
|
8904
|
+
capabilities: {
|
|
8905
|
+
transactions: supportsTransactions
|
|
8906
|
+
},
|
|
7987
8907
|
async executeSql(sql, params) {
|
|
7988
8908
|
const rows = await runner.query(sql, params);
|
|
7989
8909
|
const result = rowsToQueryResult(rows);
|
|
7990
8910
|
return [result];
|
|
7991
8911
|
},
|
|
7992
|
-
|
|
7993
|
-
|
|
7994
|
-
|
|
8912
|
+
async beginTransaction() {
|
|
8913
|
+
if (!supportsTransactions) {
|
|
8914
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8915
|
+
}
|
|
8916
|
+
await runner.beginTransaction.call(runner);
|
|
8917
|
+
},
|
|
8918
|
+
async commitTransaction() {
|
|
8919
|
+
if (!supportsTransactions) {
|
|
8920
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8921
|
+
}
|
|
8922
|
+
await runner.commitTransaction.call(runner);
|
|
8923
|
+
},
|
|
8924
|
+
async rollbackTransaction() {
|
|
8925
|
+
if (!supportsTransactions) {
|
|
8926
|
+
throw new Error("Transactions are not supported by this executor");
|
|
8927
|
+
}
|
|
8928
|
+
await runner.rollbackTransaction.call(runner);
|
|
8929
|
+
},
|
|
8930
|
+
async dispose() {
|
|
8931
|
+
await runner.dispose?.call(runner);
|
|
8932
|
+
}
|
|
7995
8933
|
};
|
|
7996
8934
|
}
|
|
7997
8935
|
|
|
8936
|
+
// src/core/execution/pooling/pool.ts
|
|
8937
|
+
var deferred = () => {
|
|
8938
|
+
let resolve;
|
|
8939
|
+
let reject;
|
|
8940
|
+
const promise = new Promise((res, rej) => {
|
|
8941
|
+
resolve = res;
|
|
8942
|
+
reject = rej;
|
|
8943
|
+
});
|
|
8944
|
+
return { promise, resolve, reject };
|
|
8945
|
+
};
|
|
8946
|
+
var Pool = class {
|
|
8947
|
+
constructor(adapter, options) {
|
|
8948
|
+
this.destroyed = false;
|
|
8949
|
+
this.creating = 0;
|
|
8950
|
+
this.leased = 0;
|
|
8951
|
+
this.idle = [];
|
|
8952
|
+
this.waiters = [];
|
|
8953
|
+
this.reapTimer = null;
|
|
8954
|
+
if (!Number.isFinite(options.max) || options.max <= 0) {
|
|
8955
|
+
throw new Error("Pool options.max must be a positive number");
|
|
8956
|
+
}
|
|
8957
|
+
this.adapter = adapter;
|
|
8958
|
+
this.options = { max: options.max, ...options };
|
|
8959
|
+
const idleTimeout = this.options.idleTimeoutMillis;
|
|
8960
|
+
if (idleTimeout && idleTimeout > 0) {
|
|
8961
|
+
const interval = this.options.reapIntervalMillis ?? Math.max(1e3, Math.floor(idleTimeout / 2));
|
|
8962
|
+
this.reapTimer = setInterval(() => {
|
|
8963
|
+
void this.reapIdle();
|
|
8964
|
+
}, interval);
|
|
8965
|
+
this.reapTimer.unref?.();
|
|
8966
|
+
}
|
|
8967
|
+
const min2 = this.options.min ?? 0;
|
|
8968
|
+
if (min2 > 0) {
|
|
8969
|
+
void this.warm(min2);
|
|
8970
|
+
}
|
|
8971
|
+
}
|
|
8972
|
+
/**
|
|
8973
|
+
* Acquire a resource lease.
|
|
8974
|
+
* The returned lease MUST be released or destroyed.
|
|
8975
|
+
*/
|
|
8976
|
+
async acquire() {
|
|
8977
|
+
if (this.destroyed) {
|
|
8978
|
+
throw new Error("Pool is destroyed");
|
|
8979
|
+
}
|
|
8980
|
+
const idle = await this.takeIdleValidated();
|
|
8981
|
+
if (idle) {
|
|
8982
|
+
this.leased++;
|
|
8983
|
+
return this.makeLease(idle);
|
|
8984
|
+
}
|
|
8985
|
+
if (this.totalLive() < this.options.max) {
|
|
8986
|
+
this.creating++;
|
|
8987
|
+
try {
|
|
8988
|
+
const created = await this.adapter.create();
|
|
8989
|
+
this.leased++;
|
|
8990
|
+
return this.makeLease(created);
|
|
8991
|
+
} finally {
|
|
8992
|
+
this.creating--;
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
8995
|
+
const waiter = deferred();
|
|
8996
|
+
this.waiters.push(waiter);
|
|
8997
|
+
const timeout = this.options.acquireTimeoutMillis;
|
|
8998
|
+
let timer = null;
|
|
8999
|
+
if (timeout && timeout > 0) {
|
|
9000
|
+
timer = setTimeout(() => {
|
|
9001
|
+
const idx = this.waiters.indexOf(waiter);
|
|
9002
|
+
if (idx >= 0) this.waiters.splice(idx, 1);
|
|
9003
|
+
waiter.reject(new Error("Pool acquire timeout"));
|
|
9004
|
+
}, timeout);
|
|
9005
|
+
timer.unref?.();
|
|
9006
|
+
}
|
|
9007
|
+
try {
|
|
9008
|
+
return await waiter.promise;
|
|
9009
|
+
} finally {
|
|
9010
|
+
if (timer) clearTimeout(timer);
|
|
9011
|
+
}
|
|
9012
|
+
}
|
|
9013
|
+
/** Destroy pool and all idle resources; waits for in-flight creations to settle. */
|
|
9014
|
+
async destroy() {
|
|
9015
|
+
if (this.destroyed) return;
|
|
9016
|
+
this.destroyed = true;
|
|
9017
|
+
if (this.reapTimer) {
|
|
9018
|
+
clearInterval(this.reapTimer);
|
|
9019
|
+
this.reapTimer = null;
|
|
9020
|
+
}
|
|
9021
|
+
while (this.waiters.length) {
|
|
9022
|
+
this.waiters.shift().reject(new Error("Pool destroyed"));
|
|
9023
|
+
}
|
|
9024
|
+
while (this.idle.length) {
|
|
9025
|
+
const entry = this.idle.shift();
|
|
9026
|
+
await this.adapter.destroy(entry.resource);
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
totalLive() {
|
|
9030
|
+
return this.idle.length + this.leased + this.creating;
|
|
9031
|
+
}
|
|
9032
|
+
makeLease(resource) {
|
|
9033
|
+
let done = false;
|
|
9034
|
+
return {
|
|
9035
|
+
resource,
|
|
9036
|
+
release: async () => {
|
|
9037
|
+
if (done) return;
|
|
9038
|
+
done = true;
|
|
9039
|
+
await this.releaseResource(resource);
|
|
9040
|
+
},
|
|
9041
|
+
destroy: async () => {
|
|
9042
|
+
if (done) return;
|
|
9043
|
+
done = true;
|
|
9044
|
+
await this.destroyResource(resource);
|
|
9045
|
+
}
|
|
9046
|
+
};
|
|
9047
|
+
}
|
|
9048
|
+
async releaseResource(resource) {
|
|
9049
|
+
this.leased = Math.max(0, this.leased - 1);
|
|
9050
|
+
if (this.destroyed) {
|
|
9051
|
+
await this.adapter.destroy(resource);
|
|
9052
|
+
return;
|
|
9053
|
+
}
|
|
9054
|
+
const next = this.waiters.shift();
|
|
9055
|
+
if (next) {
|
|
9056
|
+
this.leased++;
|
|
9057
|
+
next.resolve(this.makeLease(resource));
|
|
9058
|
+
return;
|
|
9059
|
+
}
|
|
9060
|
+
this.idle.push({ resource, lastUsedAt: Date.now() });
|
|
9061
|
+
await this.trimToMinMax();
|
|
9062
|
+
}
|
|
9063
|
+
async destroyResource(resource) {
|
|
9064
|
+
this.leased = Math.max(0, this.leased - 1);
|
|
9065
|
+
await this.adapter.destroy(resource);
|
|
9066
|
+
if (!this.destroyed && this.waiters.length && this.totalLive() < this.options.max) {
|
|
9067
|
+
const waiter = this.waiters.shift();
|
|
9068
|
+
this.creating++;
|
|
9069
|
+
try {
|
|
9070
|
+
const created = await this.adapter.create();
|
|
9071
|
+
this.leased++;
|
|
9072
|
+
waiter.resolve(this.makeLease(created));
|
|
9073
|
+
} catch (err) {
|
|
9074
|
+
waiter.reject(err);
|
|
9075
|
+
} finally {
|
|
9076
|
+
this.creating--;
|
|
9077
|
+
}
|
|
9078
|
+
}
|
|
9079
|
+
}
|
|
9080
|
+
async takeIdleValidated() {
|
|
9081
|
+
while (this.idle.length) {
|
|
9082
|
+
const entry = this.idle.pop();
|
|
9083
|
+
if (!this.adapter.validate) {
|
|
9084
|
+
return entry.resource;
|
|
9085
|
+
}
|
|
9086
|
+
const ok = await this.adapter.validate(entry.resource);
|
|
9087
|
+
if (ok) {
|
|
9088
|
+
return entry.resource;
|
|
9089
|
+
}
|
|
9090
|
+
await this.adapter.destroy(entry.resource);
|
|
9091
|
+
}
|
|
9092
|
+
return null;
|
|
9093
|
+
}
|
|
9094
|
+
async reapIdle() {
|
|
9095
|
+
if (this.destroyed) return;
|
|
9096
|
+
const idleTimeout = this.options.idleTimeoutMillis;
|
|
9097
|
+
if (!idleTimeout || idleTimeout <= 0) return;
|
|
9098
|
+
const now2 = Date.now();
|
|
9099
|
+
const min2 = this.options.min ?? 0;
|
|
9100
|
+
const keep = [];
|
|
9101
|
+
const kill = [];
|
|
9102
|
+
for (const entry of this.idle) {
|
|
9103
|
+
const expired = now2 - entry.lastUsedAt >= idleTimeout;
|
|
9104
|
+
if (expired) kill.push(entry);
|
|
9105
|
+
else keep.push(entry);
|
|
9106
|
+
}
|
|
9107
|
+
while (keep.length < min2 && kill.length) {
|
|
9108
|
+
keep.push(kill.pop());
|
|
9109
|
+
}
|
|
9110
|
+
this.idle.length = 0;
|
|
9111
|
+
this.idle.push(...keep);
|
|
9112
|
+
for (const entry of kill) {
|
|
9113
|
+
await this.adapter.destroy(entry.resource);
|
|
9114
|
+
}
|
|
9115
|
+
}
|
|
9116
|
+
async warm(targetMin) {
|
|
9117
|
+
const min2 = Math.max(0, targetMin);
|
|
9118
|
+
while (!this.destroyed && this.idle.length < min2 && this.totalLive() < this.options.max) {
|
|
9119
|
+
this.creating++;
|
|
9120
|
+
try {
|
|
9121
|
+
const created = await this.adapter.create();
|
|
9122
|
+
this.idle.push({ resource: created, lastUsedAt: Date.now() });
|
|
9123
|
+
} catch {
|
|
9124
|
+
break;
|
|
9125
|
+
} finally {
|
|
9126
|
+
this.creating--;
|
|
9127
|
+
}
|
|
9128
|
+
}
|
|
9129
|
+
}
|
|
9130
|
+
async trimToMinMax() {
|
|
9131
|
+
const max2 = this.options.max;
|
|
9132
|
+
const min2 = this.options.min ?? 0;
|
|
9133
|
+
while (this.totalLive() > max2 && this.idle.length > min2) {
|
|
9134
|
+
const entry = this.idle.shift();
|
|
9135
|
+
if (!entry) break;
|
|
9136
|
+
await this.adapter.destroy(entry.resource);
|
|
9137
|
+
}
|
|
9138
|
+
}
|
|
9139
|
+
};
|
|
9140
|
+
|
|
7998
9141
|
// src/core/execution/executors/postgres-executor.ts
|
|
7999
9142
|
function createPostgresExecutor(client) {
|
|
8000
9143
|
return createExecutorFromQueryRunner({
|
|
@@ -8016,7 +9159,11 @@ function createPostgresExecutor(client) {
|
|
|
8016
9159
|
|
|
8017
9160
|
// src/core/execution/executors/mysql-executor.ts
|
|
8018
9161
|
function createMysqlExecutor(client) {
|
|
9162
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
8019
9163
|
return {
|
|
9164
|
+
capabilities: {
|
|
9165
|
+
transactions: supportsTransactions
|
|
9166
|
+
},
|
|
8020
9167
|
async executeSql(sql, params) {
|
|
8021
9168
|
const [rows] = await client.query(sql, params);
|
|
8022
9169
|
if (!Array.isArray(rows)) {
|
|
@@ -8028,53 +9175,94 @@ function createMysqlExecutor(client) {
|
|
|
8028
9175
|
return [result];
|
|
8029
9176
|
},
|
|
8030
9177
|
async beginTransaction() {
|
|
8031
|
-
if (!
|
|
9178
|
+
if (!supportsTransactions) {
|
|
9179
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9180
|
+
}
|
|
8032
9181
|
await client.beginTransaction();
|
|
8033
9182
|
},
|
|
8034
9183
|
async commitTransaction() {
|
|
8035
|
-
if (!
|
|
9184
|
+
if (!supportsTransactions) {
|
|
9185
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9186
|
+
}
|
|
8036
9187
|
await client.commit();
|
|
8037
9188
|
},
|
|
8038
9189
|
async rollbackTransaction() {
|
|
8039
|
-
if (!
|
|
9190
|
+
if (!supportsTransactions) {
|
|
9191
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9192
|
+
}
|
|
8040
9193
|
await client.rollback();
|
|
9194
|
+
},
|
|
9195
|
+
async dispose() {
|
|
8041
9196
|
}
|
|
8042
9197
|
};
|
|
8043
9198
|
}
|
|
8044
9199
|
|
|
8045
9200
|
// src/core/execution/executors/sqlite-executor.ts
|
|
8046
9201
|
function createSqliteExecutor(client) {
|
|
9202
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commitTransaction === "function" && typeof client.rollbackTransaction === "function";
|
|
8047
9203
|
return {
|
|
9204
|
+
capabilities: {
|
|
9205
|
+
transactions: supportsTransactions
|
|
9206
|
+
},
|
|
8048
9207
|
async executeSql(sql, params) {
|
|
8049
9208
|
const rows = await client.all(sql, params);
|
|
8050
9209
|
const result = rowsToQueryResult(rows);
|
|
8051
9210
|
return [result];
|
|
8052
9211
|
},
|
|
8053
|
-
|
|
8054
|
-
|
|
8055
|
-
|
|
9212
|
+
async beginTransaction() {
|
|
9213
|
+
if (!supportsTransactions) {
|
|
9214
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9215
|
+
}
|
|
9216
|
+
await client.beginTransaction();
|
|
9217
|
+
},
|
|
9218
|
+
async commitTransaction() {
|
|
9219
|
+
if (!supportsTransactions) {
|
|
9220
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9221
|
+
}
|
|
9222
|
+
await client.commitTransaction();
|
|
9223
|
+
},
|
|
9224
|
+
async rollbackTransaction() {
|
|
9225
|
+
if (!supportsTransactions) {
|
|
9226
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9227
|
+
}
|
|
9228
|
+
await client.rollbackTransaction();
|
|
9229
|
+
},
|
|
9230
|
+
async dispose() {
|
|
9231
|
+
}
|
|
8056
9232
|
};
|
|
8057
9233
|
}
|
|
8058
9234
|
|
|
8059
9235
|
// src/core/execution/executors/mssql-executor.ts
|
|
8060
9236
|
function createMssqlExecutor(client) {
|
|
9237
|
+
const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
|
|
8061
9238
|
return {
|
|
9239
|
+
capabilities: {
|
|
9240
|
+
transactions: supportsTransactions
|
|
9241
|
+
},
|
|
8062
9242
|
async executeSql(sql, params) {
|
|
8063
9243
|
const { recordset } = await client.query(sql, params);
|
|
8064
9244
|
const result = rowsToQueryResult(recordset ?? []);
|
|
8065
9245
|
return [result];
|
|
8066
9246
|
},
|
|
8067
9247
|
async beginTransaction() {
|
|
8068
|
-
if (!
|
|
9248
|
+
if (!supportsTransactions) {
|
|
9249
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9250
|
+
}
|
|
8069
9251
|
await client.beginTransaction();
|
|
8070
9252
|
},
|
|
8071
9253
|
async commitTransaction() {
|
|
8072
|
-
if (!
|
|
9254
|
+
if (!supportsTransactions) {
|
|
9255
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9256
|
+
}
|
|
8073
9257
|
await client.commit();
|
|
8074
9258
|
},
|
|
8075
9259
|
async rollbackTransaction() {
|
|
8076
|
-
if (!
|
|
9260
|
+
if (!supportsTransactions) {
|
|
9261
|
+
throw new Error("Transactions are not supported by this executor");
|
|
9262
|
+
}
|
|
8077
9263
|
await client.rollback();
|
|
9264
|
+
},
|
|
9265
|
+
async dispose() {
|
|
8078
9266
|
}
|
|
8079
9267
|
};
|
|
8080
9268
|
}
|
|
@@ -8143,6 +9331,86 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8143
9331
|
const client = createTediousMssqlClient(connection, module2, options);
|
|
8144
9332
|
return createMssqlExecutor(client);
|
|
8145
9333
|
}
|
|
9334
|
+
|
|
9335
|
+
// src/orm/pooled-executor-factory.ts
|
|
9336
|
+
function createPooledExecutorFactory(opts) {
|
|
9337
|
+
const { pool, adapter } = opts;
|
|
9338
|
+
const makeExecutor = (mode) => {
|
|
9339
|
+
let lease = null;
|
|
9340
|
+
const getLease = async () => {
|
|
9341
|
+
if (lease) return lease;
|
|
9342
|
+
lease = await pool.acquire();
|
|
9343
|
+
return lease;
|
|
9344
|
+
};
|
|
9345
|
+
const executeWithConn = async (conn, sql, params) => {
|
|
9346
|
+
const rows = await adapter.query(conn, sql, params);
|
|
9347
|
+
return [rowsToQueryResult(rows)];
|
|
9348
|
+
};
|
|
9349
|
+
return {
|
|
9350
|
+
capabilities: { transactions: true },
|
|
9351
|
+
async executeSql(sql, params) {
|
|
9352
|
+
if (mode === "sticky") {
|
|
9353
|
+
const l2 = await getLease();
|
|
9354
|
+
return executeWithConn(l2.resource, sql, params);
|
|
9355
|
+
}
|
|
9356
|
+
if (lease) {
|
|
9357
|
+
return executeWithConn(lease.resource, sql, params);
|
|
9358
|
+
}
|
|
9359
|
+
const l = await pool.acquire();
|
|
9360
|
+
try {
|
|
9361
|
+
return await executeWithConn(l.resource, sql, params);
|
|
9362
|
+
} finally {
|
|
9363
|
+
await l.release();
|
|
9364
|
+
}
|
|
9365
|
+
},
|
|
9366
|
+
async beginTransaction() {
|
|
9367
|
+
const l = await getLease();
|
|
9368
|
+
await adapter.beginTransaction(l.resource);
|
|
9369
|
+
},
|
|
9370
|
+
async commitTransaction() {
|
|
9371
|
+
if (!lease) {
|
|
9372
|
+
throw new Error("commitTransaction called without an active transaction");
|
|
9373
|
+
}
|
|
9374
|
+
const l = lease;
|
|
9375
|
+
try {
|
|
9376
|
+
await adapter.commitTransaction(l.resource);
|
|
9377
|
+
} finally {
|
|
9378
|
+
lease = null;
|
|
9379
|
+
await l.release();
|
|
9380
|
+
}
|
|
9381
|
+
},
|
|
9382
|
+
async rollbackTransaction() {
|
|
9383
|
+
if (!lease) {
|
|
9384
|
+
return;
|
|
9385
|
+
}
|
|
9386
|
+
const l = lease;
|
|
9387
|
+
try {
|
|
9388
|
+
await adapter.rollbackTransaction(l.resource);
|
|
9389
|
+
} finally {
|
|
9390
|
+
lease = null;
|
|
9391
|
+
await l.release();
|
|
9392
|
+
}
|
|
9393
|
+
},
|
|
9394
|
+
async dispose() {
|
|
9395
|
+
if (!lease) return;
|
|
9396
|
+
const l = lease;
|
|
9397
|
+
lease = null;
|
|
9398
|
+
await l.release();
|
|
9399
|
+
}
|
|
9400
|
+
};
|
|
9401
|
+
};
|
|
9402
|
+
return {
|
|
9403
|
+
createExecutor() {
|
|
9404
|
+
return makeExecutor("session");
|
|
9405
|
+
},
|
|
9406
|
+
createTransactionalExecutor() {
|
|
9407
|
+
return makeExecutor("sticky");
|
|
9408
|
+
},
|
|
9409
|
+
async dispose() {
|
|
9410
|
+
await pool.destroy();
|
|
9411
|
+
}
|
|
9412
|
+
};
|
|
9413
|
+
}
|
|
8146
9414
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8147
9415
|
0 && (module.exports = {
|
|
8148
9416
|
AsyncLocalStorage,
|
|
@@ -8162,6 +9430,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8162
9430
|
MySqlDialect,
|
|
8163
9431
|
Orm,
|
|
8164
9432
|
OrmSession,
|
|
9433
|
+
Pool,
|
|
8165
9434
|
PostgresDialect,
|
|
8166
9435
|
PrimaryKey,
|
|
8167
9436
|
RelationKinds,
|
|
@@ -8172,7 +9441,9 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8172
9441
|
UpdateQueryBuilder,
|
|
8173
9442
|
abs,
|
|
8174
9443
|
acos,
|
|
9444
|
+
add,
|
|
8175
9445
|
addDomainEvent,
|
|
9446
|
+
aliasRef,
|
|
8176
9447
|
and,
|
|
8177
9448
|
ascii,
|
|
8178
9449
|
asin,
|
|
@@ -8205,6 +9476,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8205
9476
|
createLiteral,
|
|
8206
9477
|
createMssqlExecutor,
|
|
8207
9478
|
createMysqlExecutor,
|
|
9479
|
+
createPooledExecutorFactory,
|
|
8208
9480
|
createPostgresExecutor,
|
|
8209
9481
|
createQueryLoggingExecutor,
|
|
8210
9482
|
createSqliteExecutor,
|
|
@@ -8223,6 +9495,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8223
9495
|
degrees,
|
|
8224
9496
|
denseRank,
|
|
8225
9497
|
diffSchema,
|
|
9498
|
+
div,
|
|
8226
9499
|
endOfMonth,
|
|
8227
9500
|
eq,
|
|
8228
9501
|
esel,
|
|
@@ -8245,6 +9518,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8245
9518
|
hasOne,
|
|
8246
9519
|
hydrateRows,
|
|
8247
9520
|
inList,
|
|
9521
|
+
inSubquery,
|
|
8248
9522
|
instr,
|
|
8249
9523
|
introspectSchema,
|
|
8250
9524
|
isCaseExpressionNode,
|
|
@@ -8280,10 +9554,12 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8280
9554
|
min,
|
|
8281
9555
|
mod,
|
|
8282
9556
|
month,
|
|
9557
|
+
mul,
|
|
8283
9558
|
neq,
|
|
8284
9559
|
notBetween,
|
|
8285
9560
|
notExists,
|
|
8286
9561
|
notInList,
|
|
9562
|
+
notInSubquery,
|
|
8287
9563
|
notLike,
|
|
8288
9564
|
now,
|
|
8289
9565
|
ntile,
|
|
@@ -8315,6 +9591,7 @@ function createTediousExecutor(connection, module2, options) {
|
|
|
8315
9591
|
sin,
|
|
8316
9592
|
space,
|
|
8317
9593
|
sqrt,
|
|
9594
|
+
sub,
|
|
8318
9595
|
substr,
|
|
8319
9596
|
sum,
|
|
8320
9597
|
synchronizeSchema,
|