@mikro-orm/core 7.0.0-dev.114 → 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 (54) hide show
  1. package/EntityManager.d.ts +8 -8
  2. package/EntityManager.js +40 -60
  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 +7 -8
  7. package/drivers/IDatabaseDriver.d.ts +10 -10
  8. package/entity/Collection.js +5 -5
  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 +17 -16
  15. package/entity/WrappedEntity.js +1 -1
  16. package/entity/defineEntity.d.ts +11 -11
  17. package/errors.d.ts +8 -8
  18. package/errors.js +14 -13
  19. package/hydration/ObjectHydrator.js +23 -16
  20. package/metadata/EntitySchema.d.ts +5 -5
  21. package/metadata/EntitySchema.js +23 -21
  22. package/metadata/MetadataDiscovery.d.ts +2 -3
  23. package/metadata/MetadataDiscovery.js +117 -90
  24. package/metadata/MetadataProvider.js +2 -0
  25. package/metadata/MetadataStorage.d.ts +13 -6
  26. package/metadata/MetadataStorage.js +64 -19
  27. package/metadata/MetadataValidator.d.ts +2 -2
  28. package/metadata/MetadataValidator.js +22 -28
  29. package/metadata/types.d.ts +3 -3
  30. package/package.json +1 -1
  31. package/serialization/EntitySerializer.js +2 -2
  32. package/serialization/EntityTransformer.js +6 -6
  33. package/serialization/SerializationContext.d.ts +6 -6
  34. package/typings.d.ts +16 -14
  35. package/typings.js +15 -10
  36. package/unit-of-work/ChangeSet.d.ts +2 -3
  37. package/unit-of-work/ChangeSet.js +2 -3
  38. package/unit-of-work/ChangeSetComputer.js +3 -3
  39. package/unit-of-work/ChangeSetPersister.js +14 -14
  40. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  41. package/unit-of-work/CommitOrderCalculator.js +13 -13
  42. package/unit-of-work/UnitOfWork.d.ts +3 -3
  43. package/unit-of-work/UnitOfWork.js +46 -45
  44. package/utils/AbstractSchemaGenerator.js +7 -7
  45. package/utils/Configuration.d.ts +0 -5
  46. package/utils/DataloaderUtils.js +13 -11
  47. package/utils/EntityComparator.d.ts +6 -6
  48. package/utils/EntityComparator.js +22 -24
  49. package/utils/QueryHelper.d.ts +5 -5
  50. package/utils/QueryHelper.js +7 -7
  51. package/utils/TransactionManager.js +1 -1
  52. package/utils/Utils.d.ts +1 -1
  53. package/utils/Utils.js +1 -2
  54. package/utils/env-vars.js +0 -1
