@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120

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 (207) hide show
  1. package/EntityManager.d.ts +85 -56
  2. package/EntityManager.js +332 -293
  3. package/MikroORM.d.ts +41 -32
  4. package/MikroORM.js +100 -140
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +1 -1
  7. package/cache/FileCacheAdapter.js +8 -7
  8. package/cache/GeneratedCacheAdapter.d.ts +0 -1
  9. package/cache/GeneratedCacheAdapter.js +0 -2
  10. package/cache/index.d.ts +0 -1
  11. package/cache/index.js +0 -1
  12. package/connections/Connection.d.ts +16 -7
  13. package/connections/Connection.js +23 -14
  14. package/drivers/DatabaseDriver.d.ts +25 -16
  15. package/drivers/DatabaseDriver.js +35 -19
  16. package/drivers/IDatabaseDriver.d.ts +38 -17
  17. package/entity/BaseEntity.d.ts +0 -1
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +95 -30
  20. package/entity/Collection.js +439 -99
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +7 -0
  24. package/entity/EntityFactory.js +72 -53
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +30 -15
  27. package/entity/EntityLoader.d.ts +7 -6
  28. package/entity/EntityLoader.js +84 -72
  29. package/entity/EntityRepository.d.ts +1 -1
  30. package/entity/EntityRepository.js +2 -2
  31. package/entity/Reference.d.ts +6 -5
  32. package/entity/Reference.js +34 -9
  33. package/entity/WrappedEntity.d.ts +2 -7
  34. package/entity/WrappedEntity.js +3 -8
  35. package/entity/defineEntity.d.ts +568 -0
  36. package/entity/defineEntity.js +529 -0
  37. package/entity/index.d.ts +3 -2
  38. package/entity/index.js +3 -2
  39. package/entity/utils.d.ts +7 -0
  40. package/entity/utils.js +16 -4
  41. package/entity/validators.d.ts +11 -0
  42. package/entity/validators.js +65 -0
  43. package/enums.d.ts +21 -6
  44. package/enums.js +14 -1
  45. package/errors.d.ts +17 -9
  46. package/errors.js +41 -21
  47. package/events/EventManager.d.ts +2 -1
  48. package/events/EventManager.js +19 -11
  49. package/hydration/Hydrator.js +1 -2
  50. package/hydration/ObjectHydrator.d.ts +4 -4
  51. package/hydration/ObjectHydrator.js +50 -33
  52. package/index.d.ts +2 -2
  53. package/index.js +1 -2
  54. package/logging/DefaultLogger.d.ts +1 -1
  55. package/logging/DefaultLogger.js +1 -0
  56. package/logging/SimpleLogger.d.ts +1 -1
  57. package/logging/colors.d.ts +1 -1
  58. package/logging/colors.js +7 -6
  59. package/logging/index.d.ts +1 -0
  60. package/logging/index.js +1 -0
  61. package/logging/inspect.d.ts +2 -0
  62. package/logging/inspect.js +11 -0
  63. package/metadata/EntitySchema.d.ts +13 -17
  64. package/metadata/EntitySchema.js +67 -51
  65. package/metadata/MetadataDiscovery.d.ts +6 -10
  66. package/metadata/MetadataDiscovery.js +289 -298
  67. package/metadata/MetadataProvider.d.ts +11 -2
  68. package/metadata/MetadataProvider.js +46 -2
  69. package/metadata/MetadataStorage.d.ts +13 -11
  70. package/metadata/MetadataStorage.js +70 -37
  71. package/metadata/MetadataValidator.d.ts +2 -9
  72. package/metadata/MetadataValidator.js +22 -38
  73. package/metadata/discover-entities.d.ts +5 -0
  74. package/metadata/discover-entities.js +40 -0
  75. package/metadata/index.d.ts +1 -1
  76. package/metadata/index.js +1 -1
  77. package/metadata/types.d.ts +480 -0
  78. package/metadata/types.js +1 -0
  79. package/naming-strategy/AbstractNamingStrategy.d.ts +8 -4
  80. package/naming-strategy/AbstractNamingStrategy.js +8 -2
  81. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  82. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  83. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  84. package/naming-strategy/MongoNamingStrategy.js +6 -6
  85. package/naming-strategy/NamingStrategy.d.ts +14 -4
  86. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  87. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  88. package/not-supported.d.ts +2 -0
  89. package/not-supported.js +4 -0
  90. package/package.json +19 -11
  91. package/platforms/ExceptionConverter.js +1 -1
  92. package/platforms/Platform.d.ts +6 -13
  93. package/platforms/Platform.js +17 -43
  94. package/serialization/EntitySerializer.d.ts +5 -0
  95. package/serialization/EntitySerializer.js +47 -27
  96. package/serialization/EntityTransformer.js +28 -18
  97. package/serialization/SerializationContext.d.ts +6 -6
  98. package/serialization/SerializationContext.js +16 -13
  99. package/types/ArrayType.d.ts +1 -1
  100. package/types/ArrayType.js +2 -3
  101. package/types/BigIntType.d.ts +8 -6
  102. package/types/BigIntType.js +1 -1
  103. package/types/BlobType.d.ts +0 -1
  104. package/types/BlobType.js +0 -3
  105. package/types/BooleanType.d.ts +2 -1
  106. package/types/BooleanType.js +3 -0
  107. package/types/DecimalType.d.ts +6 -4
  108. package/types/DecimalType.js +3 -3
  109. package/types/DoubleType.js +2 -2
  110. package/types/EnumArrayType.js +1 -2
  111. package/types/JsonType.d.ts +1 -1
  112. package/types/JsonType.js +7 -2
  113. package/types/TinyIntType.js +1 -1
  114. package/types/Type.d.ts +2 -4
  115. package/types/Type.js +3 -3
  116. package/types/Uint8ArrayType.d.ts +0 -1
  117. package/types/Uint8ArrayType.js +1 -4
  118. package/types/index.d.ts +1 -1
  119. package/typings.d.ts +124 -86
  120. package/typings.js +50 -42
  121. package/unit-of-work/ChangeSet.d.ts +2 -6
  122. package/unit-of-work/ChangeSet.js +4 -5
  123. package/unit-of-work/ChangeSetComputer.d.ts +1 -3
  124. package/unit-of-work/ChangeSetComputer.js +14 -12
  125. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  126. package/unit-of-work/ChangeSetPersister.js +65 -33
  127. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  128. package/unit-of-work/CommitOrderCalculator.js +13 -13
  129. package/unit-of-work/UnitOfWork.d.ts +10 -3
  130. package/unit-of-work/UnitOfWork.js +139 -96
  131. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  132. package/utils/AbstractSchemaGenerator.js +18 -16
  133. package/utils/AsyncContext.d.ts +6 -0
  134. package/utils/AsyncContext.js +42 -0
  135. package/utils/Configuration.d.ts +753 -207
  136. package/utils/Configuration.js +145 -190
  137. package/utils/ConfigurationLoader.d.ts +1 -54
  138. package/utils/ConfigurationLoader.js +1 -352
  139. package/utils/Cursor.d.ts +0 -3
  140. package/utils/Cursor.js +9 -6
  141. package/utils/DataloaderUtils.d.ts +15 -5
  142. package/utils/DataloaderUtils.js +65 -17
  143. package/utils/EntityComparator.d.ts +13 -9
  144. package/utils/EntityComparator.js +85 -43
  145. package/utils/QueryHelper.d.ts +14 -6
  146. package/utils/QueryHelper.js +87 -25
  147. package/utils/RawQueryFragment.d.ts +48 -25
  148. package/utils/RawQueryFragment.js +66 -70
  149. package/utils/RequestContext.js +2 -2
  150. package/utils/TransactionContext.js +2 -2
  151. package/utils/TransactionManager.d.ts +65 -0
  152. package/utils/TransactionManager.js +223 -0
  153. package/utils/Utils.d.ts +12 -119
  154. package/utils/Utils.js +97 -373
  155. package/utils/clone.js +8 -23
  156. package/utils/env-vars.d.ts +7 -0
  157. package/utils/env-vars.js +97 -0
  158. package/utils/fs-utils.d.ts +32 -0
  159. package/utils/fs-utils.js +178 -0
  160. package/utils/index.d.ts +2 -1
  161. package/utils/index.js +2 -1
  162. package/utils/upsert-utils.d.ts +9 -4
  163. package/utils/upsert-utils.js +55 -4
  164. package/decorators/Check.d.ts +0 -3
  165. package/decorators/Check.js +0 -13
  166. package/decorators/CreateRequestContext.d.ts +0 -3
  167. package/decorators/CreateRequestContext.js +0 -32
  168. package/decorators/Embeddable.d.ts +0 -8
  169. package/decorators/Embeddable.js +0 -11
  170. package/decorators/Embedded.d.ts +0 -18
  171. package/decorators/Embedded.js +0 -18
  172. package/decorators/Entity.d.ts +0 -18
  173. package/decorators/Entity.js +0 -12
  174. package/decorators/Enum.d.ts +0 -9
  175. package/decorators/Enum.js +0 -16
  176. package/decorators/Filter.d.ts +0 -2
  177. package/decorators/Filter.js +0 -8
  178. package/decorators/Formula.d.ts +0 -4
  179. package/decorators/Formula.js +0 -15
  180. package/decorators/Indexed.d.ts +0 -19
  181. package/decorators/Indexed.js +0 -20
  182. package/decorators/ManyToMany.d.ts +0 -40
  183. package/decorators/ManyToMany.js +0 -14
  184. package/decorators/ManyToOne.d.ts +0 -30
  185. package/decorators/ManyToOne.js +0 -14
  186. package/decorators/OneToMany.d.ts +0 -28
  187. package/decorators/OneToMany.js +0 -17
  188. package/decorators/OneToOne.d.ts +0 -24
  189. package/decorators/OneToOne.js +0 -7
  190. package/decorators/PrimaryKey.d.ts +0 -8
  191. package/decorators/PrimaryKey.js +0 -20
  192. package/decorators/Property.d.ts +0 -250
  193. package/decorators/Property.js +0 -32
  194. package/decorators/Transactional.d.ts +0 -13
  195. package/decorators/Transactional.js +0 -28
  196. package/decorators/hooks.d.ts +0 -16
  197. package/decorators/hooks.js +0 -47
  198. package/decorators/index.d.ts +0 -17
  199. package/decorators/index.js +0 -17
  200. package/entity/ArrayCollection.d.ts +0 -116
  201. package/entity/ArrayCollection.js +0 -402
  202. package/entity/EntityValidator.d.ts +0 -19
  203. package/entity/EntityValidator.js +0 -150
  204. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  205. package/metadata/ReflectMetadataProvider.js +0 -44
  206. package/utils/resolveContextProvider.d.ts +0 -10
  207. package/utils/resolveContextProvider.js +0 -28
