metal-orm 1.0.42 → 1.0.43

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 (86) hide show
  1. package/README.md +22 -7
  2. package/dist/index.cjs +130 -74
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +121 -96
  5. package/dist/index.d.ts +121 -96
  6. package/dist/index.js +128 -74
  7. package/dist/index.js.map +1 -1
  8. package/package.json +8 -2
  9. package/scripts/run-eslint.mjs +34 -0
  10. package/src/codegen/typescript.ts +32 -15
  11. package/src/core/ast/builders.ts +7 -2
  12. package/src/core/ast/expression-builders.ts +0 -2
  13. package/src/core/ast/expression-nodes.ts +14 -5
  14. package/src/core/ast/expression-visitor.ts +11 -8
  15. package/src/core/ast/join-node.ts +1 -1
  16. package/src/core/ast/query.ts +6 -6
  17. package/src/core/ast/window-functions.ts +10 -2
  18. package/src/core/ddl/dialects/base-schema-dialect.ts +30 -3
  19. package/src/core/ddl/dialects/mssql-schema-dialect.ts +4 -0
  20. package/src/core/ddl/dialects/mysql-schema-dialect.ts +2 -0
  21. package/src/core/ddl/dialects/postgres-schema-dialect.ts +13 -1
  22. package/src/core/ddl/dialects/render-reference.test.ts +69 -0
  23. package/src/core/ddl/dialects/sqlite-schema-dialect.ts +9 -0
  24. package/src/core/ddl/introspect/mssql.ts +42 -8
  25. package/src/core/ddl/introspect/mysql.ts +30 -6
  26. package/src/core/ddl/introspect/postgres.ts +88 -34
  27. package/src/core/ddl/introspect/run-select.ts +6 -4
  28. package/src/core/ddl/introspect/sqlite.ts +56 -11
  29. package/src/core/ddl/introspect/types.ts +0 -1
  30. package/src/core/ddl/introspect/utils.ts +3 -3
  31. package/src/core/ddl/schema-dialect.ts +1 -0
  32. package/src/core/ddl/schema-generator.ts +4 -12
  33. package/src/core/ddl/sql-writing.ts +4 -4
  34. package/src/core/dialect/abstract.ts +18 -6
  35. package/src/core/dialect/base/function-table-formatter.ts +3 -2
  36. package/src/core/dialect/base/join-compiler.ts +5 -3
  37. package/src/core/dialect/base/returning-strategy.ts +1 -0
  38. package/src/core/dialect/base/sql-dialect.ts +3 -3
  39. package/src/core/dialect/mssql/functions.ts +24 -25
  40. package/src/core/dialect/mssql/index.ts +1 -4
  41. package/src/core/dialect/mysql/functions.ts +0 -1
  42. package/src/core/dialect/postgres/functions.ts +33 -34
  43. package/src/core/dialect/postgres/index.ts +1 -0
  44. package/src/core/dialect/sqlite/functions.ts +18 -19
  45. package/src/core/dialect/sqlite/index.ts +2 -0
  46. package/src/core/execution/db-executor.ts +1 -1
  47. package/src/core/execution/executors/mysql-executor.ts +2 -2
  48. package/src/core/execution/executors/postgres-executor.ts +1 -1
  49. package/src/core/execution/pooling/pool.ts +2 -0
  50. package/src/core/functions/datetime.ts +1 -1
  51. package/src/core/functions/numeric.ts +1 -1
  52. package/src/core/functions/text.ts +1 -1
  53. package/src/decorators/bootstrap.ts +27 -8
  54. package/src/decorators/column.ts +3 -11
  55. package/src/decorators/decorator-metadata.ts +3 -9
  56. package/src/decorators/entity.ts +21 -5
  57. package/src/decorators/relations.ts +2 -11
  58. package/src/orm/entity-context.ts +8 -8
  59. package/src/orm/entity-meta.ts +8 -8
  60. package/src/orm/entity-metadata.ts +11 -9
  61. package/src/orm/entity.ts +28 -29
  62. package/src/orm/execute.ts +4 -4
  63. package/src/orm/hydration.ts +42 -39
  64. package/src/orm/identity-map.ts +1 -1
  65. package/src/orm/lazy-batch.ts +9 -9
  66. package/src/orm/orm-session.ts +24 -23
  67. package/src/orm/orm.ts +2 -5
  68. package/src/orm/relation-change-processor.ts +12 -11
  69. package/src/orm/relations/belongs-to.ts +11 -11
  70. package/src/orm/relations/has-many.ts +10 -10
  71. package/src/orm/relations/has-one.ts +8 -7
  72. package/src/orm/relations/many-to-many.ts +13 -13
  73. package/src/orm/runtime-types.ts +4 -4
  74. package/src/orm/save-graph.ts +31 -25
  75. package/src/orm/unit-of-work.ts +17 -17
  76. package/src/query-builder/delete.ts +4 -3
  77. package/src/query-builder/hydration-manager.ts +6 -5
  78. package/src/query-builder/insert.ts +12 -8
  79. package/src/query-builder/query-ast-service.ts +2 -2
  80. package/src/query-builder/raw-column-parser.ts +2 -1
  81. package/src/query-builder/select-helpers.ts +2 -2
  82. package/src/query-builder/select.ts +31 -31
  83. package/src/query-builder/update.ts +4 -3
  84. package/src/schema/column.ts +26 -26
  85. package/src/schema/table.ts +47 -18
  86. package/src/schema/types.ts +22 -22
