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

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 (211) hide show
  1. package/EntityManager.d.ts +99 -57
  2. package/EntityManager.js +302 -276
  3. package/MikroORM.d.ts +44 -35
  4. package/MikroORM.js +103 -143
  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 +80 -35
  16. package/drivers/IDatabaseDriver.d.ts +44 -17
  17. package/entity/BaseEntity.d.ts +2 -2
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +94 -29
  20. package/entity/Collection.js +434 -97
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +13 -1
  24. package/entity/EntityFactory.js +84 -53
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +35 -15
  27. package/entity/EntityLoader.d.ts +6 -6
  28. package/entity/EntityLoader.js +119 -82
  29. package/entity/EntityRepository.d.ts +24 -4
  30. package/entity/EntityRepository.js +8 -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 +594 -0
  36. package/entity/defineEntity.js +533 -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 -5
  44. package/enums.js +15 -1
  45. package/errors.d.ts +23 -9
  46. package/errors.js +59 -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 +52 -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 +40 -23
  64. package/metadata/EntitySchema.js +81 -34
  65. package/metadata/MetadataDiscovery.d.ts +7 -10
  66. package/metadata/MetadataDiscovery.js +391 -331
  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 +17 -9
  72. package/metadata/MetadataValidator.js +97 -40
  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 +502 -0
  78. package/metadata/types.js +1 -0
  79. package/naming-strategy/AbstractNamingStrategy.d.ts +12 -4
  80. package/naming-strategy/AbstractNamingStrategy.js +14 -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 +24 -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 +18 -11
  91. package/platforms/ExceptionConverter.js +1 -1
  92. package/platforms/Platform.d.ts +7 -13
  93. package/platforms/Platform.js +20 -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 +290 -137
  120. package/typings.js +59 -44
  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 +26 -13
  125. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  126. package/unit-of-work/ChangeSetPersister.js +70 -34
  127. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  128. package/unit-of-work/CommitOrderCalculator.js +13 -13
  129. package/unit-of-work/IdentityMap.d.ts +12 -0
  130. package/unit-of-work/IdentityMap.js +39 -1
  131. package/unit-of-work/UnitOfWork.d.ts +23 -3
  132. package/unit-of-work/UnitOfWork.js +175 -98
  133. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  134. package/utils/AbstractSchemaGenerator.js +18 -16
  135. package/utils/AsyncContext.d.ts +6 -0
  136. package/utils/AsyncContext.js +42 -0
  137. package/utils/Configuration.d.ts +785 -207
  138. package/utils/Configuration.js +147 -190
  139. package/utils/ConfigurationLoader.d.ts +1 -54
  140. package/utils/ConfigurationLoader.js +1 -352
  141. package/utils/Cursor.d.ts +0 -3
  142. package/utils/Cursor.js +27 -11
  143. package/utils/DataloaderUtils.d.ts +15 -5
  144. package/utils/DataloaderUtils.js +64 -30
  145. package/utils/EntityComparator.d.ts +13 -9
  146. package/utils/EntityComparator.js +101 -42
  147. package/utils/QueryHelper.d.ts +14 -6
  148. package/utils/QueryHelper.js +87 -25
  149. package/utils/RawQueryFragment.d.ts +48 -25
  150. package/utils/RawQueryFragment.js +66 -70
  151. package/utils/RequestContext.js +2 -2
  152. package/utils/TransactionContext.js +2 -2
  153. package/utils/TransactionManager.d.ts +65 -0
  154. package/utils/TransactionManager.js +223 -0
  155. package/utils/Utils.d.ts +13 -126
  156. package/utils/Utils.js +100 -391
  157. package/utils/clone.js +8 -23
  158. package/utils/env-vars.d.ts +7 -0
  159. package/utils/env-vars.js +97 -0
  160. package/utils/fs-utils.d.ts +32 -0
  161. package/utils/fs-utils.js +178 -0
  162. package/utils/index.d.ts +2 -1
  163. package/utils/index.js +2 -1
  164. package/utils/upsert-utils.d.ts +9 -4
  165. package/utils/upsert-utils.js +55 -4
  166. package/decorators/Check.d.ts +0 -3
  167. package/decorators/Check.js +0 -13
  168. package/decorators/CreateRequestContext.d.ts +0 -3
  169. package/decorators/CreateRequestContext.js +0 -32
  170. package/decorators/Embeddable.d.ts +0 -8
  171. package/decorators/Embeddable.js +0 -11
  172. package/decorators/Embedded.d.ts +0 -12
  173. package/decorators/Embedded.js +0 -18
  174. package/decorators/Entity.d.ts +0 -18
  175. package/decorators/Entity.js +0 -12
  176. package/decorators/Enum.d.ts +0 -9
  177. package/decorators/Enum.js +0 -16
  178. package/decorators/Filter.d.ts +0 -2
  179. package/decorators/Filter.js +0 -8
  180. package/decorators/Formula.d.ts +0 -4
  181. package/decorators/Formula.js +0 -15
  182. package/decorators/Indexed.d.ts +0 -19
  183. package/decorators/Indexed.js +0 -20
  184. package/decorators/ManyToMany.d.ts +0 -40
  185. package/decorators/ManyToMany.js +0 -14
  186. package/decorators/ManyToOne.d.ts +0 -32
  187. package/decorators/ManyToOne.js +0 -14
  188. package/decorators/OneToMany.d.ts +0 -28
  189. package/decorators/OneToMany.js +0 -17
  190. package/decorators/OneToOne.d.ts +0 -26
  191. package/decorators/OneToOne.js +0 -7
  192. package/decorators/PrimaryKey.d.ts +0 -8
  193. package/decorators/PrimaryKey.js +0 -20
  194. package/decorators/Property.d.ts +0 -250
  195. package/decorators/Property.js +0 -32
  196. package/decorators/Transactional.d.ts +0 -13
  197. package/decorators/Transactional.js +0 -28
  198. package/decorators/hooks.d.ts +0 -16
  199. package/decorators/hooks.js +0 -47
  200. package/decorators/index.d.ts +0 -17
  201. package/decorators/index.js +0 -17
  202. package/entity/ArrayCollection.d.ts +0 -116
  203. package/entity/ArrayCollection.js +0 -402
  204. package/entity/EntityValidator.d.ts +0 -19
  205. package/entity/EntityValidator.js +0 -150
  206. package/exports.d.ts +0 -24
  207. package/exports.js +0 -23
  208. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  209. package/metadata/ReflectMetadataProvider.js +0 -44
  210. package/utils/resolveContextProvider.d.ts +0 -10
  211. package/utils/resolveContextProvider.js +0 -28