package/typings.js CHANGED
@@ -25,38 +25,56 @@ export class EntityMetadata {
25
25
  this.referencingProperties = [];
26
26
  this.concurrencyCheckKeys = new Set();
27
27
  Object.assign(this, meta);
28
- }
29
- addProperty(prop, sync = true) {
30
- if (prop.pivotTable && !prop.pivotEntity) {
31
- prop.pivotEntity = prop.pivotTable;
28
+ const name = meta.className ?? meta.name;
29
+ if (!this.class && name) {
30
+ this.class = ({ [name]: class {
31
+ } })[name];
32
32
  }
33
+ }
34
+ addProperty(prop) {
33
35
  this.properties[prop.name] = prop;
34
36
  this.propertyOrder.set(prop.name, this.props.length);
35
- /* v8 ignore next 3 */
36
- if (sync) {
37
- this.sync();
38
- }
37
+ this.sync();
39
38
  }
40
39
  removeProperty(name, sync = true) {
41
40
  delete this.properties[name];
42
41
  this.propertyOrder.delete(name);
43
- /* v8 ignore next 3 */
44
42
  if (sync) {
45
43
  this.sync();
46
44
  }
47
45
  }
48
- getPrimaryProps() {
49
- return this.primaryKeys.map(pk => this.properties[pk]);
46
+ getPrimaryProps(flatten = false) {
47
+ const pks = this.primaryKeys.map(pk => this.properties[pk]);
48
+ if (flatten) {
49
+ return pks.flatMap(pk => {
50
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(pk.kind)) {
51
+ return pk.targetMeta.getPrimaryProps(true);
52
+ }
53
+ return [pk];
54
+ });
55
+ }
56
+ return pks;
50
57
  }
51
58
  getPrimaryProp() {
52
59
  return this.properties[this.primaryKeys[0]];
53
60
  }
61
+ createColumnMappingObject() {
62
+ return Object.values(this.properties).reduce((o, prop) => {
63
+ if (prop.fieldNames) {
64
+ o[prop.name] = prop.fieldNames[0];
65
+ }
66
+ return o;
67
+ }, {});
68
+ }
54
69
  get tableName() {
55
70
  return this.collection;
56
71
  }
57
72
  set tableName(name) {
58
73
  this.collection = name;
59
74
  }
75
+ get uniqueName() {
76
+ return this.tableName + '_' + this._id;
77
+ }
60
78
  sync(initIndexes = false, config) {
61
79
  this.root ??= this;
62
80
  const props = Object.values(this.properties).sort((a, b) => this.propertyOrder.get(a.name) - this.propertyOrder.get(b.name));
@@ -66,23 +84,30 @@ export class EntityMetadata {
66
84
  this.uniqueProps = this.props.filter(prop => prop.unique);
67
85
  this.getterProps = this.props.filter(prop => prop.getter);
68
86
  this.comparableProps = this.props.filter(prop => EntityComparator.isComparable(prop, this));
87
+ this.validateProps = this.props.filter(prop => {
88
+ if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
89
+ return false;
90
+ }
91
+ return prop.kind === ReferenceKind.SCALAR && ['string', 'number', 'boolean', 'Date'].includes(prop.type);
92
+ });
69
93
  this.hydrateProps = this.props.filter(prop => {
70
94
  // `prop.userDefined` is either `undefined` or `false`
71
95
  const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
72
96
  // even if we don't have a setter, do not ignore value from database!
73
- const onlyGetter = prop.getter && !prop.setter;
97
+ const onlyGetter = prop.getter && !prop.setter && prop.persist === false;
74
98
  return !prop.inherited && prop.hydrate !== false && !discriminator && !prop.embedded && !onlyGetter;
75
99
  });
76
- this.trackingProps = this.hydrateProps
77
- .filter(prop => !prop.getter && !prop.setter && prop.trackChanges !== false)
78
- .filter(prop => ![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind))
79
- .filter(prop => !prop.serializedPrimaryKey);
80
- this.selfReferencing = this.relations.some(prop => [this.className, this.root.className].includes(prop.targetMeta?.root.className ?? prop.type));
100
+ this.trackingProps = this.hydrateProps.filter(prop => {
101
+ return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
102
+ });
103
+ this.selfReferencing = this.relations.some(prop => {
104
+ return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
105
+ });
81
106
  this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
82
107
  this.virtual = !!this.expression;
83
108
  if (config) {
84
109
  for (const prop of this.props) {
85
- if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => Utils.isString(item))) {
110
+ if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
86
111
  const name = config.getNamingStrategy().indexName(this.tableName, prop.fieldNames, 'check');
87
112
  const exists = this.checks.findIndex(check => check.name === name);
88
113
  if (exists !== -1) {
@@ -109,8 +134,7 @@ export class EntityMetadata {
109
134
  this.props.forEach(prop => this.initIndexes(prop));
110
135
  }
111
136
  this.definedProperties = this.trackingProps.reduce((o, prop) => {
112
- const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
113
- const isReference = [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
137
+ const isReference = (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
114
138
  if (isReference) {
115
139
  // eslint-disable-next-line @typescript-eslint/no-this-alias
116
140
  const meta = this;
@@ -129,10 +153,7 @@ export class EntityMetadata {
129
153
  wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
130
154
  // when propagation from inside hydration, we set the FK to the entity data immediately
131
155
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
132
- wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta.primaryKeys, true);
133
- }
134
- else {
135
- wrapped.__touched = !hydrator.isRunning();
156
+ wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta, true);
136
157
  }
137
158
  EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
138
159
  },
@@ -140,23 +161,6 @@ export class EntityMetadata {
140
161
  configurable: true,
141
162
  };
142
163
  }
143
- if (prop.inherited || prop.primary || isCollection || prop.persist === false || prop.trackChanges === false || isReference || prop.embedded) {
144
- return o;
145
- }
146
- o[prop.name] = {
147
- get() {
148
- return this.__helper.__data[prop.name];
149
- },
150
- set(val) {
151
- if (typeof val === 'object' && !!val && '__raw' in val) {
152
- val.assign();
153
- }
154
- this.__helper.__data[prop.name] = val;
155
- this.__helper.__touched = !this.__helper.hydrator.isRunning();
156
- },
157
- enumerable: true,
158
- configurable: true,
159
- };
160
164
  return o;
161
165
  }, { __gettersDefined: { value: true, enumerable: false } });
162
166
  }
@@ -178,7 +182,7 @@ export class EntityMetadata {
178
182
  this.indexes.push({ properties: prop.name });
179
183
  prop.index = false;
180
184
  }
181
- /* v8 ignore next 4 */
185
+ /* v8 ignore next */
182
186
  if (owner && prop.fieldNames.length > 1 && prop.unique) {
183
187
  this.uniques.push({ properties: prop.name });
184
188
  prop.unique = false;
@@ -188,4 +192,8 @@ export class EntityMetadata {
188
192
  clone() {
189
193
  return this;
190
194
  }
195
+ /** @ignore */
196
+ [Symbol.for('nodejs.util.inspect.custom')]() {
197
+ return `[${this.constructor.name}<${this.className}>]`;
198
+ }
191
199
  }
@@ -1,4 +1,3 @@
1
- import { inspect } from 'node:util';
2
1
  import type { EntityData, EntityMetadata, EntityDictionary, Primary } from '../typings.js';
3
2
  export declare class ChangeSet<T extends object> {
4
3
  entity: T;
@@ -10,13 +9,10 @@ export declare class ChangeSet<T extends object> {
10
9
  constructor(entity: T, type: ChangeSetType, payload: EntityDictionary<T>, meta: EntityMetadata<T>);
11
10
  getPrimaryKey(object?: boolean): Primary<T> | null;
12
11
  getSerializedPrimaryKey(): string | null;
13
- /** @ignore */
14
- [inspect.custom](depth?: number): string;
15
12
  }
16
13
  export interface ChangeSet<T> {
17
- name: string;
18
- rootName: string;
19
- collection: string;
14
+ meta: EntityMetadata<T>;
15
+ rootMeta: EntityMetadata<T>;
20
16
  schema?: string;
21
17
  type: ChangeSetType;
22
18
  entity: T;
@@ -1,6 +1,6 @@
1
- import { inspect } from 'node:util';
2
1
  import { helper } from '../entity/wrap.js';
3
2
  import { Utils } from '../utils/Utils.js';
3
+ import { inspect } from '../logging/inspect.js';
4
4
  export class ChangeSet {
5
5
  entity;
6
6
  type;
@@ -13,9 +13,8 @@ export class ChangeSet {
13
13
  this.type = type;
14
14
  this.payload = payload;
15
15
  this.meta = meta;
16
- this.name = meta.className;
17
- this.rootName = meta.root.className;
18
- this.collection = meta.root.collection;
16
+ this.meta = meta;
17
+ this.rootMeta = meta.root;
19
18
  this.schema = helper(entity).__schema ?? meta.root.schema;
20
19
  }
21
20
  getPrimaryKey(object = false) {
@@ -46,7 +45,7 @@ export class ChangeSet {
46
45
  return this.serializedPrimaryKey;
47
46
  }
48
47
  /** @ignore */
49
- [inspect.custom](depth = 2) {
48
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
50
49
  const object = { ...this };
51
50
  const hidden = ['meta', 'serializedPrimaryKey'];
52
51
  hidden.forEach(k => delete object[k]);
@@ -2,19 +2,17 @@ import { type Configuration } from '../utils/Configuration.js';
2
2
  import type { MetadataStorage } from '../metadata/MetadataStorage.js';
3
3
  import type { AnyEntity } from '../typings.js';
4
4
  import { ChangeSet } from './ChangeSet.js';
5
- import { type EntityValidator } from '../entity/EntityValidator.js';
6
5
  import { type Collection } from '../entity/Collection.js';
7
6
  import type { Platform } from '../platforms/Platform.js';
8
7
  import type { EntityManager } from '../EntityManager.js';
9
8
  export declare class ChangeSetComputer {
10
- private readonly validator;
11
9
  private readonly collectionUpdates;
12
10
  private readonly metadata;
13
11
  private readonly platform;
14
12
  private readonly config;
15
13
  private readonly em;
16
14
  private readonly comparator;
17
- constructor(validator: EntityValidator, collectionUpdates: Set<Collection<AnyEntity>>, metadata: MetadataStorage, platform: Platform, config: Configuration, em: EntityManager);
15
+ constructor(collectionUpdates: Set<Collection<AnyEntity>>, metadata: MetadataStorage, platform: Platform, config: Configuration, em: EntityManager);
18
16
  computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
19
17
  /**
20
18
  * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
@@ -1,17 +1,16 @@
1
1
  import { Utils } from '../utils/Utils.js';
2
2
  import { ChangeSet, ChangeSetType } from './ChangeSet.js';
3
3
  import { helper } from '../entity/wrap.js';
4
+ import { validateEntity } from '../entity/validators.js';
4
5
  import { ReferenceKind } from '../enums.js';
5
6
  export class ChangeSetComputer {
6
- validator;
7
7
  collectionUpdates;
8
8
  metadata;
9
9
  platform;
10
10
  config;
11
11
  em;
12
12
  comparator;
13
- constructor(validator, collectionUpdates, metadata, platform, config, em) {
14
- this.validator = validator;
13
+ constructor(collectionUpdates, metadata, platform, config, em) {
15
14
  this.collectionUpdates = collectionUpdates;
16
15
  this.metadata = metadata;
17
16
  this.platform = platform;
@@ -20,7 +19,7 @@ export class ChangeSetComputer {
20
19
  this.comparator = this.config.getComparator(this.metadata);
21
20
  }
22
21
  computeChangeSet(entity) {
23
- const meta = this.metadata.get(entity.constructor.name);
22
+ const meta = this.metadata.get(entity.constructor);
24
23
  if (meta.readonly) {
25
24
  return null;
26
25
  }
@@ -34,20 +33,21 @@ export class ChangeSetComputer {
34
33
  this.processPropertyInitializers(entity, prop, type, map);
35
34
  }
36
35
  }
37
- if (type === ChangeSetType.UPDATE && !wrapped.__initialized && !wrapped.isTouched()) {
38
- return null;
36
+ if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
37
+ const data = this.comparator.prepareEntity(entity);
38
+ if (Utils.equals(data, wrapped.__originalEntityData)) {
39
+ return null;
40
+ }
39
41
  }
40
42
  const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
41
43
  changeSet.originalEntity = wrapped.__originalEntityData;
42
- if (this.config.get('validate')) {
43
- this.validator.validate(changeSet.entity, changeSet.payload, meta);
44
- }
45
44
  for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
46
45
  this.processProperty(changeSet, prop);
47
46
  }
48
47
  if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
49
48
  return null;
50
49
  }
50
+ validateEntity(changeSet.entity, meta);
51
51
  // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
52
52
  // to the `map` as we want to apply those only if something else changed.
53
53
  if (type === ChangeSetType.UPDATE) {
@@ -91,7 +91,7 @@ export class ChangeSetComputer {
91
91
  computePayload(entity, ignoreUndefined = false) {
92
92
  const data = this.comparator.prepareEntity(entity);
93
93
  const wrapped = helper(entity);
94
- const entityName = wrapped.__meta.className;
94
+ const entityName = wrapped.__meta.class;
95
95
  const originalEntityData = wrapped.__originalEntityData;
96
96
  if (!wrapped.__initialized) {
97
97
  for (const prop of wrapped.__meta.primaryKeys) {
@@ -132,7 +132,7 @@ export class ChangeSetComputer {
132
132
  const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
133
133
  targets.forEach(([target, idx]) => {
134
134
  if (!target.__helper.hasPrimaryKey()) {
135
- Utils.setPayloadProperty(changeSet.payload, this.metadata.find(changeSet.name), prop, target.__helper.__identifier, idx);
135
+ Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, target.__helper.__identifier, idx);
136
136
  }
137
137
  });
138
138
  }
@@ -141,7 +141,9 @@ export class ChangeSetComputer {
141
141
  if (!target.isDirty() && changeSet.type !== ChangeSetType.CREATE) {
142
142
  return;
143
143
  }
144
- this.collectionUpdates.add(target);
144
+ if (target.isDirty()) {
145
+ this.collectionUpdates.add(target);
146
+ }
145
147
  if (prop.owner && !this.platform.usesPivotTable()) {
146
148
  changeSet.payload[prop.name] = target.getItems(false).map((item) => item.__helper.__identifier ?? item.__helper.getPrimaryKey());
147
149
  }
@@ -1,29 +1,30 @@
1
1
  import type { MetadataStorage } from '../metadata/MetadataStorage.js';
2
2
  import type { Dictionary, EntityDictionary, EntityMetadata, IHydrator } from '../typings.js';
3
3
  import { type EntityFactory } from '../entity/EntityFactory.js';
4
- import { type EntityValidator } from '../entity/EntityValidator.js';
5
4
  import { type ChangeSet } from './ChangeSet.js';
6
5
  import { type Configuration } from '../utils/Configuration.js';
7
6
  import type { DriverMethodOptions, IDatabaseDriver } from '../drivers/IDatabaseDriver.js';
7
+ import type { EntityManager } from '../EntityManager.js';
8
8
  export declare class ChangeSetPersister {
9
9
  private readonly driver;
10
10
  private readonly metadata;
11
11
  private readonly hydrator;
12
12
  private readonly factory;
13
- private readonly validator;
14
13
  private readonly config;
14
+ private readonly em;
15
15
  private readonly platform;
16
16
  private readonly comparator;
17
17
  private readonly usesReturningStatement;
18
- constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, validator: EntityValidator, config: Configuration);
18
+ constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, config: Configuration, em: EntityManager);
19
19
  executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
20
20
  executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
21
21
  executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
22
22
  private runForEachSchema;
23
+ private validateRequired;
23
24
  private processProperties;
24
25
  private persistNewEntity;
25
26
  private persistNewEntities;
26
- private propagateSchemaFromMetadata;
27
+ private prepareOptions;
27
28
  private persistNewEntitiesBatch;
28
29
  private persistManagedEntity;
29
30
  private persistManagedEntities;
@@ -3,25 +3,25 @@ import { helper } from '../entity/wrap.js';
3
3
  import { ChangeSetType } from './ChangeSet.js';
4
4
  import { isRaw } from '../utils/RawQueryFragment.js';
5
5
  import { Utils } from '../utils/Utils.js';
6
- import { OptimisticLockError } from '../errors.js';
6
+ import { OptimisticLockError, ValidationError } from '../errors.js';
7
7
  import { ReferenceKind } from '../enums.js';
8
8
  export class ChangeSetPersister {
9
9
  driver;
10
10
  metadata;
11
11
  hydrator;
12
12
  factory;
13
- validator;
14
13
  config;
14
+ em;
15
15
  platform;
16
16
  comparator;
17
17
  usesReturningStatement;
18
- constructor(driver, metadata, hydrator, factory, validator, config) {
18
+ constructor(driver, metadata, hydrator, factory, config, em) {
19
19
  this.driver = driver;
20
20
  this.metadata = metadata;
21
21
  this.hydrator = hydrator;
22
22
  this.factory = factory;
23
- this.validator = validator;
24
23
  this.config = config;
24
+ this.em = em;
25
25
  this.platform = this.driver.getPlatform();
26
26
  this.comparator = this.config.getComparator(this.metadata);
27
27
  this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
@@ -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);
@@ -62,8 +62,8 @@ export class ChangeSetPersister {
62
62
  for (let i = 0; i < changeSets.length; i += size) {
63
63
  const chunk = changeSets.slice(i, i + size);
64
64
  const pks = chunk.map(cs => cs.getPrimaryKey());
65
- options = this.propagateSchemaFromMetadata(meta, options);
66
- await this.driver.nativeDelete(meta.root.className, { [pk]: { $in: pks } }, options);
65
+ options = this.prepareOptions(meta, 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) {
@@ -79,21 +79,40 @@ export class ChangeSetPersister {
79
79
  await this[method](group, ...args, options, true);
80
80
  }
81
81
  }
82
+ validateRequired(entity) {
83
+ const wrapped = helper(entity);
84
+ for (const prop of wrapped.__meta.props) {
85
+ if (!prop.nullable &&
86
+ !prop.autoincrement &&
87
+ !prop.default &&
88
+ !prop.defaultRaw &&
89
+ !prop.onCreate &&
90
+ !prop.generated &&
91
+ !prop.embedded &&
92
+ ![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
93
+ prop.name !== wrapped.__meta.root.discriminatorColumn &&
94
+ prop.type !== 'ObjectId' &&
95
+ prop.persist !== false &&
96
+ entity[prop.name] == null) {
97
+ throw ValidationError.propertyRequired(entity, prop);
98
+ }
99
+ }
100
+ }
82
101
  processProperties(changeSet) {
83
- const meta = this.metadata.find(changeSet.name);
102
+ const meta = changeSet.meta;
84
103
  for (const prop of meta.relations) {
85
104
  this.processProperty(changeSet, prop);
86
105
  }
87
106
  if (changeSet.type === ChangeSetType.CREATE && this.config.get('validateRequired')) {
88
- this.validator.validateRequired(changeSet.entity);
107
+ this.validateRequired(changeSet.entity);
89
108
  }
90
109
  }
91
110
  async persistNewEntity(meta, changeSet, options) {
92
111
  const wrapped = helper(changeSet.entity);
93
- options = this.propagateSchemaFromMetadata(meta, options, {
112
+ options = this.prepareOptions(meta, options, {
94
113
  convertCustomTypes: false,
95
114
  });
96
- const res = await this.driver.nativeInsertMany(meta.className, [changeSet.payload], options);
115
+ const res = await this.driver.nativeInsertMany(meta.class, [changeSet.payload], options);
97
116
  if (!wrapped.hasPrimaryKey()) {
98
117
  this.mapPrimaryKey(meta, res.insertId, changeSet);
99
118
  }
@@ -116,19 +135,21 @@ export class ChangeSetPersister {
116
135
  }
117
136
  }
118
137
  }
119
- propagateSchemaFromMetadata(meta, options, additionalOptions) {
138
+ prepareOptions(meta, options, additionalOptions) {
139
+ const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
120
140
  return {
121
141
  ...options,
122
142
  ...additionalOptions,
123
143
  schema: options?.schema ?? meta.schema,
144
+ loggerContext,
124
145
  };
125
146
  }
126
147
  async persistNewEntitiesBatch(meta, changeSets, options) {
127
- options = this.propagateSchemaFromMetadata(meta, options, {
148
+ options = this.prepareOptions(meta, options, {
128
149
  convertCustomTypes: false,
129
150
  processCollections: false,
130
151
  });
131
- 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);
132
153
  for (let i = 0; i < changeSets.length; i++) {
133
154
  const changeSet = changeSets[i];
134
155
  const wrapped = helper(changeSet.entity);
@@ -146,7 +167,7 @@ export class ChangeSetPersister {
146
167
  }
147
168
  }
148
169
  async persistManagedEntity(changeSet, options) {
149
- const meta = this.metadata.find(changeSet.name);
170
+ const meta = changeSet.meta;
150
171
  const res = await this.updateEntity(meta, changeSet, options);
151
172
  this.checkOptimisticLock(meta, changeSet, res);
152
173
  this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
@@ -175,7 +196,7 @@ export class ChangeSetPersister {
175
196
  }
176
197
  async persistManagedEntitiesBatch(meta, changeSets, options) {
177
198
  await this.checkOptimisticLocks(meta, changeSets, options);
178
- options = this.propagateSchemaFromMetadata(meta, options, {
199
+ options = this.prepareOptions(meta, options, {
179
200
  convertCustomTypes: false,
180
201
  processCollections: false,
181
202
  });
@@ -187,7 +208,7 @@ export class ChangeSetPersister {
187
208
  cond.push(where);
188
209
  payload.push(changeSet.payload);
189
210
  }
190
- const res = await this.driver.nativeUpdateMany(meta.className, cond, payload, options);
211
+ const res = await this.driver.nativeUpdateMany(meta.class, cond, payload, options);
191
212
  const map = new Map();
192
213
  res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
193
214
  for (const changeSet of changeSets) {
@@ -235,17 +256,17 @@ export class ChangeSetPersister {
235
256
  }
236
257
  async updateEntity(meta, changeSet, options) {
237
258
  const cond = changeSet.getPrimaryKey(true);
238
- options = this.propagateSchemaFromMetadata(meta, options, {
259
+ options = this.prepareOptions(meta, options, {
239
260
  convertCustomTypes: false,
240
261
  });
241
262
  if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
242
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
263
+ return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
243
264
  }
244
265
  if (meta.versionProperty) {
245
266
  cond[meta.versionProperty] = this.platform.quoteVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
246
267
  }
247
268
  this.checkConcurrencyKeys(meta, changeSet, cond);
248
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
269
+ return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
249
270
  }
250
271
  async checkOptimisticLocks(meta, changeSets, options) {
251
272
  if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
@@ -262,10 +283,10 @@ export class ChangeSetPersister {
262
283
  return cond;
263
284
  });
264
285
  const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
265
- options = this.propagateSchemaFromMetadata(meta, options, {
286
+ options = this.prepareOptions(meta, options, {
266
287
  fields: primaryKeys,
267
288
  });
268
- const res = await this.driver.find(meta.root.className, { $or }, options);
289
+ const res = await this.driver.find(meta.root.class, { $or }, options);
269
290
  if (res.length !== changeSets.length) {
270
291
  const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
271
292
  const entity = changeSets.find(cs => {
@@ -286,11 +307,22 @@ export class ChangeSetPersister {
286
307
  async reloadVersionValues(meta, changeSets, options) {
287
308
  const reloadProps = meta.versionProperty && !this.usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
288
309
  if (changeSets[0].type === ChangeSetType.CREATE) {
289
- // do not reload things that already had a runtime value
290
- meta.props
291
- .filter(prop => prop.persist !== false && (prop.autoincrement || prop.generated || prop.defaultRaw))
292
- .filter(prop => (changeSets[0].entity[prop.name] == null && prop.defaultRaw !== 'null') || isRaw(changeSets[0].entity[prop.name]))
293
- .forEach(prop => reloadProps.push(prop));
310
+ for (const prop of meta.props) {
311
+ if (prop.persist === false) {
312
+ continue;
313
+ }
314
+ if (isRaw(changeSets[0].entity[prop.name])) {
315
+ reloadProps.push(prop);
316
+ continue;
317
+ }
318
+ // do not reload things that already had a runtime value
319
+ if (changeSets[0].entity[prop.name] != null || prop.defaultRaw === 'null') {
320
+ continue;
321
+ }
322
+ if (prop.autoincrement || prop.generated || prop.defaultRaw) {
323
+ reloadProps.push(prop);
324
+ }
325
+ }
294
326
  }
295
327
  if (changeSets[0].type === ChangeSetType.UPDATE) {
296
328
  const returning = new Set();
@@ -321,12 +353,12 @@ export class ChangeSetPersister {
321
353
  }
322
354
  return val;
323
355
  });
324
- options = this.propagateSchemaFromMetadata(meta, options, {
356
+ options = this.prepareOptions(meta, options, {
325
357
  fields: Utils.unique(reloadProps.map(prop => prop.name)),
326
358
  });
327
- 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);
328
360
  const map = new Map();
329
- data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
361
+ data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
330
362
  for (const changeSet of changeSets) {
331
363
  const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
332
364
  this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
@@ -334,7 +366,7 @@ export class ChangeSetPersister {
334
366
  }
335
367
  }
336
368
  processProperty(changeSet, prop) {
337
- const meta = this.metadata.find(changeSet.name);
369
+ const meta = changeSet.meta;
338
370
  const value = changeSet.payload[prop.name]; // for inline embeddables
339
371
  if (value instanceof EntityIdentifier) {
340
372
  changeSet.payload[prop.name] = value.getValue();
@@ -367,7 +399,7 @@ export class ChangeSetPersister {
367
399
  if ((!this.usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
368
400
  return;
369
401
  }
370
- const mapped = this.comparator.mapResult(meta.className, row);
402
+ const mapped = this.comparator.mapResult(meta, row);
371
403
  if (entity) {
372
404
  this.hydrator.hydrate(entity, meta, mapped, this.factory, 'full', false, true);
373
405
  }