@mikro-orm/core 7.0.0-dev.2 → 7.0.0-dev.21

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 (59) hide show
  1. package/EntityManager.d.ts +13 -5
  2. package/EntityManager.js +60 -40
  3. package/MikroORM.js +2 -2
  4. package/cache/FileCacheAdapter.js +2 -2
  5. package/decorators/Check.d.ts +2 -2
  6. package/decorators/CreateRequestContext.js +4 -1
  7. package/decorators/Embeddable.d.ts +5 -5
  8. package/decorators/Embeddable.js +1 -1
  9. package/decorators/Embedded.d.ts +6 -12
  10. package/decorators/Entity.d.ts +5 -5
  11. package/decorators/Entity.js +0 -1
  12. package/decorators/Enum.d.ts +1 -1
  13. package/decorators/Formula.d.ts +1 -2
  14. package/decorators/Indexed.d.ts +9 -7
  15. package/decorators/Indexed.js +1 -1
  16. package/decorators/ManyToMany.d.ts +2 -2
  17. package/decorators/ManyToOne.d.ts +4 -2
  18. package/decorators/OneToMany.d.ts +4 -4
  19. package/decorators/OneToOne.d.ts +3 -1
  20. package/decorators/PrimaryKey.d.ts +2 -3
  21. package/decorators/Property.d.ts +1 -1
  22. package/drivers/IDatabaseDriver.d.ts +4 -1
  23. package/entity/ArrayCollection.d.ts +1 -1
  24. package/entity/ArrayCollection.js +11 -4
  25. package/entity/Collection.d.ts +1 -2
  26. package/entity/Collection.js +14 -9
  27. package/entity/EntityFactory.js +4 -1
  28. package/entity/EntityHelper.js +3 -0
  29. package/entity/EntityLoader.d.ts +3 -2
  30. package/entity/EntityLoader.js +20 -6
  31. package/entity/Reference.d.ts +3 -7
  32. package/enums.d.ts +1 -1
  33. package/events/EventSubscriber.d.ts +3 -1
  34. package/exports.d.ts +24 -0
  35. package/exports.js +23 -0
  36. package/hydration/ObjectHydrator.js +1 -0
  37. package/index.d.ts +1 -1
  38. package/metadata/EntitySchema.d.ts +6 -4
  39. package/metadata/EntitySchema.js +23 -17
  40. package/metadata/MetadataDiscovery.js +25 -12
  41. package/metadata/MetadataValidator.js +4 -3
  42. package/package.json +7 -6
  43. package/types/BigIntType.d.ts +1 -0
  44. package/types/BigIntType.js +3 -0
  45. package/typings.d.ts +17 -10
  46. package/typings.js +3 -0
  47. package/unit-of-work/ChangeSetPersister.js +7 -1
  48. package/unit-of-work/UnitOfWork.js +25 -9
  49. package/utils/AbstractSchemaGenerator.js +5 -2
  50. package/utils/Configuration.d.ts +1 -1
  51. package/utils/Configuration.js +1 -1
  52. package/utils/Cursor.d.ts +3 -3
  53. package/utils/DataloaderUtils.d.ts +1 -1
  54. package/utils/DataloaderUtils.js +19 -5
  55. package/utils/EntityComparator.js +65 -49
  56. package/utils/QueryHelper.js +1 -1
  57. package/utils/RawQueryFragment.js +6 -1
  58. package/utils/Utils.d.ts +8 -2
  59. package/utils/Utils.js +26 -6