package/README.md CHANGED
@@ -269,6 +269,7 @@ import {
269
269
  eq,
270
270
  count,
271
271
  rowNumber,
272
+ MySqlDialect,
272
273
  sel,
273
274
  hydrateRows,
274
275
  } from 'metal-orm';
@@ -298,18 +299,24 @@ users.columns.name.notNull = true;
298
299
  users.columns.email.unique = true;
299
300
 
300
301
  // Build a query with relation & window function
302
+ const u = sel(users, 'id', 'name', 'email');
303
+ const p = sel(posts, 'id', 'userId');
304
+
301
305
  const builder = new SelectQueryBuilder(users)
302
306
  .select({
303
- ...sel(users, 'id', 'name', 'email'),
304
- postCount: count(posts.columns.id),
307
+ ...u,
308
+ postCount: count(p.id),
305
309
  rank: rowNumber(), // window function helper
306
310
  })
307
- .leftJoin(posts, eq(posts.columns.userId, users.columns.id))
308
- .groupBy(users.columns.id, users.columns.name, users.columns.email)
309
- .orderBy(count(posts.columns.id), 'DESC')
311
+ .leftJoin(posts, eq(p.userId, u.id))
312
+ .groupBy(u.id)
313
+ .groupBy(u.name)
314
+ .groupBy(u.email)
315
+ .orderBy(count(p.id), 'DESC')
310
316
  .limit(10)
311
317
  .includePick('posts', ['id', 'title', 'createdAt']); // eager relation for hydration
312
318
 
319
+ const dialect = new MySqlDialect();
313
320
  const { sql, params } = builder.compile(dialect);
314
321
  const [rows] = await connection.execute(sql, params);
315
322
 
@@ -353,6 +360,7 @@ import {
353
360
  MySqlDialect,
354
361
  SelectQueryBuilder,
355
362
  eq,
363
+ tableRef,
356
364
  createMysqlExecutor,
357
365
  } from 'metal-orm';
358
366
 
@@ -365,16 +373,19 @@ const orm = new Orm({
365
373
  executorFactory: {
366
374
  createExecutor: () => executor,
367
375
  createTransactionalExecutor: () => executor,
376
+ dispose: async () => {},
368
377
  },
369
378
  });
370
379
  const session = new OrmSession({ orm, executor });
371
380
 
381
+ const u = tableRef(users);
382
+
372
383
  // 2) Load entities with lazy relations
373
384
  const [user] = await new SelectQueryBuilder(users)
374
385
  .selectColumns('id', 'name', 'email')
375
386
  .includeLazy('posts') // HasMany as a lazy collection
376
387
  .includeLazy('roles') // BelongsToMany as a lazy collection
377
- .where(eq(users.columns.id, 1))
388
+ .where(eq(u.id, 1))
378
389
  .execute(session);
379
390
 
380
391
  // user is an EntityInstance<typeof users>
@@ -422,6 +433,8 @@ import {
422
433
  BelongsTo,
423
434
  bootstrapEntities,
424
435
  selectFromEntity,
436
+ entityRef,
437
+ eq,
425
438
  } from 'metal-orm';
426
439
 
427
440
  @Entity()
@@ -472,15 +485,17 @@ const orm = new Orm({
472
485
  executorFactory: {
473
486
  createExecutor: () => executor,
474
487
  createTransactionalExecutor: () => executor,
488
+ dispose: async () => {},
475
489
  },
476
490
  });
477
491
  const session = new OrmSession({ orm, executor });
478
492
 
479
493
  // 3) Query starting from the entity class
494
+ const U = entityRef(User);
480
495
  const [user] = await selectFromEntity(User)
481
496
  .selectColumns('id', 'name')
482
497
  .includeLazy('posts')
483
- .where(/* same eq()/and() API as before */)
498
+ .where(eq(U.id, 1))
484
499
  .execute(session);
485
500
 
486
501
  user.posts.add({ title: 'From decorators' });
