metal-orm 1.0.40 → 1.0.42

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 (45) hide show
  1. package/README.md +53 -14
  2. package/dist/index.cjs +1298 -126
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +676 -30
  5. package/dist/index.d.ts +676 -30
  6. package/dist/index.js +1293 -126
  7. package/dist/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/codegen/typescript.ts +6 -2
  10. package/src/core/ast/expression-builders.ts +25 -4
  11. package/src/core/ast/expression-nodes.ts +3 -1
  12. package/src/core/ast/expression.ts +2 -2
  13. package/src/core/ast/query.ts +24 -2
  14. package/src/core/dialect/abstract.ts +6 -2
  15. package/src/core/dialect/base/join-compiler.ts +9 -12
  16. package/src/core/dialect/base/sql-dialect.ts +98 -17
  17. package/src/core/dialect/mssql/index.ts +30 -62
  18. package/src/core/dialect/sqlite/index.ts +39 -34
  19. package/src/core/execution/db-executor.ts +46 -6
  20. package/src/core/execution/executors/mssql-executor.ts +39 -22
  21. package/src/core/execution/executors/mysql-executor.ts +23 -6
  22. package/src/core/execution/executors/sqlite-executor.ts +29 -3
  23. package/src/core/execution/pooling/pool-types.ts +30 -0
  24. package/src/core/execution/pooling/pool.ts +268 -0
  25. package/src/decorators/bootstrap.ts +7 -7
  26. package/src/index.ts +6 -0
  27. package/src/orm/domain-event-bus.ts +49 -0
  28. package/src/orm/entity-metadata.ts +9 -9
  29. package/src/orm/entity.ts +58 -0
  30. package/src/orm/orm-session.ts +465 -270
  31. package/src/orm/orm.ts +61 -11
  32. package/src/orm/pooled-executor-factory.ts +131 -0
  33. package/src/orm/query-logger.ts +6 -12
  34. package/src/orm/relation-change-processor.ts +75 -0
  35. package/src/orm/relations/many-to-many.ts +4 -2
  36. package/src/orm/save-graph.ts +303 -0
  37. package/src/orm/transaction-runner.ts +3 -3
  38. package/src/orm/unit-of-work.ts +128 -0
  39. package/src/query-builder/delete-query-state.ts +67 -38
  40. package/src/query-builder/delete.ts +37 -1
  41. package/src/query-builder/insert-query-state.ts +131 -61
  42. package/src/query-builder/insert.ts +27 -1
  43. package/src/query-builder/update-query-state.ts +114 -77
  44. package/src/query-builder/update.ts +38 -1
  45. package/src/schema/table.ts +210 -115
package/dist/index.js CHANGED
@@ -50,6 +50,54 @@ var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
50
50
  collation: options.collation
51
51
  };
52
52
  };
53
+ var TABLE_REF_CACHE = /* @__PURE__ */ new WeakMap();
54
+ var withColumnProps = (table) => {
55
+ const cached = TABLE_REF_CACHE.get(table);
56
+ if (cached) return cached;
57
+ const proxy = new Proxy(table, {
58
+ get(target, prop, receiver) {
59
+ if (prop === "$") return target.columns;
60
+ if (Reflect.has(target, prop)) return Reflect.get(target, prop, receiver);
61
+ if (typeof prop === "string" && prop in target.columns) return target.columns[prop];
62
+ return void 0;
63
+ },
64
+ has(target, prop) {
65
+ return prop === "$" || Reflect.has(target, prop) || typeof prop === "string" && prop in target.columns;
66
+ },
67
+ ownKeys(target) {
68
+ const base = Reflect.ownKeys(target);
69
+ const cols = Object.keys(target.columns);
70
+ for (const k of cols) {
71
+ if (!base.includes(k)) base.push(k);
72
+ }
73
+ if (!base.includes("$")) base.push("$");
74
+ return base;
75
+ },
76
+ getOwnPropertyDescriptor(target, prop) {
77
+ if (prop === "$") {
78
+ return {
79
+ configurable: true,
80
+ enumerable: false,
81
+ get() {
82
+ return target.columns;
83
+ }
84
+ };
85
+ }
86
+ if (typeof prop === "string" && prop in target.columns && !Reflect.has(target, prop)) {
87
+ return {
88
+ configurable: true,
89
+ enumerable: true,
90
+ value: target.columns[prop],
91
+ writable: false
92
+ };
93
+ }
94
+ return Reflect.getOwnPropertyDescriptor(target, prop);
95
+ }
96
+ });
97
+ TABLE_REF_CACHE.set(table, proxy);
98
+ return proxy;
99
+ };
100
+ var tableRef = (table) => withColumnProps(table);
53
101
 
54
102
  // src/schema/column.ts
55
103
  var col = {
@@ -287,6 +335,12 @@ var toOperand = (val) => {
287
335
  }
288
336
  return toNode(val);
289
337
  };
338
+ var hasQueryAst = (value) => typeof value.getAST === "function";
339
+ var resolveSelectQueryNode = (query) => hasQueryAst(query) ? query.getAST() : query;
340
+ var toScalarSubqueryNode = (query) => ({
341
+ type: "ScalarSubquery",
342
+ query: resolveSelectQueryNode(query)
343
+ });
290
344
  var columnOperand = (col2) => toNode(col2);