@@ -7,7 +7,6 @@ import { helper } from './wrap.js';
7
7
  export class Collection extends ArrayCollection {
8
8
  readonly;
9
9
  _populated;
10
- _em;
11
10
  // this is for some reason needed for TS, otherwise it can fail with `Type instantiation is excessively deep and possibly infinite.`
12
11
  _snapshot;
13
12
  constructor(owner, items, initialized = true) {
@@ -220,11 +219,20 @@ export class Collection extends ArrayCollection {
220
219
  const em = this.getEntityManager();
221
220
  if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
222
221
  const order = [...this.items]; // copy order of references
223
- const customOrder = !!options.orderBy;
222
+ const orderBy = this.createOrderBy(options.orderBy);
223
+ const customOrder = orderBy.length > 0;
224
224
  // eslint-disable-next-line dot-notation
225
- const items = await em['colLoader'].load([this, options]);
226
- if (!customOrder) {
227
- this.reorderItems(items, order);
225
+ const items = await em['colLoader'].load([
226
+ this,
227
+ { ...options, orderBy },
228
+ ]);
229
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
230
+ this.initialized = true;
231
+ this.dirty = false;
232
+ if (!customOrder) {
233
+ this.reorderItems(items, order);
234
+ }
235
+ return this;
228
236
  }
229
237
  this.items.clear();
230
238
  let i = 0;
@@ -254,7 +262,7 @@ export class Collection extends ArrayCollection {
254
262
  }
255
263
  getEntityManager(items = [], required = true) {
256
264
  const wrapped = helper(this.owner);
257
- let em = (this._em ?? wrapped.__em);
265
+ let em = wrapped.__em;
258
266
  if (!em) {
259
267
  for (const i of items) {
260
268
  if (i && helper(i).__em) {
@@ -263,9 +271,6 @@ export class Collection extends ArrayCollection {
263
271
  }
264
272
  }
265
273
  }
266
- if (em) {
267
- Object.defineProperty(this, '_em', { value: em });
268
- }
269
274
  if (!em && required) {
270
275
  throw ValidationError.entityNotManaged(this.owner);
271
276
  }
@@ -45,6 +45,7 @@ export class EntityFactory {
45
45
  let wrapped = exists && helper(exists);
46
46
  if (wrapped && !options.refresh) {
47
47
  wrapped.__processing = true;
48
+ Utils.dropUndefinedProperties(data);
48
49
  this.mergeData(meta2, exists, data, options);
49
50
  wrapped.__processing = false;
50
51
  if (wrapped.isInitialized()) {
@@ -86,7 +87,9 @@ export class EntityFactory {
86
87
  }
87
88
  if (options.merge && wrapped.hasPrimaryKey()) {
88
89
  this.unitOfWork.register(entity, data, {
89
- refresh: options.refresh && options.initialized,
90
+ // Always refresh to ensure the payload is in correct shape for joined strategy. When loading nested relations,
91
+ // they will be created early without `Type.ensureComparable` being properly handled, resulting in extra updates.
92
+ refresh: options.initialized,
90
93
  newEntity: options.newEntity,
91
94
  loaded: options.initialized,
92
95
  });
@@ -146,6 +146,9 @@ export class EntityHelper {
146
146
  set(val) {
147
147
  const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
148
148
  const old = Reference.unwrapReference(wrapped.__data[prop.name]);
149
+ if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
150
+ old[prop.inversedBy].removeWithoutPropagation(this);
151
+ }
149
152
  wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
150
153
  // when propagation from inside hydration, we set the FK to the entity data immediately
151
154
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
@@ -1,4 +1,4 @@
1
- import type { ConnectionType, Dictionary, FilterQuery, PopulateOptions } from '../typings.js';
1
+ import type { AnyEntity, ConnectionType, Dictionary, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
2
2
  import type { EntityManager } from '../EntityManager.js';
3
3
  import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
4
4
  import type { EntityField } from '../drivers/IDatabaseDriver.js';
@@ -49,7 +49,8 @@ export declare class EntityLoader {
49
49
  private findChildren;
50
50
  private mergePrimaryCondition;
51
51
  private populateField;
52
- private findChildrenFromPivotTable;
52
+ /** @internal */
53
+ findChildrenFromPivotTable<Entity extends object>(filtered: Entity[], prop: EntityProperty<Entity>, options: Required<EntityLoaderOptions<Entity>>, orderBy?: QueryOrderMap<Entity>[], populate?: PopulateOptions<Entity>, pivotJoin?: boolean): Promise<AnyEntity[][]>;
53
54
  private extractChildCondition;
54
55
  private buildFields;
55
56
  private getChildReferences;
@@ -141,7 +141,8 @@ export class EntityLoader {
141
141
  .filter(orderBy => (Array.isArray(orderBy[prop.name]) && orderBy[prop.name].length > 0) || Utils.isObject(orderBy[prop.name]))
142
142
  .flatMap(orderBy => orderBy[prop.name]);
143
143
  if (prop.kind === ReferenceKind.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
144
- return this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
144
+ const res = await this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
145
+ return Utils.flatten(res);
145
146
  }
146
147
  const where = await this.extractChildCondition(options, prop);
147
148
  const data = await this.findChildren(entities, prop, populate, { ...options, where, orderBy: innerOrderBy }, !!(ref || prop.mapToPk));
@@ -249,9 +250,13 @@ export class EntityLoader {
249
250
  }
250
251
  }
251
252
  }
253
+ const orderBy = [...Utils.asArray(options.orderBy), ...propOrderBy].filter((order, idx, array) => {
254
+ // skip consecutive ordering with the same key to get around mongo issues
255
+ return idx === 0 || !Utils.equals(Object.keys(array[idx - 1]), Object.keys(order));
256
+ });
252
257
  const items = await this.em.find(prop.type, where, {
253
258
  filters, convertCustomTypes, lockMode, populateWhere, logging,
254
- orderBy: [...Utils.asArray(options.orderBy), ...propOrderBy],
259
+ orderBy,
255
260
  populate: populate.children ?? populate.all ?? [],
256
261
  exclude: Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude,
257
262
  strategy, fields, schema, connectionType,
@@ -310,9 +315,16 @@ export class EntityLoader {
310
315
  const innerOrderBy = Utils.asArray(options.orderBy)
311
316
  .filter(orderBy => Utils.isObject(orderBy[prop.name]))
312
317
  .map(orderBy => orderBy[prop.name]);
313
- const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging } = options;
318
+ const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging, schema } = options;
314
319
  const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
315
- const filtered = Utils.unique(children.filter(e => !options.visited.has(e)));
320
+ const visited = options.visited;
321
+ for (const entity of entities) {
322
+ visited.delete(entity);
323
+ }
324
+ const filtered = Utils.unique(children.filter(e => !visited.has(e)));
325
+ for (const entity of entities) {
326
+ visited.add(entity);
327
+ }
316
328
  await this.populate(prop.type, filtered, populate.children ?? populate.all, {
317
329
  where: await this.extractChildCondition(options, prop, false),
318
330
  orderBy: innerOrderBy,
@@ -325,12 +337,14 @@ export class EntityLoader {
325
337
  populateWhere,
326
338
  connectionType,
327
339
  logging,
340
+ schema,
328
341
  // @ts-ignore not a public option, will be propagated to the populate call
329
342
  refresh: refresh && !filtered.every(item => options.visited.has(item)),
330
343
  // @ts-ignore not a public option, will be propagated to the populate call
331
344
  visited: options.visited,
332
345
  });
333
346
  }
347
+ /** @internal */
334
348
  async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
335
349
  const ids = filtered.map(e => e.__helper.__primaryKeys);
336
350
  const refresh = options.refresh;
@@ -368,7 +382,7 @@ export class EntityLoader {
368
382
  return this.em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
369
383
  });
370
384
  entity[prop.name].hydrate(items, true);
371
- children.push(...items);
385
+ children.push(items);
372
386
  }
373
387
  return children;
374
388
  }
@@ -514,7 +528,7 @@ export class EntityLoader {
514
528
  if (refresh) {
515
529
  return entities;
516
530
  }
517
- return entities.filter(e => !e[field]?.__helper?.__initialized);
531
+ return entities.filter(e => e[field] !== null && !e[field]?.__helper?.__initialized);
518
532
  }
519
533
  lookupAllRelationships(entityName) {
520
534
  const ret = [];
@@ -1,5 +1,5 @@
1
1
  import { inspect } from 'node:util';
2
- import type { AddEager, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
2
+ import type { AddEager, AddOptional, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
3
3
  import type { FindOneOptions, FindOneOrFailOptions } from '../drivers/IDatabaseDriver.js';
4
4
  export declare class Reference<T extends object> {
5
5
  private entity;
@@ -72,15 +72,11 @@ export interface LoadReferenceOrFailOptions<T extends object, P extends string =
72
72
  /**
73
73
  * shortcut for `wrap(entity).toReference()`
74
74
  */
75
- export declare function ref<T>(entity: T | Ref<T>): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>;
75
+ export declare function ref<I extends unknown | Ref<unknown> | undefined | null, T extends I & {}>(entity: I): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>> | AddOptional<typeof entity>;
76
76
  /**
77
77
  * shortcut for `Reference.createFromPK(entityType, pk)`
78
78
  */
79
- export declare function ref<T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk?: T | PKV): Ref<T>;
80
- /**
81
- * shortcut for `wrap(entity).toReference()`
82
- */
83
- export declare function ref<T>(value: T | Ref<T>): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>;
79
+ export declare function ref<I extends unknown | undefined | null, T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk: I): Ref<T> | AddOptional<typeof pk>;
84
80
  /**
85
81
  * shortcut for `Reference.createNakedFromPK(entityType, pk)`
86
82
  */
package/enums.d.ts CHANGED
@@ -66,7 +66,7 @@ export declare enum QueryOrderNumeric {
66
66
  ASC = 1,
67
67
  DESC = -1
68
68
  }
69
- export type QueryOrderKeysFlat = QueryOrder | QueryOrderNumeric | keyof typeof QueryOrder;
69
+ export type QueryOrderKeysFlat = QueryOrder | QueryOrderNumeric | `${QueryOrder}`;
70
70
  export type QueryOrderKeys<T> = QueryOrderKeysFlat | QueryOrderMap<T>;
71
71
  export type QueryOrderMap<T> = {
72
72
  [K in EntityKey<T>]?: QueryOrderKeys<ExpandProperty<T[K]>>;
@@ -13,7 +13,9 @@ export interface FlushEventArgs extends Omit<EventArgs<any>, 'entity' | 'changeS
13
13
  uow: UnitOfWork;
14
14
  }
15
15
  export interface TransactionEventArgs extends Omit<EventArgs<any>, 'entity' | 'meta' | 'changeSet'> {
16
- transaction?: Transaction;
16
+ transaction?: Transaction & {
17
+ savepointName?: string;
18
+ };
17
19
  uow?: UnitOfWork;
18
20
  }
19
21
  export interface EventSubscriber<T = any> {
package/exports.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module core
4
+ */
5
+ export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, } from './typings.js';
6
+ export * from './enums.js';
7
+ export * from './errors.js';
8
+ export * from './exceptions.js';
9
+ export * from './entity/index.js';
10
+ export * from './serialization/index.js';
11
+ export * from './events/index.js';
12
+ export { CreateOptions, MergeOptions, ForkOptions } from './EntityManager.js';
13
+ export * from './unit-of-work/index.js';
14
+ export * from './utils/index.js';
15
+ export * from './logging/index.js';
16
+ export * from './hydration/index.js';
17
+ export * from './drivers/index.js';
18
+ export * from './connections/index.js';
19
+ export * from './platforms/index.js';
20
+ export * from './types/index.js';
21
+ export * from './naming-strategy/index.js';
22
+ export * from './metadata/index.js';
23
+ export * from './cache/index.js';
24
+ export * from './decorators/index.js';
package/exports.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module core
4
+ */
5
+ export { PrimaryKeyProp, EntityMetadata, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, } from './typings.js';
6
+ export * from './enums.js';
7
+ export * from './errors.js';
8
+ export * from './exceptions.js';
9
+ export * from './entity/index.js';
10
+ export * from './serialization/index.js';
11
+ export * from './events/index.js';
12
+ export * from './unit-of-work/index.js';
13
+ export * from './utils/index.js';
14
+ export * from './logging/index.js';
15
+ export * from './hydration/index.js';
16
+ export * from './drivers/index.js';
17
+ export * from './connections/index.js';
18
+ export * from './platforms/index.js';
19
+ export * from './types/index.js';
20
+ export * from './naming-strategy/index.js';
21
+ export * from './metadata/index.js';
22
+ export * from './cache/index.js';
23
+ export * from './decorators/index.js';
@@ -256,6 +256,7 @@ export class ObjectHydrator extends Hydrator {
256
256
  ...prop2,
257
257
  name: childProp.name,
258
258
  embedded: childProp.embedded,
259
+ embeddedProps: childProp.embeddedProps,
259
260
  };
260
261
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
261
262
  ret.push(...hydrateProperty(prop3, childProp.object, [...path, childProp.embedded[1]], childDataKey).map(l => ' ' + l));
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @packageDocumentation
3
3
  * @module core
4
4
  */
5
- export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, } from './typings.js';
5
+ export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, } from './typings.js';
6
6
  export * from './enums.js';
7
7
  export * from './errors.js';
8
8
  export * from './exceptions.js';
@@ -31,7 +31,7 @@ export type EntitySchemaProperty<Target, Owner> = ({
31
31
  kind: ReferenceKind.MANY_TO_MANY | 'm:n';
32
32
  } & TypeDef<Target> & ManyToManyOptions<Owner, Target>) | ({
33
33
  kind: ReferenceKind.EMBEDDED | 'embedded';
34
- } & EmbeddedTypeDef<Target> & EmbeddedOptions & PropertyOptions<Owner>) | ({
34
+ } & EmbeddedTypeDef<Target> & EmbeddedOptions<Owner, Target> & PropertyOptions<Owner>) | ({
35
35
  enum: true;
36
36
  } & EnumOptions<Owner>) | (TypeDef<Target> & PropertyOptions<Owner>);
37
37
  type OmitBaseProps<Entity, Base> = IsNever<Base> extends true ? Entity : Omit<Entity, keyof Base>;
@@ -63,13 +63,13 @@ export declare class EntitySchema<Entity = any, Base = never> {
63
63
  addVersion(name: EntityKey<Entity>, type: TypeType, options?: PropertyOptions<Entity>): void;
64
64
  addPrimaryKey(name: EntityKey<Entity>, type: TypeType, options?: PrimaryKeyOptions<Entity>): void;
65
65
  addSerializedPrimaryKey(name: EntityKey<Entity>, type: TypeType, options?: SerializedPrimaryKeyOptions<Entity>): void;
66
- addEmbedded<Target = AnyEntity>(name: EntityKey<Entity>, options: EmbeddedOptions): void;
66
+ addEmbedded<Target = AnyEntity>(name: EntityKey<Entity>, options: EmbeddedOptions<Entity, Target>): void;
67
67
  addManyToOne<Target = AnyEntity>(name: EntityKey<Entity>, type: TypeType, options: ManyToOneOptions<Entity, Target>): void;
68
68
  addManyToMany<Target = AnyEntity>(name: EntityKey<Entity>, type: TypeType, options: ManyToManyOptions<Entity, Target>): void;
69
69
  addOneToMany<Target = AnyEntity>(name: EntityKey<Entity>, type: TypeType, options: OneToManyOptions<Entity, Target>): void;
70
70
  addOneToOne<Target = AnyEntity>(name: EntityKey<Entity>, type: TypeType, options: OneToOneOptions<Entity, Target>): void;
71
- addIndex(options: IndexOptions<Entity>): void;
72
- addUnique(options: UniqueOptions<Entity>): void;
71
+ addIndex<Key extends string>(options: IndexOptions<Entity, Key>): void;
72
+ addUnique<Key extends string>(options: UniqueOptions<Entity, Key>): void;
73
73
  setCustomRepository(repository: () => Constructor): void;
74
74
  setExtends(base: string | EntitySchema): void;
75
75
  setClass(proto: EntityClass<Entity>): void;
@@ -83,5 +83,7 @@ export declare class EntitySchema<Entity = any, Base = never> {
83
83
  private initPrimaryKeys;
84
84
  private normalizeType;
85
85
  private createProperty;
86
+ private rename;
87
+ private renameCompositeOptions;
86
88
  }
87
89
  export {};
@@ -34,23 +34,7 @@ export class EntitySchema {
34
34
  return schema;
35
35
  }
36
36
  addProperty(name, type, options = {}) {
37
- const rename = (data, from, to) => {
38
- if (from in options && !(to in options)) {
39
- // @ts-ignore
40
- options[to] = [options[from]];
41
- // @ts-ignore
42
- delete options[from];
43
- }
44
- };
45
- if (name !== options.name) {
46
- Utils.renameKey(options, 'name', 'fieldName');
47
- }
48
- rename(options, 'fieldName', 'fieldNames');
49
- rename(options, 'ref', 'ref');
50
- rename(options, 'joinColumn', 'joinColumns');
51
- rename(options, 'inverseJoinColumn', 'inverseJoinColumns');
52
- rename(options, 'referenceColumnName', 'referencedColumnNames');
53
- rename(options, 'columnType', 'columnTypes');
37
+ this.renameCompositeOptions(name, options);
54
38
  const prop = { name, kind: ReferenceKind.SCALAR, ...options, type: this.normalizeType(options, type) };
55
39
  if (type && Type.isMappedType(type.prototype)) {
56
40
  prop.type = type;
@@ -94,6 +78,7 @@ export class EntitySchema {
94
78
  this.addProperty(name, type, options);
95
79
  }
96
80
  addEmbedded(name, options) {
81
+ this.renameCompositeOptions(name, options);
97
82
  Utils.defaultValue(options, 'prefix', true);
98
83
  if (options.array) {
99
84
  options.object = true; // force object mode for arrays
@@ -289,4 +274,25 @@ export class EntitySchema {
289
274
  ...options,
290
275
  };
291
276
  }
277
+ rename(data, from, to) {
278
+ if (from in data && !(to in data)) {
279
+ // @ts-ignore
280
+ data[to] = [data[from]];
281
+ // @ts-ignore
282
+ delete data[from];
283
+ }
284
+ }
285
+ renameCompositeOptions(name, options = {}) {
286
+ if (name !== options.name && !options.fieldNames) {
287
+ Utils.renameKey(options, 'name', 'fieldName');
288
+ }
289
+ else if (options.name && (options.fieldNames?.length ?? 0) > 1) {
290
+ delete options.name;
291
+ }
292
+ this.rename(options, 'fieldName', 'fieldNames');
293
+ this.rename(options, 'joinColumn', 'joinColumns');
294
+ this.rename(options, 'inverseJoinColumn', 'inverseJoinColumns');
295
+ this.rename(options, 'referenceColumnName', 'referencedColumnNames');
296
+ this.rename(options, 'columnType', 'columnTypes');
297
+ }
292
298
  }
@@ -1,5 +1,5 @@
1
1
  import { basename, extname } from 'node:path';
2
- import globby from 'globby';
2
+ import { glob } from 'tinyglobby';
3
3
  import { EntityMetadata, } from '../typings.js';
4
4
  import { Utils } from '../utils/Utils.js';
5
5
  import { MetadataValidator } from './MetadataValidator.js';
@@ -7,7 +7,7 @@ import { MetadataStorage } from './MetadataStorage.js';
7
7
  import { EntitySchema } from './EntitySchema.js';
8
8
  import { Cascade, ReferenceKind } from '../enums.js';
9
9
  import { MetadataError } from '../errors.js';
10
- import { ArrayType, BigIntType, BlobType, DecimalType, DoubleType, EnumArrayType, IntervalType, JsonType, t, Type, Uint8ArrayType, UnknownType, } from '../types/index.js';
10
+ import { ArrayType, BigIntType, BlobType, DateType, DecimalType, DoubleType, EnumArrayType, IntervalType, JsonType, t, Type, Uint8ArrayType, UnknownType, } from '../types/index.js';
11
11
  import { colors } from '../logging/colors.js';
12
12
  import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
13
13
  export class MetadataDiscovery {
@@ -181,7 +181,7 @@ export class MetadataDiscovery {
181
181
  }
182
182
  async discoverDirectories(paths) {
183
183
  paths = paths.map(path => Utils.normalizePath(path));
184
- const files = await globby(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
184
+ const files = await glob(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
185
185
  this.logger.log('discovery', `- processing ${colors.cyan('' + files.length)} files`);
186
186
  const found = [];
187
187
  for (const filepath of files) {
@@ -264,7 +264,8 @@ export class MetadataDiscovery {
264
264
  // initialize global metadata for given entity
265
265
  MetadataStorage.getMetadata(entity.meta.className, filepath);
266
266
  }
267
- return entity;
267
+ const meta = Utils.copy(entity.meta, false);
268
+ return EntitySchema.fromMetadata(meta);
268
269
  }
269
270
  const path = entity[MetadataStorage.PATH_SYMBOL];
270
271
  if (path) {
@@ -765,6 +766,7 @@ export class MetadataDiscovery {
765
766
  delete prop.default;
766
767
  if (properties[prop.name] && properties[prop.name].type !== prop.type) {
767
768
  properties[prop.name].type = `${properties[prop.name].type} | ${prop.type}`;
769
+ properties[prop.name].runtimeType = 'any';
768
770
  return properties[prop.name];
769
771
  }
770
772
  return properties[prop.name] = prop;
@@ -872,6 +874,7 @@ export class MetadataDiscovery {
872
874
  meta.properties[name].persist = false; // only virtual as we store the whole object
873
875
  meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
874
876
  meta.properties[name].object = true;
877
+ this.initCustomType(meta, meta.properties[name], true);
875
878
  }
876
879
  this.initEmbeddables(meta, meta.properties[name], visited);
877
880
  }
@@ -905,11 +908,13 @@ export class MetadataDiscovery {
905
908
  }
906
909
  if (!meta.root.discriminatorMap) {
907
910
  meta.root.discriminatorMap = {};
908
- const children = metadata.filter(m => m.root.className === meta.root.className && !m.abstract);
909
- children.forEach(m => {
911
+ const children = metadata
912
+ .filter(m => m.root.className === meta.root.className && !m.abstract)
913
+ .sort((a, b) => a.className.localeCompare(b.className));
914
+ for (const m of children) {
910
915
  const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
911
916
  meta.root.discriminatorMap[name] = m.className;
912
- });
917
+ }
913
918
  }
914
919
  meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, className]) => className === meta.className)?.[0];
915
920
  if (!meta.root.properties[meta.root.discriminatorColumn]) {
@@ -922,7 +927,7 @@ export class MetadataDiscovery {
922
927
  }
923
928
  let i = 1;
924
929
  Object.values(meta.properties).forEach(prop => {
925
- const newProp = Utils.copy(prop, false);
930
+ const newProp = { ...prop };
926
931
  if (meta.root.properties[prop.name] && meta.root.properties[prop.name].type !== prop.type) {
927
932
  const name = newProp.name;
928
933
  this.initFieldName(newProp, newProp.object);
@@ -944,6 +949,7 @@ export class MetadataDiscovery {
944
949
  meta.collection = meta.root.collection;
945
950
  meta.root.indexes = Utils.unique([...meta.root.indexes, ...meta.indexes]);
946
951
  meta.root.uniques = Utils.unique([...meta.root.uniques, ...meta.uniques]);
952
+ meta.root.checks = Utils.unique([...meta.root.checks, ...meta.checks]);
947
953
  }
948
954
  createDiscriminatorProperty(meta) {
949
955
  meta.addProperty({
@@ -1095,7 +1101,7 @@ export class MetadataDiscovery {
1095
1101
  meta.concurrencyCheckKeys.add(prop.name);
1096
1102
  }
1097
1103
  }
1098
- initCustomType(meta, prop) {
1104
+ initCustomType(meta, prop, objectEmbeddable = false) {
1099
1105
  // `prop.type` might be actually instance of custom type class
1100
1106
  if (Type.isMappedType(prop.type) && !prop.customType) {
1101
1107
  prop.customType = prop.type;
@@ -1115,12 +1121,16 @@ export class MetadataDiscovery {
1115
1121
  if (!prop.customType && prop.array && prop.items) {
1116
1122
  prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1117
1123
  }
1124
+ const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
1125
+ if (objectEmbeddable && !prop.customType && isArray) {
1126
+ prop.customType = new JsonType();
1127
+ }
1118
1128
  // for number arrays we make sure to convert the items to numbers
1119
1129
  if (!prop.customType && prop.type === 'number[]') {
1120
1130
  prop.customType = new ArrayType(i => +i);
1121
1131
  }
1122
1132
  // `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
1123
- if (!prop.customType && (prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]'))) {
1133
+ if (!prop.customType && isArray) {
1124
1134
  prop.customType = new ArrayType();
1125
1135
  }
1126
1136
  if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
@@ -1131,7 +1141,7 @@ export class MetadataDiscovery {
1131
1141
  }
1132
1142
  const mappedType = this.getMappedType(prop);
1133
1143
  if (prop.fieldNames?.length === 1 && !prop.customType) {
1134
- [BigIntType, DoubleType, DecimalType, IntervalType]
1144
+ [BigIntType, DoubleType, DecimalType, IntervalType, DateType]
1135
1145
  .filter(type => mappedType instanceof type)
1136
1146
  .forEach(type => prop.customType = new type());
1137
1147
  }
@@ -1144,6 +1154,9 @@ export class MetadataDiscovery {
1144
1154
  prop.runtimeType ??= prop.customType.runtimeType;
1145
1155
  }
1146
1156
  }
1157
+ else if (prop.runtimeType === 'object') {
1158
+ prop.runtimeType = mappedType.runtimeType;
1159
+ }
1147
1160
  else {
1148
1161
  prop.runtimeType ??= mappedType.runtimeType;
1149
1162
  }
@@ -1158,7 +1171,7 @@ export class MetadataDiscovery {
1158
1171
  prop.customType.mode = prop.runtimeType.toLowerCase();
1159
1172
  }
1160
1173
  }
1161
- if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !prop.type?.toString().endsWith('[]')) {
1174
+ if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1162
1175
  prop.type = prop.customType.name;
1163
1176
  }
1164
1177
  if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && this.metadata.get(prop.type).compositePK) {
@@ -100,14 +100,15 @@ export class MetadataValidator {
100
100
  if (!prop.type) {
101
101
  throw MetadataError.fromWrongTypeDefinition(meta, prop);
102
102
  }
103
+ const targetMeta = metadata.find(prop.type);
103
104
  // references do have type of known entity
104
- if (!metadata.find(prop.type)) {
105
+ if (!targetMeta) {
105
106
  throw MetadataError.fromWrongTypeDefinition(meta, prop);
106
107
  }
107
- if (metadata.find(prop.type).abstract && !metadata.find(prop.type).discriminatorColumn) {
108
+ if (targetMeta.abstract && !targetMeta.discriminatorColumn && !targetMeta.embeddable) {
108
109
  throw MetadataError.targetIsAbstract(meta, prop);
109
110
  }
110
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.persist === false && metadata.find(prop.type).compositePK && options.checkNonPersistentCompositeProps) {
111
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.persist === false && targetMeta.compositePK && options.checkNonPersistentCompositeProps) {
111
112
  throw MetadataError.nonPersistentCompositeProp(meta, prop);
112
113
  }
113
114
  }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.2",
4
+ "version": "7.0.0-dev.21",
5
5
  "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.",
6
6
  "exports": {
7
7
  "./package.json": "./package.json",
8
- ".": "./index.js"
8
+ ".": "./index.js",
9
+ "./exports.js": "./exports.js"
9
10
  },
10
11
  "repository": {
11
12
  "type": "git",
@@ -52,10 +53,10 @@
52
53
  },
53
54
  "dependencies": {
54
55
  "dataloader": "2.2.3",
55
- "dotenv": "16.4.7",
56
+ "dotenv": "16.5.0",
56
57
  "esprima": "4.0.1",
57
- "globby": "11.1.0",
58
- "mikro-orm": "7.0.0-dev.2",
59
- "reflect-metadata": "0.2.2"
58
+ "mikro-orm": "7.0.0-dev.21",
59
+ "reflect-metadata": "0.2.2",
60
+ "tinyglobby": "0.2.13"
60
61
  }
61
62
  }
@@ -13,4 +13,5 @@ export declare class BigIntType extends Type<string | bigint | number | null | u
13
13
  toJSON(value: string | bigint | null | undefined): string | bigint | null | undefined;
14
14
  getColumnType(prop: EntityProperty, platform: Platform): string;
15
15
  compareAsType(): string;
16
+ compareValues(a: string, b: string): boolean;
16
17
  }
@@ -42,4 +42,7 @@ export class BigIntType extends Type {
42
42
  compareAsType() {
43
43
  return this.mode ?? 'bigint';
44
44
  }
45
+ compareValues(a, b) {
46
+ return String(a) === String(b);
47
+ }
45
48
  }