metal-orm 1.0.16 → 1.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +37 -40
  2. package/dist/decorators/index.cjs +344 -69
  3. package/dist/decorators/index.cjs.map +1 -1
  4. package/dist/decorators/index.d.cts +1 -1
  5. package/dist/decorators/index.d.ts +1 -1
  6. package/dist/decorators/index.js +344 -69
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +567 -181
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +66 -30
  11. package/dist/index.d.ts +66 -30
  12. package/dist/index.js +559 -181
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-BKZrMRCQ.d.cts → select-BuMpVcVt.d.cts} +265 -74
  15. package/dist/{select-BKZrMRCQ.d.ts → select-BuMpVcVt.d.ts} +265 -74
  16. package/package.json +5 -1
  17. package/src/codegen/naming-strategy.ts +15 -10
  18. package/src/core/ast/aggregate-functions.ts +50 -4
  19. package/src/core/ast/builders.ts +23 -3
  20. package/src/core/ast/expression-builders.ts +36 -16
  21. package/src/core/ast/expression-nodes.ts +17 -9
  22. package/src/core/ast/join-node.ts +5 -3
  23. package/src/core/ast/join.ts +16 -16
  24. package/src/core/ast/query.ts +44 -29
  25. package/src/core/ddl/dialects/mssql-schema-dialect.ts +18 -0
  26. package/src/core/ddl/dialects/mysql-schema-dialect.ts +11 -0
  27. package/src/core/ddl/dialects/postgres-schema-dialect.ts +9 -0
  28. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
  29. package/src/core/ddl/introspect/functions/postgres.ts +2 -6
  30. package/src/core/dialect/abstract.ts +12 -8
  31. package/src/core/dialect/base/sql-dialect.ts +58 -46
  32. package/src/core/dialect/mssql/functions.ts +24 -15
  33. package/src/core/dialect/mssql/index.ts +53 -28
  34. package/src/core/dialect/postgres/functions.ts +33 -24
  35. package/src/core/dialect/sqlite/functions.ts +19 -12
  36. package/src/core/dialect/sqlite/index.ts +22 -13
  37. package/src/core/functions/datetime.ts +2 -1
  38. package/src/core/functions/numeric.ts +2 -1
  39. package/src/core/functions/standard-strategy.ts +52 -12
  40. package/src/core/functions/text.ts +2 -1
  41. package/src/core/functions/types.ts +8 -8
  42. package/src/index.ts +5 -4
  43. package/src/orm/domain-event-bus.ts +43 -25
  44. package/src/orm/entity-meta.ts +40 -0
  45. package/src/orm/execution-context.ts +6 -0
  46. package/src/orm/hydration-context.ts +6 -4
  47. package/src/orm/orm-session.ts +35 -24
  48. package/src/orm/orm.ts +10 -10
  49. package/src/orm/query-logger.ts +15 -0
  50. package/src/orm/runtime-types.ts +60 -2
  51. package/src/orm/transaction-runner.ts +7 -0
  52. package/src/orm/unit-of-work.ts +1 -0
  53. package/src/query-builder/column-selector.ts +9 -7
  54. package/src/query-builder/insert-query-state.ts +13 -3
  55. package/src/query-builder/query-ast-service.ts +59 -38
  56. package/src/query-builder/relation-conditions.ts +38 -34
  57. package/src/query-builder/relation-manager.ts +8 -3
  58. package/src/query-builder/relation-service.ts +59 -46
  59. package/src/query-builder/select-helpers.ts +50 -0
  60. package/src/query-builder/select-query-state.ts +19 -7
  61. package/src/query-builder/select.ts +339 -167
  62. package/src/query-builder/update-query-state.ts +31 -9
  63. package/src/schema/column.ts +75 -39
  64. package/src/schema/types.ts +17 -6
