@mikro-orm/core 7.0.16-dev.1 → 7.0.16-dev.11

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/EntityManager.js CHANGED
@@ -659,7 +659,7 @@ export class EntityManager {
659
659
  where = await em.processWhere(entityName, where, options, 'read');
660
660
  validateEmptyWhere(where);
661
661
  em.checkLockRequirements(options.lockMode, meta);
662
- const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.OPTIMISTIC;
662
+ const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.NONE || options.lockMode === LockMode.OPTIMISTIC;
663
663
  if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
664
664
  return em.lockAndPopulate(meta, entity, where, options);
665
665
  }
@@ -665,8 +665,11 @@ export class EntityLoader {
665
665
  }
666
666
  return ret;
667
667
  }, []);
668
- // we need to automatically select the FKs too, e.g. for 1:m relations to be able to wire them with the items
669
- if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
668
+ // we need to automatically select the FKs too, e.g. for 1:m and inverse 1:1 relations
669
+ // to be able to wire them with the items
670
+ if (prop.kind === ReferenceKind.ONE_TO_MANY ||
671
+ prop.kind === ReferenceKind.MANY_TO_MANY ||
672
+ (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner)) {
670
673
  const owner = prop.targetMeta.properties[prop.mappedBy];
671
674
  // when the owning FK is lazy, we need to explicitly select it even without user-provided fields,
672
675
  // otherwise the driver will exclude it and we won't be able to map children to their parent collections
package/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * @module core
4
4
  */
5
5
  export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, } from './typings.js';
6
- export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, IndexCallback, FormulaCallback, FormulaColumns, FormulaTable, SchemaTable, SchemaColumns, EntityDataPropValue, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
6
+ export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, IndexCallback, FormulaCallback, FormulaColumns, FormulaTable, SchemaTable, SchemaColumns, SchemaColumnRef, EntityDataPropValue, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
7
7
  export * from './enums.js';
8
8
  export * from './errors.js';
9
9
  export * from './exceptions.js';
@@ -963,9 +963,13 @@ export class MetadataDiscovery {
963
963
  meta.propertyOrder.set(prop.name, (order += 0.01));
964
964
  });
965
965
  }
966
- meta.indexes = Utils.unique([...base.indexes, ...meta.indexes]);
967
- meta.uniques = Utils.unique([...base.uniques, ...meta.uniques]);
968
- meta.checks = Utils.unique([...base.checks, ...meta.checks]);
966
+ // TPT children have their own tables that don't contain the parent's columns,
967
+ // so propagating parent indexes/uniques/checks would target missing columns.
968
+ if (meta.inheritanceType !== 'tpt' || !meta.tptParent) {
969
+ meta.indexes = Utils.unique([...base.indexes, ...meta.indexes]);
970
+ meta.uniques = Utils.unique([...base.uniques, ...meta.uniques]);
971
+ meta.checks = Utils.unique([...base.checks, ...meta.checks]);
972
+ }
969
973
  const pks = Object.values(meta.properties)
970
974
  .filter(p => p.primary)
971
975
  .map(p => p.name);
