metal-orm 1.0.16 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +33 -37
  2. package/dist/decorators/index.cjs +152 -23
  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 +152 -23
  7. package/dist/decorators/index.js.map +1 -1
  8. package/dist/index.cjs +322 -115
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +53 -4
  11. package/dist/index.d.ts +53 -4
  12. package/dist/index.js +316 -115
  13. package/dist/index.js.map +1 -1
  14. package/dist/{select-BKZrMRCQ.d.cts → select-BPCn6MOH.d.cts} +183 -64
  15. package/dist/{select-BKZrMRCQ.d.ts → select-BPCn6MOH.d.ts} +183 -64
  16. package/package.json +2 -1
  17. package/src/core/ast/aggregate-functions.ts +50 -4
  18. package/src/core/ast/expression-builders.ts +22 -15
  19. package/src/core/ast/expression-nodes.ts +6 -0
  20. package/src/core/ddl/introspect/functions/postgres.ts +2 -6
  21. package/src/core/dialect/abstract.ts +12 -8
  22. package/src/core/dialect/mssql/functions.ts +24 -15
  23. package/src/core/dialect/postgres/functions.ts +33 -24
  24. package/src/core/dialect/sqlite/functions.ts +19 -12
  25. package/src/core/functions/datetime.ts +2 -1
  26. package/src/core/functions/numeric.ts +2 -1
  27. package/src/core/functions/standard-strategy.ts +52 -12
  28. package/src/core/functions/text.ts +2 -1
  29. package/src/core/functions/types.ts +8 -8
  30. package/src/index.ts +5 -4
  31. package/src/orm/domain-event-bus.ts +43 -25
  32. package/src/orm/entity-meta.ts +40 -0
  33. package/src/orm/execution-context.ts +6 -0
  34. package/src/orm/hydration-context.ts +6 -4
  35. package/src/orm/orm-session.ts +35 -24
  36. package/src/orm/orm.ts +10 -10
  37. package/src/orm/query-logger.ts +15 -0
  38. package/src/orm/runtime-types.ts +60 -2
  39. package/src/orm/transaction-runner.ts +7 -0
  40. package/src/orm/unit-of-work.ts +1 -0
  41. package/src/query-builder/insert-query-state.ts +13 -3
  42. package/src/query-builder/select-helpers.ts +50 -0
  43. package/src/query-builder/select.ts +122 -30
  44. package/src/query-builder/update-query-state.ts +31 -9
  45. package/src/schema/types.ts +16 -6