package/dist/index.js CHANGED
@@ -88,6 +88,30 @@ var col = {
88
88
  * Creates a UUID column definition
89
89
  */
90
90
  uuid: () => ({ name: "", type: "UUID" }),
91
+ /**
92
+ * Creates a binary large object column definition
93
+ */
94
+ blob: () => ({ name: "", type: "BLOB" }),
95
+ /**
96
+ * Creates a fixed-length binary column definition
97
+ */
98
+ binary: (length2) => ({
99
+ name: "",
100
+ type: "BINARY",
101
+ args: length2 !== void 0 ? [length2] : void 0
102
+ }),
103
+ /**
104
+ * Creates a variable-length binary column definition
105
+ */
106
+ varbinary: (length2) => ({
107
+ name: "",
108
+ type: "VARBINARY",
109
+ args: length2 !== void 0 ? [length2] : void 0
110
+ }),
111
+ /**
112
+ * Creates a Postgres bytea column definition
113
+ */
114
+ bytea: () => ({ name: "", type: "BYTEA" }),
91
115
  /**
92
116
  * Creates a timestamp column definition
93
117
  */
@@ -237,10 +261,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
237
261
 
238
262
  // src/core/ast/expression-builders.ts
239
263
  var valueToOperand = (value) => {
240
- if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
241
- return { type: "Literal", value: value === void 0 ? null : value };
264
+ if (isOperandNode(value)) {
265
+ return value;
242
266
  }
243
- return value;
267
+ return {
268
+ type: "Literal",
269
+ value
270
+ };
244
271
  };
245
272
  var toNode = (col2) => {
246
273
  if (isOperandNode(col2)) return col2;
@@ -251,14 +278,20 @@ var toLiteralNode = (value) => ({
251
278
  type: "Literal",
252
279
  value
253
280
  });
281
+ var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
282
+ var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
254
283
  var toOperand = (val) => {
255
- if (val === null) return { type: "Literal", value: null };
256
- if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
257
- return { type: "Literal", value: val };
284
+ if (isLiteralValue(val)) {
285
+ return valueToOperand(val);
258
286
  }
259
287
  return toNode(val);
260
288
  };
261
289
  var columnOperand = (col2) => toNode(col2);
290
+ var outerRef = (col2) => ({
291
+ ...columnOperand(col2),
292
+ scope: "outer"
293
+ });
294
+ var correlateBy = (table, column) => outerRef({ name: column, table });
262
295
  var createBinaryExpression = (operator, left2, right2, escape) => {
263
296
  const node = {
264
297
  type: "BinaryExpression",
@@ -400,6 +433,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
400
433
  return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
401
434
  };
402
435
 
436
+ // src/core/sql/sql.ts
437
+ var SQL_OPERATORS = {
438
+ /** Equality operator */
439
+ EQUALS: "=",
440
+ /** Not equals operator */
441
+ NOT_EQUALS: "!=",
442
+ /** Greater than operator */
443
+ GREATER_THAN: ">",
444
+ /** Greater than or equal operator */
445
+ GREATER_OR_EQUAL: ">=",
446
+ /** Less than operator */
447
+ LESS_THAN: "<",
448
+ /** Less than or equal operator */
449
+ LESS_OR_EQUAL: "<=",
450
+ /** LIKE pattern matching operator */
451
+ LIKE: "LIKE",
452
+ /** NOT LIKE pattern matching operator */
453
+ NOT_LIKE: "NOT LIKE",
454
+ /** IN membership operator */
455
+ IN: "IN",
456
+ /** NOT IN membership operator */
457
+ NOT_IN: "NOT IN",
458
+ /** BETWEEN range operator */
459
+ BETWEEN: "BETWEEN",
460
+ /** NOT BETWEEN range operator */
461
+ NOT_BETWEEN: "NOT BETWEEN",
462
+ /** IS NULL null check operator */
463
+ IS_NULL: "IS NULL",
464
+ /** IS NOT NULL null check operator */
465
+ IS_NOT_NULL: "IS NOT NULL",
466
+ /** Logical AND operator */
467
+ AND: "AND",
468
+ /** Logical OR operator */
469
+ OR: "OR",
470
+ /** EXISTS operator */
471
+ EXISTS: "EXISTS",
472
+ /** NOT EXISTS operator */
473
+ NOT_EXISTS: "NOT EXISTS"
474
+ };
475
+ var JOIN_KINDS = {
476
+ /** INNER JOIN type */
477
+ INNER: "INNER",
478
+ /** LEFT JOIN type */
479
+ LEFT: "LEFT",
480
+ /** RIGHT JOIN type */
481
+ RIGHT: "RIGHT",
482
+ /** CROSS JOIN type */
483
+ CROSS: "CROSS"
484
+ };
485
+ var ORDER_DIRECTIONS = {
486
+ /** Ascending order */
487
+ ASC: "ASC",
488
+ /** Descending order */
489
+ DESC: "DESC"
490
+ };
491
+
403
492
  // src/core/ast/aggregate-functions.ts
404
493
  var buildAggregate = (name) => (col2) => ({
405
494
  type: "Function",
@@ -409,6 +498,20 @@ var buildAggregate = (name) => (col2) => ({
409
498
  var count = buildAggregate("COUNT");
410
499
  var sum = buildAggregate("SUM");
411
500
  var avg = buildAggregate("AVG");
501
+ var min = buildAggregate("MIN");
502
+ var max = buildAggregate("MAX");
503
+ var toOrderByNode = (order) => ({
504
+ type: "OrderBy",
505
+ column: columnOperand(order.column),
506
+ direction: order.direction ?? ORDER_DIRECTIONS.ASC
507
+ });
508
+ var groupConcat = (col2, options) => ({
509
+ type: "Function",
510
+ name: "GROUP_CONCAT",
511
+ args: [columnOperand(col2)],
512
+ orderBy: options?.orderBy?.map(toOrderByNode),
513
+ separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
514
+ });
412
515
 
413
516
  // src/core/ast/expression-visitor.ts
414
517
  var expressionDispatchers = /* @__PURE__ */ new Map();
@@ -499,13 +602,57 @@ var toTableRef = (table) => ({
499
602
  alias: table.alias
500
603
  });
501
604
 
605
+ // src/core/ast/builders.ts
606
+ var buildColumnNode = (table, column) => {
607
+ if (column.type === "Column") {
608
+ return column;
609
+ }
610
+ const def = column;
611
+ const baseTable = def.table ? table.alias && def.table === table.name ? table.alias : def.table : table.alias || table.name;
612
+ return {
613
+ type: "Column",
614
+ table: baseTable,
615
+ name: def.name
616
+ };
617
+ };
618
+ var buildColumnNodes = (table, names) => names.map((name) => ({
619
+ type: "Column",
620
+ table: table.alias || table.name,
621
+ name
622
+ }));
623
+ var createTableNode = (table) => ({
624
+ type: "Table",
625
+ name: table.name
626
+ });
627
+ var fnTable = (name, args = [], alias, opts) => ({
628
+ type: "FunctionTable",
629
+ name,
630
+ args,
631
+ alias,
632
+ lateral: opts?.lateral,
633
+ withOrdinality: opts?.withOrdinality,
634
+ columnAliases: opts?.columnAliases,
635
+ schema: opts?.schema
636
+ });
637
+ var derivedTable = (query, alias, columnAliases) => ({
638
+ type: "DerivedTable",
639
+ query,
640
+ alias,
641
+ columnAliases
642
+ });
643
+
502
644
  // src/core/functions/standard-strategy.ts
503
- var StandardFunctionStrategy = class {
645
+ var StandardFunctionStrategy = class _StandardFunctionStrategy {
504
646
  constructor() {
505
647
  this.renderers = /* @__PURE__ */ new Map();
506
648
  this.registerStandard();
507
649
  }
508
650
  registerStandard() {
651
+ this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
652
+ this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
653
+ this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
654
+ this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
655
+ this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
509
656
  this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
510
657
  this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
511
658
  this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
@@ -532,6 +679,7 @@ var StandardFunctionStrategy = class {
532
679
  this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
533
680
  this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
534
681
  this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
682
+ this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
535
683
  }
536
684
  add(name, renderer) {
537
685
  this.renderers.set(name, renderer);
@@ -539,6 +687,36 @@ var StandardFunctionStrategy = class {
539
687
  getRenderer(name) {
540
688
  return this.renderers.get(name);
541
689
  }
690
+ renderGroupConcat(ctx) {
691
+ const arg = ctx.compiledArgs[0];
692
+ const orderClause = this.buildOrderByExpression(ctx);
693
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
694
+ const separatorClause = this.formatGroupConcatSeparator(ctx);
695
+ return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
696
+ }
697
+ buildOrderByExpression(ctx) {
698
+ const orderBy = ctx.node.orderBy;
699
+ if (!orderBy || orderBy.length === 0) {
700
+ return "";
701
+ }
702
+ const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
703
+ return `ORDER BY ${parts.join(", ")}`;
704
+ }
705
+ formatGroupConcatSeparator(ctx) {
706
+ if (!ctx.node.separator) {
707
+ return "";
708
+ }
709
+ return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
710
+ }
711
+ getGroupConcatSeparatorOperand(ctx) {
712
+ return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
713
+ }
714
+ static {
715
+ this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
716
+ type: "Literal",
717
+ value: ","
718
+ };
719
+ }
542
720
  };
543
721
 
544
722
  // src/core/dialect/abstract.ts
@@ -885,7 +1063,11 @@ var Dialect = class _Dialect {
885
1063
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
886
1064
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
887
1065
  if (renderer) {
888
- return renderer({ node: fnNode, compiledArgs });
1066
+ return renderer({
1067
+ node: fnNode,
1068
+ compiledArgs,
1069
+ compileOperand: (operand) => this.compileOperand(operand, ctx)
1070
+ });
889
1071
  }
890
1072
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
891
1073
  }
@@ -1148,7 +1330,7 @@ var SqlDialectBase = class extends Dialect {
1148
1330
  return this.returningStrategy.compileReturning(returning, ctx);
1149
1331
  }
1150
1332
  compileInsertColumnList(columns) {
1151
- return columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
1333
+ return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
1152
1334
  }
1153
1335
  compileInsertValues(values, ctx) {
1154
1336
  return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
@@ -1174,7 +1356,7 @@ var SqlDialectBase = class extends Dialect {
1174
1356
  compileUpdateAssignments(assignments, ctx) {
1175
1357
  return assignments.map((assignment) => {
1176
1358
  const col2 = assignment.column;
1177
- const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
1359
+ const target = this.quoteIdentifier(col2.name);
1178
1360
  const value = this.compileOperand(assignment.value, ctx);
1179
1361
  return `${target} = ${value}`;
1180
1362
  }).join(", ");
@@ -1206,12 +1388,29 @@ var SqlDialectBase = class extends Dialect {
1206
1388
  if (tableSource.type === "FunctionTable") {
1207
1389
  return this.compileFunctionTable(tableSource, ctx);
1208
1390
  }
1391
+ if (tableSource.type === "DerivedTable") {
1392
+ return this.compileDerivedTable(tableSource, ctx);
1393
+ }
1209
1394
  return this.compileTableSource(tableSource);
1210
1395
  }
1211
1396
  compileFunctionTable(fn4, ctx) {
1212
1397
  return FunctionTableFormatter.format(fn4, ctx, this);
1213
1398
  }
1399
+ compileDerivedTable(table, ctx) {
1400
+ if (!table.alias) {
1401
+ throw new Error("Derived tables must have an alias.");
1402
+ }
1403
+ const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
1404
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
1405
+ return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
1406
+ }
1214
1407
  compileTableSource(table) {
1408
+ if (table.type === "FunctionTable") {
1409
+ return this.compileFunctionTable(table);
1410
+ }
1411
+ if (table.type === "DerivedTable") {
1412
+ return this.compileDerivedTable(table);
1413
+ }
1215
1414
  const base = this.compileTableName(table);
1216
1415
  return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
1217
1416
  }
@@ -1308,6 +1507,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
1308
1507
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1309
1508
  return `DATE_TRUNC('${partClean}', ${date})`;
1310
1509
  });
1510
+ this.add("GROUP_CONCAT", (ctx) => {
1511
+ const arg = ctx.compiledArgs[0];
1512
+ const orderClause = this.buildOrderByExpression(ctx);
1513
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
1514
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1515
+ const separator = ctx.compileOperand(separatorOperand);
1516
+ return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
1517
+ });
1311
1518
  }
1312
1519
  };
1313
1520
 
@@ -1552,6 +1759,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
1552
1759
  }
1553
1760
  return `date(${date}, 'start of ${partClean}')`;
1554
1761
  });
1762
+ this.add("GROUP_CONCAT", (ctx) => {
1763
+ const arg = ctx.compiledArgs[0];
1764
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1765
+ const separator = ctx.compileOperand(separatorOperand);
1766
+ return `GROUP_CONCAT(${arg}, ${separator})`;
1767
+ });
1555
1768
  }
1556
1769
  };
1557
1770
 
@@ -1586,6 +1799,12 @@ var SqliteDialect = class extends SqlDialectBase {
1586
1799
  const columns = this.formatReturningColumns(returning);
1587
1800
  return ` RETURNING ${columns}`;
1588
1801
  }
1802
+ formatReturningColumns(returning) {
1803
+ return returning.map((column) => {
1804
+ const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
1805
+ return `${this.quoteIdentifier(column.name)}${alias}`;
1806
+ }).join(", ");
1807
+ }
1589
1808
  supportsReturning() {
1590
1809
  return true;
1591
1810
  }
@@ -1668,6 +1887,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1668
1887
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1669
1888
  return `DATETRUNC(${partClean}, ${date})`;
1670
1889
  });
1890
+ this.add("GROUP_CONCAT", (ctx) => {
1891
+ const arg = ctx.compiledArgs[0];
1892
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1893
+ const separator = ctx.compileOperand(separatorOperand);
1894
+ const orderClause = this.buildOrderByExpression(ctx);
1895
+ const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
1896
+ return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
1897
+ });
1671
1898
  }
1672
1899
  };
