@mikro-orm/core 7.3.0-dev.2 → 7.3.0-dev.20

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 (49) hide show
  1. package/EntityManager.js +131 -32
  2. package/drivers/DatabaseDriver.d.ts +2 -0
  3. package/drivers/DatabaseDriver.js +16 -3
  4. package/entity/EntityAssigner.js +15 -3
  5. package/entity/EntityFactory.d.ts +8 -0
  6. package/entity/EntityFactory.js +69 -3
  7. package/entity/EntityLoader.js +31 -15
  8. package/entity/WrappedEntity.js +6 -1
  9. package/entity/defineEntity.d.ts +32 -19
  10. package/entity/defineEntity.js +9 -0
  11. package/entity/validators.js +4 -1
  12. package/errors.d.ts +7 -0
  13. package/errors.js +15 -0
  14. package/hydration/ObjectHydrator.js +6 -2
  15. package/metadata/MetadataDiscovery.d.ts +10 -0
  16. package/metadata/MetadataDiscovery.js +178 -30
  17. package/metadata/MetadataStorage.d.ts +8 -0
  18. package/metadata/MetadataStorage.js +47 -3
  19. package/metadata/MetadataValidator.js +2 -1
  20. package/metadata/types.d.ts +12 -0
  21. package/package.json +1 -1
  22. package/platforms/Platform.d.ts +6 -0
  23. package/platforms/Platform.js +26 -0
  24. package/serialization/EntitySerializer.js +52 -12
  25. package/types/DecimalType.js +34 -1
  26. package/types/DoubleType.d.ts +7 -3
  27. package/types/DoubleType.js +8 -3
  28. package/typings.d.ts +26 -6
  29. package/typings.js +5 -2
  30. package/unit-of-work/ChangeSetComputer.js +22 -7
  31. package/unit-of-work/ChangeSetPersister.js +24 -5
  32. package/unit-of-work/CommitOrderCalculator.js +2 -1
  33. package/unit-of-work/IdentityMap.d.ts +3 -2
  34. package/unit-of-work/IdentityMap.js +30 -7
  35. package/unit-of-work/UnitOfWork.js +45 -7
  36. package/utils/Configuration.d.ts +12 -1
  37. package/utils/EntityComparator.d.ts +5 -0
  38. package/utils/EntityComparator.js +87 -19
  39. package/utils/QueryHelper.d.ts +14 -0
  40. package/utils/QueryHelper.js +90 -13
  41. package/utils/RawQueryFragment.d.ts +5 -1
  42. package/utils/RawQueryFragment.js +27 -19
  43. package/utils/TransactionManager.js +4 -0
  44. package/utils/Utils.d.ts +2 -0
  45. package/utils/Utils.js +24 -8
  46. package/utils/clone.js +5 -7
  47. package/utils/env-vars.js +2 -0
  48. package/utils/fs-utils.js +19 -15
  49. package/utils/upsert-utils.js +2 -1
@@ -1,5 +1,5 @@
1
1
  import type { EntityManager } from '../EntityManager.js';
2
- import type { ColumnType, PropertyOptions, ReferenceOptions, EnumOptions, EmbeddedOptions, ManyToOneOptions, OneToManyOptions, OneToOneOptions, ManyToManyOptions, IndexColumnOptions } from '../metadata/types.js';
2
+ import type { ColumnType, PropertyOptions, ReferenceOptions, EnumOptions, EmbeddedOptions, ManyToOneOptions, OneToManyOptions, OneToOneOptions, ManyToManyOptions, IndexColumnOptions, SequenceOptions } from '../metadata/types.js';
3
3
  import type { AnyString, GeneratedColumnCallback, Constructor, CheckCallback, FilterQuery, EntityName, Dictionary, EntityMetadata, PrimaryKeyProp, EntityRepositoryType, Hidden, Opt, Primary, EntityClass, EntitySchemaWithMeta, InferEntity, MaybeReturnType, Ref, LazyRef, IndexCallback, TriggerCallback, FormulaCallback, EntityCtor, IsNever, IWrappedEntity, DefineConfig, Config, MaybePromise, IndexHints, OptionalProps, ExtractDefineEntityProperties } from '../typings.js';
4
4
  import type { Raw } from '../utils/RawQueryFragment.js';
5
5
  import type { ScalarReference } from './Reference.js';