package/dist/index.cjs CHANGED
@@ -112,6 +112,7 @@ __export(index_exports, {
112
112
  diffSchema: () => diffSchema,
113
113
  endOfMonth: () => endOfMonth,
114
114
  eq: () => eq,
115
+ esel: () => esel,
115
116
  executeHydrated: () => executeHydrated,
116
117
  executeHydratedWithContexts: () => executeHydratedWithContexts,
117
118
  exists: () => exists,
@@ -123,6 +124,7 @@ __export(index_exports, {
123
124
  generateCreateTableSql: () => generateCreateTableSql,
124
125
  generateSchemaSql: () => generateSchemaSql,
125
126
  getSchemaIntrospector: () => getSchemaIntrospector,
127
+ groupConcat: () => groupConcat,
126
128
  gt: () => gt,
127
129
  gte: () => gte,
128
130
  hasMany: () => hasMany,
@@ -137,6 +139,7 @@ __export(index_exports, {
137
139
  isNotNull: () => isNotNull,
138
140
  isNull: () => isNull,
139
141
  isOperandNode: () => isOperandNode,
142
+ isValueOperandInput: () => isValueOperandInput,
140
143
  isWindowFunctionNode: () => isWindowFunctionNode,
141
144
  jsonPath: () => jsonPath,
142
145
  lag: () => lag,
@@ -159,6 +162,8 @@ __export(index_exports, {
159
162
  lt: () => lt,
160
163
  lte: () => lte,
161
164
  ltrim: () => ltrim,
165
+ max: () => max,
166
+ min: () => min,
162
167
  mod: () => mod,
163
168
  month: () => month,
164
169
  neq: () => neq,
@@ -189,6 +194,7 @@ __export(index_exports, {
189
194
  rowsToQueryResult: () => rowsToQueryResult,
190
195
  rpad: () => rpad,
191
196
  rtrim: () => rtrim,
197
+ sel: () => sel,
192
198
  sign: () => sign,
193
199
  sin: () => sin,
194
200
  space: () => space,
@@ -422,10 +428,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
422
428
 
423
429
  // src/core/ast/expression-builders.ts
424
430
  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 };
431
+ if (isOperandNode(value)) {
432
+ return value;
427
433
  }
428
- return value;
434
+ return {
435
+ type: "Literal",
436
+ value
437
+ };
429
438
  };
430
439
  var toNode = (col2) => {
431
440
  if (isOperandNode(col2)) return col2;
@@ -436,10 +445,11 @@ var toLiteralNode = (value) => ({
436
445
  type: "Literal",
437
446
  value
438
447
  });
448
+ var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
449
+ var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
439
450
  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 };
451
+ if (isLiteralValue(val)) {
452
+ return valueToOperand(val);
443
453
  }
444
454
  return toNode(val);
445
455
  };
@@ -585,6 +595,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
585
595
  return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
586
596
  };
587
597
 
598
+ // src/core/sql/sql.ts
599
+ var SQL_OPERATORS = {
600
+ /** Equality operator */
601
+ EQUALS: "=",
602
+ /** Not equals operator */
603
+ NOT_EQUALS: "!=",
604
+ /** Greater than operator */
605
+ GREATER_THAN: ">",
606
+ /** Greater than or equal operator */
607
+ GREATER_OR_EQUAL: ">=",
608
+ /** Less than operator */
609
+ LESS_THAN: "<",
610
+ /** Less than or equal operator */
611
+ LESS_OR_EQUAL: "<=",
612
+ /** LIKE pattern matching operator */
613
+ LIKE: "LIKE",
614
+ /** NOT LIKE pattern matching operator */
615
+ NOT_LIKE: "NOT LIKE",
616
+ /** IN membership operator */
617
+ IN: "IN",
618
+ /** NOT IN membership operator */
619
+ NOT_IN: "NOT IN",
620
+ /** BETWEEN range operator */
621
+ BETWEEN: "BETWEEN",
622
+ /** NOT BETWEEN range operator */
623
+ NOT_BETWEEN: "NOT BETWEEN",
624
+ /** IS NULL null check operator */
625
+ IS_NULL: "IS NULL",
626
+ /** IS NOT NULL null check operator */
627
+ IS_NOT_NULL: "IS NOT NULL",
628
+ /** Logical AND operator */
629
+ AND: "AND",
630
+ /** Logical OR operator */
631
+ OR: "OR",
632
+ /** EXISTS operator */
633
+ EXISTS: "EXISTS",
634
+ /** NOT EXISTS operator */
635
+ NOT_EXISTS: "NOT EXISTS"
636
+ };
637
+ var JOIN_KINDS = {
638
+ /** INNER JOIN type */
639
+ INNER: "INNER",
640
+ /** LEFT JOIN type */
641
+ LEFT: "LEFT",
642
+ /** RIGHT JOIN type */
643
+ RIGHT: "RIGHT",
644
+ /** CROSS JOIN type */
645
+ CROSS: "CROSS"
646
+ };
647
+ var ORDER_DIRECTIONS = {
648
+ /** Ascending order */
649
+ ASC: "ASC",
650
+ /** Descending order */
651
+ DESC: "DESC"
652
+ };
653
+
588
654
  // src/core/ast/aggregate-functions.ts
589
655
  var buildAggregate = (name) => (col2) => ({
590
656
  type: "Function",
@@ -594,6 +660,20 @@ var buildAggregate = (name) => (col2) => ({
594
660
  var count = buildAggregate("COUNT");
595
661
  var sum = buildAggregate("SUM");
596
662
  var avg = buildAggregate("AVG");
663
+ var min = buildAggregate("MIN");
664
+ var max = buildAggregate("MAX");
665
+ var toOrderByNode = (order) => ({
666
+ type: "OrderBy",
667
+ column: columnOperand(order.column),
668
+ direction: order.direction ?? ORDER_DIRECTIONS.ASC
669
+ });
670
+ var groupConcat = (col2, options) => ({
671
+ type: "Function",
672
+ name: "GROUP_CONCAT",
673
+ args: [columnOperand(col2)],
674
+ orderBy: options?.orderBy?.map(toOrderByNode),
675
+ separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
676
+ });
597
677
 
598
678
  // src/core/ast/expression-visitor.ts
599
679
  var expressionDispatchers = /* @__PURE__ */ new Map();
@@ -685,12 +765,17 @@ var toTableRef = (table) => ({
685
765
  });
686
766
 
687
767
  // src/core/functions/standard-strategy.ts
688
- var StandardFunctionStrategy = class {
768
+ var StandardFunctionStrategy = class _StandardFunctionStrategy {
689
769
  constructor() {
690
770
  this.renderers = /* @__PURE__ */ new Map();
691
771
  this.registerStandard();
692
772
  }
693
773
  registerStandard() {
774
+ this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
775
+ this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
776
+ this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
777
+ this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
778
+ this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
694
779
  this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
695
780
  this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
696
781
  this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
@@ -717,6 +802,7 @@ var StandardFunctionStrategy = class {
717
802
  this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
718
803
  this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
719
804
  this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
805
+ this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
720
806
  }
721
807
  add(name, renderer) {
722
808
  this.renderers.set(name, renderer);
@@ -724,6 +810,36 @@ var StandardFunctionStrategy = class {
724
810
  getRenderer(name) {
725
811
  return this.renderers.get(name);
726
812
  }
813
+ renderGroupConcat(ctx) {
814
+ const arg = ctx.compiledArgs[0];
815
+ const orderClause = this.buildOrderByExpression(ctx);
816
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
817
+ const separatorClause = this.formatGroupConcatSeparator(ctx);
818
+ return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
819
+ }
820
+ buildOrderByExpression(ctx) {
821
+ const orderBy = ctx.node.orderBy;
822
+ if (!orderBy || orderBy.length === 0) {
823
+ return "";
824
+ }
825
+ const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
826
+ return `ORDER BY ${parts.join(", ")}`;
827
+ }
828
+ formatGroupConcatSeparator(ctx) {
829
+ if (!ctx.node.separator) {
830
+ return "";
831
+ }
832
+ return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
833
+ }
834
+ getGroupConcatSeparatorOperand(ctx) {
835
+ return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
836
+ }
837
+ static {
838
+ this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
839
+ type: "Literal",
840
+ value: ","
841
+ };
842
+ }
727
843
  };
728
844
 
729
845
  // src/core/dialect/abstract.ts
@@ -1070,7 +1186,11 @@ var Dialect = class _Dialect {
1070
1186
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
1071
1187
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
1072
1188
  if (renderer) {
1073
- return renderer({ node: fnNode, compiledArgs });
1189
+ return renderer({
1190
+ node: fnNode,
1191
+ compiledArgs,
1192
+ compileOperand: (operand) => this.compileOperand(operand, ctx)
1193
+ });
1074
1194
  }
1075
1195
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
1076
1196
  }
@@ -1493,6 +1613,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
1493
1613
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1494
1614
  return `DATE_TRUNC('${partClean}', ${date})`;
1495
1615
  });
1616
+ this.add("GROUP_CONCAT", (ctx) => {
1617
+ const arg = ctx.compiledArgs[0];
1618
+ const orderClause = this.buildOrderByExpression(ctx);
1619
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
1620
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1621
+ const separator = ctx.compileOperand(separatorOperand);
1622
+ return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
1623
+ });
1496
1624
  }
1497
1625
  };
1498
1626
 
@@ -1737,6 +1865,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
1737
1865
  }
1738
1866
  return `date(${date}, 'start of ${partClean}')`;
1739
1867
  });
1868
+ this.add("GROUP_CONCAT", (ctx) => {
1869
+ const arg = ctx.compiledArgs[0];
1870
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1871
+ const separator = ctx.compileOperand(separatorOperand);
1872
+ return `GROUP_CONCAT(${arg}, ${separator})`;
1873
+ });
1740
1874
  }
1741
1875
  };
1742
1876
 
@@ -1853,6 +1987,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1853
1987
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1854
1988
  return `DATETRUNC(${partClean}, ${date})`;
1855
1989
  });
1990
+ this.add("GROUP_CONCAT", (ctx) => {
1991
+ const arg = ctx.compiledArgs[0];
1992
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1993
+ const separator = ctx.compileOperand(separatorOperand);
1994
+ const orderClause = this.buildOrderByExpression(ctx);
1995
+ const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
1996
+ return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
1997
+ });
1856
1998
  }
1857
1999
  };