1673
1900
 
@@ -1744,6 +1971,9 @@ var SqlServerDialect = class extends Dialect {
1744
1971
  return `UPDATE ${table} SET ${assignments}${whereClause};`;
1745
1972
  }
1746
1973
  compileDeleteAst(ast, ctx) {
1974
+ if (ast.from.type !== "Table") {
1975
+ throw new Error("DELETE only supports base tables in the MSSQL dialect.");
1976
+ }
1747
1977
  const table = this.quoteIdentifier(ast.from.name);
1748
1978
  const whereClause = this.compileWhere(ast.where, ctx);
1749
1979
  return `DELETE FROM ${table}${whereClause};`;
@@ -1767,9 +1997,9 @@ var SqlServerDialect = class extends Dialect {
1767
1997
  return expr;
1768
1998
  }).join(", ");
1769
1999
  const distinct = ast.distinct ? "DISTINCT " : "";
1770
- const from = `${this.quoteIdentifier(ast.from.name)}`;
2000
+ const from = this.compileTableSource(ast.from, ctx);
1771
2001
  const joins = ast.joins.map((j) => {
1772
- const table = this.quoteIdentifier(j.table.name);
2002
+ const table = this.compileTableSource(j.table, ctx);
1773
2003
  const cond = this.compileExpression(j.condition, ctx);
1774
2004
  return `${j.kind} JOIN ${table} ON ${cond}`;
1775
2005
  }).join(" ");
@@ -1799,6 +2029,21 @@ var SqlServerDialect = class extends Dialect {
1799
2029
  }
1800
2030
  return pagination;
