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.
Files changed (52) hide show
  1. package/dist/index.cjs +1466 -189
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +723 -51
  4. package/dist/index.d.ts +723 -51
  5. package/dist/index.js +1457 -189
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/codegen/typescript.ts +66 -5
  9. package/src/core/ast/aggregate-functions.ts +15 -15
  10. package/src/core/ast/expression-builders.ts +378 -316
  11. package/src/core/ast/expression-nodes.ts +210 -186
  12. package/src/core/ast/expression-visitor.ts +40 -30
  13. package/src/core/ast/query.ts +164 -132
  14. package/src/core/ast/window-functions.ts +86 -86
  15. package/src/core/dialect/abstract.ts +509 -479
  16. package/src/core/dialect/base/groupby-compiler.ts +6 -6
  17. package/src/core/dialect/base/join-compiler.ts +9 -12
  18. package/src/core/dialect/base/orderby-compiler.ts +20 -6
  19. package/src/core/dialect/base/sql-dialect.ts +237 -138
  20. package/src/core/dialect/mssql/index.ts +164 -185
  21. package/src/core/dialect/sqlite/index.ts +39 -34
  22. package/src/core/execution/db-executor.ts +46 -6
  23. package/src/core/execution/executors/mssql-executor.ts +39 -22
  24. package/src/core/execution/executors/mysql-executor.ts +23 -6
  25. package/src/core/execution/executors/sqlite-executor.ts +29 -3
  26. package/src/core/execution/pooling/pool-types.ts +30 -0
  27. package/src/core/execution/pooling/pool.ts +268 -0
  28. package/src/core/functions/standard-strategy.ts +46 -37
  29. package/src/decorators/bootstrap.ts +7 -7
  30. package/src/index.ts +6 -0
  31. package/src/orm/domain-event-bus.ts +49 -0
  32. package/src/orm/entity-metadata.ts +9 -9
  33. package/src/orm/entity.ts +58 -0
  34. package/src/orm/orm-session.ts +465 -270
  35. package/src/orm/orm.ts +61 -11
  36. package/src/orm/pooled-executor-factory.ts +131 -0
  37. package/src/orm/query-logger.ts +6 -12
  38. package/src/orm/relation-change-processor.ts +75 -0
  39. package/src/orm/relations/many-to-many.ts +4 -2
  40. package/src/orm/save-graph.ts +303 -0
  41. package/src/orm/transaction-runner.ts +3 -3
  42. package/src/orm/unit-of-work.ts +128 -0
  43. package/src/query-builder/delete-query-state.ts +67 -38
  44. package/src/query-builder/delete.ts +37 -1
  45. package/src/query-builder/hydration-manager.ts +93 -79
  46. package/src/query-builder/insert-query-state.ts +131 -61
  47. package/src/query-builder/insert.ts +27 -1
  48. package/src/query-builder/query-ast-service.ts +207 -170
  49. package/src/query-builder/select-query-state.ts +169 -162
  50. package/src/query-builder/select.ts +15 -23
  51. package/src/query-builder/update-query-state.ts +114 -77
  52. package/src/query-builder/update.ts +38 -1