1858
2000
 
@@ -2222,62 +2364,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
2222
2364
  meta: relationName ? { relationName } : void 0
2223
2365
  });
2224
2366
 
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
2367
  // src/query-builder/hydration-manager.ts
2282
2368
  var HydrationManager = class _HydrationManager {
2283
2369
  /**
@@ -4405,6 +4491,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4405
4491
  select(columns) {
4406
4492
  return this.clone(this.columnSelector.select(this.context, columns));
4407
4493
  }
4494
+ /**
4495
+ * Selects columns from the root table by name (typed).
4496
+ * @param cols - Column names on the root table
4497
+ */
4498
+ selectColumns(...cols) {
4499
+ const selection = {};
4500
+ for (const key of cols) {
4501
+ const col2 = this.env.table.columns[key];
4502
+ if (!col2) {
4503
+ throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
4504
+ }
4505
+ selection[key] = col2;
4506
+ }
4507
+ return this.select(selection);
4508
+ }
4408
4509
  /**
4409
4510
 
4410
4511
  * Selects raw column expressions
@@ -4565,6 +4666,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4565
4666
  nextLazy.add(relationName);
4566
4667
  return this.clone(this.context, nextLazy);
4567
4668
  }
4669
+ /**
4670
+ * Selects columns for a related table in a single hop.
4671
+ */
4672
+ selectRelationColumns(relationName, ...cols) {
4673
+ const relation = this.env.table.relations[relationName];
4674
+ if (!relation) {
4675
+ throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4676
+ }
4677
+ const target = relation.target;
4678
+ for (const col2 of cols) {
4679
+ if (!target.columns[col2]) {
4680
+ throw new Error(
4681
+ `Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
4682
+ );
4683
+ }
4684
+ }
4685
+ return this.include(relationName, { columns: cols });
4686
+ }
4687
+ /**
4688
+ * Convenience alias for selecting specific columns from a relation.
4689
+ */
4690
+ includePick(relationName, cols) {
4691
+ return this.selectRelationColumns(relationName, ...cols);
4692
+ }
4693
+ /**
4694
+ * Selects columns for the root table and relations from a single config object.
4695
+ */
4696
+ selectColumnsDeep(config) {
4697
+ let qb = this;
4698
+ if (config.root?.length) {
4699
+ qb = qb.selectColumns(...config.root);
4700
+ }
4701
+ for (const key of Object.keys(config)) {
4702
+ if (key === "root") continue;
4703
+ const relName = key;
4704
+ const cols = config[relName];
4705
+ if (!cols || !cols.length) continue;
4706
+ qb = qb.selectRelationColumns(relName, ...cols);
4707
+ }
4708
+ return qb;
4709
+ }
4568
4710
  getLazyRelations() {
4569
4711
  return Array.from(this.lazyRelations);
4570
4712
  }
@@ -4840,6 +4982,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4840
4982
  var createColumn = (table, name) => ({ type: "Column", table, name });
4841
4983
  var createLiteral = (val) => ({ type: "Literal", value: val });
4842
4984
 
4985
+ // src/orm/entity-metadata.ts
4986
+ var metadataMap = /* @__PURE__ */ new Map();
4987
+ var getEntityMetadata = (target) => {
4988
+ return metadataMap.get(target);
4989
+ };
4990
+
4991
+ // src/decorators/bootstrap.ts
4992
+ var getTableDefFromEntity = (ctor) => {
4993
+ const meta = getEntityMetadata(ctor);
4994
+ if (!meta) return void 0;
4995
+ return meta.table;
4996
+ };
4997
+ var selectFromEntity = (ctor) => {
4998
+ const table = getTableDefFromEntity(ctor);
4999
+ if (!table) {
5000
+ throw new Error("Entity metadata has not been bootstrapped");
5001
+ }
5002
+ return new SelectQueryBuilder(table);
5003
+ };
5004
+
5005
+ // src/query-builder/select-helpers.ts
5006
+ function sel(table, ...cols) {
5007
+ const selection = {};
5008
+ for (const col2 of cols) {
5009
+ const def = table.columns[col2];
5010
+ if (!def) {
5011
+ throw new Error(`Column '${col2}' not found on table '${table.name}'`);
5012
+ }
5013
+ selection[col2] = def;
5014
+ }
5015
+ return selection;
5016
+ }
5017
+ function esel(entity, ...props) {
5018
+ const table = getTableDefFromEntity(entity);
5019
+ if (!table) {
5020
+ throw new Error(`No table definition registered for entity '${entity.name}'`);
5021
+ }
5022
+ const selection = {};
5023
+ for (const prop of props) {
5024
+ const col2 = table.columns[prop];
5025
+ if (!col2) {
5026
+ throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
5027
+ }
5028
+ selection[prop] = col2;
5029
+ }
5030
+ return selection;
5031
+ }
5032
+
4843
5033
  // src/query-builder/insert-query-state.ts
4844
5034
  var InsertQueryState = class _InsertQueryState {
4845
5035
  constructor(table, ast) {
@@ -4858,7 +5048,15 @@ var InsertQueryState = class _InsertQueryState {
4858
5048
  if (!rows.length) return this;
4859
5049
  const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
4860
5050
  const newRows = rows.map(
4861
- (row) => definedColumns.map((column) => valueToOperand(row[column.name]))
5051
+ (row, rowIndex) => definedColumns.map((column) => {
5052
+ const rawValue = row[column.name];
5053
+ if (!isValueOperandInput(rawValue)) {
5054
+ throw new Error(
5055
+ `Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
5056
+ );
5057
+ }
5058
+ return valueToOperand(rawValue);
5059
+ })
4862
5060
  );