1801
2031
  }
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
+ }
1802
2047
  compileCtes(ast, ctx) {
1803
2048
  if (!ast.ctes || ast.ctes.length === 0) return "";
1804
2049
  const defs = ast.ctes.map((cte) => {
@@ -1927,6 +2172,17 @@ var SelectQueryState = class _SelectQueryState {
1927
2172
  joins: [...this.ast.joins ?? [], join]
1928
2173
  });
1929
2174
  }
2175
+ /**
2176
+ * Replaces the FROM clause.
2177
+ * @param from - Table source for the FROM clause
2178
+ * @returns New SelectQueryState with updated FROM
2179
+ */
2180
+ withFrom(from) {
2181
+ return this.clone({
2182
+ ...this.ast,
2183
+ from
2184
+ });
2185
+ }
1930
2186
  /**
1931
2187
  * Adds a WHERE clause to the query
1932
2188
  * @param predicate - WHERE predicate expression
@@ -2037,62 +2293,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
2037
2293
  meta: relationName ? { relationName } : void 0
2038
2294
  });
2039
2295
 
2040
- // src/core/sql/sql.ts
2041
- var SQL_OPERATORS = {
2042
- /** Equality operator */
2043
- EQUALS: "=",
2044
- /** Not equals operator */
2045
- NOT_EQUALS: "!=",
2046
- /** Greater than operator */
2047
- GREATER_THAN: ">",
2048
- /** Greater than or equal operator */
2049
- GREATER_OR_EQUAL: ">=",
2050
- /** Less than operator */
2051
- LESS_THAN: "<",
2052
- /** Less than or equal operator */
2053
- LESS_OR_EQUAL: "<=",
2054
- /** LIKE pattern matching operator */
2055
- LIKE: "LIKE",
2056
- /** NOT LIKE pattern matching operator */
2057
- NOT_LIKE: "NOT LIKE",
2058
- /** IN membership operator */
2059
- IN: "IN",
2060
- /** NOT IN membership operator */
2061
- NOT_IN: "NOT IN",
2062
- /** BETWEEN range operator */
2063
- BETWEEN: "BETWEEN",
2064
- /** NOT BETWEEN range operator */
2065
- NOT_BETWEEN: "NOT BETWEEN",
2066
- /** IS NULL null check operator */
2067
- IS_NULL: "IS NULL",
2068
- /** IS NOT NULL null check operator */
2069
- IS_NOT_NULL: "IS NOT NULL",
2070
- /** Logical AND operator */
2071
- AND: "AND",
2072
- /** Logical OR operator */
2073
- OR: "OR",
2074
- /** EXISTS operator */
2075
- EXISTS: "EXISTS",
2076
- /** NOT EXISTS operator */
2077
- NOT_EXISTS: "NOT EXISTS"
2078
- };
2079
- var JOIN_KINDS = {
2080
- /** INNER JOIN type */
2081
- INNER: "INNER",
2082
- /** LEFT JOIN type */
2083
- LEFT: "LEFT",
2084
- /** RIGHT JOIN type */
2085
- RIGHT: "RIGHT",
2086
- /** CROSS JOIN type */
2087
- CROSS: "CROSS"
2088
- };
2089
- var ORDER_DIRECTIONS = {
2090
- /** Ascending order */
2091
- ASC: "ASC",
2092
- /** Descending order */
2093
- DESC: "DESC"
2094
- };
2095
-
2096
2296
  // src/query-builder/hydration-manager.ts
2097
2297
  var HydrationManager = class _HydrationManager {
2098
2298
  /**
@@ -2475,38 +2675,6 @@ var buildDefaultHydrationPlan = (table) => ({
2475
2675
  relations: []
2476
2676
  });
2477
2677
 
2478
- // src/core/ast/builders.ts
2479
- var buildColumnNode = (table, column) => {
2480
- if (column.type === "Column") {
2481
- return column;
2482
- }
2483
- const def = column;
2484
- return {
2485
- type: "Column",
2486
- table: def.table || table.name,
2487
- name: def.name
2488
- };
2489
- };
2490
- var buildColumnNodes = (table, names) => names.map((name) => ({
2491
- type: "Column",
2492
- table: table.name,
2493
- name
2494
- }));
2495
- var createTableNode = (table) => ({
2496
- type: "Table",
2497
- name: table.name
2498
- });
2499
- var fnTable = (name, args = [], alias, opts) => ({
2500
- type: "FunctionTable",
2501
- name,
2502
- args,
2503
- alias,
2504
- lateral: opts?.lateral,
2505
- withOrdinality: opts?.withOrdinality,
2506
- columnAliases: opts?.columnAliases,
2507
- schema: opts?.schema
2508
- });
2509
-
2510
2678
  // src/query-builder/raw-column-parser.ts
2511
2679
  var parseRawColumn = (col2, tableName, ctes) => {
2512
2680
  if (col2.includes("(")) {
@@ -2546,6 +2714,8 @@ var QueryAstService = class {
2546
2714
  const existingAliases = new Set(
2547
2715
  this.state.ast.columns.map((c) => c.alias || c.name)
2548
2716
  );
2717
+ const from = this.state.ast.from;
2718
+ const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
2549
2719
  const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
2550
2720
  if (existingAliases.has(alias)) return acc;
2551
2721
  if (isExpressionSelectionNode(val)) {
@@ -2553,9 +2723,10 @@ var QueryAstService = class {
2553
2723
  return acc;
2554
2724
  }
2555
2725
  const colDef = val;
2726
+ const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
2556
2727
  acc.push({
2557
2728
  type: "Column",
2558
- table: colDef.table || this.table.name,
2729
+ table: resolvedTable,
2559
2730
  name: colDef.name,
2560
2731
  alias
2561
2732
  });
@@ -2570,7 +2741,9 @@ var QueryAstService = class {
2570
2741
  * @returns Column selection result with updated state and added columns
2571
2742
  */
2572
2743
  selectRaw(cols) {
2573
- const newCols = cols.map((col2) => parseRawColumn(col2, this.table.name, this.state.ast.ctes));
2744
+ const from = this.state.ast.from;
2745
+ const defaultTable = from.type === "Table" && from.alias ? from.alias : this.table.name;
2746
+ const newCols = cols.map((col2) => parseRawColumn(col2, defaultTable, this.state.ast.ctes));
2574
2747
  const nextState = this.state.withColumns(newCols);
2575
2748
  return { state: nextState, addedColumns: newCols };
2576
2749
  }
@@ -2606,6 +2779,14 @@ var QueryAstService = class {
2606
2779
  };
2607
2780
  return this.state.withSetOperation(op);
2608
2781
  }
2782
+ /**
2783
+ * Replaces the FROM clause for the current query.
2784
+ * @param from - Table source to use in the FROM clause
2785
+ * @returns Updated query state with new FROM
2786
+ */
2787
+ withFrom(from) {
2788
+ return this.state.withFrom(from);
2789
+ }
2609
2790
  /**
2610
2791
  * Selects a subquery as a column
2611
2792
  * @param alias - Alias for the subquery
@@ -2639,7 +2820,9 @@ var QueryAstService = class {
2639
2820
  * @returns Updated query state with GROUP BY clause
2640
2821
  */
2641
2822
  withGroupBy(col2) {
2642
- const node = buildColumnNode(this.table, 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);
2643
2826
  return this.state.withGroupBy([node]);
2644
2827
  }
2645
2828
  /**
@@ -2658,7 +2841,9 @@ var QueryAstService = class {
2658
2841
  * @returns Updated query state with ORDER BY clause
2659
2842
  */
2660
2843
  withOrderBy(col2, direction) {
2661
- const node = buildColumnNode(this.table, col2);
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);
2662
2847
  return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
2663
2848
  }