291
345
  var outerRef = (col2) => ({
292
346
  ...columnOperand(col2),
@@ -337,14 +391,16 @@ var isNotNull = (left2) => ({
337
391
  left: toNode(left2),
338
392
  operator: "IS NOT NULL"
339
393
  });
340
- var createInExpression = (operator, left2, values) => ({
394
+ var createInExpression = (operator, left2, right2) => ({
341
395
  type: "InExpression",
342
396
  left: toNode(left2),
343
397
  operator,
344
- right: values.map((v) => toOperand(v))
398
+ right: right2
345
399
  });
346
- var inList = (left2, values) => createInExpression("IN", left2, values);
347
- var notInList = (left2, values) => createInExpression("NOT IN", left2, values);
400
+ var inList = (left2, values) => createInExpression("IN", left2, values.map((v) => toOperand(v)));
401
+ var notInList = (left2, values) => createInExpression("NOT IN", left2, values.map((v) => toOperand(v)));
402
+ var inSubquery = (left2, subquery) => createInExpression("IN", left2, toScalarSubqueryNode(subquery));
403
+ var notInSubquery = (left2, subquery) => createInExpression("NOT IN", left2, toScalarSubqueryNode(subquery));
348
404
  var createBetweenExpression = (operator, left2, lower2, upper2) => ({
349
405
  type: "BetweenExpression",
350
406
  left: toNode(left2),
@@ -1027,8 +1083,12 @@ var Dialect = class _Dialect {
1027
1083
  });
1028
1084
  this.registerExpressionCompiler("InExpression", (inExpr, ctx) => {
1029
1085
  const left2 = this.compileOperand(inExpr.left, ctx);
1030
- const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
1031
- return `${left2} ${inExpr.operator} (${values})`;
1086
+ if (Array.isArray(inExpr.right)) {
1087
+ const values = inExpr.right.map((v) => this.compileOperand(v, ctx)).join(", ");
1088
+ return `${left2} ${inExpr.operator} (${values})`;
1089
+ }
1090
+ const subquerySql = this.compileSelectAst(inExpr.right.query, ctx).trim().replace(/;$/, "");
1091
+ return `${left2} ${inExpr.operator} (${subquerySql})`;
1032
1092
  });
1033
1093
  this.registerExpressionCompiler("ExistsExpression", (existsExpr, ctx) => {
1034
1094
  const subquerySql = this.compileSelectForExists(existsExpr.subquery, ctx);
@@ -1286,17 +1346,9 @@ var NoReturningStrategy = class {
1286
1346
 
1287
1347
  // src/core/dialect/base/join-compiler.ts
1288
1348
  var JoinCompiler = class {
1289
- /**
1290
- * Compiles all JOIN clauses from a SELECT query AST.
1291
- * @param ast - The SELECT query AST containing join definitions.
1292
- * @param ctx - The compiler context for expression compilation.
1293
- * @param compileFrom - Function to compile table sources (tables or subqueries).
1294
- * @param compileExpression - Function to compile join condition expressions.
1295
- * @returns SQL JOIN clauses (e.g., " LEFT JOIN table ON condition") or empty string if no joins.
1296
- */
1297
- static compileJoins(ast, ctx, compileFrom, compileExpression) {
1298
- if (!ast.joins || ast.joins.length === 0) return "";
1299
- const parts = ast.joins.map((j) => {
1349
+ static compileJoins(joins, ctx, compileFrom, compileExpression) {
1350
+ if (!joins || joins.length === 0) return "";
1351
+ const parts = joins.map((j) => {
1300
1352
  const table = compileFrom(j.table, ctx);
1301
1353
  const cond = compileExpression(j.condition, ctx);
1302
1354
  return `${j.kind} JOIN ${table} ON ${cond}`;
@@ -1379,25 +1431,41 @@ var SqlDialectBase = class extends Dialect {
1379
1431
  return `${ctes}${combined}${orderBy}${pagination}`;
1380
1432
  }
1381
1433
  compileInsertAst(ast, ctx) {
1434
+ if (!ast.columns.length) {
1435
+ throw new Error("INSERT queries must specify columns.");
1436
+ }
1382
1437
  const table = this.compileTableName(ast.into);
1383
1438
  const columnList = this.compileInsertColumnList(ast.columns);
1384
- const values = this.compileInsertValues(ast.values, ctx);
1439
+ const source = this.compileInsertSource(ast.source, ctx);
1385
1440
  const returning = this.compileReturning(ast.returning, ctx);
1386
- return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning}`;
1441
+ return `INSERT INTO ${table} (${columnList}) ${source}${returning}`;
1387
1442
  }
1388
1443
  compileReturning(returning, ctx) {
1389
1444
  return this.returningStrategy.compileReturning(returning, ctx);
1390
1445
  }
1446
+ compileInsertSource(source, ctx) {
1447
+ if (source.type === "InsertValues") {
1448
+ if (!source.rows.length) {
1449
+ throw new Error("INSERT ... VALUES requires at least one row.");
1450
+ }
1451
+ const values = source.rows.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1452
+ return `VALUES ${values}`;
1453
+ }
1454
+ const normalized = this.normalizeSelectAst(source.query);
1455
+ return this.compileSelectAst(normalized, ctx).trim();
1456
+ }
1391
1457
  compileInsertColumnList(columns) {
1392
1458
  return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
1393
1459
  }
1394
- compileInsertValues(values, ctx) {
1395
- return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
1396
- }
1397
1460
  compileSelectCore(ast, ctx) {
1398
1461
  const columns = this.compileSelectColumns(ast, ctx);
1399
1462
  const from = this.compileFrom(ast.from, ctx);
1400
- const joins = JoinCompiler.compileJoins(ast, ctx, this.compileFrom.bind(this), this.compileExpression.bind(this));
1463
+ const joins = JoinCompiler.compileJoins(
1464
+ ast.joins,
1465
+ ctx,
1466
+ this.compileFrom.bind(this),
1467
+ this.compileExpression.bind(this)
1468
+ );
1401
1469
  const whereClause = this.compileWhere(ast.where, ctx);
1402
1470
  const groupBy = GroupByCompiler.compileGroupBy(ast, (term) => this.compileOrderingTerm(term, ctx));
1403
1471
  const having = this.compileHaving(ast, ctx);
@@ -1411,25 +1479,37 @@ var SqlDialectBase = class extends Dialect {
1411
1479
  return `SELECT ${this.compileDistinct(ast)}${columns} FROM ${from}${joins}${whereClause}${groupBy}${having}${orderBy}${pagination}`;
1412
1480
  }
1413
1481
  compileUpdateAst(ast, ctx) {
1414
- const table = this.compileTableName(ast.table);
1415
- const assignments = this.compileUpdateAssignments(ast.set, ctx);
1482
+ const target = this.compileTableReference(ast.table);
1483
+ const assignments = this.compileUpdateAssignments(ast.set, ast.table, ctx);
1484
+ const fromClause = this.compileUpdateFromClause(ast, ctx);
1416
1485
  const whereClause = this.compileWhere(ast.where, ctx);
1417
1486
  const returning = this.compileReturning(ast.returning, ctx);
1418
- return `UPDATE ${table} SET ${assignments}${whereClause}${returning}`;
1487
+ return `UPDATE ${target} SET ${assignments}${fromClause}${whereClause}${returning}`;
1419
1488
  }
1420
- compileUpdateAssignments(assignments, ctx) {
1489
+ compileUpdateAssignments(assignments, table, ctx) {
1421
1490
  return assignments.map((assignment) => {
1422
1491
  const col2 = assignment.column;
1423
- const target = this.quoteIdentifier(col2.name);
1492
+ const target = this.compileQualifiedColumn(col2, table);
1424
1493
  const value = this.compileOperand(assignment.value, ctx);
1425
1494
  return `${target} = ${value}`;
1426
1495
  }).join(", ");
1427
1496
  }
1497
+ compileQualifiedColumn(column, table) {
1498
+ const baseTableName = table.name;
1499
+ const alias = table.alias;
1500
+ const columnTable = column.table ?? alias ?? baseTableName;
1501
+ const tableQualifier = alias && column.table === baseTableName ? alias : columnTable;
1502
+ if (!tableQualifier) {
1503
+ return this.quoteIdentifier(column.name);
1504
+ }
1505
+ return `${this.quoteIdentifier(tableQualifier)}.${this.quoteIdentifier(column.name)}`;
1506
+ }
1428
1507
  compileDeleteAst(ast, ctx) {
1429
- const table = this.compileTableName(ast.from);
1508
+ const target = this.compileTableReference(ast.from);
1509
+ const usingClause = this.compileDeleteUsingClause(ast, ctx);
1430
1510
  const whereClause = this.compileWhere(ast.where, ctx);
1431
1511
  const returning = this.compileReturning(ast.returning, ctx);
1432
- return `DELETE FROM ${table}${whereClause}${returning}`;
1512
+ return `DELETE FROM ${target}${usingClause}${whereClause}${returning}`;
1433
1513
  }
1434
1514
  formatReturningColumns(returning) {
1435
1515
  return this.returningStrategy.formatReturningColumns(returning, this.quoteIdentifier.bind(this));
@@ -1484,6 +1564,38 @@ var SqlDialectBase = class extends Dialect {
1484
1564
  }
1485
1565
  return this.quoteIdentifier(table.name);
1486
1566
  }
1567
+ compileTableReference(table) {
1568
+ const base = this.compileTableName(table);
1569
+ return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
1570
+ }
1571
+ compileUpdateFromClause(ast, ctx) {
1572
+ if (!ast.from && (!ast.joins || ast.joins.length === 0)) return "";
1573
+ if (!ast.from) {
1574
+ throw new Error("UPDATE with JOINs requires an explicit FROM clause.");
1575
+ }
1576
+ const from = this.compileFrom(ast.from, ctx);
1577
+ const joins = JoinCompiler.compileJoins(
1578
+ ast.joins,
1579
+ ctx,
1580
+ this.compileFrom.bind(this),
1581
+ this.compileExpression.bind(this)
1582
+ );
1583
+ return ` FROM ${from}${joins}`;
1584
+ }
1585
+ compileDeleteUsingClause(ast, ctx) {
1586
+ if (!ast.using && (!ast.joins || ast.joins.length === 0)) return "";
1587
+ if (!ast.using) {
1588
+ throw new Error("DELETE with JOINs requires a USING clause.");
1589
+ }
1590
+ const usingTable = this.compileFrom(ast.using, ctx);
1591
+ const joins = JoinCompiler.compileJoins(
1592
+ ast.joins,
1593
+ ctx,
1594
+ this.compileFrom.bind(this),
1595
+ this.compileExpression.bind(this)
1596
+ );
1597
+ return ` USING ${usingTable}${joins}`;
1598
+ }
1487
1599
  compileHaving(ast, ctx) {
1488
1600
  if (!ast.having) return "";
1489
1601
  return ` HAVING ${this.compileExpression(ast.having, ctx)}`;
@@ -1864,6 +1976,9 @@ var SqliteDialect = class extends SqlDialectBase {
1864
1976
  const col2 = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
1865
1977
  return `json_extract(${col2}, '${node.path}')`;
1866
1978
  }
1979
+ compileQualifiedColumn(column, _table) {
1980
+ return this.quoteIdentifier(column.name);
1981
+ }
1867
1982
  compileReturning(returning, ctx) {
1868
1983
  if (!returning || returning.length === 0) return "";
1869
1984
  const columns = this.formatReturningColumns(returning);
@@ -1969,7 +2084,7 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1969
2084
  };
1970
2085
 
1971
2086
  // src/core/dialect/mssql/index.ts
1972
- var SqlServerDialect = class extends Dialect {
2087
+ var SqlServerDialect = class extends SqlDialectBase {
1973
2088
  /**
1974
2089
  * Creates a new SqlServerDialect instance
1975
2090
  */
@@ -2012,7 +2127,7 @@ var SqlServerDialect = class extends Dialect {
2012
2127
  const hasSetOps = !!(ast.setOps && ast.setOps.length);
2013
2128
  const ctes = this.compileCtes(ast, ctx);
2014
2129
  const baseAst = hasSetOps ? { ...ast, setOps: void 0, orderBy: void 0, limit: void 0, offset: void 0 } : ast;
2015
- const baseSelect = this.compileSelectCore(baseAst, ctx);
2130
+ const baseSelect = this.compileSelectCoreForMssql(baseAst, ctx);
2016
2131
  if (!hasSetOps) {
2017
2132
  return `${ctes}${baseSelect}`;
2018
2133
  }
@@ -2023,32 +2138,26 @@ var SqlServerDialect = class extends Dialect {
2023
2138
  const tail = pagination || orderBy;
2024
2139
  return `${ctes}${combined}${tail}`;
2025
2140
  }
2026
- compileInsertAst(ast, ctx) {
2027
- const table = this.quoteIdentifier(ast.into.name);
2028
- const columnList = ast.columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
2029
- const values = ast.values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
2030
- return `INSERT INTO ${table} (${columnList}) VALUES ${values};`;
2031
- }
2032
- compileUpdateAst(ast, ctx) {
2033
- const table = this.quoteIdentifier(ast.table.name);
2034
- const assignments = ast.set.map((assignment) => {
2035
- const col2 = assignment.column;
2036
- const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
2037
- const value = this.compileOperand(assignment.value, ctx);
2038
- return `${target} = ${value}`;
2039
- }).join(", ");
2040
- const whereClause = this.compileWhere(ast.where, ctx);
2041
- return `UPDATE ${table} SET ${assignments}${whereClause};`;
2042
- }
2043
2141
  compileDeleteAst(ast, ctx) {
2142
+ if (ast.using) {
2143
+ throw new Error("DELETE ... USING is not supported in the MSSQL dialect; use join() instead.");
2144
+ }
2044
2145
  if (ast.from.type !== "Table") {
2045
2146
  throw new Error("DELETE only supports base tables in the MSSQL dialect.");
2046
2147
  }
2047
- const table = this.quoteIdentifier(ast.from.name);
2148
+ const alias = ast.from.alias ?? ast.from.name;
2149
+ const target = this.compileTableReference(ast.from);
2150
+ const joins = JoinCompiler.compileJoins(
2151
+ ast.joins,
2152
+ ctx,
2153
+ this.compileFrom.bind(this),
2154
+ this.compileExpression.bind(this)
2155
+ );
2048
2156
  const whereClause = this.compileWhere(ast.where, ctx);
2049
- return `DELETE FROM ${table}${whereClause};`;
2157
+ const returning = this.compileReturning(ast.returning, ctx);
2158
+ return `DELETE ${this.quoteIdentifier(alias)} FROM ${target}${joins}${whereClause}${returning}`;
2050
2159
  }
2051
- compileSelectCore(ast, ctx) {
2160
+ compileSelectCoreForMssql(ast, ctx) {
2052
2161
  const columns = ast.columns.map((c) => {
2053
2162
  let expr = "";
2054
2163
  if (c.type === "Function") {
@@ -2067,9 +2176,9 @@ var SqlServerDialect = class extends Dialect {
2067
2176
  return expr;
2068
2177
  }).join(", ");
2069
2178
  const distinct = ast.distinct ? "DISTINCT " : "";
2070
- const from = this.compileTableSource(ast.from, ctx);
2179
+ const from = this.compileTableSource(ast.from);
2071
2180
  const joins = ast.joins.map((j) => {
2072
- const table = this.compileTableSource(j.table, ctx);
2181
+ const table = this.compileTableSource(j.table);
2073
2182
  const cond = this.compileExpression(j.condition, ctx);
2074
2183
  return `${j.kind} JOIN ${table} ON ${cond}`;
2075
2184
  }).join(" ");
@@ -2103,27 +2212,6 @@ var SqlServerDialect = class extends Dialect {
2103
2212
  }
2104
2213
  return pagination;
2105
2214
  }
2106
- renderOrderByNulls(order) {
2107
- return order.nulls ? ` NULLS ${order.nulls}` : "";
2108
- }
2109
- renderOrderByCollation(order) {
2110
- return order.collation ? ` COLLATE ${order.collation}` : "";
2111
- }
2112
- compileTableSource(table, ctx) {
2113
- if (table.type === "FunctionTable") {
2114
- return FunctionTableFormatter.format(table, ctx, this);
2115
- }
2116
- if (table.type === "DerivedTable") {
2117
- return this.compileDerivedTable(table, ctx);
2118
- }
2119
- const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
2120
- return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2121
- }
2122
- compileDerivedTable(table, ctx) {
2123
- const sub2 = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2124
- const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2125
- return `(${sub2}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
2126
- }
2127
2215
  compileCtes(ast, ctx) {
2128
2216
  if (!ast.ctes || ast.ctes.length === 0) return "";
2129
2217
  const defs = ast.ctes.map((cte) => {
@@ -2134,10 +2222,6 @@ var SqlServerDialect = class extends Dialect {
2134
2222
  }).join(", ");
2135
2223
  return `WITH ${defs} `;
2136
2224
  }
2137
- wrapSetOperand(sql) {
2138
- const trimmed = sql.trim().replace(/;$/, "");
2139
- return `(${trimmed})`;
2140
- }
2141
2225
  };
2142
2226
 
2143
2227
  // src/core/dialect/dialect-factory.ts
@@ -2964,7 +3048,7 @@ var QueryAstService = class {
2964
3048
  }
2965
3049
  normalizeOrderingTerm(term) {
2966
3050
  const from = this.state.ast.from;
2967
- const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3051
+ const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
2968
3052
  const termType = term?.type;
2969
3053
  if (termType === "Column") {
2970
3054
  return term;
@@ -2978,7 +3062,7 @@ var QueryAstService = class {
2978
3062
  if (termType === "BinaryExpression" || termType === "LogicalExpression" || termType === "NullExpression" || termType === "InExpression" || termType === "ExistsExpression" || termType === "BetweenExpression" || termType === "ArithmeticExpression") {
2979
3063
  return term;
2980
3064
  }
2981
- return buildColumnNode(tableRef, term);
3065
+ return buildColumnNode(tableRef2, term);
2982
3066
  }
2983
3067
  };
2984
3068
 
@@ -3384,8 +3468,8 @@ var ColumnSelector = class {
3384
3468
  */
3385
3469
  distinct(context, columns) {
3386
3470
  const from = context.state.ast.from;
3387
- const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
3388
- const nodes = columns.map((col2) => buildColumnNode(tableRef, col2));
3471
+ const tableRef2 = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
3472
+ const nodes = columns.map((col2) => buildColumnNode(tableRef2, col2));
3389
3473
  const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
3390
3474
  const nextState = astService.withDistinct(nodes);
3391
3475
  return { state: nextState, hydration: context.hydration };
@@ -3932,8 +4016,10 @@ var DefaultManyToManyCollection = class {
3932
4016
  attach(target) {
3933
4017
  const entity = this.ensureEntity(target);
3934
4018
  const id = this.extractId(entity);
3935
- if (id == null) return;
3936
- if (this.items.some((item) => this.extractId(item) === id)) {
4019
+ if (id != null && this.items.some((item) => this.extractId(item) === id)) {
4020
+ return;
4021
+ }
4022
+ if (id == null && this.items.includes(entity)) {
3937
4023
  return;
3938
4024
  }
3939
4025
  this.items.push(entity);
@@ -5256,15 +5342,36 @@ var InsertQueryState = class _InsertQueryState {
5256
5342
  type: "InsertQuery",
5257
5343
  into: createTableNode(table),
5258
5344
  columns: [],
5259
- values: []
5345
+ source: {
5346
+ type: "InsertValues",
5347
+ rows: []
5348
+ }
5260
5349
  };
5261
5350
  }
5262
5351
  clone(nextAst) {
5263
5352
  return new _InsertQueryState(this.table, nextAst);
5264
5353
  }
5354
+ ensureColumnsFromRow(rows) {
5355
+ if (this.ast.columns.length) return this.ast.columns;
5356
+ return buildColumnNodes(this.table, Object.keys(rows[0]));
5357
+ }
5358
+ appendValues(rows) {
5359
+ if (this.ast.source.type === "InsertValues") {
5360
+ return [...this.ast.source.rows, ...rows];
5361
+ }
5362
+ return rows;
5363
+ }
5364
+ getTableColumns() {
5365
+ const names = Object.keys(this.table.columns);
5366
+ if (!names.length) return [];
5367
+ return buildColumnNodes(this.table, names);
5368
+ }
5265
5369
  withValues(rows) {
5266
5370
  if (!rows.length) return this;
5267
- const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
5371
+ if (this.ast.source.type === "InsertSelect") {
5372
+ throw new Error("Cannot mix INSERT ... VALUES with INSERT ... SELECT source.");
5373
+ }
5374
+ const definedColumns = this.ensureColumnsFromRow(rows);
5268
5375
  const newRows = rows.map(
5269
5376
  (row, rowIndex) => definedColumns.map((column) => {
5270
5377
  const rawValue = row[column.name];
@@ -5279,7 +5386,34 @@ var InsertQueryState = class _InsertQueryState {
5279
5386
  return this.clone({
5280
5387
  ...this.ast,
5281
5388
  columns: definedColumns,
5282
- values: [...this.ast.values, ...newRows]
5389
+ source: {
5390
+ type: "InsertValues",
5391
+ rows: this.appendValues(newRows)
5392
+ }
5393
+ });
5394
+ }
5395
+ withColumns(columns) {
5396
+ if (!columns.length) return this;
5397
+ return this.clone({
5398
+ ...this.ast,
5399
+ columns: [...columns]
5400
+ });
5401
+ }
5402
+ withSelect(query, columns) {
5403
+ const targetColumns = columns.length ? columns : this.ast.columns.length ? this.ast.columns : this.getTableColumns();
5404
+ if (!targetColumns.length) {
5405
+ throw new Error("INSERT ... SELECT requires specifying destination columns.");
5406
+ }
5407
+ if (this.ast.source.type === "InsertValues" && this.ast.source.rows.length) {
5408
+ throw new Error("Cannot mix INSERT ... SELECT with INSERT ... VALUES source.");
5409
+ }
5410
+ return this.clone({
5411
+ ...this.ast,
5412
+ columns: [...targetColumns],
5413
+ source: {
5414
+ type: "InsertSelect",
5415
+ query
5416
+ }
5283
5417
  });
5284
5418
  }
5285
5419
  withReturning(columns) {
@@ -5304,11 +5438,27 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
5304
5438
  if (!rows.length) return this;
5305
5439
  return this.clone(this.state.withValues(rows));
5306
5440
  }
5441
+ columns(...columns) {
5442
+ if (!columns.length) return this;
5443
+ return this.clone(this.state.withColumns(this.resolveColumnNodes(columns)));
5444
+ }
5445
+ fromSelect(query, columns = []) {
5446
+ const ast = this.resolveSelectQuery(query);
5447
+ const nodes = columns.length ? this.resolveColumnNodes(columns) : [];
5448
+ return this.clone(this.state.withSelect(ast, nodes));
5449
+ }
5307
5450
  returning(...columns) {
5308
5451
  if (!columns.length) return this;
5309
5452
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5310
5453
  return this.clone(this.state.withReturning(nodes));
5311
5454
  }
5455
+ // Helpers for column/AST resolution
5456
+ resolveColumnNodes(columns) {
5457
+ return columns.map((column) => buildColumnNode(this.table, column));
5458
+ }
5459
+ resolveSelectQuery(query) {
5460
+ return typeof query.getAST === "function" ? query.getAST() : query;
5461
+ }
5312
5462
  compile(arg) {
5313
5463
  if (typeof arg.compileInsert === "function") {
5314
5464
  return arg.compileInsert(this.state.ast);
@@ -5342,7 +5492,8 @@ var UpdateQueryState = class _UpdateQueryState {
5342
5492
  this.ast = ast ?? {
5343
5493
  type: "UpdateQuery",
5344
5494
  table: createTableNode(table),
5345
- set: []
5495
+ set: [],
5496
+ joins: []
5346
5497
  };
5347
5498
  }
5348
5499
  clone(nextAst) {
@@ -5381,6 +5532,27 @@ var UpdateQueryState = class _UpdateQueryState {
5381
5532
  returning: [...columns]
5382
5533
  });
5383
5534
  }
5535
+ withFrom(from) {
5536
+ return this.clone({
5537
+ ...this.ast,
5538
+ from
5539
+ });
5540
+ }
5541
+ withJoin(join) {
5542
+ return this.clone({
5543
+ ...this.ast,
5544
+ joins: [...this.ast.joins ?? [], join]
5545
+ });
5546
+ }
5547
+ withTableAlias(alias) {
5548
+ return this.clone({
5549
+ ...this.ast,
5550
+ table: {
5551
+ ...this.ast.table,
5552
+ alias
5553
+ }
5554
+ });
5555
+ }
5384
5556
  };
5385
5557
 
5386
5558
  // src/query-builder/update.ts
@@ -5392,6 +5564,18 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5392
5564
  clone(state) {
5393
5565
  return new _UpdateQueryBuilder(this.table, state);
5394
5566
  }
5567
+ as(alias) {
5568
+ return this.clone(this.state.withTableAlias(alias));
5569
+ }
5570
+ from(source) {
5571
+ const tableSource = this.resolveTableSource(source);
5572
+ return this.clone(this.state.withFrom(tableSource));
5573
+ }
5574
+ join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
5575
+ const joinTarget = this.resolveJoinTarget(table);
5576
+ const joinNode = createJoinNode(kind, joinTarget, condition, relationName);
5577
+ return this.clone(this.state.withJoin(joinNode));
5578
+ }
5395
5579
  set(values) {
5396
5580
  return this.clone(this.state.withSet(values));
5397
5581
  }
@@ -5403,6 +5587,16 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5403
5587
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5404
5588
  return this.clone(this.state.withReturning(nodes));
5405
5589
  }
5590
+ resolveTableSource(source) {
5591
+ if (isTableSourceNode(source)) {
5592
+ return source;
5593
+ }
5594
+ return { type: "Table", name: source.name, schema: source.schema };
5595
+ }
5596
+ resolveJoinTarget(table) {
5597
+ if (typeof table === "string") return table;
5598
+ return this.resolveTableSource(table);
5599
+ }
5406
5600
  compile(arg) {
5407
5601
  if (typeof arg.compileUpdate === "function") {
5408
5602
  return arg.compileUpdate(this.state.ast);
@@ -5417,6 +5611,7 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5417
5611
  return this.state.ast;
5418
5612
  }
5419
5613
  };
5614
+ var isTableSourceNode = (source) => typeof source.type === "string";
5420
5615
 
5421
5616
  // src/query-builder/delete-query-state.ts
5422
5617
  var DeleteQueryState = class _DeleteQueryState {
@@ -5424,7 +5619,8 @@ var DeleteQueryState = class _DeleteQueryState {
5424
5619
  this.table = table;
5425
5620
  this.ast = ast ?? {
5426
5621
  type: "DeleteQuery",
5427
- from: createTableNode(table)
5622
+ from: createTableNode(table),
5623
+ joins: []
5428
5624
  };
5429
5625
  }
5430
5626
  clone(nextAst) {
@@ -5442,6 +5638,27 @@ var DeleteQueryState = class _DeleteQueryState {
5442
5638
  returning: [...columns]
5443
5639
  });
5444
5640
  }
5641
+ withUsing(source) {
5642
+ return this.clone({
5643
+ ...this.ast,
5644
+ using: source
5645
+ });
5646
+ }
5647
+ withJoin(join) {
5648
+ return this.clone({
5649
+ ...this.ast,
5650
+ joins: [...this.ast.joins ?? [], join]
5651
+ });
5652
+ }
5653
+ withTableAlias(alias) {
5654
+ return this.clone({
5655
+ ...this.ast,
5656
+ from: {
5657
+ ...this.ast.from,
5658
+ alias
5659
+ }
5660
+ });
5661
+ }
5445
5662
  };
5446
5663
 
5447
5664
  // src/query-builder/delete.ts
@@ -5456,11 +5673,32 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
5456
5673
  where(expr) {
5457
5674
  return this.clone(this.state.withWhere(expr));
5458
5675
  }
5676
+ as(alias) {
5677
+ return this.clone(this.state.withTableAlias(alias));
5678
+ }
5679
+ using(source) {
5680
+ return this.clone(this.state.withUsing(this.resolveTableSource(source)));
5681
+ }
5682
+ join(table, condition, kind = JOIN_KINDS.INNER, relationName) {
5683
+ const target = this.resolveJoinTarget(table);
5684
+ const joinNode = createJoinNode(kind, target, condition, relationName);
5685
+ return this.clone(this.state.withJoin(joinNode));
5686
+ }
5459
5687
  returning(...columns) {
5460
5688
  if (!columns.length) return this;
5461
5689
  const nodes = columns.map((column) => buildColumnNode(this.table, column));
5462
5690
  return this.clone(this.state.withReturning(nodes));
5463
5691
  }
5692
+ resolveTableSource(source) {
5693
+ if (isTableSourceNode2(source)) {
5694
+ return source;
5695
+ }
5696
+ return { type: "Table", name: source.name, schema: source.schema };
5697
+ }
5698
+ resolveJoinTarget(table) {
5699
+ if (typeof table === "string") return table;
5700
+ return this.resolveTableSource(table);
5701
+ }
5464
5702
  compile(arg) {
5465
5703
  if (typeof arg.compileDelete === "function") {
5466
5704
  return arg.compileDelete(this.state.ast);
@@ -5475,6 +5713,7 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
5475
5713
  return this.state.ast;
5476
5714
  }
5477
5715
  };
5716
+ var isTableSourceNode2 = (source) => typeof source.type === "string";
5478
5717
 
5479
5718
  // src/core/ddl/sql-writing.ts
5480
5719
  var resolvePrimaryKey = (table) => {
@@ -6823,9 +7062,13 @@ var TypeScriptGenerator = class {
6823
7062
  */
6824
7063
  printInExpression(inExpr) {
6825
7064
  const left2 = this.printOperand(inExpr.left);
6826
- const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
6827
7065
  const fn4 = this.mapOp(inExpr.operator);
6828
- return `${fn4}(${left2}, [${values}])`;
7066
+ if (Array.isArray(inExpr.right)) {
7067
+ const values = inExpr.right.map((v) => this.printOperand(v)).join(", ");
7068
+ return `${fn4}(${left2}, [${values}])`;
7069
+ }
7070
+ const subquery = this.inlineChain(this.buildSelectLines(inExpr.right.query));
7071
+ return `${fn4}(${left2}, (${subquery}))`;
6829
7072
  }
6830
7073
  /**
6831
7074
  * Prints a null expression to TypeScript code
@@ -7010,6 +7253,13 @@ var EntityStatus = /* @__PURE__ */ ((EntityStatus2) => {
7010
7253
 
7011
7254
  // src/orm/unit-of-work.ts
7012
7255
  var UnitOfWork = class {
7256
+ /**
7257
+ * Creates a new UnitOfWork instance.
7258
+ * @param dialect - The database dialect
7259
+ * @param executor - The database executor
7260
+ * @param identityMap - The identity map
7261
+ * @param hookContext - Function to get the hook context
7262
+ */
7013
7263
  constructor(dialect, executor, identityMap, hookContext) {
7014
7264
  this.dialect = dialect;
7015
7265
  this.executor = executor;
@@ -7017,21 +7267,50 @@ var UnitOfWork = class {
7017
7267
  this.hookContext = hookContext;
7018
7268
  this.trackedEntities = /* @__PURE__ */ new Map();
7019
7269
  }
7270
+ /**
7271
+ * Gets the identity buckets map.
7272
+ */
7020
7273
  get identityBuckets() {
7021
7274
  return this.identityMap.bucketsMap;
7022
7275
  }
7276
+ /**
7277
+ * Gets all tracked entities.
7278
+ * @returns Array of tracked entities
7279
+ */
7023
7280
  getTracked() {
7024
7281
  return Array.from(this.trackedEntities.values());
7025
7282
  }
7283
+ /**
7284
+ * Gets an entity by table and primary key.
7285
+ * @param table - The table definition
7286
+ * @param pk - The primary key value
7287
+ * @returns The entity or undefined if not found
7288
+ */
7026
7289
  getEntity(table, pk) {
7027
7290
  return this.identityMap.getEntity(table, pk);
7028
7291
  }
7292
+ /**
7293
+ * Gets all tracked entities for a specific table.
7294
+ * @param table - The table definition
7295
+ * @returns Array of tracked entities
7296
+ */
7029
7297
  getEntitiesForTable(table) {
7030
7298
  return this.identityMap.getEntitiesForTable(table);
7031
7299
  }
7300
+ /**
7301
+ * Finds a tracked entity.
7302
+ * @param entity - The entity to find
7303
+ * @returns The tracked entity or undefined if not found
7304
+ */
7032
7305
  findTracked(entity) {
7033
7306
  return this.trackedEntities.get(entity);
7034
7307
  }
7308
+ /**
7309
+ * Sets an entity in the identity map.
7310
+ * @param table - The table definition
7311
+ * @param pk - The primary key value
7312
+ * @param entity - The entity instance
7313
+ */
7035
7314
  setEntity(table, pk, entity) {
7036
7315
  if (pk === null || pk === void 0) return;
7037
7316
  let tracked = this.trackedEntities.get(entity);
@@ -7049,6 +7328,12 @@ var UnitOfWork = class {
7049
7328
  }
7050
7329
  this.registerIdentity(tracked);
7051
7330
  }
7331
+ /**
7332
+ * Tracks a new entity.
7333
+ * @param table - The table definition
7334
+ * @param entity - The entity instance
7335
+ * @param pk - Optional primary key value
7336
+ */
7052
7337
  trackNew(table, entity, pk) {
7053
7338
  const tracked = {
7054
7339
  table,
@@ -7062,6 +7347,12 @@ var UnitOfWork = class {
7062
7347
  this.registerIdentity(tracked);
7063
7348
  }
7064
7349
  }
7350
+ /**
7351
+ * Tracks a managed entity.
7352
+ * @param table - The table definition
7353
+ * @param pk - The primary key value
7354
+ * @param entity - The entity instance
7355
+ */
7065
7356
  trackManaged(table, pk, entity) {
7066
7357
  const tracked = {
7067
7358
  table,
@@ -7073,17 +7364,28 @@ var UnitOfWork = class {
7073
7364
  this.trackedEntities.set(entity, tracked);
7074
7365
  this.registerIdentity(tracked);
7075
7366
  }
7367
+ /**
7368
+ * Marks an entity as dirty (modified).
7369
+ * @param entity - The entity to mark as dirty
7370
+ */
7076
7371
  markDirty(entity) {
7077
7372
  const tracked = this.trackedEntities.get(entity);
7078
7373
  if (!tracked) return;
7079
7374
  if (tracked.status === "new" /* New */ || tracked.status === "removed" /* Removed */) return;
7080
7375
  tracked.status = "dirty" /* Dirty */;
7081
7376
  }
7377
+ /**
7378
+ * Marks an entity as removed.
7379
+ * @param entity - The entity to mark as removed
7380
+ */
7082
7381
  markRemoved(entity) {
7083
7382
  const tracked = this.trackedEntities.get(entity);
7084
7383
  if (!tracked) return;
7085
7384
  tracked.status = "removed" /* Removed */;
7086
7385
  }
7386
+ /**
7387
+ * Flushes pending changes to the database.
7388
+ */
7087
7389
  async flush() {
7088
7390
  const toFlush = Array.from(this.trackedEntities.values());
7089
7391
  for (const tracked of toFlush) {
@@ -7102,10 +7404,17 @@ var UnitOfWork = class {
7102
7404
  }
7103
7405
  }
7104
7406
  }
7407
+ /**
7408
+ * Resets the unit of work by clearing all tracked entities and identity map.
7409
+ */
7105
7410
  reset() {
7106
7411
  this.trackedEntities.clear();
7107
7412
  this.identityMap.clear();
7108
7413
  }
7414
+ /**
7415
+ * Flushes an insert operation for a new entity.
7416
+ * @param tracked - The tracked entity to insert
7417
+ */
7109
7418
  async flushInsert(tracked) {
7110
7419
  await this.runHook(tracked.table.hooks?.beforeInsert, tracked);
7111
7420
  const payload = this.extractColumns(tracked.table, tracked.entity);
@@ -7122,6 +7431,10 @@ var UnitOfWork = class {
7122
7431
  this.registerIdentity(tracked);
7123
7432
  await this.runHook(tracked.table.hooks?.afterInsert, tracked);
7124
7433
  }
7434
+ /**
7435
+ * Flushes an update operation for a modified entity.
7436
+ * @param tracked - The tracked entity to update
7437
+ */
7125
7438
  async flushUpdate(tracked) {
7126
7439
  if (tracked.pk == null) return;
7127
7440
  const changes = this.computeChanges(tracked);
@@ -7144,6 +7457,10 @@ var UnitOfWork = class {
7144
7457
  this.registerIdentity(tracked);
7145
7458
  await this.runHook(tracked.table.hooks?.afterUpdate, tracked);
7146
7459
  }
7460
+ /**
7461
+ * Flushes a delete operation for a removed entity.
7462
+ * @param tracked - The tracked entity to delete
7463
+ */
7147
7464
  async flushDelete(tracked) {
7148
7465
  if (tracked.pk == null) return;
7149
7466
  await this.runHook(tracked.table.hooks?.beforeDelete, tracked);
@@ -7157,10 +7474,20 @@ var UnitOfWork = class {
7157
7474
  this.identityMap.remove(tracked);
7158
7475
  await this.runHook(tracked.table.hooks?.afterDelete, tracked);
7159
7476
  }
7477
+ /**
7478
+ * Runs a table hook if defined.
7479
+ * @param hook - The hook function
7480
+ * @param tracked - The tracked entity
7481
+ */
7160
7482
  async runHook(hook, tracked) {
7161
7483
  if (!hook) return;
7162
7484
  await hook(this.hookContext(), tracked.entity);
7163
7485
  }
7486
+ /**
7487
+ * Computes changes between current entity state and original snapshot.
7488
+ * @param tracked - The tracked entity
7489
+ * @returns Object with changed column values
7490
+ */
7164
7491
  computeChanges(tracked) {
7165
7492
  const snapshot = tracked.original ?? {};
7166
7493
  const changes = {};
@@ -7172,6 +7499,12 @@ var UnitOfWork = class {
7172
7499
  }
7173
7500
  return changes;
7174
7501
  }
7502
+ /**
7503
+ * Extracts column values from an entity.
7504
+ * @param table - The table definition
7505
+ * @param entity - The entity instance
7506
+ * @returns Object with column values
7507
+ */
7175
7508
  extractColumns(table, entity) {
7176
7509
  const payload = {};
7177
7510
  for (const column of Object.keys(table.columns)) {
@@ -7180,9 +7513,19 @@ var UnitOfWork = class {
7180
7513
  }
7181
7514
  return payload;
7182
7515
  }
7516
+ /**
7517
+ * Executes a compiled query.
7518
+ * @param compiled - The compiled query
7519
+ * @returns Query results
7520
+ */
7183
7521
  async executeCompiled(compiled) {
7184
7522
  return this.executor.executeSql(compiled.sql, compiled.params);
7185
7523
  }
7524
+ /**
7525
+ * Gets columns for RETURNING clause.
7526
+ * @param table - The table definition
7527
+ * @returns Array of column nodes
7528
+ */
7186
7529
  getReturningColumns(table) {
7187
7530
  return Object.values(table.columns).map((column) => ({
7188
7531
  type: "Column",
@@ -7191,6 +7534,11 @@ var UnitOfWork = class {
7191
7534
  alias: column.name
7192
7535
  }));
7193
7536
  }
7537
+ /**
7538
+ * Applies RETURNING clause results to the tracked entity.
7539
+ * @param tracked - The tracked entity
7540
+ * @param results - Query results
7541
+ */
7194
7542
  applyReturningResults(tracked, results) {
7195
7543
  if (!this.dialect.supportsReturning()) return;
7196
7544
  const first = results[0];
@@ -7202,15 +7550,30 @@ var UnitOfWork = class {
7202
7550
  tracked.entity[columnName] = row[i];
7203
7551
  }
7204
7552
  }
7553
+ /**
7554
+ * Normalizes a column name by removing quotes and table prefixes.
7555
+ * @param column - The column name to normalize
7556
+ * @returns Normalized column name
7557
+ */
7205
7558
  normalizeColumnName(column) {
7206
7559
  const parts = column.split(".");
7207
7560
  const candidate = parts[parts.length - 1];
7208
7561
  return candidate.replace(/^["`[\]]+|["`[\]]+$/g, "");
7209
7562
  }
7563
+ /**
7564
+ * Registers an entity in the identity map.
7565
+ * @param tracked - The tracked entity to register
7566
+ */
7210
7567
  registerIdentity(tracked) {
7211
7568
  if (tracked.pk == null) return;
7212
7569
  this.identityMap.register(tracked);
7213
7570
  }
7571
+ /**
7572
+ * Creates a snapshot of an entity's current state.
7573
+ * @param table - The table definition
7574
+ * @param entity - The entity instance
7575
+ * @returns Object with entity state
7576
+ */
7214
7577
  createSnapshot(table, entity) {
7215
7578
  const snapshot = {};
7216
7579
  for (const column of Object.keys(table.columns)) {
@@ -7218,6 +7581,11 @@ var UnitOfWork = class {
7218
7581
  }
7219
7582
  return snapshot;
7220
7583
  }
7584
+ /**
7585
+ * Gets the primary key value from a tracked entity.
7586
+ * @param tracked - The tracked entity
7587
+ * @returns Primary key value or null
7588
+ */
7221
7589
  getPrimaryKeyValue(tracked) {
7222
7590
  const key = findPrimaryKey(tracked.table);
7223
7591
  const val = tracked.entity[key];
@@ -7228,6 +7596,10 @@ var UnitOfWork = class {
7228
7596
 
7229
7597
  // src/orm/domain-event-bus.ts
7230
7598
  var DomainEventBus = class {
7599
+ /**
7600
+ * Creates a new DomainEventBus instance.
7601
+ * @param initialHandlers - Optional initial event handlers
7602
+ */
7231
7603
  constructor(initialHandlers) {
7232
7604
  this.handlers = /* @__PURE__ */ new Map();
7233
7605
  if (initialHandlers) {
@@ -7238,15 +7610,32 @@ var DomainEventBus = class {
7238
7610
  }
7239
7611
  }
7240
7612
  }
7613
+ /**
7614
+ * Registers an event handler for a specific event type.
7615
+ * @template TType - The event type
7616
+ * @param type - The event type
7617
+ * @param handler - The event handler
7618
+ */
7241
7619
  on(type, handler) {
7242
7620
  const key = type;
7243
7621
  const existing = this.handlers.get(key) ?? [];
7244
7622
  existing.push(handler);
7245
7623
  this.handlers.set(key, existing);
7246
7624
  }
7625
+ /**
7626
+ * Registers an event handler for a specific event type (alias for on).
7627
+ * @template TType - The event type
7628
+ * @param type - The event type
7629
+ * @param handler - The event handler
7630
+ */
7247
7631
  register(type, handler) {
7248
7632
  this.on(type, handler);
7249
7633
  }
7634
+ /**
7635
+ * Dispatches domain events for tracked entities.
7636
+ * @param trackedEntities - Iterable of tracked entities
7637
+ * @param ctx - The context to pass to handlers
7638
+ */
7250
7639
  async dispatch(trackedEntities, ctx) {
7251
7640
  for (const tracked of trackedEntities) {
7252
7641
  const entity = tracked.entity;
@@ -7271,18 +7660,34 @@ var addDomainEvent = (entity, event) => {
7271
7660
 
7272
7661
  // src/orm/relation-change-processor.ts
7273
7662
  var RelationChangeProcessor = class {
7663
+ /**
7664
+ * Creates a new RelationChangeProcessor instance.
7665
+ * @param unitOfWork - The unit of work instance
7666
+ * @param dialect - The database dialect
7667
+ * @param executor - The database executor
7668
+ */
7274
7669
  constructor(unitOfWork, dialect, executor) {
7275
7670
  this.unitOfWork = unitOfWork;
7276
7671
  this.dialect = dialect;
7277
7672
  this.executor = executor;
7278
7673
  this.relationChanges = [];
7279
7674
  }
7675
+ /**
7676
+ * Registers a relation change for processing.
7677
+ * @param entry - The relation change entry
7678
+ */
7280
7679
  registerChange(entry) {
7281
7680
  this.relationChanges.push(entry);
7282
7681
  }
7682
+ /**
7683
+ * Resets the relation change processor by clearing all pending changes.
7684
+ */
7283
7685
  reset() {
7284
7686
  this.relationChanges.length = 0;
7285
7687
  }
7688
+ /**
7689
+ * Processes all pending relation changes.
7690
+ */
7286
7691
  async process() {
7287
7692
  if (!this.relationChanges.length) return;
7288
7693
  const entries = [...this.relationChanges];
@@ -7304,6 +7709,10 @@ var RelationChangeProcessor = class {
7304
7709
  }
7305
7710
  }
7306
7711
  }
7712
+ /**
7713
+ * Handles changes for has-many relations.
7714
+ * @param entry - The relation change entry
7715
+ */
7307
7716
  async handleHasManyChange(entry) {
7308
7717
  const relation = entry.relation;
7309
7718
  const target = entry.change.entity;
@@ -7322,6 +7731,10 @@ var RelationChangeProcessor = class {
7322
7731
  this.detachHasManyChild(tracked.entity, relation);
7323
7732
  }
7324
7733
  }
7734
+ /**
7735
+ * Handles changes for has-one relations.
7736
+ * @param entry - The relation change entry
7737
+ */
7325
7738
  async handleHasOneChange(entry) {
7326
7739
  const relation = entry.relation;
7327
7740
  const target = entry.change.entity;
@@ -7340,8 +7753,16 @@ var RelationChangeProcessor = class {
7340
7753
  this.detachHasOneChild(tracked.entity, relation);
7341
7754
  }
7342
7755
  }
7756
+ /**
7757
+ * Handles changes for belongs-to relations.
7758
+ * @param _entry - The relation change entry (reserved for future use)
7759
+ */
7343
7760
  async handleBelongsToChange(_entry) {
7344
7761
  }
7762
+ /**
7763
+ * Handles changes for belongs-to-many relations.
7764
+ * @param entry - The relation change entry
7765
+ */
7345
7766
  async handleBelongsToManyChange(entry) {
7346
7767
  const relation = entry.relation;
7347
7768
  const rootKey = relation.localKey || findPrimaryKey(entry.rootTable);
@@ -7360,11 +7781,22 @@ var RelationChangeProcessor = class {
7360
7781
  }
7361
7782
  }
7362
7783
  }
7784
+ /**
7785
+ * Assigns a foreign key for has-many relations.
7786
+ * @param child - The child entity
7787
+ * @param relation - The has-many relation
7788
+ * @param rootValue - The root entity's primary key value
7789
+ */
7363
7790
  assignHasManyForeignKey(child, relation, rootValue) {
7364
7791
  const current = child[relation.foreignKey];
7365
7792
  if (current === rootValue) return;
7366
7793
  child[relation.foreignKey] = rootValue;
7367
7794
  }
7795
+ /**
7796
+ * Detaches a child entity from has-many relations.
7797
+ * @param child - The child entity
7798
+ * @param relation - The has-many relation
7799
+ */
7368
7800
  detachHasManyChild(child, relation) {
7369
7801
  if (relation.cascade === "all" || relation.cascade === "remove") {
7370
7802
  this.unitOfWork.markRemoved(child);
@@ -7373,11 +7805,22 @@ var RelationChangeProcessor = class {
7373
7805
  child[relation.foreignKey] = null;
7374
7806
  this.unitOfWork.markDirty(child);
7375
7807
  }
7808
+ /**
7809
+ * Assigns a foreign key for has-one relations.
7810
+ * @param child - The child entity
7811
+ * @param relation - The has-one relation
7812
+ * @param rootValue - The root entity's primary key value
7813
+ */
7376
7814
  assignHasOneForeignKey(child, relation, rootValue) {
7377
7815
  const current = child[relation.foreignKey];
7378
7816
  if (current === rootValue) return;
7379
7817
  child[relation.foreignKey] = rootValue;
7380
7818
  }
7819
+ /**
7820
+ * Detaches a child entity from has-one relations.
7821
+ * @param child - The child entity
7822
+ * @param relation - The has-one relation
7823
+ */
7381
7824
  detachHasOneChild(child, relation) {
7382
7825
  if (relation.cascade === "all" || relation.cascade === "remove") {
7383
7826
  this.unitOfWork.markRemoved(child);
@@ -7386,6 +7829,12 @@ var RelationChangeProcessor = class {
7386
7829
  child[relation.foreignKey] = null;
7387
7830
  this.unitOfWork.markDirty(child);
7388
7831
  }
7832
+ /**
7833
+ * Inserts a pivot row for belongs-to-many relations.
7834
+ * @param relation - The belongs-to-many relation
7835
+ * @param rootId - The root entity's primary key value
7836
+ * @param targetId - The target entity's primary key value
7837
+ */
7389
7838
  async insertPivotRow(relation, rootId, targetId) {
7390
7839
  const payload = {
7391
7840
  [relation.pivotForeignKeyToRoot]: rootId,
@@ -7395,6 +7844,12 @@ var RelationChangeProcessor = class {
7395
7844
  const compiled = builder.compile(this.dialect);
7396
7845
  await this.executor.executeSql(compiled.sql, compiled.params);
7397
7846
  }
7847
+ /**
7848
+ * Deletes a pivot row for belongs-to-many relations.
7849
+ * @param relation - The belongs-to-many relation
7850
+ * @param rootId - The root entity's primary key value
7851
+ * @param targetId - The target entity's primary key value
7852
+ */
7398
7853
  async deletePivotRow(relation, rootId, targetId) {
7399
7854
  const rootCol = relation.pivotTable.columns[relation.pivotForeignKeyToRoot];
7400
7855
  const targetCol = relation.pivotTable.columns[relation.pivotForeignKeyToTarget];
@@ -7405,6 +7860,12 @@ var RelationChangeProcessor = class {
7405
7860
  const compiled = builder.compile(this.dialect);
7406
7861
  await this.executor.executeSql(compiled.sql, compiled.params);
7407
7862
  }
7863
+ /**
7864
+ * Resolves the primary key value from an entity.
7865
+ * @param entity - The entity
7866
+ * @param table - The table definition
7867
+ * @returns The primary key value or null
7868
+ */
7408
7869
  resolvePrimaryKeyValue(entity, table) {
7409
7870
  if (!entity) return null;
7410
7871
  const key = findPrimaryKey(table);
@@ -7420,42 +7881,231 @@ var createQueryLoggingExecutor = (executor, logger) => {
7420
7881
  return executor;
7421
7882
  }
7422
7883
  const wrapped = {
7884
+ capabilities: executor.capabilities,
7423
7885
  async executeSql(sql, params) {
7424
7886
  logger({ sql, params });
7425
7887
  return executor.executeSql(sql, params);
7426
- }
7888
+ },
7889
+ beginTransaction: () => executor.beginTransaction(),
7890
+ commitTransaction: () => executor.commitTransaction(),
7891
+ rollbackTransaction: () => executor.rollbackTransaction(),
7892
+ dispose: () => executor.dispose()
7427
7893
  };
7428
- if (executor.beginTransaction) {
7429
- wrapped.beginTransaction = executor.beginTransaction.bind(executor);
7430
- }
7431
- if (executor.commitTransaction) {
7432
- wrapped.commitTransaction = executor.commitTransaction.bind(executor);
7433
- }
7434
- if (executor.rollbackTransaction) {
7435
- wrapped.rollbackTransaction = executor.rollbackTransaction.bind(executor);
7436
- }
7437
7894
  return wrapped;
7438
7895
  };
7439
7896
 
7440
7897
  // src/orm/transaction-runner.ts
7441
7898
  var runInTransaction = async (executor, action) => {
7442
- if (!executor.beginTransaction) {
7899
+ if (!executor.capabilities.transactions) {
7443
7900
  await action();
7444
7901
  return;
7445
7902
  }
7446
7903
  await executor.beginTransaction();
7447
7904
  try {
7448
7905
  await action();
7449
- await executor.commitTransaction?.();
7906
+ await executor.commitTransaction();
7450
7907
  } catch (error) {
7451
- await executor.rollbackTransaction?.();
7908
+ await executor.rollbackTransaction();
7452
7909
  throw error;
7453
7910
  }
7454
7911
  };
7455
7912
 
7913
+ // src/orm/save-graph.ts
7914
+ var toKey8 = (value) => value === null || value === void 0 ? "" : String(value);
7915
+ var pickColumns = (table, payload) => {
7916
+ const columns = {};
7917
+ for (const key of Object.keys(table.columns)) {
7918
+ if (payload[key] !== void 0) {
7919
+ columns[key] = payload[key];
7920
+ }
7921
+ }
7922
+ return columns;
7923
+ };
7924
+ var ensureEntity = (session, table, payload) => {
7925
+ const pk = findPrimaryKey(table);
7926
+ const row = pickColumns(table, payload);
7927
+ const pkValue = payload[pk];
7928
+ if (pkValue !== void 0 && pkValue !== null) {
7929
+ const tracked = session.getEntity(table, pkValue);
7930
+ if (tracked) {
7931
+ return tracked;
7932
+ }
7933
+ if (row[pk] === void 0) {
7934
+ row[pk] = pkValue;
7935
+ }
7936
+ }
7937
+ return createEntityFromRow(session, table, row);
7938
+ };
7939
+ var assignColumns = (table, entity, payload) => {
7940
+ for (const key of Object.keys(table.columns)) {
7941
+ if (payload[key] !== void 0) {
7942
+ entity[key] = payload[key];
7943
+ }
7944
+ }
7945
+ };
7946
+ var isEntityInCollection = (items, pkName, entity) => {
7947
+ if (items.includes(entity)) return true;
7948
+ const entityPk = entity[pkName];
7949
+ if (entityPk === void 0 || entityPk === null) return false;
7950
+ return items.some((item) => toKey8(item[pkName]) === toKey8(entityPk));
7951
+ };
7952
+ var findInCollectionByPk = (items, pkName, pkValue) => {
7953
+ if (pkValue === void 0 || pkValue === null) return void 0;
7954
+ return items.find((item) => toKey8(item[pkName]) === toKey8(pkValue));
7955
+ };
7956
+ var handleHasMany = async (session, root, relationName, relation, payload, options) => {
7957
+ if (!Array.isArray(payload)) return;
7958
+ const collection = root[relationName];
7959
+ await collection.load();
7960
+ const targetTable = relation.target;
7961
+ const targetPk = findPrimaryKey(targetTable);
7962
+ const existing = collection.getItems();
7963
+ const seen = /* @__PURE__ */ new Set();
7964
+ for (const item of payload) {
7965
+ if (item === null || item === void 0) continue;
7966
+ const asObj = typeof item === "object" ? item : { [targetPk]: item };
7967
+ const pkValue = asObj[targetPk];
7968
+ const current = findInCollectionByPk(existing, targetPk, pkValue) ?? (pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) : void 0);
7969
+ const entity = current ?? ensureEntity(session, targetTable, asObj);
7970
+ assignColumns(targetTable, entity, asObj);
7971
+ await applyGraphToEntity(session, targetTable, entity, asObj, options);
7972
+ if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
7973
+ collection.attach(entity);
7974
+ }
7975
+ if (pkValue !== void 0 && pkValue !== null) {
7976
+ seen.add(toKey8(pkValue));
7977
+ }
7978
+ }
7979
+ if (options.pruneMissing) {
7980
+ for (const item of [...collection.getItems()]) {
7981
+ const pkValue = item[targetPk];
7982
+ if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
7983
+ collection.remove(item);
7984
+ }
7985
+ }
7986
+ }
7987
+ };
7988
+ var handleHasOne = async (session, root, relationName, relation, payload, options) => {
7989
+ const ref = root[relationName];
7990
+ if (payload === void 0) return;
7991
+ if (payload === null) {
7992
+ ref.set(null);
7993
+ return;
7994
+ }
7995
+ const pk = findPrimaryKey(relation.target);
7996
+ if (typeof payload === "number" || typeof payload === "string") {
7997
+ const entity = ref.set({ [pk]: payload });
7998
+ if (entity) {
7999
+ await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
8000
+ }
8001
+ return;
8002
+ }
8003
+ const attached = ref.set(payload);
8004
+ if (attached) {
8005
+ await applyGraphToEntity(session, relation.target, attached, payload, options);
8006
+ }
8007
+ };
8008
+ var handleBelongsTo = async (session, root, relationName, relation, payload, options) => {
8009
+ const ref = root[relationName];
8010
+ if (payload === void 0) return;
8011
+ if (payload === null) {
8012
+ ref.set(null);
8013
+ return;
8014
+ }
8015
+ const pk = relation.localKey || findPrimaryKey(relation.target);
8016
+ if (typeof payload === "number" || typeof payload === "string") {
8017
+ const entity = ref.set({ [pk]: payload });
8018
+ if (entity) {
8019
+ await applyGraphToEntity(session, relation.target, entity, { [pk]: payload }, options);
8020
+ }
8021
+ return;
8022
+ }
8023
+ const attached = ref.set(payload);
8024
+ if (attached) {
8025
+ await applyGraphToEntity(session, relation.target, attached, payload, options);
8026
+ }
8027
+ };
8028
+ var handleBelongsToMany = async (session, root, relationName, relation, payload, options) => {
8029
+ if (!Array.isArray(payload)) return;
8030
+ const collection = root[relationName];
8031
+ await collection.load();
8032
+ const targetTable = relation.target;
8033
+ const targetPk = relation.targetKey || findPrimaryKey(targetTable);
8034
+ const seen = /* @__PURE__ */ new Set();
8035
+ for (const item of payload) {
8036
+ if (item === null || item === void 0) continue;
8037
+ if (typeof item === "number" || typeof item === "string") {
8038
+ const id = item;
8039
+ collection.attach(id);
8040
+ seen.add(toKey8(id));
8041
+ continue;
8042
+ }
8043
+ const asObj = item;
8044
+ const pkValue = asObj[targetPk];
8045
+ const entity = pkValue !== void 0 && pkValue !== null ? session.getEntity(targetTable, pkValue) ?? ensureEntity(session, targetTable, asObj) : ensureEntity(session, targetTable, asObj);
8046
+ assignColumns(targetTable, entity, asObj);
8047
+ await applyGraphToEntity(session, targetTable, entity, asObj, options);
8048
+ if (!isEntityInCollection(collection.getItems(), targetPk, entity)) {
8049
+ collection.attach(entity);
8050
+ }
8051
+ if (pkValue !== void 0 && pkValue !== null) {
8052
+ seen.add(toKey8(pkValue));
8053
+ }
8054
+ }
8055
+ if (options.pruneMissing) {
8056
+ for (const item of [...collection.getItems()]) {
8057
+ const pkValue = item[targetPk];
8058
+ if (pkValue !== void 0 && pkValue !== null && !seen.has(toKey8(pkValue))) {
8059
+ collection.detach(item);
8060
+ }
8061
+ }
8062
+ }
8063
+ };
8064
+ var applyRelation = async (session, table, entity, relationName, relation, payload, options) => {
8065
+ switch (relation.type) {
8066
+ case RelationKinds.HasMany:
8067
+ return handleHasMany(session, entity, relationName, relation, payload, options);
8068
+ case RelationKinds.HasOne:
8069
+ return handleHasOne(session, entity, relationName, relation, payload, options);
8070
+ case RelationKinds.BelongsTo:
8071
+ return handleBelongsTo(session, entity, relationName, relation, payload, options);
8072
+ case RelationKinds.BelongsToMany:
8073
+ return handleBelongsToMany(session, entity, relationName, relation, payload, options);
8074
+ }
8075
+ };
8076
+ var applyGraphToEntity = async (session, table, entity, payload, options) => {
8077
+ assignColumns(table, entity, payload);
8078
+ for (const [relationName, relation] of Object.entries(table.relations)) {
8079
+ if (!(relationName in payload)) continue;
8080
+ await applyRelation(session, table, entity, relationName, relation, payload[relationName], options);
8081
+ }
8082
+ };
8083
+ var saveGraphInternal = async (session, entityClass, payload, options = {}) => {
8084
+ const table = getTableDefFromEntity(entityClass);
8085
+ if (!table) {
8086
+ throw new Error("Entity metadata has not been bootstrapped");
8087
+ }
8088
+ const root = ensureEntity(session, table, payload);
8089
+ await applyGraphToEntity(session, table, root, payload, options);
8090
+ return root;
8091
+ };
8092
+
7456
8093
  // src/orm/orm-session.ts
7457
8094
  var OrmSession = class {
8095
+ /**
8096
+ * Creates a new OrmSession instance.
8097
+ * @param opts - Session options
8098
+ */
7458
8099
  constructor(opts) {
8100
+ /**
8101
+ * Registers a relation change.
8102
+ * @param root - The root entity
8103
+ * @param relationKey - The relation key
8104
+ * @param rootTable - The root table definition
8105
+ * @param relationName - The relation name
8106
+ * @param relation - The relation definition
8107
+ * @param change - The relation change
8108
+ */
7459
8109
  this.registerRelationChange = (root, relationKey, rootTable, relationName, relation, change) => {
7460
8110
  this.relationChanges.registerChange(
7461
8111
  buildRelationChangeEntry(root, relationKey, rootTable, relationName, relation, change)
@@ -7469,42 +8119,117 @@ var OrmSession = class {
7469
8119
  this.relationChanges = new RelationChangeProcessor(this.unitOfWork, this.orm.dialect, this.executor);
7470
8120
  this.domainEvents = new DomainEventBus(opts.domainEventHandlers);
7471
8121
  }
8122
+ /**
8123
+ * Releases resources associated with this session (executor/pool leases) and resets tracking.
8124
+ * Must be safe to call multiple times.
8125
+ */
8126
+ async dispose() {
8127
+ try {
8128
+ await this.executor.dispose();
8129
+ } finally {
8130
+ this.unitOfWork.reset();
8131
+ this.relationChanges.reset();
8132
+ }
8133
+ }
8134
+ /**
8135
+ * Gets the database dialect.
8136
+ */
7472
8137
  get dialect() {
7473
8138
  return this.orm.dialect;
7474
8139
  }
8140
+ /**
8141
+ * Gets the identity buckets map.
8142
+ */
7475
8143
  get identityBuckets() {
7476
8144
  return this.unitOfWork.identityBuckets;
7477
8145
  }
8146
+ /**
8147
+ * Gets all tracked entities.
8148
+ */
7478
8149
  get tracked() {
7479
8150
  return this.unitOfWork.getTracked();
7480
8151
  }
8152
+ /**
8153
+ * Gets an entity by table and primary key.
8154
+ * @param table - The table definition
8155
+ * @param pk - The primary key value
8156
+ * @returns The entity or undefined if not found
8157
+ */
7481
8158
  getEntity(table, pk) {
7482
8159
  return this.unitOfWork.getEntity(table, pk);
7483
8160
  }
8161
+ /**
8162
+ * Sets an entity in the identity map.
8163
+ * @param table - The table definition
8164
+ * @param pk - The primary key value
8165
+ * @param entity - The entity instance
8166
+ */
7484
8167
  setEntity(table, pk, entity) {
7485
8168
  this.unitOfWork.setEntity(table, pk, entity);
7486
8169
  }
8170
+ /**
8171
+ * Tracks a new entity.
8172
+ * @param table - The table definition
8173
+ * @param entity - The entity instance
8174
+ * @param pk - Optional primary key value
8175
+ */
7487
8176
  trackNew(table, entity, pk) {
7488
8177
  this.unitOfWork.trackNew(table, entity, pk);
7489
8178
  }
8179
+ /**
8180
+ * Tracks a managed entity.
8181
+ * @param table - The table definition
8182
+ * @param pk - The primary key value
8183
+ * @param entity - The entity instance
8184
+ */
7490
8185
  trackManaged(table, pk, entity) {
7491
8186
  this.unitOfWork.trackManaged(table, pk, entity);
7492
8187
  }
8188
+ /**
8189
+ * Marks an entity as dirty (modified).
8190
+ * @param entity - The entity to mark as dirty
8191
+ */
7493
8192
  markDirty(entity) {
7494
8193
  this.unitOfWork.markDirty(entity);
7495
8194
  }
8195
+ /**
8196
+ * Marks an entity as removed.
8197
+ * @param entity - The entity to mark as removed
8198
+ */
7496
8199
  markRemoved(entity) {
7497
8200
  this.unitOfWork.markRemoved(entity);
7498
8201
  }
8202
+ /**
8203
+ * Gets all tracked entities for a specific table.
8204
+ * @param table - The table definition
8205
+ * @returns Array of tracked entities
8206
+ */
7499
8207
  getEntitiesForTable(table) {
7500
8208
  return this.unitOfWork.getEntitiesForTable(table);
7501
8209
  }
8210
+ /**
8211
+ * Registers an interceptor for flush lifecycle hooks.
8212
+ * @param interceptor - The interceptor to register
8213
+ */
7502
8214
  registerInterceptor(interceptor) {
7503
8215
  this.interceptors.push(interceptor);
7504
8216
  }
8217
+ /**
8218
+ * Registers a domain event handler.
8219
+ * @param type - The event type
8220
+ * @param handler - The event handler
8221
+ */
7505
8222
  registerDomainEventHandler(type, handler) {
7506
8223
  this.domainEvents.on(type, handler);
7507
8224
  }
8225
+ /**
8226
+ * Finds an entity by its primary key.
8227
+ * @template TCtor - The entity constructor type
8228
+ * @param entityClass - The entity constructor
8229
+ * @param id - The primary key value
8230
+ * @returns The entity instance or null if not found
8231
+ * @throws If entity metadata is not bootstrapped or table has no primary key
8232
+ */
7508
8233
  async find(entityClass, id) {
7509
8234
  const table = getTableDefFromEntity(entityClass);
7510
8235
  if (!table) {
@@ -7523,14 +8248,46 @@ var OrmSession = class {
7523
8248
  const rows = await executeHydrated(this, qb);
7524
8249
  return rows[0] ?? null;
7525
8250
  }
8251
+ /**
8252
+ * Finds a single entity using a query builder.
8253
+ * @template TTable - The table type
8254
+ * @param qb - The query builder
8255
+ * @returns The first entity instance or null if not found
8256
+ */
7526
8257
  async findOne(qb) {
7527
8258
  const limited = qb.limit(1);
7528
8259
  const rows = await executeHydrated(this, limited);
7529
8260
  return rows[0] ?? null;
7530
8261
  }
8262
+ /**
8263
+ * Finds multiple entities using a query builder.
8264
+ * @template TTable - The table type
8265
+ * @param qb - The query builder
8266
+ * @returns Array of entity instances
8267
+ */
7531
8268
  async findMany(qb) {
7532
8269
  return executeHydrated(this, qb);
7533
8270
  }
8271
+ /**
8272
+ * Saves an entity graph (root + nested relations) based on a DTO-like payload.
8273
+ * @param entityClass - Root entity constructor
8274
+ * @param payload - DTO payload containing column values and nested relations
8275
+ * @param options - Graph save options
8276
+ * @returns The root entity instance
8277
+ */
8278
+ async saveGraph(entityClass, payload, options) {
8279
+ const { transactional = true, ...graphOptions } = options ?? {};
8280
+ const execute = () => saveGraphInternal(this, entityClass, payload, graphOptions);
8281
+ if (!transactional) {
8282
+ return execute();
8283
+ }
8284
+ return this.transaction(() => execute());
8285
+ }
8286
+ /**
8287
+ * Persists an entity (either inserts or updates).
8288
+ * @param entity - The entity to persist
8289
+ * @throws If entity metadata is not bootstrapped
8290
+ */
7534
8291
  async persist(entity) {
7535
8292
  if (this.unitOfWork.findTracked(entity)) {
7536
8293
  return;
@@ -7547,12 +8304,22 @@ var OrmSession = class {
7547
8304
  this.trackNew(table, entity);
7548
8305
  }
7549
8306
  }
8307
+ /**
8308
+ * Marks an entity for removal.
8309
+ * @param entity - The entity to remove
8310
+ */
7550
8311
  async remove(entity) {
7551
8312
  this.markRemoved(entity);
7552
8313
  }
8314
+ /**
8315
+ * Flushes pending changes to the database.
8316
+ */
7553
8317
  async flush() {
7554
8318
  await this.unitOfWork.flush();
7555
8319
  }
8320
+ /**
8321
+ * Flushes pending changes with interceptors and relation processing.
8322
+ */
7556
8323
  async flushWithHooks() {
7557
8324
  for (const interceptor of this.interceptors) {
7558
8325
  await interceptor.beforeFlush?.(this);
@@ -7564,14 +8331,24 @@ var OrmSession = class {
7564
8331
  await interceptor.afterFlush?.(this);
7565
8332
  }
7566
8333
  }
8334
+ /**
8335
+ * Commits the current transaction.
8336
+ */
7567
8337
  async commit() {
7568
8338
  await runInTransaction(this.executor, async () => {
7569
8339
  await this.flushWithHooks();
7570
8340
  });
7571
8341
  await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
7572
8342
  }
8343
+ /**
8344
+ * Executes a function within a transaction.
8345
+ * @template T - The return type
8346
+ * @param fn - The function to execute
8347
+ * @returns The result of the function
8348
+ * @throws If the transaction fails
8349
+ */
7573
8350
  async transaction(fn4) {
7574
- if (!this.executor.beginTransaction) {
8351
+ if (!this.executor.capabilities.transactions) {
7575
8352
  const result = await fn4(this);
7576
8353
  await this.commit();
7577
8354
  return result;
@@ -7580,7 +8357,7 @@ var OrmSession = class {
7580
8357
  try {
7581
8358
  const result = await fn4(this);
7582
8359
  await this.flushWithHooks();
7583
- await this.executor.commitTransaction?.();
8360
+ await this.executor.commitTransaction();
7584
8361
  await this.domainEvents.dispatch(this.unitOfWork.getTracked(), this);
7585
8362
  return result;
7586
8363
  } catch (err) {
@@ -7588,11 +8365,20 @@ var OrmSession = class {
7588
8365
  throw err;
7589
8366
  }
7590
8367
  }
8368
+ /**
8369
+ * Rolls back the current transaction.
8370
+ */
7591
8371
  async rollback() {
7592
- await this.executor.rollbackTransaction?.();
8372
+ if (this.executor.capabilities.transactions) {
8373
+ await this.executor.rollbackTransaction();
8374
+ }
7593
8375
  this.unitOfWork.reset();
7594
8376
  this.relationChanges.reset();
7595
8377
  }
8378
+ /**
8379
+ * Gets the execution context.
8380
+ * @returns The execution context
8381
+ */
7596
8382
  getExecutionContext() {
7597
8383
  return {
7598
8384
  dialect: this.orm.dialect,
@@ -7600,6 +8386,10 @@ var OrmSession = class {
7600
8386
  interceptors: this.orm.interceptors
7601
8387
  };
7602
8388
  }
8389
+ /**
8390
+ * Gets the hydration context.
8391
+ * @returns The hydration context
8392
+ */
7603
8393
  getHydrationContext() {
7604
8394
  return {
7605
8395
  identityMap: this.identityMap,
@@ -7642,29 +8432,49 @@ var InterceptorPipeline = class {
7642
8432
 
7643
8433
  // src/orm/orm.ts
7644
8434
  var Orm = class {
8435
+ /**
8436
+ * Creates a new ORM instance.
8437
+ * @param opts - ORM options
8438
+ */
7645
8439
  constructor(opts) {
7646
8440
  this.dialect = opts.dialect;
7647
8441
  this.interceptors = opts.interceptors ?? new InterceptorPipeline();
7648
8442
  this.namingStrategy = opts.namingStrategy ?? new DefaultNamingStrategy();
7649
8443
  this.executorFactory = opts.executorFactory;
7650
8444
  }
7651
- createSession(options) {
7652
- const executor = this.executorFactory.createExecutor(options?.tx);
8445
+ /**
8446
+ * Creates a new ORM session.
8447
+ * @param options - Optional session options
8448
+ * @returns The ORM session
8449
+ */
8450
+ createSession() {
8451
+ const executor = this.executorFactory.createExecutor();
7653
8452
  return new OrmSession({ orm: this, executor });
7654
8453
  }
8454
+ /**
8455
+ * Executes a function within a transaction.
8456
+ * @template T - The return type
8457
+ * @param fn - The function to execute
8458
+ * @returns The result of the function
8459
+ * @throws If the transaction fails
8460
+ */
7655
8461
  async transaction(fn4) {
7656
8462
  const executor = this.executorFactory.createTransactionalExecutor();
7657
8463
  const session = new OrmSession({ orm: this, executor });
7658
8464
  try {
7659
- const result = await fn4(session);
7660
- await session.commit();
7661
- return result;
8465
+ return await session.transaction(() => fn4(session));
7662
8466
  } catch (err) {
7663
- await session.rollback();
7664
8467
  throw err;
7665
8468
  } finally {
8469
+ await session.dispose();
7666
8470
  }
7667
8471
  }
8472
+ /**
8473
+ * Shuts down the ORM and releases underlying resources (pools, timers).
8474
+ */
8475
+ async dispose() {
8476
+ await this.executorFactory.dispose();
8477
+ }
7668
8478
  };
7669
8479
 
7670
8480
  // src/decorators/decorator-metadata.ts
@@ -7923,18 +8733,245 @@ function rowsToQueryResult(rows) {
7923
8733
  return { columns, values };
7924
8734
  }
7925
8735
  function createExecutorFromQueryRunner(runner) {
8736
+ const supportsTransactions = typeof runner.beginTransaction === "function" && typeof runner.commitTransaction === "function" && typeof runner.rollbackTransaction === "function";
7926
8737
  return {
8738
+ capabilities: {
8739
+ transactions: supportsTransactions
8740
+ },
7927
8741
  async executeSql(sql, params) {
7928
8742
  const rows = await runner.query(sql, params);
7929
8743
  const result = rowsToQueryResult(rows);
7930
8744
  return [result];
7931
8745
  },
7932
- beginTransaction: runner.beginTransaction?.bind(runner),
7933
- commitTransaction: runner.commitTransaction?.bind(runner),
7934
- rollbackTransaction: runner.rollbackTransaction?.bind(runner)
8746
+ async beginTransaction() {
8747
+ if (!supportsTransactions) {
8748
+ throw new Error("Transactions are not supported by this executor");
8749
+ }
8750
+ await runner.beginTransaction.call(runner);
8751
+ },
8752
+ async commitTransaction() {
8753
+ if (!supportsTransactions) {
8754
+ throw new Error("Transactions are not supported by this executor");
8755
+ }
8756
+ await runner.commitTransaction.call(runner);
8757
+ },
8758
+ async rollbackTransaction() {
8759
+ if (!supportsTransactions) {
8760
+ throw new Error("Transactions are not supported by this executor");
8761
+ }
8762
+ await runner.rollbackTransaction.call(runner);
8763
+ },
8764
+ async dispose() {
8765
+ await runner.dispose?.call(runner);
8766
+ }
7935
8767
  };
7936
8768
  }
7937
8769
 
8770
+ // src/core/execution/pooling/pool.ts
8771
+ var deferred = () => {
8772
+ let resolve;
8773
+ let reject;
8774
+ const promise = new Promise((res, rej) => {
8775
+ resolve = res;
8776
+ reject = rej;
8777
+ });
8778
+ return { promise, resolve, reject };
8779
+ };
8780
+ var Pool = class {
8781
+ constructor(adapter, options) {
8782
+ this.destroyed = false;
8783
+ this.creating = 0;
8784
+ this.leased = 0;
8785
+ this.idle = [];
8786
+ this.waiters = [];
8787
+ this.reapTimer = null;
8788
+ if (!Number.isFinite(options.max) || options.max <= 0) {
8789
+ throw new Error("Pool options.max must be a positive number");
8790
+ }
8791
+ this.adapter = adapter;
8792
+ this.options = { max: options.max, ...options };
8793
+ const idleTimeout = this.options.idleTimeoutMillis;
8794
+ if (idleTimeout && idleTimeout > 0) {
8795
+ const interval = this.options.reapIntervalMillis ?? Math.max(1e3, Math.floor(idleTimeout / 2));
8796
+ this.reapTimer = setInterval(() => {
8797
+ void this.reapIdle();
8798
+ }, interval);
8799
+ this.reapTimer.unref?.();
8800
+ }
8801
+ const min2 = this.options.min ?? 0;
8802
+ if (min2 > 0) {
8803
+ void this.warm(min2);
8804
+ }
8805
+ }
8806
+ /**
8807
+ * Acquire a resource lease.
8808
+ * The returned lease MUST be released or destroyed.
8809
+ */
8810
+ async acquire() {
8811
+ if (this.destroyed) {
8812
+ throw new Error("Pool is destroyed");
8813
+ }
8814
+ const idle = await this.takeIdleValidated();
8815
+ if (idle) {
8816
+ this.leased++;
8817
+ return this.makeLease(idle);
8818
+ }
8819
+ if (this.totalLive() < this.options.max) {
8820
+ this.creating++;
8821
+ try {
8822
+ const created = await this.adapter.create();
8823
+ this.leased++;
8824
+ return this.makeLease(created);
8825
+ } finally {
8826
+ this.creating--;
8827
+ }
8828
+ }
8829
+ const waiter = deferred();
8830
+ this.waiters.push(waiter);
8831
+ const timeout = this.options.acquireTimeoutMillis;
8832
+ let timer = null;
8833
+ if (timeout && timeout > 0) {
8834
+ timer = setTimeout(() => {
8835
+ const idx = this.waiters.indexOf(waiter);
8836
+ if (idx >= 0) this.waiters.splice(idx, 1);
8837
+ waiter.reject(new Error("Pool acquire timeout"));
8838
+ }, timeout);
8839
+ timer.unref?.();
8840
+ }
8841
+ try {
8842
+ return await waiter.promise;
8843
+ } finally {
8844
+ if (timer) clearTimeout(timer);
8845
+ }
8846
+ }
8847
+ /** Destroy pool and all idle resources; waits for in-flight creations to settle. */
8848
+ async destroy() {
8849
+ if (this.destroyed) return;
8850
+ this.destroyed = true;
8851
+ if (this.reapTimer) {
8852
+ clearInterval(this.reapTimer);
8853
+ this.reapTimer = null;
8854
+ }
8855
+ while (this.waiters.length) {
8856
+ this.waiters.shift().reject(new Error("Pool destroyed"));
8857
+ }
8858
+ while (this.idle.length) {
8859
+ const entry = this.idle.shift();
8860
+ await this.adapter.destroy(entry.resource);
8861
+ }
8862
+ }
8863
+ totalLive() {
8864
+ return this.idle.length + this.leased + this.creating;
8865
+ }
8866
+ makeLease(resource) {
8867
+ let done = false;
8868
+ return {
8869
+ resource,
8870
+ release: async () => {
8871
+ if (done) return;
8872
+ done = true;
8873
+ await this.releaseResource(resource);
8874
+ },
8875
+ destroy: async () => {
8876
+ if (done) return;
8877
+ done = true;
8878
+ await this.destroyResource(resource);
8879
+ }
8880
+ };
8881
+ }
8882
+ async releaseResource(resource) {
8883
+ this.leased = Math.max(0, this.leased - 1);
8884
+ if (this.destroyed) {
8885
+ await this.adapter.destroy(resource);
8886
+ return;
8887
+ }
8888
+ const next = this.waiters.shift();
8889
+ if (next) {
8890
+ this.leased++;
8891
+ next.resolve(this.makeLease(resource));
8892
+ return;
8893
+ }
8894
+ this.idle.push({ resource, lastUsedAt: Date.now() });
8895
+ await this.trimToMinMax();
8896
+ }
8897
+ async destroyResource(resource) {
8898
+ this.leased = Math.max(0, this.leased - 1);
8899
+ await this.adapter.destroy(resource);
8900
+ if (!this.destroyed && this.waiters.length && this.totalLive() < this.options.max) {
8901
+ const waiter = this.waiters.shift();
8902
+ this.creating++;
8903
+ try {
8904
+ const created = await this.adapter.create();
8905
+ this.leased++;
8906
+ waiter.resolve(this.makeLease(created));
8907
+ } catch (err) {
8908
+ waiter.reject(err);
8909
+ } finally {
8910
+ this.creating--;
8911
+ }
8912
+ }
8913
+ }
8914
+ async takeIdleValidated() {
8915
+ while (this.idle.length) {
8916
+ const entry = this.idle.pop();
8917
+ if (!this.adapter.validate) {
8918
+ return entry.resource;
8919
+ }
8920
+ const ok = await this.adapter.validate(entry.resource);
8921
+ if (ok) {
8922
+ return entry.resource;
8923
+ }
8924
+ await this.adapter.destroy(entry.resource);
8925
+ }
8926
+ return null;
8927
+ }
8928
+ async reapIdle() {
8929
+ if (this.destroyed) return;
8930
+ const idleTimeout = this.options.idleTimeoutMillis;
8931
+ if (!idleTimeout || idleTimeout <= 0) return;
8932
+ const now2 = Date.now();
8933
+ const min2 = this.options.min ?? 0;
8934
+ const keep = [];
8935
+ const kill = [];
8936
+ for (const entry of this.idle) {
8937
+ const expired = now2 - entry.lastUsedAt >= idleTimeout;
8938
+ if (expired) kill.push(entry);
8939
+ else keep.push(entry);
8940
+ }
8941
+ while (keep.length < min2 && kill.length) {
8942
+ keep.push(kill.pop());
8943
+ }
8944
+ this.idle.length = 0;
8945
+ this.idle.push(...keep);
8946
+ for (const entry of kill) {
8947
+ await this.adapter.destroy(entry.resource);
8948
+ }
8949
+ }
8950
+ async warm(targetMin) {
8951
+ const min2 = Math.max(0, targetMin);
8952
+ while (!this.destroyed && this.idle.length < min2 && this.totalLive() < this.options.max) {
8953
+ this.creating++;
8954
+ try {
8955
+ const created = await this.adapter.create();
8956
+ this.idle.push({ resource: created, lastUsedAt: Date.now() });
8957
+ } catch {
8958
+ break;
8959
+ } finally {
8960
+ this.creating--;
8961
+ }
8962
+ }
8963
+ }
8964
+ async trimToMinMax() {
8965
+ const max2 = this.options.max;
8966
+ const min2 = this.options.min ?? 0;
8967
+ while (this.totalLive() > max2 && this.idle.length > min2) {
8968
+ const entry = this.idle.shift();
8969
+ if (!entry) break;
8970
+ await this.adapter.destroy(entry.resource);
8971
+ }
8972
+ }
8973
+ };
8974
+
7938
8975
  // src/core/execution/executors/postgres-executor.ts
7939
8976
  function createPostgresExecutor(client) {
7940
8977
  return createExecutorFromQueryRunner({
@@ -7956,7 +8993,11 @@ function createPostgresExecutor(client) {
7956
8993
 
7957
8994
  // src/core/execution/executors/mysql-executor.ts
7958
8995
  function createMysqlExecutor(client) {
8996
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
7959
8997
  return {
8998
+ capabilities: {
8999
+ transactions: supportsTransactions
9000
+ },
7960
9001
  async executeSql(sql, params) {
7961
9002
  const [rows] = await client.query(sql, params);
7962
9003
  if (!Array.isArray(rows)) {
@@ -7968,53 +9009,94 @@ function createMysqlExecutor(client) {
7968
9009
  return [result];
7969
9010
  },
7970
9011
  async beginTransaction() {
7971
- if (!client.beginTransaction) return;
9012
+ if (!supportsTransactions) {
9013
+ throw new Error("Transactions are not supported by this executor");
9014
+ }
7972
9015
  await client.beginTransaction();
7973
9016
  },
7974
9017
  async commitTransaction() {
7975
- if (!client.commit) return;
9018
+ if (!supportsTransactions) {
9019
+ throw new Error("Transactions are not supported by this executor");
9020
+ }
7976
9021
  await client.commit();
7977
9022
  },
7978
9023
  async rollbackTransaction() {
7979
- if (!client.rollback) return;
9024
+ if (!supportsTransactions) {
9025
+ throw new Error("Transactions are not supported by this executor");
9026
+ }
7980
9027
  await client.rollback();
9028
+ },
9029
+ async dispose() {
7981
9030
  }
7982
9031
  };
7983
9032
  }
7984
9033
 
7985
9034
  // src/core/execution/executors/sqlite-executor.ts
7986
9035
  function createSqliteExecutor(client) {
9036
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commitTransaction === "function" && typeof client.rollbackTransaction === "function";
7987
9037
  return {
9038
+ capabilities: {
9039
+ transactions: supportsTransactions
9040
+ },
7988
9041
  async executeSql(sql, params) {
7989
9042
  const rows = await client.all(sql, params);
7990
9043
  const result = rowsToQueryResult(rows);
7991
9044
  return [result];
7992
9045
  },
7993
- beginTransaction: client.beginTransaction?.bind(client),
7994
- commitTransaction: client.commitTransaction?.bind(client),
7995
- rollbackTransaction: client.rollbackTransaction?.bind(client)
9046
+ async beginTransaction() {
9047
+ if (!supportsTransactions) {
9048
+ throw new Error("Transactions are not supported by this executor");
9049
+ }
9050
+ await client.beginTransaction();
9051
+ },
9052
+ async commitTransaction() {
9053
+ if (!supportsTransactions) {
9054
+ throw new Error("Transactions are not supported by this executor");
9055
+ }
9056
+ await client.commitTransaction();
9057
+ },
9058
+ async rollbackTransaction() {
9059
+ if (!supportsTransactions) {
9060
+ throw new Error("Transactions are not supported by this executor");
9061
+ }
9062
+ await client.rollbackTransaction();
9063
+ },
9064
+ async dispose() {
9065
+ }
7996
9066
  };
7997
9067
  }
7998
9068
 
7999
9069
  // src/core/execution/executors/mssql-executor.ts
8000
9070
  function createMssqlExecutor(client) {
9071
+ const supportsTransactions = typeof client.beginTransaction === "function" && typeof client.commit === "function" && typeof client.rollback === "function";
8001
9072
  return {
9073
+ capabilities: {
9074
+ transactions: supportsTransactions
9075
+ },
8002
9076
  async executeSql(sql, params) {
8003
9077
  const { recordset } = await client.query(sql, params);
8004
9078
  const result = rowsToQueryResult(recordset ?? []);
8005
9079
  return [result];
8006
9080
  },
8007
9081
  async beginTransaction() {
8008
- if (!client.beginTransaction) return;
9082
+ if (!supportsTransactions) {
9083
+ throw new Error("Transactions are not supported by this executor");
9084
+ }
8009
9085
  await client.beginTransaction();
8010
9086
  },
8011
9087
  async commitTransaction() {
8012
- if (!client.commit) return;
9088
+ if (!supportsTransactions) {
9089
+ throw new Error("Transactions are not supported by this executor");
9090
+ }
8013
9091
  await client.commit();
8014
9092
  },
8015
9093
  async rollbackTransaction() {
8016
- if (!client.rollback) return;
9094
+ if (!supportsTransactions) {
9095
+ throw new Error("Transactions are not supported by this executor");
9096
+ }
8017
9097
  await client.rollback();
9098
+ },
9099
+ async dispose() {
8018
9100
  }
8019
9101
  };
8020
9102
  }
@@ -8083,6 +9165,86 @@ function createTediousExecutor(connection, module, options) {
8083
9165
  const client = createTediousMssqlClient(connection, module, options);
8084
9166
  return createMssqlExecutor(client);
8085
9167
  }
9168
+
9169
+ // src/orm/pooled-executor-factory.ts
9170
+ function createPooledExecutorFactory(opts) {
9171
+ const { pool, adapter } = opts;
9172
+ const makeExecutor = (mode) => {
9173
+ let lease = null;
9174
+ const getLease = async () => {
9175
+ if (lease) return lease;
9176
+ lease = await pool.acquire();
9177
+ return lease;
9178
+ };
9179
+ const executeWithConn = async (conn, sql, params) => {
9180
+ const rows = await adapter.query(conn, sql, params);
9181
+ return [rowsToQueryResult(rows)];
9182
+ };
9183
+ return {
9184
+ capabilities: { transactions: true },
9185
+ async executeSql(sql, params) {
9186
+ if (mode === "sticky") {
9187
+ const l2 = await getLease();
9188
+ return executeWithConn(l2.resource, sql, params);
9189
+ }
9190
+ if (lease) {
9191
+ return executeWithConn(lease.resource, sql, params);
9192
+ }
9193
+ const l = await pool.acquire();
9194
+ try {
9195
+ return await executeWithConn(l.resource, sql, params);
9196
+ } finally {
9197
+ await l.release();
9198
+ }
9199
+ },
9200
+ async beginTransaction() {
9201
+ const l = await getLease();
9202
+ await adapter.beginTransaction(l.resource);
9203
+ },
9204
+ async commitTransaction() {
9205
+ if (!lease) {
9206
+ throw new Error("commitTransaction called without an active transaction");
9207
+ }
9208
+ const l = lease;
9209
+ try {
9210
+ await adapter.commitTransaction(l.resource);
9211
+ } finally {
9212
+ lease = null;
9213
+ await l.release();
9214
+ }
9215
+ },
9216
+ async rollbackTransaction() {
9217
+ if (!lease) {
9218
+ return;
9219
+ }
9220
+ const l = lease;
9221
+ try {
9222
+ await adapter.rollbackTransaction(l.resource);
9223
+ } finally {
9224
+ lease = null;
9225
+ await l.release();
9226
+ }
9227
+ },
9228
+ async dispose() {
9229
+ if (!lease) return;
9230
+ const l = lease;
9231
+ lease = null;
9232
+ await l.release();
9233
+ }
9234
+ };
9235
+ };
9236
+ return {
9237
+ createExecutor() {
9238
+ return makeExecutor("session");
9239
+ },
9240
+ createTransactionalExecutor() {
9241
+ return makeExecutor("sticky");
9242
+ },
9243
+ async dispose() {
9244
+ await pool.destroy();
9245
+ }
9246
+ };
9247
+ }
8086
9248
  export {
8087
9249
  AsyncLocalStorage,
8088
9250
  BelongsTo,
@@ -8101,6 +9263,7 @@ export {
8101
9263
  MySqlDialect,
8102
9264
  Orm,
8103
9265
  OrmSession,
9266
+ Pool,
8104
9267
  PostgresDialect,
8105
9268
  PrimaryKey,
8106
9269
  RelationKinds,
@@ -8146,6 +9309,7 @@ export {
8146
9309
  createLiteral,
8147
9310
  createMssqlExecutor,
8148
9311
  createMysqlExecutor,
9312
+ createPooledExecutorFactory,
8149
9313
  createPostgresExecutor,
8150
9314
  createQueryLoggingExecutor,
8151
9315
  createSqliteExecutor,
@@ -8187,6 +9351,7 @@ export {
8187
9351
  hasOne,
8188
9352
  hydrateRows,
8189
9353
  inList,
9354
+ inSubquery,
8190
9355
  instr,
8191
9356
  introspectSchema,
8192
9357
  isCaseExpressionNode,
@@ -8227,6 +9392,7 @@ export {
8227
9392
  notBetween,
8228
9393
  notExists,
8229
9394
  notInList,
9395
+ notInSubquery,
8230
9396
  notLike,
8231
9397
  now,
8232
9398
  ntile,
@@ -8262,6 +9428,7 @@ export {
8262
9428
  substr,
8263
9429
  sum,
8264
9430
  synchronizeSchema,
9431
+ tableRef,
8265
9432
  tan,
8266
9433
  toColumnRef,
8267
9434
  toTableRef,