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.js CHANGED
@@ -237,10 +237,13 @@ var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressi
237
237
 
238
238
  // src/core/ast/expression-builders.ts
239
239
  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 };
240
+ if (isOperandNode(value)) {
241
+ return value;
242
242
  }
243
- return value;
243
+ return {
244
+ type: "Literal",
245
+ value
246
+ };
244
247
  };
245
248
  var toNode = (col2) => {
246
249
  if (isOperandNode(col2)) return col2;
@@ -251,10 +254,11 @@ var toLiteralNode = (value) => ({
251
254
  type: "Literal",
252
255
  value
253
256
  });
257
+ var isLiteralValue = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
258
+ var isValueOperandInput = (value) => isOperandNode(value) || isLiteralValue(value);
254
259
  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 };
260
+ if (isLiteralValue(val)) {
261
+ return valueToOperand(val);
258
262
  }
259
263
  return toNode(val);
260
264
  };
@@ -400,6 +404,62 @@ var windowFunction = (name, args = [], partitionBy, orderBy) => {
400
404
  return buildWindowFunction(name, nodeArgs, partitionNodes, orderNodes);
401
405
  };
402
406
 
407
+ // src/core/sql/sql.ts
408
+ var SQL_OPERATORS = {
409
+ /** Equality operator */
410
+ EQUALS: "=",
411
+ /** Not equals operator */
412
+ NOT_EQUALS: "!=",
413
+ /** Greater than operator */
414
+ GREATER_THAN: ">",
415
+ /** Greater than or equal operator */
416
+ GREATER_OR_EQUAL: ">=",
417
+ /** Less than operator */
418
+ LESS_THAN: "<",
419
+ /** Less than or equal operator */
420
+ LESS_OR_EQUAL: "<=",
421
+ /** LIKE pattern matching operator */
422
+ LIKE: "LIKE",
423
+ /** NOT LIKE pattern matching operator */
424
+ NOT_LIKE: "NOT LIKE",
425
+ /** IN membership operator */
426
+ IN: "IN",
427
+ /** NOT IN membership operator */
428
+ NOT_IN: "NOT IN",
429
+ /** BETWEEN range operator */
430
+ BETWEEN: "BETWEEN",
431
+ /** NOT BETWEEN range operator */
432
+ NOT_BETWEEN: "NOT BETWEEN",
433
+ /** IS NULL null check operator */
434
+ IS_NULL: "IS NULL",
435
+ /** IS NOT NULL null check operator */
436
+ IS_NOT_NULL: "IS NOT NULL",
437
+ /** Logical AND operator */
438
+ AND: "AND",
439
+ /** Logical OR operator */
440
+ OR: "OR",
441
+ /** EXISTS operator */
442
+ EXISTS: "EXISTS",
443
+ /** NOT EXISTS operator */
444
+ NOT_EXISTS: "NOT EXISTS"
445
+ };
446
+ var JOIN_KINDS = {
447
+ /** INNER JOIN type */
448
+ INNER: "INNER",
449
+ /** LEFT JOIN type */
450
+ LEFT: "LEFT",
451
+ /** RIGHT JOIN type */
452
+ RIGHT: "RIGHT",
453
+ /** CROSS JOIN type */
454
+ CROSS: "CROSS"
455
+ };
456
+ var ORDER_DIRECTIONS = {
457
+ /** Ascending order */
458
+ ASC: "ASC",
459
+ /** Descending order */
460
+ DESC: "DESC"
461
+ };
462
+
403
463
  // src/core/ast/aggregate-functions.ts
