@mikro-orm/core 7.0.0-dev.113 → 7.0.0-dev.115

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 (61) hide show
  1. package/EntityManager.d.ts +8 -8
  2. package/EntityManager.js +47 -69
  3. package/MikroORM.d.ts +1 -1
  4. package/MikroORM.js +2 -3
  5. package/drivers/DatabaseDriver.d.ts +11 -11
  6. package/drivers/DatabaseDriver.js +8 -9
  7. package/drivers/IDatabaseDriver.d.ts +12 -12
  8. package/entity/Collection.js +7 -6
  9. package/entity/EntityAssigner.js +9 -9
  10. package/entity/EntityFactory.js +14 -17
  11. package/entity/EntityHelper.d.ts +2 -2
  12. package/entity/EntityHelper.js +2 -2
  13. package/entity/EntityLoader.d.ts +3 -3
  14. package/entity/EntityLoader.js +22 -35
  15. package/entity/WrappedEntity.js +1 -1
  16. package/entity/defineEntity.d.ts +11 -11
  17. package/entity/validators.js +2 -2
  18. package/errors.d.ts +8 -8
  19. package/errors.js +14 -13
  20. package/hydration/ObjectHydrator.js +25 -18
  21. package/metadata/EntitySchema.d.ts +5 -5
  22. package/metadata/EntitySchema.js +23 -21
  23. package/metadata/MetadataDiscovery.d.ts +2 -3
  24. package/metadata/MetadataDiscovery.js +119 -92
  25. package/metadata/MetadataProvider.js +2 -0
  26. package/metadata/MetadataStorage.d.ts +13 -6
  27. package/metadata/MetadataStorage.js +64 -19
  28. package/metadata/MetadataValidator.d.ts +2 -2
  29. package/metadata/MetadataValidator.js +22 -28
  30. package/metadata/types.d.ts +3 -3
  31. package/package.json +1 -1
  32. package/platforms/Platform.js +2 -2
  33. package/serialization/EntitySerializer.js +2 -2
  34. package/serialization/EntityTransformer.js +6 -6
  35. package/serialization/SerializationContext.d.ts +6 -6
  36. package/typings.d.ts +19 -17
  37. package/typings.js +15 -10
  38. package/unit-of-work/ChangeSet.d.ts +2 -3
  39. package/unit-of-work/ChangeSet.js +2 -3
  40. package/unit-of-work/ChangeSetComputer.js +3 -3
  41. package/unit-of-work/ChangeSetPersister.js +14 -14
  42. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  43. package/unit-of-work/CommitOrderCalculator.js +13 -13
  44. package/unit-of-work/UnitOfWork.d.ts +3 -3
  45. package/unit-of-work/UnitOfWork.js +46 -45
  46. package/utils/AbstractSchemaGenerator.js +7 -7
  47. package/utils/Configuration.d.ts +0 -5
  48. package/utils/Cursor.js +3 -3
  49. package/utils/DataloaderUtils.js +13 -11
  50. package/utils/EntityComparator.d.ts +6 -6
  51. package/utils/EntityComparator.js +30 -27
  52. package/utils/QueryHelper.d.ts +6 -6
  53. package/utils/QueryHelper.js +18 -17
  54. package/utils/RawQueryFragment.d.ts +11 -12
  55. package/utils/RawQueryFragment.js +28 -55
  56. package/utils/TransactionManager.js +1 -1
  57. package/utils/Utils.d.ts +3 -1
  58. package/utils/Utils.js +10 -2
  59. package/utils/clone.js +7 -21
  60. package/utils/env-vars.js +0 -1
  61. package/utils/upsert-utils.d.ts +4 -4
@@ -7,7 +7,7 @@ import { EntityLoader, type EntityLoaderOptions } from './entity/EntityLoader.js
7
7
  import { Reference } from './entity/Reference.js';
8
8
  import { UnitOfWork } from './unit-of-work/UnitOfWork.js';