2664
2849
  /**
@@ -2762,7 +2947,8 @@ var RelationProjectionHelper = class {
2762
2947
  var assertNever = (value) => {
2763
2948
  throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
2764
2949
  };
2765
- var baseRelationCondition = (root, relation) => {
2950
+ var baseRelationCondition = (root, relation, rootAlias) => {
2951
+ const rootTable = rootAlias || root.name;
2766
2952
  const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
2767
2953
  const localKey = relation.localKey || defaultLocalKey;
2768
2954
  switch (relation.type) {
@@ -2770,12 +2956,12 @@ var baseRelationCondition = (root, relation) => {
2770
2956
  case RelationKinds.HasOne:
2771
2957
  return eq(
2772
2958
  { type: "Column", table: relation.target.name, name: relation.foreignKey },
2773
- { type: "Column", table: root.name, name: localKey }
2959
+ { type: "Column", table: rootTable, name: localKey }
2774
2960
  );
2775
2961
  case RelationKinds.BelongsTo:
2776
2962
  return eq(
2777
2963
  { type: "Column", table: relation.target.name, name: localKey },
2778
- { type: "Column", table: root.name, name: relation.foreignKey }
2964
+ { type: "Column", table: rootTable, name: relation.foreignKey }
2779
2965
  );
2780
2966
  case RelationKinds.BelongsToMany:
2781
2967
  throw new Error("BelongsToMany relations do not support the standard join condition builder");
@@ -2783,12 +2969,13 @@ var baseRelationCondition = (root, relation) => {
2783
2969
  return assertNever(relation);
2784
2970
  }
2785
2971
  };
2786
- var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
2972
+ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
2787
2973
  const rootKey = relation.localKey || findPrimaryKey(root);
2788
2974
  const targetKey = relation.targetKey || findPrimaryKey(relation.target);
2975
+ const rootTable = rootAlias || root.name;
2789
2976
  const pivotCondition = eq(
2790
2977
  { type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
2791
- { type: "Column", table: root.name, name: rootKey }
2978
+ { type: "Column", table: rootTable, name: rootKey }
2792
2979
  );
2793
2980
  const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
2794
2981
  let targetCondition = eq(
@@ -2806,12 +2993,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
2806
2993
  );
2807
2994
  return [pivotJoin, targetJoin];
2808
2995
  };
2809
- var buildRelationJoinCondition = (root, relation, extra) => {
2810
- const base = baseRelationCondition(root, relation);
2996
+ var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
2997
+ const base = baseRelationCondition(root, relation, rootAlias);
2811
2998
  return extra ? and(base, extra) : base;
2812
2999
  };
2813
- var buildRelationCorrelation = (root, relation) => {
2814
- return baseRelationCondition(root, relation);
3000
+ var buildRelationCorrelation = (root, relation, rootAlias) => {
3001
+ return baseRelationCondition(root, relation, rootAlias);
2815
3002
  };
2816
3003
 
2817
3004
  // src/core/ast/join-metadata.ts
@@ -2855,7 +3042,7 @@ var RelationService = class {
2855
3042
  match(relationName, predicate) {
2856
3043
  const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
2857
3044
  const pk = findPrimaryKey(this.table);
2858
- const distinctCols = [{ type: "Column", table: this.table.name, name: pk }];
3045
+ const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
2859
3046
  const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
2860
3047
  const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
2861
3048
  return { state: nextState, hydration: joined.hydration };
@@ -2942,9 +3129,13 @@ var RelationService = class {
2942
3129
  * @param ast - Query AST to modify
2943
3130
  * @returns Modified query AST with relation correlation
2944
3131
  */