package/dist/index.js CHANGED
@@ -245,6 +245,7 @@ var belongsToMany = (target, pivotTable, options) => ({
245
245
 
246
246
  // src/core/ast/expression-nodes.ts
247
247
  var operandTypes = /* @__PURE__ */ new Set([
248
+ "AliasRef",
248
249
  "Column",
249
250
  "Literal",
250
251
  "Function",
@@ -286,11 +287,21 @@ var toOperand = (val) => {
286
287
  }
287
288
  return toNode(val);
288
289
  };
290
+ var hasQueryAst = (value) => typeof value.getAST === "function";
291
+ var resolveSelectQueryNode = (query) => hasQueryAst(query) ? query.getAST() : query;
292
+ var toScalarSubqueryNode = (query) => ({
293
+ type: "ScalarSubquery",
294
+ query: resolveSelectQueryNode(query)
295
+ });
289
296
  var columnOperand = (col2) => toNode(col2);
290
297
  var outerRef = (col2) => ({
291
298
  ...columnOperand(col2),
292
299
  scope: "outer"
293
300
  });
301
+ var aliasRef = (name) => ({
302
+ type: "AliasRef",
303
+ name
304
+ });
294
305
  var correlateBy = (table, column) => outerRef({ name: column, table });
295
306
  var createBinaryExpression = (operator, left2, right2, escape) => {
296
307
  const node = {
@@ -332,14 +343,16 @@ var isNotNull = (left2) => ({
332
343
  left: toNode(left2),
333
344
  operator: "IS NOT NULL"
334
345
  });
335
- var createInExpression = (operator, left2, values) => ({
346
+ var createInExpression = (operator, left2, right2) => ({
336
347
  type: "InExpression",
337
348
  left: toNode(left2),
338
349
  operator,
339
- right: values.map((v) => toOperand(v))
350
+ right: right2
340
351
  });
341
- var inList = (left2, values) => createInExpression("IN", left2, values);
342
- var notInList = (left2, values) => createInExpression("NOT IN", left2, values);
352
+ var inList = (left2, values) => createInExpression("IN", left2, values.map((v) => toOperand(v)));
353
+ var notInList = (left2, values) => createInExpression("NOT IN", left2, values.map((v) => toOperand(v)));
354
+ var inSubquery = (left2, subquery) => createInExpression("IN", left2, toScalarSubqueryNode(subquery));
355
+ var notInSubquery = (left2, subquery) => createInExpression("NOT IN", left2, toScalarSubqueryNode(subquery));
343
356
  var createBetweenExpression = (operator, left2, lower2, upper2) => ({
344
357
  type: "BetweenExpression",
345
358
  left: toNode(left2),
@@ -349,6 +362,16 @@ var createBetweenExpression = (operator, left2, lower2, upper2) => ({
349
362
  });
350
363
  var between = (left2, lower2, upper2) => createBetweenExpression("BETWEEN", left2, lower2, upper2);
351
364
  var notBetween = (left2, lower2, upper2) => createBetweenExpression("NOT BETWEEN", left2, lower2, upper2);
365
+ var createArithmeticExpression = (operator, left2, right2) => ({
366
+ type: "ArithmeticExpression",
367
+ left: toOperand(left2),
368
+ operator,
369
+ right: toOperand(right2)
370
+ });
371
+ var add = (left2, right2) => createArithmeticExpression("+", left2, right2);
372
+ var sub = (left2, right2) => createArithmeticExpression("-", left2, right2);
373
+ var mul = (left2, right2) => createArithmeticExpression("*", left2, right2);
374
+ var div = (left2, right2) => createArithmeticExpression("/", left2, right2);
352
375
  var jsonPath = (col2, path) => ({
353
376
  type: "JsonPath",
354
377
  column: columnOperand(col2),
@@ -427,7 +450,7 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
427
450
  const partitionNodes = partitionBy?.map((col2) => columnOperand(col2)) ?? void 0;
428
451
  const orderNodes = orderBy?.map((o) => ({
429
452
  type: "OrderBy",
430
- column: columnOperand(o.column),
453
+ term: columnOperand(o.column),
431
454
  direction: o.direction
432
455
  }));
433
456
  return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
@@ -502,7 +525,7 @@ var min = buildAggregate("MIN");
502
525
  var max = buildAggregate("MAX");
503
526
  var toOrderByNode = (order) => ({
504
527
  type: "OrderBy",
505
- column: columnOperand(order.column),
528
+ term: columnOperand(order.column),
506
529
  direction: order.direction ?? ORDER_DIRECTIONS.ASC
507
530
  });
508
531
  var groupConcat = (col2, options) => ({
@@ -552,6 +575,9 @@ var visitExpression = (node, visitor) => {
552
575
  case "BetweenExpression":
553
576
  if (visitor.visitBetweenExpression) return visitor.visitBetweenExpression(node);
554
577
  break;
578
+ case "ArithmeticExpression":
579
+ if (visitor.visitArithmeticExpression) return visitor.visitArithmeticExpression(node);
580
+ break;
555
581
  default:
556
582
  break;
557
583
  }
@@ -583,6 +609,9 @@ var visitOperand = (node, visitor) => {
583
609
  case "WindowFunction":
584
610
  if (visitor.visitWindowFunction) return visitor.visitWindowFunction(node);
585
611
  break;
612
+ case "AliasRef":
613
+ if (visitor.visitAliasRef) return visitor.visitAliasRef(node);
614
+ break;
586
615
  default:
587
616
  break;
588
617
  }
@@ -699,7 +728,14 @@ var StandardFunctionStrategy = class _StandardFunctionStrategy {
699
728
  if (!orderBy || orderBy.length === 0) {
700
729
  return "";
701
730
  }
702
- const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
731
+ const parts = orderBy.map((order) => {
732
+ const term = isOperandNode(order.term) ? ctx.compileOperand(order.term) : (() => {
733
+ throw new Error("ORDER BY expressions inside functions must be operands");
734
+ })();
735
+ const collation = order.collation ? ` COLLATE ${order.collation}` : "";
736
+ const nulls = order.nulls ? ` NULLS ${order.nulls}` : "";
737
+ return `${term} ${order.direction}${collation}${nulls}`;
738
+ });
703
739
  return `ORDER BY ${parts.join(", ")}`;
704
740
  }
705
741
  formatGroupConcatSeparator(ctx) {
@@ -964,6 +1000,16 @@ var Dialect = class _Dialect {
964
1000
  }
965
1001
  return compiler(node, ctx);
966
1002
  }
1003
+ /**
1004
+ * Compiles an ordering term (operand, expression, or alias reference).
1005
+ */
1006
+ compileOrderingTerm(term, ctx) {
1007
+ if (isOperandNode(term)) {
1008
+ return this.compileOperand(term, ctx);
1009
+ }
1010
+ const expr = this.compileExpression(term, ctx);
1011
+ return `(${expr})`;
1012
+ }
967
1013
  registerDefaultExpressionCompilers() {
968
1014
  this.registerExpressionCompiler("BinaryExpression", (binary, ctx) => {
969
1015
  const left2 = this.compileOperand(binary.left, ctx);
@@ -989,8 +1035,12 @@ var Dialect = class _Dialect {
989
1035
  });
990
1036
  this.registerExpressionCompiler("InExpression", (inExpr, ctx) => {
991
1037
  const left2 = this.compileOperand(inExpr.left, ctx);
992
- const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
993
- return `${left2} ${inExpr.operator} (${values})`;
1038
+ if (Array.isArray(inExpr.right)) {
1039
+ const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
1040
+ return `${left2} ${inExpr.operator} (${values})`;
1041
+ }
1042
+ const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1043
+ return `${left2} ${inExpr.operator} (${subquerySql})`;
994
1044
  });
995
1045
  this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
996
1046
  const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
@@ -1002,9 +1052,15 @@ var Dialect = class _Dialect {
1002
1052
  const upper2 = this.compileOperand(betweenExpr.upper, ctx);
1003
1053
  return `${left2} ${betweenExpr.operator} ${lower2} AND ${upper2}`;
1004
1054
  });
1055
+ this.registerExpressionCompiler("ArithmeticExpression", (arith, ctx) => {
1056
+ const left2 = this.compileOperand(arith.left, ctx);
1057
+ const right2 = this.compileOperand(arith.right, ctx);
1058
+ return `${left2} ${arith.operator} ${right2}`;
1059
+ });
1005
1060
  }
1006
1061
  registerDefaultOperandCompilers() {
1007
1062
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1063
+ this.registerOperandCompiler("AliasRef", (alias, _ctx) => this.quoteIdentifier(alias.name));
1008
1064
  this.registerOperandCompiler("Column", (column, _ctx) => {
1009
1065
  return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
1010
1066
  });
@@ -1042,9 +1098,12 @@ var Dialect = class _Dialect {
1042
1098
  parts.push(partitionClause);
1043
1099
  }
1044
1100
  if (node.orderBy && node.orderBy.length > 0) {
1045
- const orderClause = "ORDER BY " + node.orderBy.map(
1046
- (o) => `${this.quoteIdentifier(o.column.table)}.${this.quoteIdentifier(o.column.name)} ${o.direction}`
1047
- ).join(", ");
1101
+ const orderClause = "ORDER BY " + node.orderBy.map((o) => {
1102
+ const term = this.compileOrderingTerm(o.term, ctx);
1103
+ const collation = o.collation ? ` COLLATE ${o.collation}` : "";
1104
+ const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
1105
+ return `${term} ${o.direction}${collation}${nulls}`;
1106
+ }).join(", ");
1048
1107
  parts.push(orderClause);
1049
1108
  }
1050
1109
  result += parts.join(" ");
@@ -1239,17 +1298,9 @@ var NoReturningStrategy = class {
1239
1298
 
1240
1299
  // src/core/dialect/base/join-compiler.ts
1241
1300
  var JoinCompiler = class {
1242
- /**
1243
- * Compiles all JOIN clauses from a SELECT query AST.
1244
- * @param ast - The SELECT query AST containing join definitions.
1245
- * @param ctx - The compiler context for expression compilation.
1246
- * @param compileFrom - Function to compile table sources (tables or subqueries).
1247
- * @param compileExpression - Function to compile join condition expressions.
1248
- * @returns SQL JOIN clauses (e.g., " LEFT JOIN table ON condition") or empty string if no joins.
1249
- */
1250
- static compileJoins(ast, ctx, compileFrom, compileExpression) {
1251
- if (!ast.joins || ast.joins.length === 0) return "";
1252
- const parts = ast.joins.map((j) => {
1301
+ static compileJoins(joins, ctx, compileFrom, compileExpression) {
1302
+ if (!joins || joins.length === 0) return "";
1303
+ const parts = joins.map((j) => {
1253
1304
  const table = compileFrom(j.table, ctx);
1254
1305
  const cond = compileExpression(j.condition, ctx);
1255
1306
  return `${j.kind} JOIN ${table} ON ${cond}`;
@@ -1263,12 +1314,12 @@ var GroupByCompiler = class {
1263
1314
  /**
1264
1315
  * Compiles GROUP BY clause from a SELECT query AST.
1265
1316
  * @param ast - The SELECT query AST containing grouping columns.
1266
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
1317
+ * @param renderTerm - Function to render a grouping term.
1267
1318
  * @returns SQL GROUP BY clause (e.g., " GROUP BY table.col1, table.col2") or empty string if no grouping.
1268
1319
  */
1269
- static compileGroupBy(ast, quoteIdentifier) {
1320
+ static compileGroupBy(ast, renderTerm) {
1270
1321
  if (!ast.groupBy || ast.groupBy.length === 0) return "";
1271
- const cols = ast.groupBy.map((c) => `${quoteIdentifier(c.table)}.${quoteIdentifier(c.name)}`).join(", ");
1322
+ const cols = ast.groupBy.map(renderTerm).join(", ");
1272
1323
  return ` GROUP BY ${cols}`;
1273
1324
  }
1274
1325
  };
@@ -1278,12 +1329,19 @@ var OrderByCompiler = class {
1278
1329
  /**
1279
1330
  * Compiles ORDER BY clause from a SELECT query AST.
1280
1331
  * @param ast - The SELECT query AST containing sort specifications.
1281
- * @param quoteIdentifier - Function to quote identifiers according to dialect rules.
1332
+ * @param renderTerm - Function to render an ordering term.
1333
+ * @param renderNulls - Optional function to render NULLS FIRST/LAST.
1334
+ * @param renderCollation - Optional function to render COLLATE clause.
1282
1335
  * @returns SQL ORDER BY clause (e.g., " ORDER BY table.col1 ASC, table.col2 DESC") or empty string if no ordering.
1283
1336
  */
1284
- static compileOrderBy(ast, quoteIdentifier) {
1337
+ static compileOrderBy(ast, renderTerm, renderNulls, renderCollation) {
1285
1338
  if (!ast.orderBy || ast.orderBy.length === 0) return "";
1286
- const parts = ast.orderBy.map((o) => `${quoteIdentifier(o.column.table)}.${quoteIdentifier(o.column.name)} ${o.direction}`).join(", ");
1339
+ const parts = ast.orderBy.map((o) => {
1340
+ const term = renderTerm(o.term);
1341
+ const collation = renderCollation ? renderCollation(o) : o.collation ? ` COLLATE ${o.collation}` : "";
1342
+ const nulls = renderNulls ? renderNulls(o) : o.nulls ? ` NULLS ${o.nulls}` : "";
1343
+ return `${term} ${o.direction}${collation}${nulls}`;
1344
+ }).join(", ");
1287
1345
  return ` ORDER BY ${parts}`;
1288
1346
  }
1289
1347
  };
@@ -1314,58 +1372,96 @@ var SqlDialectBase = class extends Dialect {
1314
1372
  }
1315
1373
  compileSelectWithSetOps(ast, baseSelect, ctes, ctx) {
1316
1374
  const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
1317
- const orderBy = OrderByCompiler.compileOrderBy(ast, this.quoteIdentifier.bind(this));
1375
+ const orderBy = OrderByCompiler.compileOrderBy(
1376
+ ast,
1377
+ (term) => this.compileOrderingTerm(term, ctx),
1378
+ this.renderOrderByNulls.bind(this),
1379
+ this.renderOrderByCollation.bind(this)
1380
+ );
1318
1381
  const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
1319
1382
  const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
1320
1383
  return `${ctes}${combined}${orderBy}${pagination}`;
1321
1384
  }
1322
1385
  compileInsertAst(ast, ctx) {
1386
+ if (!ast.columns.length) {
1387
+ throw new Error("INSERT queries must specify columns.");
1388
+ }
1323
1389
  const table = this.compileTableName(ast.into);
1324
1390
  const columnList = this.compileInsertColumnList(ast.columns);
1325
- const values = this.compileInsertValues(ast.values, ctx);
1391
+ const source = this.compileInsertSource(ast.source, ctx);
1326
1392
  const returning = this.compileReturning(ast.returning, ctx);
1327
- return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning}`;
1393
+ return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
1328
1394
  }
1329
1395
  compileReturning(returning, ctx) {
1330
1396
  return this.returningStrategy.compileReturning(returning, ctx);
1331
1397
  }
1398
+ compileInsertSource(source, ctx) {
1399
+ if (source.type === "InsertValues") {
1400
+ if (!source.rows.length) {
1401
+ throw new Error("INSERT ... VALUES requires at least one row.");
1402
+ }
1403
+ const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1404
+ return `VALUES ${values}`;
1405
+ }
1406
+ const normalized = this.normalizeSelectAst(source.query);
1407
+ return this.compileSelectAst(normalized, ctx).trim();
1408
+ }
1332
1409
  compileInsertColumnList(columns) {
1333
1410
  return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
1334
1411
  }
1335
- compileInsertValues(values, ctx) {
1336
- return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1337
- }
1338
1412
  compileSelectCore(ast, ctx) {
1339
1413
  const columns = this.compileSelectColumns(ast, ctx);
1340
1414
  const from = this.compileFrom(ast.from, ctx);
1341
- const joins = JoinCompiler.compileJoins(ast, ctx, this.compileFrom.bind(this), this.compileExpression.bind(this));
1415
+ const joins = JoinCompiler.compileJoins(
1416
+ ast.joins,
1417
+ ctx,
1418
+ this.compileFrom.bind(this),
1419
+ this.compileExpression.bind(this)
1420
+ );
1342
1421
  const whereClause = this.compileWhere(ast.where, ctx);
1343
- const groupBy = GroupByCompiler.compileGroupBy(ast, this.quoteIdentifier.bind(this));
1422
+ const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
1344
1423
  const having = this.compileHaving(ast, ctx);
1345
- const orderBy = OrderByCompiler.compileOrderBy(ast, this.quoteIdentifier.bind(this));
1424
+ const orderBy = OrderByCompiler.compileOrderBy(
1425
+ ast,
1426
+ (term) => this.compileOrderingTerm(term, ctx),
1427
+ this.renderOrderByNulls.bind(this),
1428
+ this.renderOrderByCollation.bind(this)
1429
+ );
1346
1430
  const pagination = this.paginationStrategy.compilePagination(ast.limit, ast.offset);
1347
1431
  return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
1348
1432
  }
1349
1433
  compileUpdateAst(ast, ctx) {
1350
- const table = this.compileTableName(ast.table);
1351
- const assignments = this.compileUpdateAssignments(ast.set, ctx);
1434
+ const target = this.compileTableReference(ast.table);
1435
+ const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
1436
+ const fromClause = this.compileUpdateFromClause(ast, ctx);
1352
1437
  const whereClause = this.compileWhere(ast.where, ctx);
1353
1438
  const returning = this.compileReturning(ast.returning, ctx);
1354
- return `UPDATE ${table} SET ${assignments}${whereClause}${returning}`;
1439
+ return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
1355
1440
  }
1356
- compileUpdateAssignments(assignments, ctx) {
1441
+ compileUpdateAssignments(assignments, table, ctx) {
1357
1442
  return assignments.map((assignment) => {
1358
1443
  const col2 = assignment.column;
1359
- const target = this.quoteIdentifier(col2.name);
1444
+ const target = this.compileQualifiedColumn(col2, table);
1360
1445
  const value = this.compileOperand(assignment.value, ctx);
1361
1446
  return `${target} = ${value}`;
1362
1447
  }).join(", ");
1363
1448
  }
1449
+ compileQualifiedColumn(column, table) {
1450
+ const baseTableName = table.name;
1451
+ const alias = table.alias;
1452
+ const columnTable = column.table ?? alias ?? baseTableName;
1453
+ const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
1454
+ if (!tableQualifier) {
1455
+ return this.quoteIdentifier(column.name);
1456
+ }
1457
+ return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
1458
+ }
1364
1459
  compileDeleteAst(ast, ctx) {
1365
- const table = this.compileTableName(ast.from);
1460
+ const target = this.compileTableReference(ast.from);
1461
+ const usingClause = this.compileDeleteUsingClause(ast, ctx);
1366
1462
  const whereClause = this.compileWhere(ast.where, ctx);
1367
1463
  const returning = this.compileReturning(ast.returning, ctx);
1368
- return `DELETE FROM ${table}${whereClause}${returning}`;
1464
+ return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
1369
1465
  }
1370
1466
  formatReturningColumns(returning) {
1371
1467
  return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
@@ -1420,6 +1516,38 @@ var SqlDialectBase = class extends Dialect {
1420
1516
  }
1421
1517
  return this.quoteIdentifier(table.name);
1422
1518
  }
1519
+ compileTableReference(table) {
1520
+ const base = this.compileTableName(table);
1521
+ return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
1522
+ }
1523
+ compileUpdateFromClause(ast, ctx) {
1524
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
1525
+ if (!ast.from) {
1526
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
1527
+ }
1528
+ const from = this.compileFrom(ast.from, ctx);
1529
+ const joins = JoinCompiler.compileJoins(
1530
+ ast.joins,
1531
+ ctx,
1532
+ this.compileFrom.bind(this),
1533
+ this.compileExpression.bind(this)
1534
+ );
1535
+ return ` FROM ${from}${joins}`;
1536
+ }
1537
+ compileDeleteUsingClause(ast, ctx) {
1538
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
1539
+ if (!ast.using) {
1540
+ throw new Error("DELETE with JOINs requires a USING clause.");
1541
+ }
1542
+ const usingTable = this.compileFrom(ast.using, ctx);
1543
+ const joins = JoinCompiler.compileJoins(
1544
+ ast.joins,
1545
+ ctx,
1546
+ this.compileFrom.bind(this),
1547
+ this.compileExpression.bind(this)
1548
+ );
1549
+ return ` USING ${usingTable}${joins}`;
1550
+ }
1423
1551
  compileHaving(ast, ctx) {
1424
1552
  if (!ast.having) return "";
1425
1553
  return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
@@ -1431,6 +1559,12 @@ var SqlDialectBase = class extends Dialect {
1431
1559
  const trimmed = this.stripTrailingSemicolon(sql);
1432
1560
  return `(${trimmed})`;
1433
1561
  }
1562
+ renderOrderByNulls(order) {
1563
+ return order.nulls ? ` NULLS ${order.nulls}` : "";
1564
+ }
1565
+ renderOrderByCollation(order) {
1566
+ return order.collation ? ` COLLATE ${order.collation}` : "";
1567
+ }
1434
1568
  };
1435
1569
 
1436
1570
  // src/core/dialect/postgres/functions.ts
@@ -1794,6 +1928,9 @@ var SqliteDialect = class extends SqlDialectBase {
1794
1928
  const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
1795
1929
  return `json_extract(${col2}, '${node.path}')`;
1796
1930
  }
1931
+ compileQualifiedColumn(column, _table) {
1932
+ return this.quoteIdentifier(column.name);
1933
+ }
1797
1934
  compileReturning(returning, ctx) {
1798
1935
  if (!returning || returning.length === 0) return "";
1799
1936
  const columns = this.formatReturningColumns(returning);
@@ -1899,7 +2036,7 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1899
2036
  };
1900
2037
 
1901
2038
  // src/core/dialect/mssql/index.ts
1902
- var SqlServerDialect = class extends Dialect {
2039
+ var SqlServerDialect = class extends SqlDialectBase {
1903
2040
  /**
1904
2041
  * Creates a new SqlServerDialect instance
1905
2042
  */
@@ -1942,43 +2079,37 @@ var SqlServerDialect = class extends Dialect {
1942
2079
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
1943
2080
  const ctes = this.compileCtes(ast, ctx);
1944
2081
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
1945
- const baseSelect = this.compileSelectCore(baseAst, ctx);
2082
+ const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
1946
2083
  if (!hasSetOps) {
1947
2084
  return `${ctes}${baseSelect}`;
1948
2085
  }
1949
2086
  const compound = ast.setOps.map((op) => `${op.operator} ${this.wrapSetOperand(this.compileSelectAst(op.query, ctx))}`).join(" ");
1950
- const orderBy = this.compileOrderBy(ast);
2087
+ const orderBy = this.compileOrderBy(ast, ctx);
1951
2088
  const pagination = this.compilePagination(ast, orderBy);
1952
2089
  const combined = `${this.wrapSetOperand(baseSelect)} ${compound}`;
1953
2090
  const tail = pagination || orderBy;
1954
2091
  return `${ctes}${combined}${tail}`;
1955
2092
  }
1956
- compileInsertAst(ast, ctx) {
1957
- const table = this.quoteIdentifier(ast.into.name);
1958
- const columnList = ast.columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
1959
- const values = ast.values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1960
- return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
1961
- }
1962
- compileUpdateAst(ast, ctx) {
1963
- const table = this.quoteIdentifier(ast.table.name);
1964
- const assignments = ast.set.map((assignment) => {
1965
- const col2 = assignment.column;
1966
- const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
1967
- const value = this.compileOperand(assignment.value, ctx);
1968
- return `${target} = ${value}`;
1969
- }).join(", ");
1970
- const whereClause = this.compileWhere(ast.where, ctx);
1971
- return `UPDATE ${table} SET ${assignments}${whereClause};`;
1972
- }
1973
2093
  compileDeleteAst(ast, ctx) {
2094
+ if (ast.using) {
2095
+ throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
2096
+ }
1974
2097
  if (ast.from.type !== "Table") {
1975
2098
  throw new Error("DELETE only supports base tables in the MSSQL dialect.");
1976
2099
  }
1977
- const table = this.quoteIdentifier(ast.from.name);
2100
+ const alias = ast.from.alias ?? ast.from.name;
2101
+ const target = this.compileTableReference(ast.from);
2102
+ const joins = JoinCompiler.compileJoins(
2103
+ ast.joins,
2104
+ ctx,
2105
+ this.compileFrom.bind(this),
2106
+ this.compileExpression.bind(this)
2107
+ );
1978
2108
  const whereClause = this.compileWhere(ast.where, ctx);
1979
- return `DELETE FROM ${table}${whereClause};`;
2109
+ const returning = this.compileReturning(ast.returning, ctx);
2110
+ return `DELETE ${this.quoteIdentifier(alias)} FROM ${target}${joins}${whereClause}${returning}`;
1980
2111
  }
1981
- compileSelectCore(ast, ctx) {
2112
+ compileSelectCoreForMssql(ast, ctx) {
1982
2113
  const columns = ast.columns.map((c) => {
1983
2114
  let expr = "";
1984
2115
  if (c.type === "Function") {
@@ -1997,25 +2128,29 @@ var SqlServerDialect = class extends Dialect {
1997
2128
  return expr;
1998
2129
  }).join(", ");
1999
2130
  const distinct = ast.distinct ? "DISTINCT " : "";
2000
- const from = this.compileTableSource(ast.from, ctx);
2131
+ const from = this.compileTableSource(ast.from);
2001
2132
  const joins = ast.joins.map((j) => {
2002
- const table = this.compileTableSource(j.table, ctx);
2133
+ const table = this.compileTableSource(j.table);
2003
2134
  const cond = this.compileExpression(j.condition, ctx);
2004
2135
  return `${j.kind} JOIN ${table} ON ${cond}`;
2005
2136
  }).join(" ");
2006
2137
  const whereClause = this.compileWhere(ast.where, ctx);
2007
- const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((c) => `${this.quoteIdentifier(c.table)}.${this.quoteIdentifier(c.name)}`).join(", ") : "";
2138
+ const groupBy = ast.groupBy && ast.groupBy.length > 0 ? " GROUP BY " + ast.groupBy.map((term) => this.compileOrderingTerm(term, ctx)).join(", ") : "";
2008
2139
  const having = ast.having ? ` HAVING ${this.compileExpression(ast.having, ctx)}` : "";
2009
- const orderBy = this.compileOrderBy(ast);
2140
+ const orderBy = this.compileOrderBy(ast, ctx);
2010
2141
  const pagination = this.compilePagination(ast, orderBy);
2011
2142
  if (pagination) {
2012
2143
  return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${pagination}`;
2013
2144
  }
2014
2145
  return `SELECT ${distinct}${columns} FROM ${from}${joins ? " " + joins : ""}${whereClause}${groupBy}${having}${orderBy}`;
2015
2146
  }
2016
- compileOrderBy(ast) {
2017
- if (!ast.orderBy || ast.orderBy.length === 0) return "";
2018
- return " ORDER BY " + ast.orderBy.map((o) => `${this.quoteIdentifier(o.column.table)}.${this.quoteIdentifier(o.column.name)} ${o.direction}`).join(", ");
2147
+ compileOrderBy(ast, ctx) {
2148
+ return OrderByCompiler.compileOrderBy(
2149
+ ast,
2150
+ (term) => this.compileOrderingTerm(term, ctx),
2151
+ this.renderOrderByNulls.bind(this),
2152
+ this.renderOrderByCollation.bind(this)
2153
+ );
2019
2154
  }
2020
2155
  compilePagination(ast, orderBy) {
2021
2156
  const hasLimit = ast.limit !== void 0;
@@ -2029,21 +2164,6 @@ var SqlServerDialect = class extends Dialect {
2029
2164
  }
2030
2165
  return pagination;
2031
2166
  }
2032
- compileTableSource(table, ctx) {
2033
- if (table.type === "FunctionTable") {
2034
- return FunctionTableFormatter.format(table, ctx, this);
2035
- }
2036
- if (table.type === "DerivedTable") {
2037
- return this.compileDerivedTable(table, ctx);
2038
- }
2039
- const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
2040
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2041
- }
2042
- compileDerivedTable(table, ctx) {
2043
- const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2044
- const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2045
- return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
2046
- }
2047
2167
  compileCtes(ast, ctx) {
2048
2168
  if (!ast.ctes || ast.ctes.length === 0) return "";
2049
2169
  const defs = ast.ctes.map((cte) => {
@@ -2054,10 +2174,6 @@ var SqlServerDialect = class extends Dialect {
2054
2174
  }).join(", ");
2055
2175
  return `WITH ${defs} `;
2056
2176
  }
2057
- wrapSetOperand(sql) {
2058
- const trimmed = sql.trim().replace(/;$/, "");
2059
- return `(${trimmed})`;
2060
- }
2061
2177
  };
2062
2178
 
2063
2179
  // src/core/dialect/dialect-factory.ts
@@ -2207,7 +2323,7 @@ var SelectQueryState = class _SelectQueryState {
2207
2323
  }
2208
2324
  /**
2209
2325
  * Adds GROUP BY columns to the query
2210
- * @param columns - Columns to group by
2326
+ * @param columns - Terms to group by
2211
2327
  * @returns New SelectQueryState with GROUP BY clause
2212
2328
  */
2213
2329
  withGroupBy(columns) {
@@ -2490,31 +2606,38 @@ var HydrationManager = class _HydrationManager {
2490
2606
  }
2491
2607
  const mapped = [];
2492
2608
  for (const ob of orderBy) {
2493
- if (ob.column.table !== plan.rootTable) {
2494
- return null;
2495
- }
2496
- const alias = projectionAliases.get(`${ob.column.table}.${ob.column.name}`) ?? ob.column.name;
2497
- if (!availableColumns.has(alias)) {
2498
- return null;
2499
- }
2500
- mapped.push({
2501
- type: "OrderBy",
2502
- column: { type: "Column", table: baseAlias, name: alias },
2503
- direction: ob.direction
2504
- });
2609
+ const mappedTerm = this.mapOrderingTerm(ob.term, plan, projectionAliases, baseAlias, availableColumns);
2610
+ if (!mappedTerm) return null;
2611
+ mapped.push({ ...ob, term: mappedTerm });
2505
2612
  }
2506
2613
  return mapped;
2507
2614
  }
2615
+ mapOrderingTerm(term, plan, projectionAliases, baseAlias, availableColumns) {
2616
+ if (term.type === "Column") {
2617
+ const col2 = term;
2618
+ if (col2.table !== plan.rootTable) return null;
2619
+ const alias = projectionAliases.get(`${col2.table}.${col2.name}`) ?? col2.name;
2620
+ if (!availableColumns.has(alias)) return null;
2621
+ return { type: "Column", table: baseAlias, name: alias };
2622
+ }
2623
+ if (term.type === "AliasRef") {
2624
+ const aliasName = term.name;
2625
+ if (!availableColumns.has(aliasName)) return null;
2626
+ return { type: "Column", table: baseAlias, name: aliasName };
2627
+ }
2628
+ return null;
2629
+ }
2508
2630
  buildPagingColumns(primaryKey, orderBy, tableAlias) {
2509
2631
  const columns = [{ type: "Column", table: tableAlias, name: primaryKey, alias: primaryKey }];
2510
2632
  if (!orderBy) return columns;
2511
2633
  for (const ob of orderBy) {
2512
- if (!columns.some((col2) => col2.name === ob.column.name)) {
2634
+ const term = ob.term;
2635
+ if (!columns.some((col2) => col2.name === term.name)) {
2513
2636
  columns.push({
2514
2637
  type: "Column",
2515
2638
  table: tableAlias,
2516
- name: ob.column.name,
2517
- alias: ob.column.name
2639
+ name: term.name,
2640
+ alias: term.name
2518
2641
  });
2519
2642
  }
2520
2643
  }
@@ -2820,10 +2943,8 @@ var QueryAstService = class {
2820
2943
  * @returns Updated query state with GROUP BY clause
2821
2944
  */
2822
2945
  withGroupBy(col2) {
2823
- const from = this.state.ast.from;
2824
- const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
2825
- const node = buildColumnNode(tableRef, col2);
2826
- return this.state.withGroupBy([node]);
2946
+ const term = this.normalizeOrderingTerm(col2);
2947
+ return this.state.withGroupBy([term]);
2827
2948
  }
2828
2949
  /**
2829
2950
  * Adds a HAVING clause to the query
@@ -2840,11 +2961,9 @@ var QueryAstService = class {
2840
2961
  * @param direction - Order direction (ASC/DESC)
2841
2962
  * @returns Updated query state with ORDER BY clause
2842
2963
  */
2843
- withOrderBy(col2, direction) {
2844
- const from = this.state.ast.from;
2845
- const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
2846
- const node = buildColumnNode(tableRef, col2);
2847
- return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
2964
+ withOrderBy(term, direction, nulls, collation) {
2965
+ const normalized = this.normalizeOrderingTerm(term);
2966
+ return this.state.withOrderBy([{ type: "OrderBy", term: normalized, direction, nulls, collation }]);
2848
2967
  }
2849
2968
  /**
2850
2969
  * Adds a DISTINCT clause to the query
@@ -2879,6 +2998,24 @@ var QueryAstService = class {
2879
2998
  combineExpressions(existing, next) {
2880
2999
  return existing ? and(existing, next) : next;
2881
3000
  }
3001
+ normalizeOrderingTerm(term) {
3002
+ const from = this.state.ast.from;
3003
+ const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3004
+ const termType = term?.type;
3005
+ if (termType === "Column") {
3006
+ return term;
3007
+ }
3008
+ if (termType === "AliasRef") {
3009
+ return term;
3010
+ }
3011
+ if (isOperandNode(term)) {
3012
+ return term;
3013
+ }
3014
+ if (termType === "BinaryExpression" || termType === "LogicalExpression" || termType === "NullExpression" || termType === "InExpression" || termType === "ExistsExpression" || termType === "BetweenExpression" || termType === "ArithmeticExpression") {
3015
+ return term;
3016
+ }
3017
+ return buildColumnNode(tableRef, term);
3018
+ }
2882
3019
  };
2883
3020
 
2884
3021
  // src/query-builder/relation-projection-helper.ts
@@ -3831,8 +3968,10 @@ var DefaultManyToManyCollection = class {
3831
3968
  attach(target) {
3832
3969
  const entity = this.ensureEntity(target);
3833
3970
  const id = this.extractId(entity);
3834
- if (id == null) return;
3835
- if (this.items.some((item) => this.extractId(item) === id)) {
3971
+ if (id != null && this.items.some((item) => this.extractId(item) === id)) {
3972
+ return;
3973
+ }
3974
+ if (id == null && this.items.includes(entity)) {
3836
3975
  return;
3837
3976
  }
3838
3977
  this.items.push(entity);
@@ -4528,8 +4667,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4528
4667
  * @returns New query builder instance with the subquery selection
4529
4668
 
4530
4669
  */
4531
- selectSubquery(alias, sub) {
4532
- const query = this.resolveQueryNode(sub);
4670
+ selectSubquery(alias, sub2) {
4671
+ const query = this.resolveQueryNode(sub2);
4533
4672
  return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
4534
4673
  }
4535
4674
  /**
@@ -4711,16 +4850,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4711
4850
  return this.clone(nextContext);
4712
4851
  }
4713
4852
  /**
4714
-
4715
- * Adds a GROUP BY clause to the query
4716
-
4717
- * @param col - Column definition or column node to group by
4718
-
4719
- * @returns New query builder instance with the GROUP BY clause
4720
-
4721
- */
4722
- groupBy(col2) {
4723
- const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(col2));
4853
+ * Adds a GROUP BY clause to the query
4854
+ * @param term - Column definition or ordering term to group by
4855
+ * @returns New query builder instance with the GROUP BY clause
4856
+ */
4857
+ groupBy(term) {
4858
+ const nextContext = this.applyAst(this.context, (service) => service.withGroupBy(term));
4724
4859
  return this.clone(nextContext);
4725
4860
  }
4726
4861
  /**
@@ -4737,18 +4872,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4737
4872
  return this.clone(nextContext);
4738
4873
  }
4739
4874
  /**
4740
-
4741
- * Adds an ORDER BY clause to the query
4742
-
4743
- * @param col - Column definition or column node to order by
4744
-
4745
- * @param direction - Order direction (defaults to ASC)
4746
-
4747
- * @returns New query builder instance with the ORDER BY clause
4748
-
4749
- */
4750
- orderBy(col2, direction = ORDER_DIRECTIONS.ASC) {
4751
- const nextContext = this.applyAst(this.context, (service) => service.withOrderBy(col2, direction));
4875
+ * Adds an ORDER BY clause to the query
4876
+ * @param term - Column definition or ordering term to order by
4877
+ * @param directionOrOptions - Order direction or options (defaults to ASC)
4878
+ * @returns New query builder instance with the ORDER BY clause
4879
+ */
4880
+ orderBy(term, directionOrOptions = ORDER_DIRECTIONS.ASC) {
4881
+ const options = typeof directionOrOptions === "string" ? { direction: directionOrOptions } : directionOrOptions;
4882
+ const dir = options.direction ?? ORDER_DIRECTIONS.ASC;
4883
+ const nextContext = this.applyAst(
4884
+ this.context,
4885
+ (service) => service.withOrderBy(term, dir, options.nulls, options.collation)
4886
+ );
4752
4887
  return this.clone(nextContext);
4753
4888
  }
4754
4889
  /**
@@ -5159,15 +5294,36 @@ var InsertQueryState = class _InsertQueryState {
5159
5294
  type: "InsertQuery",
5160
5295
  into: createTableNode(table),
5161
5296
  columns: [],
5162
- values: []
5297
+ source: {
5298
+ type: "InsertValues",
5299
+ rows: []
5300
+ }
5163
5301
  };
5164
5302
  }
5165
5303
  clone(nextAst) {
5166
5304
  return new _InsertQueryState(this.table, nextAst);
5167
5305
  }
5306
+ ensureColumnsFromRow(rows) {
5307
+ if (this.ast.columns.length) return this.ast.columns;
5308
+ return buildColumnNodes(this.table, Object.keys(rows[0]));
5309
+ }
5310
+ appendValues(rows) {
5311
+ if (this.ast.source.type === "InsertValues") {
5312
+ return [...this.ast.source.rows, ...rows];
5313
+ }
5314
+ return rows;
5315
+ }
5316
+ getTableColumns() {
5317
+ const names = Object.keys(this.table.columns);
5318
+ if (!names.length) return [];
5319
+ return buildColumnNodes(this.table, names);
5320
+ }
5168
5321
  withValues(rows) {
5169
5322
  if (!rows.length) return this;
5170
- const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
5323
+ if (this.ast.source.type === "InsertSelect") {
5324
+ throw new Error("Cannot mix INSERT ... VALUES with INSERT ... SELECT source.");
5325
+ }
5326
+ const definedColumns = this.ensureColumnsFromRow(rows);
5171
5327
  const newRows = rows.map(
5172
5328
  (row, rowIndex) => definedColumns.map((column) => {
5173
5329
  const rawValue = row[column.name];
@@ -5182,7 +5338,34 @@ var InsertQueryState = class _InsertQueryState {
5182
5338
  return this.clone({
5183
5339
  ...this.ast,
5184
5340
  columns: definedColumns,
5185
- values: [...this.ast.values, ...newRows]
5341
+ source: {
5342
+ type: "InsertValues",
5343
+ rows: this.appendValues(newRows)
5344
+ }
5345
+ });
5346
+ }
5347
+ withColumns(columns) {
5348
+ if (!columns.length) return this;
5349
+ return this.clone({
5350
+ ...this.ast,
5351
+ columns: [...columns]
5352
+ });
5353
+ }
5354
+ withSelect(query, columns) {
5355
+ const targetColumns = columns.length ? columns : this.ast.columns.length ? this.ast.columns : this.getTableColumns();
5356
+ if (!targetColumns.length) {
5357
+ throw new Error("INSERT ... SELECT requires specifying destination columns.");
5358
+ }
5359
+ if (this.ast.source.type === "InsertValues" && this.ast.source.rows.length) {
5360
+ throw new Error("Cannot mix INSERT ... SELECT with INSERT ... VALUES source.");
5361
+ }
5362
+ return this.clone({
5363
+ ...this.ast,
5364
+ columns: [...targetColumns],
5365
+ source: {
5366
+ type: "InsertSelect",
5367
+ query
5368
+ }
5186
5369
  });
5187
5370
  }
5188
5371
  withReturning(columns) {
@@ -5207,11 +5390,27 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
5207
5390
  if (!rows.length) return this;
5208
5391
  return this.clone(this.state.withValues(rows));
5209
5392
  }
5393
+ columns(...columns) {
5394
+ if (!columns.length) return this;
5395
+ return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
5396
+ }
5397
+ fromSelect(query, columns = []) {
5398
+ const ast = this.resolveSelectQuery(query);
5399
+ const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
5400
+ return this.clone(this.state.withSelect(ast, nodes));
5401
+ }
5210
5402
  returning(...columns) {
5211
5403
  if (!columns.length) return this;
5212
5404
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5213
5405
  return this.clone(this.state.withReturning(nodes));
5214
5406
  }
5407
+ // Helpers for column/AST resolution
5408
+ resolveColumnNodes(columns) {
5409
+ return columns.map((column) => buildColumnNode(this.table, column));
5410
+ }
5411
+ resolveSelectQuery(query) {
5412
+ return typeof query.getAST === "function" ? query.getAST() : query;
5413
+ }
5215
5414
  compile(arg) {
5216
5415
  if (typeof arg.compileInsert === "function") {
5217
5416
  return arg.compileInsert(this.state.ast);
@@ -5245,7 +5444,8 @@ var UpdateQueryState = class _UpdateQueryState {
5245
5444
  this.ast = ast ?? {
5246
5445
  type: "UpdateQuery",
5247
5446
  table: createTableNode(table),
5248
- set: []
5447
+ set: [],
5448
+ joins: []
5249
5449
  };
5250
5450
  }
5251
5451
  clone(nextAst) {
@@ -5284,6 +5484,27 @@ var UpdateQueryState = class _UpdateQueryState {
5284
5484
  returning: [...columns]
5285
5485
  });
5286
5486
  }
5487
+ withFrom(from) {
5488
+ return this.clone({
5489
+ ...this.ast,
5490
+ from
5491
+ });
5492
+ }
5493
+ withJoin(join) {
5494
+ return this.clone({
5495
+ ...this.ast,
5496
+ joins: [...this.ast.joins ?? [], join]
5497
+ });
5498
+ }
5499
+ withTableAlias(alias) {
5500
+ return this.clone({
5501
+ ...this.ast,
5502
+ table: {
5503
+ ...this.ast.table,
5504
+ alias
5505
+ }
5506
+ });
5507
+ }
5287
5508
  };
5288
5509
 
5289
5510
  // src/query-builder/update.ts
@@ -5295,6 +5516,18 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5295
5516
  clone(state) {
5296
5517
  return new _UpdateQueryBuilder(this.table, state);
5297
5518
  }
5519
+ as(alias) {
5520
+ return this.clone(this.state.withTableAlias(alias));
5521
+ }
5522
+ from(source) {
5523
+ const tableSource = this.resolveTableSource(source);
5524
+ return this.clone(this.state.withFrom(tableSource));
5525
+ }
5526
+ join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
5527
+ const joinTarget = this.resolveJoinTarget(table);
5528
+ const joinNode = createJoinNode(kind, joinTarget, condition, relationName);
5529
+ return this.clone(this.state.withJoin(joinNode));
5530
+ }
5298
5531
  set(values) {
5299
5532
  return this.clone(this.state.withSet(values));
5300
5533
  }
@@ -5306,6 +5539,16 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5306
5539
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5307
5540
  return this.clone(this.state.withReturning(nodes));
5308
5541
  }
5542
+ resolveTableSource(source) {
5543
+ if (isTableSourceNode(source)) {
5544
+ return source;
5545
+ }
5546
+ return { type: "Table", name: source.name, schema: source.schema };
5547
+ }
5548
+ resolveJoinTarget(table) {
5549
+ if (typeof table === "string") return table;
5550
+ return this.resolveTableSource(table);
5551
+ }
5309
5552
  compile(arg) {
5310
5553
  if (typeof arg.compileUpdate === "function") {
5311
5554
  return arg.compileUpdate(this.state.ast);
@@ -5320,6 +5563,7 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5320
5563
  return this.state.ast;
5321
5564
  }
5322
5565
  };
5566
+ var isTableSourceNode = (source) => typeof source.type === "string";
5323
5567
 
5324
5568
  // src/query-builder/delete-query-state.ts
5325
5569
  var DeleteQueryState = class _DeleteQueryState {
@@ -5327,7 +5571,8 @@ var DeleteQueryState = class _DeleteQueryState {
5327
5571
  this.table = table;
5328
5572
  this.ast = ast ?? {
5329
5573
  type: "DeleteQuery",
5330
- from: createTableNode(table)
5574
+ from: createTableNode(table),
5575
+ joins: []
5331
5576
  };
5332
5577
  }
5333
5578
  clone(nextAst) {
@@ -5345,6 +5590,27 @@ var DeleteQueryState = class _DeleteQueryState {
5345
5590
  returning: [...columns]
5346
5591
  });
5347
5592
  }
5593
+ withUsing(source) {
5594
+ return this.clone({
5595
+ ...this.ast,
5596
+ using: source
5597
+ });
5598
+ }
5599
+ withJoin(join) {
5600
+ return this.clone({
5601
+ ...this.ast,
5602
+ joins: [...this.ast.joins ?? [], join]
5603
+ });
5604
+ }
5605
+ withTableAlias(alias) {
5606
+ return this.clone({
5607
+ ...this.ast,
5608
+ from: {
5609
+ ...this.ast.from,
5610
+ alias
5611
+ }
5612
+ });
5613
+ }
5348
5614
  };
5349
5615
 
5350
5616
  // src/query-builder/delete.ts
@@ -5359,11 +5625,32 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
5359
5625
  where(expr) {
5360
5626
  return this.clone(this.state.withWhere(expr));
5361
5627
  }
5628
+ as(alias) {
5629
+ return this.clone(this.state.withTableAlias(alias));
5630
+ }
5631
+ using(source) {
5632
+ return this.clone(this.state.withUsing(this.resolveTableSource(source)));
5633
+ }
5634
+ join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
5635
+ const target = this.resolveJoinTarget(table);
5636
+ const joinNode = createJoinNode(kind, target, condition, relationName);
5637
+ return this.clone(this.state.withJoin(joinNode));
5638
+ }
5362
5639
  returning(...columns) {
5363
5640
  if (!columns.length) return this;
5364
5641
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5365
5642
  return this.clone(this.state.withReturning(nodes));
5366
5643
  }
5644
+ resolveTableSource(source) {
5645
+ if (isTableSourceNode2(source)) {
5646
+ return source;
5647
+ }
5648
+ return { type: "Table", name: source.name, schema: source.schema };
5649
+ }
5650
+ resolveJoinTarget(table) {
5651
+ if (typeof table === "string") return table;
5652
+ return this.resolveTableSource(table);
5653
+ }
5367
5654
  compile(arg) {
5368
5655
  if (typeof arg.compileDelete === "function") {
5369
5656
  return arg.compileDelete(this.state.ast);
@@ -5378,6 +5665,7 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
5378
5665
  return this.state.ast;
5379
5666
  }
5380
5667
  };
5668
+ var isTableSourceNode2 = (source) => typeof source.type === "string";
5381
5669
 
5382
5670
  // src/core/ddl/sql-writing.ts
5383
5671
  var resolvePrimaryKey = (table) => {
@@ -6576,7 +6864,7 @@ var TypeScriptGenerator = class {
6576
6864
  lines.push(`.where(${this.printExpression(ast.where)})`);
6577
6865
  }
6578
6866
  if (ast.groupBy && ast.groupBy.length) {
6579
- const cols = ast.groupBy.map((c) => `${this.namingStrategy.tableToSymbol(c.table)}.${c.name}`).join(", ");
6867
+ const cols = ast.groupBy.map((term) => this.printOrderingTerm(term)).join(", ");
6580
6868
  lines.push(`.groupBy(${cols})`);
6581
6869
  }
6582
6870
  if (ast.having) {
@@ -6584,7 +6872,16 @@ var TypeScriptGenerator = class {
6584
6872
  }
6585
6873
  if (ast.orderBy && ast.orderBy.length) {
6586
6874
  ast.orderBy.forEach((o) => {
6587
- lines.push(`.orderBy(${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name}, '${o.direction}')`);
6875
+ const term = this.printOrderingTerm(o.term);
6876
+ const opts = [`direction: '${o.direction}'`];
6877
+ if (o.nulls) opts.push(`nulls: '${o.nulls}'`);
6878
+ if (o.collation) opts.push(`collation: '${o.collation}'`);
6879
+ const hasOpts = opts.length > 1;
6880
+ if (hasOpts) {
6881
+ lines.push(`.orderBy(${term}, { ${opts.join(", ")} })`);
6882
+ } else {
6883
+ lines.push(`.orderBy(${term}, '${o.direction}')`);
6884
+ }
6588
6885
  });
6589
6886
  }
6590
6887
  if (ast.limit) lines.push(`.limit(${ast.limit})`);
@@ -6607,6 +6904,29 @@ var TypeScriptGenerator = class {
6607
6904
  printOperand(node) {
6608
6905
  return visitOperand(node, this);
6609
6906
  }
6907
+ /**
6908
+ * Prints an ordering term (operand/expression/alias) to TypeScript code.
6909
+ */
6910
+ printOrderingTerm(term) {
6911
+ if (!term || !term.type) {
6912
+ throw new Error("Unsupported ordering term");
6913
+ }
6914
+ switch (term.type) {
6915
+ case "Column":
6916
+ return `${this.namingStrategy.tableToSymbol(term.table)}.${term.name}`;
6917
+ case "AliasRef":
6918
+ return this.visitAliasRef(term);
6919
+ case "Literal":
6920
+ case "Function":
6921
+ case "JsonPath":
6922
+ case "ScalarSubquery":
6923
+ case "CaseExpression":
6924
+ case "WindowFunction":
6925
+ return this.printOperand(term);
6926
+ default:
6927
+ return this.printExpression(term);
6928
+ }
6929
+ }
6610
6930
  visitBinaryExpression(binary) {
6611
6931
  return this.printBinaryExpression(binary);
6612
6932
  }
@@ -6625,6 +6945,9 @@ var TypeScriptGenerator = class {
6625
6945
  visitBetweenExpression(betweenExpr) {
6626
6946
  return this.printBetweenExpression(betweenExpr);
6627
6947
  }
6948
+ visitArithmeticExpression(arithExpr) {
6949
+ return this.printArithmeticExpression(arithExpr);
6950
+ }
6628
6951
  visitColumn(node) {
6629
6952
  return this.printColumnOperand(node);
6630
6953
  }
@@ -6646,6 +6969,9 @@ var TypeScriptGenerator = class {
6646
6969
  visitWindowFunction(node) {
6647
6970
  return this.printWindowFunctionOperand(node);
6648
6971
  }
6972
+ visitAliasRef(node) {
6973
+ return `aliasRef('${node.name}')`;
6974
+ }
6649
6975
  /**
6650
6976
  * Prints a binary expression to TypeScript code
6651
6977
  * @param binary - Binary expression node
@@ -6676,6 +7002,11 @@ var TypeScriptGenerator = class {
6676
7002
  ${parts.join(",\n ")}
6677
7003
  )`;
6678
7004
  }
7005
+ printArithmeticExpression(expr) {
7006
+ const left2 = this.printOperand(expr.left);
7007
+ const right2 = this.printOperand(expr.right);
7008
+ return `${left2} ${expr.operator} ${right2}`;
7009
+ }
6679
7010
  /**
6680
7011
  * Prints an IN expression to TypeScript code
6681
7012
  * @param inExpr - IN expression node
@@ -6683,9 +7014,13 @@ var TypeScriptGenerator = class {
6683
7014
  */
6684
7015
  printInExpression(inExpr) {
6685
7016
  const left2 = this.printOperand(inExpr.left);
6686
- const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
6687
7017
  const fn4 = this.mapOp(inExpr.operator);
6688
- return `${fn4}(${left2}, [${values}])`;
7018
+ if (Array.isArray(inExpr.right)) {
7019
+ const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
7020
+ return `${fn4}(${left2}, [${values}])`;
7021
+ }
7022
+ const subquery = this.inlineChain(this.buildSelectLines(inExpr.right.query));
7023
+ return `${fn4}(${left2}, (${subquery}))`;
6689
7024
  }
6690
7025
  /**
6691
7026
  * Prints a null expression to TypeScript code
@@ -6789,7 +7124,12 @@ var TypeScriptGenerator = class {
6789
7124
  parts.push(partitionClause);
6790
7125
  }
6791
7126
  if (node.orderBy && node.orderBy.length > 0) {
6792
- const orderClause = "ORDER BY " + node.orderBy.map((o) => `${this.namingStrategy.tableToSymbol(o.column.table)}.${o.column.name} ${o.direction}`).join(", ");
7127
+ const orderClause = "ORDER BY " + node.orderBy.map((o) => {
7128
+ const term = this.printOrderingTerm(o.term);
7129
+ const collation = o.collation ? ` COLLATE ${o.collation}` : "";
7130
+ const nulls = o.nulls ? ` NULLS ${o.nulls}` : "";
7131
+ return `${term} ${o.direction}${collation}${nulls}`;
7132
+ }).join(", ");
6793
7133
  parts.push(orderClause);
6794
7134
  }
6795
7135
  result += parts.join(" ");
@@ -6865,6 +7205,13 @@ var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
6865
7205
 
6866
7206
  // src/orm/unit-of-work.ts
6867
7207
  var UnitOfWork = class {
7208
+ /**
7209
+ * Creates a new UnitOfWork instance.
7210
+ * @param dialect - The database dialect
7211
+ * @param executor - The database executor
7212
+ * @param identityMap - The identity map
7213
+ * @param hookContext - Function to get the hook context
7214
+ */
6868
7215
  constructor(dialect, executor, identityMap, hookContext) {
6869
7216
  this.dialect = dialect;
6870
7217
  this.executor = executor;
@@ -6872,21 +7219,50 @@ var UnitOfWork = class {
6872
7219
  this.hookContext = hookContext;
6873
7220
  this.trackedEntities = /* @__PURE__ */ new Map();
6874
7221
  }
7222
+ /**
7223
+ * Gets the identity buckets map.
7224
+ */
6875
7225
  get identityBuckets() {
6876
7226
  return this.identityMap.bucketsMap;
6877
7227
  }
7228
+ /**
7229
+ * Gets all tracked entities.
7230
+ * @returns Array of tracked entities
7231
+ */
6878
7232
  getTracked() {
6879
7233
  return Array.from(this.trackedEntities.values());
6880
7234
  }
7235
+ /**
7236
+ * Gets an entity by table and primary key.
7237
+ * @param table - The table definition
7238
+ * @param pk - The primary key value
7239
+ * @returns The entity or undefined if not found
7240
+ */
6881
7241
  getEntity(table, pk) {
6882
7242
  return this.identityMap.getEntity(table, pk);
6883
7243
  }
7244
+ /**
7245
+ * Gets all tracked entities for a specific table.
7246
+ * @param table - The table definition
7247
+ * @returns Array of tracked entities
7248
+ */
6884
7249
  getEntitiesForTable(table) {
6885
7250
  return this.identityMap.getEntitiesForTable(table);
6886
7251
  }
7252
+ /**
7253
+ * Finds a tracked entity.
7254
+ * @param entity - The entity to find
7255
+ * @returns The tracked entity or undefined if not found
7256
+ */
6887
7257
  findTracked(entity) {
6888
7258
  return this.trackedEntities.get(entity);
6889
7259
  }
7260
+ /**
7261
+ * Sets an entity in the identity map.
7262
+ * @param table - The table definition
7263
+ * @param pk - The primary key value
7264
+ * @param entity - The entity instance
7265
+ */
6890
7266
  setEntity(table, pk, entity) {
6891
7267
  if (pk === null || pk === void 0) return;
6892
7268
  let tracked = this.trackedEntities.get(entity);
@@ -6904,6 +7280,12 @@ var UnitOfWork = class {
6904
7280
  }
6905
7281
  this.registerIdentity(tracked);
6906
7282
  }
7283
+ /**
7284
+ * Tracks a new entity.
7285
+ * @param table - The table definition
7286
+ * @param entity - The entity instance
7287
+ * @param pk - Optional primary key value
7288
+ */
6907
7289
  trackNew(table, entity, pk) {
6908
7290
  const tracked = {
6909
7291
  table,
@@ -6917,6 +7299,12 @@ var UnitOfWork = class {
6917
7299
  this.registerIdentity(tracked);
6918
7300
  }
6919
7301
  }
7302
+ /**
7303
+ * Tracks a managed entity.
7304
+ * @param table - The table definition
7305
+ * @param pk - The primary key value
7306
+ * @param entity - The entity instance
7307
+ */
6920
7308
  trackManaged(table, pk, entity) {
6921
7309
  const tracked = {
6922
7310
  table,
@@ -6928,17 +7316,28 @@ var UnitOfWork = class {
6928
7316
  this.trackedEntities.set(entity, tracked);
6929
7317
  this.registerIdentity(tracked);
6930
7318
  }
7319
+ /**
7320
+ * Marks an entity as dirty (modified).
7321
+ * @param entity - The entity to mark as dirty
7322
+ */
6931
7323
  markDirty(entity) {
6932
7324
  const tracked = this.trackedEntities.get(entity);
6933
7325
  if (!tracked) return;
6934
7326
  if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
6935
7327
  tracked.status = "dirty" /* Dirty */;
6936
7328
  }
7329
+ /**
7330
+ * Marks an entity as removed.
7331
+ * @param entity - The entity to mark as removed
7332
+ */
6937
7333
  markRemoved(entity) {
6938
7334
  const tracked = this.trackedEntities.get(entity);
6939
7335
  if (!tracked) return;
6940
7336
  tracked.status = "removed" /* Removed */;
6941
7337
  }
7338
+ /**
7339
+ * Flushes pending changes to the database.
7340
+ */
6942
7341
  async flush() {
6943
7342
  const toFlush = Array.from(this.trackedEntities.values());
6944
7343
  for (const tracked of toFlush) {
@@ -6957,10 +7356,17 @@ var UnitOfWork = class {
6957
7356
  }
6958
7357
  }
6959
7358
  }
7359
+ /**
7360
+ * Resets the unit of work by clearing all tracked entities and identity map.
7361
+ */
6960
7362
  reset() {
6961
7363
  this.trackedEntities.clear();
6962
7364
  this.identityMap.clear();
6963
7365
  }
7366
+ /**
7367
+ * Flushes an insert operation for a new entity.
7368
+ * @param tracked - The tracked entity to insert
7369
+ */
6964
7370
  async flushInsert(tracked) {
6965
7371
  await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
6966
7372
  const payload = this.extractColumns(tracked.table, tracked.entity);
@@ -6977,6 +7383,10 @@ var UnitOfWork = class {
6977
7383
  this.registerIdentity(tracked);
6978
7384
  await this.runHook(tracked.table.hooks?.afterInsert, tracked);
6979
7385
  }
7386
+ /**
7387
+ * Flushes an update operation for a modified entity.
7388
+ * @param tracked - The tracked entity to update
7389
+ */
6980
7390
  async flushUpdate(tracked) {
6981
7391
  if (tracked.pk == null) return;
6982
7392
  const changes = this.computeChanges(tracked);
@@ -6999,6 +7409,10 @@ var UnitOfWork = class {
6999
7409
  this.registerIdentity(tracked);
7000
7410
  await this.runHook(tracked.table.hooks?.afterUpdate, tracked);
7001
7411
  }
7412
+ /**
7413
+ * Flushes a delete operation for a removed entity.
7414
+ * @param tracked - The tracked entity to delete
7415
+ */
7002
7416
  async flushDelete(tracked) {
7003
7417
  if (tracked.pk == null) return;
7004
7418
  await this.runHook(tracked.table.hooks?.beforeDelete, tracked);
@@ -7012,10 +7426,20 @@ var UnitOfWork = class {
7012
7426
  this.identityMap.remove(tracked);
7013
7427
  await this.runHook(tracked.table.hooks?.afterDelete, tracked);
7014
7428
  }
7429
+ /**
7430
+ * Runs a table hook if defined.
7431
+ * @param hook - The hook function
7432
+ * @param tracked - The tracked entity
7433
+ */
7015
7434
  async runHook(hook, tracked) {
7016
7435
  if (!hook) return;
7017
7436
  await hook(this.hookContext(), tracked.entity);
7018
7437
  }
7438
+ /**
7439
+ * Computes changes between current entity state and original snapshot.
7440
+ * @param tracked - The tracked entity
7441
+ * @returns Object with changed column values
7442
+ */
7019
7443
  computeChanges(tracked) {
7020
7444
  const snapshot = tracked.original ?? {};
7021
7445
  const changes = {};
@@ -7027,6 +7451,12 @@ var UnitOfWork = class {
7027
7451
  }
7028
7452
  return changes;
7029
7453
  }
7454
+ /**
7455
+ * Extracts column values from an entity.
7456
+ * @param table - The table definition
7457
+ * @param entity - The entity instance
7458
+ * @returns Object with column values
7459
+ */
7030
7460
  extractColumns(table, entity) {
7031
7461
  const payload = {};
7032
7462
  for (const column of Object.keys(table.columns)) {
@@ -7035,9 +7465,19 @@ var UnitOfWork = class {
7035
7465
  }
7036
7466
  return payload;
7037
7467
  }
7468
+ /**
7469
+ * Executes a compiled query.
7470
+ * @param compiled - The compiled query
7471
+ * @returns Query results
7472
+ */
7038
7473
  async executeCompiled(compiled) {
7039
7474
  return this.executor.executeSql(compiled.sql, compiled.params);
7040
7475
  }
7476
+ /**
7477
+ * Gets columns for RETURNING clause.
7478
+ * @param table - The table definition
7479
+ * @returns Array of column nodes
7480
+ */
7041
7481
  getReturningColumns(table) {
7042
7482
  return Object.values(table.columns).map((column) => ({
7043
7483
  type: "Column",
@@ -7046,6 +7486,11 @@ var UnitOfWork = class {
7046
7486
  alias: column.name
7047
7487
  }));
7048
7488
  }
7489
+ /**
7490
+ * Applies RETURNING clause results to the tracked entity.
7491
+ * @param tracked - The tracked entity
7492
+ * @param results - Query results
7493
+ */
7049
7494
  applyReturningResults(tracked, results) {
7050
7495
  if (!this.dialect.supportsReturning()) return;
7051
7496
  const first = results[0];
@@ -7057,15 +7502,30 @@ var UnitOfWork = class {
7057
7502
  tracked.entity[columnName] = row[i];
7058
7503
  }
7059
7504
  }
7505
+ /**
7506
+ * Normalizes a column name by removing quotes and table prefixes.
7507
+ * @param column - The column name to normalize
7508
+ * @returns Normalized column name
7509
+ */
7060
7510
  normalizeColumnName(column) {
7061
7511
  const parts = column.split(".");
7062
7512
  const candidate = parts[parts.length - 1];
7063
7513
  return candidate.replace(/^["`[\]]+|["`[\]]+$/g, "");
7064
7514
  }
7515
+ /**
7516
+ * Registers an entity in the identity map.
7517
+ * @param tracked - The tracked entity to register
7518
+ */
7065
7519
  registerIdentity(tracked) {
7066
7520
  if (tracked.pk == null) return;
7067
7521
  this.identityMap.register(tracked);
7068
7522
  }
7523
+ /**
7524
+ * Creates a snapshot of an entity's current state.
7525
+ * @param table - The table definition
7526
+ * @param entity - The entity instance
7527
+ * @returns Object with entity state
7528
+ */
7069
7529
  createSnapshot(table, entity) {
7070
7530
  const snapshot = {};
7071
7531
  for (const column of Object.keys(table.columns)) {
@@ -7073,6 +7533,11 @@ var UnitOfWork = class {
7073
7533
  }
7074
7534
  return snapshot;
7075
7535
  }
7536
+ /**
7537
+ * Gets the primary key value from a tracked entity.
7538
+ * @param tracked - The tracked entity
7539
+ * @returns Primary key value or null
7540
+ */
7076
7541
  getPrimaryKeyValue(tracked) {
7077
7542
  const key = findPrimaryKey(tracked.table);
7078
7543
  const val = tracked.entity[key];
@@ -7083,6 +7548,10 @@ var UnitOfWork = class {
7083
7548
 
7084
7549
  // src/orm/domain-event-bus.ts
7085
7550
  var DomainEventBus = class {
7551
+ /**
7552
+ * Creates a new DomainEventBus instance.
7553
+ * @param initialHandlers - Optional initial event handlers
7554
+ */
7086
7555
  constructor(initialHandlers) {
7087
7556
  this.handlers = /* @__PURE__ */ new Map();
7088
7557
  if (initialHandlers) {
@@ -7093,15 +7562,32 @@ var DomainEventBus = class {
7093
7562
  }
7094
7563
  }
7095
7564
  }
7565
+ /**
7566
+ * Registers an event handler for a specific event type.
7567
+ * @template TType - The event type
7568
+ * @param type - The event type
7569
+ * @param handler - The event handler
7570
+ */
7096
7571
  on(type, handler) {
7097
7572
  const key = type;
7098
7573
  const existing = this.handlers.get(key) ?? [];
7099
7574
  existing.push(handler);
7100
7575
  this.handlers.set(key, existing);
7101
7576
  }
7577
+ /**
7578
+ * Registers an event handler for a specific event type (alias for on).
7579
+ * @template TType - The event type
7580
+ * @param type - The event type
7581
+ * @param handler - The event handler
7582
+ */
7102
7583
  register(type, handler) {
7103
7584
  this.on(type, handler);
7104
7585
  }
7586
+ /**
7587
+ * Dispatches domain events for tracked entities.
7588
+ * @param trackedEntities - Iterable of tracked entities
7589
+ * @param ctx - The context to pass to handlers
7590
+ */
7105
7591
  async dispatch(trackedEntities, ctx) {
7106
7592
  for (const tracked of trackedEntities) {
7107
7593
  const entity = tracked.entity;
@@ -7126,18 +7612,34 @@ var addDomainEvent = (entity, event) => {
7126
7612
 
7127
7613
  // src/orm/relation-change-processor.ts
7128
7614
  var RelationChangeProcessor = class {
7615
+ /**
7616
+ * Creates a new RelationChangeProcessor instance.
7617
+ * @param unitOfWork - The unit of work instance
7618
+ * @param dialect - The database dialect
7619
+ * @param executor - The database executor
7620
+ */
7129
7621
  constructor(unitOfWork, dialect, executor) {
7130
7622
  this.unitOfWork = unitOfWork;
7131
7623
  this.dialect = dialect;
7132
7624
  this.executor = executor;
7133
7625
  this.relationChanges = [];
7134
7626
  }
7627
+ /**
7628
+ * Registers a relation change for processing.
7629
+ * @param entry - The relation change entry
7630
+ */
7135
7631
  registerChange(entry) {
7136
7632
  this.relationChanges.push(entry);
7137
7633
  }
7634
+ /**
7635
+ * Resets the relation change processor by clearing all pending changes.
7636
+ */
7138
7637
  reset() {
7139
7638
  this.relationChanges.length = 0;
7140
7639
  }
7640
+ /**
7641
+ * Processes all pending relation changes.
7642
+ */
7141
7643
  async process() {
7142
7644
  if (!this.relationChanges.length) return;
7143
7645
  const entries = [...this.relationChanges];
@@ -7159,6 +7661,10 @@ var RelationChangeProcessor = class {
7159
7661
  }
7160
7662
  }
7161
7663
  }
7664
+ /**
7665
+ * Handles changes for has-many relations.
7666
+ * @param entry - The relation change entry
7667
+ */
7162
7668
  async handleHasManyChange(entry) {
7163
7669
  const relation = entry.relation;
7164
7670
  const target = entry.change.entity;
@@ -7177,6 +7683,10 @@ var RelationChangeProcessor = class {
7177
7683
  this.detachHasManyChild(tracked.entity, relation);
7178
7684
  }
7179
7685
  }
7686
+ /**
7687
+ * Handles changes for has-one relations.
7688
+ * @param entry - The relation change entry
7689
+ */
7180
7690
  async handleHasOneChange(entry) {
7181
7691
  const relation = entry.relation;
7182
7692
  const target = entry.change.entity;
@@ -7195,8 +7705,16 @@ var RelationChangeProcessor = class {
7195
7705
  this.detachHasOneChild(tracked.entity, relation);
7196
7706
  }
7197
7707
  }
7708
+ /**
7709
+ * Handles changes for belongs-to relations.
7710
+ * @param _entry - The relation change entry (reserved for future use)
7711
+ */
7198
7712
  async handleBelongsToChange(_entry) {
7199
7713
  }
7714
+ /**
7715
+ * Handles changes for belongs-to-many relations.
7716
+ * @param entry - The relation change entry
7717
+ */
7200
7718
  async handleBelongsToManyChange(entry) {
7201
7719
  const relation = entry.relation;
7202
7720
  const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
@@ -7215,11 +7733,22 @@ var RelationChangeProcessor = class {
7215
7733
  }
7216
7734
  }
7217
7735
  }
7736
+ /**
7737
+ * Assigns a foreign key for has-many relations.
7738
+ * @param child - The child entity
7739
+ * @param relation - The has-many relation
7740
+ * @param rootValue - The root entity's primary key value
7741
+ */
7218
7742
  assignHasManyForeignKey(child, relation, rootValue) {
7219
7743
  const current = child[relation.foreignKey];
7220
7744
  if (current === rootValue) return;
7221
7745
  child[relation.foreignKey] = rootValue;
7222
7746
  }
7747
+ /**
7748
+ * Detaches a child entity from has-many relations.
7749
+ * @param child - The child entity
7750
+ * @param relation - The has-many relation
7751
+ */
7223
7752
  detachHasManyChild(child, relation) {
7224
7753
  if (relation.cascade === "all" || relation.cascade === "remove") {
7225
7754
  this.unitOfWork.markRemoved(child);
@@ -7228,11 +7757,22 @@ var RelationChangeProcessor = class {
7228
7757
  child[relation.foreignKey] = null;
7229
7758
  this.unitOfWork.markDirty(child);
7230
7759
  }
7760
+ /**
7761
+ * Assigns a foreign key for has-one relations.
7762
+ * @param child - The child entity
7763
+ * @param relation - The has-one relation
7764
+ * @param rootValue - The root entity's primary key value
7765
+ */
7231
7766
  assignHasOneForeignKey(child, relation, rootValue) {
7232
7767
  const current = child[relation.foreignKey];
7233
7768
  if (current === rootValue) return;
7234
7769
  child[relation.foreignKey] = rootValue;
7235
7770
  }
7771
+ /**
7772
+ * Detaches a child entity from has-one relations.
7773
+ * @param child - The child entity
7774
+ * @param relation - The has-one relation
7775
+ */
7236
7776
  detachHasOneChild(child, relation) {
7237
7777
  if (relation.cascade === "all" || relation.cascade === "remove") {
7238
7778
  this.unitOfWork.markRemoved(child);
@@ -7241,6 +7781,12 @@ var RelationChangeProcessor = class {
7241
7781
  child[relation.foreignKey] = null;
7242
7782
  this.unitOfWork.markDirty(child);
7243
7783
  }
7784
+ /**
7785
+ * Inserts a pivot row for belongs-to-many relations.
7786
+ * @param relation - The belongs-to-many relation
7787
+ * @param rootId - The root entity's primary key value
7788
+ * @param targetId - The target entity's primary key value
7789
+ */
7244
7790
  async insertPivotRow(relation, rootId, targetId) {
7245
7791
  const payload = {
7246
7792
  [relation.pivotForeignKeyToRoot]: rootId,
@@ -7250,6 +7796,12 @@ var RelationChangeProcessor = class {
7250
7796
  const compiled = builder.compile(this.dialect);
7251
7797
  await this.executor.executeSql(compiled.sql, compiled.params);
7252
7798
  }
7799
+ /**
7800
+ * Deletes a pivot row for belongs-to-many relations.
7801
+ * @param relation - The belongs-to-many relation
7802
+ * @param rootId - The root entity's primary key value
7803
+ * @param targetId - The target entity's primary key value
7804
+ */
7253
7805
  async deletePivotRow(relation, rootId, targetId) {
7254
7806
  const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
7255
7807
  const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
@@ -7260,6 +7812,12 @@ var RelationChangeProcessor = class {
7260
7812
  const compiled = builder.compile(this.dialect);
7261
7813
  await this.executor.executeSql(compiled.sql, compiled.params);
7262
7814
  }
7815
+ /**
7816
+ * Resolves the primary key value from an entity.
7817
+ * @param entity - The entity
7818
+ * @param table - The table definition
7819
+ * @returns The primary key value or null
7820
+ */
7263
7821
  resolvePrimaryKeyValue(entity, table) {
7264
7822
  if (!entity) return null;
7265
7823
  const key = findPrimaryKey(table);
@@ -7275,42 +7833,231 @@ var createQueryLoggingExecutor = (executor, logger) => {
7275
7833
  return executor;
7276
7834
  }
7277
7835
  const wrapped = {
7836
+ capabilities: executor.capabilities,
7278
7837
  async executeSql(sql, params) {
7279
7838
  logger({ sql, params });
7280
7839
  return executor.executeSql(sql, params);
7281
- }
7840
+ },
7841
+ beginTransaction: () => executor.beginTransaction(),
7842
+ commitTransaction: () => executor.commitTransaction(),
7843
+ rollbackTransaction: () => executor.rollbackTransaction(),
7844
+ dispose: () => executor.dispose()
7282
7845
  };
7283
- if (executor.beginTransaction) {
7284
- wrapped.beginTransaction = executor.beginTransaction.bind(executor);
7285
- }
7286
- if (executor.commitTransaction) {
7287
- wrapped.commitTransaction = executor.commitTransaction.bind(executor);
7288
- }
7289
- if (executor.rollbackTransaction) {
7290
- wrapped.rollbackTransaction = executor.rollbackTransaction.bind(executor);
7291
- }
7292
7846
  return wrapped;
7293
7847
  };
7294
7848
 
7295
7849
  // src/orm/transaction-runner.ts
7296
7850
  var runInTransaction = async (executor, action) => {
7297
- if (!executor.beginTransaction) {
7851
+ if (!executor.capabilities.transactions) {
7298
7852
  await action();
7299
7853
  return;
7300
7854
  }
7301
7855
  await executor.beginTransaction();
7302
7856
  try {
7303
7857
  await action();
7304
- await executor.commitTransaction?.();
7858
+ await executor.commitTransaction();
7305
7859
  } catch (error) {
7306
- await executor.rollbackTransaction?.();
7860
+ await executor.rollbackTransaction();
7307
7861
  throw error;
7308
7862
  }
7309
7863
  };
7310
7864
 
7865
+ // src/orm/save-graph.ts
7866
+ var toKey8 = (value) => value === null || value === void 0 ? "" : String(value);
7867
+ var pickColumns = (table, payload) => {
7868
+ const columns = {};
7869
+ for (const key of Object.keys(table.columns)) {
7870
+ if (payload[key] !== void 0) {
7871
+ columns[key] = payload[key];
7872
+ }
7873
+ }
7874
+ return columns;
7875
+ };
7876
+ var ensureEntity = (session, table, payload) => {
7877
+ const pk = findPrimaryKey(table);
7878
+ const row = pickColumns(table, payload);
7879
+ const pkValue = payload[pk];
7880
+ if (pkValue !== void 0 && pkValue !== null) {
7881
+ const tracked = session.getEntity(table, pkValue);
7882
+ if (tracked) {
7883
+ return tracked;
7884
+ }
7885
+ if (row[pk] === void 0) {
7886
+ row[pk] = pkValue;
7887
+ }
7888
+ }
7889
+ return createEntityFromRow(session, table, row);
7890
+ };
7891
+ var assignColumns = (table, entity, payload) => {
7892
+ for (const key of Object.keys(table.columns)) {
7893
+ if (payload[key] !== void 0) {
7894
+ entity[key] = payload[key];
7895
+ }
7896
+ }
7897
+ };
7898
+ var isEntityInCollection = (items, pkName, entity) => {
7899
+ if (items.includes(entity)) return true;
7900
+ const entityPk = entity[pkName];
7901
+ if (entityPk === void 0 || entityPk === null) return false;
7902
+ return items.some((item) => toKey8(item[pkName]) === toKey8(entityPk));
7903
+ };
7904
+ var findInCollectionByPk = (items, pkName, pkValue) => {
7905
+ if (pkValue === void 0 || pkValue === null) return void 0;
7906
+ return items.find((item) => toKey8(item[pkName]) === toKey8(pkValue));
7907
+ };
7908
+ var handleHasMany = async (session, root, relationName, relation, payload, options) => {
7909
+ if (!Array.isArray(payload)) return;
7910
+ const collection = root[relationName];
7911
+ await collection.load();
7912
+ const targetTable = relation.target;
7913
+ const targetPk = findPrimaryKey(targetTable);
7914
+ const existing = collection.getItems();
7915
+ const seen = /* @__PURE__ */ new Set();
7916
+ for (const item of payload) {
7917
+ if (item === null || item === void 0) continue;
7918
+ const asObj = typeof item === "object" ? item : { [targetPk]: item };
7919
+ const pkValue = asObj[targetPk];
7920
+ const current = findInCollectionByPk(existing, targetPk, pkValue) ?? (pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) : void 0);
7921
+ const entity = current ?? ensureEntity(session, targetTable, asObj);
7922
+ assignColumns(targetTable, entity, asObj);
7923
+ await applyGraphToEntity(session, targetTable, entity, asObj, options);
7924
+ if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
7925
+ collection.attach(entity);
7926
+ }
7927
+ if (pkValue !== void 0 && pkValue !== null) {
7928
+ seen.add(toKey8(pkValue));
7929
+ }
7930
+ }
7931
+ if (options.pruneMissing) {
7932
+ for (const item of [...collection.getItems()]) {
7933
+ const pkValue = item[targetPk];
7934
+ if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
7935
+ collection.remove(item);
7936
+ }
7937
+ }
7938
+ }
7939
+ };
7940
+ var handleHasOne = async (session, root, relationName, relation, payload, options) => {
7941
+ const ref = root[relationName];
7942
+ if (payload === void 0) return;
7943
+ if (payload === null) {
7944
+ ref.set(null);
7945
+ return;
7946
+ }
7947
+ const pk = findPrimaryKey(relation.target);
7948
+ if (typeof payload === "number" || typeof payload === "string") {
7949
+ const entity = ref.set({ [pk]: payload });
7950
+ if (entity) {
7951
+ await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
7952
+ }
7953
+ return;
7954
+ }
7955
+ const attached = ref.set(payload);
7956
+ if (attached) {
7957
+ await applyGraphToEntity(session, relation.target, attached, payload, options);
7958
+ }
7959
+ };
7960
+ var handleBelongsTo = async (session, root, relationName, relation, payload, options) => {
7961
+ const ref = root[relationName];
7962
+ if (payload === void 0) return;
7963
+ if (payload === null) {
7964
+ ref.set(null);
7965
+ return;
7966
+ }
7967
+ const pk = relation.localKey || findPrimaryKey(relation.target);
7968
+ if (typeof payload === "number" || typeof payload === "string") {
7969
+ const entity = ref.set({ [pk]: payload });
7970
+ if (entity) {
7971
+ await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
7972
+ }
7973
+ return;
7974
+ }
7975
+ const attached = ref.set(payload);
7976
+ if (attached) {
7977
+ await applyGraphToEntity(session, relation.target, attached, payload, options);
7978
+ }
7979
+ };
7980
+ var handleBelongsToMany = async (session, root, relationName, relation, payload, options) => {
7981
+ if (!Array.isArray(payload)) return;
7982
+ const collection = root[relationName];
7983
+ await collection.load();
7984
+ const targetTable = relation.target;
7985
+ const targetPk = relation.targetKey || findPrimaryKey(targetTable);
7986
+ const seen = /* @__PURE__ */ new Set();
7987
+ for (const item of payload) {
7988
+ if (item === null || item === void 0) continue;
7989
+ if (typeof item === "number" || typeof item === "string") {
7990
+ const id = item;
7991
+ collection.attach(id);
7992
+ seen.add(toKey8(id));
7993
+ continue;
7994
+ }
7995
+ const asObj = item;
7996
+ const pkValue = asObj[targetPk];
7997
+ const entity = pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) ?? ensureEntity(session, targetTable, asObj) : ensureEntity(session, targetTable, asObj);
7998
+ assignColumns(targetTable, entity, asObj);
7999
+ await applyGraphToEntity(session, targetTable, entity, asObj, options);
8000
+ if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
8001
+ collection.attach(entity);
8002
+ }
8003
+ if (pkValue !== void 0 && pkValue !== null) {
8004
+ seen.add(toKey8(pkValue));
8005
+ }
8006
+ }
8007
+ if (options.pruneMissing) {
8008
+ for (const item of [...collection.getItems()]) {
8009
+ const pkValue = item[targetPk];
8010
+ if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
8011
+ collection.detach(item);
8012
+ }
8013
+ }
8014
+ }
8015
+ };
8016
+ var applyRelation = async (session, table, entity, relationName, relation, payload, options) => {
8017
+ switch (relation.type) {
8018
+ case RelationKinds.HasMany:
8019
+ return handleHasMany(session, entity, relationName, relation, payload, options);
8020
+ case RelationKinds.HasOne:
8021
+ return handleHasOne(session, entity, relationName, relation, payload, options);
8022
+ case RelationKinds.BelongsTo:
8023
+ return handleBelongsTo(session, entity, relationName, relation, payload, options);
8024
+ case RelationKinds.BelongsToMany:
8025
+ return handleBelongsToMany(session, entity, relationName, relation, payload, options);
8026
+ }
8027
+ };
8028
+ var applyGraphToEntity = async (session, table, entity, payload, options) => {
8029
+ assignColumns(table, entity, payload);
8030
+ for (const [relationName, relation] of Object.entries(table.relations)) {
8031
+ if (!(relationName in payload)) continue;
8032
+ await applyRelation(session, table, entity, relationName, relation, payload[relationName], options);
8033
+ }
8034
+ };
8035
+ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
8036
+ const table = getTableDefFromEntity(entityClass);
8037
+ if (!table) {
8038
+ throw new Error("Entity metadata has not been bootstrapped");
8039
+ }
8040
+ const root = ensureEntity(session, table, payload);
8041
+ await applyGraphToEntity(session, table, root, payload, options);
8042
+ return root;
8043
+ };
8044
+
7311
8045
  // src/orm/orm-session.ts
7312
8046
  var OrmSession = class {
8047
+ /**
8048
+ * Creates a new OrmSession instance.
8049
+ * @param opts - Session options
8050
+ */
7313
8051
  constructor(opts) {
8052
+ /**
8053
+ * Registers a relation change.
8054
+ * @param root - The root entity
8055
+ * @param relationKey - The relation key
8056
+ * @param rootTable - The root table definition
8057
+ * @param relationName - The relation name
8058
+ * @param relation - The relation definition
8059
+ * @param change - The relation change
8060
+ */
7314
8061
  this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
7315
8062
  this.relationChanges.registerChange(
7316
8063
  buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
@@ -7324,42 +8071,117 @@ var OrmSession = class {
7324
8071
  this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
7325
8072
  this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
7326
8073
  }
8074
+ /**
8075
+ * Releases resources associated with this session (executor/pool leases) and resets tracking.
8076
+ * Must be safe to call multiple times.
8077
+ */
8078
+ async dispose() {
8079
+ try {
8080
+ await this.executor.dispose();
8081
+ } finally {
8082
+ this.unitOfWork.reset();
8083
+ this.relationChanges.reset();
8084
+ }
8085
+ }
8086
+ /**
8087
+ * Gets the database dialect.
8088
+ */
7327
8089
  get dialect() {
7328
8090
  return this.orm.dialect;
7329
8091
  }
8092
+ /**
8093
+ * Gets the identity buckets map.
8094
+ */
7330
8095
  get identityBuckets() {
7331
8096
  return this.unitOfWork.identityBuckets;
7332
8097
  }
8098
+ /**
8099
+ * Gets all tracked entities.
8100
+ */
7333
8101
  get tracked() {
7334
8102
  return this.unitOfWork.getTracked();
7335
8103
  }
8104
+ /**
8105
+ * Gets an entity by table and primary key.
8106
+ * @param table - The table definition
8107
+ * @param pk - The primary key value
8108
+ * @returns The entity or undefined if not found
8109
+ */
7336
8110
  getEntity(table, pk) {
7337
8111
  return this.unitOfWork.getEntity(table, pk);
7338
8112
  }
8113
+ /**
8114
+ * Sets an entity in the identity map.
8115
+ * @param table - The table definition
8116
+ * @param pk - The primary key value
8117
+ * @param entity - The entity instance
8118
+ */
7339
8119
  setEntity(table, pk, entity) {
7340
8120
  this.unitOfWork.setEntity(table, pk, entity);
7341
8121
  }
8122
+ /**
8123
+ * Tracks a new entity.
8124
+ * @param table - The table definition
8125
+ * @param entity - The entity instance
8126
+ * @param pk - Optional primary key value
8127
+ */
7342
8128
  trackNew(table, entity, pk) {
7343
8129
  this.unitOfWork.trackNew(table, entity, pk);
7344
8130
  }
8131
+ /**
8132
+ * Tracks a managed entity.
8133
+ * @param table - The table definition
8134
+ * @param pk - The primary key value
8135
+ * @param entity - The entity instance
8136
+ */
7345
8137
  trackManaged(table, pk, entity) {
7346
8138
  this.unitOfWork.trackManaged(table, pk, entity);
7347
8139
  }
8140
+ /**
8141
+ * Marks an entity as dirty (modified).
8142
+ * @param entity - The entity to mark as dirty
8143
+ */
7348
8144
  markDirty(entity) {
7349
8145
  this.unitOfWork.markDirty(entity);
7350
8146
  }
8147
+ /**
8148
+ * Marks an entity as removed.
8149
+ * @param entity - The entity to mark as removed
8150
+ */
7351
8151
  markRemoved(entity) {
7352
8152
  this.unitOfWork.markRemoved(entity);
7353
8153
  }
8154
+ /**
8155
+ * Gets all tracked entities for a specific table.
8156
+ * @param table - The table definition
8157
+ * @returns Array of tracked entities
8158
+ */
7354
8159
  getEntitiesForTable(table) {
7355
8160
  return this.unitOfWork.getEntitiesForTable(table);
7356
8161
  }
8162
+ /**
8163
+ * Registers an interceptor for flush lifecycle hooks.
8164
+ * @param interceptor - The interceptor to register
8165
+ */
7357
8166
  registerInterceptor(interceptor) {
7358
8167
  this.interceptors.push(interceptor);
7359
8168
  }
8169
+ /**
8170
+ * Registers a domain event handler.
8171
+ * @param type - The event type
8172
+ * @param handler - The event handler
8173
+ */
7360
8174
  registerDomainEventHandler(type, handler) {
7361
8175
  this.domainEvents.on(type, handler);
7362
8176
  }
8177
+ /**
8178
+ * Finds an entity by its primary key.
8179
+ * @template TCtor - The entity constructor type
8180
+ * @param entityClass - The entity constructor
8181
+ * @param id - The primary key value
8182
+ * @returns The entity instance or null if not found
8183
+ * @throws If entity metadata is not bootstrapped or table has no primary key
8184
+ */
7363
8185
  async find(entityClass, id) {
7364
8186
  const table = getTableDefFromEntity(entityClass);
7365
8187
  if (!table) {
@@ -7378,14 +8200,46 @@ var OrmSession = class {
7378
8200
  const rows = await executeHydrated(this, qb);
7379
8201
  return rows[0] ?? null;
7380
8202
  }
8203
+ /**
8204
+ * Finds a single entity using a query builder.
8205
+ * @template TTable - The table type
8206
+ * @param qb - The query builder
8207
+ * @returns The first entity instance or null if not found
8208
+ */
7381
8209
  async findOne(qb) {
7382
8210
  const limited = qb.limit(1);
7383
8211
  const rows = await executeHydrated(this, limited);
7384
8212
  return rows[0] ?? null;
7385
8213
  }
8214
+ /**
8215
+ * Finds multiple entities using a query builder.
8216
+ * @template TTable - The table type
8217
+ * @param qb - The query builder
8218
+ * @returns Array of entity instances
8219
+ */
7386
8220
  async findMany(qb) {
7387
8221
  return executeHydrated(this, qb);
7388
8222
  }
8223
+ /**
8224
+ * Saves an entity graph (root + nested relations) based on a DTO-like payload.
8225
+ * @param entityClass - Root entity constructor
8226
+ * @param payload - DTO payload containing column values and nested relations
8227
+ * @param options - Graph save options
8228
+ * @returns The root entity instance
8229
+ */
8230
+ async saveGraph(entityClass, payload, options) {
8231
+ const { transactional = true, ...graphOptions } = options ?? {};
8232
+ const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
8233
+ if (!transactional) {
8234
+ return execute();
8235
+ }
8236
+ return this.transaction(() => execute());
8237
+ }
8238
+ /**
8239
+ * Persists an entity (either inserts or updates).
8240
+ * @param entity - The entity to persist
8241
+ * @throws If entity metadata is not bootstrapped
8242
+ */
7389
8243
  async persist(entity) {
7390
8244
  if (this.unitOfWork.findTracked(entity)) {
7391
8245
  return;
@@ -7402,12 +8256,22 @@ var OrmSession = class {
7402
8256
  this.trackNew(table, entity);
7403
8257
  }
7404
8258
  }
8259
+ /**
8260
+ * Marks an entity for removal.
8261
+ * @param entity - The entity to remove
8262
+ */
7405
8263
  async remove(entity) {
7406
8264
  this.markRemoved(entity);
7407
8265
  }
8266
+ /**
8267
+ * Flushes pending changes to the database.
8268
+ */
7408
8269
  async flush() {
7409
8270
  await this.unitOfWork.flush();
7410
8271
  }
8272
+ /**
8273
+ * Flushes pending changes with interceptors and relation processing.
8274
+ */
7411
8275
  async flushWithHooks() {
7412
8276
  for (const interceptor of this.interceptors) {
7413
8277
  await interceptor.beforeFlush?.(this);
@@ -7419,14 +8283,24 @@ var OrmSession = class {
7419
8283
  await interceptor.afterFlush?.(this);
7420
8284
  }
7421
8285
  }
8286
+ /**
8287
+ * Commits the current transaction.
8288
+ */
7422
8289
  async commit() {
7423
8290
  await runInTransaction(this.executor, async () => {
7424
8291
  await this.flushWithHooks();
7425
8292
  });
7426
8293
  await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
7427
8294
  }
8295
+ /**
8296
+ * Executes a function within a transaction.
8297
+ * @template T - The return type
8298
+ * @param fn - The function to execute
8299
+ * @returns The result of the function
8300
+ * @throws If the transaction fails
8301
+ */
7428
8302
  async transaction(fn4) {
7429
- if (!this.executor.beginTransaction) {
8303
+ if (!this.executor.capabilities.transactions) {
7430
8304
  const result = await fn4(this);
7431
8305
  await this.commit();
7432
8306
  return result;
@@ -7435,7 +8309,7 @@ var OrmSession = class {
7435
8309
  try {
7436
8310
  const result = await fn4(this);
7437
8311
  await this.flushWithHooks();
7438
- await this.executor.commitTransaction?.();
8312
+ await this.executor.commitTransaction();
7439
8313
  await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
7440
8314
  return result;
7441
8315
  } catch (err) {
@@ -7443,11 +8317,20 @@ var OrmSession = class {
7443
8317
  throw err;
7444
8318
  }
7445
8319
  }
8320
+ /**
8321
+ * Rolls back the current transaction.
8322
+ */
7446
8323
  async rollback() {
7447
- await this.executor.rollbackTransaction?.();
8324
+ if (this.executor.capabilities.transactions) {
8325
+ await this.executor.rollbackTransaction();
8326
+ }
7448
8327
  this.unitOfWork.reset();
7449
8328
  this.relationChanges.reset();
7450
8329
  }
8330
+ /**
8331
+ * Gets the execution context.
8332
+ * @returns The execution context
8333
+ */
7451
8334
  getExecutionContext() {
7452
8335
  return {
7453
8336
  dialect: this.orm.dialect,
@@ -7455,6 +8338,10 @@ var OrmSession = class {
7455
8338
  interceptors: this.orm.interceptors
7456
8339
  };
7457
8340
  }
8341
+ /**
8342
+ * Gets the hydration context.
8343
+ * @returns The hydration context
8344
+ */
7458
8345
  getHydrationContext() {
7459
8346
  return {
7460
8347
  identityMap: this.identityMap,
@@ -7497,29 +8384,49 @@ var InterceptorPipeline = class {
7497
8384
 
7498
8385
  // src/orm/orm.ts
7499
8386
  var Orm = class {
8387
+ /**
8388
+ * Creates a new ORM instance.
8389
+ * @param opts - ORM options
8390
+ */
7500
8391
  constructor(opts) {
7501
8392
  this.dialect = opts.dialect;
7502
8393
  this.interceptors = opts.interceptors ?? new InterceptorPipeline();
7503
8394
  this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
7504
8395
  this.executorFactory = opts.executorFactory;
7505
8396
  }
7506
- createSession(options) {
7507
- const executor = this.executorFactory.createExecutor(options?.tx);
8397
+ /**
8398
+ * Creates a new ORM session.
8399
+ * @param options - Optional session options
8400
+ * @returns The ORM session
8401
+ */
8402
+ createSession() {
8403
+ const executor = this.executorFactory.createExecutor();
7508
8404
  return new OrmSession({ orm: this, executor });
7509
8405
  }
8406
+ /**
8407
+ * Executes a function within a transaction.
8408
+ * @template T - The return type
8409
+ * @param fn - The function to execute
8410
+ * @returns The result of the function
8411
+ * @throws If the transaction fails
8412
+ */
7510
8413
  async transaction(fn4) {
7511
8414
  const executor = this.executorFactory.createTransactionalExecutor();
7512
8415
  const session = new OrmSession({ orm: this, executor });
7513
8416
  try {
7514
- const result = await fn4(session);
7515
- await session.commit();
7516
- return result;
8417
+ return await session.transaction(() => fn4(session));
7517
8418
  } catch (err) {
7518
- await session.rollback();
7519
8419
  throw err;
7520
8420
  } finally {
8421
+ await session.dispose();
7521
8422
  }
7522
8423
  }
8424
+ /**
8425
+ * Shuts down the ORM and releases underlying resources (pools, timers).
8426
+ */
8427
+ async dispose() {
8428
+ await this.executorFactory.dispose();
8429
+ }
7523
8430
  };
7524
8431
 
7525
8432
  // src/decorators/decorator-metadata.ts
@@ -7778,18 +8685,245 @@ function rowsToQueryResult(rows) {
7778
8685
  return { columns, values };
7779
8686
  }
7780
8687
  function createExecutorFromQueryRunner(runner) {
8688
+ const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
7781
8689
  return {
8690
+ capabilities: {
8691
+ transactions: supportsTransactions
8692
+ },
7782
8693
  async executeSql(sql, params) {
7783
8694
  const rows = await runner.query(sql, params);
7784
8695
  const result = rowsToQueryResult(rows);
7785
8696
  return [result];
7786
8697
  },
7787
- beginTransaction: runner.beginTransaction?.bind(runner),
7788
- commitTransaction: runner.commitTransaction?.bind(runner),
7789
- rollbackTransaction: runner.rollbackTransaction?.bind(runner)
8698
+ async beginTransaction() {
8699
+ if (!supportsTransactions) {
8700
+ throw new Error("Transactions are not supported by this executor");
8701
+ }
8702
+ await runner.beginTransaction.call(runner);
8703
+ },
8704
+ async commitTransaction() {
8705
+ if (!supportsTransactions) {
8706
+ throw new Error("Transactions are not supported by this executor");
8707
+ }
8708
+ await runner.commitTransaction.call(runner);
8709
+ },
8710
+ async rollbackTransaction() {
8711
+ if (!supportsTransactions) {
8712
+ throw new Error("Transactions are not supported by this executor");
8713
+ }
8714
+ await runner.rollbackTransaction.call(runner);
8715
+ },
8716
+ async dispose() {
8717
+ await runner.dispose?.call(runner);
8718
+ }
7790
8719
  };
7791
8720
  }
7792
8721
 
8722
+ // src/core/execution/pooling/pool.ts
8723
+ var deferred = () => {
8724
+ let resolve;
8725
+ let reject;
8726
+ const promise = new Promise((res, rej) => {
8727
+ resolve = res;
8728
+ reject = rej;
8729
+ });
8730
+ return { promise, resolve, reject };
8731
+ };
8732
+ var Pool = class {
8733
+ constructor(adapter, options) {
8734
+ this.destroyed = false;
8735
+ this.creating = 0;
8736
+ this.leased = 0;
8737
+ this.idle = [];
8738
+ this.waiters = [];
8739
+ this.reapTimer = null;
8740
+ if (!Number.isFinite(options.max) || options.max <= 0) {
8741
+ throw new Error("Pool options.max must be a positive number");
8742
+ }
8743
+ this.adapter = adapter;
8744
+ this.options = { max: options.max, ...options };
8745
+ const idleTimeout = this.options.idleTimeoutMillis;
8746
+ if (idleTimeout && idleTimeout > 0) {
8747
+ const interval = this.options.reapIntervalMillis ?? Math.max(1e3, Math.floor(idleTimeout / 2));
8748
+ this.reapTimer = setInterval(() => {
8749
+ void this.reapIdle();
8750
+ }, interval);
8751
+ this.reapTimer.unref?.();
8752
+ }
8753
+ const min2 = this.options.min ?? 0;
8754
+ if (min2 > 0) {
8755
+ void this.warm(min2);
8756
+ }
8757
+ }
8758
+ /**
8759
+ * Acquire a resource lease.
8760
+ * The returned lease MUST be released or destroyed.
8761
+ */
8762
+ async acquire() {
8763
+ if (this.destroyed) {
8764
+ throw new Error("Pool is destroyed");
8765
+ }
8766
+ const idle = await this.takeIdleValidated();
8767
+ if (idle) {
8768
+ this.leased++;
8769
+ return this.makeLease(idle);
8770
+ }
8771
+ if (this.totalLive() < this.options.max) {
8772
+ this.creating++;
8773
+ try {
8774
+ const created = await this.adapter.create();
8775
+ this.leased++;
8776
+ return this.makeLease(created);
8777
+ } finally {
8778
+ this.creating--;
8779
+ }
8780
+ }
8781
+ const waiter = deferred();
8782
+ this.waiters.push(waiter);
8783
+ const timeout = this.options.acquireTimeoutMillis;
8784
+ let timer = null;
8785
+ if (timeout && timeout > 0) {
8786
+ timer = setTimeout(() => {
8787
+ const idx = this.waiters.indexOf(waiter);
8788
+ if (idx >= 0) this.waiters.splice(idx, 1);
8789
+ waiter.reject(new Error("Pool acquire timeout"));
8790
+ }, timeout);
8791
+ timer.unref?.();
8792
+ }
8793
+ try {
8794
+ return await waiter.promise;
8795
+ } finally {
8796
+ if (timer) clearTimeout(timer);
8797
+ }
8798
+ }
8799
+ /** Destroy pool and all idle resources; waits for in-flight creations to settle. */
8800
+ async destroy() {
8801
+ if (this.destroyed) return;
8802
+ this.destroyed = true;
8803
+ if (this.reapTimer) {
8804
+ clearInterval(this.reapTimer);
8805
+ this.reapTimer = null;
8806
+ }
8807
+ while (this.waiters.length) {
8808
+ this.waiters.shift().reject(new Error("Pool destroyed"));
8809
+ }
8810
+ while (this.idle.length) {
8811
+ const entry = this.idle.shift();
8812
+ await this.adapter.destroy(entry.resource);
8813
+ }
8814
+ }
8815
+ totalLive() {
8816
+ return this.idle.length + this.leased + this.creating;
8817
+ }
8818
+ makeLease(resource) {
8819
+ let done = false;
8820
+ return {
8821
+ resource,
8822
+ release: async () => {
8823
+ if (done) return;
8824
+ done = true;
8825
+ await this.releaseResource(resource);
8826
+ },
8827
+ destroy: async () => {
8828
+ if (done) return;
8829
+ done = true;
8830
+ await this.destroyResource(resource);
8831
+ }
8832
+ };
8833
+ }
8834
+ async releaseResource(resource) {
8835
+ this.leased = Math.max(0, this.leased - 1);
8836
+ if (this.destroyed) {
8837
+ await this.adapter.destroy(resource);
8838
+ return;
8839
+ }
8840
+ const next = this.waiters.shift();
8841
+ if (next) {
8842
+ this.leased++;
8843
+ next.resolve(this.makeLease(resource));
8844
+ return;
8845
+ }
8846
+ this.idle.push({ resource, lastUsedAt: Date.now() });
8847
+ await this.trimToMinMax();
8848
+ }
8849
+ async destroyResource(resource) {
8850
+ this.leased = Math.max(0, this.leased - 1);
8851
+ await this.adapter.destroy(resource);
8852
+ if (!this.destroyed && this.waiters.length && this.totalLive() < this.options.max) {
8853
+ const waiter = this.waiters.shift();
8854
+ this.creating++;
8855
+ try {
8856
+ const created = await this.adapter.create();
8857
+ this.leased++;
8858
+ waiter.resolve(this.makeLease(created));
8859
+ } catch (err) {
8860
+ waiter.reject(err);
8861
+ } finally {
8862
+ this.creating--;
8863
+ }
8864
+ }
8865
+ }
8866
+ async takeIdleValidated() {
8867
+ while (this.idle.length) {
8868
+ const entry = this.idle.pop();
8869
+ if (!this.adapter.validate) {
8870
+ return entry.resource;
8871
+ }
8872
+ const ok = await this.adapter.validate(entry.resource);
8873
+ if (ok) {
8874
+ return entry.resource;
8875
+ }
8876
+ await this.adapter.destroy(entry.resource);
8877
+ }
8878
+ return null;
8879
+ }
8880
+ async reapIdle() {
8881
+ if (this.destroyed) return;
8882
+ const idleTimeout = this.options.idleTimeoutMillis;
8883
+ if (!idleTimeout || idleTimeout <= 0) return;
8884
+ const now2 = Date.now();
8885
+ const min2 = this.options.min ?? 0;
8886
+ const keep = [];
8887
+ const kill = [];
8888
+ for (const entry of this.idle) {
8889
+ const expired = now2 - entry.lastUsedAt >= idleTimeout;
8890
+ if (expired) kill.push(entry);
8891
+ else keep.push(entry);
8892
+ }
8893
+ while (keep.length < min2 && kill.length) {
8894
+ keep.push(kill.pop());
8895
+ }
8896
+ this.idle.length = 0;
8897
+ this.idle.push(...keep);
8898
+ for (const entry of kill) {
8899
+ await this.adapter.destroy(entry.resource);
8900
+ }
8901
+ }
8902
+ async warm(targetMin) {
8903
+ const min2 = Math.max(0, targetMin);
8904
+ while (!this.destroyed && this.idle.length < min2 && this.totalLive() < this.options.max) {
8905
+ this.creating++;
8906
+ try {
8907
+ const created = await this.adapter.create();
8908
+ this.idle.push({ resource: created, lastUsedAt: Date.now() });
8909
+ } catch {
8910
+ break;
8911
+ } finally {
8912
+ this.creating--;
8913
+ }
8914
+ }
8915
+ }
8916
+ async trimToMinMax() {
8917
+ const max2 = this.options.max;
8918
+ const min2 = this.options.min ?? 0;
8919
+ while (this.totalLive() > max2 && this.idle.length > min2) {
8920
+ const entry = this.idle.shift();
8921
+ if (!entry) break;
8922
+ await this.adapter.destroy(entry.resource);
8923
+ }
8924
+ }
8925
+ };
8926
+
7793
8927
  // src/core/execution/executors/postgres-executor.ts
7794
8928
  function createPostgresExecutor(client) {
7795
8929
  return createExecutorFromQueryRunner({
@@ -7811,7 +8945,11 @@ function createPostgresExecutor(client) {
7811
8945
 
7812
8946
  // src/core/execution/executors/mysql-executor.ts
7813
8947
  function createMysqlExecutor(client) {
8948
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
7814
8949
  return {
8950
+ capabilities: {
8951
+ transactions: supportsTransactions
8952
+ },
7815
8953
  async executeSql(sql, params) {
7816
8954
  const [rows] = await client.query(sql, params);
7817
8955
  if (!Array.isArray(rows)) {
@@ -7823,53 +8961,94 @@ function createMysqlExecutor(client) {
7823
8961
  return [result];
7824
8962
  },
7825
8963
  async beginTransaction() {
7826
- if (!client.beginTransaction) return;
8964
+ if (!supportsTransactions) {
8965
+ throw new Error("Transactions are not supported by this executor");
8966
+ }
7827
8967
  await client.beginTransaction();
7828
8968
  },
7829
8969
  async commitTransaction() {
7830
- if (!client.commit) return;
8970
+ if (!supportsTransactions) {
8971
+ throw new Error("Transactions are not supported by this executor");
8972
+ }
7831
8973
  await client.commit();
7832
8974
  },
7833
8975
  async rollbackTransaction() {
7834
- if (!client.rollback) return;
8976
+ if (!supportsTransactions) {
8977
+ throw new Error("Transactions are not supported by this executor");
8978
+ }
7835
8979
  await client.rollback();
8980
+ },
8981
+ async dispose() {
7836
8982
  }
7837
8983
  };
7838
8984
  }
7839
8985
 
7840
8986
  // src/core/execution/executors/sqlite-executor.ts
7841
8987
  function createSqliteExecutor(client) {
8988
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commitTransaction === "function" && typeof client.rollbackTransaction === "function";
7842
8989
  return {
8990
+ capabilities: {
8991
+ transactions: supportsTransactions
8992
+ },
7843
8993
  async executeSql(sql, params) {
7844
8994
  const rows = await client.all(sql, params);
7845
8995
  const result = rowsToQueryResult(rows);
7846
8996
  return [result];
7847
8997
  },
7848
- beginTransaction: client.beginTransaction?.bind(client),
7849
- commitTransaction: client.commitTransaction?.bind(client),
7850
- rollbackTransaction: client.rollbackTransaction?.bind(client)
8998
+ async beginTransaction() {
8999
+ if (!supportsTransactions) {
9000
+ throw new Error("Transactions are not supported by this executor");
9001
+ }
9002
+ await client.beginTransaction();
9003
+ },
9004
+ async commitTransaction() {
9005
+ if (!supportsTransactions) {
9006
+ throw new Error("Transactions are not supported by this executor");
9007
+ }
9008
+ await client.commitTransaction();
9009
+ },
9010
+ async rollbackTransaction() {
9011
+ if (!supportsTransactions) {
9012
+ throw new Error("Transactions are not supported by this executor");
9013
+ }
9014
+ await client.rollbackTransaction();
9015
+ },
9016
+ async dispose() {
9017
+ }
7851
9018
  };
7852
9019
  }
7853
9020
 
7854
9021
  // src/core/execution/executors/mssql-executor.ts
7855
9022
  function createMssqlExecutor(client) {
9023
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
7856
9024
  return {
9025
+ capabilities: {
9026
+ transactions: supportsTransactions
9027
+ },
7857
9028
  async executeSql(sql, params) {
7858
9029
  const { recordset } = await client.query(sql, params);
7859
9030
  const result = rowsToQueryResult(recordset ?? []);
7860
9031
  return [result];
7861
9032
  },
7862
9033
  async beginTransaction() {
7863
- if (!client.beginTransaction) return;
9034
+ if (!supportsTransactions) {
9035
+ throw new Error("Transactions are not supported by this executor");
9036
+ }
7864
9037
  await client.beginTransaction();
7865
9038
  },
7866
9039
  async commitTransaction() {
7867
- if (!client.commit) return;
9040
+ if (!supportsTransactions) {
9041
+ throw new Error("Transactions are not supported by this executor");
9042
+ }
7868
9043
  await client.commit();
7869
9044
  },
7870
9045
  async rollbackTransaction() {
7871
- if (!client.rollback) return;
9046
+ if (!supportsTransactions) {
9047
+ throw new Error("Transactions are not supported by this executor");
9048
+ }
7872
9049
  await client.rollback();
9050
+ },
9051
+ async dispose() {
7873
9052
  }
7874
9053
  };
7875
9054
  }
@@ -7938,6 +9117,86 @@ function createTediousExecutor(connection, module, options) {
7938
9117
  const client = createTediousMssqlClient(connection, module, options);
7939
9118
  return createMssqlExecutor(client);
7940
9119
  }
9120
+
9121
+ // src/orm/pooled-executor-factory.ts
9122
+ function createPooledExecutorFactory(opts) {
9123
+ const { pool, adapter } = opts;
9124
+ const makeExecutor = (mode) => {
9125
+ let lease = null;
9126
+ const getLease = async () => {
9127
+ if (lease) return lease;
9128
+ lease = await pool.acquire();
9129
+ return lease;
9130
+ };
9131
+ const executeWithConn = async (conn, sql, params) => {
9132
+ const rows = await adapter.query(conn, sql, params);
9133
+ return [rowsToQueryResult(rows)];
9134
+ };
9135
+ return {
9136
+ capabilities: { transactions: true },
9137
+ async executeSql(sql, params) {
9138
+ if (mode === "sticky") {
9139
+ const l2 = await getLease();
9140
+ return executeWithConn(l2.resource, sql, params);
9141
+ }
9142
+ if (lease) {
9143
+ return executeWithConn(lease.resource, sql, params);
9144
+ }
9145
+ const l = await pool.acquire();
9146
+ try {
9147
+ return await executeWithConn(l.resource, sql, params);
9148
+ } finally {
9149
+ await l.release();
9150
+ }
9151
+ },
9152
+ async beginTransaction() {
9153
+ const l = await getLease();
9154
+ await adapter.beginTransaction(l.resource);
9155
+ },
9156
+ async commitTransaction() {
9157
+ if (!lease) {
9158
+ throw new Error("commitTransaction called without an active transaction");
9159
+ }
9160
+ const l = lease;
9161
+ try {
9162
+ await adapter.commitTransaction(l.resource);
9163
+ } finally {
9164
+ lease = null;
9165
+ await l.release();
9166
+ }
9167
+ },
9168
+ async rollbackTransaction() {
9169
+ if (!lease) {
9170
+ return;
9171
+ }
9172
+ const l = lease;
9173
+ try {
9174
+ await adapter.rollbackTransaction(l.resource);
9175
+ } finally {
9176
+ lease = null;
9177
+ await l.release();
9178
+ }
9179
+ },
9180
+ async dispose() {
9181
+ if (!lease) return;
9182
+ const l = lease;
9183
+ lease = null;
9184
+ await l.release();
9185
+ }
9186
+ };
9187
+ };
9188
+ return {
9189
+ createExecutor() {
9190
+ return makeExecutor("session");
9191
+ },
9192
+ createTransactionalExecutor() {
9193
+ return makeExecutor("sticky");
9194
+ },
9195
+ async dispose() {
9196
+ await pool.destroy();
9197
+ }
9198
+ };
9199
+ }
7941
9200
  export {
7942
9201
  AsyncLocalStorage,
7943
9202
  BelongsTo,
@@ -7956,6 +9215,7 @@ export {
7956
9215
  MySqlDialect,
7957
9216
  Orm,
7958
9217
  OrmSession,
9218
+ Pool,
7959
9219
  PostgresDialect,
7960
9220
  PrimaryKey,
7961
9221
  RelationKinds,
@@ -7966,7 +9226,9 @@ export {
7966
9226
  UpdateQueryBuilder,
7967
9227
  abs,
7968
9228
  acos,
9229
+ add,
7969
9230
  addDomainEvent,
9231
+ aliasRef,
7970
9232
  and,
7971
9233
  ascii,
7972
9234
  asin,
@@ -7999,6 +9261,7 @@ export {
7999
9261
  createLiteral,
8000
9262
  createMssqlExecutor,
8001
9263
  createMysqlExecutor,
9264
+ createPooledExecutorFactory,
8002
9265
  createPostgresExecutor,
8003
9266
  createQueryLoggingExecutor,
8004
9267
  createSqliteExecutor,
@@ -8017,6 +9280,7 @@ export {
8017
9280
  degrees,
8018
9281
  denseRank,
8019
9282
  diffSchema,
9283
+ div,
8020
9284
  endOfMonth,
8021
9285
  eq,
8022
9286
  esel,
@@ -8039,6 +9303,7 @@ export {
8039
9303
  hasOne,
8040
9304
  hydrateRows,
8041
9305
  inList,
9306
+ inSubquery,
8042
9307
  instr,
8043
9308
  introspectSchema,
8044
9309
  isCaseExpressionNode,
@@ -8074,10 +9339,12 @@ export {
8074
9339
  min,
8075
9340
  mod,
8076
9341
  month,
9342
+ mul,
8077
9343
  neq,
8078
9344
  notBetween,
8079
9345
  notExists,
8080
9346
  notInList,
9347
+ notInSubquery,
8081
9348
  notLike,
8082
9349
  now,
8083
9350
  ntile,
@@ -8109,6 +9376,7 @@ export {
8109
9376
  sin,
8110
9377
  space,
8111
9378
  sqrt,
9379
+ sub,
8112
9380
  substr,
8113
9381
  sum,
8114
9382
  synchronizeSchema,