404
464
  var buildAggregate = (name) => (col2) => ({
405
465
  type: "Function",
@@ -409,6 +469,20 @@ var buildAggregate = (name) => (col2) => ({
409
469
  var count = buildAggregate("COUNT");
410
470
  var sum = buildAggregate("SUM");
411
471
  var avg = buildAggregate("AVG");
472
+ var min = buildAggregate("MIN");
473
+ var max = buildAggregate("MAX");
474
+ var toOrderByNode = (order) => ({
475
+ type: "OrderBy",
476
+ column: columnOperand(order.column),
477
+ direction: order.direction ?? ORDER_DIRECTIONS.ASC
478
+ });
479
+ var groupConcat = (col2, options) => ({
480
+ type: "Function",
481
+ name: "GROUP_CONCAT",
482
+ args: [columnOperand(col2)],
483
+ orderBy: options?.orderBy?.map(toOrderByNode),
484
+ separator: options?.separator !== void 0 ? valueToOperand(options.separator) : void 0
485
+ });
412
486
 
413
487
  // src/core/ast/expression-visitor.ts
414
488
  var expressionDispatchers = /* @__PURE__ */ new Map();
@@ -500,12 +574,17 @@ var toTableRef = (table) => ({
500
574
  });
501
575
 
502
576
  // src/core/functions/standard-strategy.ts
503
- var StandardFunctionStrategy = class {
577
+ var StandardFunctionStrategy = class _StandardFunctionStrategy {
504
578
  constructor() {
505
579
  this.renderers = /* @__PURE__ */ new Map();
506
580
  this.registerStandard();
507
581
  }
508
582
  registerStandard() {
583
+ this.add("COUNT", ({ compiledArgs }) => `COUNT(${compiledArgs.join(", ")})`);
584
+ this.add("SUM", ({ compiledArgs }) => `SUM(${compiledArgs[0]})`);
585
+ this.add("AVG", ({ compiledArgs }) => `AVG(${compiledArgs[0]})`);
586
+ this.add("MIN", ({ compiledArgs }) => `MIN(${compiledArgs[0]})`);
587
+ this.add("MAX", ({ compiledArgs }) => `MAX(${compiledArgs[0]})`);
509
588
  this.add("ABS", ({ compiledArgs }) => `ABS(${compiledArgs[0]})`);
510
589
  this.add("UPPER", ({ compiledArgs }) => `UPPER(${compiledArgs[0]})`);
511
590
  this.add("LOWER", ({ compiledArgs }) => `LOWER(${compiledArgs[0]})`);
@@ -532,6 +611,7 @@ var StandardFunctionStrategy = class {
532
611
  this.add("DAY_OF_WEEK", ({ compiledArgs }) => `DAYOFWEEK(${compiledArgs[0]})`);
533
612
  this.add("WEEK_OF_YEAR", ({ compiledArgs }) => `WEEKOFYEAR(${compiledArgs[0]})`);
534
613
  this.add("DATE_TRUNC", ({ compiledArgs }) => `DATE_TRUNC(${compiledArgs[0]}, ${compiledArgs[1]})`);
614
+ this.add("GROUP_CONCAT", (ctx) => this.renderGroupConcat(ctx));
535
615
  }
536
616
  add(name, renderer) {
537
617
  this.renderers.set(name, renderer);
@@ -539,6 +619,36 @@ var StandardFunctionStrategy = class {
539
619
  getRenderer(name) {
540
620
  return this.renderers.get(name);
541
621
  }
622
+ renderGroupConcat(ctx) {
623
+ const arg = ctx.compiledArgs[0];
624
+ const orderClause = this.buildOrderByExpression(ctx);
625
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
626
+ const separatorClause = this.formatGroupConcatSeparator(ctx);
627
+ return `GROUP_CONCAT(${arg}${orderSegment}${separatorClause})`;
628
+ }
629
+ buildOrderByExpression(ctx) {
630
+ const orderBy = ctx.node.orderBy;
631
+ if (!orderBy || orderBy.length === 0) {
632
+ return "";
633
+ }
634
+ const parts = orderBy.map((order) => `${ctx.compileOperand(order.column)} ${order.direction}`);
635
+ return `ORDER BY ${parts.join(", ")}`;
636
+ }
637
+ formatGroupConcatSeparator(ctx) {
638
+ if (!ctx.node.separator) {
639
+ return "";
640
+ }
641
+ return ` SEPARATOR ${ctx.compileOperand(ctx.node.separator)}`;
642
+ }
643
+ getGroupConcatSeparatorOperand(ctx) {
644
+ return ctx.node.separator ?? _StandardFunctionStrategy.DEFAULT_GROUP_CONCAT_SEPARATOR;
645
+ }
646
+ static {
647
+ this.DEFAULT_GROUP_CONCAT_SEPARATOR = {
648
+ type: "Literal",
649
+ value: ","
650
+ };
651
+ }
542
652
  };
543
653
 
544
654
  // src/core/dialect/abstract.ts
@@ -885,7 +995,11 @@ var Dialect = class _Dialect {
885
995
  const compiledArgs = fnNode.args.map((arg) => this.compileOperand(arg, ctx));
886
996
  const renderer = this.functionStrategy.getRenderer(fnNode.name);
887
997
  if (renderer) {
888
- return renderer({ node: fnNode, compiledArgs });
998
+ return renderer({
999
+ node: fnNode,
1000
+ compiledArgs,
1001
+ compileOperand: (operand) => this.compileOperand(operand, ctx)
1002
+ });
889
1003
  }
890
1004
  return `${fnNode.name}(${compiledArgs.join(", ")})`;
891
1005
  }
@@ -1308,6 +1422,14 @@ var PostgresFunctionStrategy = class extends StandardFunctionStrategy {
1308
1422
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1309
1423
  return `DATE_TRUNC('${partClean}', ${date})`;
1310
1424
  });
1425
+ this.add("GROUP_CONCAT", (ctx) => {
1426
+ const arg = ctx.compiledArgs[0];
1427
+ const orderClause = this.buildOrderByExpression(ctx);
1428
+ const orderSegment = orderClause ? ` ${orderClause}` : "";
1429
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1430
+ const separator = ctx.compileOperand(separatorOperand);
1431
+ return `STRING_AGG(${arg}, ${separator}${orderSegment})`;
1432
+ });
1311
1433
  }
1312
1434
  };
1313
1435
 
@@ -1552,6 +1674,12 @@ var SqliteFunctionStrategy = class extends StandardFunctionStrategy {
1552
1674
  }
1553
1675
  return `date(${date}, 'start of ${partClean}')`;
1554
1676
  });
1677
+ this.add("GROUP_CONCAT", (ctx) => {
1678
+ const arg = ctx.compiledArgs[0];
1679
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1680
+ const separator = ctx.compileOperand(separatorOperand);
1681
+ return `GROUP_CONCAT(${arg}, ${separator})`;
1682
+ });
1555
1683
  }
1556
1684
  };
1557
1685
 
@@ -1668,6 +1796,14 @@ var MssqlFunctionStrategy = class extends StandardFunctionStrategy {
1668
1796
  const partClean = String(partArg.value).replace(/['"]/g, "").toLowerCase();
1669
1797
  return `DATETRUNC(${partClean}, ${date})`;
1670
1798
  });
1799
+ this.add("GROUP_CONCAT", (ctx) => {
1800
+ const arg = ctx.compiledArgs[0];
1801
+ const separatorOperand = this.getGroupConcatSeparatorOperand(ctx);
1802
+ const separator = ctx.compileOperand(separatorOperand);
1803
+ const orderClause = this.buildOrderByExpression(ctx);
1804
+ const withinGroup = orderClause ? ` WITHIN GROUP (${orderClause})` : "";
1805
+ return `STRING_AGG(${arg}, ${separator})${withinGroup}`;
1806
+ });
1671
1807
  }
1672
1808
  };