2945
- applyRelationCorrelation(relationName, ast) {
3132
+ applyRelationCorrelation(relationName, ast, additionalCorrelation) {
2946
3133
  const relation = this.getRelation(relationName);
2947
- const correlation = buildRelationCorrelation(this.table, relation);
3134
+ const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
3135
+ let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
3136
+ if (additionalCorrelation) {
3137
+ correlation = and(correlation, additionalCorrelation);
3138
+ }
2948
3139
  const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
2949
3140
  return {
2950
3141
  ...ast,
@@ -2961,17 +3152,19 @@ var RelationService = class {
2961
3152
  */
2962
3153
  withJoin(state, relationName, joinKind, extraCondition) {
2963
3154
  const relation = this.getRelation(relationName);
3155
+ const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
2964
3156
  if (relation.type === RelationKinds.BelongsToMany) {
2965
3157
  const joins = buildBelongsToManyJoins(
2966
3158
  this.table,
2967
3159
  relationName,
2968
3160
  relation,
2969
3161
  joinKind,
2970
- extraCondition
3162
+ extraCondition,
3163
+ rootAlias
2971
3164
  );
2972
3165
  return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
2973
3166
  }
2974
- const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
3167
+ const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
2975
3168
  const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
2976
3169
  return this.astService(state).withJoin(joinNode);
2977
3170
  }
@@ -3010,6 +3203,11 @@ var RelationService = class {
3010
3203
  astService(state = this.state) {
3011
3204
  return this.createQueryAstService(this.table, state);
3012
3205
  }
3206
+ rootTableName() {
3207
+ const from = this.state.ast.from;
3208
+ if (from.type === "Table" && from.alias) return from.alias;
3209
+ return this.table.name;
3210
+ }
3013
3211
  };
3014
3212
 
3015
3213
  // src/query-builder/select-query-builder-deps.ts
@@ -3084,7 +3282,9 @@ var ColumnSelector = class {
3084
3282
  * @returns Updated query context with DISTINCT clause
3085
3283
  */
3086
3284
  distinct(context, columns) {
3087
- const nodes = columns.map((col2) => buildColumnNode(this.env.table, col2));
3285
+ const from = context.state.ast.from;
3286
+ const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
3287
+ const nodes = columns.map((col2) => buildColumnNode(tableRef, col2));
3088
3288
  const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
3089
3289
  const nextState = astService.withDistinct(nodes);
3090
3290
  return { state: nextState, hydration: context.hydration };
@@ -3141,8 +3341,8 @@ var RelationManager = class {
3141
3341
  * @param ast - Query AST to modify
3142
3342
  * @returns Modified query AST with relation correlation
3143
3343
  */
3144
- applyRelationCorrelation(context, relationName, ast) {
3145
- return this.createService(context).applyRelationCorrelation(relationName, ast);
3344
+ applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
3345
+ return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
3146
3346
  }
3147
3347
  /**
3148
3348
  * Creates a relation service instance
@@ -4189,9 +4389,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4189
4389
  clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
4190
4390
  return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
4191
4391
  }
4392
+ /**
4393
+ * Applies an alias to the root FROM table.
4394
+ * @param alias - Alias to apply
4395
+ */
4396
+ as(alias) {
4397
+ const from = this.context.state.ast.from;
4398
+ if (from.type !== "Table") {
4399
+ throw new Error("Cannot alias non-table FROM sources");
4400
+ }
4401
+ const nextFrom = { ...from, alias };
4402
+ const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
4403
+ return this.clone(nextContext);
4404
+ }
4192
4405
  resolveQueryNode(query) {
4193
4406
  return typeof query.getAST === "function" ? query.getAST() : query;
4194
4407
  }
4408
+ applyCorrelation(ast, correlation) {
4409
+ if (!correlation) return ast;
4410
+ const combinedWhere = ast.where ? and(correlation, ast.where) : correlation;
4411
+ return {
4412
+ ...ast,
4413
+ where: combinedWhere
4414
+ };
4415
+ }
4195
4416
  createChildBuilder(table) {
4196
4417
  return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
4197
4418
  }
@@ -4220,6 +4441,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4220
4441
  select(columns) {
4221
4442
  return this.clone(this.columnSelector.select(this.context, columns));
4222
4443
  }
4444
+ /**
4445
+ * Selects columns from the root table by name (typed).
4446
+ * @param cols - Column names on the root table
4447
+ */
4448
+ selectColumns(...cols) {
4449
+ const selection = {};
4450
+ for (const key of cols) {
4451
+ const col2 = this.env.table.columns[key];
4452
+ if (!col2) {
4453
+ throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
4454
+ }
4455
+ selection[key] = col2;
4456
+ }
4457
+ return this.select(selection);
4458
+ }
4223
4459
  /**
4224
4460
 
4225
4461
  * Selects raw column expressions
@@ -4268,6 +4504,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4268
4504
  const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
4269
4505
  return this.clone(nextContext);
4270
4506
  }
4507
+ /**
4508
+ * Replaces the FROM clause with a derived table (subquery with alias)
4509
+ * @param subquery - Subquery to use as the FROM source
4510
+ * @param alias - Alias for the derived table
4511
+ * @param columnAliases - Optional column alias list
4512
+ * @returns New query builder instance with updated FROM
4513
+ */
4514
+ fromSubquery(subquery, alias, columnAliases) {
4515
+ const subAst = this.resolveQueryNode(subquery);
4516
+ const fromNode = derivedTable(subAst, alias, columnAliases);
4517
+ const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
4518
+ return this.clone(nextContext);
4519
+ }
4271
4520
  /**
4272
4521
 
4273
4522
  * Selects a subquery as a column
@@ -4283,6 +4532,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4283
4532
  const query = this.resolveQueryNode(sub);
4284
4533
  return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
4285
4534
  }
4535
+ /**
4536
+ * Adds a JOIN against a derived table (subquery with alias)
4537
+ * @param subquery - Subquery to join
4538
+ * @param alias - Alias for the derived table
4539
+ * @param condition - Join condition expression
4540
+ * @param joinKind - Join kind (defaults to INNER)
4541
+ * @param columnAliases - Optional column alias list for the derived table
4542
+ * @returns New query builder instance with the derived-table join
4543
+ */
4544
+ joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
4545
+ const subAst = this.resolveQueryNode(subquery);
4546
+ const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
4547
+ const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
4548
+ return this.clone(nextContext);
4549
+ }
4286
4550
  /**
4287
4551
 
4288
4552
  * Adds an INNER JOIN to the query
@@ -4380,6 +4644,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4380
4644
  nextLazy.add(relationName);
4381
4645
  return this.clone(this.context, nextLazy);
4382
4646
  }
4647
+ /**
4648
+ * Selects columns for a related table in a single hop.
4649
+ */
4650
+ selectRelationColumns(relationName, ...cols) {
4651
+ const relation = this.env.table.relations[relationName];
4652
+ if (!relation) {
4653
+ throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4654
+ }
4655
+ const target = relation.target;
4656
+ for (const col2 of cols) {
4657
+ if (!target.columns[col2]) {
4658
+ throw new Error(
4659
+ `Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
4660
+ );
4661
+ }
4662
+ }
4663
+ return this.include(relationName, { columns: cols });
4664
+ }
4665
+ /**
4666
+ * Convenience alias for selecting specific columns from a relation.
4667
+ */
4668
+ includePick(relationName, cols) {
4669
+ return this.selectRelationColumns(relationName, ...cols);
4670
+ }
4671
+ /**
4672
+ * Selects columns for the root table and relations from a single config object.
4673
+ */
4674
+ selectColumnsDeep(config) {
4675
+ let qb = this;
4676
+ if (config.root?.length) {
4677
+ qb = qb.selectColumns(...config.root);
4678
+ }
4679
+ for (const key of Object.keys(config)) {
4680
+ if (key === "root") continue;
4681
+ const relName = key;
4682
+ const cols = config[relName];
4683
+ if (!cols || !cols.length) continue;
4684
+ qb = qb.selectRelationColumns(relName, ...cols);
4685
+ }
4686
+ return qb;
4687
+ }
4383
4688
  getLazyRelations() {
4384
4689
  return Array.from(this.lazyRelations);
4385
4690
  }
@@ -4541,9 +4846,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4541
4846
  * @returns New query builder instance with the WHERE EXISTS condition
4542
4847
 
4543
4848
  */
4544
- whereExists(subquery) {
4849
+ whereExists(subquery, correlate) {
4545
4850
  const subAst = this.resolveQueryNode(subquery);
4546
- return this.where(exists(subAst));
4851
+ const correlated = this.applyCorrelation(subAst, correlate);
4852
+ return this.where(exists(correlated));
4547
4853
  }
4548
4854
  /**
4549
4855
 
@@ -4554,9 +4860,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4554
4860
  * @returns New query builder instance with the WHERE NOT EXISTS condition
4555
4861
 
4556
4862
  */
4557
- whereNotExists(subquery) {
4863
+ whereNotExists(subquery, correlate) {
4558
4864
  const subAst = this.resolveQueryNode(subquery);
4559
- return this.where(notExists(subAst));
4865
+ const correlated = this.applyCorrelation(subAst, correlate);
4866
+ return this.where(notExists(correlated));
4560
4867
  }
4561
4868
  /**
4562
4869
 
@@ -4569,17 +4876,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4569
4876
  * @returns New query builder instance with the relationship existence check
4570
4877
 
4571
4878
  */
4572
- whereHas(relationName, callback) {
4879
+ whereHas(relationName, callbackOrOptions, maybeOptions) {
4573
4880
  const relation = this.env.table.relations[relationName];
4574
4881
  if (!relation) {
4575
4882
  throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4576
4883
  }
4884
+ const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
4885
+ const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
4577
4886
  let subQb = this.createChildBuilder(relation.target);
4578
4887
  if (callback) {
4579
4888
  subQb = callback(subQb);
4580
4889
  }
4581
4890
  const subAst = subQb.getAST();
4582
- const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
4891
+ const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
4583
4892
  return this.where(exists(finalSubAst));
4584
4893
  }
4585
4894
  /**
@@ -4593,17 +4902,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4593
4902
  * @returns New query builder instance with the relationship non-existence check
4594
4903
 
4595
4904
  */
4596
- whereHasNot(relationName, callback) {
4905
+ whereHasNot(relationName, callbackOrOptions, maybeOptions) {
4597
4906
  const relation = this.env.table.relations[relationName];
4598
4907
  if (!relation) {
4599
4908
  throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4600
4909
  }
4910
+ const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
4911
+ const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
4601
4912
  let subQb = this.createChildBuilder(relation.target);
4602
4913
  if (callback) {
4603
4914
  subQb = callback(subQb);
4604
4915
  }
4605
4916
  const subAst = subQb.getAST();
4606
- const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
4917
+ const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
4607
4918
  return this.where(notExists(finalSubAst));
4608
4919
  }
4609
4920
  /**
@@ -4655,6 +4966,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4655
4966
  var createColumn = (table, name) => ({ type: "Column", table, name });
4656
4967
  var createLiteral = (val) => ({ type: "Literal", value: val });
4657
4968
 
4969
+ // src/orm/entity-metadata.ts
4970
+ var metadataMap = /* @__PURE__ */ new Map();
4971
+ var getEntityMetadata = (target) => {
4972
+ return metadataMap.get(target);
4973
+ };
4974
+
4975
+ // src/decorators/bootstrap.ts
4976
+ var getTableDefFromEntity = (ctor) => {
4977
+ const meta = getEntityMetadata(ctor);
4978
+ if (!meta) return void 0;
4979
+ return meta.table;
4980
+ };
4981
+ var selectFromEntity = (ctor) => {
4982
+ const table = getTableDefFromEntity(ctor);
4983
+ if (!table) {
4984
+ throw new Error("Entity metadata has not been bootstrapped");
4985
+ }
4986
+ return new SelectQueryBuilder(table);
4987
+ };
4988
+
4989
+ // src/query-builder/select-helpers.ts
4990
+ function sel(table, ...cols) {
4991
+ const selection = {};
4992
+ for (const col2 of cols) {
4993
+ const def = table.columns[col2];
4994
+ if (!def) {
4995
+ throw new Error(`Column '${col2}' not found on table '${table.name}'`);
4996
+ }
4997
+ selection[col2] = def;
4998
+ }
4999
+ return selection;
5000
+ }
5001
+ function esel(entity, ...props) {
5002
+ const table = getTableDefFromEntity(entity);
5003
+ if (!table) {
5004
+ throw new Error(`No table definition registered for entity '${entity.name}'`);
5005
+ }
5006
+ const selection = {};
5007
+ for (const prop of props) {
5008
+ const col2 = table.columns[prop];
5009
+ if (!col2) {
5010
+ throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
5011
+ }
5012
+ selection[prop] = col2;
5013
+ }
5014
+ return selection;
5015
+ }
5016
+
4658
5017
  // src/query-builder/insert-query-state.ts
4659
5018
  var InsertQueryState = class _InsertQueryState {
4660
5019
  constructor(table, ast) {
@@ -4673,7 +5032,15 @@ var InsertQueryState = class _InsertQueryState {
4673
5032
  if (!rows.length) return this;
4674
5033
  const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
4675
5034
  const newRows = rows.map(
4676
- (row) => definedColumns.map((column) => valueToOperand(row[column.name]))
5035
+ (row, rowIndex) => definedColumns.map((column) => {
5036
+ const rawValue = row[column.name];
5037
+ if (!isValueOperandInput(rawValue)) {
5038
+ throw new Error(
5039
+ `Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
5040
+ );
5041
+ }
5042
+ return valueToOperand(rawValue);
5043
+ })
4677
5044
  );
4678
5045
  return this.clone({
4679
5046
  ...this.ast,
@@ -4724,6 +5091,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
4724
5091
  };
4725
5092
 
4726
5093
  // src/query-builder/update-query-state.ts
5094
+ var isUpdateValue = (value) => {
5095
+ if (value === null) return true;
5096
+ switch (typeof value) {
5097
+ case "string":
5098
+ case "number":
5099
+ case "boolean":
5100
+ return true;
5101
+ default:
5102
+ return isOperandNode(value);
5103
+ }
5104
+ };
4727
5105
  var UpdateQueryState = class _UpdateQueryState {
4728
5106
  constructor(table, ast) {
4729
5107
  this.table = table;
@@ -4737,14 +5115,21 @@ var UpdateQueryState = class _UpdateQueryState {
4737
5115
  return new _UpdateQueryState(this.table, nextAst);
4738
5116
  }
4739
5117
  withSet(values) {
4740
- const assignments = Object.entries(values).map(([column, value]) => ({
4741
- column: {
4742
- type: "Column",
4743
- table: this.table.name,
4744
- name: column
4745
- },
4746
- value: valueToOperand(value)
4747
- }));
5118
+ const assignments = Object.entries(values).map(([column, rawValue]) => {
5119
+ if (!isUpdateValue(rawValue)) {
5120
+ throw new Error(
5121
+ `Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
5122
+ );
5123
+ }
5124
+ return {
5125
+ column: {
5126
+ type: "Column",
5127
+ table: this.table.name,
5128
+ name: column
5129
+ },
5130
+ value: valueToOperand(rawValue)
5131
+ };
5132
+ });
4748
5133
  return this.clone({
4749
5134
  ...this.ast,
4750
5135
  set: assignments
@@ -5953,7 +6338,7 @@ var DefaultNamingStrategy = class {
5953
6338
  * @returns Capitalized table name (handles schema-qualified names)
5954
6339
  */
5955
6340
  tableToSymbol(table) {
5956
- const tableName = typeof table === "string" ? table : table.name;
6341
+ const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.name;
5957
6342
  if (tableName.includes(".")) {
5958
6343
  return tableName.split(".").map((part) => this.capitalize(part)).join("");
5959
6344
  }
@@ -6012,8 +6397,8 @@ var TypeScriptGenerator = class {
6012
6397
  return `${key}: ${this.printOperand(operand)}`;
6013
6398
  });
6014
6399
  lines.push(`db.select({`);
6015
- selections.forEach((sel, index) => {
6016
- lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
6400
+ selections.forEach((sel2, index) => {
6401
+ lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
6017
6402
  });
6018
6403
  lines.push(`})`);
6019
6404
  lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
@@ -6296,26 +6681,6 @@ var TypeScriptGenerator = class {
6296
6681
  }
6297
6682
  };
6298
6683
 
6299
- // src/orm/entity-metadata.ts
6300
- var metadataMap = /* @__PURE__ */ new Map();
6301
- var getEntityMetadata = (target) => {
6302
- return metadataMap.get(target);
6303
- };
6304
-
6305
- // src/decorators/bootstrap.ts
6306
- var getTableDefFromEntity = (ctor) => {
6307
- const meta = getEntityMetadata(ctor);
6308
- if (!meta) return void 0;
6309
- return meta.table;
6310
- };
6311
- var selectFromEntity = (ctor) => {
6312
- const table = getTableDefFromEntity(ctor);
6313
- if (!table) {
6314
- throw new Error("Entity metadata has not been bootstrapped");
6315
- }
6316
- return new SelectQueryBuilder(table);
6317
- };
6318
-
6319
6684
  // src/orm/identity-map.ts
6320
6685
  var IdentityMap = class {
6321
6686
  constructor() {
@@ -6528,6 +6893,7 @@ var UnitOfWork = class {
6528
6893
  extractColumns(table, entity) {
6529
6894
  const payload = {};
6530
6895
  for (const column of Object.keys(table.columns)) {
6896
+ if (entity[column] === void 0) continue;
6531
6897
  payload[column] = entity[column];
6532
6898
  }
6533
6899
  return payload;
@@ -6582,24 +6948,30 @@ var UnitOfWork = class {
6582
6948
  var DomainEventBus = class {
6583
6949
  constructor(initialHandlers) {
6584
6950
  this.handlers = /* @__PURE__ */ new Map();
6585
- const handlers = initialHandlers ?? {};
6586
- Object.entries(handlers).forEach(([name, list]) => {
6587
- this.handlers.set(name, [...list]);
6588
- });
6951
+ if (initialHandlers) {
6952
+ for (const key in initialHandlers) {
6953
+ const type = key;
6954
+ const list = initialHandlers[type] ?? [];
6955
+ this.handlers.set(type, [...list]);
6956
+ }
6957
+ }
6589
6958
  }
6590
- register(name, handler) {
6591
- const existing = this.handlers.get(name) ?? [];
6959
+ on(type, handler) {
6960
+ const key = type;
6961
+ const existing = this.handlers.get(key) ?? [];
6592
6962
  existing.push(handler);
6593
- this.handlers.set(name, existing);
6963
+ this.handlers.set(key, existing);
6964
+ }
6965
+ register(type, handler) {
6966
+ this.on(type, handler);
6594
6967
  }
6595
6968
  async dispatch(trackedEntities, ctx) {
6596
6969
  for (const tracked of trackedEntities) {
6597
6970
  const entity = tracked.entity;
6598
- if (!entity.domainEvents || !entity.domainEvents.length) continue;
6971
+ if (!entity.domainEvents?.length) continue;
6599
6972
  for (const event of entity.domainEvents) {
6600
- const eventName = this.getEventName(event);
6601
- const handlers = this.handlers.get(eventName);
6602
- if (!handlers) continue;
6973
+ const handlers = this.handlers.get(event.type);
6974
+ if (!handlers?.length) continue;
6603
6975
  for (const handler of handlers) {
6604
6976
  await handler(event, ctx);
6605
6977
  }
@@ -6607,11 +6979,6 @@ var DomainEventBus = class {
6607
6979
  entity.domainEvents = [];
6608
6980
  }
6609
6981
  }
6610
- getEventName(event) {
6611
- if (!event) return "Unknown";
6612
- if (typeof event === "string") return event;
6613
- return event.constructor?.name ?? "Unknown";
6614
- }
6615
6982
  };
6616
6983
  var addDomainEvent = (entity, event) => {
6617
6984
  if (!entity.domainEvents) {
@@ -6853,8 +7220,8 @@ var OrmSession = class {
6853
7220
  registerInterceptor(interceptor) {
6854
7221
  this.interceptors.push(interceptor);
6855
7222
  }
6856
- registerDomainEventHandler(name, handler) {
6857
- this.domainEvents.register(name, handler);
7223
+ registerDomainEventHandler(type, handler) {
7224
+ this.domainEvents.on(type, handler);
6858
7225
  }
6859
7226
  async find(entityClass, id) {
6860
7227
  const table = getTableDefFromEntity(entityClass);
@@ -6866,7 +7233,11 @@ var OrmSession = class {
6866
7233
  if (!column) {
6867
7234
  throw new Error("Entity table does not expose a primary key");
6868
7235
  }
6869
- const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
7236
+ const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
7237
+ acc[col2.name] = col2;
7238
+ return acc;
7239
+ }, {});
7240
+ const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
6870
7241
  const rows = await executeHydrated(this, qb);
6871
7242
  return rows[0] ?? null;
6872
7243
  }
@@ -6978,7 +7349,6 @@ var Orm = class {
6978
7349
  const executor = this.executorFactory.createExecutor(options?.tx);
6979
7350
  return new OrmSession({ orm: this, executor });
6980
7351
  }
6981
- // Nice convenience:
6982
7352
  async transaction(fn4) {
6983
7353
  const executor = this.executorFactory.createTransactionalExecutor();
6984
7354
  const session = new OrmSession({ orm: this, executor });
@@ -7141,6 +7511,7 @@ export {
7141
7511
  columnOperand,
7142
7512
  concat,
7143
7513
  concatWs,
7514
+ correlateBy,
7144
7515
  cos,
7145
7516
  cot,
7146
7517
  count,
@@ -7169,6 +7540,7 @@ export {
7169
7540
  diffSchema,
7170
7541
  endOfMonth,
7171
7542
  eq,
7543
+ esel,
7172
7544
  executeHydrated,
7173
7545
  executeHydratedWithContexts,
7174
7546
  exists,
@@ -7180,6 +7552,7 @@ export {
7180
7552
  generateCreateTableSql,
7181
7553
  generateSchemaSql,
7182
7554
  getSchemaIntrospector,
7555
+ groupConcat,
7183
7556
  gt,
7184
7557
  gte,
7185
7558
  hasMany,
@@ -7194,6 +7567,7 @@ export {
7194
7567
  isNotNull,
7195
7568
  isNull,
7196
7569
  isOperandNode,
7570
+ isValueOperandInput,
7197
7571
  isWindowFunctionNode,
7198
7572
  jsonPath,
7199
7573
  lag,
@@ -7216,6 +7590,8 @@ export {
7216
7590
  lt,
7217
7591
  lte,
7218
7592
  ltrim,
7593
+ max,
7594
+ min,
7219
7595
  mod,
7220
7596
  month,
7221
7597
  neq,
@@ -7226,6 +7602,7 @@ export {
7226
7602
  now,
7227
7603
  ntile,
7228
7604
  or,
7605
+ outerRef,
7229
7606
  pi,
7230
7607
  position,
7231
7608
  pow,
@@ -7246,6 +7623,7 @@ export {
7246
7623
  rowsToQueryResult,
7247
7624
  rpad,
7248
7625
  rtrim,
7626
+ sel,
7249
7627
  sign,
7250
7628
  sin,
7251
7629
  space,