package/dist/index.cjs CHANGED
@@ -127,6 +127,7 @@ __export(index_exports, {
127
127
  diffSchema: () => diffSchema,
128
128
  div: () => div,
129
129
  endOfMonth: () => endOfMonth,
130
+ entityRef: () => entityRef,
130
131
  eq: () => eq,
131
132
  esel: () => esel,
132
133
  executeHydrated: () => executeHydrated,
@@ -139,6 +140,7 @@ __export(index_exports, {
139
140
  fromUnixTime: () => fromUnixTime,
140
141
  generateCreateTableSql: () => generateCreateTableSql,
141
142
  generateSchemaSql: () => generateSchemaSql,
143
+ getColumn: () => getColumn,
142
144
  getSchemaIntrospector: () => getSchemaIntrospector,
143
145
  getTableDefFromEntity: () => getTableDefFromEntity,
144
146
  groupConcat: () => groupConcat,
@@ -247,7 +249,8 @@ module.exports = __toCommonJS(index_exports);
247
249
  // src/schema/table.ts
248
250
  var defineTable = (name, columns, relations = {}, hooks, options = {}) => {
249
251
  const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
250
- acc[key] = { ...def, name: key, table: name };
252
+ const colDef = { ...def, name: key, table: name };
253
+ acc[key] = colDef;
251
254
  return acc;
252
255
  }, {});
253
256
  return {
@@ -271,17 +274,20 @@ var withColumnProps = (table) => {
271
274
  if (cached) return cached;
272
275
  const proxy = new Proxy(table, {
273
276
  get(target, prop, receiver) {
274
- if (prop === "$") return target.columns;
277
+ const t = target;
278
+ if (prop === "$") return t.columns;
275
279
  if (Reflect.has(target, prop)) return Reflect.get(target, prop, receiver);
276
- if (typeof prop === "string" && prop in target.columns) return target.columns[prop];
280
+ if (typeof prop === "string" && prop in t.columns) return t.columns[prop];
277
281
  return void 0;
278
282
  },
279
283
  has(target, prop) {
280
- return prop === "$" || Reflect.has(target, prop) || typeof prop === "string" && prop in target.columns;
284
+ const t = target;
285
+ return prop === "$" || Reflect.has(target, prop) || typeof prop === "string" && prop in t.columns;
281
286
  },
282
287
  ownKeys(target) {
288
+ const t = target;
283
289
  const base = Reflect.ownKeys(target);
284
- const cols = Object.keys(target.columns);
290
+ const cols = Object.keys(t.columns);
285
291
  for (const k of cols) {
286
292
  if (!base.includes(k)) base.push(k);
287
293
  }
@@ -313,6 +319,14 @@ var withColumnProps = (table) => {
313
319
  return proxy;
314
320
  };
315
321
  var tableRef = (table) => withColumnProps(table);
322
+ function getColumn(table, key) {
323
+ const col2 = table.columns[key];
324
+ if (!col2) {
325
+ const tableName = table.name || "<unknown>";
326
+ throw new Error(`Column '${key}' does not exist on table '${tableName}'`);
327
+ }
328
+ return col2;
329
+ }
316
330
 
317
331
  // src/schema/column.ts
318
332
  var col = {
@@ -517,10 +531,14 @@ var operandTypes = /* @__PURE__ */ new Set([
517
531
  "CaseExpression",
518
532
  "WindowFunction"
519
533
  ]);
520
- var isOperandNode = (node) => node && operandTypes.has(node.type);
521
- var isFunctionNode = (node) => node?.type === "Function";
522
- var isCaseExpressionNode = (node) => node?.type === "CaseExpression";
523
- var isWindowFunctionNode = (node) => node?.type === "WindowFunction";
534
+ var hasTypeProperty = (value) => typeof value === "object" && value !== null && "type" in value;
535
+ var isOperandNode = (node) => {
536
+ if (!hasTypeProperty(node)) return false;
537
+ return operandTypes.has(node.type);
538
+ };
539
+ var isFunctionNode = (node) => isOperandNode(node) && node.type === "Function";
540
+ var isCaseExpressionNode = (node) => isOperandNode(node) && node.type === "CaseExpression";
541
+ var isWindowFunctionNode = (node) => isOperandNode(node) && node.type === "WindowFunction";
524
542
  var isExpressionSelectionNode = (node) => isFunctionNode(node) || isCaseExpressionNode(node) || isWindowFunctionNode(node);
525
543
 
526
544
  // src/core/ast/expression-builders.ts
@@ -810,14 +828,15 @@ var registerOperandDispatcher = (type, dispatcher) => {
810
828
  };
811
829
  var clearExpressionDispatchers = () => expressionDispatchers.clear();
812
830
  var clearOperandDispatchers = () => operandDispatchers.clear();
831
+ var getNodeType = (node) => typeof node === "object" && node !== null && typeof node.type === "string" ? node.type : void 0;
813
832
  var unsupportedExpression = (node) => {
814
- throw new Error(`Unsupported expression type "${node?.type ?? "unknown"}"`);
833
+ throw new Error(`Unsupported expression type "${getNodeType(node) ?? "unknown"}"`);
815
834
  };
816
835
  var unsupportedOperand = (node) => {
817
- throw new Error(`Unsupported operand type "${node?.type ?? "unknown"}"`);
836
+ throw new Error(`Unsupported operand type "${getNodeType(node) ?? "unknown"}"`);
818
837
  };
819
838
  var visitExpression = (node, visitor) => {
820
- const dynamic = expressionDispatchers.get(node?.type);
839
+ const dynamic = expressionDispatchers.get(node.type);
821
840
  if (dynamic) return dynamic(node, visitor);
822
841
  switch (node.type) {
823
842
  case "BinaryExpression":
@@ -848,7 +867,7 @@ var visitExpression = (node, visitor) => {
848
867
  return unsupportedExpression(node);
849
868
  };
850
869
  var visitOperand = (node, visitor) => {
851
- const dynamic = operandDispatchers.get(node?.type);
870
+ const dynamic = operandDispatchers.get(node.type);
852
871
  if (dynamic) return dynamic(node, visitor);
853
872
  switch (node.type) {
854
873
  case "Column":
@@ -1075,7 +1094,8 @@ var Dialect = class _Dialect {
1075
1094
  if (!where) return "";
1076
1095
  return ` WHERE ${this.compileExpression(where, ctx)}`;
1077
1096
  }
1078
- compileReturning(returning, ctx) {
1097
+ compileReturning(returning, _ctx) {
1098
+ void _ctx;
1079
1099
  if (!returning || returning.length === 0) return "";
1080
1100
  throw new Error("RETURNING is not supported by this dialect.");
1081
1101
  }
@@ -1123,14 +1143,16 @@ var Dialect = class _Dialect {
1123
1143
  * @param index - Parameter index
1124
1144
  * @returns Formatted placeholder string
1125
1145
  */
1126
- formatPlaceholder(index) {
1146
+ formatPlaceholder(_index) {
1147
+ void _index;
1127
1148
  return "?";
1128
1149
  }
1129
1150
  /**
1130
1151
  * Whether the current dialect supports a given set operation.
1131
1152
  * Override in concrete dialects to restrict support.
1132
1153
  */
1133
- supportsSetOperation(kind) {
1154
+ supportsSetOperation(_kind) {
1155
+ void _kind;
1134
1156
  return true;
1135
1157
  }
1136
1158
  /**
@@ -1323,15 +1345,22 @@ var Dialect = class _Dialect {
1323
1345
  }
1324
1346
  registerDefaultOperandCompilers() {
1325
1347
  this.registerOperandCompiler("Literal", (literal, ctx) => ctx.addParameter(literal.value));
1326
- this.registerOperandCompiler("AliasRef", (alias, _ctx) => this.quoteIdentifier(alias.name));
1348
+ this.registerOperandCompiler("AliasRef", (alias, _ctx) => {
1349
+ void _ctx;
1350
+ return this.quoteIdentifier(alias.name);
1351
+ });
1327
1352
  this.registerOperandCompiler("Column", (column, _ctx) => {
1353
+ void _ctx;
1328
1354
  return `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`;
1329
1355
  });
1330
1356
  this.registerOperandCompiler(
1331
1357
  "Function",
1332
1358
  (fnNode, ctx) => this.compileFunctionOperand(fnNode, ctx)
1333
1359
  );
1334
- this.registerOperandCompiler("JsonPath", (path, _ctx) => this.compileJsonPath(path));
1360
+ this.registerOperandCompiler("JsonPath", (path, _ctx) => {
1361
+ void _ctx;
1362
+ return this.compileJsonPath(path);
1363
+ });
1335
1364
  this.registerOperandCompiler("ScalarSubquery", (node, ctx) => {
1336
1365
  const sql = this.compileSelectAst(node.query, ctx).trim().replace(/;$/, "");
1337
1366
  return `(${sql})`;
@@ -1375,7 +1404,8 @@ var Dialect = class _Dialect {
1375
1404
  });
1376
1405
  }
1377
1406
  // Default fallback, should be overridden by dialects if supported
1378
- compileJsonPath(node) {
1407
+ compileJsonPath(_node) {
1408
+ void _node;
1379
1409
  throw new Error("JSON Path not supported by this dialect");
1380
1410
  }
1381
1411
  /**
@@ -1541,6 +1571,7 @@ var NoReturningStrategy = class {
1541
1571
  * @throws Error indicating RETURNING is not supported.
1542
1572
  */
1543
1573
  compileReturning(returning, _ctx) {
1574
+ void _ctx;
1544
1575
  if (!returning || returning.length === 0) return "";
1545
1576
  throw new Error("RETURNING is not supported by this dialect.");
1546
1577
  }
@@ -1942,6 +1973,7 @@ var PostgresDialect = class extends SqlDialectBase {
1942
1973
  return `${col2}->>'${node.path}'`;
1943
1974
  }
1944
1975
  compileReturning(returning, ctx) {
1976
+ void ctx;
1945
1977
  if (!returning || returning.length === 0) return "";
1946
1978
  const columns = this.formatReturningColumns(returning);
1947
1979
  return ` RETURNING ${columns}`;
@@ -2192,9 +2224,11 @@ var SqliteDialect = class extends SqlDialectBase {
2192
2224
  return `json_extract(${col2}, '${node.path}')`;
2193
2225
  }
2194
2226
  compileQualifiedColumn(column, _table) {
2227
+ void _table;
2195
2228
  return this.quoteIdentifier(column.name);
2196
2229
  }
2197
2230
  compileReturning(returning, ctx) {
2231
+ void ctx;
2198
2232
  if (!returning || returning.length === 0) return "";
2199
2233
  const columns = this.formatReturningColumns(returning);
2200
2234
  return ` RETURNING ${columns}`;
@@ -2847,7 +2881,8 @@ var HydrationManager = class _HydrationManager {
2847
2881
  getProjectionNames(columns) {
2848
2882
  const names = [];
2849
2883
  for (const col2 of columns) {
2850
- const alias = col2.alias ?? col2.name;
2884
+ const node = col2;
2885
+ const alias = node.alias ?? node.name;
2851
2886
  if (!alias) return void 0;
2852
2887
  names.push(alias);
2853
2888
  }
@@ -3064,7 +3099,8 @@ var buildDefaultHydrationPlan = (table) => ({
3064
3099
  // src/query-builder/raw-column-parser.ts
3065
3100
  var parseRawColumn = (col2, tableName, ctes) => {
3066
3101
  if (col2.includes("(")) {
3067
- const [fn4, rest] = col2.split("(");
3102
+ const [_fn, rest] = col2.split("(");
3103
+ void _fn;
3068
3104
  const colName = rest.replace(")", "");
3069
3105
  const [table, name] = colName.includes(".") ? colName.split(".") : [tableName, colName];
3070
3106
  return { type: "Column", table, name, alias: col2 };
@@ -3264,7 +3300,7 @@ var QueryAstService = class {
3264
3300
  normalizeOrderingTerm(term) {
3265
3301
  const from = this.state.ast.from;
3266
3302
  const tableRef2 = from.type === "Table" && from.alias ? { ...this.table, alias: from.alias } : this.table;
3267
- const termType = term?.type;
3303
+ const termType = term.type;
3268
3304
  if (termType === "Column") {
3269
3305
  return term;
3270
3306
  }
@@ -4264,7 +4300,6 @@ var DefaultManyToManyCollection = class {
4264
4300
  }
4265
4301
  async syncByIds(ids) {
4266
4302
  await this.load();
4267
- const targetKey = this.relation.targetKey || findPrimaryKey(this.relation.target);
4268
4303
  const normalized = new Set(ids.map((id) => toKey5(id)));
4269
4304
  const currentIds = new Set(this.items.map((item) => toKey5(this.extractId(item))));
4270
4305
  for (const id of normalized) {
@@ -4535,7 +4570,6 @@ var createEntityProxy = (ctx, table, row, lazyRelations = []) => {
4535
4570
  enumerable: false,
4536
4571
  writable: false
4537
4572
  });
4538
- let proxy;
4539
4573
  const handler = {
4540
4574
  get(targetObj, prop, receiver) {
4541
4575
  if (prop === ENTITY_META) {
@@ -4543,7 +4577,7 @@ var createEntityProxy = (ctx, table, row, lazyRelations = []) => {
4543
4577
  }
4544
4578
  if (prop === "$load") {
4545
4579
  return async (relationName) => {
4546
- const wrapper = getRelationWrapper(meta, relationName, proxy);
4580
+ const wrapper = getRelationWrapper(meta, relationName, receiver);
4547
4581
  if (wrapper && typeof wrapper.load === "function") {
4548
4582
  return wrapper.load();
4549
4583
  }
@@ -4551,19 +4585,19 @@ var createEntityProxy = (ctx, table, row, lazyRelations = []) => {
4551
4585
  };
4552
4586
  }
4553
4587
  if (typeof prop === "string" && table.relations[prop]) {
4554
- return getRelationWrapper(meta, prop, proxy);
4588
+ return getRelationWrapper(meta, prop, receiver);
4555
4589
  }
4556
4590
  return Reflect.get(targetObj, prop, receiver);
4557
4591
  },
4558
4592
  set(targetObj, prop, value, receiver) {
4559
4593
  const result = Reflect.set(targetObj, prop, value, receiver);
4560
4594
  if (typeof prop === "string" && table.columns[prop]) {
4561
- ctx.markDirty(proxy);
4595
+ ctx.markDirty(receiver);
4562
4596
  }
4563
4597
  return result;
4564
4598
  }
4565
4599
  };
4566
- proxy = new Proxy(target, handler);
4600
+ const proxy = new Proxy(target, handler);
4567
4601
  populateHydrationCache(proxy, row, meta);
4568
4602
  return proxy;
4569
4603
  };
@@ -4805,7 +4839,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
4805
4839
  return this.clone(nextContext);
4806
4840
  }
4807
4841
  resolveQueryNode(query) {
4808
- return typeof query.getAST === "function" ? query.getAST() : query;
4842
+ const candidate = query;
4843
+ return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
4809
4844
  }
4810
4845
  applyCorrelation(ast, correlation) {
4811
4846
  if (!correlation) return ast;
@@ -5074,18 +5109,18 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
5074
5109
  * Selects columns for the root table and relations from a single config object.
5075
5110
  */
5076
5111
  selectColumnsDeep(config) {
5077
- let qb = this;
5112
+ let currBuilder = this;
5078
5113
  if (config.root?.length) {
5079
- qb = qb.selectColumns(...config.root);
5114
+ currBuilder = currBuilder.selectColumns(...config.root);
5080
5115
  }
5081
5116
  for (const key of Object.keys(config)) {
5082
5117
  if (key === "root") continue;
5083
5118
  const relName = key;
5084
5119
  const cols = config[relName];
5085
5120
  if (!cols || !cols.length) continue;
5086
- qb = qb.selectRelationColumns(relName, ...cols);
5121
+ currBuilder = currBuilder.selectRelationColumns(relName, ...cols);
5087
5122
  }
5088
- return qb;
5123
+ return currBuilder;
5089
5124
  }
5090
5125
  getLazyRelations() {
5091
5126
  return Array.from(this.lazyRelations);
@@ -5520,6 +5555,13 @@ var selectFromEntity = (ctor) => {
5520
5555
  }
5521
5556
  return new SelectQueryBuilder(table);
5522
5557
  };
5558
+ var entityRef = (ctor) => {
5559
+ const table = getTableDefFromEntity(ctor);
5560
+ if (!table) {
5561
+ throw new Error(`Entity '${ctor.name}' is not registered with decorators or has not been bootstrapped`);
5562
+ }
5563
+ return tableRef(table);
5564
+ };
5523
5565
 
5524
5566
  // src/query-builder/select-helpers.ts
5525
5567
  function sel(table, ...cols) {
@@ -5672,11 +5714,13 @@ var InsertQueryBuilder = class _InsertQueryBuilder {
5672
5714
  return columns.map((column) => buildColumnNode(this.table, column));
5673
5715
  }
5674
5716
  resolveSelectQuery(query) {
5675
- return typeof query.getAST === "function" ? query.getAST() : query;
5717
+ const candidate = query;
5718
+ return typeof candidate.getAST === "function" && candidate.getAST ? candidate.getAST() : query;
5676
5719
  }
5677
5720
  compile(arg) {
5678
- if (typeof arg.compileInsert === "function") {
5679
- return arg.compileInsert(this.state.ast);
5721
+ const candidate = arg;
5722
+ if (typeof candidate.compileInsert === "function") {
5723
+ return candidate.compileInsert(this.state.ast);
5680
5724
  }
5681
5725
  const dialect = resolveDialectInput(arg);
5682
5726
  return dialect.compileInsert(this.state.ast);
@@ -5813,8 +5857,9 @@ var UpdateQueryBuilder = class _UpdateQueryBuilder {
5813
5857
  return this.resolveTableSource(table);
5814
5858
  }
5815
5859
  compile(arg) {
5816
- if (typeof arg.compileUpdate === "function") {
5817
- return arg.compileUpdate(this.state.ast);
5860
+ const candidate = arg;
5861
+ if (typeof candidate.compileUpdate === "function") {
5862
+ return candidate.compileUpdate(this.state.ast);
5818
5863
  }
5819
5864
  const dialect = resolveDialectInput(arg);
5820
5865
  return dialect.compileUpdate(this.state.ast);
@@ -5915,8 +5960,9 @@ var DeleteQueryBuilder = class _DeleteQueryBuilder {
5915
5960
  return this.resolveTableSource(table);
5916
5961
  }
5917
5962
  compile(arg) {
5918
- if (typeof arg.compileDelete === "function") {
5919
- return arg.compileDelete(this.state.ast);
5963
+ const candidate = arg;
5964
+ if (typeof candidate.compileDelete === "function") {
5965
+ return candidate.compileDelete(this.state.ast);
5920
5966
  }
5921
5967
  const dialect = resolveDialectInput(arg);
5922
5968
  return dialect.compileDelete(this.state.ast);
@@ -5966,7 +6012,7 @@ var generateCreateTableSql = (table, dialect) => {
5966
6012
  const pk = resolvePrimaryKey(table);
5967
6013
  const inlinePkColumns = /* @__PURE__ */ new Set();
5968
6014
  const columnLines = Object.values(table.columns).map((col2) => {
5969
- const includePk = dialect.preferInlinePkAutoincrement?.(col2, table, pk) && pk.includes(col2.name);
6015
+ const includePk = dialect.preferInlinePkAutoincrement(col2, table, pk) && pk.includes(col2.name);
5970
6016
  if (includePk) {
5971
6017
  inlinePkColumns.add(col2.name);
5972
6018
  }
@@ -6471,7 +6517,7 @@ var postgresIntrospector = {
6471
6517
  ],
6472
6518
  where: and(
6473
6519
  eq({ table: "ns", name: "nspname" }, schema),
6474
- eq({ table: "i", name: "indisprimary" }, { type: "Literal", value: false })
6520
+ eq({ table: "i", name: "indisprimary" }, false)
6475
6521
  )
6476
6522
  };
6477
6523
  const indexQueryRows = await runSelectNode(indexQuery, ctx);
@@ -6635,6 +6681,14 @@ var mysqlIntrospector = {
6635
6681
  };
6636
6682
 
6637
6683
  // src/core/ddl/introspect/sqlite.ts
6684
+ var toReferentialAction = (value) => {
6685
+ if (!value) return void 0;
6686
+ const normalized = value.toUpperCase();
6687
+ if (normalized === "NO ACTION" || normalized === "RESTRICT" || normalized === "CASCADE" || normalized === "SET NULL" || normalized === "SET DEFAULT") {
6688
+ return normalized;
6689
+ }
6690
+ return void 0;
6691
+ };
6638
6692
  var escapeSingleQuotes = (name) => name.replace(/'/g, "''");
6639
6693
  var sqliteIntrospector = {
6640
6694
  async introspect(ctx, options) {
@@ -6668,8 +6722,8 @@ var sqliteIntrospector = {
6668
6722
  col2.references = {
6669
6723
  table: fk.table,
6670
6724
  column: fk.to,
6671
- onDelete: fk.on_delete?.toUpperCase(),
6672
- onUpdate: fk.on_update?.toUpperCase()
6725
+ onDelete: toReferentialAction(fk.on_delete),
6726
+ onUpdate: toReferentialAction(fk.on_update)
6673
6727
  };
6674
6728
  }
6675
6729
  });
@@ -7079,11 +7133,7 @@ var TypeScriptGenerator = class {
7079
7133
  const lines = [];
7080
7134
  const hydration = ast.meta?.hydration;
7081
7135
  const hydratedRelations = new Set(hydration?.relations?.map((r) => r.name) ?? []);
7082
- const selections = ast.columns.filter((col2) => !(hydration && isRelationAlias(col2.alias))).map((col2) => {
7083
- const key = col2.alias || col2.name;
7084
- const operand = col2;
7085
- return `${key}: ${this.printOperand(operand)}`;
7086
- });
7136
+ const selections = ast.columns.filter((col2) => !(hydration && isRelationAlias(col2.alias))).map((col2, index) => `${this.getSelectionKey(col2, index)}: ${this.printOperand(col2)}`);
7087
7137
  lines.push(`db.select({`);
7088
7138
  selections.forEach((sel2, index) => {
7089
7139
  lines.push(` ${sel2}${index < selections.length - 1 ? "," : ""}`);
@@ -7171,7 +7221,7 @@ var TypeScriptGenerator = class {
7171
7221
  * Prints an ordering term (operand/expression/alias) to TypeScript code.
7172
7222
  */
7173
7223
  printOrderingTerm(term) {
7174
- if (!term || !term.type) {
7224
+ if (!term || !("type" in term)) {
7175
7225
  throw new Error("Unsupported ordering term");
7176
7226
  }
7177
7227
  switch (term.type) {
@@ -7190,6 +7240,18 @@ var TypeScriptGenerator = class {
7190
7240
  return this.printExpression(term);
7191
7241
  }
7192
7242
  }
7243
+ getSelectionKey(selection, index) {
7244
+ if (selection.alias) {
7245
+ return selection.alias;
7246
+ }
7247
+ if (this.isNamedSelection(selection)) {
7248
+ return selection.name;
7249
+ }
7250
+ return `selection${index + 1}`;
7251
+ }
7252
+ isNamedSelection(selection) {
7253
+ return "name" in selection;
7254
+ }
7193
7255
  visitBinaryExpression(binary) {
7194
7256
  return this.printBinaryExpression(binary);
7195
7257
  }
@@ -7973,6 +8035,7 @@ var RelationChangeProcessor = class {
7973
8035
  * @param _entry - The relation change entry (reserved for future use)
7974
8036
  */
7975
8037
  async handleBelongsToChange(_entry) {
8038
+ void _entry;
7976
8039
  }
7977
8040
  /**
7978
8041
  * Handles changes for belongs-to-many relations.
@@ -8086,7 +8149,7 @@ var RelationChangeProcessor = class {
8086
8149
  const key = findPrimaryKey(table);
8087
8150
  const value = entity[key];
8088
8151
  if (value === void 0 || value === null) return null;
8089
- return value;
8152
+ return value ?? null;
8090
8153
  }
8091
8154
  };
8092
8155
 
@@ -8678,8 +8741,6 @@ var Orm = class {
8678
8741
  const session = new OrmSession({ orm: this, executor });
8679
8742
  try {
8680
8743
  return await session.transaction(() => fn4(session));
8681
- } catch (err) {
8682
- throw err;
8683
8744
  } finally {
8684
8745
  await session.dispose();
8685
8746
  }
@@ -8710,9 +8771,6 @@ var getOrCreateMetadataBag = (context) => {
8710
8771
  var readMetadataBag = (context) => {
8711
8772
  return context.metadata?.[METADATA_KEY];
8712
8773
  };
8713
- var registerInitializer = (context, initializer) => {
8714
- context.addInitializer?.(initializer);
8715
- };
8716
8774
 
8717
8775
  // src/decorators/entity.ts
8718
8776
  var toSnakeCase = (value) => {
@@ -8742,14 +8800,24 @@ function Entity(options = {}) {
8742
8800
  if (bag) {
8743
8801
  const meta = ensureEntityMetadata(ctor);
8744
8802
  for (const entry of bag.columns) {
8745
- if (!meta.columns[entry.propertyName]) {
8746
- addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
8803
+ if (meta.columns[entry.propertyName]) {
8804
+ throw new Error(
8805
+ `Column '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
8806
+ );
8747
8807
  }
8808
+ addColumnMetadata(ctor, entry.propertyName, { ...entry.column });
8748
8809
  }
8749
8810
  for (const entry of bag.relations) {
8750
- if (!meta.relations[entry.propertyName]) {
8751
- addRelationMetadata(ctor, entry.propertyName, entry.relation);
8811
+ if (meta.relations[entry.propertyName]) {
8812
+ throw new Error(
8813
+ `Relation '${entry.propertyName}' is already defined on entity '${ctor.name}'.`
8814
+ );
8752
8815
  }
8816
+ const relationCopy = entry.relation.kind === RelationKinds.BelongsToMany ? {
8817
+ ...entry.relation,
8818
+ defaultPivotColumns: entry.relation.defaultPivotColumns ? [...entry.relation.defaultPivotColumns] : void 0
8819
+ } : { ...entry.relation };
8820
+ addRelationMetadata(ctor, entry.propertyName, relationCopy);
8753
8821
  }
8754
8822
  }
8755
8823
  }
@@ -8812,13 +8880,6 @@ var registerColumnFromContext = (context, column) => {
8812
8880
  if (!bag.columns.some((entry) => entry.propertyName === propertyName)) {
8813
8881
  bag.columns.push({ propertyName, column: { ...column } });
8814
8882
  }
8815
- registerInitializer(context, function() {
8816
- const ctor = resolveConstructor(this);
8817
- if (!ctor) {
8818
- return;
8819
- }
8820
- registerColumn(ctor, propertyName, column);
8821
- });
8822
8883
  };
8823
8884
  function Column(definition) {
8824
8885
  const normalized = normalizeColumnInput(definition);
@@ -8874,13 +8935,6 @@ var createFieldDecorator = (metadataFactory) => {
8874
8935
  if (!bag.relations.some((entry) => entry.propertyName === propertyName2)) {
8875
8936
  bag.relations.push({ propertyName: propertyName2, relation: relationMetadata });
8876
8937
  }
8877
- registerInitializer(ctx, function() {
8878
- const ctor2 = resolveConstructor2(this);
8879
- if (!ctor2) {
8880
- return;
8881
- }
8882
- registerRelation(ctor2, propertyName2, relationMetadata);
8883
- });
8884
8938
  return;
8885
8939
  }
8886
8940
  const propertyName = normalizePropertyName2(propertyKeyOrContext);
@@ -9546,6 +9600,7 @@ function createPooledExecutorFactory(opts) {
9546
9600
  diffSchema,
9547
9601
  div,
9548
9602
  endOfMonth,
9603
+ entityRef,
9549
9604
  eq,
9550
9605
  esel,
9551
9606
  executeHydrated,
@@ -9558,6 +9613,7 @@ function createPooledExecutorFactory(opts) {
9558
9613
  fromUnixTime,
9559
9614
  generateCreateTableSql,
9560
9615
  generateSchemaSql,
9616
+ getColumn,
9561
9617
  getSchemaIntrospector,
9562
9618
  getTableDefFromEntity,
9563
9619
  groupConcat,