4863
5061
  return this.clone({
4864
5062
  ...this.ast,
@@ -4909,6 +5107,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
4909
5107
  };
4910
5108
 
4911
5109
  // src/query-builder/update-query-state.ts
5110
+ var isUpdateValue = (value) => {
5111
+ if (value === null) return true;
5112
+ switch (typeof value) {
5113
+ case "string":
5114
+ case "number":
5115
+ case "boolean":
5116
+ return true;
5117
+ default:
5118
+ return isOperandNode(value);
5119
+ }
5120
+ };
4912
5121
  var UpdateQueryState = class _UpdateQueryState {
4913
5122
  constructor(table, ast) {
4914
5123
  this.table = table;
@@ -4922,14 +5131,21 @@ var UpdateQueryState = class _UpdateQueryState {
4922
5131
  return new _UpdateQueryState(this.table, nextAst);
4923
5132
  }
4924
5133
  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
- }));
5134
+ const assignments = Object.entries(values).map(([column, rawValue]) => {
5135
+ if (!isUpdateValue(rawValue)) {
5136
+ throw new Error(
5137
+ `Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
5138
+ );
5139
+ }
5140
+ return {
5141
+ column: {
5142
+ type: "Column",
5143
+ table: this.table.name,
5144
+ name: column
5145
+ },
5146
+ value: valueToOperand(rawValue)
5147
+ };
5148
+ });
4933
5149
  return this.clone({
4934
5150
  ...this.ast,
4935
5151
  set: assignments
@@ -6197,8 +6413,8 @@ var TypeScriptGenerator = class {
6197
6413
  return `${key}: ${this.printOperand(operand)}`;
6198
6414
  });
6199
6415
  lines.push(`db.select({`);
6200
- selections.forEach((sel, index) => {
6201
- lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
6416
+ selections.forEach((sel2, index) => {
6417
+ lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
6202
6418
  });
6203
6419
  lines.push(`})`);
6204
6420
  lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
@@ -6481,26 +6697,6 @@ var TypeScriptGenerator = class {
6481
6697
  }
6482
6698
  };
6483
6699
 
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
6700
  // src/orm/identity-map.ts
6505
6701
  var IdentityMap = class {
6506
6702
  constructor() {
@@ -6713,6 +6909,7 @@ var UnitOfWork = class {
6713
6909
  extractColumns(table, entity) {
6714
6910
  const payload = {};
6715
6911
  for (const column of Object.keys(table.columns)) {
6912
+ if (entity[column] === void 0) continue;
6716
6913
  payload[column] = entity[column];
6717
6914
  }
6718
6915
  return payload;
@@ -6767,24 +6964,30 @@ var UnitOfWork = class {
6767
6964
  var DomainEventBus = class {
6768
6965
  constructor(initialHandlers) {
6769
6966
  this.handlers = /* @__PURE__ */ new Map();
6770
- const handlers = initialHandlers ?? {};
6771
- Object.entries(handlers).forEach(([name, list]) => {
6772
- this.handlers.set(name, [...list]);
6773
- });
6967
+ if (initialHandlers) {
6968
+ for (const key in initialHandlers) {
6969
+ const type = key;
6970
+ const list = initialHandlers[type] ?? [];
6971
+ this.handlers.set(type, [...list]);
6972
+ }
6973
+ }
6774
6974
  }
6775
- register(name, handler) {
6776
- const existing = this.handlers.get(name) ?? [];
6975
+ on(type, handler) {
6976
+ const key = type;
6977
+ const existing = this.handlers.get(key) ?? [];
6777
6978
  existing.push(handler);
6778
- this.handlers.set(name, existing);
6979
+ this.handlers.set(key, existing);
6980
+ }
6981
+ register(type, handler) {
6982
+ this.on(type, handler);
6779
6983
  }
6780
6984
  async dispatch(trackedEntities, ctx) {
6781
6985
  for (const tracked of trackedEntities) {
6782
6986
  const entity = tracked.entity;
6783
- if (!entity.domainEvents || !entity.domainEvents.length) continue;
6987
+ if (!entity.domainEvents?.length) continue;
6784
6988
  for (const event of entity.domainEvents) {
6785
- const eventName = this.getEventName(event);
6786
- const handlers = this.handlers.get(eventName);
6787
- if (!handlers) continue;
6989
+ const handlers = this.handlers.get(event.type);
6990
+ if (!handlers?.length) continue;
6788
6991
  for (const handler of handlers) {
6789
6992
  await handler(event, ctx);
6790
6993
  }
@@ -6792,11 +6995,6 @@ var DomainEventBus = class {
6792
6995
  entity.domainEvents = [];
6793
6996
  }
6794
6997
  }
6795
- getEventName(event) {
6796
- if (!event) return "Unknown";
6797
- if (typeof event === "string") return event;
6798
- return event.constructor?.name ?? "Unknown";
6799
- }
6800
6998
  };
6801
6999
  var addDomainEvent = (entity, event) => {
6802
7000
  if (!entity.domainEvents) {
@@ -7038,8 +7236,8 @@ var OrmSession = class {
7038
7236
  registerInterceptor(interceptor) {
7039
7237
  this.interceptors.push(interceptor);
7040
7238
  }
7041
- registerDomainEventHandler(name, handler) {
7042
- this.domainEvents.register(name, handler);
7239
+ registerDomainEventHandler(type, handler) {
7240
+ this.domainEvents.on(type, handler);
7043
7241
  }
7044
7242
  async find(entityClass, id) {
7045
7243
  const table = getTableDefFromEntity(entityClass);
@@ -7051,7 +7249,11 @@ var OrmSession = class {
7051
7249
  if (!column) {
7052
7250
  throw new Error("Entity table does not expose a primary key");
7053
7251
  }
7054
- const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
7252
+ const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
7253
+ acc[col2.name] = col2;
7254
+ return acc;
7255
+ }, {});
7256
+ const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
7055
7257
  const rows = await executeHydrated(this, qb);
7056
7258
  return rows[0] ?? null;
7057
7259
  }
@@ -7163,7 +7365,6 @@ var Orm = class {
7163
7365
  const executor = this.executorFactory.createExecutor(options?.tx);
7164
7366
  return new OrmSession({ orm: this, executor });
7165
7367
  }
7166
- // Nice convenience:
7167
7368
  async transaction(fn4) {
7168
7369
  const executor = this.executorFactory.createTransactionalExecutor();
7169
7370
  const session = new OrmSession({ orm: this, executor });
@@ -7355,6 +7556,7 @@ function createMssqlExecutor(client) {
7355
7556
  diffSchema,
7356
7557
  endOfMonth,
7357
7558
  eq,
7559
+ esel,
7358
7560
  executeHydrated,
7359
7561
  executeHydratedWithContexts,
7360
7562
  exists,
@@ -7366,6 +7568,7 @@ function createMssqlExecutor(client) {
7366
7568
  generateCreateTableSql,
7367
7569
  generateSchemaSql,
7368
7570
  getSchemaIntrospector,
7571
+ groupConcat,
7369
7572
  gt,
7370
7573
  gte,
7371
7574
  hasMany,
@@ -7380,6 +7583,7 @@ function createMssqlExecutor(client) {
7380
7583
  isNotNull,
7381
7584
  isNull,
7382
7585
  isOperandNode,
7586
+ isValueOperandInput,
7383
7587
  isWindowFunctionNode,
7384
7588
  jsonPath,
7385
7589
  lag,
@@ -7402,6 +7606,8 @@ function createMssqlExecutor(client) {
7402
7606
  lt,
7403
7607
  lte,
7404
7608
  ltrim,
7609
+ max,
7610
+ min,
7405
7611
  mod,
7406
7612
  month,
7407
7613
  neq,
@@ -7432,6 +7638,7 @@ function createMssqlExecutor(client) {
7432
7638
  rowsToQueryResult,
7433
7639
  rpad,
7434
7640
  rtrim,
7641
+ sel,
7435
7642
  sign,
7436
7643
  sin,
7437
7644
  space,