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.cjs CHANGED
@@ -84,6 +84,7 @@ __export(index_exports, {
84
84
  columnOperand: () => columnOperand,
85
85
  concat: () => concat,
86
86
  concatWs: () => concatWs,
87
+ correlateBy: () => correlateBy,
87
88
  cos: () => cos,
88
89
  cot: () => cot,
89
90
  count: () => count,
@@ -112,6 +113,7 @@ __export(index_exports, {
112
113
  diffSchema: () => diffSchema,
113
114
  endOfMonth: () => endOfMonth,
114
115
  eq: () => eq,
116
+ esel: () => esel,
115
117
  executeHydrated: () => executeHydrated,
116
118
  executeHydratedWithContexts: () => executeHydratedWithContexts,
117
119
  exists: () => exists,
@@ -123,6 +125,7 @@ __export(index_exports, {
123
125
  generateCreateTableSql: () => generateCreateTableSql,
124
126
  generateSchemaSql: () => generateSchemaSql,
125
127
  getSchemaIntrospector: () => getSchemaIntrospector,
128
+ groupConcat: () => groupConcat,
126
129
  gt: () => gt,
127
130
  gte: () => gte,
128
131
  hasMany: () => hasMany,
@@ -137,6 +140,7 @@ __export(index_exports, {
137
140
  isNotNull: () => isNotNull,
138
141
  isNull: () => isNull,
139
142
  isOperandNode: () => isOperandNode,
143
+ isValueOperandInput: () => isValueOperandInput,
140
144
  isWindowFunctionNode: () => isWindowFunctionNode,
141
145
  jsonPath: () => jsonPath,
142
146
  lag: () => lag,
@@ -159,6 +163,8 @@ __export(index_exports, {
159
163
  lt: () => lt,
160
164
  lte: () => lte,
161
165
  ltrim: () => ltrim,
166
+ max: () => max,
167
+ min: () => min,
162
168
  mod: () => mod,
163
169
  month: () => month,
164
170
  neq: () => neq,
@@ -169,6 +175,7 @@ __export(index_exports, {
169
175
  now: () => now,
170
176
  ntile: () => ntile,
171
177
  or: () => or,
178
+ outerRef: () => outerRef,
172
179
  pi: () => pi,
173
180
  position: () => position,
174
181
  pow: () => pow,
@@ -189,6 +196,7 @@ __export(index_exports, {
189
196
  rowsToQueryResult: () => rowsToQueryResult,
190
197
  rpad: () => rpad,
191
198
  rtrim: () => rtrim,
199
+ sel: () => sel,
192
200
  sign: () => sign,
193
201
  sin: () => sin,
194
202
  space: () => space,
@@ -273,6 +281,30 @@ var col = {
273
281
  * Creates a UUID column definition
274
282
  */
275
283
  uuid: () => ({ name: "", type: "UUID" }),
284
+ /**
285
+ * Creates a binary large object column definition
286
+ */
287
+ blob: () => ({ name: "", type: "BLOB" }),
288
+ /**
289
+ * Creates a fixed-length binary column definition
290
+ */
291
+ binary: (length2) => ({
292
+ name: "",
293
+ type: "BINARY",
294
+ args: length2 !== void 0 ? [length2] : void 0
295
+ }),
296
+ /**
297
+ * Creates a variable-length binary column definition
298
+ */
299
+ varbinary: (length2) => ({
300
+ name: "",
301
+ type: "VARBINARY",
302
+ args: length2 !== void 0 ? [length2] : void 0
303
+ }),
304
+ /**
305
+ * Creates a Postgres bytea column definition
306
+ */
307
+ bytea: () => ({ name: "", type: "BYTEA" }),
276
308
  /**
277
309
  * Creates a timestamp column definition
278
310
  */
@@ -422,10 +454,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
422
454
 
423
455
  // src/core/ast/expression-builders.ts
424
456
  var valueToOperand = (value) => {
425
- if (value === null || value === void 0 || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
426
- return { type: "Literal", value: value === void 0 ? null : value };
457
+ if (isOperandNode(value)) {
458
+ return value;
427
459
  }
428
- return value;
460
+ return {
461
+ type: "Literal",
462
+ value
463
+ };
429
464
  };
430
465
  var toNode = (col2) => {
431
466
  if (isOperandNode(col2)) return col2;
@@ -436,14 +471,20 @@ var toLiteralNode = (value) => ({
436
471
  type: "Literal",
437
472
  value
438
473
  });
474
+ var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
475
+ var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
439
476
  var toOperand = (val) => {
440
- if (val === null) return { type: "Literal", value: null };
441
- if (typeof val === "string" || typeof val === "number" || typeof val === "boolean") {
442
- return { type: "Literal", value: val };
477
+ if (isLiteralValue(val)) {
478
+ return valueToOperand(val);
443
479
  }
444
480
  return toNode(val);
445
481
  };
446
482
  var columnOperand = (col2) => toNode(col2);
483
+ var outerRef = (col2) => ({
484
+ ...columnOperand(col2),
485
+ scope: "outer"
486
+ });
487
+ var correlateBy = (table, column) => outerRef({ name: column, table });
447
488
  var createBinaryExpression = (operator, left2, right2, escape) => {
448
489
  const node = {
449
490
  type: "BinaryExpression",
@@ -585,6 +626,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
585
626
  return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
586
627
  };
587
628
 
629
+ // src/core/sql/sql.ts
630
+ var SQL_OPERATORS = {
631
+ /** Equality operator */
632
+ EQUALS: "=",
633
+ /** Not equals operator */
634
+ NOT_EQUALS: "!=",
635
+ /** Greater than operator */
636
+ GREATER_THAN: ">",
637
+ /** Greater than or equal operator */
638
+ GREATER_OR_EQUAL: ">=",
639
+ /** Less than operator */
640
+ LESS_THAN: "<",
641
+ /** Less than or equal operator */
642
+ LESS_OR_EQUAL: "<=",
643
+ /** LIKE pattern matching operator */
644
+ LIKE: "LIKE",
645
+ /** NOT LIKE pattern matching operator */
646
+ NOT_LIKE: "NOT LIKE",
647
+ /** IN membership operator */
648
+ IN: "IN",
649
+ /** NOT IN membership operator */
650
+ NOT_IN: "NOT IN",
651
+ /** BETWEEN range operator */
652
+ BETWEEN: "BETWEEN",
653
+ /** NOT BETWEEN range operator */
654
+ NOT_BETWEEN: "NOT BETWEEN",
655
+ /** IS NULL null check operator */
656
+ IS_NULL: "IS NULL",
657
+ /** IS NOT NULL null check operator */
658
+ IS_NOT_NULL: "IS NOT NULL",
659
+ /** Logical AND operator */
660
+ AND: "AND",
661
+ /** Logical OR operator */
662
+ OR: "OR",
663
+ /** EXISTS operator */
664
+ EXISTS: "EXISTS",
665
+ /** NOT EXISTS operator */
666
+ NOT_EXISTS: "NOT EXISTS"
667
+ };
668
+ var JOIN_KINDS = {
669
+ /** INNER JOIN type */
670
+ INNER: "INNER",
671
+ /** LEFT JOIN type */
672
+ LEFT: "LEFT",
673
+ /** RIGHT JOIN type */
674
+ RIGHT: "RIGHT",
675
+ /** CROSS JOIN type */
676
+ CROSS: "CROSS"
677
+ };
678
+ var ORDER_DIRECTIONS = {
679
+ /** Ascending order */
680
+ ASC: "ASC",
681
+ /** Descending order */
682
+ DESC: "DESC"
683
+ };
684
+
588
685
  // src/core/ast/aggregate-functions.ts
589
686
  var buildAggregate = (name) => (col2) => ({
590
687
  type: "Function",
@@ -594,6 +691,20 @@ var buildAggregate = (name) => (col2) => ({
594
691
  var count = buildAggregate("COUNT");
595
692
  var sum = buildAggregate("SUM");
596
693
  var avg = buildAggregate("AVG");
694
+ var min = buildAggregate("MIN");
695
+ var max = buildAggregate("MAX");
696
+ var toOrderByNode = (order) => ({
697
+ type: "OrderBy",
698
+ column: columnOperand(order.column),
699
+ direction: order.direction ?? ORDER_DIRECTIONS.ASC
700
+ });
701
+ var groupConcat = (col2, options) => ({
702
+ type: "Function",
703
+ name: "GROUP_CONCAT",
704
+ args: [columnOperand(col2)],
705
+ orderBy: options?.orderBy?.map(toOrderByNode),
706
+ separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
707
+ });
597
708
 
598
709
  // src/core/ast/expression-visitor.ts
599
710
  var expressionDispatchers = /* @__PURE__ */ new Map();
@@ -684,13 +795,57 @@ var toTableRef = (table) => ({
684
795
  alias: table.alias
685
796
  });
686
797
 
798
+ // src/core/ast/builders.ts
799
+ var buildColumnNode = (table, column) => {
800
+ if (column.type === "Column") {
801
+ return column;
802
+ }
803
+ const def = column;
804
+ const baseTable = def.table ? table.alias && def.table === table.name ? table.alias : def.table : table.alias || table.name;
805
+ return {
806
+ type: "Column",
807
+ table: baseTable,
808
+ name: def.name
809
+ };
810
+ };
811
+ var buildColumnNodes = (table, names) => names.map((name) => ({
812
+ type: "Column",
813
+ table: table.alias || table.name,
814
+ name
815
+ }));
816
+ var createTableNode = (table) => ({
817
+ type: "Table",
818
+ name: table.name
819
+ });
820
+ var fnTable = (name, args = [], alias, opts) => ({
821
+ type: "FunctionTable",
822
+ name,
823
+ args,
824
+ alias,
825
+ lateral: opts?.lateral,
826
+ withOrdinality: opts?.withOrdinality,
827
+ columnAliases: opts?.columnAliases,
828
+ schema: opts?.schema
829
+ });
830
+ var derivedTable = (query, alias, columnAliases) => ({
831
+ type: "DerivedTable",
832
+ query,
833
+ alias,
834
+ columnAliases
835
+ });
836
+
687
837
  // src/core/functions/standard-strategy.ts
688
- var StandardFunctionStrategy = class {
838
+ var StandardFunctionStrategy = class _StandardFunctionStrategy {
689
839
  constructor() {
690
840
  this.renderers = /* @__PURE__ */ new Map();
691
841
  this.registerStandard();
692
842
  }
693
843
  registerStandard() {
844
+ this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
845
+ this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
846
+ this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
847
+ this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
848
+ this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
694
849
  this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
695
850
  this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
696
851
  this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
@@ -717,6 +872,7 @@ var StandardFunctionStrategy = class {
717
872
  this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
718
873
  this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
719
874
  this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
875
+ this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
720
876
  }
721
877
  add(name, renderer) {
722
878
  this.renderers.set(name, renderer);
@@ -724,6 +880,36 @@ var StandardFunctionStrategy = class {
724
880
  getRenderer(name) {
725
881
  return this.renderers.get(name);
726
882
  }
883
+ renderGroupConcat(ctx) {
884
+ const arg = ctx.compiledArgs[0];
885
+ const orderClause = this.buildOrderByExpression(ctx);
886
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
887
+ const separatorClause = this.formatGroupConcatSeparator(ctx);
888
+ return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
889
+ }
890
+ buildOrderByExpression(ctx) {
891
+ const orderBy = ctx.node.orderBy;
892
+ if (!orderBy || orderBy.length === 0) {
893
+ return "";
894
+ }
895
+ const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
896
+ return `ORDER BY ${parts.join(", ")}`;
897
+ }
898
+ formatGroupConcatSeparator(ctx) {
899
+ if (!ctx.node.separator) {
900
+ return "";
901
+ }
902
+ return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
903
+ }
904
+ getGroupConcatSeparatorOperand(ctx) {
905
+ return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
906
+ }
907
+ static {
908
+ this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
909
+ type: "Literal",
910
+ value: ","
911
+ };
912
+ }
727
913
  };
728
914
 
729
915
  // src/core/dialect/abstract.ts
@@ -1070,7 +1256,11 @@ var Dialect = class _Dialect {
1070
1256
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
1071
1257
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
1072
1258
  if (renderer) {
1073
- return renderer({ node: fnNode, compiledArgs });
1259
+ return renderer({
1260
+ node: fnNode,
1261
+ compiledArgs,
1262
+ compileOperand: (operand) => this.compileOperand(operand, ctx)
1263
+ });
1074
1264
  }
1075
1265
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
1076
1266
  }
@@ -1333,7 +1523,7 @@ var SqlDialectBase = class extends Dialect {
1333
1523
  return this.returningStrategy.compileReturning(returning, ctx);
1334
1524
  }
1335
1525
  compileInsertColumnList(columns) {
1336
- return columns.map((column) => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(", ");
1526
+ return columns.map((column) => this.quoteIdentifier(column.name)).join(", ");
1337
1527
  }
1338
1528
  compileInsertValues(values, ctx) {
1339
1529
  return values.map((row) => `(${row.map((value) => this.compileOperand(value, ctx)).join(", ")})`).join(", ");
@@ -1359,7 +1549,7 @@ var SqlDialectBase = class extends Dialect {
1359
1549
  compileUpdateAssignments(assignments, ctx) {
1360
1550
  return assignments.map((assignment) => {
1361
1551
  const col2 = assignment.column;
1362
- const target = `${this.quoteIdentifier(col2.table)}.${this.quoteIdentifier(col2.name)}`;
1552
+ const target = this.quoteIdentifier(col2.name);
1363
1553
  const value = this.compileOperand(assignment.value, ctx);
1364
1554
  return `${target} = ${value}`;
1365
1555
  }).join(", ");
@@ -1391,12 +1581,29 @@ var SqlDialectBase = class extends Dialect {
1391
1581
  if (tableSource.type === "FunctionTable") {
1392
1582
  return this.compileFunctionTable(tableSource, ctx);
1393
1583
  }
1584
+ if (tableSource.type === "DerivedTable") {
1585
+ return this.compileDerivedTable(tableSource, ctx);
1586
+ }
1394
1587
  return this.compileTableSource(tableSource);
1395
1588
  }
1396
1589
  compileFunctionTable(fn4, ctx) {
1397
1590
  return FunctionTableFormatter.format(fn4, ctx, this);
1398
1591
  }
1592
+ compileDerivedTable(table, ctx) {
1593
+ if (!table.alias) {
1594
+ throw new Error("Derived tables must have an alias.");
1595
+ }
1596
+ const subquery = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
1597
+ const columns = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
1598
+ return `(${subquery}) AS ${this.quoteIdentifier(table.alias)}${columns}`;
1599
+ }
1399
1600
  compileTableSource(table) {
1601
+ if (table.type === "FunctionTable") {
1602
+ return this.compileFunctionTable(table);
1603
+ }
1604
+ if (table.type === "DerivedTable") {
1605
+ return this.compileDerivedTable(table);
1606
+ }
1400
1607
  const base = this.compileTableName(table);
1401
1608
  return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
1402
1609
  }
@@ -1493,6 +1700,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
1493
1700
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1494
1701
  return `DATE_TRUNC('${partClean}', ${date})`;
1495
1702
  });
1703
+ this.add("GROUP_CONCAT", (ctx) => {
1704
+ const arg = ctx.compiledArgs[0];
1705
+ const orderClause = this.buildOrderByExpression(ctx);
1706
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
1707
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1708
+ const separator = ctx.compileOperand(separatorOperand);
1709
+ return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
1710
+ });
1496
1711
  }
1497
1712
  };
1498
1713
 
@@ -1737,6 +1952,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
1737
1952
  }
1738
1953
  return `date(${date}, 'start of ${partClean}')`;
1739
1954
  });
1955
+ this.add("GROUP_CONCAT", (ctx) => {
1956
+ const arg = ctx.compiledArgs[0];
1957
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1958
+ const separator = ctx.compileOperand(separatorOperand);
1959
+ return `GROUP_CONCAT(${arg}, ${separator})`;
1960
+ });
1740
1961
  }
1741
1962
  };
1742
1963
 
@@ -1771,6 +1992,12 @@ var SqliteDialect = class extends SqlDialectBase {
1771
1992
  const columns = this.formatReturningColumns(returning);
1772
1993
  return ` RETURNING ${columns}`;
1773
1994
  }
1995
+ formatReturningColumns(returning) {
1996
+ return returning.map((column) => {
1997
+ const alias = column.alias ? ` AS ${this.quoteIdentifier(column.alias)}` : "";
1998
+ return `${this.quoteIdentifier(column.name)}${alias}`;
1999
+ }).join(", ");
2000
+ }
1774
2001
  supportsReturning() {
1775
2002
  return true;
1776
2003
  }
@@ -1853,6 +2080,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1853
2080
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1854
2081
  return `DATETRUNC(${partClean}, ${date})`;
1855
2082
  });
2083
+ this.add("GROUP_CONCAT", (ctx) => {
2084
+ const arg = ctx.compiledArgs[0];
2085
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
2086
+ const separator = ctx.compileOperand(separatorOperand);
2087
+ const orderClause = this.buildOrderByExpression(ctx);
2088
+ const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
2089
+ return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
2090
+ });
1856
2091
  }
1857
2092
  };
1858
2093
 
@@ -1929,6 +2164,9 @@ var SqlServerDialect = class extends Dialect {
1929
2164
  return `UPDATE ${table} SET ${assignments}${whereClause};`;
1930
2165
  }
1931
2166
  compileDeleteAst(ast, ctx) {
2167
+ if (ast.from.type !== "Table") {
2168
+ throw new Error("DELETE only supports base tables in the MSSQL dialect.");
2169
+ }
1932
2170
  const table = this.quoteIdentifier(ast.from.name);
1933
2171
  const whereClause = this.compileWhere(ast.where, ctx);
1934
2172
  return `DELETE FROM ${table}${whereClause};`;
@@ -1952,9 +2190,9 @@ var SqlServerDialect = class extends Dialect {
1952
2190
  return expr;
1953
2191
  }).join(", ");
1954
2192
  const distinct = ast.distinct ? "DISTINCT " : "";
1955
- const from = `${this.quoteIdentifier(ast.from.name)}`;
2193
+ const from = this.compileTableSource(ast.from, ctx);
1956
2194
  const joins = ast.joins.map((j) => {
1957
- const table = this.quoteIdentifier(j.table.name);
2195
+ const table = this.compileTableSource(j.table, ctx);
1958
2196
  const cond = this.compileExpression(j.condition, ctx);
1959
2197
  return `${j.kind} JOIN ${table} ON ${cond}`;
1960
2198
  }).join(" ");
@@ -1984,6 +2222,21 @@ var SqlServerDialect = class extends Dialect {
1984
2222
  }
1985
2223
  return pagination;
1986
2224
  }
2225
+ compileTableSource(table, ctx) {
2226
+ if (table.type === "FunctionTable") {
2227
+ return FunctionTableFormatter.format(table, ctx, this);
2228
+ }
2229
+ if (table.type === "DerivedTable") {
2230
+ return this.compileDerivedTable(table, ctx);
2231
+ }
2232
+ const base = table.schema ? `${this.quoteIdentifier(table.schema)}.${this.quoteIdentifier(table.name)}` : this.quoteIdentifier(table.name);
2233
+ return table.alias ? `${base} AS ${this.quoteIdentifier(table.alias)}` : base;
2234
+ }
2235
+ compileDerivedTable(table, ctx) {
2236
+ const sub = this.compileSelectAst(this.normalizeSelectAst(table.query), ctx).trim().replace(/;$/, "");
2237
+ const cols = table.columnAliases?.length ? ` (${table.columnAliases.map((c) => this.quoteIdentifier(c)).join(", ")})` : "";
2238
+ return `(${sub}) AS ${this.quoteIdentifier(table.alias)}${cols}`;
2239
+ }
1987
2240
  compileCtes(ast, ctx) {
1988
2241
  if (!ast.ctes || ast.ctes.length === 0) return "";
1989
2242
  const defs = ast.ctes.map((cte) => {
@@ -2112,6 +2365,17 @@ var SelectQueryState = class _SelectQueryState {
2112
2365
  joins: [...this.ast.joins ?? [], join]
2113
2366
  });
2114
2367
  }
2368
+ /**
2369
+ * Replaces the FROM clause.
2370
+ * @param from - Table source for the FROM clause
2371
+ * @returns New SelectQueryState with updated FROM
2372
+ */
2373
+ withFrom(from) {
2374
+ return this.clone({
2375
+ ...this.ast,
2376
+ from
2377
+ });
2378
+ }
2115
2379
  /**
2116
2380
  * Adds a WHERE clause to the query
2117
2381
  * @param predicate - WHERE predicate expression
@@ -2222,62 +2486,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
2222
2486
  meta: relationName ? { relationName } : void 0
2223
2487
  });
2224
2488
 
2225
- // src/core/sql/sql.ts
2226
- var SQL_OPERATORS = {
2227
- /** Equality operator */
2228
- EQUALS: "=",
2229
- /** Not equals operator */
2230
- NOT_EQUALS: "!=",
2231
- /** Greater than operator */
2232
- GREATER_THAN: ">",
2233
- /** Greater than or equal operator */
2234
- GREATER_OR_EQUAL: ">=",
2235
- /** Less than operator */
2236
- LESS_THAN: "<",
2237
- /** Less than or equal operator */
2238
- LESS_OR_EQUAL: "<=",
2239
- /** LIKE pattern matching operator */
2240
- LIKE: "LIKE",
2241
- /** NOT LIKE pattern matching operator */
2242
- NOT_LIKE: "NOT LIKE",
2243
- /** IN membership operator */
2244
- IN: "IN",
2245
- /** NOT IN membership operator */
2246
- NOT_IN: "NOT IN",
2247
- /** BETWEEN range operator */
2248
- BETWEEN: "BETWEEN",
2249
- /** NOT BETWEEN range operator */
2250
- NOT_BETWEEN: "NOT BETWEEN",
2251
- /** IS NULL null check operator */
2252
- IS_NULL: "IS NULL",
2253
- /** IS NOT NULL null check operator */
2254
- IS_NOT_NULL: "IS NOT NULL",
2255
- /** Logical AND operator */
2256
- AND: "AND",
2257
- /** Logical OR operator */
2258
- OR: "OR",
2259
- /** EXISTS operator */
2260
- EXISTS: "EXISTS",
2261
- /** NOT EXISTS operator */
2262
- NOT_EXISTS: "NOT EXISTS"
2263
- };
2264
- var JOIN_KINDS = {
2265
- /** INNER JOIN type */
2266
- INNER: "INNER",
2267
- /** LEFT JOIN type */
2268
- LEFT: "LEFT",
2269
- /** RIGHT JOIN type */
2270
- RIGHT: "RIGHT",
2271
- /** CROSS JOIN type */
2272
- CROSS: "CROSS"
2273
- };
2274
- var ORDER_DIRECTIONS = {
2275
- /** Ascending order */
2276
- ASC: "ASC",
2277
- /** Descending order */
2278
- DESC: "DESC"
2279
- };
2280
-
2281
2489
  // src/query-builder/hydration-manager.ts
2282
2490
  var HydrationManager = class _HydrationManager {
2283
2491
  /**
@@ -2660,38 +2868,6 @@ var buildDefaultHydrationPlan = (table) => ({
2660
2868
  relations: []
2661
2869
  });
2662
2870
 
2663
- // src/core/ast/builders.ts
2664
- var buildColumnNode = (table, column) => {
2665
- if (column.type === "Column") {
2666
- return column;
2667
- }
2668
- const def = column;
2669
- return {
2670
- type: "Column",
2671
- table: def.table || table.name,
2672
- name: def.name
2673
- };
2674
- };
2675
- var buildColumnNodes = (table, names) => names.map((name) => ({
2676
- type: "Column",
2677
- table: table.name,
2678
- name
2679
- }));
2680
- var createTableNode = (table) => ({
2681
- type: "Table",
2682
- name: table.name
2683
- });
2684
- var fnTable = (name, args = [], alias, opts) => ({
2685
- type: "FunctionTable",
2686
- name,
2687
- args,
2688
- alias,
2689
- lateral: opts?.lateral,
2690
- withOrdinality: opts?.withOrdinality,
2691
- columnAliases: opts?.columnAliases,
2692
- schema: opts?.schema
2693
- });
2694
-
2695
2871
  // src/query-builder/raw-column-parser.ts
2696
2872
  var parseRawColumn = (col2, tableName, ctes) => {
2697
2873
  if (col2.includes("(")) {
@@ -2731,6 +2907,8 @@ var QueryAstService = class {
2731
2907
  const existingAliases = new Set(
2732
2908
  this.state.ast.columns.map((c) => c.alias || c.name)
2733
2909
  );
2910
+ const from = this.state.ast.from;
2911
+ const rootTableName = from.type === "Table" && from.alias ? from.alias : this.table.name;
2734
2912
  const newCols = Object.entries(columns).reduce((acc, [alias, val]) => {
2735
2913
  if (existingAliases.has(alias)) return acc;
2736
2914
  if (isExpressionSelectionNode(val)) {
@@ -2738,9 +2916,10 @@ var QueryAstService = class {
2738
2916
  return acc;
2739
2917
  }
2740
2918
  const colDef = val;
2919
+ const resolvedTable = colDef.table && colDef.table === this.table.name && from.type === "Table" && from.alias ? from.alias : colDef.table || rootTableName;
2741
2920
  acc.push({
2742
2921
  type: "Column",
2743
- table: colDef.table || this.table.name,
2922
+ table: resolvedTable,
2744
2923
  name: colDef.name,
2745
2924
  alias
2746
2925
  });
@@ -2755,7 +2934,9 @@ var QueryAstService = class {
2755
2934
  * @returns Column selection result with updated state and added columns
2756
2935
  */
2757
2936
  selectRaw(cols) {
2758
- const newCols = cols.map((col2) => parseRawColumn(col2, this.table.name, this.state.ast.ctes));
2937
+ const from = this.state.ast.from;
2938
+ const defaultTable = from.type === "Table" && from.alias ? from.alias : this.table.name;
2939
+ const newCols = cols.map((col2) => parseRawColumn(col2, defaultTable, this.state.ast.ctes));
2759
2940
  const nextState = this.state.withColumns(newCols);
2760
2941
  return { state: nextState, addedColumns: newCols };
2761
2942
  }
@@ -2791,6 +2972,14 @@ var QueryAstService = class {
2791
2972
  };
2792
2973
  return this.state.withSetOperation(op);
2793
2974
  }
2975
+ /**
2976
+ * Replaces the FROM clause for the current query.
2977
+ * @param from - Table source to use in the FROM clause
2978
+ * @returns Updated query state with new FROM
2979
+ */
2980
+ withFrom(from) {
2981
+ return this.state.withFrom(from);
2982
+ }
2794
2983
  /**
2795
2984
  * Selects a subquery as a column
2796
2985
  * @param alias - Alias for the subquery
@@ -2824,7 +3013,9 @@ var QueryAstService = class {
2824
3013
  * @returns Updated query state with GROUP BY clause
2825
3014
  */
2826
3015
  withGroupBy(col2) {
2827
- const node = buildColumnNode(this.table, col2);
3016
+ const from = this.state.ast.from;
3017
+ const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3018
+ const node = buildColumnNode(tableRef, col2);
2828
3019
  return this.state.withGroupBy([node]);
2829
3020
  }
2830
3021
  /**
@@ -2843,7 +3034,9 @@ var QueryAstService = class {
2843
3034
  * @returns Updated query state with ORDER BY clause
2844
3035
  */
2845
3036
  withOrderBy(col2, direction) {
2846
- const node = buildColumnNode(this.table, col2);
3037
+ const from = this.state.ast.from;
3038
+ const tableRef = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3039
+ const node = buildColumnNode(tableRef, col2);
2847
3040
  return this.state.withOrderBy([{ type: "OrderBy", column: node, direction }]);
2848
3041
  }
2849
3042
  /**
@@ -2947,7 +3140,8 @@ var RelationProjectionHelper = class {
2947
3140
  var assertNever = (value) => {
2948
3141
  throw new Error(`Unhandled relation type: ${JSON.stringify(value)}`);
2949
3142
  };
2950
- var baseRelationCondition = (root, relation) => {
3143
+ var baseRelationCondition = (root, relation, rootAlias) => {
3144
+ const rootTable = rootAlias || root.name;
2951
3145
  const defaultLocalKey = relation.type === RelationKinds.HasMany || relation.type === RelationKinds.HasOne ? findPrimaryKey(root) : findPrimaryKey(relation.target);
2952
3146
  const localKey = relation.localKey || defaultLocalKey;
2953
3147
  switch (relation.type) {
@@ -2955,12 +3149,12 @@ var baseRelationCondition = (root, relation) => {
2955
3149
  case RelationKinds.HasOne:
2956
3150
  return eq(
2957
3151
  { type: "Column", table: relation.target.name, name: relation.foreignKey },
2958
- { type: "Column", table: root.name, name: localKey }
3152
+ { type: "Column", table: rootTable, name: localKey }
2959
3153
  );
2960
3154
  case RelationKinds.BelongsTo:
2961
3155
  return eq(
2962
3156
  { type: "Column", table: relation.target.name, name: localKey },
2963
- { type: "Column", table: root.name, name: relation.foreignKey }
3157
+ { type: "Column", table: rootTable, name: relation.foreignKey }
2964
3158
  );
2965
3159
  case RelationKinds.BelongsToMany:
2966
3160
  throw new Error("BelongsToMany relations do not support the standard join condition builder");
@@ -2968,12 +3162,13 @@ var baseRelationCondition = (root, relation) => {
2968
3162
  return assertNever(relation);
2969
3163
  }
2970
3164
  };
2971
- var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) => {
3165
+ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra, rootAlias) => {
2972
3166
  const rootKey = relation.localKey || findPrimaryKey(root);
2973
3167
  const targetKey = relation.targetKey || findPrimaryKey(relation.target);
3168
+ const rootTable = rootAlias || root.name;
2974
3169
  const pivotCondition = eq(
2975
3170
  { type: "Column", table: relation.pivotTable.name, name: relation.pivotForeignKeyToRoot },
2976
- { type: "Column", table: root.name, name: rootKey }
3171
+ { type: "Column", table: rootTable, name: rootKey }
2977
3172
  );
2978
3173
  const pivotJoin = createJoinNode(joinKind, relation.pivotTable.name, pivotCondition);
2979
3174
  let targetCondition = eq(
@@ -2991,12 +3186,12 @@ var buildBelongsToManyJoins = (root, relationName, relation, joinKind, extra) =>
2991
3186
  );
2992
3187
  return [pivotJoin, targetJoin];
2993
3188
  };
2994
- var buildRelationJoinCondition = (root, relation, extra) => {
2995
- const base = baseRelationCondition(root, relation);
3189
+ var buildRelationJoinCondition = (root, relation, extra, rootAlias) => {
3190
+ const base = baseRelationCondition(root, relation, rootAlias);
2996
3191
  return extra ? and(base, extra) : base;
2997
3192
  };
2998
- var buildRelationCorrelation = (root, relation) => {
2999
- return baseRelationCondition(root, relation);
3193
+ var buildRelationCorrelation = (root, relation, rootAlias) => {
3194
+ return baseRelationCondition(root, relation, rootAlias);
3000
3195
  };
3001
3196
 
3002
3197
  // src/core/ast/join-metadata.ts
@@ -3040,7 +3235,7 @@ var RelationService = class {
3040
3235
  match(relationName, predicate) {
3041
3236
  const joined = this.joinRelation(relationName, JOIN_KINDS.INNER, predicate);
3042
3237
  const pk = findPrimaryKey(this.table);
3043
- const distinctCols = [{ type: "Column", table: this.table.name, name: pk }];
3238
+ const distinctCols = [{ type: "Column", table: this.rootTableName(), name: pk }];
3044
3239
  const existingDistinct = joined.state.ast.distinct ? joined.state.ast.distinct : [];
3045
3240
  const nextState = this.astService(joined.state).withDistinct([...existingDistinct, ...distinctCols]);
3046
3241
  return { state: nextState, hydration: joined.hydration };
@@ -3127,9 +3322,13 @@ var RelationService = class {
3127
3322
  * @param ast - Query AST to modify
3128
3323
  * @returns Modified query AST with relation correlation
3129
3324
  */
3130
- applyRelationCorrelation(relationName, ast) {
3325
+ applyRelationCorrelation(relationName, ast, additionalCorrelation) {
3131
3326
  const relation = this.getRelation(relationName);
3132
- const correlation = buildRelationCorrelation(this.table, relation);
3327
+ const rootAlias = this.state.ast.from.type === "Table" ? this.state.ast.from.alias : void 0;
3328
+ let correlation = buildRelationCorrelation(this.table, relation, rootAlias);
3329
+ if (additionalCorrelation) {
3330
+ correlation = and(correlation, additionalCorrelation);
3331
+ }
3133
3332
  const whereInSubquery = ast.where ? and(correlation, ast.where) : correlation;
3134
3333
  return {
3135
3334
  ...ast,
@@ -3146,17 +3345,19 @@ var RelationService = class {
3146
3345
  */
3147
3346
  withJoin(state, relationName, joinKind, extraCondition) {
3148
3347
  const relation = this.getRelation(relationName);
3348
+ const rootAlias = state.ast.from.type === "Table" ? state.ast.from.alias : void 0;
3149
3349
  if (relation.type === RelationKinds.BelongsToMany) {
3150
3350
  const joins = buildBelongsToManyJoins(
3151
3351
  this.table,
3152
3352
  relationName,
3153
3353
  relation,
3154
3354
  joinKind,
3155
- extraCondition
3355
+ extraCondition,
3356
+ rootAlias
3156
3357
  );
3157
3358
  return joins.reduce((current, join) => this.astService(current).withJoin(join), state);
3158
3359
  }
3159
- const condition = buildRelationJoinCondition(this.table, relation, extraCondition);
3360
+ const condition = buildRelationJoinCondition(this.table, relation, extraCondition, rootAlias);
3160
3361
  const joinNode = createJoinNode(joinKind, relation.target.name, condition, relationName);
3161
3362
  return this.astService(state).withJoin(joinNode);
3162
3363
  }
@@ -3195,6 +3396,11 @@ var RelationService = class {
3195
3396
  astService(state = this.state) {
3196
3397
  return this.createQueryAstService(this.table, state);
3197
3398
  }
3399
+ rootTableName() {
3400
+ const from = this.state.ast.from;
3401
+ if (from.type === "Table" && from.alias) return from.alias;
3402
+ return this.table.name;
3403
+ }
3198
3404
  };
3199
3405
 
3200
3406
  // src/query-builder/select-query-builder-deps.ts
@@ -3269,7 +3475,9 @@ var ColumnSelector = class {
3269
3475
  * @returns Updated query context with DISTINCT clause
3270
3476
  */
3271
3477
  distinct(context, columns) {
3272
- const nodes = columns.map((col2) => buildColumnNode(this.env.table, col2));
3478
+ const from = context.state.ast.from;
3479
+ const tableRef = from.type === "Table" && from.alias ? { ...this.env.table, alias: from.alias } : this.env.table;
3480
+ const nodes = columns.map((col2) => buildColumnNode(tableRef, col2));
3273
3481
  const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
3274
3482
  const nextState = astService.withDistinct(nodes);
3275
3483
  return { state: nextState, hydration: context.hydration };
@@ -3326,8 +3534,8 @@ var RelationManager = class {
3326
3534
  * @param ast - Query AST to modify
3327
3535
  * @returns Modified query AST with relation correlation
3328
3536
  */
3329
- applyRelationCorrelation(context, relationName, ast) {
3330
- return this.createService(context).applyRelationCorrelation(relationName, ast);
3537
+ applyRelationCorrelation(context, relationName, ast, additionalCorrelation) {
3538
+ return this.createService(context).applyRelationCorrelation(relationName, ast, additionalCorrelation);
3331
3539
  }
3332
3540
  /**
3333
3541
  * Creates a relation service instance
@@ -4374,9 +4582,30 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4374
4582
  clone(context = this.context, lazyRelations = new Set(this.lazyRelations)) {
4375
4583
  return new _SelectQueryBuilder(this.env.table, context.state, context.hydration, this.env.deps, lazyRelations);
4376
4584
  }
4585
+ /**
4586
+ * Applies an alias to the root FROM table.
4587
+ * @param alias - Alias to apply
4588
+ */
4589
+ as(alias) {
4590
+ const from = this.context.state.ast.from;
4591
+ if (from.type !== "Table") {
4592
+ throw new Error("Cannot alias non-table FROM sources");
4593
+ }
4594
+ const nextFrom = { ...from, alias };
4595
+ const nextContext = this.applyAst(this.context, (service) => service.withFrom(nextFrom));
4596
+ return this.clone(nextContext);
4597
+ }
4377
4598
  resolveQueryNode(query) {
4378
4599
  return typeof query.getAST === "function" ? query.getAST() : query;
4379
4600
  }
4601
+ applyCorrelation(ast, correlation) {
4602
+ if (!correlation) return ast;
4603
+ const combinedWhere = ast.where ? and(correlation, ast.where) : correlation;
4604
+ return {
4605
+ ...ast,
4606
+ where: combinedWhere
4607
+ };
4608
+ }
4380
4609
  createChildBuilder(table) {
4381
4610
  return new _SelectQueryBuilder(table, void 0, void 0, this.env.deps);
4382
4611
  }
@@ -4405,6 +4634,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4405
4634
  select(columns) {
4406
4635
  return this.clone(this.columnSelector.select(this.context, columns));
4407
4636
  }
4637
+ /**
4638
+ * Selects columns from the root table by name (typed).
4639
+ * @param cols - Column names on the root table
4640
+ */
4641
+ selectColumns(...cols) {
4642
+ const selection = {};
4643
+ for (const key of cols) {
4644
+ const col2 = this.env.table.columns[key];
4645
+ if (!col2) {
4646
+ throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
4647
+ }
4648
+ selection[key] = col2;
4649
+ }
4650
+ return this.select(selection);
4651
+ }
4408
4652
  /**
4409
4653
 
4410
4654
  * Selects raw column expressions
@@ -4453,6 +4697,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4453
4697
  const nextContext = this.applyAst(this.context, (service) => service.withCte(name, subAst, columns, true));
4454
4698
  return this.clone(nextContext);
4455
4699
  }
4700
+ /**
4701
+ * Replaces the FROM clause with a derived table (subquery with alias)
4702
+ * @param subquery - Subquery to use as the FROM source
4703
+ * @param alias - Alias for the derived table
4704
+ * @param columnAliases - Optional column alias list
4705
+ * @returns New query builder instance with updated FROM
4706
+ */
4707
+ fromSubquery(subquery, alias, columnAliases) {
4708
+ const subAst = this.resolveQueryNode(subquery);
4709
+ const fromNode = derivedTable(subAst, alias, columnAliases);
4710
+ const nextContext = this.applyAst(this.context, (service) => service.withFrom(fromNode));
4711
+ return this.clone(nextContext);
4712
+ }
4456
4713
  /**
4457
4714
 
4458
4715
  * Selects a subquery as a column
@@ -4468,6 +4725,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4468
4725
  const query = this.resolveQueryNode(sub);
4469
4726
  return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
4470
4727
  }
4728
+ /**
4729
+ * Adds a JOIN against a derived table (subquery with alias)
4730
+ * @param subquery - Subquery to join
4731
+ * @param alias - Alias for the derived table
4732
+ * @param condition - Join condition expression
4733
+ * @param joinKind - Join kind (defaults to INNER)
4734
+ * @param columnAliases - Optional column alias list for the derived table
4735
+ * @returns New query builder instance with the derived-table join
4736
+ */
4737
+ joinSubquery(subquery, alias, condition, joinKind = JOIN_KINDS.INNER, columnAliases) {
4738
+ const subAst = this.resolveQueryNode(subquery);
4739
+ const joinNode = createJoinNode(joinKind, derivedTable(subAst, alias, columnAliases), condition);
4740
+ const nextContext = this.applyAst(this.context, (service) => service.withJoin(joinNode));
4741
+ return this.clone(nextContext);
4742
+ }
4471
4743
  /**
4472
4744
 
4473
4745
  * Adds an INNER JOIN to the query
@@ -4565,6 +4837,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4565
4837
  nextLazy.add(relationName);
4566
4838
  return this.clone(this.context, nextLazy);
4567
4839
  }
4840
+ /**
4841
+ * Selects columns for a related table in a single hop.
4842
+ */
4843
+ selectRelationColumns(relationName, ...cols) {
4844
+ const relation = this.env.table.relations[relationName];
4845
+ if (!relation) {
4846
+ throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4847
+ }
4848
+ const target = relation.target;
4849
+ for (const col2 of cols) {
4850
+ if (!target.columns[col2]) {
4851
+ throw new Error(
4852
+ `Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
4853
+ );
4854
+ }
4855
+ }
4856
+ return this.include(relationName, { columns: cols });
4857
+ }
4858
+ /**
4859
+ * Convenience alias for selecting specific columns from a relation.
4860
+ */
4861
+ includePick(relationName, cols) {
4862
+ return this.selectRelationColumns(relationName, ...cols);
4863
+ }
4864
+ /**
4865
+ * Selects columns for the root table and relations from a single config object.
4866
+ */
4867
+ selectColumnsDeep(config) {
4868
+ let qb = this;
4869
+ if (config.root?.length) {
4870
+ qb = qb.selectColumns(...config.root);
4871
+ }
4872
+ for (const key of Object.keys(config)) {
4873
+ if (key === "root") continue;
4874
+ const relName = key;
4875
+ const cols = config[relName];
4876
+ if (!cols || !cols.length) continue;
4877
+ qb = qb.selectRelationColumns(relName, ...cols);
4878
+ }
4879
+ return qb;
4880
+ }
4568
4881
  getLazyRelations() {
4569
4882
  return Array.from(this.lazyRelations);
4570
4883
  }
@@ -4726,9 +5039,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4726
5039
  * @returns New query builder instance with the WHERE EXISTS condition
4727
5040
 
4728
5041
  */
4729
- whereExists(subquery) {
5042
+ whereExists(subquery, correlate) {
4730
5043
  const subAst = this.resolveQueryNode(subquery);
4731
- return this.where(exists(subAst));
5044
+ const correlated = this.applyCorrelation(subAst, correlate);
5045
+ return this.where(exists(correlated));
4732
5046
  }
4733
5047
  /**
4734
5048
 
@@ -4739,9 +5053,10 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4739
5053
  * @returns New query builder instance with the WHERE NOT EXISTS condition
4740
5054
 
4741
5055
  */
4742
- whereNotExists(subquery) {
5056
+ whereNotExists(subquery, correlate) {
4743
5057
  const subAst = this.resolveQueryNode(subquery);
4744
- return this.where(notExists(subAst));
5058
+ const correlated = this.applyCorrelation(subAst, correlate);
5059
+ return this.where(notExists(correlated));
4745
5060
  }
4746
5061
  /**
4747
5062
 
@@ -4754,17 +5069,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4754
5069
  * @returns New query builder instance with the relationship existence check
4755
5070
 
4756
5071
  */
4757
- whereHas(relationName, callback) {
5072
+ whereHas(relationName, callbackOrOptions, maybeOptions) {
4758
5073
  const relation = this.env.table.relations[relationName];
4759
5074
  if (!relation) {
4760
5075
  throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4761
5076
  }
5077
+ const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
5078
+ const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
4762
5079
  let subQb = this.createChildBuilder(relation.target);
4763
5080
  if (callback) {
4764
5081
  subQb = callback(subQb);
4765
5082
  }
4766
5083
  const subAst = subQb.getAST();
4767
- const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
5084
+ const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
4768
5085
  return this.where(exists(finalSubAst));
4769
5086
  }
4770
5087
  /**
@@ -4778,17 +5095,19 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4778
5095
  * @returns New query builder instance with the relationship non-existence check
4779
5096
 
4780
5097
  */
4781
- whereHasNot(relationName, callback) {
5098
+ whereHasNot(relationName, callbackOrOptions, maybeOptions) {
4782
5099
  const relation = this.env.table.relations[relationName];
4783
5100
  if (!relation) {
4784
5101
  throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4785
5102
  }
5103
+ const callback = typeof callbackOrOptions === "function" ? callbackOrOptions : void 0;
5104
+ const options = typeof callbackOrOptions === "function" ? maybeOptions : callbackOrOptions;
4786
5105
  let subQb = this.createChildBuilder(relation.target);
4787
5106
  if (callback) {
4788
5107
  subQb = callback(subQb);
4789
5108
  }
4790
5109
  const subAst = subQb.getAST();
4791
- const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
5110
+ const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst, options?.correlate);
4792
5111
  return this.where(notExists(finalSubAst));
4793
5112
  }
4794
5113
  /**
@@ -4840,6 +5159,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4840
5159
  var createColumn = (table, name) => ({ type: "Column", table, name });
4841
5160
  var createLiteral = (val) => ({ type: "Literal", value: val });
4842
5161
 
5162
+ // src/orm/entity-metadata.ts
5163
+ var metadataMap = /* @__PURE__ */ new Map();
5164
+ var getEntityMetadata = (target) => {
5165
+ return metadataMap.get(target);
5166
+ };
5167
+
5168
+ // src/decorators/bootstrap.ts
5169
+ var getTableDefFromEntity = (ctor) => {
5170
+ const meta = getEntityMetadata(ctor);
5171
+ if (!meta) return void 0;
5172
+ return meta.table;
5173
+ };
5174
+ var selectFromEntity = (ctor) => {
5175
+ const table = getTableDefFromEntity(ctor);
5176
+ if (!table) {
5177
+ throw new Error("Entity metadata has not been bootstrapped");
5178
+ }
5179
+ return new SelectQueryBuilder(table);
5180
+ };
5181
+
5182
+ // src/query-builder/select-helpers.ts
5183
+ function sel(table, ...cols) {
5184
+ const selection = {};
5185
+ for (const col2 of cols) {
5186
+ const def = table.columns[col2];
5187
+ if (!def) {
5188
+ throw new Error(`Column '${col2}' not found on table '${table.name}'`);
5189
+ }
5190
+ selection[col2] = def;
5191
+ }
5192
+ return selection;
5193
+ }
5194
+ function esel(entity, ...props) {
5195
+ const table = getTableDefFromEntity(entity);
5196
+ if (!table) {
5197
+ throw new Error(`No table definition registered for entity '${entity.name}'`);
5198
+ }
5199
+ const selection = {};
5200
+ for (const prop of props) {
5201
+ const col2 = table.columns[prop];
5202
+ if (!col2) {
5203
+ throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
5204
+ }
5205
+ selection[prop] = col2;
5206
+ }
5207
+ return selection;
5208
+ }
5209
+
4843
5210
  // src/query-builder/insert-query-state.ts
4844
5211
  var InsertQueryState = class _InsertQueryState {
4845
5212
  constructor(table, ast) {
@@ -4858,7 +5225,15 @@ var InsertQueryState = class _InsertQueryState {
4858
5225
  if (!rows.length) return this;
4859
5226
  const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
4860
5227
  const newRows = rows.map(
4861
- (row) => definedColumns.map((column) => valueToOperand(row[column.name]))
5228
+ (row, rowIndex) => definedColumns.map((column) => {
5229
+ const rawValue = row[column.name];
5230
+ if (!isValueOperandInput(rawValue)) {
5231
+ throw new Error(
5232
+ `Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
5233
+ );
5234
+ }
5235
+ return valueToOperand(rawValue);
5236
+ })
4862
5237
  );
4863
5238
  return this.clone({
4864
5239
  ...this.ast,
@@ -4909,6 +5284,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
4909
5284
  };
4910
5285
 
4911
5286
  // src/query-builder/update-query-state.ts
5287
+ var isUpdateValue = (value) => {
5288
+ if (value === null) return true;
5289
+ switch (typeof value) {
5290
+ case "string":
5291
+ case "number":
5292
+ case "boolean":
5293
+ return true;
5294
+ default:
5295
+ return isOperandNode(value);
5296
+ }
5297
+ };
4912
5298
  var UpdateQueryState = class _UpdateQueryState {
4913
5299
  constructor(table, ast) {
4914
5300
  this.table = table;
@@ -4922,14 +5308,21 @@ var UpdateQueryState = class _UpdateQueryState {
4922
5308
  return new _UpdateQueryState(this.table, nextAst);
4923
5309
  }
4924
5310
  withSet(values) {
4925
- const assignments = Object.entries(values).map(([column, value]) => ({
4926
- column: {
4927
- type: "Column",
4928
- table: this.table.name,
4929
- name: column
4930
- },
4931
- value: valueToOperand(value)
4932
- }));
5311
+ const assignments = Object.entries(values).map(([column, rawValue]) => {
5312
+ if (!isUpdateValue(rawValue)) {
5313
+ throw new Error(
5314
+ `Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
5315
+ );
5316
+ }
5317
+ return {
5318
+ column: {
5319
+ type: "Column",
5320
+ table: this.table.name,
5321
+ name: column
5322
+ },
5323
+ value: valueToOperand(rawValue)
5324
+ };
5325
+ });
4933
5326
  return this.clone({
4934
5327
  ...this.ast,
4935
5328
  set: assignments
@@ -6138,7 +6531,7 @@ var DefaultNamingStrategy = class {
6138
6531
  * @returns Capitalized table name (handles schema-qualified names)
6139
6532
  */
6140
6533
  tableToSymbol(table) {
6141
- const tableName = typeof table === "string" ? table : table.name;
6534
+ const tableName = typeof table === "string" ? table : table.type === "DerivedTable" ? table.alias : table.name;
6142
6535
  if (tableName.includes(".")) {
6143
6536
  return tableName.split(".").map((part) => this.capitalize(part)).join("");
6144
6537
  }
@@ -6197,8 +6590,8 @@ var TypeScriptGenerator = class {
6197
6590
  return `${key}: ${this.printOperand(operand)}`;
6198
6591
  });
6199
6592
  lines.push(`db.select({`);
6200
- selections.forEach((sel, index) => {
6201
- lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
6593
+ selections.forEach((sel2, index) => {
6594
+ lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
6202
6595
  });
6203
6596
  lines.push(`})`);
6204
6597
  lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
@@ -6481,26 +6874,6 @@ var TypeScriptGenerator = class {
6481
6874
  }
6482
6875
  };
6483
6876
 
6484
- // src/orm/entity-metadata.ts
6485
- var metadataMap = /* @__PURE__ */ new Map();
6486
- var getEntityMetadata = (target) => {
6487
- return metadataMap.get(target);
6488
- };
6489
-
6490
- // src/decorators/bootstrap.ts
6491
- var getTableDefFromEntity = (ctor) => {
6492
- const meta = getEntityMetadata(ctor);
6493
- if (!meta) return void 0;
6494
- return meta.table;
6495
- };
6496
- var selectFromEntity = (ctor) => {
6497
- const table = getTableDefFromEntity(ctor);
6498
- if (!table) {
6499
- throw new Error("Entity metadata has not been bootstrapped");
6500
- }
6501
- return new SelectQueryBuilder(table);
6502
- };
6503
-
6504
6877
  // src/orm/identity-map.ts
6505
6878
  var IdentityMap = class {
6506
6879
  constructor() {
@@ -6713,6 +7086,7 @@ var UnitOfWork = class {
6713
7086
  extractColumns(table, entity) {
6714
7087
  const payload = {};
6715
7088
  for (const column of Object.keys(table.columns)) {
7089
+ if (entity[column] === void 0) continue;
6716
7090
  payload[column] = entity[column];
6717
7091
  }
6718
7092
  return payload;
@@ -6767,24 +7141,30 @@ var UnitOfWork = class {
6767
7141
  var DomainEventBus = class {
6768
7142
  constructor(initialHandlers) {
6769
7143
  this.handlers = /* @__PURE__ */ new Map();
6770
- const handlers = initialHandlers ?? {};
6771
- Object.entries(handlers).forEach(([name, list]) => {
6772
- this.handlers.set(name, [...list]);
6773
- });
7144
+ if (initialHandlers) {
7145
+ for (const key in initialHandlers) {
7146
+ const type = key;
7147
+ const list = initialHandlers[type] ?? [];
7148
+ this.handlers.set(type, [...list]);
7149
+ }
7150
+ }
6774
7151
  }
6775
- register(name, handler) {
6776
- const existing = this.handlers.get(name) ?? [];
7152
+ on(type, handler) {
7153
+ const key = type;
7154
+ const existing = this.handlers.get(key) ?? [];
6777
7155
  existing.push(handler);
6778
- this.handlers.set(name, existing);
7156
+ this.handlers.set(key, existing);
7157
+ }
7158
+ register(type, handler) {
7159
+ this.on(type, handler);
6779
7160
  }
6780
7161
  async dispatch(trackedEntities, ctx) {
6781
7162
  for (const tracked of trackedEntities) {
6782
7163
  const entity = tracked.entity;
6783
- if (!entity.domainEvents || !entity.domainEvents.length) continue;
7164
+ if (!entity.domainEvents?.length) continue;
6784
7165
  for (const event of entity.domainEvents) {
6785
- const eventName = this.getEventName(event);
6786
- const handlers = this.handlers.get(eventName);
6787
- if (!handlers) continue;
7166
+ const handlers = this.handlers.get(event.type);
7167
+ if (!handlers?.length) continue;
6788
7168
  for (const handler of handlers) {
6789
7169
  await handler(event, ctx);
6790
7170
  }
@@ -6792,11 +7172,6 @@ var DomainEventBus = class {
6792
7172
  entity.domainEvents = [];
6793
7173
  }
6794
7174
  }
6795
- getEventName(event) {
6796
- if (!event) return "Unknown";
6797
- if (typeof event === "string") return event;
6798
- return event.constructor?.name ?? "Unknown";
6799
- }
6800
7175
  };
6801
7176
  var addDomainEvent = (entity, event) => {
6802
7177
  if (!entity.domainEvents) {
@@ -7038,8 +7413,8 @@ var OrmSession = class {
7038
7413
  registerInterceptor(interceptor) {
7039
7414
  this.interceptors.push(interceptor);
7040
7415
  }
7041
- registerDomainEventHandler(name, handler) {
7042
- this.domainEvents.register(name, handler);
7416
+ registerDomainEventHandler(type, handler) {
7417
+ this.domainEvents.on(type, handler);
7043
7418
  }
7044
7419
  async find(entityClass, id) {
7045
7420
  const table = getTableDefFromEntity(entityClass);
@@ -7051,7 +7426,11 @@ var OrmSession = class {
7051
7426
  if (!column) {
7052
7427
  throw new Error("Entity table does not expose a primary key");
7053
7428
  }
7054
- const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
7429
+ const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
7430
+ acc[col2.name] = col2;
7431
+ return acc;
7432
+ }, {});
7433
+ const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
7055
7434
  const rows = await executeHydrated(this, qb);
7056
7435
  return rows[0] ?? null;
7057
7436
  }
@@ -7163,7 +7542,6 @@ var Orm = class {
7163
7542
  const executor = this.executorFactory.createExecutor(options?.tx);
7164
7543
  return new OrmSession({ orm: this, executor });
7165
7544
  }
7166
- // Nice convenience:
7167
7545
  async transaction(fn4) {
7168
7546
  const executor = this.executorFactory.createTransactionalExecutor();
7169
7547
  const session = new OrmSession({ orm: this, executor });
@@ -7327,6 +7705,7 @@ function createMssqlExecutor(client) {
7327
7705
  columnOperand,
7328
7706
  concat,
7329
7707
  concatWs,
7708
+ correlateBy,
7330
7709
  cos,
7331
7710
  cot,
7332
7711
  count,
@@ -7355,6 +7734,7 @@ function createMssqlExecutor(client) {
7355
7734
  diffSchema,
7356
7735
  endOfMonth,
7357
7736
  eq,
7737
+ esel,
7358
7738
  executeHydrated,
7359
7739
  executeHydratedWithContexts,
7360
7740
  exists,
@@ -7366,6 +7746,7 @@ function createMssqlExecutor(client) {
7366
7746
  generateCreateTableSql,
7367
7747
  generateSchemaSql,
7368
7748
  getSchemaIntrospector,
7749
+ groupConcat,
7369
7750
  gt,
7370
7751
  gte,
7371
7752
  hasMany,
@@ -7380,6 +7761,7 @@ function createMssqlExecutor(client) {
7380
7761
  isNotNull,
7381
7762
  isNull,
7382
7763
  isOperandNode,
7764
+ isValueOperandInput,
7383
7765
  isWindowFunctionNode,
7384
7766
  jsonPath,
7385
7767
  lag,
@@ -7402,6 +7784,8 @@ function createMssqlExecutor(client) {
7402
7784
  lt,
7403
7785
  lte,
7404
7786
  ltrim,
7787
+ max,
7788
+ min,
7405
7789
  mod,
7406
7790
  month,
7407
7791
  neq,
@@ -7412,6 +7796,7 @@ function createMssqlExecutor(client) {
7412
7796
  now,
7413
7797
  ntile,
7414
7798
  or,
7799
+ outerRef,
7415
7800
  pi,
7416
7801
  position,
7417
7802
  pow,
@@ -7432,6 +7817,7 @@ function createMssqlExecutor(client) {
7432
7817
  rowsToQueryResult,
7433
7818
  rpad,
7434
7819
  rtrim,
7820
+ sel,
7435
7821
  sign,
7436
7822
  sin,
7437
7823
  space,