metal-orm 1.0.60 → 1.0.63

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.
package/dist/index.js CHANGED
@@ -831,6 +831,9 @@ var toTableRef = (table) => ({
831
831
  alias: hasAlias(table) ? table.alias : void 0
832
832
  });
833
833
 
834
+ // src/core/ast/expression.ts
835
+ var asType = (expr) => expr;
836
+
834
837
  // src/core/functions/function-registry.ts
835
838
  var FunctionRegistry = class {
836
839
  renderers = /* @__PURE__ */ new Map();
@@ -3444,10 +3447,9 @@ var HydrationPlanner = class _HydrationPlanner {
3444
3447
  const rootCols = new Set(currentPlan.rootColumns);
3445
3448
  let changed = false;
3446
3449
  columns.forEach((node) => {
3447
- if (node.type !== "Column") return;
3448
- if (node.table !== this.table.name) return;
3449
- const alias = node.alias || node.name;
3450
- if (isRelationAlias(alias)) return;
3450
+ const alias = node.type === "Column" ? node.alias || node.name : node.alias;
3451
+ if (!alias || isRelationAlias(alias)) return;
3452
+ if (node.type === "Column" && node.table !== this.table.name) return;
3451
3453
  if (!rootCols.has(alias)) {
3452
3454
  rootCols.add(alias);
3453
3455
  changed = true;
@@ -5913,9 +5915,22 @@ var executeWithContexts = async (execCtx, entityCtx, qb) => {
5913
5915
  await loadLazyRelationsForTable(entityCtx, qb.getTable(), lazyRelations, lazyRelationOptions);
5914
5916
  return entities;
5915
5917
  };
5918
+ var executePlainWithContexts = async (execCtx, qb) => {
5919
+ const ast = qb.getAST();
5920
+ const compiled = execCtx.dialect.compileSelect(ast);
5921
+ const executed = await execCtx.interceptors.run({ sql: compiled.sql, params: compiled.params }, execCtx.executor);
5922
+ const rows = flattenResults(executed);
5923
+ if (ast.setOps && ast.setOps.length > 0) {
5924
+ return rows;
5925
+ }
5926
+ return hydrateRows(rows, qb.getHydrationPlan());
5927
+ };
5916
5928
  async function executeHydrated(session, qb) {
5917
5929
  return executeWithContexts(session.getExecutionContext(), session, qb);
5918
5930
  }
5931
+ async function executeHydratedPlain(session, qb) {
5932
+ return executePlainWithContexts(session.getExecutionContext(), qb);
5933
+ }
5919
5934
  async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
5920
5935
  const entityCtx = hydCtx.entityContext;
5921
5936
  if (!entityCtx) {
@@ -5923,6 +5938,9 @@ async function executeHydratedWithContexts(execCtx, hydCtx, qb) {
5923
5938
  }
5924
5939
  return executeWithContexts(execCtx, entityCtx, qb);
5925
5940
  }
5941
+ async function executeHydratedPlainWithContexts(execCtx, qb) {
5942
+ return executePlainWithContexts(execCtx, qb);
5943
+ }
5926
5944
  var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOptions) => {
5927
5945
  if (!lazyRelations.length) return;
5928
5946
  const tracked = ctx.getEntitiesForTable(table);
@@ -5970,6 +5988,146 @@ var loadLazyRelationsForTable = async (ctx, table, lazyRelations, lazyRelationOp
5970
5988
  }
5971
5989
  };
5972
5990
 
5991
+ // src/orm/entity-metadata.ts
5992
+ var metadataMap = /* @__PURE__ */ new Map();
5993
+ var ensureEntityMetadata = (target) => {
5994
+ let meta = metadataMap.get(target);
5995
+ if (!meta) {
5996
+ meta = {
5997
+ target,
5998
+ tableName: target.name || "unknown",
5999
+ columns: {},
6000
+ relations: {}
6001
+ };
6002
+ metadataMap.set(target, meta);
6003
+ }
6004
+ return meta;
6005
+ };
6006
+ var getEntityMetadata = (target) => {
6007
+ return metadataMap.get(target);
6008
+ };
6009
+ var getAllEntityMetadata = () => {
6010
+ return Array.from(metadataMap.values());
6011
+ };
6012
+ var addColumnMetadata = (target, propertyKey, column) => {
6013
+ const meta = ensureEntityMetadata(target);
6014
+ meta.columns[propertyKey] = { ...column };
6015
+ };
6016
+ var addRelationMetadata = (target, propertyKey, relation) => {
6017
+ const meta = ensureEntityMetadata(target);
6018
+ meta.relations[propertyKey] = relation;
6019
+ };
6020
+ var setEntityTableName = (target, tableName, hooks) => {
6021
+ const meta = ensureEntityMetadata(target);
6022
+ if (tableName && tableName.length > 0) {
6023
+ meta.tableName = tableName;
6024
+ }
6025
+ if (hooks) {
6026
+ meta.hooks = hooks;
6027
+ }
6028
+ };
6029
+ var buildTableDef = (meta) => {
6030
+ if (meta.table) {
6031
+ return meta.table;
6032
+ }
6033
+ const columns = {};
6034
+ for (const [key, def] of Object.entries(meta.columns)) {
6035
+ columns[key] = {
6036
+ ...def,
6037
+ name: key,
6038
+ table: meta.tableName
6039
+ };
6040
+ }
6041
+ const table = defineTable(meta.tableName, columns, {}, meta.hooks);
6042
+ meta.table = table;
6043
+ return table;
6044
+ };
6045
+
6046
+ // src/orm/entity-registry.ts
6047
+ var tableToConstructor = /* @__PURE__ */ new Map();
6048
+ var rebuildRegistry = () => {
6049
+ tableToConstructor.clear();
6050
+ for (const meta of getAllEntityMetadata()) {
6051
+ if (meta.table) {
6052
+ tableToConstructor.set(meta.table, meta.target);
6053
+ }
6054
+ }
6055
+ };
6056
+
6057
+ // src/orm/entity-materializer.ts
6058
+ var PrototypeMaterializationStrategy = class {
6059
+ materialize(ctor, data) {
6060
+ const instance = Object.create(ctor.prototype);
6061
+ Object.assign(instance, data);
6062
+ return instance;
6063
+ }
6064
+ };
6065
+ var ConstructorMaterializationStrategy = class {
6066
+ materialize(ctor, data) {
6067
+ const instance = Reflect.construct(ctor, []);
6068
+ Object.assign(instance, data);
6069
+ return instance;
6070
+ }
6071
+ };
6072
+ var DefaultEntityMaterializer = class {
6073
+ constructor(strategy = new ConstructorMaterializationStrategy()) {
6074
+ this.strategy = strategy;
6075
+ }
6076
+ materialize(ctor, row) {
6077
+ if (hasEntityMeta(row)) {
6078
+ return this.materializeEntityProxy(ctor, row);
6079
+ }
6080
+ const instance = this.strategy.materialize(ctor, row);
6081
+ this.materializeRelations(instance);
6082
+ return instance;
6083
+ }
6084
+ materializeMany(ctor, rows) {
6085
+ return rows.map((row) => this.materialize(ctor, row));
6086
+ }
6087
+ /**
6088
+ * Recursively materializes nested relation data.
6089
+ */
6090
+ materializeRelations(instance) {
6091
+ rebuildRegistry();
6092
+ for (const value of Object.values(instance)) {
6093
+ if (value === null || value === void 0) continue;
6094
+ if (typeof value === "object" && !Array.isArray(value)) {
6095
+ const nested = value;
6096
+ if (this.isEntityLike(nested)) {
6097
+ }
6098
+ }
6099
+ if (Array.isArray(value) && value.length > 0) {
6100
+ const first = value[0];
6101
+ if (typeof first === "object" && first !== null && this.isEntityLike(first)) {
6102
+ }
6103
+ }
6104
+ }
6105
+ }
6106
+ /**
6107
+ * Simple heuristic to check if an object looks like an entity.
6108
+ */
6109
+ isEntityLike(obj) {
6110
+ return "id" in obj || Object.keys(obj).some(
6111
+ (k) => k.endsWith("Id") || k === "createdAt" || k === "updatedAt"
6112
+ );
6113
+ }
6114
+ materializeEntityProxy(ctor, row) {
6115
+ const proxy = row;
6116
+ const baseline = this.strategy.materialize(ctor, {});
6117
+ for (const key of Object.keys(baseline)) {
6118
+ if (!Object.prototype.hasOwnProperty.call(proxy, key)) {
6119
+ proxy[key] = baseline[key];
6120
+ }
6121
+ }
6122
+ Object.setPrototypeOf(proxy, ctor.prototype);
6123
+ return proxy;
6124
+ }
6125
+ };
6126
+ var materializeAs = (ctor, results) => {
6127
+ const materializer = new DefaultEntityMaterializer();
6128
+ return materializer.materializeMany(ctor, results);
6129
+ };
6130
+
5973
6131
  // src/query-builder/query-resolution.ts
5974
6132
  function resolveSelectQuery(query) {
5975
6133
  const candidate = query;
@@ -6380,6 +6538,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6380
6538
  relationFacet;
6381
6539
  lazyRelations;
6382
6540
  lazyRelationOptions;
6541
+ entityConstructor;
6383
6542
  /**
6384
6543
  * Creates a new SelectQueryBuilder instance
6385
6544
  * @param table - Table definition to query
@@ -6387,7 +6546,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6387
6546
  * @param hydration - Optional hydration manager
6388
6547
  * @param dependencies - Optional query builder dependencies
6389
6548
  */
6390
- constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions) {
6549
+ constructor(table, state, hydration, dependencies, lazyRelations, lazyRelationOptions, entityConstructor) {
6391
6550
  const deps = resolveSelectQueryBuilderDependencies(dependencies);
6392
6551
  this.env = { table, deps };
6393
6552
  const createAstService = (nextState) => deps.createQueryAstService(table, nextState);
@@ -6399,6 +6558,7 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6399
6558
  };
6400
6559
  this.lazyRelations = new Set(lazyRelations ?? []);
6401
6560
  this.lazyRelationOptions = new Map(lazyRelationOptions ?? []);
6561
+ this.entityConstructor = entityConstructor;
6402
6562
  this.columnSelector = deps.createColumnSelector(this.env);
6403
6563
  const relationManager = deps.createRelationManager(this.env);
6404
6564
  this.fromFacet = new SelectFromFacet(this.env, createAstService);
@@ -6422,7 +6582,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6422
6582
  context.hydration,
6423
6583
  this.env.deps,
6424
6584
  lazyRelations,
6425
- lazyRelationOptions
6585
+ lazyRelationOptions,
6586
+ this.entityConstructor
6426
6587
  );
6427
6588
  }
6428
6589
  /**
@@ -6470,7 +6631,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6470
6631
  select(...args) {
6471
6632
  if (args.length === 1 && typeof args[0] === "object" && args[0] !== null && typeof args[0] !== "string") {
6472
6633
  const columns = args[0];
6473
- return this.clone(this.projectionFacet.select(this.context, columns));
6634
+ return this.clone(
6635
+ this.projectionFacet.select(this.context, columns)
6636
+ );
6474
6637
  }
6475
6638
  const cols = args;
6476
6639
  const selection = {};
@@ -6481,7 +6644,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6481
6644
  }
6482
6645
  selection[key] = col2;
6483
6646
  }
6484
- return this.clone(this.projectionFacet.select(this.context, selection));
6647
+ return this.clone(
6648
+ this.projectionFacet.select(this.context, selection)
6649
+ );
6485
6650
  }
6486
6651
  /**
6487
6652
  * Selects raw column expressions
@@ -6585,7 +6750,9 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6585
6750
  */
6586
6751
  selectSubquery(alias, sub2) {
6587
6752
  const query = resolveSelectQuery(sub2);
6588
- return this.clone(this.projectionFacet.selectSubquery(this.context, alias, query));
6753
+ return this.clone(
6754
+ this.projectionFacet.selectSubquery(this.context, alias, query)
6755
+ );
6589
6756
  }
6590
6757
  /**
6591
6758
  * Adds a JOIN against a derived table (subquery with alias)
@@ -6813,16 +6980,69 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6813
6980
  return this.env.table;
6814
6981
  }
6815
6982
  /**
6816
- * Executes the query and returns hydrated results
6983
+ * Ensures that if no columns are selected, all columns from the table are selected by default.
6984
+ */
6985
+ ensureDefaultSelection() {
6986
+ const columns = this.context.state.ast.columns;
6987
+ if (!columns || columns.length === 0) {
6988
+ const columnKeys = Object.keys(this.env.table.columns);
6989
+ return this.select(...columnKeys);
6990
+ }
6991
+ return this;
6992
+ }
6993
+ /**
6994
+ * Executes the query and returns hydrated results.
6995
+ * If the builder was created with an entity constructor (e.g. via selectFromEntity),
6996
+ * this will automatically return fully materialized entity instances.
6997
+ *
6817
6998
  * @param ctx - ORM session context
6818
- * @returns Promise of entity instances
6999
+ * @returns Promise of entity instances (or objects if generic T is not an entity)
6819
7000
  * @example
6820
- * const users = await qb.select('id', 'name')
6821
- * .where(eq(userTable.columns.active, true))
6822
- * .execute(session);
7001
+ * const users = await selectFromEntity(User).execute(session);
7002
+ * // users is User[]
7003
+ * users[0] instanceof User; // true
6823
7004
  */
6824
7005
  async execute(ctx) {
6825
- return executeHydrated(ctx, this);
7006
+ if (this.entityConstructor) {
7007
+ return this.executeAs(this.entityConstructor, ctx);
7008
+ }
7009
+ const builder = this.ensureDefaultSelection();
7010
+ return executeHydrated(ctx, builder);
7011
+ }
7012
+ /**
7013
+ * Executes the query and returns plain row objects (POJOs), ignoring any entity materialization.
7014
+ * Use this if you want raw data even when using selectFromEntity.
7015
+ *
7016
+ * @param ctx - ORM session context
7017
+ * @returns Promise of plain entity instances
7018
+ * @example
7019
+ * const rows = await selectFromEntity(User).executePlain(session);
7020
+ * // rows is EntityInstance<UserTable>[] (plain objects)
7021
+ * rows[0] instanceof User; // false
7022
+ */
7023
+ async executePlain(ctx) {
7024
+ const builder = this.ensureDefaultSelection();
7025
+ const rows = await executeHydratedPlain(ctx, builder);
7026
+ return rows;
7027
+ }
7028
+ /**
7029
+ * Executes the query and returns results as real class instances.
7030
+ * Unlike execute(), this returns actual instances of the decorated entity class
7031
+ * with working methods and proper instanceof checks.
7032
+ * @param entityClass - The entity class constructor
7033
+ * @param ctx - ORM session context
7034
+ * @returns Promise of entity class instances
7035
+ * @example
7036
+ * const users = await selectFromEntity(User)
7037
+ * .include('posts')
7038
+ * .executeAs(User, session);
7039
+ * users[0] instanceof User; // true!
7040
+ * users[0].getFullName(); // works!
7041
+ */
7042
+ async executeAs(entityClass, ctx) {
7043
+ const builder = this.ensureDefaultSelection();
7044
+ const results = await executeHydrated(ctx, builder);
7045
+ return materializeAs(entityClass, results);
6826
7046
  }
6827
7047
  /**
6828
7048
  * Executes a count query for the current builder without LIMIT/OFFSET clauses.
@@ -6840,7 +7060,8 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6840
7060
  * const { items, totalItems } = await qb.executePaged(session, { page: 1, pageSize: 20 });
6841
7061
  */
6842
7062
  async executePaged(session, options) {
6843
- return executePagedQuery(this, session, options, (sess) => this.count(sess));
7063
+ const builder = this.ensureDefaultSelection();
7064
+ return executePagedQuery(builder, session, options, (sess) => this.count(sess));
6844
7065
  }
6845
7066
  /**
6846
7067
  * Executes the query with provided execution and hydration contexts
@@ -6853,7 +7074,12 @@ var SelectQueryBuilder = class _SelectQueryBuilder {
6853
7074
  * const users = await qb.executeWithContexts(execCtx, hydCtx);
6854
7075
  */
6855
7076
  async executeWithContexts(execCtx, hydCtx) {
6856
- return executeHydratedWithContexts(execCtx, hydCtx, this);
7077
+ const builder = this.ensureDefaultSelection();
7078
+ const results = await executeHydratedWithContexts(execCtx, hydCtx, builder);
7079
+ if (this.entityConstructor) {
7080
+ return materializeAs(this.entityConstructor, results);
7081
+ }
7082
+ return results;
6857
7083
  }
6858
7084
  /**
6859
7085
  * Adds a WHERE condition to the query
@@ -7146,61 +7372,6 @@ var isTableDef = (value) => {
7146
7372
  return true;
7147
7373
  };
7148
7374
 
7149
- // src/orm/entity-metadata.ts
7150
- var metadataMap = /* @__PURE__ */ new Map();
7151
- var ensureEntityMetadata = (target) => {
7152
- let meta = metadataMap.get(target);
7153
- if (!meta) {
7154
- meta = {
7155
- target,
7156
- tableName: target.name || "unknown",
7157
- columns: {},
7158
- relations: {}
7159
- };
7160
- metadataMap.set(target, meta);
7161
- }
7162
- return meta;
7163
- };
7164
- var getEntityMetadata = (target) => {
7165
- return metadataMap.get(target);
7166
- };
7167
- var getAllEntityMetadata = () => {
7168
- return Array.from(metadataMap.values());
7169
- };
7170
- var addColumnMetadata = (target, propertyKey, column) => {
7171
- const meta = ensureEntityMetadata(target);
7172
- meta.columns[propertyKey] = { ...column };
7173
- };
7174
- var addRelationMetadata = (target, propertyKey, relation) => {
7175
- const meta = ensureEntityMetadata(target);
7176
- meta.relations[propertyKey] = relation;
7177
- };
7178
- var setEntityTableName = (target, tableName, hooks) => {
7179
- const meta = ensureEntityMetadata(target);
7180
- if (tableName && tableName.length > 0) {
7181
- meta.tableName = tableName;
7182
- }
7183
- if (hooks) {
7184
- meta.hooks = hooks;
7185
- }
7186
- };
7187
- var buildTableDef = (meta) => {
7188
- if (meta.table) {
7189
- return meta.table;
7190
- }
7191
- const columns = {};
7192
- for (const [key, def] of Object.entries(meta.columns)) {
7193
- columns[key] = {
7194
- ...def,
7195
- name: key,
7196
- table: meta.tableName
7197
- };
7198
- }
7199
- const table = defineTable(meta.tableName, columns, {}, meta.hooks);
7200
- meta.table = table;
7201
- return table;
7202
- };
7203
-
7204
7375
  // src/decorators/bootstrap.ts
7205
7376
  var unwrapTarget = (target) => {
7206
7377
  if (typeof target === "function" && target.prototype === void 0) {
@@ -7320,7 +7491,15 @@ var selectFromEntity = (ctor) => {
7320
7491
  if (!table) {
7321
7492
  throw new Error(`Entity '${ctor.name}' is not registered with decorators or has not been bootstrapped`);
7322
7493
  }
7323
- return new SelectQueryBuilder(table);
7494
+ return new SelectQueryBuilder(
7495
+ table,
7496
+ void 0,
7497
+ void 0,
7498
+ void 0,
7499
+ void 0,
7500
+ void 0,
7501
+ ctor
7502
+ );
7324
7503
  };
7325
7504
  var entityRef = (ctor) => {
7326
7505
  const table = getTableDefFromEntity(ctor);
@@ -12565,7 +12744,9 @@ export {
12565
12744
  BelongsTo,
12566
12745
  BelongsToMany,
12567
12746
  Column,
12747
+ ConstructorMaterializationStrategy,
12568
12748
  DefaultBelongsToReference,
12749
+ DefaultEntityMaterializer,
12569
12750
  DefaultHasManyCollection,
12570
12751
  DefaultManyToManyCollection,
12571
12752
  DeleteQueryBuilder,
@@ -12581,6 +12762,7 @@ export {
12581
12762
  Pool,
12582
12763
  PostgresDialect,
12583
12764
  PrimaryKey,
12765
+ PrototypeMaterializationStrategy,
12584
12766
  RelationKinds,
12585
12767
  STANDARD_COLUMN_TYPES,
12586
12768
  SelectQueryBuilder,
@@ -12596,6 +12778,7 @@ export {
12596
12778
  aliasRef,
12597
12779
  and,
12598
12780
  arrayAppend,
12781
+ asType,
12599
12782
  ascii,
12600
12783
  asin,
12601
12784
  atan,
@@ -12661,6 +12844,8 @@ export {
12661
12844
  eq,
12662
12845
  esel,
12663
12846
  executeHydrated,
12847
+ executeHydratedPlain,
12848
+ executeHydratedPlainWithContexts,
12664
12849
  executeHydratedWithContexts,
12665
12850
  executeSchemaSql,
12666
12851
  executeSchemaSqlFor,
@@ -12732,6 +12917,7 @@ export {
12732
12917
  lt,
12733
12918
  lte,
12734
12919
  ltrim,
12920
+ materializeAs,
12735
12921
  max,
12736
12922
  md5,
12737
12923
  min,