1673
1809
 
@@ -2037,62 +2173,6 @@ var createJoinNode = (kind, tableName, condition, relationName) => ({
2037
2173
  meta: relationName ? { relationName } : void 0
2038
2174
  });
2039
2175
 
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
2176
  // src/query-builder/hydration-manager.ts
2097
2177
  var HydrationManager = class _HydrationManager {
2098
2178
  /**
@@ -4220,6 +4300,21 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4220
4300
  select(columns) {
4221
4301
  return this.clone(this.columnSelector.select(this.context, columns));
4222
4302
  }
4303
+ /**
4304
+ * Selects columns from the root table by name (typed).
4305
+ * @param cols - Column names on the root table
4306
+ */
4307
+ selectColumns(...cols) {
4308
+ const selection = {};
4309
+ for (const key of cols) {
4310
+ const col2 = this.env.table.columns[key];
4311
+ if (!col2) {
4312
+ throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
4313
+ }
4314
+ selection[key] = col2;
4315
+ }
4316
+ return this.select(selection);
4317
+ }
4223
4318
  /**
4224
4319
 
4225
4320
  * Selects raw column expressions
@@ -4380,6 +4475,47 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4380
4475
  nextLazy.add(relationName);
4381
4476
  return this.clone(this.context, nextLazy);
4382
4477
  }
4478
+ /**
4479
+ * Selects columns for a related table in a single hop.
4480
+ */
4481
+ selectRelationColumns(relationName, ...cols) {
4482
+ const relation = this.env.table.relations[relationName];
4483
+ if (!relation) {
4484
+ throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
4485
+ }
4486
+ const target = relation.target;
4487
+ for (const col2 of cols) {
4488
+ if (!target.columns[col2]) {
4489
+ throw new Error(
4490
+ `Column '${col2}' not found on related table '${target.name}' for relation '${relationName}'`
4491
+ );
4492
+ }
4493
+ }
4494
+ return this.include(relationName, { columns: cols });
4495
+ }
4496
+ /**
4497
+ * Convenience alias for selecting specific columns from a relation.
4498
+ */
4499
+ includePick(relationName, cols) {
4500
+ return this.selectRelationColumns(relationName, ...cols);
4501
+ }
4502
+ /**
4503
+ * Selects columns for the root table and relations from a single config object.
4504
+ */
4505
+ selectColumnsDeep(config) {
4506
+ let qb = this;
4507
+ if (config.root?.length) {
4508
+ qb = qb.selectColumns(...config.root);
4509
+ }
4510
+ for (const key of Object.keys(config)) {
4511
+ if (key === "root") continue;
4512
+ const relName = key;
4513
+ const cols = config[relName];
4514
+ if (!cols || !cols.length) continue;
4515
+ qb = qb.selectRelationColumns(relName, ...cols);
4516
+ }
4517
+ return qb;
4518
+ }
4383
4519
  getLazyRelations() {
4384
4520
  return Array.from(this.lazyRelations);
4385
4521
  }
@@ -4655,6 +4791,54 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4655
4791
  var createColumn = (table, name) => ({ type: "Column", table, name });
4656
4792
  var createLiteral = (val) => ({ type: "Literal", value: val });
4657
4793
 
4794
+ // src/orm/entity-metadata.ts
4795
+ var metadataMap = /* @__PURE__ */ new Map();
4796
+ var getEntityMetadata = (target) => {
4797
+ return metadataMap.get(target);
4798
+ };
4799
+
4800
+ // src/decorators/bootstrap.ts
4801
+ var getTableDefFromEntity = (ctor) => {
4802
+ const meta = getEntityMetadata(ctor);
4803
+ if (!meta) return void 0;
4804
+ return meta.table;
4805
+ };
4806
+ var selectFromEntity = (ctor) => {
4807
+ const table = getTableDefFromEntity(ctor);
4808
+ if (!table) {
4809
+ throw new Error("Entity metadata has not been bootstrapped");
4810
+ }
4811
+ return new SelectQueryBuilder(table);
4812
+ };
4813
+
4814
+ // src/query-builder/select-helpers.ts
4815
+ function sel(table, ...cols) {
4816
+ const selection = {};
4817
+ for (const col2 of cols) {
4818
+ const def = table.columns[col2];
4819
+ if (!def) {
4820
+ throw new Error(`Column '${col2}' not found on table '${table.name}'`);
4821
+ }
4822
+ selection[col2] = def;
4823
+ }
4824
+ return selection;
4825
+ }
4826
+ function esel(entity, ...props) {
4827
+ const table = getTableDefFromEntity(entity);
4828
+ if (!table) {
4829
+ throw new Error(`No table definition registered for entity '${entity.name}'`);
4830
+ }
4831
+ const selection = {};
4832
+ for (const prop of props) {
4833
+ const col2 = table.columns[prop];
4834
+ if (!col2) {
4835
+ throw new Error(`No column '${prop}' found for entity '${entity.name}'`);
4836
+ }
4837
+ selection[prop] = col2;
4838
+ }
4839
+ return selection;
4840
+ }
4841
+
4658
4842
  // src/query-builder/insert-query-state.ts
4659
4843
  var InsertQueryState = class _InsertQueryState {
4660
4844
  constructor(table, ast) {
@@ -4673,7 +4857,15 @@ var InsertQueryState = class _InsertQueryState {
4673
4857
  if (!rows.length) return this;
4674
4858
  const definedColumns = this.ast.columns.length ? this.ast.columns : buildColumnNodes(this.table, Object.keys(rows[0]));
4675
4859
  const newRows = rows.map(
4676
- (row) => definedColumns.map((column) => valueToOperand(row[column.name]))
4860
+ (row, rowIndex) => definedColumns.map((column) => {
4861
+ const rawValue = row[column.name];
4862
+ if (!isValueOperandInput(rawValue)) {
4863
+ throw new Error(
4864
+ `Invalid insert value for column "${column.name}" in row ${rowIndex}: only primitives, null, or OperandNodes are allowed`
4865
+ );
4866
+ }
4867
+ return valueToOperand(rawValue);
4868
+ })
4677
4869
  );
4678
4870
  return this.clone({
4679
4871
  ...this.ast,
@@ -4724,6 +4916,17 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
4724
4916
  };
4725
4917
 
4726
4918
  // src/query-builder/update-query-state.ts
4919
+ var isUpdateValue = (value) => {
4920
+ if (value === null) return true;
4921
+ switch (typeof value) {
4922
+ case "string":
4923
+ case "number":
4924
+ case "boolean":
4925
+ return true;
4926
+ default:
4927
+ return isOperandNode(value);
4928
+ }
4929
+ };
4727
4930
  var UpdateQueryState = class _UpdateQueryState {
4728
4931
  constructor(table, ast) {
4729
4932
  this.table = table;
@@ -4737,14 +4940,21 @@ var UpdateQueryState = class _UpdateQueryState {
4737
4940
  return new _UpdateQueryState(this.table, nextAst);
4738
4941
  }
4739
4942
  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
- }));
4943
+ const assignments = Object.entries(values).map(([column, rawValue]) => {
4944
+ if (!isUpdateValue(rawValue)) {
4945
+ throw new Error(
4946
+ `Invalid update value for column "${column}": only primitives, null, or OperandNodes are allowed`
4947
+ );
4948
+ }
4949
+ return {
4950
+ column: {
4951
+ type: "Column",
4952
+ table: this.table.name,
4953
+ name: column
4954
+ },
4955
+ value: valueToOperand(rawValue)
4956
+ };
4957
+ });
4748
4958
  return this.clone({
4749
4959
  ...this.ast,
4750
4960
  set: assignments
@@ -6012,8 +6222,8 @@ var TypeScriptGenerator = class {
6012
6222
  return `${key}: ${this.printOperand(operand)}`;
6013
6223
  });
6014
6224
  lines.push(`db.select({`);
6015
- selections.forEach((sel, index) => {
6016
- lines.push(` ${sel}${index < selections.length - 1 ? "," : ""}`);
6225
+ selections.forEach((sel2, index) => {
6226
+ lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
6017
6227
  });
6018
6228
  lines.push(`})`);
6019
6229
  lines.push(`.from(${this.namingStrategy.tableToSymbol(ast.from)})`);
@@ -6296,26 +6506,6 @@ var TypeScriptGenerator = class {
6296
6506
  }
6297
6507
  };
6298
6508
 
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
6509
  // src/orm/identity-map.ts
6320
6510
  var IdentityMap = class {
6321
6511
  constructor() {
@@ -6528,6 +6718,7 @@ var UnitOfWork = class {
6528
6718
  extractColumns(table, entity) {
6529
6719
  const payload = {};
6530
6720
  for (const column of Object.keys(table.columns)) {
6721
+ if (entity[column] === void 0) continue;
6531
6722
  payload[column] = entity[column];
6532
6723
  }
6533
6724
  return payload;
@@ -6582,24 +6773,30 @@ var UnitOfWork = class {
6582
6773
  var DomainEventBus = class {
6583
6774
  constructor(initialHandlers) {
6584
6775
  this.handlers = /* @__PURE__ */ new Map();
6585
- const handlers = initialHandlers ?? {};
6586
- Object.entries(handlers).forEach(([name, list]) => {
6587
- this.handlers.set(name, [...list]);
6588
- });
6776
+ if (initialHandlers) {
6777
+ for (const key in initialHandlers) {
6778
+ const type = key;
6779
+ const list = initialHandlers[type] ?? [];
6780
+ this.handlers.set(type, [...list]);
6781
+ }
6782
+ }
6589
6783
  }
6590
- register(name, handler) {
6591
- const existing = this.handlers.get(name) ?? [];
6784
+ on(type, handler) {
6785
+ const key = type;
6786
+ const existing = this.handlers.get(key) ?? [];
6592
6787
  existing.push(handler);
6593
- this.handlers.set(name, existing);
6788
+ this.handlers.set(key, existing);
6789
+ }
6790
+ register(type, handler) {
6791
+ this.on(type, handler);
6594
6792
  }
6595
6793
  async dispatch(trackedEntities, ctx) {
6596
6794
  for (const tracked of trackedEntities) {
6597
6795
  const entity = tracked.entity;
6598
- if (!entity.domainEvents || !entity.domainEvents.length) continue;
6796
+ if (!entity.domainEvents?.length) continue;
6599
6797
  for (const event of entity.domainEvents) {
6600
- const eventName = this.getEventName(event);
6601
- const handlers = this.handlers.get(eventName);
6602
- if (!handlers) continue;
6798
+ const handlers = this.handlers.get(event.type);
6799
+ if (!handlers?.length) continue;
6603
6800
  for (const handler of handlers) {
6604
6801
  await handler(event, ctx);
6605
6802
  }
@@ -6607,11 +6804,6 @@ var DomainEventBus = class {
6607
6804
  entity.domainEvents = [];
6608
6805
  }
6609
6806
  }
6610
- getEventName(event) {
6611
- if (!event) return "Unknown";
6612
- if (typeof event === "string") return event;
6613
- return event.constructor?.name ?? "Unknown";
6614
- }
6615
6807
  };
6616
6808
  var addDomainEvent = (entity, event) => {
6617
6809
  if (!entity.domainEvents) {
@@ -6853,8 +7045,8 @@ var OrmSession = class {
6853
7045
  registerInterceptor(interceptor) {
6854
7046
  this.interceptors.push(interceptor);
6855
7047
  }
6856
- registerDomainEventHandler(name, handler) {
6857
- this.domainEvents.register(name, handler);
7048
+ registerDomainEventHandler(type, handler) {
7049
+ this.domainEvents.on(type, handler);
6858
7050
  }
6859
7051
  async find(entityClass, id) {
6860
7052
  const table = getTableDefFromEntity(entityClass);
@@ -6866,7 +7058,11 @@ var OrmSession = class {
6866
7058
  if (!column) {
6867
7059
  throw new Error("Entity table does not expose a primary key");
6868
7060
  }
6869
- const qb = selectFromEntity(entityClass).where(eq(column, id)).limit(1);
7061
+ const columnSelections = Object.values(table.columns).reduce((acc, col2) => {
7062
+ acc[col2.name] = col2;
7063
+ return acc;
7064
+ }, {});
7065
+ const qb = selectFromEntity(entityClass).select(columnSelections).where(eq(column, id)).limit(1);
6870
7066
  const rows = await executeHydrated(this, qb);
6871
7067
  return rows[0] ?? null;
6872
7068
  }
@@ -6978,7 +7174,6 @@ var Orm = class {
6978
7174
  const executor = this.executorFactory.createExecutor(options?.tx);
6979
7175
  return new OrmSession({ orm: this, executor });
6980
7176
  }
6981
- // Nice convenience:
6982
7177
  async transaction(fn4) {
6983
7178
  const executor = this.executorFactory.createTransactionalExecutor();
6984
7179
  const session = new OrmSession({ orm: this, executor });
@@ -7169,6 +7364,7 @@ export {
7169
7364
  diffSchema,
7170
7365
  endOfMonth,
7171
7366
  eq,
7367
+ esel,
7172
7368
  executeHydrated,
7173
7369
  executeHydratedWithContexts,
7174
7370
  exists,
@@ -7180,6 +7376,7 @@ export {
7180
7376
  generateCreateTableSql,
7181
7377
  generateSchemaSql,
7182
7378
  getSchemaIntrospector,
7379
+ groupConcat,
7183
7380
  gt,
7184
7381
  gte,
7185
7382
  hasMany,
@@ -7194,6 +7391,7 @@ export {
7194
7391
  isNotNull,
7195
7392
  isNull,
7196
7393
  isOperandNode,
7394
+ isValueOperandInput,
7197
7395
  isWindowFunctionNode,
7198
7396
  jsonPath,
7199
7397
  lag,
@@ -7216,6 +7414,8 @@ export {
7216
7414
  lt,
7217
7415
  lte,
7218
7416
  ltrim,
7417
+ max,
7418
+ min,
7219
7419
  mod,
7220
7420
  month,
7221
7421
  neq,
@@ -7246,6 +7446,7 @@ export {
7246
7446
  rowsToQueryResult,
7247
7447
  rpad,
7248
7448
  rtrim,
7449
+ sel,
7249
7450
  sign,
7250
7451
  sin,
7251
7452
  space,