@@ -1,4 +1,3 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks';
2
1
  import { Collection } from '../entity/Collection.js';
3
2
  import { EntityHelper } from '../entity/EntityHelper.js';
4
3
  import { helper } from '../entity/wrap.js';
@@ -13,8 +12,9 @@ import { Cascade, DeferMode, EventType, LockMode, ReferenceKind } from '../enums
13
12
  import { OptimisticLockError, ValidationError } from '../errors.js';
14
13
  import { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
15
14
  import { IdentityMap } from './IdentityMap.js';
15
+ import { createAsyncContext } from '../utils/AsyncContext.js';
16
16
  // to deal with validation for flush inside flush hooks and `Promise.all`
17
- const insideFlush = new AsyncLocalStorage();
17
+ const insideFlush = createAsyncContext();
18
18
  export class UnitOfWork {
19
19
  em;
20
20
  /** map of references to managed entities */
@@ -42,8 +42,8 @@ export class UnitOfWork {
42
42
  this.identityMap = new IdentityMap(this.platform.getDefaultSchemaName());
43
43
  this.eventManager = this.em.getEventManager();
44
44
  this.comparator = this.em.getComparator();
45
- this.changeSetComputer = new ChangeSetComputer(this.em.getValidator(), this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
46
- this.changeSetPersister = new ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.getValidator(), this.em.config);
45
+ this.changeSetComputer = new ChangeSetComputer(this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
46
+ this.changeSetPersister = new ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.config, this.em);
47
47
  }
48
48
  merge(entity, visited) {
49
49
  const wrapped = helper(entity);
@@ -61,10 +61,43 @@ export class UnitOfWork {
61
61
  // as there can be some entity with already changed state that is not yet flushed
62
62
  if (wrapped.__initialized && (!visited || !wrapped.__originalEntityData)) {
63
63
  wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
64
- wrapped.__touched = false;
65
64
  }
66
65
  this.cascade(entity, Cascade.MERGE, visited ?? new Set());
67
66
  }
67
+ /**
68
+ * Entity data can wary in its shape, e.g. we might get a deep relation graph with joined strategy, but for diffing,
69
+ * we need to normalize the shape, so relation values are only raw FKs. This method handles that.
70
+ * @internal
71
+ */
72
+ normalizeEntityData(meta, data) {
73
+ const forceUndefined = this.em.config.get('forceUndefined');
74
+ for (const key of Utils.keys(data)) {
75
+ const prop = meta.properties[key];
76
+ if (!prop) {
77
+ continue;
78
+ }
79
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
80
+ data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
81
+ }
82
+ else if (prop.kind === ReferenceKind.EMBEDDED && !prop.object && Utils.isPlainObject(data[prop.name])) {
83
+ for (const p of prop.targetMeta.props) {
84
+ /* v8 ignore next */
85
+ const prefix = prop.prefix === false ? '' : prop.prefix === true ? prop.name + '_' : prop.prefix;
86
+ data[prefix + p.name] = data[prop.name][p.name];
87
+ }
88
+ data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
89
+ }
90
+ if (prop.hydrate === false && prop.customType?.ensureComparable(meta, prop)) {
91
+ const converted = prop.customType.convertToJSValue(data[key], this.platform, { key, mode: 'hydration', force: true });
92
+ data[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { key, mode: 'hydration' });
93
+ }
94
+ if (forceUndefined) {
95
+ if (data[key] === null) {
96
+ data[key] = undefined;
97
+ }
98
+ }
99
+ }
100
+ }
68
101
  /**
69
102
  * @internal
70
103
  */
@@ -82,31 +115,14 @@ export class UnitOfWork {
82
115
  wrapped.__em ??= this.em;
83
116
  wrapped.__managed = true;
84
117
  if (data && (options?.refresh || !wrapped.__originalEntityData)) {
118
+ this.normalizeEntityData(wrapped.__meta, data);
85
119
  for (const key of Utils.keys(data)) {
86
120
  const prop = wrapped.__meta.properties[key];
87
- if (!prop) {
88
- continue;
89
- }
90
- wrapped.__loadedProperties.add(key);
91
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
92
- data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
93
- }
94
- else if (prop.kind === ReferenceKind.EMBEDDED && !prop.object && Utils.isPlainObject(data[prop.name])) {
95
- for (const p of prop.targetMeta.props) {
96
- /* v8 ignore next */
97
- const prefix = prop.prefix === false ? '' : prop.prefix === true ? prop.name + '_' : prop.prefix;
98
- data[prefix + p.name] = data[prop.name][p.name];
99
- }
100
- data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
101
- }
102
- if (forceUndefined) {
103
- if (data[key] === null) {
104
- data[key] = undefined;
105
- }
121
+ if (prop) {
122
+ wrapped.__loadedProperties.add(key);
106
123
  }
107
124
  }
108
125
  wrapped.__originalEntityData = data;
109
- wrapped.__touched = false;
110
126
  }
111
127
  return entity;
112
128
  }
@@ -125,7 +141,7 @@ export class UnitOfWork {
125
141
  /**
126
142
  * 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`.
127
143
  */
128
- getById(entityName, id, schema) {
144
+ getById(entityName, id, schema, convertCustomTypes) {
129
145
  if (id == null || (Array.isArray(id) && id.length === 0)) {
130
146
  return undefined;
131
147
  }
@@ -135,7 +151,16 @@ export class UnitOfWork {
135
151
  hash = '' + id;
136
152
  }
137
153
  else {
138
- const keys = Array.isArray(id) ? Utils.flatten(id) : [id];
154
+ let keys = Array.isArray(id) ? Utils.flatten(id) : [id];
155
+ keys = meta.getPrimaryProps(true).map((p, i) => {
156
+ if (!convertCustomTypes && p.customType) {
157
+ return p.customType.convertToDatabaseValue(keys[i], this.platform, {
158
+ key: p.name,
159
+ mode: 'hydration',
160
+ });
161
+ }
162
+ return keys[i];
163
+ });
139
164
  hash = Utils.getPrimaryKeyHash(keys);
140
165
  }
141
166
  schema ??= meta.schema ?? this.em.config.getSchema();
@@ -144,6 +169,40 @@ export class UnitOfWork {
144
169
  }
145
170
  return this.identityMap.getByHash(meta, hash);
146
171
  }
172
+ /**
173
+ * Returns entity from the identity map by an alternate key (non-PK property).
174
+ * @param convertCustomTypes - If true, the value is in database format and will be converted to JS format for lookup.
175
+ * If false (default), the value is assumed to be in JS format already.
176
+ */
177
+ getByKey(entityName, key, value, schema, convertCustomTypes) {
178
+ const meta = this.metadata.find(entityName).root;
179
+ schema ??= meta.schema ?? this.em.config.getSchema();
180
+ const prop = meta.properties[key];
181
+ // Convert from DB format to JS format if needed
182
+ if (convertCustomTypes && prop?.customType) {
183
+ value = prop.customType.convertToJSValue(value, this.platform, { mode: 'hydration' });
184
+ }
185
+ const hash = this.identityMap.getKeyHash(key, '' + value, schema);
186
+ return this.identityMap.getByHash(meta, hash);
187
+ }
188
+ /**
189
+ * Stores an entity in the identity map under an alternate key (non-PK property).
190
+ * Also sets the property value on the entity.
191
+ * @param convertCustomTypes - If true, the value is in database format and will be converted to JS format.
192
+ * If false (default), the value is assumed to be in JS format already.
193
+ */
194
+ storeByKey(entity, key, value, schema, convertCustomTypes) {
195
+ const meta = entity.__meta.root;
196
+ schema ??= meta.schema ?? this.em.config.getSchema();
197
+ const prop = meta.properties[key];
198
+ // Convert from DB format to JS format if needed
199
+ if (convertCustomTypes && prop?.customType) {
200
+ value = prop.customType.convertToJSValue(value, this.platform, { mode: 'hydration' });
201
+ }
202
+ // Set the property on the entity
203
+ entity[key] = value;
204
+ this.identityMap.storeByKey(entity, key, '' + value, schema);
205
+ }
147
206
  tryGetById(entityName, where, schema, strict = true) {
148
207
  const pk = Utils.extractPK(where, this.metadata.find(entityName), strict);
149
208
  if (!pk) {
@@ -182,13 +241,11 @@ export class UnitOfWork {
182
241
  if (insideFlush.getStore()) {
183
242
  return false;
184
243
  }
185
- if (this.queuedActions.has(meta.className) || this.queuedActions.has(meta.root.className)) {
244
+ if (this.queuedActions.has(meta.class) || this.queuedActions.has(meta.root.class)) {
186
245
  return true;
187
246
  }
188
- for (const entity of this.identityMap.getStore(meta).values()) {
189
- if (helper(entity).__initialized && helper(entity).isTouched()) {
190
- return true;
191
- }
247
+ if (meta.discriminatorMap && Object.values(meta.discriminatorMap).some(v => this.queuedActions.has(v))) {
248
+ return true;
192
249
  }
193
250
  return false;
194
251
  }
@@ -209,7 +266,6 @@ export class UnitOfWork {
209
266
  this.changeSets.set(entity, cs);
210
267
  this.persistStack.delete(entity);
211
268
  wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
212
- wrapped.__touched = false;
213
269
  }
214
270
  recomputeSingleChangeSet(entity) {
215
271
  const changeSet = this.changeSets.get(entity);
@@ -220,7 +276,6 @@ export class UnitOfWork {
220
276
  if (cs && !this.checkUniqueProps(cs)) {
221
277
  Object.assign(changeSet.payload, cs.payload);
222
278
  helper(entity).__originalEntityData = this.comparator.prepareEntity(entity);
223
- helper(entity).__touched = false;
224
279
  }
225
280
  }
226
281
  persist(entity, visited, options = {}) {
@@ -230,7 +285,7 @@ export class UnitOfWork {
230
285
  }
231
286
  const wrapped = helper(entity);
232
287
  this.persistStack.add(entity);
233
- this.queuedActions.add(wrapped.__meta.className);
288
+ this.queuedActions.add(wrapped.__meta.class);
234
289
  this.removeStack.delete(entity);
235
290
  if (!wrapped.__managed && wrapped.hasPrimaryKey()) {
236
291
  this.identityMap.store(entity);
@@ -243,7 +298,7 @@ export class UnitOfWork {
243
298
  // allow removing not managed entities if they are not part of the persist stack
244
299
  if (helper(entity).__managed || !this.persistStack.has(entity)) {
245
300
  this.removeStack.add(entity);
246
- this.queuedActions.add(helper(entity).__meta.className);
301
+ this.queuedActions.add(helper(entity).__meta.class);
247
302
  }
248
303
  else {
249
304
  this.persistStack.delete(entity);
@@ -303,17 +358,21 @@ export class UnitOfWork {
303
358
  cs.entity.__helper.__processing = true;
304
359
  }
305
360
  await this.eventManager.dispatchEvent(EventType.onFlush, { em: this.em, uow: this });
361
+ this.filterCollectionUpdates();
306
362
  // nothing to do, do not start transaction
307
363
  if (this.changeSets.size === 0 && this.collectionUpdates.size === 0 && this.extraUpdates.size === 0) {
308
- return void (await this.eventManager.dispatchEvent(EventType.afterFlush, { em: this.em, uow: this }));
364
+ await this.eventManager.dispatchEvent(EventType.afterFlush, { em: this.em, uow: this });
365
+ return;
309
366
  }
310
367
  const groups = this.getChangeSetGroups();
311
368
  const platform = this.em.getPlatform();
312
369
  const runInTransaction = !this.em.isInTransaction() && platform.supportsTransactions() && this.em.config.get('implicitTransactions');
313
370
  if (runInTransaction) {
371
+ const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
314
372
  await this.em.getConnection('write').transactional(trx => this.persistToDatabase(groups, trx), {
315
373
  ctx: oldTx,
316
374
  eventBroadcaster: new TransactionEventBroadcaster(this.em),
375
+ loggerContext,
317
376
  });
318
377
  }
319
378
  else {
@@ -330,10 +389,10 @@ export class UnitOfWork {
330
389
  }
331
390
  }
332
391
  async lock(entity, options) {
333
- if (!this.getById(entity.constructor.name, helper(entity).__primaryKeys, helper(entity).__schema)) {
392
+ if (!this.getById(entity.constructor, helper(entity).__primaryKeys, helper(entity).__schema)) {
334
393
  throw ValidationError.entityNotManaged(entity);
335
394
  }
336
- const meta = this.metadata.find(entity.constructor.name);
395
+ const meta = this.metadata.find(entity.constructor);
337
396
  if (options.lockMode === LockMode.OPTIMISTIC) {
338
397
  await this.lockOptimistic(entity, meta, options.lockVersion);
339
398
  }
@@ -357,7 +416,7 @@ export class UnitOfWork {
357
416
  if (Utils.isCollection(rel)) {
358
417
  rel.removeWithoutPropagation(entity);
359
418
  }
360
- else if (rel && (prop.mapToPk ? helper(this.em.getReference(prop.type, rel)).getSerializedPrimaryKey() === serializedPK : rel === entity)) {
419
+ else if (rel && (prop.mapToPk ? helper(this.em.getReference(prop.targetMeta.class, rel)).getSerializedPrimaryKey() === serializedPK : rel === entity)) {
361
420
  if (prop.formula) {
362
421
  delete referrer[prop.name];
363
422
  }
@@ -369,7 +428,6 @@ export class UnitOfWork {
369
428
  }
370
429
  delete wrapped.__identifier;
371
430
  delete wrapped.__originalEntityData;
372
- wrapped.__touched = false;
373
431
  wrapped.__managed = false;
374
432
  }
375
433
  computeChangeSets() {
@@ -379,14 +437,14 @@ export class UnitOfWork {
379
437
  this.cascade(entity, Cascade.REMOVE, visited);
380
438
  }
381
439
  visited.clear();
382
- for (const entity of this.persistStack) {
383
- this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack: true });
384
- }
385
440
  for (const entity of this.identityMap) {
386
441
  if (!this.removeStack.has(entity) && !this.persistStack.has(entity) && !this.orphanRemoveStack.has(entity)) {
387
442
  this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack: true });
388
443
  }
389
444
  }
445
+ for (const entity of this.persistStack) {
446
+ this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack: true });
447
+ }
390
448
  visited.clear();
391
449
  for (const entity of this.persistStack) {
392
450
  this.findNewEntities(entity, visited);
@@ -400,24 +458,24 @@ export class UnitOfWork {
400
458
  const inserts = {};
401
459
  for (const cs of this.changeSets.values()) {
402
460
  if (cs.type === ChangeSetType.CREATE) {
403
- inserts[cs.meta.className] ??= [];
404
- inserts[cs.meta.className].push(cs);
461
+ inserts[cs.meta.uniqueName] ??= [];
462
+ inserts[cs.meta.uniqueName].push(cs);
405
463
  }
406
464
  }
407
465
  for (const cs of this.changeSets.values()) {
408
466
  if (cs.type === ChangeSetType.UPDATE) {
409
- this.findEarlyUpdates(cs, inserts[cs.meta.className]);
467
+ this.findEarlyUpdates(cs, inserts[cs.meta.uniqueName]);
410
468
  }
411
469
  }
412
470
  for (const entity of this.removeStack) {
413
471
  const wrapped = helper(entity);
414
- /* v8 ignore next 3 */
472
+ /* v8 ignore next */
415
473
  if (wrapped.__processing) {
416
474
  continue;
417
475
  }
418
476
  const deletePkHash = [wrapped.getSerializedPrimaryKey(), ...this.expandUniqueProps(entity)];
419
477
  let type = ChangeSetType.DELETE;
420
- for (const cs of inserts[wrapped.__meta.className] ?? []) {
478
+ for (const cs of inserts[wrapped.__meta.uniqueName] ?? []) {
421
479
  if (deletePkHash.some(hash => hash === cs.getSerializedPrimaryKey() || this.expandUniqueProps(cs.entity).find(child => hash === child))) {
422
480
  type = ChangeSetType.DELETE_EARLY;
423
481
  }
@@ -436,7 +494,7 @@ export class UnitOfWork {
436
494
  }
437
495
  for (const cs of this.changeSets.values()) {
438
496
  for (const prop of props) {
439
- if (prop.name in cs.payload && cs.rootName === changeSet.rootName && cs.type === changeSet.type) {
497
+ if (prop.name in cs.payload && cs.rootMeta === changeSet.rootMeta && cs.type === changeSet.type) {
440
498
  conflicts = true;
441
499
  if (changeSet.payload[prop.name] == null) {
442
500
  type = ChangeSetType.UPDATE_EARLY;
@@ -455,9 +513,10 @@ export class UnitOfWork {
455
513
  }
456
514
  scheduleOrphanRemoval(entity, visited) {
457
515
  if (entity) {
458
- helper(entity).__em = this.em;
516
+ const wrapped = helper(entity);
517
+ wrapped.__em = this.em;
459
518
  this.orphanRemoveStack.add(entity);
460
- this.queuedActions.add(entity.__meta.className);
519
+ this.queuedActions.add(wrapped.__meta.class);
461
520
  this.cascade(entity, Cascade.SCHEDULE_ORPHAN_REMOVAL, visited);
462
521
  }
463
522
  }
@@ -606,7 +665,7 @@ export class UnitOfWork {
606
665
  const copy = this.comparator.prepareEntity(changeSet.entity);
607
666
  await this.eventManager.dispatchEvent(type, { entity: changeSet.entity, meta, em: this.em, changeSet });
608
667
  const current = this.comparator.prepareEntity(changeSet.entity);
609
- const diff = this.comparator.diffEntities(changeSet.name, copy, current);
668
+ const diff = this.comparator.diffEntities(changeSet.meta.class, copy, current);
610
669
  Object.assign(changeSet.payload, diff);
611
670
  const wrapped = helper(changeSet.entity);
612
671
  if (wrapped.__identifier) {
@@ -701,7 +760,7 @@ export class UnitOfWork {
701
760
  if (!meta.versionProperty) {
702
761
  throw OptimisticLockError.notVersioned(meta);
703
762
  }
704
- if (!Utils.isDefined(version)) {
763
+ if (typeof version === 'undefined') {
705
764
  return;
706
765
  }
707
766
  const wrapped = helper(entity);
@@ -715,26 +774,26 @@ export class UnitOfWork {
715
774
  }
716
775
  fixMissingReference(entity, prop) {
717
776
  const reference = entity[prop.name];
718
- const kind = Reference.unwrapReference(reference);
719
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && kind && !prop.mapToPk) {
720
- if (!Utils.isEntity(kind)) {
721
- entity[prop.name] = this.em.getReference(prop.type, kind, { wrapped: !!prop.ref });
777
+ const target = Reference.unwrapReference(reference);
778
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && target && !prop.mapToPk) {
779
+ if (!Utils.isEntity(target)) {
780
+ entity[prop.name] = this.em.getReference(prop.targetMeta.class, target, { wrapped: !!prop.ref });
722
781
  }
723
- else if (!helper(kind).__initialized && !helper(kind).__em) {
724
- const pk = helper(kind).getPrimaryKey();
725
- entity[prop.name] = this.em.getReference(prop.type, pk, { wrapped: !!prop.ref });
782
+ else if (!helper(target).__initialized && !helper(target).__em) {
783
+ const pk = helper(target).getPrimaryKey();
784
+ entity[prop.name] = this.em.getReference(prop.targetMeta.class, pk, { wrapped: !!prop.ref });
726
785
  }
727
786
  }
728
- // perf: set the `Collection._property` to skip the getter, as it can be slow when there is a lot of relations
729
- if (Utils.isCollection(kind)) {
730
- kind.property = prop;
787
+ // perf: set the `Collection._property` to skip the getter, as it can be slow when there are a lot of relations
788
+ if (Utils.isCollection(target)) {
789
+ target.property = prop;
731
790
  }
732
791
  const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
733
- if (isCollection && Array.isArray(kind)) {
792
+ if (isCollection && Array.isArray(target)) {
734
793
  const collection = new Collection(entity);
735
794
  collection.property = prop;
736
795
  entity[prop.name] = collection;
737
- collection.set(kind);
796
+ collection.set(target);
738
797
  }
739
798
  }
740
799
  async persistToDatabase(groups, ctx) {
@@ -744,30 +803,30 @@ export class UnitOfWork {
744
803
  const commitOrder = this.getCommitOrder();
745
804
  const commitOrderReversed = [...commitOrder].reverse();
746
805
  // early delete - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
747
- for (const name of commitOrderReversed) {
748
- await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE_EARLY].get(name) ?? [], ctx);
806
+ for (const meta of commitOrderReversed) {
807
+ await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE_EARLY].get(meta) ?? [], ctx);
749
808
  }
750
809
  // early update - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
751
- for (const name of commitOrder) {
752
- await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE_EARLY].get(name) ?? [], ctx);
810
+ for (const meta of commitOrder) {
811
+ await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE_EARLY].get(meta) ?? [], ctx);
753
812
  }
754
813
  // extra updates
755
814
  await this.commitExtraUpdates(ChangeSetType.UPDATE_EARLY, ctx);
756
815
  // create
757
- for (const name of commitOrder) {
758
- await this.commitCreateChangeSets(groups[ChangeSetType.CREATE].get(name) ?? [], ctx);
816
+ for (const meta of commitOrder) {
817
+ await this.commitCreateChangeSets(groups[ChangeSetType.CREATE].get(meta) ?? [], ctx);
759
818
  }
760
819
  // update
761
- for (const name of commitOrder) {
762
- await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE].get(name) ?? [], ctx);
820
+ for (const meta of commitOrder) {
821
+ await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE].get(meta) ?? [], ctx);
763
822
  }
764
823
  // extra updates
765
824
  await this.commitExtraUpdates(ChangeSetType.UPDATE, ctx);
766
825
  // collection updates
767
826
  await this.commitCollectionUpdates(ctx);
768
827
  // delete - entity deletions need to be in reverse commit order
769
- for (const name of commitOrderReversed) {
770
- await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE].get(name) ?? [], ctx);
828
+ for (const meta of commitOrderReversed) {
829
+ await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE].get(meta) ?? [], ctx);
771
830
  }
772
831
  // take snapshots of all persisted collections
773
832
  const visited = new Set();
@@ -803,7 +862,7 @@ export class UnitOfWork {
803
862
  if (Utils.isCollection(ref)) {
804
863
  ref.getItems(false).some(item => {
805
864
  const cs = this.changeSets.get(Reference.unwrapReference(item));
806
- const isScheduledForInsert = cs && cs.type === ChangeSetType.CREATE && !cs.persisted;
865
+ const isScheduledForInsert = cs?.type === ChangeSetType.CREATE && !cs.persisted;
807
866
  if (isScheduledForInsert) {
808
867
  this.scheduleExtraUpdate(changeSet, [prop]);
809
868
  return true;
@@ -812,7 +871,7 @@ export class UnitOfWork {
812
871
  });
813
872
  }
814
873
  const cs = this.changeSets.get(Reference.unwrapReference(ref));
815
- const isScheduledForInsert = cs && cs.type === ChangeSetType.CREATE && !cs.persisted;
874
+ const isScheduledForInsert = cs?.type === ChangeSetType.CREATE && !cs.persisted;
816
875
  if (isScheduledForInsert) {
817
876
  this.scheduleExtraUpdate(changeSet, [prop]);
818
877
  }
@@ -841,9 +900,16 @@ export class UnitOfWork {
841
900
  }
842
901
  await this.changeSetPersister.executeUpdates(changeSets, batched, { ctx });
843
902
  for (const changeSet of changeSets) {
844
- helper(changeSet.entity).__originalEntityData = this.comparator.prepareEntity(changeSet.entity);
845
- helper(changeSet.entity).__touched = false;
846
- helper(changeSet.entity).__initialized = true;
903
+ const wrapped = helper(changeSet.entity);
904
+ wrapped.__originalEntityData = this.comparator.prepareEntity(changeSet.entity);
905
+ if (!wrapped.__initialized) {
906
+ for (const prop of changeSet.meta.relations) {
907
+ if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind) && changeSet.entity[prop.name] == null) {
908
+ changeSet.entity[prop.name] = Collection.create(changeSet.entity, prop.name, undefined, wrapped.isInitialized());
909
+ }
910
+ }
911
+ wrapped.__initialized = true;
912
+ }
847
913
  await this.runHooks(EventType.afterUpdate, changeSet);
848
914
  }
849
915
  }
@@ -886,23 +952,34 @@ export class UnitOfWork {
886
952
  }
887
953
  }
888
954
  async commitCollectionUpdates(ctx) {
889
- const collectionUpdates = [];
955
+ this.filterCollectionUpdates();
956
+ const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
957
+ await this.em.getDriver().syncCollections(this.collectionUpdates, {
958
+ ctx,
959
+ schema: this.em.schema,
960
+ loggerContext,
961
+ });
890
962
  for (const coll of this.collectionUpdates) {
963
+ coll.takeSnapshot();
964
+ }
965
+ }
966
+ filterCollectionUpdates() {
967
+ for (const coll of this.collectionUpdates) {
968
+ let skip = true;
891
969
  if (coll.property.owner || coll.getItems(false).filter(item => !item.__helper.__initialized).length > 0) {
892
970
  if (this.platform.usesPivotTable()) {
893
- collectionUpdates.push(coll);
971
+ skip = false;
894
972
  }
895
973
  }
896
974
  else if (coll.property.kind === ReferenceKind.ONE_TO_MANY && coll.getSnapshot() === undefined) {
897
- collectionUpdates.push(coll);
975
+ skip = false;
898
976
  }
899
977
  else if (coll.property.kind === ReferenceKind.MANY_TO_MANY && !coll.property.owner) {
900
- collectionUpdates.push(coll);
978
+ skip = false;
979
+ }
980
+ if (skip) {
981
+ this.collectionUpdates.delete(coll);
901
982
  }
902
- }
903
- await this.em.getDriver().syncCollections(collectionUpdates, { ctx, schema: this.em.schema });
904
- for (const coll of this.collectionUpdates) {
905
- coll.takeSnapshot();
906
983
  }
907
984
  }
908
985
  /**
@@ -918,10 +995,10 @@ export class UnitOfWork {
918
995
  };
919
996
  for (const cs of this.changeSets.values()) {
920
997
  const group = groups[cs.type];
921
- const classGroup = group.get(cs.rootName) ?? [];
998
+ const classGroup = group.get(cs.rootMeta) ?? [];
922
999
  classGroup.push(cs);
923
- if (!group.has(cs.rootName)) {
924
- group.set(cs.rootName, classGroup);
1000
+ if (!group.has(cs.rootMeta)) {
1001
+ group.set(cs.rootMeta, classGroup);
925
1002
  }
926
1003
  }
927
1004
  return groups;
@@ -929,14 +1006,14 @@ export class UnitOfWork {
929
1006
  getCommitOrder() {
930
1007
  const calc = new CommitOrderCalculator();
931
1008
  const set = new Set();
932
- this.changeSets.forEach(cs => set.add(cs.rootName));
933
- set.forEach(entityName => calc.addNode(entityName));
934
- for (const entityName of set) {
935
- for (const prop of this.metadata.find(entityName).props) {
936
- calc.discoverProperty(prop, entityName);
1009
+ this.changeSets.forEach(cs => set.add(cs.rootMeta));
1010
+ set.forEach(meta => calc.addNode(meta._id));
1011
+ for (const meta of set) {
1012
+ for (const prop of meta.relations) {
1013
+ calc.discoverProperty(prop, meta._id);
937
1014
  }
938
1015
  }
939
- return calc.sort();
1016
+ return calc.sort().map(id => this.metadata.getById(id));
940
1017
  }
941
1018
  resetTransaction(oldTx) {
942
1019
  if (oldTx) {
@@ -10,18 +10,18 @@ export declare abstract class AbstractSchemaGenerator<D extends IDatabaseDriver>
10
10
  protected readonly platform: ReturnType<D['getPlatform']>;
11
11
  protected readonly connection: ReturnType<D['getConnection']>;
12
12
  constructor(em: D | D[typeof EntityManagerType]);
13
- createSchema(options?: CreateSchemaOptions): Promise<void>;
13
+ create(options?: CreateSchemaOptions): Promise<void>;
14
14
  /**
15
15
  * Returns true if the database was created.
16
16
  */
17
17
  ensureDatabase(options?: EnsureDatabaseOptions): Promise<boolean>;
18
- refreshDatabase(options?: RefreshDatabaseOptions): Promise<void>;
19
- clearDatabase(options?: ClearDatabaseOptions): Promise<void>;
18
+ refresh(options?: RefreshDatabaseOptions): Promise<void>;
19
+ clear(options?: ClearDatabaseOptions): Promise<void>;
20
20
  protected clearIdentityMap(): void;
21
21
  getCreateSchemaSQL(options?: CreateSchemaOptions): Promise<string>;
22
- dropSchema(options?: DropSchemaOptions): Promise<void>;
22
+ drop(options?: DropSchemaOptions): Promise<void>;
23
23
  getDropSchemaSQL(options?: Omit<DropSchemaOptions, 'dropDb'>): Promise<string>;
24
- updateSchema(options?: UpdateSchemaOptions): Promise<void>;
24
+ update(options?: UpdateSchemaOptions): Promise<void>;
25
25
  getUpdateSchemaSQL(options?: UpdateSchemaOptions): Promise<string>;
26
26
  getUpdateSchemaMigrationSQL(options?: UpdateSchemaOptions): Promise<{
27
27
  up: string;
@@ -15,7 +15,7 @@ export class AbstractSchemaGenerator {
15
15
  this.platform = this.driver.getPlatform();
16
16
  this.connection = this.driver.getConnection();
17
17
  }
18
- async createSchema(options) {
18
+ async create(options) {
19
19
  this.notImplemented();
20
20
  }
21
21
  /**
@@ -24,7 +24,7 @@ export class AbstractSchemaGenerator {
24
24
  async ensureDatabase(options) {
25
25
  this.notImplemented();
26
26
  }
27
- async refreshDatabase(options) {
27
+ async refresh(options) {
28
28
  if (options?.dropDb) {
29
29
  const name = this.config.get('dbName');
30
30
  await this.dropDatabase(name);
@@ -32,20 +32,22 @@ export class AbstractSchemaGenerator {
32
32
  }
33
33
  else {
34
34
  await this.ensureDatabase();
35
- await this.dropSchema(options);
35
+ await this.drop(options);
36
36
  }
37
37
  if (options?.createSchema !== false) {
38
- await this.createSchema(options);
38
+ await this.create(options);
39
39
  }
40
40
  }
41
- async clearDatabase(options) {
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
+ }
45
+ if (options?.clearIdentityMap ?? true) {
46
+ this.clearIdentityMap();
44
47
  }
45
- this.clearIdentityMap();
46
48
  }
47
49
  clearIdentityMap() {
48
- /* v8 ignore next 3 */
50
+ /* v8 ignore next */
49
51
  if (!this.em) {
50
52
  return;
51
53
  }
@@ -57,13 +59,13 @@ export class AbstractSchemaGenerator {
57
59
  async getCreateSchemaSQL(options) {
58
60
  this.notImplemented();
59
61
  }
60
- async dropSchema(options) {
62
+ async drop(options) {
61
63
  this.notImplemented();
62
64
  }
63
65
  async getDropSchemaSQL(options) {
64
66
  this.notImplemented();
65
67
  }
66
- async updateSchema(options) {
68
+ async update(options) {
67
69
  this.notImplemented();
68
70
  }
69
71
  async getUpdateSchemaSQL(options) {
@@ -88,21 +90,21 @@ export class AbstractSchemaGenerator {
88
90
  this.notImplemented();
89
91
  }
90
92
  getOrderedMetadata(schema) {
91
- const metadata = Object.values(this.metadata.getAll()).filter(meta => {
92
- const isRootEntity = meta.root.className === meta.className;
93
+ const metadata = [...this.metadata.getAll().values()].filter(meta => {
94
+ const isRootEntity = meta.root.class === meta.class;
93
95
  return isRootEntity && !meta.embeddable && !meta.virtual;
94
96
  });
95
97
  const calc = new CommitOrderCalculator();
96
- metadata.forEach(meta => calc.addNode(meta.root.className));
98
+ metadata.forEach(meta => calc.addNode(meta.root._id));
97
99
  let meta = metadata.pop();
98
100
  while (meta) {
99
- for (const prop of meta.props) {
100
- calc.discoverProperty(prop, meta.root.className);
101
+ for (const prop of meta.relations) {
102
+ calc.discoverProperty(prop, meta.root._id);
101
103
  }
102
104
  meta = metadata.pop();
103
105
  }
104
106
  return calc.sort()
105
- .map(cls => this.metadata.find(cls))
107
+ .map(cls => this.metadata.getById(cls))
106
108
  .filter(meta => {
107
109
  const targetSchema = meta.schema ?? this.config.get('schema', this.platform.getDefaultSchemaName());
108
110
  return schema ? [schema, '*'].includes(targetSchema) : meta.schema !== '*';