@@ -1531,7 +1535,7 @@ export class MetadataDiscovery {
1531
1535
  const table = this.createSchemaTable(meta);
1532
1536
  for (const check of meta.checks) {
1533
1537
  const fieldNames = check.property ? meta.properties[check.property].fieldNames : [];
1534
- check.name ??= this.#namingStrategy.indexName(meta.tableName, fieldNames, 'check');
1538
+ check.name ??= this.#platform.getIndexName(meta.tableName, fieldNames, 'check');
1535
1539
  if (check.expression instanceof Function) {
1536
1540
  check.expression = check.expression(columns, table);
1537
1541
  }
@@ -1556,7 +1560,7 @@ export class MetadataDiscovery {
1556
1560
  }
1557
1561
  if (expression) {
1558
1562
  meta.checks.push({
1559
- name: this.#namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
1563
+ name: this.#platform.getIndexName(meta.tableName, prop.fieldNames, 'check'),
1560
1564
  property: prop.name,
1561
1565
  expression,
1562
1566
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "7.0.16-dev.1",
3
+ "version": "7.0.16-dev.11",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "keywords": [
6
6
  "data-mapper",
@@ -271,9 +271,17 @@ export declare abstract class Platform {
271
271
  /** Whether the platform supports unsigned integer columns. */
272
272
  supportsUnsigned(): boolean;
273
273
  /**
274
- * Returns the default name of index for the given columns
274
+ * Maximum length of identifiers (table, column, index, constraint, …) the platform supports.
275
+ * Names produced by {@link getIndexName} above this limit are hash-truncated. Defaults to
276
+ * `Infinity` (no truncation); SQL platforms override with their engine's limit
277
+ * (PG 63, MySQL/MariaDB 64, MSSQL/Oracle 128).
275
278
  */
276
- getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence'): string;
279
+ getMaxIdentifierLength(): number;
280
+ /**
281
+ * Returns the default name of index for the given columns, hash-truncated if it would
282
+ * exceed {@link getMaxIdentifierLength}.
283
+ */
284
+ getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence' | 'check'): string;
277
285
  /** Returns the default primary key constraint name. */
278
286
  getDefaultPrimaryName(tableName: string, columns: string[]): string;
279
287
  /** Whether the platform supports custom names for primary key constraints. */
@@ -618,10 +618,26 @@ export class Platform {
618
618
  return false;
619
619
  }
620
620
  /**
621
- * Returns the default name of index for the given columns
621
+ * Maximum length of identifiers (table, column, index, constraint, …) the platform supports.
622
+ * Names produced by {@link getIndexName} above this limit are hash-truncated. Defaults to
623
+ * `Infinity` (no truncation); SQL platforms override with their engine's limit
624
+ * (PG 63, MySQL/MariaDB 64, MSSQL/Oracle 128).
625
+ */
626
+ getMaxIdentifierLength() {
627
+ return Infinity;
628
+ }
629
+ /**
630
+ * Returns the default name of index for the given columns, hash-truncated if it would
631
+ * exceed {@link getMaxIdentifierLength}.
622
632
  */
623
633
  getIndexName(tableName, columns, type) {
624
- return this.namingStrategy.indexName(tableName, columns, type);
634
+ const indexName = this.namingStrategy.indexName(tableName, columns, type);
635
+ const max = this.getMaxIdentifierLength();
636
+ if (indexName.length > max) {
637
+ const suffix = type === 'primary' ? 'pkey' : type;
638
+ return `${indexName.substring(0, max - 8 - type.length)}_${Utils.hash(indexName, 5)}_${suffix}`;
639
+ }
640
+ return indexName;
625
641
  }
626
642
  /** Returns the default primary key constraint name. */
627
643
  getDefaultPrimaryName(tableName, columns) {
package/typings.d.ts CHANGED
@@ -579,19 +579,37 @@ export type SchemaTable = {
579
579
  export type FormulaColumns<T> = Record<PropertyName<T>, string> & {
580
580
  toString(): string;
581
581
  };
582
+ /**
583
+ * Column reference for schema callbacks. Behaves like a string (coercible via `toString()`),
584
+ * with arbitrary nested property access for embedded sub-columns (e.g. `cols.address.city`).
585
+ */
586
+ export type SchemaColumnRef = string & {
587
+ readonly [key: string]: SchemaColumnRef;
588
+ };
582
589
  /**
583
590
  * Column mapping for schema callbacks (indexes, checks, generated columns).
584
591
  * Maps property names to field names. For TPT entities, only includes properties
585
592
  * that belong to the current table (not inherited properties from parent tables).
593
+ * Embedded properties expose their sub-columns via nested access (e.g. `cols.address.city`),
594
+ * while coercing to the embedded property's own column name via `toString()` (matches the
595
+ * pre-7712 behaviour, regardless of any custom `prefix`).
596
+ */
597
+ export type SchemaColumns<T> = Record<PropertyName<T>, SchemaColumnRef>;
598
+ /**
599
+ * Callback for custom index expressions. Receives column mappings, table info, and the index name.
600
+ * The runtime `columns` object includes nested entries for embedded properties (see `SchemaColumnRef`);
601
+ * cast to `SchemaColumns<T>` if you need typed nested access.
586
602
  */
587
- export type SchemaColumns<T> = Record<PropertyName<T>, string>;
588
- /** Callback for custom index expressions. Receives column mappings, table info, and the index name. */
589
603
  export type IndexCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable, indexName: string) => string | Raw;
590
604
  /** Callback for computed (formula) properties. Receives column mappings and table info, returns a SQL expression. */
591
605
  export type FormulaCallback<T> = (columns: FormulaColumns<T>, table: FormulaTable) => string | Raw;
592
606
  /** Callback for CHECK constraint expressions. Receives column mappings and table info. */
593
- export type CheckCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable) => string | Raw;
594
- /** Callback for generated (computed) column expressions. Receives column mappings and table info. */
607
+ export type CheckCallback<T> = (columns: SchemaColumns<T>, table: SchemaTable) => string | Raw;
608
+ /**
609
+ * Callback for generated (computed) column expressions. Receives column mappings and table info.
610
+ * The runtime `columns` object includes nested entries for embedded properties (see `SchemaColumnRef`);
611
+ * cast to `SchemaColumns<T>` if you need typed nested access.
612
+ */
595
613
  export type GeneratedColumnCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable) => string | Raw;
596
614
  /** Definition of a CHECK constraint on a table or property. */
597
615
  export interface CheckConstraint<T = any> {
@@ -728,8 +746,12 @@ export declare class EntityMetadata<Entity = any, Class extends EntityCtor<Entit
728
746
  /**
729
747
  * Creates a column mapping for schema callbacks (indexes, checks, generated columns).
730
748
  * For TPT entities, only includes properties that belong to the current table (ownProps).
749
+ * Embedded properties expose their sub-columns via nested access (e.g. `cols.address.city`),
750
+ * while still coercing to the embedded column prefix when used as a string (GH #7712).
731
751
  */
732
752
  createSchemaColumnMappingObject(): SchemaColumns<Entity>;
753
+ /** @internal Recursively builds a column mapping for an embedded property's sub-columns. */
754
+ private static buildEmbeddedColumnMapping;
733
755
  get tableName(): string;
734
756
  set tableName(name: string);
735
757
  get uniqueName(): string;
package/typings.js CHANGED
@@ -116,16 +116,37 @@ export class EntityMetadata {
116
116
  /**
117
117
  * Creates a column mapping for schema callbacks (indexes, checks, generated columns).
118
118
  * For TPT entities, only includes properties that belong to the current table (ownProps).
119
+ * Embedded properties expose their sub-columns via nested access (e.g. `cols.address.city`),
120
+ * while still coercing to the embedded column prefix when used as a string (GH #7712).
119
121
  */
120
122
  createSchemaColumnMappingObject() {
121
123
  // For TPT entities, only include properties that belong to this entity's table
122
124
  const props = this.inheritanceType === 'tpt' && this.ownProps ? this.ownProps : Object.values(this.properties);
123
- return props.reduce((o, prop) => {
124
- if (prop.fieldNames) {
125
- o[prop.name] = prop.fieldNames[0];
125
+ const result = {};
126
+ for (const prop of props) {
127
+ if (!prop.fieldNames) {
128
+ continue;
126
129
  }
127
- return o;
128
- }, {});
130
+ if (prop.kind === ReferenceKind.EMBEDDED && prop.embeddedProps) {
131
+ result[prop.name] = EntityMetadata.buildEmbeddedColumnMapping(prop);
132
+ continue;
133
+ }
134
+ result[prop.name] = prop.fieldNames[0];
135
+ }
136
+ return result;
137
+ }
138
+ /** @internal Recursively builds a column mapping for an embedded property's sub-columns. */
139
+ static buildEmbeddedColumnMapping(embeddedProp) {
140
+ const result = {};
141
+ for (const [name, sub] of Object.entries(embeddedProp.embeddedProps)) {
142
+ result[name] =
143
+ sub.kind === ReferenceKind.EMBEDDED && sub.embeddedProps
144
+ ? EntityMetadata.buildEmbeddedColumnMapping(sub)
145
+ : sub.fieldNames[0];
146
+ }
147
+ const prefix = embeddedProp.fieldNames[0];
148
+ Object.defineProperty(result, 'toString', { value: () => prefix, enumerable: false });
149
+ return result;
129
150
  }
130
151
  get tableName() {
131
152
  return this.collection;
@@ -176,9 +197,10 @@ export class EntityMetadata {
176
197
  // Virtual entities evaluate expressions at query time, view entities create actual database views.
177
198
  this.virtual = !!this.expression && !this.view;
178
199
  if (config) {
200
+ const platform = config.getPlatform();
179
201
  for (const prop of this.props) {
180
202
  if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
181
- const name = config.getNamingStrategy().indexName(this.tableName, prop.fieldNames, 'check');
203
+ const name = platform.getIndexName(this.tableName, prop.fieldNames, 'check');
182
204
  const exists = this.checks.findIndex(check => check.name === name);
183
205
  if (exists !== -1) {
184
206
  this.checks.splice(exists, 1);
@@ -186,9 +208,7 @@ export class EntityMetadata {
186
208
  this.checks.push({
187
209
  name,
188
210
  property: prop.name,
189
- expression: config
190
- .getPlatform()
191
- .getEnumCheckConstraintExpression(prop.fieldNames[0], prop.items),
211
+ expression: platform.getEnumCheckConstraintExpression(prop.fieldNames[0], prop.items),
192
212
  });
193
213
  }
194
214
  }
@@ -463,7 +463,7 @@ export class UnitOfWork {
463
463
  if (options.lockMode === LockMode.OPTIMISTIC) {
464
464
  await this.lockOptimistic(entity, meta, options.lockVersion);
465
465
  }
466
- else if (options.lockMode != null) {
466
+ else if (options.lockMode != null && options.lockMode !== LockMode.NONE) {
467
467
  await this.lockPessimistic(entity, options);
468
468
  }
469
469
  }
package/utils/Utils.js CHANGED
@@ -141,7 +141,7 @@ export function parseJsonSafe(value) {
141
141
  /** Collection of general-purpose utility methods used throughout the ORM. */
142
142
  export class Utils {
143
143
  static PK_SEPARATOR = '~~~';
144
- static #ORM_VERSION = '7.0.16-dev.1';
144
+ static #ORM_VERSION = '7.0.16-dev.11';
145
145
  /**
146
146
  * Checks if the argument is instance of `Object`. Returns false for arrays.
147
147
  */