9
9
  import type { CountOptions, DeleteOptions, FilterOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateOptions, StreamOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from './drivers/IDatabaseDriver.js';
10
- import type { AnyString, ArrayElement, AutoPath, ConnectionType, Dictionary, EntityData, EntityDictionary, EntityDTO, EntityMetadata, EntityName, FilterDef, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MergeLoaded, MergeSelected, NoInfer, ObjectQuery, Primary, Ref, RequiredEntityData, UnboxArray } from './typings.js';
10
+ import type { AnyString, ArrayElement, AutoPath, ConnectionType, Dictionary, EntityClass, EntityData, EntityDictionary, EntityDTO, EntityMetadata, EntityName, FilterDef, FilterQuery, FromEntityType, GetRepository, IHydrator, IsSubset, Loaded, MergeLoaded, MergeSelected, NoInfer, ObjectQuery, Primary, Ref, RequiredEntityData, UnboxArray } from './typings.js';
11
11
  import { FlushMode, LockMode, PopulatePath, type TransactionOptions } from './enums.js';
12
12
  import type { MetadataStorage } from './metadata/MetadataStorage.js';
13
13
  import type { Transaction } from './connections/Connection.js';
@@ -99,7 +99,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
99
99
  /**
100
100
  * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
101
101
  */
102
- addFilter<T extends EntityName<any> | readonly EntityName<any>[]>(options: FilterDef<T>): void;
102
+ addFilter<T extends EntityName | readonly EntityName[]>(options: FilterDef<T>): void;
103
103
  /**
104
104
  * Sets filter parameter values globally inside context defined by this entity manager.
105
105
  * If you want to set shared value for all contexts, be sure to use the root entity manager.
@@ -120,21 +120,21 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
120
120
  disableContextResolution?: boolean;
121
121
  }): T;
122
122
  setFlushMode(flushMode?: FlushMode | `${FlushMode}`): void;
123
- protected processWhere<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entityName: string, where: FilterQuery<Entity>, options: FindOptions<Entity, Hint, Fields, Excludes> | FindOneOptions<Entity, Hint, Fields, Excludes>, type: 'read' | 'update' | 'delete'): Promise<FilterQuery<Entity>>;
124
- protected applyDiscriminatorCondition<Entity extends object>(entityName: string, where: FilterQuery<Entity>): FilterQuery<Entity>;
123
+ protected processWhere<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<Entity>, options: FindOptions<Entity, Hint, Fields, Excludes> | FindOneOptions<Entity, Hint, Fields, Excludes>, type: 'read' | 'update' | 'delete'): Promise<FilterQuery<Entity>>;
124
+ protected applyDiscriminatorCondition<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity>): FilterQuery<Entity>;
125
125
  protected createPopulateWhere<Entity extends object>(cond: ObjectQuery<Entity>, options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any> | CountOptions<Entity, any>): ObjectQuery<Entity>;
126
126
  protected getJoinedFilters<Entity extends object>(meta: EntityMetadata<Entity>, options: FindOptions<Entity, any, any, any> | FindOneOptions<Entity, any, any, any>): Promise<ObjectQuery<Entity> | undefined>;
127
127
  /**
128
128
  * When filters are active on M:1 or 1:1 relations, we need to ref join them eagerly as they might affect the FK value.
129
129
  */
130
130
  protected autoJoinRefsForFilters<T extends object>(meta: EntityMetadata<T>, options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, parent?: {
131
- className: string;
131
+ class: EntityClass;
132
132
  propName: string;
133
133
  }): Promise<void>;
134
134
  /**
135
135
  * @internal
136
136
  */
137
- applyFilters<Entity extends object>(entityName: string, where: FilterQuery<Entity> | undefined, options: FilterOptions | undefined, type: 'read' | 'update' | 'delete', findOptions?: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any>): Promise<FilterQuery<Entity> | undefined>;
137
+ applyFilters<Entity extends object>(entityName: EntityName<Entity>, where: FilterQuery<Entity> | undefined, options: FilterOptions | undefined, type: 'read' | 'update' | 'delete', findOptions?: FindOptions<any, any, any, any> | FindOneOptions<any, any, any, any>): Promise<FilterQuery<Entity> | undefined>;
138
138
  /**
139
139
  * Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as tuple
140
140
  * where the first element is the array of entities, and the second is the count.
@@ -508,11 +508,11 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
508
508
  /**
509
509
  * @internal
510
510
  */
511
- cacheKey<T extends object>(entityName: string, options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any> | CountOptions<T, any>, method: string, where: FilterQuery<T>): unknown[];
511
+ cacheKey<T extends object>(entityName: EntityName<T>, options: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any> | CountOptions<T, any>, method: string, where: FilterQuery<T>): unknown[];
512
512
  /**
513
513
  * @internal
514
514
  */
515
- tryCache<T extends object, R>(entityName: string, config: boolean | number | [string, number] | undefined, key: unknown, refresh?: boolean, merge?: boolean): Promise<{
515
+ tryCache<T extends object, R>(entityName: EntityName<T>, config: boolean | number | [string, number] | undefined, key: unknown, refresh?: boolean, merge?: boolean): Promise<{
516
516
  data?: R | null;
517
517
  key: string;
518
518
  } | undefined>;
package/EntityManager.js CHANGED
@@ -4,7 +4,7 @@ import { Cursor } from './utils/Cursor.js';
4
4
  import { DataloaderUtils } from './utils/DataloaderUtils.js';
5
5
  import { QueryHelper } from './utils/QueryHelper.js';
6
6
  import { TransactionContext } from './utils/TransactionContext.js';
7
- import { isRaw, RawQueryFragment } from './utils/RawQueryFragment.js';
7
+ import { isRaw, Raw } from './utils/RawQueryFragment.js';
8
8
  import { EntityFactory } from './entity/EntityFactory.js';
9
9
  import { EntityAssigner } from './entity/EntityAssigner.js';
10
10
  import { validateEmptyWhere, validateParams, validatePrimaryKey, validateProperty } from './entity/validators.js';
@@ -35,7 +35,7 @@ export class EntityManager {
35
35
  global = false;
36
36
  name;
37
37
  loaders = {};
38
- repositoryMap = {};
38
+ repositoryMap = new Map();
39
39
  entityLoader;
40
40
  comparator;
41
41
  entityFactory;
@@ -88,13 +88,12 @@ export class EntityManager {
88
88
  * Gets repository for given entity. You can pass either string name or entity class reference.
89
89
  */
90
90
  getRepository(entityName) {
91
- entityName = Utils.className(entityName);
92
- if (!this.repositoryMap[entityName]) {
93
- const meta = this.metadata.get(entityName);
91
+ const meta = this.metadata.get(entityName);
92
+ if (!this.repositoryMap.has(meta)) {
94
93
  const RepositoryClass = this.config.getRepositoryClass(meta.repository);
95
- this.repositoryMap[entityName] = new RepositoryClass(this, entityName);
94
+ this.repositoryMap.set(meta, new RepositoryClass(this, entityName));
96
95
  }
97
- return this.repositoryMap[entityName];
96
+ return this.repositoryMap.get(meta);
98
97
  }
99
98
  /**
100
99
  * Shortcut for `em.getRepository()`.
@@ -116,7 +115,6 @@ export class EntityManager {
116
115
  const em = this.getContext();
117
116
  em.prepareOptions(options);
118
117
  await em.tryFlush(entityName, options);
119
- entityName = Utils.className(entityName);
120
118
  where = await em.processWhere(entityName, where, options, 'read');
121
119
  validateParams(where);
122
120
  options.orderBy = options.orderBy || {};
@@ -192,7 +190,6 @@ export class EntityManager {
192
190
  em.prepareOptions(options);
193
191
  options.strategy = 'joined';
194
192
  await em.tryFlush(entityName, options);
195
- entityName = Utils.className(entityName);
196
193
  const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
197
194
  validateParams(where);
198
195
  options.orderBy = options.orderBy || {};
@@ -303,15 +300,15 @@ export class EntityManager {
303
300
  if (!meta?.discriminatorValue) {
304
301
  return where;
305
302
  }
306
- const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.find(cls));
303
+ const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.get(cls));
307
304
  const children = [];
308
305
  const lookUpChildren = (ret, type) => {
309
306
  const children = types.filter(meta2 => meta2.extends === type);
310
- children.forEach(m => lookUpChildren(ret, m.className));
307
+ children.forEach(m => lookUpChildren(ret, m.class));
311
308
  ret.push(...children.filter(c => c.discriminatorValue));
312
309
  return children;
313
310
  };
314
- lookUpChildren(children, meta.className);
311
+ lookUpChildren(children, meta.class);
315
312
  /* v8 ignore next */
316
313
  where[meta.root.discriminatorColumn] = children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue;
317
314
  return where;
@@ -341,7 +338,7 @@ export class EntityManager {
341
338
  continue;
342
339
  }
343
340
  const filters = QueryHelper.mergePropertyFilters(prop.filters, options.filters);
344
- const where = await this.applyFilters(prop.type, {}, filters, 'read', {
341
+ const where = await this.applyFilters(prop.targetMeta.class, {}, filters, 'read', {
345
342
  ...options,
346
343
  populate: hint.children,
347
344
  });
@@ -377,11 +374,11 @@ export class EntityManager {
377
374
  if (prop.object
378
375
  || ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
379
376
  || !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
380
- || (parent?.className === prop.targetMeta.root.className && parent.propName === prop.inversedBy)) {
377
+ || (parent?.class === prop.targetMeta.root.class && parent.propName === prop.inversedBy)) {
381
378
  continue;
382
379
  }
383
380
  options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
384
- const cond = await this.applyFilters(prop.type, {}, options.filters, 'read', options);
381
+ const cond = await this.applyFilters(prop.targetMeta.class, {}, options.filters, 'read', options);
385
382
  if (!Utils.isEmpty(cond)) {
386
383
  const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
387
384
  let found = false;
@@ -404,7 +401,7 @@ export class EntityManager {
404
401
  const prop = meta?.properties[field];
405
402
  if (prop && !ref) {
406
403
  hint.children ??= [];
407
- await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { className: meta.root.className, propName: prop.name });
404
+ await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { class: meta.root.class, propName: prop.name });
408
405
  }
409
406
  }
410
407
  }
@@ -412,16 +409,13 @@ export class EntityManager {
412
409
  * @internal
413
410
  */
414
411
  async applyFilters(entityName, where, options, type, findOptions) {
415
- const meta = this.metadata.find(entityName);
412
+ const meta = this.metadata.get(entityName);
416
413
  const filters = [];
417
414
  const ret = [];
418
- if (!meta) {
419
- return where;
420
- }
421
415
  const active = new Set();
422
416
  const push = (source) => {
423
417
  const activeFilters = QueryHelper
424
- .getActiveFilters(entityName, options, source)
418
+ .getActiveFilters(meta, options, source)
425
419
  .filter(f => !active.has(f.name));
426
420
  filters.push(...activeFilters);
427
421
  activeFilters.forEach(f => active.add(f.name));
@@ -440,7 +434,7 @@ export class EntityManager {
440
434
  if (!args && filter.cond.length > 0 && filter.args !== false) {
441
435
  throw new Error(`No arguments provided for filter '${filter.name}'`);
442
436
  }
443
- cond = await filter.cond(args, type, this, findOptions, entityName);
437
+ cond = await filter.cond(args, type, this, findOptions, Utils.className(entityName));
444
438
  }
445
439
  else {
446
440
  cond = filter.cond;
@@ -457,7 +451,7 @@ export class EntityManager {
457
451
  }
458
452
  ret.push(cond);
459
453
  }
460
- const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
454
+ const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c) || Raw.hasObjectFragments(c));
461
455
  return conds.length > 1 ? { $and: conds } : conds[0];
462
456
  }
463
457
  /**
@@ -468,12 +462,10 @@ export class EntityManager {
468
462
  const em = this.getContext(false);
469
463
  await em.tryFlush(entityName, options);
470
464
  options.flushMode = 'commit'; // do not try to auto flush again
471
- return RawQueryFragment.run(async () => {
472
- return Promise.all([
473
- em.find(entityName, where, options),
474
- em.count(entityName, where, options),
475
- ]);
476
- });
465
+ return Promise.all([
466
+ em.find(entityName, where, options),
467
+ em.count(entityName, where, options),
468
+ ]);
477
469
  }
478
470
  /**
479
471
  * Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as {@apilink Cursor} object.
@@ -533,10 +525,9 @@ export class EntityManager {
533
525
  */
534
526
  async findByCursor(entityName, options) {
535
527
  const em = this.getContext(false);
536
- entityName = Utils.className(entityName);
537
528
  options.overfetch ??= true;
538
529
  options.where ??= {};
539
- if (Utils.isEmpty(options.orderBy)) {
530
+ if (Utils.isEmpty(options.orderBy) && !Raw.hasObjectFragments(options.orderBy)) {
540
531
  throw new Error('Explicit `orderBy` option required');
541
532
  }
542
533
  const [entities, count] = options.includeCount !== false
@@ -553,9 +544,9 @@ export class EntityManager {
553
544
  const ret = await this.refresh(entity, options);
554
545
  if (!ret) {
555
546
  options.failHandler ??= this.config.get('findOneOrFailHandler');
556
- const entityName = entity.constructor.name;
557
- const where = helper(entity).getPrimaryKey();
558
- throw options.failHandler(entityName, where);
547
+ const wrapped = helper(entity);
548
+ const where = wrapped.getPrimaryKey();
549
+ throw options.failHandler(wrapped.__meta.className, where);
559
550
  }
560
551
  return ret;
561
552
  }
@@ -566,9 +557,8 @@ export class EntityManager {
566
557
  */
567
558
  async refresh(entity, options = {}) {
568
559
  const fork = this.fork({ keepTransactionContext: true });
569
- const entityName = entity.constructor.name;
570
560
  const wrapped = helper(entity);
571
- const reloaded = await fork.findOne(entityName, entity, {
561
+ const reloaded = await fork.findOne(wrapped.__meta.class, entity, {
572
562
  schema: wrapped.__schema,
573
563
  ...options,
574
564
  flushMode: FlushMode.COMMIT,
@@ -580,7 +570,7 @@ export class EntityManager {
580
570
  }
581
571
  let found = false;
582
572
  for (const e of fork.unitOfWork.getIdentityMap()) {
583
- const ref = em.getReference(e.constructor.name, helper(e).getPrimaryKey());
573
+ const ref = em.getReference(e.constructor, helper(e).getPrimaryKey());
584
574
  const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true });
585
575
  em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, true);
586
576
  Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
@@ -605,7 +595,6 @@ export class EntityManager {
605
595
  return ret;
606
596
  }
607
597
  const em = this.getContext();
608
- entityName = Utils.className(entityName);
609
598
  em.prepareOptions(options);
610
599
  let entity = em.unitOfWork.tryGetById(entityName, where, options.schema);
611
600
  // query for a not managed entity which is already in the identity map as it
@@ -683,10 +672,10 @@ export class EntityManager {
683
672
  if (!entity || isStrictViolation) {
684
673
  const key = options.strict ? 'findExactlyOneOrFailHandler' : 'findOneOrFailHandler';
685
674
  options.failHandler ??= this.config.get(key);
686
- entityName = Utils.className(entityName);
675
+ const name = Utils.className(entityName);
687
676
  /* v8 ignore next */
688
677
  where = Utils.isEntity(where) ? helper(where).getPrimaryKey() : where;
689
- throw options.failHandler(entityName, where);
678
+ throw options.failHandler(name, where);
690
679
  }
691
680
  return entity;
692
681
  }
@@ -726,11 +715,11 @@ export class EntityManager {
726
715
  let where;
727
716
  let entity = null;
728
717
  if (data === undefined) {
729
- entityName = entityNameOrEntity.constructor.name;
718
+ entityName = entityNameOrEntity.constructor;
730
719
  data = entityNameOrEntity;
731
720
  }
732
721
  else {
733
- entityName = Utils.className(entityNameOrEntity);
722
+ entityName = entityNameOrEntity;
734
723
  }
735
724
  const meta = this.metadata.get(entityName);
736
725
  const convertCustomTypes = !Utils.isEntity(data);
@@ -793,7 +782,7 @@ export class EntityManager {
793
782
  where[meta.primaryKeys[0]] = ret.insertId;
794
783
  }
795
784
  }
796
- const data2 = await this.driver.findOne(meta.className, where, {
785
+ const data2 = await this.driver.findOne(meta.class, where, {
797
786
  fields: returning,
798
787
  ctx: em.transactionContext,
799
788
  convertCustomTypes: true,
@@ -848,11 +837,11 @@ export class EntityManager {
848
837
  let entityName;
849
838
  let propIndex;
850
839
  if (data === undefined) {
851
- entityName = entityNameOrEntity[0].constructor.name;
840
+ entityName = entityNameOrEntity[0].constructor;
852
841
  data = entityNameOrEntity;
853
842
  }
854
843
  else {
855
- entityName = Utils.className(entityNameOrEntity);
844
+ entityName = entityNameOrEntity;
856
845
  }
857
846
  const batchSize = options.batchSize ?? this.config.get('batchSize');
858
847
  if (data.length > batchSize) {
@@ -960,7 +949,7 @@ export class EntityManager {
960
949
  where.$or[idx][prop] = item[prop];
961
950
  });
962
951
  });
963
- const data2 = await this.driver.find(meta.className, where, {
952
+ const data2 = await this.driver.find(meta.class, where, {
964
953
  fields: returning.concat(...add).concat(...(Array.isArray(uniqueFields) ? uniqueFields : [])),
965
954
  ctx: em.transactionContext,
966
955
  convertCustomTypes: true,
@@ -1113,11 +1102,11 @@ export class EntityManager {
1113
1102
  em.prepareOptions(options);
1114
1103
  let entityName;
1115
1104
  if (data === undefined) {
1116
- entityName = entityNameOrEntity.constructor.name;
1105
+ entityName = entityNameOrEntity.constructor;
1117
1106
  data = entityNameOrEntity;
1118
1107
  }
1119
1108
  else {
1120
- entityName = Utils.className(entityNameOrEntity);
1109
+ entityName = entityNameOrEntity;
1121
1110
  }
1122
1111
  if (Utils.isEntity(data)) {
1123
1112
  if (options.schema && helper(data).getSchema() == null) {
@@ -1148,11 +1137,11 @@ export class EntityManager {
1148
1137
  em.prepareOptions(options);
1149
1138
  let entityName;
1150
1139
  if (data === undefined) {
1151
- entityName = entityNameOrEntities[0].constructor.name;
1140
+ entityName = entityNameOrEntities[0].constructor;
1152
1141
  data = entityNameOrEntities;
1153
1142
  }
1154
1143
  else {
1155
- entityName = Utils.className(entityNameOrEntities);
1144
+ entityName = entityNameOrEntities;
1156
1145
  }
1157
1146
  if (data.length === 0) {
1158
1147
  return [];
@@ -1189,7 +1178,6 @@ export class EntityManager {
1189
1178
  async nativeUpdate(entityName, where, data, options = {}) {
1190
1179
  const em = this.getContext(false);
1191
1180
  em.prepareOptions(options);
1192
- entityName = Utils.className(entityName);
1193
1181
  data = QueryHelper.processObjectParams(data);
1194
1182
  where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
1195
1183
  validateParams(data, 'update data');
@@ -1203,7 +1191,6 @@ export class EntityManager {
1203
1191
  async nativeDelete(entityName, where, options = {}) {
1204
1192
  const em = this.getContext(false);
1205
1193
  em.prepareOptions(options);
1206
- entityName = Utils.className(entityName);
1207
1194
  where = await em.processWhere(entityName, where, options, 'delete');
1208
1195
  validateParams(where, 'delete condition');
1209
1196
  const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
@@ -1213,7 +1200,6 @@ export class EntityManager {
1213
1200
  * Maps raw database result to an entity and merges it to this EntityManager.
1214
1201
  */
1215
1202
  map(entityName, result, options = {}) {
1216
- entityName = Utils.className(entityName);
1217
1203
  const meta = this.metadata.get(entityName);
1218
1204
  const data = this.driver.mapResult(result, meta);
1219
1205
  for (const k of Object.keys(data)) {
@@ -1235,13 +1221,12 @@ export class EntityManager {
1235
1221
  */
1236
1222
  merge(entityName, data, options = {}) {
1237
1223
  if (Utils.isEntity(entityName)) {
1238
- return this.merge(entityName.constructor.name, entityName, data);
1224
+ return this.merge(entityName.constructor, entityName, data);
1239
1225
  }
1240
1226
  const em = options.disableContextResolution ? this : this.getContext();
1241
1227
  options.schema ??= em._schema;
1242
1228
  options.validate ??= true;
1243
1229
  options.cascade ??= true;
1244
- entityName = Utils.className(entityName);
1245
1230
  validatePrimaryKey(data, em.metadata.get(entityName));
1246
1231
  let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
1247
1232
  if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
@@ -1295,7 +1280,7 @@ export class EntityManager {
1295
1280
  getReference(entityName, id, options = {}) {
1296
1281
  options.schema ??= this.schema;
1297
1282
  options.convertCustomTypes ??= false;
1298
- const meta = this.metadata.get(Utils.className(entityName));
1283
+ const meta = this.metadata.get(entityName);
1299
1284
  if (Utils.isPrimaryKey(id)) {
1300
1285
  if (meta.compositePK) {
1301
1286
  throw ValidationError.invalidCompositeIdentifier(meta);
@@ -1316,7 +1301,6 @@ export class EntityManager {
1316
1301
  // Shallow copy options since the object will be modified when deleting orderBy
1317
1302
  options = { ...options };
1318
1303
  em.prepareOptions(options);
1319
- entityName = Utils.className(entityName);
1320
1304
  await em.tryFlush(entityName, options);
1321
1305
  where = await em.processWhere(entityName, where, options, 'read');
1322
1306
  options.populate = await em.preparePopulate(entityName, options);
@@ -1352,7 +1336,7 @@ export class EntityManager {
1352
1336
  for (const ent of entities) {
1353
1337
  if (!Utils.isEntity(ent, true)) {
1354
1338
  /* v8 ignore next */
1355
- const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor.name) : undefined;
1339
+ const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor) : undefined;
1356
1340
  throw ValidationError.notDiscoveredEntity(ent, meta);
1357
1341
  }
1358
1342
  // do not cascade just yet, cascading of entities in persist stack is done when flushing
@@ -1396,7 +1380,6 @@ export class EntityManager {
1396
1380
  async tryFlush(entityName, options) {
1397
1381
  const em = this.getContext();
1398
1382
  const flushMode = options.flushMode ?? em.flushMode ?? em.config.get('flushMode');
1399
- entityName = Utils.className(entityName);
1400
1383
  const meta = em.metadata.get(entityName);
1401
1384
  if (flushMode === FlushMode.COMMIT) {
1402
1385
  return;
@@ -1415,7 +1398,6 @@ export class EntityManager {
1415
1398
  * Checks whether given property can be populated on the entity.
1416
1399
  */
1417
1400
  canPopulate(entityName, property) {
1418
- entityName = Utils.className(entityName);
1419
1401
  // eslint-disable-next-line prefer-const
1420
1402
  let [p, ...parts] = property.split('.');
1421
1403
  const meta = this.metadata.find(entityName);
@@ -1426,11 +1408,8 @@ export class EntityManager {
1426
1408
  p = p.split(':', 2)[0];
1427
1409
  }
1428
1410
  const ret = p in meta.root.properties;
1429
- if (!ret) {
1430
- return !!this.metadata.find(property)?.pivotTable;
1431
- }
1432
1411
  if (parts.length > 0) {
1433
- return this.canPopulate((meta.root.properties)[p].type, parts.join('.'));
1412
+ return this.canPopulate(meta.root.properties[p].targetMeta.class, parts.join('.'));
1434
1413
  }
1435
1414
  return ret;
1436
1415
  }
@@ -1444,7 +1423,7 @@ export class EntityManager {
1444
1423
  }
1445
1424
  const em = this.getContext();
1446
1425
  em.prepareOptions(options);
1447
- const entityName = arr[0].constructor.name;
1426
+ const entityName = arr[0].constructor;
1448
1427
  const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
1449
1428
  await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
1450
1429
  return entities;
@@ -1573,7 +1552,6 @@ export class EntityManager {
1573
1552
  */
1574
1553
  getMetadata(entityName) {
1575
1554
  if (entityName) {
1576
- entityName = Utils.className(entityName);
1577
1555
  return this.metadata.get(entityName);
1578
1556
  }
1579
1557
  return this.metadata;
@@ -1602,8 +1580,8 @@ export class EntityManager {
1602
1580
  lockTableAliases: options.lockTableAliases,
1603
1581
  });
1604
1582
  }
1605
- const preparedPopulate = await this.preparePopulate(meta.className, options);
1606
- await this.entityLoader.populate(meta.className, [entity], preparedPopulate, {
1583
+ const preparedPopulate = await this.preparePopulate(meta.class, options);
1584
+ await this.entityLoader.populate(meta.class, [entity], preparedPopulate, {
1607
1585
  ...options,
1608
1586
  ...this.getPopulateWhere(where, options),
1609
1587
  orderBy: options.populateOrderBy ?? options.orderBy,
@@ -1740,7 +1718,7 @@ export class EntityManager {
1740
1718
  for (const k of ['ctx', 'strategy', 'flushMode', 'logging', 'loggerContext']) {
1741
1719
  delete opts[k];
1742
1720
  }
1743
- return [entityName, method, opts, where];
1721
+ return [Utils.className(entityName), method, opts, where];
1744
1722
  }
1745
1723
  /**
1746
1724
  * @internal
package/MikroORM.d.ts CHANGED
@@ -94,7 +94,7 @@ export declare class MikroORM<Driver extends IDatabaseDriver = IDatabaseDriver,
94
94
  /**
95
95
  * Allows dynamically discovering new entity by reference, handy for testing schema diffing.
96
96
  */
97
- discoverEntity<T extends Constructor | EntitySchema>(entities: T | T[], reset?: string | string[]): void;
97
+ discoverEntity<T extends Constructor | EntitySchema>(entities: T | T[], reset?: EntityName | EntityName[]): void;
98
98
  /**
99
99
  * Gets the SchemaGenerator.
100
100
  */
package/MikroORM.js CHANGED
@@ -158,7 +158,6 @@ export class MikroORM {
158
158
  */
159
159
  getMetadata(entityName) {
160
160
  if (entityName) {
161
- entityName = Utils.className(entityName);
162
161
  return this.metadata.get(entityName);
163
162
  }
164
163
  return this.metadata;
@@ -181,8 +180,8 @@ export class MikroORM {
181
180
  const tmp = this.discovery.discoverReferences(Utils.asArray(entities));
182
181
  const metadata = this.discovery.processDiscoveredEntities(tmp);
183
182
  for (const meta of metadata) {
184
- this.metadata.set(meta.className, meta);
185
- meta.root = this.metadata.get(meta.root.className);
183
+ this.metadata.set(meta.class, meta);
184
+ meta.root = this.metadata.get(meta.root.class);
186
185
  }
187
186
  this.metadata.decorate(this.em);
188
187
  }
@@ -22,18 +22,18 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
22
22
  protected comparator: EntityComparator;
23
23
  protected metadata: MetadataStorage;
24
24
  protected constructor(config: Configuration, dependencies: string[]);
25
- abstract find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
26
- abstract findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: string, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
27
- abstract nativeInsert<T extends object>(entityName: string, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
28
- abstract nativeInsertMany<T extends object>(entityName: string, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
29
- abstract nativeUpdate<T extends object>(entityName: string, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
30
- nativeUpdateMany<T extends object>(entityName: string, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
31
- abstract nativeDelete<T extends object>(entityName: string, where: FilterQuery<T>, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
32
- abstract count<T extends object, P extends string = never>(entityName: string, where: FilterQuery<T>, options?: CountOptions<T, P>): Promise<number>;
25
+ abstract find<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: FindOptions<T, P, F, E>): Promise<EntityData<T>[]>;
26
+ abstract findOne<T extends object, P extends string = never, F extends string = '*', E extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: FindOneOptions<T, P, F, E>): Promise<EntityData<T> | null>;
27
+ abstract nativeInsert<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
28
+ abstract nativeInsertMany<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
29
+ abstract nativeUpdate<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
30
+ nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
31
+ abstract nativeDelete<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
32
+ abstract count<T extends object, P extends string = never>(entityName: EntityName<T>, where: FilterQuery<T>, options?: CountOptions<T, P>): Promise<number>;
33
33
  createEntityManager(useContext?: boolean): this[typeof EntityManagerType];
34
34
  findVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: FindOptions<T, any, any, any>): Promise<EntityData<T>[]>;
35
- countVirtual<T extends object>(entityName: string, where: FilterQuery<T>, options: CountOptions<T, any>): Promise<number>;
36
- aggregate(entityName: string, pipeline: any[]): Promise<any[]>;
35
+ countVirtual<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: CountOptions<T, any>): Promise<number>;
36
+ aggregate(entityName: EntityName, pipeline: any[]): Promise<any[]>;
37
37
  loadFromPivotTable<T extends object, O extends object>(prop: EntityProperty, owners: Primary<O>[][], where?: FilterQuery<any>, orderBy?: OrderDefinition<T>, ctx?: Transaction, options?: FindOptions<T, any, any, any>, pivotJoin?: boolean): Promise<Dictionary<T[]>>;
38
38
  syncCollections<T extends object, O extends object>(collections: Iterable<Collection<T, O>>, options?: DriverMethodOptions): Promise<void>;
39
39
  mapResult<T extends object>(result: EntityDictionary<T>, meta?: EntityMetadata<T>, populate?: PopulateOptions<T>[]): EntityData<T> | null;
@@ -58,7 +58,7 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
58
58
  /** @internal */
59
59
  mapDataToFieldNames(data: Dictionary, stringifyJsonArrays: boolean, properties?: Record<string, EntityProperty>, convertCustomTypes?: boolean, object?: boolean): Dictionary;
60
60
  protected inlineEmbeddables<T extends object>(meta: EntityMetadata<T>, data: T, where?: boolean): void;
61
- protected getPrimaryKeyFields(entityName: string): string[];
61
+ protected getPrimaryKeyFields<T>(meta: EntityMetadata<T>): string[];
62
62
  protected createReplicas(cb: (c: ConnectionOptions) => C): C[];
63
63
  lockPessimistic<T extends object>(entity: T, options: LockOptions): Promise<void>;
64
64
  abstract stream<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, options: StreamOptions<T>): AsyncIterableIterator<T>;
@@ -59,7 +59,7 @@ export class DatabaseDriver {
59
59
  {
60
60
  const pk = coll.property.targetMeta.primaryKeys[0];
61
61
  const data = { [coll.property.name]: coll.getIdentifiers(pk) };
62
- await this.nativeUpdate(coll.owner.constructor.name, helper(coll.owner).getPrimaryKey(), data, options);
62
+ await this.nativeUpdate(coll.owner.constructor, helper(coll.owner).getPrimaryKey(), data, options);
63
63
  }
64
64
  }
65
65
  }
@@ -67,7 +67,7 @@ export class DatabaseDriver {
67
67
  if (!result || !meta) {
68
68
  return result ?? null;
69
69
  }
70
- return this.comparator.mapResult(meta.className, result);
70
+ return this.comparator.mapResult(meta, result);
71
71
  }
72
72
  async connect(options) {
73
73
  await this.connection.connect(options);
@@ -152,7 +152,7 @@ export class DatabaseDriver {
152
152
  }
153
153
  const createOrderBy = (prop, direction) => {
154
154
  if (Utils.isPlainObject(direction)) {
155
- const value = Utils.keys(direction).reduce((o, key) => {
155
+ const value = Utils.getObjectQueryKeys(direction).reduce((o, key) => {
156
156
  Object.assign(o, createOrderBy(key, direction[key]));
157
157
  return o;
158
158
  }, {});
@@ -277,14 +277,14 @@ export class DatabaseDriver {
277
277
  // explicitly allow `$exists`, `$eq` and `$ne` operators here as they can't be misused this way
278
278
  const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f) && !['$exists', '$ne', '$eq'].includes(f));
279
279
  if (operator) {
280
- throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.className, prop.name, data);
280
+ throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.class, prop.name, data);
281
281
  }
282
282
  if (prop.object && where) {
283
283
  const inline = (payload, sub, path) => {
284
284
  if (sub.kind === ReferenceKind.EMBEDDED && Utils.isObject(payload[sub.embedded[1]])) {
285
285
  return Object.keys(payload[sub.embedded[1]]).forEach(kkk => {
286
286
  if (!sub.embeddedProps[kkk]) {
287
- throw ValidationError.invalidEmbeddableQuery(meta.className, kkk, sub.type);
287
+ throw ValidationError.invalidEmbeddableQuery(meta.class, kkk, sub.type);
288
288
  }
289
289
  inline(payload[sub.embedded[1]], sub.embeddedProps[kkk], [...path, sub.embedded[1]]);
290
290
  });
@@ -308,7 +308,7 @@ export class DatabaseDriver {
308
308
  data[props[kk].name] = data[prop.name][props[kk].embedded[1]];
309
309
  }
310
310
  else {
311
- throw ValidationError.invalidEmbeddableQuery(meta.className, kk, prop.type);
311
+ throw ValidationError.invalidEmbeddableQuery(meta.class, kk, prop.type);
312
312
  }
313
313
  });
314
314
  if (!unknownProp) {
@@ -317,9 +317,8 @@ export class DatabaseDriver {
317
317
  }
318
318
  });
319
319
  }
320
- getPrimaryKeyFields(entityName) {
321
- const meta = this.metadata.find(entityName);
322
- return meta ? Utils.flatten(meta.getPrimaryProps().map(pk => pk.fieldNames)) : [this.config.getNamingStrategy().referenceColumnName()];
320
+ getPrimaryKeyFields(meta) {
321
+ return meta.getPrimaryProps().flatMap(pk => pk.fieldNames);
323
322
  }
324
323
  createReplicas(cb) {
325
324
  const replicas = this.config.get('replicas', []);