@@ -130,6 +130,7 @@ export interface PropertyChain<in out Value, in out Options> {
130
130
  unique(unique?: boolean): PropertyChain<Value, Options>;
131
131
  comment(comment: string): PropertyChain<Value, Options>;
132
132
  collation(collation: string): PropertyChain<Value, Options>;
133
+ sequence(sequence: SequenceOptions | number): PropertyChain<Value, Options>;
133
134
  accessor(accessor?: string | boolean): PropertyChain<Value, Options>;
134
135
  eager(eager?: boolean): HasKind<Options, 'm:1' | '1:m' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
135
136
  cascade(...cascade: Cascade[]): HasKind<Options, 'm:1' | '1:m' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
@@ -486,6 +487,12 @@ export declare class UniversalPropertyOptionsBuilder<in out Value, in out Option
486
487
  * Emits a `COLLATE` clause on the column definition; the accepted collation names are dialect-specific.
487
488
  */
488
489
  collation(collation: string): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
490
+ /**
491
+ * Set the start value and increment of an autoincrement column. (SQL only)
492
+ * A number is a shorthand for `{ startWith }`.
493
+ * Applied only when the column is created (and by `orm.schema.clear()`), never diffed by the schema generator.
494
+ */
495
+ sequence(sequence: SequenceOptions | number): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
489
496
  /** mysql only */
490
497
  extra(extra: string): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
491
498
  /**
@@ -593,7 +600,7 @@ type EntityTarget = {
593
600
  '~entity': any;
594
601
  } | EntityClass;
595
602
  declare const propertyBuilders: PropertyBuilders;
596
- type PropertyBuildersOverrideKeys = 'bigint' | 'array' | 'decimal' | 'json' | 'string' | 'text' | 'datetime' | 'time' | 'enum';
603
+ type PropertyBuildersOverrideKeys = 'bigint' | 'array' | 'decimal' | 'double' | 'json' | 'string' | 'text' | 'datetime' | 'time' | 'enum';
597
604
  /** Map of factory functions for creating type-safe property builders (scalars, enums, embeddables, and relations). */
598
605
  export type PropertyBuilders = {
599
606
  [K in Exclude<keyof typeof types, PropertyBuildersOverrideKeys>]: () => UniversalPropertyOptionsBuilder<InferPropertyValueType<(typeof types)[K]>, EmptyOptions, IncludeKeysForProperty>;
@@ -601,6 +608,7 @@ export type PropertyBuilders = {
601
608
  bigint: <Mode extends 'bigint' | 'number' | 'string' = 'bigint'>(mode?: Mode) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.bigint<Mode>>, EmptyOptions, IncludeKeysForProperty>;
602
609
  array: <T = string>(toJsValue?: (i: string) => T, toDbValue?: (i: T) => string) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.array<T>>, EmptyOptions, IncludeKeysForProperty>;
603
610
  decimal: <Mode extends 'number' | 'string' = 'string'>(mode?: Mode) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.decimal<Mode>>, EmptyOptions, IncludeKeysForProperty>;
611
+ double: <Mode extends 'number' | 'string' = 'number'>(mode?: Mode) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.double<Mode>>, EmptyOptions, IncludeKeysForProperty>;
604
612
  json: <T>() => UniversalPropertyOptionsBuilder<T, EmptyOptions, IncludeKeysForProperty>;
605
613
  string: () => StringPropertyOptionsBuilder<InferPropertyValueType<typeof types.string>, EmptyOptions>;
606
614
  text: () => StringPropertyOptionsBuilder<InferPropertyValueType<typeof types.text>, EmptyOptions>;
@@ -630,6 +638,21 @@ type AllKeys<TProperties, TBase> = keyof TProperties | (IsNever<TBase> extends t
630
638
  type PartialWhere<TProperties, TBase> = string | FilterQuery<{
631
639
  [K in AllKeys<TProperties, TBase> & string]?: unknown;
632
640
  }>;
641
+ type DefineEntityFilterMap = Dictionary<{
642
+ name: string;
643
+ cond: Dictionary | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any>, entityName?: string) => MaybePromise<FilterQuery<any>>);
644
+ default?: boolean;
645
+ entity?: EntityName<any> | EntityName<any>[];
646
+ args?: boolean;
647
+ strict?: boolean;
648
+ rls?: boolean | {
649
+ setting?: string;
650
+ };
651
+ }>;
652
+ type DefineEntityFilterMapLoose = Dictionary<{
653
+ name: string;
654
+ cond: Dictionary;
655
+ }>;
633
656
  /** Metadata descriptor for `defineEntity()`, combining entity options with property definitions. */
634
657
  export interface EntityMetadataWithProperties<TName extends string, TTableName extends string, TProperties extends Record<string, any>, TPK extends (keyof TProperties)[] | undefined = undefined, TBase = never, TRepository = never, TForceObject extends boolean = false, TDiscriminatorColumn extends string | undefined = undefined, TDiscriminatorValue extends string | number | undefined = undefined, TBaseDiscriminatorColumn extends string | undefined = undefined, TEmbeddable extends boolean = false, TForceUndefined extends boolean = false> extends Omit<Partial<EntityMetadata<InferEntityFromProperties<TProperties, TPK, TBase, TRepository>>>, 'properties' | 'extends' | 'primaryKeys' | 'hooks' | 'discriminator' | 'discriminatorColumn' | 'discriminatorValue' | 'versionProperty' | 'concurrencyCheckKeys' | 'serializedPrimaryKey' | 'indexes' | 'uniques' | 'triggers' | 'repository' | 'filters' | 'orderBy'> {
635
658
  name: TName;
@@ -641,20 +664,10 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
641
664
  '~discriminatorColumn'?: TBaseDiscriminatorColumn;
642
665
  });
643
666
  properties: TProperties | ((properties: PropertyBuilders) => TProperties);
644
- primaryKeys?: TPK & InferPrimaryKeyConstraint<TProperties>[];
667
+ primaryKeys?: TPK & NoInfer<InferPrimaryKeyConstraint<TProperties>>[];
645
668
  hooks?: DefineEntityHooks;
646
669
  repository?: () => TRepository;
647
- filters?: Dictionary<{
648
- name: string;
649
- cond: Dictionary | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any>, entityName?: string) => MaybePromise<FilterQuery<any>>);
650
- default?: boolean;
651
- entity?: EntityName<any> | EntityName<any>[];
652
- args?: boolean;
653
- strict?: boolean;
654
- rls?: boolean | {
655
- setting?: string;
656
- };
657
- }>;
670
+ filters?: DefineEntityFilterMap | IsNever<TRepository, never, DefineEntityFilterMapLoose>;
658
671
  forceObject?: TForceObject;