@@ -30,7 +30,7 @@ export class ChangeSetPersister {
30
30
  if (!withSchema) {
31
31
  return this.runForEachSchema(changeSets, 'executeInserts', options);
32
32
  }
33
- const meta = this.metadata.find(changeSets[0].name);
33
+ const meta = changeSets[0].meta;
34
34
  changeSets.forEach(changeSet => this.processProperties(changeSet));
35
35
  if (changeSets.length > 1 && this.config.get('useBatchInserts', this.platform.usesBatchInserts())) {
36
36
  return this.persistNewEntities(meta, changeSets, options);
@@ -43,7 +43,7 @@ export class ChangeSetPersister {
43
43
  if (!withSchema) {
44
44
  return this.runForEachSchema(changeSets, 'executeUpdates', options, batched);
45
45
  }
46
- const meta = this.metadata.find(changeSets[0].name);
46
+ const meta = changeSets[0].meta;
47
47
  changeSets.forEach(changeSet => this.processProperties(changeSet));
48
48
  if (batched && changeSets.length > 1 && this.config.get('useBatchUpdates', this.platform.usesBatchUpdates())) {
49
49
  return this.persistManagedEntities(meta, changeSets, options);
@@ -63,7 +63,7 @@ export class ChangeSetPersister {
63
63
  const chunk = changeSets.slice(i, i + size);
64
64
  const pks = chunk.map(cs => cs.getPrimaryKey());
65
65
  options = this.prepareOptions(meta, options);
66
- await this.driver.nativeDelete(meta.root.className, { [pk]: { $in: pks } }, options);
66
+ await this.driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
67
67
  }
68
68
  }
69
69
  async runForEachSchema(changeSets, method, options, ...args) {
@@ -99,7 +99,7 @@ export class ChangeSetPersister {
99
99
  }
100
100
  }
101
101
  processProperties(changeSet) {
102
- const meta = this.metadata.find(changeSet.name);
102
+ const meta = changeSet.meta;
103
103
  for (const prop of meta.relations) {
104
104
  this.processProperty(changeSet, prop);
105
105
  }
@@ -112,7 +112,7 @@ export class ChangeSetPersister {
112
112
  options = this.prepareOptions(meta, options, {
113
113
  convertCustomTypes: false,
114
114
  });
115
- const res = await this.driver.nativeInsertMany(meta.className, [changeSet.payload], options);
115
+ const res = await this.driver.nativeInsertMany(meta.class, [changeSet.payload], options);
116
116
  if (!wrapped.hasPrimaryKey()) {
117
117
  this.mapPrimaryKey(meta, res.insertId, changeSet);
118
118
  }
@@ -149,7 +149,7 @@ export class ChangeSetPersister {
149
149
  convertCustomTypes: false,
150
150
  processCollections: false,
151
151
  });
152
- const res = await this.driver.nativeInsertMany(meta.className, changeSets.map(cs => cs.payload), options);
152
+ const res = await this.driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
153
153
  for (let i = 0; i < changeSets.length; i++) {
154
154
  const changeSet = changeSets[i];
155
155
  const wrapped = helper(changeSet.entity);
@@ -167,7 +167,7 @@ export class ChangeSetPersister {
167
167
  }
168
168
  }
169
169
  async persistManagedEntity(changeSet, options) {
170
- const meta = this.metadata.find(changeSet.name);
170
+ const meta = changeSet.meta;
171
171
  const res = await this.updateEntity(meta, changeSet, options);
172
172
  this.checkOptimisticLock(meta, changeSet, res);
173
173
  this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
@@ -208,7 +208,7 @@ export class ChangeSetPersister {
208
208
  cond.push(where);
209
209
  payload.push(changeSet.payload);
210
210
  }
211
- const res = await this.driver.nativeUpdateMany(meta.className, cond, payload, options);
211
+ const res = await this.driver.nativeUpdateMany(meta.class, cond, payload, options);
212
212
  const map = new Map();
213
213
  res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
214
214
  for (const changeSet of changeSets) {
@@ -260,13 +260,13 @@ export class ChangeSetPersister {
260
260
  convertCustomTypes: false,
261
261
  });
262
262
  if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
263
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
263
+ return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
264
264
  }
265
265
  if (meta.versionProperty) {
266
266
  cond[meta.versionProperty] = this.platform.quoteVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
267
267
  }
268
268
  this.checkConcurrencyKeys(meta, changeSet, cond);
269
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
269
+ return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
270
270
  }
271
271
  async checkOptimisticLocks(meta, changeSets, options) {
272
272
  if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
@@ -286,7 +286,7 @@ export class ChangeSetPersister {
286
286
  options = this.prepareOptions(meta, options, {
287
287
  fields: primaryKeys,
288
288
  });
289
- const res = await this.driver.find(meta.root.className, { $or }, options);
289
+ const res = await this.driver.find(meta.root.class, { $or }, options);
290
290
  if (res.length !== changeSets.length) {
291
291
  const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
292
292
  const entity = changeSets.find(cs => {
@@ -356,7 +356,7 @@ export class ChangeSetPersister {
356
356
  options = this.prepareOptions(meta, options, {
357
357
  fields: Utils.unique(reloadProps.map(prop => prop.name)),
358
358
  });
359
- const data = await this.driver.find(meta.className, { [pk]: { $in: pks } }, options);
359
+ const data = await this.driver.find(meta.class, { [pk]: { $in: pks } }, options);
360
360
  const map = new Map();
361
361
  data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
362
362
  for (const changeSet of changeSets) {
@@ -366,7 +366,7 @@ export class ChangeSetPersister {
366
366
  }
367
367
  }
368
368
  processProperty(changeSet, prop) {
369
- const meta = this.metadata.find(changeSet.name);
369
+ const meta = changeSet.meta;
370
370
  const value = changeSet.payload[prop.name]; // for inline embeddables
371
371
  if (value instanceof EntityIdentifier) {
372
372
  changeSet.payload[prop.name] = value.getValue();
@@ -399,7 +399,7 @@ export class ChangeSetPersister {
399
399
  if ((!this.usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
400
400
  return;
401
401
  }
402
- const mapped = this.comparator.mapResult(meta.className, row);
402
+ const mapped = this.comparator.mapResult(meta, row);
403
403
  if (entity) {
404
404
  this.hydrator.hydrate(entity, meta, mapped, this.factory, 'full', false, true);
405
405
  }
@@ -1,17 +1,18 @@
1
- import type { Dictionary, EntityProperty } from '../typings.js';
1
+ import type { EntityProperty } from '../typings.js';
2
2
  export declare const enum NodeState {
3
3
  NOT_VISITED = 0,
4
4
  IN_PROGRESS = 1,
5
5
  VISITED = 2
6
6
  }
7
+ type Hash = number;
7
8
  export interface Node {
8
- hash: string;
9
+ hash: Hash;
9
10
  state: NodeState;
10
- dependencies: Dictionary<Edge>;
11
+ dependencies: Map<Hash, Edge>;
11
12
  }
12
13
  export interface Edge {
13
- from: string;
14
- to: string;
14
+ from: Hash;
15
+ to: Hash;
15
16
  weight: number;
16
17
  }
17
18
  /**
@@ -32,23 +33,23 @@ export declare class CommitOrderCalculator {
32
33
  /**
33
34
  * Checks for node existence in graph.
34
35
  */
35
- hasNode(hash: string): boolean;
36
+ hasNode(hash: Hash): boolean;
36
37
  /**
37
38
  * Adds a new node to the graph, assigning its hash.
38
39
  */
39
- addNode(hash: string): void;
40
+ addNode(hash: Hash): void;
40
41
  /**
41
42
  * Adds a new dependency (edge) to the graph using their hashes.
42
43
  */
43
- addDependency(from: string, to: string, weight: number): void;
44
- discoverProperty(prop: EntityProperty, entityName: string): void;
44
+ addDependency(from: Hash, to: Hash, weight: number): void;
45
+ discoverProperty(prop: EntityProperty, entityName: Hash): void;
45
46
  /**
46
47
  * Return a valid order list of all current nodes.
47
48
  * The desired topological sorting is the reverse post order of these searches.
48
49
  *
49
50
  * @internal Highly performance-sensitive method.
50
51
  */
51
- sort(): string[];
52
+ sort(): Hash[];
52
53
  /**
53
54
  * Visit a given node definition for reordering.
54
55
  *
@@ -60,3 +61,4 @@ export declare class CommitOrderCalculator {
60
61
  */
61
62
  private visitOpenNode;
62
63
  }
64
+ export {};
@@ -17,26 +17,26 @@ export var NodeState;
17
17
  */
18
18
  export class CommitOrderCalculator {
19
19
  /** Matrix of nodes, keys are provided hashes and values are the node definition objects. */
20
- nodes = {};
20
+ nodes = new Map();
21
21
  /** Volatile variable holding calculated nodes during sorting process. */
22
22
  sortedNodeList = [];
23
23
  /**
24
24
  * Checks for node existence in graph.
25
25
  */
26
26
  hasNode(hash) {
27
- return hash in this.nodes;
27
+ return this.nodes.has(hash);
28
28
  }
29
29
  /**
30
30
  * Adds a new node to the graph, assigning its hash.
31
31
  */
32
32
  addNode(hash) {
33
- this.nodes[hash] = { hash, state: 0 /* NodeState.NOT_VISITED */, dependencies: {} };
33
+ this.nodes.set(hash, { hash, state: 0 /* NodeState.NOT_VISITED */, dependencies: new Map() });
34
34
  }
35
35
  /**
36
36
  * Adds a new dependency (edge) to the graph using their hashes.
37
37
  */
38
38
  addDependency(from, to, weight) {
39
- this.nodes[from].dependencies[to] = { from, to, weight };
39
+ this.nodes.get(from).dependencies.set(to, { from, to, weight });
40
40
  }
41
41
  discoverProperty(prop, entityName) {
42
42
  const toOneOwner = (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner) || prop.kind === ReferenceKind.MANY_TO_ONE;
@@ -44,8 +44,8 @@ export class CommitOrderCalculator {
44
44
  if (!toOneOwner && !toManyOwner) {
45
45
  return;
46
46
  }
47
- const propertyType = prop.targetMeta?.root.className;
48
- if (!propertyType || !this.hasNode(propertyType)) {
47
+ const propertyType = prop.targetMeta?.root._id;
48
+ if (propertyType == null || !this.hasNode(propertyType)) {
49
49
  return;
50
50
  }
51
51
  this.addDependency(propertyType, entityName, prop.nullable || prop.persist === false ? 0 : 1);
@@ -57,14 +57,14 @@ export class CommitOrderCalculator {
57
57
  * @internal Highly performance-sensitive method.
58
58
  */
59
59
  sort() {
60
- for (const vertex of Object.values(this.nodes)) {
60
+ for (const vertex of this.nodes.values()) {
61
61
  if (vertex.state !== 0 /* NodeState.NOT_VISITED */) {
62
62
  continue;
63
63
  }
64
64
  this.visit(vertex);
65
65
  }
66
66
  const sortedList = this.sortedNodeList.reverse();
67
- this.nodes = {};
67
+ this.nodes = new Map();
68
68
  this.sortedNodeList = [];
69
69
  return sortedList;
70
70
  }
@@ -75,8 +75,8 @@ export class CommitOrderCalculator {
75
75
  */
76
76
  visit(node) {
77
77
  node.state = 1 /* NodeState.IN_PROGRESS */;
78
- for (const edge of Object.values(node.dependencies)) {
79
- const target = this.nodes[edge.to];
78
+ for (const edge of node.dependencies.values()) {
79
+ const target = this.nodes.get(edge.to);
80
80
  switch (target.state) {
81
81
  case 2 /* NodeState.VISITED */: break; // Do nothing, since node was already visited
82
82
  case 1 /* NodeState.IN_PROGRESS */:
@@ -94,11 +94,11 @@ export class CommitOrderCalculator {
94
94
  * Visits all target's dependencies if in cycle with given node
95
95
  */
96
96
  visitOpenNode(node, target, edge) {
97
- if (!target.dependencies[node.hash] || target.dependencies[node.hash].weight >= edge.weight) {
97
+ if (!target.dependencies.has(node.hash) || target.dependencies.get(node.hash).weight >= edge.weight) {
98
98
  return;
99
99
  }
100
- for (const edge of Object.values(target.dependencies)) {
101
- const targetNode = this.nodes[edge.to];
100
+ for (const edge of target.dependencies.values()) {
101
+ const targetNode = this.nodes.get(edge.to);
102
102
  if (targetNode.state === 0 /* NodeState.NOT_VISITED */) {
103
103
  this.visit(targetNode);
104
104
  }
@@ -1,4 +1,4 @@
1
- import type { AnyEntity, EntityData, EntityMetadata, EntityProperty, FilterQuery, Primary } from '../typings.js';
1
+ import type { AnyEntity, EntityData, EntityMetadata, EntityName, EntityProperty, FilterQuery, Primary } from '../typings.js';
2
2
  import { Collection } from '../entity/Collection.js';
3
3
  import { Reference } from '../entity/Reference.js';
4
4
  import { ChangeSet, ChangeSetType } from './ChangeSet.js';
@@ -45,8 +45,8 @@ export declare class UnitOfWork {
45
45
  /**
46
46
  * Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
47
47
  */
48
- getById<T extends object>(entityName: string, id: Primary<T> | Primary<T>[], schema?: string, convertCustomTypes?: boolean): T | undefined;
49
- tryGetById<T extends object>(entityName: string, where: FilterQuery<T>, schema?: string, strict?: boolean): T | null;
48
+ getById<T extends object>(entityName: EntityName<T>, id: Primary<T> | Primary<T>[], schema?: string, convertCustomTypes?: boolean): T | undefined;
49
+ tryGetById<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, schema?: string, strict?: boolean): T | null;
50
50
  /**
51
51
  * Returns map of all managed entities.
52
52
  */
@@ -207,7 +207,7 @@ export class UnitOfWork {
207
207
  if (insideFlush.getStore()) {
208
208
  return false;
209
209
  }
210
- if (this.queuedActions.has(meta.className) || this.queuedActions.has(meta.root.className)) {
210
+ if (this.queuedActions.has(meta.class) || this.queuedActions.has(meta.root.class)) {
211
211
  return true;
212
212
  }
213
213
  if (meta.discriminatorMap && Object.values(meta.discriminatorMap).some(v => this.queuedActions.has(v))) {
@@ -251,7 +251,7 @@ export class UnitOfWork {
251
251
  }
252
252
  const wrapped = helper(entity);
253
253
  this.persistStack.add(entity);
254
- this.queuedActions.add(wrapped.__meta.className);
254
+ this.queuedActions.add(wrapped.__meta.class);
255
255
  this.removeStack.delete(entity);
256
256
  if (!wrapped.__managed && wrapped.hasPrimaryKey()) {
257
257
  this.identityMap.store(entity);
@@ -264,7 +264,7 @@ export class UnitOfWork {
264
264
  // allow removing not managed entities if they are not part of the persist stack
265
265
  if (helper(entity).__managed || !this.persistStack.has(entity)) {
266
266
  this.removeStack.add(entity);
267
- this.queuedActions.add(helper(entity).__meta.className);
267
+ this.queuedActions.add(helper(entity).__meta.class);
268
268
  }
269
269
  else {
270
270
  this.persistStack.delete(entity);
@@ -355,10 +355,10 @@ export class UnitOfWork {
355
355
  }
356
356
  }
357
357
  async lock(entity, options) {
358
- if (!this.getById(entity.constructor.name, helper(entity).__primaryKeys, helper(entity).__schema)) {
358
+ if (!this.getById(entity.constructor, helper(entity).__primaryKeys, helper(entity).__schema)) {
359
359
  throw ValidationError.entityNotManaged(entity);
360
360
  }
361
- const meta = this.metadata.find(entity.constructor.name);
361
+ const meta = this.metadata.find(entity.constructor);
362
362
  if (options.lockMode === LockMode.OPTIMISTIC) {
363
363
  await this.lockOptimistic(entity, meta, options.lockVersion);
364
364
  }
@@ -382,7 +382,7 @@ export class UnitOfWork {
382
382
  if (Utils.isCollection(rel)) {
383
383
  rel.removeWithoutPropagation(entity);
384
384
  }
385
- else if (rel && (prop.mapToPk ? helper(this.em.getReference(prop.type, rel)).getSerializedPrimaryKey() === serializedPK : rel === entity)) {
385
+ else if (rel && (prop.mapToPk ? helper(this.em.getReference(prop.targetMeta.class, rel)).getSerializedPrimaryKey() === serializedPK : rel === entity)) {
386
386
  if (prop.formula) {
387
387
  delete referrer[prop.name];
388
388
  }
@@ -424,13 +424,13 @@ export class UnitOfWork {
424
424
  const inserts = {};
425
425
  for (const cs of this.changeSets.values()) {
426
426
  if (cs.type === ChangeSetType.CREATE) {
427
- inserts[cs.meta.className] ??= [];
428
- inserts[cs.meta.className].push(cs);
427
+ inserts[cs.meta.uniqueName] ??= [];
428
+ inserts[cs.meta.uniqueName].push(cs);
429
429
  }
430
430
  }
431
431
  for (const cs of this.changeSets.values()) {
432
432
  if (cs.type === ChangeSetType.UPDATE) {
433
- this.findEarlyUpdates(cs, inserts[cs.meta.className]);
433
+ this.findEarlyUpdates(cs, inserts[cs.meta.uniqueName]);
434
434
  }
435
435
  }
436
436
  for (const entity of this.removeStack) {
@@ -441,7 +441,7 @@ export class UnitOfWork {
441
441
  }
442
442
  const deletePkHash = [wrapped.getSerializedPrimaryKey(), ...this.expandUniqueProps(entity)];
443
443
  let type = ChangeSetType.DELETE;
444
- for (const cs of inserts[wrapped.__meta.className] ?? []) {
444
+ for (const cs of inserts[wrapped.__meta.uniqueName] ?? []) {
445
445
  if (deletePkHash.some(hash => hash === cs.getSerializedPrimaryKey() || this.expandUniqueProps(cs.entity).find(child => hash === child))) {
446
446
  type = ChangeSetType.DELETE_EARLY;
447
447
  }
@@ -460,7 +460,7 @@ export class UnitOfWork {
460
460
  }
461
461
  for (const cs of this.changeSets.values()) {
462
462
  for (const prop of props) {
463
- if (prop.name in cs.payload && cs.rootName === changeSet.rootName && cs.type === changeSet.type) {
463
+ if (prop.name in cs.payload && cs.rootMeta === changeSet.rootMeta && cs.type === changeSet.type) {
464
464
  conflicts = true;
465
465
  if (changeSet.payload[prop.name] == null) {
466
466
  type = ChangeSetType.UPDATE_EARLY;
@@ -479,9 +479,10 @@ export class UnitOfWork {
479
479
  }
480
480
  scheduleOrphanRemoval(entity, visited) {
481
481
  if (entity) {
482
- helper(entity).__em = this.em;
482
+ const wrapped = helper(entity);
483
+ wrapped.__em = this.em;
483
484
  this.orphanRemoveStack.add(entity);
484
- this.queuedActions.add(entity.__meta.className);
485
+ this.queuedActions.add(wrapped.__meta.class);
485
486
  this.cascade(entity, Cascade.SCHEDULE_ORPHAN_REMOVAL, visited);
486
487
  }
487
488
  }
@@ -630,7 +631,7 @@ export class UnitOfWork {
630
631
  const copy = this.comparator.prepareEntity(changeSet.entity);
631
632
  await this.eventManager.dispatchEvent(type, { entity: changeSet.entity, meta, em: this.em, changeSet });
632
633
  const current = this.comparator.prepareEntity(changeSet.entity);
633
- const diff = this.comparator.diffEntities(changeSet.name, copy, current);
634
+ const diff = this.comparator.diffEntities(changeSet.meta.class, copy, current);
634
635
  Object.assign(changeSet.payload, diff);
635
636
  const wrapped = helper(changeSet.entity);
636
637
  if (wrapped.__identifier) {
@@ -739,26 +740,26 @@ export class UnitOfWork {
739
740
  }
740
741
  fixMissingReference(entity, prop) {
741
742
  const reference = entity[prop.name];
742
- const kind = Reference.unwrapReference(reference);
743
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && kind && !prop.mapToPk) {
744
- if (!Utils.isEntity(kind)) {
745
- entity[prop.name] = this.em.getReference(prop.type, kind, { wrapped: !!prop.ref });
743
+ const target = Reference.unwrapReference(reference);
744
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && target && !prop.mapToPk) {
745
+ if (!Utils.isEntity(target)) {
746
+ entity[prop.name] = this.em.getReference(prop.targetMeta.class, target, { wrapped: !!prop.ref });
746
747
  }
747
- else if (!helper(kind).__initialized && !helper(kind).__em) {
748
- const pk = helper(kind).getPrimaryKey();
749
- entity[prop.name] = this.em.getReference(prop.type, pk, { wrapped: !!prop.ref });
748
+ else if (!helper(target).__initialized && !helper(target).__em) {
749
+ const pk = helper(target).getPrimaryKey();
750
+ entity[prop.name] = this.em.getReference(prop.targetMeta.class, pk, { wrapped: !!prop.ref });
750
751
  }
751
752
  }
752
- // perf: set the `Collection._property` to skip the getter, as it can be slow when there is a lot of relations
753
- if (Utils.isCollection(kind)) {
754
- kind.property = prop;
753
+ // perf: set the `Collection._property` to skip the getter, as it can be slow when there are a lot of relations
754
+ if (Utils.isCollection(target)) {
755
+ target.property = prop;
755
756
  }
756
757
  const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
757
- if (isCollection && Array.isArray(kind)) {
758
+ if (isCollection && Array.isArray(target)) {
758
759
  const collection = new Collection(entity);
759
760
  collection.property = prop;
760
761
  entity[prop.name] = collection;
761
- collection.set(kind);
762
+ collection.set(target);
762
763
  }
763
764
  }
764
765
  async persistToDatabase(groups, ctx) {
@@ -768,30 +769,30 @@ export class UnitOfWork {
768
769
  const commitOrder = this.getCommitOrder();
769
770
  const commitOrderReversed = [...commitOrder].reverse();
770
771
  // early delete - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
771
- for (const name of commitOrderReversed) {
772
- await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE_EARLY].get(name) ?? [], ctx);
772
+ for (const meta of commitOrderReversed) {
773
+ await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE_EARLY].get(meta) ?? [], ctx);
773
774
  }
774
775
  // early update - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
775
- for (const name of commitOrder) {
776
- await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE_EARLY].get(name) ?? [], ctx);
776
+ for (const meta of commitOrder) {
777
+ await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE_EARLY].get(meta) ?? [], ctx);
777
778
  }
778
779
  // extra updates
779
780
  await this.commitExtraUpdates(ChangeSetType.UPDATE_EARLY, ctx);
780
781
  // create
781
- for (const name of commitOrder) {
782
- await this.commitCreateChangeSets(groups[ChangeSetType.CREATE].get(name) ?? [], ctx);
782
+ for (const meta of commitOrder) {
783
+ await this.commitCreateChangeSets(groups[ChangeSetType.CREATE].get(meta) ?? [], ctx);
783
784
  }
784
785
  // update
785
- for (const name of commitOrder) {
786
- await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE].get(name) ?? [], ctx);
786
+ for (const meta of commitOrder) {
787
+ await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE].get(meta) ?? [], ctx);
787
788
  }
788
789
  // extra updates
789
790
  await this.commitExtraUpdates(ChangeSetType.UPDATE, ctx);
790
791
  // collection updates
791
792
  await this.commitCollectionUpdates(ctx);
792
793
  // delete - entity deletions need to be in reverse commit order
793
- for (const name of commitOrderReversed) {
794
- await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE].get(name) ?? [], ctx);
794
+ for (const meta of commitOrderReversed) {
795
+ await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE].get(meta) ?? [], ctx);
795
796
  }
796
797
  // take snapshots of all persisted collections
797
798
  const visited = new Set();
@@ -960,10 +961,10 @@ export class UnitOfWork {
960
961
  };
961
962
  for (const cs of this.changeSets.values()) {
962
963
  const group = groups[cs.type];
963
- const classGroup = group.get(cs.rootName) ?? [];
964
+ const classGroup = group.get(cs.rootMeta) ?? [];
964
965
  classGroup.push(cs);
965
- if (!group.has(cs.rootName)) {
966
- group.set(cs.rootName, classGroup);
966
+ if (!group.has(cs.rootMeta)) {
967
+ group.set(cs.rootMeta, classGroup);
967
968
  }
968
969
  }
969
970
  return groups;
@@ -971,14 +972,14 @@ export class UnitOfWork {
971
972
  getCommitOrder() {
972
973
  const calc = new CommitOrderCalculator();
973
974
  const set = new Set();
974
- this.changeSets.forEach(cs => set.add(cs.rootName));
975
- set.forEach(entityName => calc.addNode(entityName));
976
- for (const entityName of set) {
977
- for (const prop of this.metadata.find(entityName).props) {
978
- calc.discoverProperty(prop, entityName);
975
+ this.changeSets.forEach(cs => set.add(cs.rootMeta));
976
+ set.forEach(meta => calc.addNode(meta._id));
977
+ for (const meta of set) {
978
+ for (const prop of meta.relations) {
979
+ calc.discoverProperty(prop, meta._id);
979
980
  }
980
981
  }
981
- return calc.sort();
982
+ return calc.sort().map(id => this.metadata.getById(id));
982
983
  }
983
984
  resetTransaction(oldTx) {
984
985
  if (oldTx) {
@@ -40,7 +40,7 @@ export class AbstractSchemaGenerator {
40
40
  }
41
41
  async clear(options) {
42
42
  for (const meta of this.getOrderedMetadata(options?.schema).reverse()) {
43
- await this.driver.nativeDelete(meta.className, {}, options);
43
+ await this.driver.nativeDelete(meta.class, {}, options);
44
44
  }
45
45
  if (options?.clearIdentityMap ?? true) {
46
46
  this.clearIdentityMap();
@@ -90,21 +90,21 @@ export class AbstractSchemaGenerator {
90
90
  this.notImplemented();
91
91
  }
92
92
  getOrderedMetadata(schema) {
93
- const metadata = Object.values(this.metadata.getAll()).filter(meta => {
94
- const isRootEntity = meta.root.className === meta.className;
93
+ const metadata = [...this.metadata.getAll().values()].filter(meta => {
94
+ const isRootEntity = meta.root.class === meta.class;
95
95
  return isRootEntity && !meta.embeddable && !meta.virtual;
96
96
  });
97
97
  const calc = new CommitOrderCalculator();
98
- metadata.forEach(meta => calc.addNode(meta.root.className));
98
+ metadata.forEach(meta => calc.addNode(meta.root._id));
99
99
  let meta = metadata.pop();
100
100
  while (meta) {
101
- for (const prop of meta.props) {
102
- calc.discoverProperty(prop, meta.root.className);
101
+ for (const prop of meta.relations) {
102
+ calc.discoverProperty(prop, meta.root._id);
103
103
  }
104
104
  meta = metadata.pop();
105
105
  }
106
106
  return calc.sort()
107
- .map(cls => this.metadata.find(cls))
107
+ .map(cls => this.metadata.getById(cls))
108
108
  .filter(meta => {
109
109
  const targetSchema = meta.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
110
110
  return schema ? [schema, '*'].includes(targetSchema) : meta.schema !== '*';
@@ -402,11 +402,6 @@ export interface MetadataDiscoveryOptions {
402
402
  * @default true
403
403
  */
404
404
  checkDuplicateFieldNames?: boolean;
405
- /**
406
- * Check for duplicate entities and throw an error if found.
407
- * @default true
408
- */
409
- checkDuplicateEntities?: boolean;
410
405
  /**
411
406
  * Check for composite primary keys marked as `persist: false` and throw an error if found.
412
407
  * @default true
@@ -11,7 +11,7 @@ export class DataloaderUtils {
11
11
  static groupPrimaryKeysByEntityAndOpts(refsWithOpts) {
12
12
  const map = new Map();
13
13
  for (const [ref, opts] of refsWithOpts) {
14
- /* The key is a combination of the className and a stringified version if the load options because we want
14
+ /* The key is a combination of the uniqueName (a unique table name based identifier) and a stringified version if the load options because we want
15
15
  to map each combination of entities/options into separate find queries in order to return accurate results.
16
16
  This could be further optimized finding the "lowest common denominator" among the different options
17
17
  for each Entity and firing a single query for each Entity instead of Entity+options combination.
@@ -24,7 +24,7 @@ export class DataloaderUtils {
24
24
  Thus such approach should probably be configurable, if not opt-in.
25
25
  NOTE: meta + opts multi maps (https://github.com/martian17/ds-js) might be a more elegant way
26
26
  to implement this but not necessarily faster. */
27
- const key = `${helper(ref).__meta.className}|${JSON.stringify(opts ?? {})}`;
27
+ const key = `${helper(ref).__meta.uniqueName}|${JSON.stringify(opts ?? {})}`;
28
28
  let primaryKeysSet = map.get(key);
29
29
  if (primaryKeysSet == null) {
30
30
  primaryKeysSet = new Set();
@@ -42,9 +42,10 @@ export class DataloaderUtils {
42
42
  return async (refsWithOpts) => {
43
43
  const groupedIdsMap = DataloaderUtils.groupPrimaryKeysByEntityAndOpts(refsWithOpts);
44
44
  const promises = Array.from(groupedIdsMap).map(([key, idsSet]) => {
45
- const className = key.substring(0, key.indexOf('|'));
45
+ const uniqueName = key.substring(0, key.indexOf('|'));
46
46
  const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
47
- return em.find(className, Array.from(idsSet), opts);
47
+ const meta = em.getMetadata().getByUniqueName(uniqueName);
48
+ return em.find(meta.class, Array.from(idsSet), opts);
48
49
  });
49
50
  await Promise.all(promises);
50
51
  /* Instead of assigning each find result to the original reference we use a shortcut
@@ -70,7 +71,7 @@ export class DataloaderUtils {
70
71
  The value is another Map which we can use to filter the find query to get results pertaining to the collections that have been dataloaded:
71
72
  its keys are the props we are going to filter to and its values are the corresponding PKs.
72
73
  */
73
- const key = `${col.property.targetMeta.className}|${JSON.stringify(opts ?? {})}`;
74
+ const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
74
75
  let filterMap = entitiesMap.get(key); // We are going to use this map to filter the entities pertaining to the collections that have been dataloaded.
75
76
  if (filterMap == null) {
76
77
  filterMap = new Map();
@@ -97,9 +98,10 @@ export class DataloaderUtils {
97
98
  */
98
99
  static entitiesAndOptsMapToQueries(entitiesAndOptsMap, em) {
99
100
  return Array.from(entitiesAndOptsMap, async ([key, filterMap]) => {
100
- const className = key.substring(0, key.indexOf('|'));
101
+ const uniqueName = key.substring(0, key.indexOf('|'));
101
102
  const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
102
- const res = await em.find(className, opts?.where != null && Object.keys(opts.where).length > 0 ?
103
+ const meta = em.getMetadata().getByUniqueName(uniqueName);
104
+ const res = await em.find(meta.class, opts?.where != null && Object.keys(opts.where).length > 0 ?
103
105
  {
104
106
  $and: [
105
107
  {
@@ -121,7 +123,7 @@ export class DataloaderUtils {
121
123
  ...(opts.populate === false ? [] : opts.populate ?? []),
122
124
  ...Array.from(filterMap.keys()).filter(
123
125
  // We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
124
- prop => em.getMetadata(className).properties[prop]?.ref !== true),
126
+ prop => meta.properties[prop]?.ref !== true),
125
127
  ],
126
128
  });
127
129
  return [key, res];
@@ -164,7 +166,7 @@ export class DataloaderUtils {
164
166
  // We need to filter the results in order to map each input collection
165
167
  // to a subset of each query matching the collection items.
166
168
  return collsWithOpts.map(([col, opts]) => {
167
- const key = `${col.property.targetMeta.className}|${JSON.stringify(opts ?? {})}`;
169
+ const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
168
170
  const entities = resultsMap.get(key);
169
171
  if (entities == null) {
170
172
  // Should never happen
@@ -183,7 +185,7 @@ export class DataloaderUtils {
183
185
  return async (collsWithOpts) => {
184
186
  const groups = new Map();
185
187
  for (const [col, opts] of collsWithOpts) {
186
- const key = `${col.property.targetMeta.className}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
188
+ const key = `${col.property.targetMeta.uniqueName}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
187
189
  const value = groups.get(key) ?? [];
188
190
  value.push([col, opts ?? {}]);
189
191
  groups.set(key, value);
@@ -198,7 +200,7 @@ export class DataloaderUtils {
198
200
  const owners = group.map(c => c[0].owner);
199
201
  const $or = [];
200
202
  // a bit of a hack, but we need to prefix the key, since we have only a column name, not a property name
201
- const alias = em.config.getNamingStrategy().aliasName(prop.pivotEntity, 0);
203
+ const alias = em.config.getNamingStrategy().aliasName(Utils.className(prop.pivotEntity), 0);
202
204
  const fk = `${alias}.${Utils.getPrimaryKeyHash(prop.joinColumns)}`;
203
205
  for (const c of group) {
204
206
  $or.push({ $and: [c[1]?.where ?? {}, { [fk]: c[0].owner }] });