659
672
  /** Hydrate `null` as `undefined` for this entity and infer nullable properties as `T | undefined`. */
660
673
  forceUndefined?: TForceUndefined;
@@ -669,16 +682,16 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
669
682
  /** Alias for `discriminator`. */
670
683
  discriminatorColumn?: TDiscriminatorColumn;
671
684
  discriminatorValue?: TDiscriminatorValue;
672
- versionProperty?: AllKeys<TProperties, TBase>;
673
- concurrencyCheckKeys?: Set<AllKeys<TProperties, TBase>>;
674
- serializedPrimaryKey?: AllKeys<TProperties, TBase>;
685
+ versionProperty?: NoInfer<AllKeys<TProperties, TBase>>;
686
+ concurrencyCheckKeys?: Set<NoInfer<AllKeys<TProperties, TBase>>>;
687
+ serializedPrimaryKey?: NoInfer<AllKeys<TProperties, TBase>>;
675
688
  indexes?: {
676
689
  properties?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
677
690
  name?: string;
678
691
  type?: string;
679
692
  options?: Dictionary;
680
693
  expression?: string | IndexCallback<InferEntityFromProperties<TProperties, TPK, TBase>>;
681
- where?: PartialWhere<TProperties, TBase>;
694
+ where?: NoInfer<PartialWhere<TProperties, TBase>>;
682
695
  columns?: IndexColumnOptions[];
683
696
  include?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
684
697
  fillFactor?: number;
@@ -691,7 +704,7 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
691
704
  name?: string;
692
705
  options?: Dictionary;
693
706
  expression?: string | IndexCallback<InferEntityFromProperties<TProperties, TPK, TBase>>;
694
- where?: PartialWhere<TProperties, TBase>;
707
+ where?: NoInfer<PartialWhere<TProperties, TBase>>;
695
708
  deferMode?: DeferMode | `${DeferMode}`;
696
709
  columns?: IndexColumnOptions[];
697
710
  include?: NoInfer<AllKeys<TProperties, TBase>> | NoInfer<AllKeys<TProperties, TBase>>[];
@@ -323,6 +323,14 @@ export class UniversalPropertyOptionsBuilder {
323
323
  collation(collation) {
324
324
  return this.assignOptions({ collation });
325
325
  }
326
+ /**
327
+ * Set the start value and increment of an autoincrement column. (SQL only)
328
+ * A number is a shorthand for `{ startWith }`.
329
+ * Applied only when the column is created (and by `orm.schema.clear()`), never diffed by the schema generator.
330
+ */
331
+ sequence(sequence) {
332
+ return this.assignOptions({ sequence: typeof sequence === 'number' ? { startWith: sequence } : sequence });
333
+ }
326
334
  /** mysql only */
327
335
  extra(extra) {
328
336
  return this.assignOptions({ extra });
@@ -511,6 +519,7 @@ const propertyBuilders = {
511
519
  bigint: (mode) => new UniversalPropertyOptionsBuilder({ type: new types.bigint(mode) }),
512
520
  array: (toJsValue = i => i, toDbValue = i => i) => new UniversalPropertyOptionsBuilder({ type: new types.array(toJsValue, toDbValue) }),
513
521
  decimal: (mode) => new UniversalPropertyOptionsBuilder({ type: new types.decimal(mode) }),
522
+ double: (mode) => new UniversalPropertyOptionsBuilder({ type: new types.double(mode) }),
514
523
  json: () => new UniversalPropertyOptionsBuilder({ type: types.json }),
515
524
  string: () => new StringPropertyOptionsBuilder({
516
525
  type: types.string,
@@ -24,7 +24,10 @@ export function validateProperty(prop, givenValue, entity) {
24
24
  }
25
25
  function getValue(o, prop) {
26
26
  if (prop.embedded && prop.embedded[0] in o) {
27
- return o[prop.embedded[0]]?.[prop.embedded[1]];
27
+ const embeddable = o[prop.embedded[0]];
28
+ const variantProp = embeddable?.__meta?.properties[prop.embedded[1]];
29
+ // a same-named property of a different kind in another polymorphic variant
30
+ return variantProp && !Utils.isSameKind(variantProp, prop) ? undefined : embeddable?.[prop.embedded[1]];
28
31
  }
29
32
  /* v8 ignore next */
30
33
  if (prop.ref) {
package/errors.d.ts CHANGED
@@ -10,6 +10,7 @@ export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Er
10
10
  static fromWrongPropertyType(entity: AnyEntity, property: string, expectedType: string, givenType: string, givenValue: string): ValidationError;
11
11
  static fromWrongRepositoryType(entityName: string, repoType: string, method: string): ValidationError;
12
12
  static fromMergeWithoutPK(meta: EntityMetadata): ValidationError;
13
+ static referenceWithoutPK(entity: AnyEntity): ValidationError;
13
14
  static transactionRequired(): ValidationError;
14
15
  static entityNotManaged(entity: AnyEntity): ValidationError;
15
16
  static notEntity(owner: AnyEntity, prop: EntityProperty, data: any): ValidationError;
@@ -90,6 +91,12 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
90
91
  static triggersNotSupportedByDriver(meta: EntityMetadata): MetadataError;
91
92
  /** Thrown when row level security is declared on an entity using a driver that does not support it. */
92
93
  static rowLevelSecurityNotSupportedByDriver(meta: EntityMetadata): MetadataError;
94
+ /** Thrown when the `sequence` option is declared on a property that is not autoincrement. */
95
+ static sequenceWithoutAutoincrement(meta: EntityMetadata, prop: EntityProperty): MetadataError;
96
+ /** Thrown when the `sequence` option is combined with an identity option list in `generated`. */
97
+ static sequenceWithIdentityOptions(meta: EntityMetadata, prop: EntityProperty): MetadataError;
98
+ /** Thrown when `sequence.incrementBy` is declared on a platform without a per-column increment. */
99
+ static sequenceIncrementNotSupported(meta: EntityMetadata, prop: EntityProperty, platform: string): MetadataError;
93
100
  /** Thrown when row level security is declared on a non-root entity of an STI hierarchy. */
94
101
  static rowLevelSecurityOnNonRootStiEntity(meta: EntityMetadata): MetadataError;
95
102
  /** Thrown when two policies on the same entity are given the same explicit name. */
package/errors.js CHANGED
@@ -28,6 +28,9 @@ export class ValidationError extends Error {
28
28
  static fromMergeWithoutPK(meta) {
29
29
  return new ValidationError(`You cannot merge entity '${meta.className}' without identifier!`);
30
30
  }
31
+ static referenceWithoutPK(entity) {
32
+ return new ValidationError(`Entity '${entity.constructor.name}' is only known by an alternate key and has no primary key, load it first`, entity);
33
+ }
31
34
  static transactionRequired() {
32
35
  return new ValidationError('An open transaction is required for this operation');
33
36
  }
@@ -293,6 +296,18 @@ export class MetadataError extends ValidationError {
293
296
  static rowLevelSecurityNotSupportedByDriver(meta) {
294
297
  return new MetadataError(`Entity ${meta.className} declares row level security which is not supported by the current driver. Row level security is only available with the PostgreSQL driver. To test a PostgreSQL app without a server, use the \`@mikro-orm/pglite\` driver instead of sqlite.`);
295
298
  }
299
+ /** Thrown when the `sequence` option is declared on a property that is not autoincrement. */
300
+ static sequenceWithoutAutoincrement(meta, prop) {
301
+ return MetadataError.fromMessage(meta, prop, `defines the 'sequence' option, but is not an autoincrement property`);
302
+ }
303
+ /** Thrown when the `sequence` option is combined with an identity option list in `generated`. */
304
+ static sequenceWithIdentityOptions(meta, prop) {
305
+ return MetadataError.fromMessage(meta, prop, `defines the 'sequence' option together with identity options in 'generated', use only one of them`);
306
+ }
307
+ /** Thrown when `sequence.incrementBy` is declared on a platform without a per-column increment. */
308
+ static sequenceIncrementNotSupported(meta, prop, platform) {
309
+ return MetadataError.fromMessage(meta, prop, `defines 'sequence.incrementBy', but ${platform} does not support a per-column increment`);
310
+ }
296
311
  /** Thrown when row level security is declared on a non-root entity of an STI hierarchy. */
297
312
  static rowLevelSecurityOnNonRootStiEntity(meta) {
298
313
  return new MetadataError(`Entity ${meta.className} declares row level security, but it is part of a single table inheritance hierarchy. Declare policies on the root entity ${meta.root.className} instead, as the whole hierarchy shares a single table.`);
@@ -207,7 +207,7 @@ export class ObjectHydrator extends Hydrator {
207
207
  if (prop.customType?.ensureComparable(meta, prop)) {
208
208
  registerCustomType(prop, this.safeKey(prop.name), 'convertToDatabaseValue', context);
209
209
  ret.push(` if (data${dataKey} != null && typeof data${dataKey} !== 'object' && convertCustomTypes) {`);
210
- ret.push(` data${dataKey} = convertToDatabaseValue_${this.safeKey(prop.name)}(entity${entityKey}.__helper.getPrimaryKey());`);
210
+ ret.push(` data${dataKey} = convertToDatabaseValue_${this.safeKey(prop.name)}(entity${entityKey}.__helper.getTargetKeyValue(${prop.targetKey ? this.quote(prop.targetKey) : ''}));`);
211
211
  ret.push(` }`);
212
212
  }
213
213
  return ret;
@@ -313,6 +313,10 @@ export class ObjectHydrator extends Hydrator {
313
313
  ? dataKey + this.wrap(childProp.embedded[1])
314
314
  : this.wrap(childProp.name);
315
315
  const prop2 = childMeta.properties[childProp.embedded[1]];
316
+ // a same-named property of a different kind in another variant
317
+ if (prop2 && !Utils.isSameKind(prop2, childProp)) {
318
+ return;
319
+ }
316
320
  const prop3 = {
317
321
  ...prop2,
318
322
  name: childProp.name,
@@ -404,7 +408,7 @@ export class ObjectHydrator extends Hydrator {
404
408
  const code = `// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n` +
405
409
  `return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n` +
406
410
  `${lines.join('\n')}\n}`;
407
- const fnKey = `hydrator-${meta.uniqueName}-${type}-${normalizeAccessors}`;
411
+ const fnKey = `hydrator-${meta.compiledName}-${type}-${normalizeAccessors}`;
408
412
  const hydrator = Utils.createFunction(context, code, this.config.get('compiledFunctions'), fnKey);
409
413
  this.#hydrators[key].set(meta.class, hydrator);
410
414
  return hydrator;
@@ -29,11 +29,21 @@ export declare class MetadataDiscovery {
29
29
  private initFieldName;
30
30
  private initManyToOneFieldName;
31
31
  private initManyToManyFieldName;
32
+ /**
33
+ * Walks up the TPT hierarchy to the entity whose M:N declaration this property inherits. A child redeclaring
34
+ * the property with a different target, pivot table, join columns or fixed order keeps its own pivot table.
35
+ */
36
+ private getPivotDeclaringMeta;
32
37
  private initManyToManyFields;
33
38
  private isExplicitTableName;
34
39
  private initManyToOneFields;
35
40
  private initOneToManyFields;
36
41
  private processEntity;
42
+ /**
43
+ * Groups the relations of all entities by target class name in one pass, so `findReferencingProperties()`
44
+ * does not go over the relations of every entity for each entity. Lists keep the order of `metadata` and `relations`.
45
+ */
46
+ private indexReferencingProperties;
37
47
  private findReferencingProperties;
38
48
  private initFactoryField;
39
49
  private ensureCorrectFKOrderInPivotEntity;