@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
@@ -1,12 +1,11 @@
1
- import { inspect } from 'node:util';
2
1
  import { Collection } from './Collection.js';
3
2
  import { Utils } from '../utils/Utils.js';
4
3
  import { Reference } from './Reference.js';
5
4
  import { ReferenceKind, SCALAR_TYPES } from '../enums.js';
6
- import { EntityValidator } from './EntityValidator.js';
5
+ import { validateProperty } from './validators.js';
7
6
  import { helper, wrap } from './wrap.js';
8
7
  import { EntityHelper } from './EntityHelper.js';
9
- const validator = new EntityValidator(false);
8
+ import { ValidationError } from '../errors.js';
10
9
  export class EntityAssigner {
11
10
  static assign(entity, data, options = {}) {
12
11
  let opts = options;
@@ -42,9 +41,17 @@ export class EntityAssigner {
42
41
  }
43
42
  const prop = { ...props[propName], name: propName };
44
43
  if (prop && options.onlyOwnProperties) {
45
- if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
44
+ if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
46
45
  return;
47
46
  }
47
+ if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
48
+ if (!prop.owner) {
49
+ return;
50
+ }
51
+ else if (value?.map) {
52
+ value = value.map((v) => Utils.extractPK(v, prop.targetMeta));
53
+ }
54
+ }
48
55
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
49
56
  value = Utils.extractPK(value, prop.targetMeta);
50
57
  }
@@ -70,7 +77,7 @@ export class EntityAssigner {
70
77
  if (options.updateByPrimaryKey) {
71
78
  const pk = Utils.extractPK(value, prop.targetMeta);
72
79
  if (pk) {
73
- const ref = options.em.getReference(prop.type, pk, options);
80
+ const ref = options.em.getReference(prop.targetMeta.class, pk, options);
74
81
  // if the PK differs, we want to change the target entity, not update it
75
82
  const wrappedChild = helper(ref);
76
83
  const sameTarget = wrappedChild.getSerializedPrimaryKey() === wrapped.getSerializedPrimaryKey();
@@ -86,8 +93,9 @@ export class EntityAssigner {
86
93
  }
87
94
  return EntityAssigner.assignReference(entity, value, prop, options.em, options);
88
95
  }
89
- if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.includes(prop.runtimeType) && (prop.setter || !prop.getter)) {
90
- return entity[prop.name] = validator.validateProperty(prop, value, entity);
96
+ if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && (prop.setter || !prop.getter)) {
97
+ validateProperty(prop, value, entity);
98
+ return entity[prop.name] = value;
91
99
  }
92
100
  if (prop.kind === ReferenceKind.EMBEDDED && EntityAssigner.validateEM(options.em)) {
93
101
  return EntityAssigner.assignEmbeddable(entity, value, prop, options.em, options);
@@ -112,7 +120,7 @@ export class EntityAssigner {
112
120
  }
113
121
  const meta2 = helper(ref).__meta;
114
122
  const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
115
- /* v8 ignore next 7 */
123
+ /* v8 ignore next */
116
124
  if (prop2 && !ref[prop2.name]) {
117
125
  if (Reference.isReference(ref)) {
118
126
  ref.unwrap()[prop2.name] = Reference.wrapReference(entity, prop2);
@@ -133,13 +141,13 @@ export class EntityAssigner {
133
141
  entity[prop.name] = Reference.wrapReference(value, prop);
134
142
  }
135
143
  else if (Utils.isPrimaryKey(value, true) && EntityAssigner.validateEM(em)) {
136
- entity[prop.name] = prop.mapToPk ? value : Reference.wrapReference(em.getReference(prop.type, value, options), prop);
144
+ entity[prop.name] = prop.mapToPk ? value : Reference.wrapReference(em.getReference(prop.targetMeta.class, value, options), prop);
137
145
  }
138
146
  else if (Utils.isPlainObject(value) && options.merge && EntityAssigner.validateEM(em)) {
139
- entity[prop.name] = Reference.wrapReference(em.merge(prop.type, value, options), prop);
147
+ entity[prop.name] = Reference.wrapReference(em.merge(prop.targetMeta.class, value, options), prop);
140
148
  }
141
149
  else if (Utils.isPlainObject(value) && EntityAssigner.validateEM(em)) {
142
- entity[prop.name] = Reference.wrapReference(em.create(prop.type, value, options), prop);
150
+ entity[prop.name] = Reference.wrapReference(em.create(prop.targetMeta.class, value, options), prop);
143
151
  }
144
152
  else {
145
153
  const name = entity.constructor.name;
@@ -158,14 +166,14 @@ export class EntityAssigner {
158
166
  if (options.updateNestedEntities && options.updateByPrimaryKey && Utils.isPlainObject(item)) {
159
167
  const pk = Utils.extractPK(item, prop.targetMeta);
160
168
  if (pk && EntityAssigner.validateEM(em)) {
161
- const ref = em.getUnitOfWork().getById(prop.type, pk, options.schema);
169
+ const ref = em.getUnitOfWork().getById(prop.targetMeta.class, pk, options.schema);
162
170
  if (ref) {
163
171
  return EntityAssigner.assign(ref, item, options);
164
172
  }
165
173
  }
166
174
  return this.createCollectionItem(item, em, prop, invalid, options);
167
175
  }
168
- /* v8 ignore next 3 */
176
+ /* v8 ignore next */
169
177
  if (options.updateNestedEntities && !options.updateByPrimaryKey && collection[idx] && helper(collection[idx])?.isInitialized()) {
170
178
  return EntityAssigner.assign(collection[idx], item, options);
171
179
  }
@@ -173,7 +181,7 @@ export class EntityAssigner {
173
181
  });
174
182
  if (invalid.length > 0) {
175
183
  const name = entity.constructor.name;
176
- throw new Error(`Invalid collection values provided for '${name}.${prop.name}' in ${name}.assign(): ${inspect(invalid)}`);
184
+ throw ValidationError.invalidCollectionValues(name, prop.name, invalid);
177
185
  }
178
186
  if (Array.isArray(value)) {
179
187
  collection.set(items);
@@ -199,7 +207,7 @@ export class EntityAssigner {
199
207
  entity[propName].push(...Object.values(tmp));
200
208
  });
201
209
  }
202
- const create = () => EntityAssigner.validateEM(em) && em.getEntityFactory().createEmbeddable(prop.type, value, {
210
+ const create = () => EntityAssigner.validateEM(em) && em.getEntityFactory().createEmbeddable(prop.targetMeta.class, value, {
203
211
  convertCustomTypes: options.convertCustomTypes,
204
212
  newEntity: options.mergeEmbeddedProperties ? !('propName' in entity) : true,
205
213
  });
@@ -213,13 +221,13 @@ export class EntityAssigner {
213
221
  return item;
214
222
  }
215
223
  if (Utils.isPrimaryKey(item) && EntityAssigner.validateEM(em)) {
216
- return em.getReference(prop.type, item, options);
224
+ return em.getReference(prop.targetMeta.class, item, options);
217
225
  }
218
226
  if (Utils.isPlainObject(item) && options.merge && EntityAssigner.validateEM(em)) {
219
- return em.merge(prop.type, item, options);
227
+ return em.merge(prop.targetMeta.class, item, options);
220
228
  }
221
229
  if (Utils.isPlainObject(item) && EntityAssigner.validateEM(em)) {
222
- return em.create(prop.type, item, options);
230
+ return em.create(prop.targetMeta.class, item, options);
223
231
  }
224
232
  invalid.push(item);
225
233
  return item;
@@ -4,12 +4,18 @@ import type { EntityComparator } from '../utils/EntityComparator.js';
4
4
  export interface FactoryOptions {
5
5
  initialized?: boolean;
6
6
  newEntity?: boolean;
7
+ /**
8
+ * Property `onCreate` hooks are normally executed during `flush` operation.
9
+ * With this option, they will be processed early inside `em.create()` method.
10
+ */
11
+ processOnCreateHooksEarly?: boolean;
7
12
  merge?: boolean;
8
13
  refresh?: boolean;
9
14
  convertCustomTypes?: boolean;
10
15
  recomputeSnapshot?: boolean;
11
16
  schema?: string;
12
17
  parentSchema?: string;
18
+ normalizeAccessors?: boolean;
13
19
  }
14
20
  export declare class EntityFactory {
15
21
  private readonly em;
@@ -27,6 +33,7 @@ export declare class EntityFactory {
27
33
  createEmbeddable<T extends object>(entityName: EntityName<T>, data: EntityData<T>, options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>): T;
28
34
  getComparator(): EntityComparator;
29
35
  private createEntity;
36
+ private assignDefaultValues;
30
37
  private hydrate;
31
38
  private findEntity;
32
39
  private processDiscriminatorColumn;
@@ -4,6 +4,7 @@ import { EventType, ReferenceKind } from '../enums.js';
4
4
  import { Reference } from './Reference.js';
5
5
  import { helper } from './wrap.js';
6
6
  import { EntityHelper } from './EntityHelper.js';
7
+ import { JsonType } from '../types/JsonType.js';
7
8
  export class EntityFactory {
8
9
  em;
9
10
  driver;
@@ -29,7 +30,6 @@ export class EntityFactory {
29
30
  if (data.__entity) {
30
31
  return data;
31
32
  }
32
- entityName = Utils.className(entityName);
33
33
  const meta = this.metadata.get(entityName);
34
34
  if (meta.virtual) {
35
35
  data = { ...data };
@@ -37,8 +37,8 @@ export class EntityFactory {
37
37
  this.hydrate(entity, meta, data, options);
38
38
  return entity;
39
39
  }
40
- if (this.platform.usesDifferentSerializedPrimaryKey()) {
41
- meta.primaryKeys.forEach(pk => this.denormalizePrimaryKey(data, pk, meta.properties[pk]));
40
+ if (meta.serializedPrimaryKey) {
41
+ this.denormalizePrimaryKey(meta, data);
42
42
  }
43
43
  const meta2 = this.processDiscriminatorColumn(meta, data);
44
44
  const exists = this.findEntity(data, meta2, options);
@@ -59,7 +59,7 @@ export class EntityFactory {
59
59
  wrapped.__initialized = options.initialized;
60
60
  if (options.newEntity || meta.forceConstructor || meta.virtual) {
61
61
  const tmp = { ...data };
62
- meta.constructorParams.forEach(prop => delete tmp[prop]);
62
+ meta.constructorParams?.forEach(prop => delete tmp[prop]);
63
63
  this.hydrate(entity, meta2, tmp, options);
64
64
  // since we now process only a copy of the `data` via hydrator, but later we register the state with the full snapshot,
65
65
  // we need to go through all props with custom types that have `ensureComparable: true` and ensure they are comparable
@@ -71,9 +71,11 @@ export class EntityFactory {
71
71
  continue;
72
72
  }
73
73
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
74
- data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
74
+ data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
75
+ }
76
+ if (prop.customType instanceof JsonType && this.platform.convertsJsonAutomatically()) {
77
+ data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
75
78
  }
76
- data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
77
79
  }
78
80
  }
79
81
  }
@@ -81,7 +83,6 @@ export class EntityFactory {
81
83
  else {
82
84
  this.hydrate(entity, meta2, data, options);
83
85
  }
84
- wrapped.__touched = false;
85
86
  if (exists && meta.discriminatorColumn && !(entity instanceof meta2.class)) {
86
87
  Object.setPrototypeOf(entity, meta2.prototype);
87
88
  }
@@ -108,12 +109,12 @@ export class EntityFactory {
108
109
  data = QueryHelper.processParams(data);
109
110
  const existsData = this.comparator.prepareEntity(entity);
110
111
  const originalEntityData = helper(entity).__originalEntityData ?? {};
111
- const diff = this.comparator.diffEntities(meta.className, originalEntityData, existsData);
112
+ const diff = this.comparator.diffEntities(meta.class, originalEntityData, existsData);
112
113
  // version properties are not part of entity snapshots
113
114
  if (meta.versionProperty && data[meta.versionProperty] && data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
114
115
  diff[meta.versionProperty] = data[meta.versionProperty];
115
116
  }
116
- const diff2 = this.comparator.diffEntities(meta.className, existsData, data);
117
+ const diff2 = this.comparator.diffEntities(meta.class, existsData, data, { includeInverseSides: true });
117
118
  // do not override values changed by user
118
119
  Utils.keys(diff).forEach(key => delete diff2[key]);
119
120
  Utils.keys(diff2).filter(key => {
@@ -136,6 +137,10 @@ export class EntityFactory {
136
137
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
137
138
  diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
138
139
  }
140
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) && prop.customType?.ensureComparable(meta, prop) && diff2[key] != null) {
141
+ const converted = prop.customType.convertToJSValue(diff2[key], this.platform, { force: true });
142
+ diff2[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { fromQuery: true });
143
+ }
139
144
  originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
140
145
  helper(entity).__loadedProperties.add(key);
141
146
  });
@@ -146,18 +151,17 @@ export class EntityFactory {
146
151
  // we just create the entity from scratch, which will automatically pick the right one from the identity map and call `mergeData` on it
147
152
  data[prop.name]
148
153
  .filter(child => Utils.isPlainObject(child)) // objects with prototype can be PKs (e.g. `ObjectId`)
149
- .forEach(child => this.create(prop.type, child, options)); // we can ignore the value, we just care about the `mergeData` call
154
+ .forEach(child => this.create(prop.targetMeta.class, child, options)); // we can ignore the value, we just care about the `mergeData` call
150
155
  return;
151
156
  }
152
157
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name]) && entity[prop.name] && helper(entity[prop.name]).__initialized) {
153
- this.create(prop.type, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
158
+ this.create(prop.targetMeta.class, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
154
159
  }
155
160
  });
156
- helper(entity).__touched = false;
161
+ this.unitOfWork.normalizeEntityData(meta, originalEntityData);
157
162
  }
158
163
  createReference(entityName, id, options = {}) {
159
164
  options.convertCustomTypes ??= true;
160
- entityName = Utils.className(entityName);
161
165
  const meta = this.metadata.get(entityName);
162
166
  const schema = this.driver.getSchemaName(meta, options);
163
167
  if (meta.simplePK) {
@@ -171,8 +175,8 @@ export class EntityFactory {
171
175
  if (Array.isArray(id)) {
172
176
  id = Utils.getPrimaryKeyCondFromArray(id, meta);
173
177
  }
174
- const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform, options.convertCustomTypes);
175
- const exists = this.unitOfWork.getById(entityName, pks, schema);
178
+ const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform);
179
+ const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
176
180
  if (exists) {
177
181
  return exists;
178
182
  }
@@ -182,7 +186,6 @@ export class EntityFactory {
182
186
  return this.create(entityName, id, { ...options, initialized: false });
183
187
  }
184
188
  createEmbeddable(entityName, data, options = {}) {
185
- entityName = Utils.className(entityName);
186
189
  data = { ...data };
187
190
  const meta = this.metadata.get(entityName);
188
191
  const meta2 = this.processDiscriminatorColumn(meta, data);
@@ -194,7 +197,7 @@ export class EntityFactory {
194
197
  createEntity(data, meta, options) {
195
198
  const schema = this.driver.getSchemaName(meta, options);
196
199
  if (options.newEntity || meta.forceConstructor || meta.virtual) {
197
- if (!meta.class) {
200
+ if (meta.polymorphs) {
198
201
  throw new Error(`Cannot create entity ${meta.className}, class prototype is unknown`);
199
202
  }
200
203
  const params = this.extractConstructorParams(meta, data, options);
@@ -231,28 +234,39 @@ export class EntityFactory {
231
234
  }
232
235
  return entity;
233
236
  }
237
+ assignDefaultValues(entity, meta) {
238
+ for (const prop of meta.props) {
239
+ if (prop.onCreate) {
240
+ entity[prop.name] ??= prop.onCreate(entity, this.em);
241
+ }
242
+ }
243
+ }
234
244
  hydrate(entity, meta, data, options) {
235
245
  if (options.initialized) {
236
- this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
246
+ this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
237
247
  }
238
248
  else {
239
- this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
249
+ this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
240
250
  }
241
251
  Utils.keys(data).forEach(key => {
242
252
  helper(entity)?.__loadedProperties.add(key);
243
253
  helper(entity)?.__serializationContext.fields?.add(key);
244
254
  });
255
+ const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this.config.get('processOnCreateHooksEarly');
256
+ if (options.newEntity && processOnCreateHooksEarly) {
257
+ this.assignDefaultValues(entity, meta);
258
+ }
245
259
  }
246
260
  findEntity(data, meta, options) {
247
261
  const schema = this.driver.getSchemaName(meta, options);
248
262
  if (meta.simplePK) {
249
- return this.unitOfWork.getById(meta.className, data[meta.primaryKeys[0]], schema);
263
+ return this.unitOfWork.getById(meta.class, data[meta.primaryKeys[0]], schema);
250
264
  }
251
265
  if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
252
266
  return undefined;
253
267
  }
254
- const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform);
255
- return this.unitOfWork.getById(meta.className, pks, schema);
268
+ const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform, options.convertCustomTypes);
269
+ return this.unitOfWork.getById(meta.class, pks, schema);
256
270
  }
257
271
  processDiscriminatorColumn(meta, data) {
258
272
  if (!meta.root.discriminatorColumn) {
@@ -261,60 +275,65 @@ export class EntityFactory {
261
275
  const prop = meta.properties[meta.root.discriminatorColumn];
262
276
  const value = data[prop.name];
263
277
  const type = meta.root.discriminatorMap[value];
264
- meta = type ? this.metadata.find(type) : meta;
278
+ meta = type ? this.metadata.get(type) : meta;
265
279
  return meta;
266
280
  }
267
281
  /**
268
282
  * denormalize PK to value required by driver (e.g. ObjectId)
269
283
  */
270
- denormalizePrimaryKey(data, primaryKey, prop) {
271
- const pk = this.platform.getSerializedPrimaryKeyField(primaryKey);
272
- if (data[pk] != null || data[primaryKey] != null) {
273
- let id = (data[pk] || data[primaryKey]);
274
- if (prop.type.toLowerCase() === 'objectid') {
275
- id = this.platform.denormalizePrimaryKey(id);
276
- }
277
- delete data[pk];
278
- data[primaryKey] = id;
284
+ denormalizePrimaryKey(meta, data) {
285
+ const pk = meta.getPrimaryProp();
286
+ const spk = meta.properties[meta.serializedPrimaryKey];
287
+ if (!spk?.serializedPrimaryKey) {
288
+ return;
289
+ }
290
+ if (pk.type === 'ObjectId' && (data[pk.name] != null || data[spk.name] != null)) {
291
+ data[pk.name] = this.platform.denormalizePrimaryKey((data[spk.name] || data[pk.name]));
292
+ delete data[spk.name];
279
293
  }
280
294
  }
281
295
  /**
282
296
  * returns parameters for entity constructor, creating references from plain ids
283
297
  */
284
298
  extractConstructorParams(meta, data, options) {
299
+ if (!meta.constructorParams) {
300
+ return [data];
301
+ }
285
302
  return meta.constructorParams.map(k => {
286
- if (meta.properties[k] && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[k].kind) && data[k]) {
287
- const pk = Reference.unwrapReference(data[k]);
288
- const entity = this.unitOfWork.getById(meta.properties[k].type, pk, options.schema);
303
+ const prop = meta.properties[k];
304
+ const value = data[k];
305
+ if (prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && value) {
306
+ const pk = Reference.unwrapReference(value);
307
+ const entity = this.unitOfWork.getById(prop.targetMeta.class, pk, options.schema, true);
289
308
  if (entity) {
290
309
  return entity;
291
310
  }
292
- if (Utils.isEntity(data[k])) {
293
- return data[k];
311
+ if (Utils.isEntity(value)) {
312
+ return value;
294
313
  }
295
- const nakedPk = Utils.extractPK(data[k], meta.properties[k].targetMeta, true);
296
- if (Utils.isObject(data[k]) && !nakedPk) {
297
- return this.create(meta.properties[k].type, data[k], options);
314
+ const nakedPk = Utils.extractPK(value, prop.targetMeta, true);
315
+ if (Utils.isObject(value) && !nakedPk) {
316
+ return this.create(prop.targetMeta.class, value, options);
298
317
  }
299
318
  const { newEntity, initialized, ...rest } = options;
300
- const target = this.createReference(meta.properties[k].type, nakedPk, rest);
301
- return Reference.wrapReference(target, meta.properties[k]);
319
+ const target = this.createReference(prop.targetMeta.class, nakedPk, rest);
320
+ return Reference.wrapReference(target, prop);
302
321
  }
303
- if (meta.properties[k]?.kind === ReferenceKind.EMBEDDED && data[k]) {
304
- /* v8 ignore next 3 */
305
- if (Utils.isEntity(data[k])) {
306
- return data[k];
322
+ if (prop?.kind === ReferenceKind.EMBEDDED && value) {
323
+ /* v8 ignore next */
324
+ if (Utils.isEntity(value)) {
325
+ return value;
307
326
  }
308
- return this.createEmbeddable(meta.properties[k].type, data[k], options);
327
+ return this.createEmbeddable(prop.targetMeta.class, value, options);
309
328
  }
310
- if (!meta.properties[k]) {
329
+ if (!prop) {
311
330
  const tmp = { ...data };
312
331
  for (const prop of meta.props) {
313
332
  if (!options.convertCustomTypes || !prop.customType || tmp[prop.name] == null) {
314
333
  continue;
315
334
  }
316
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(tmp[prop.name]) && !Utils.extractPK(tmp[prop.name], meta.properties[prop.name].targetMeta, true)) {
317
- tmp[prop.name] = Reference.wrapReference(this.create(meta.properties[prop.name].type, tmp[prop.name], options), prop);
335
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(tmp[prop.name]) && !Utils.extractPK(tmp[prop.name], prop.targetMeta, true)) {
336
+ tmp[prop.name] = Reference.wrapReference(this.create(prop.targetMeta.class, tmp[prop.name], options), prop);
318
337
  }
319
338
  else if (prop.kind === ReferenceKind.SCALAR) {
320
339
  tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this.platform);
@@ -322,10 +341,10 @@ export class EntityFactory {
322
341
  }
323
342
  return tmp;
324
343
  }
325
- if (options.convertCustomTypes && meta.properties[k].customType && data[k] != null) {
326
- return meta.properties[k].customType.convertToJSValue(data[k], this.platform);
344
+ if (options.convertCustomTypes && prop.customType && value != null) {
345
+ return prop.customType.convertToJSValue(value, this.platform);
327
346
  }
328
- return data[k];
347
+ return value;
329
348
  });
330
349
  }
331
350
  get unitOfWork() {
@@ -6,9 +6,9 @@ import { type EntityMetadata, type EntityProperty, type IHydrator } from '../typ
6
6
  export declare class EntityHelper {
7
7
  static decorate<T extends object>(meta: EntityMetadata<T>, em: EntityManager): void;
8
8
  /**
9
- * As a performance optimization, we create entity state methods in a lazy manner. We first add
9
+ * As a performance optimization, we create entity state methods lazily. We first add
10
10
  * the `null` value to the prototype to reserve space in memory. Then we define a setter on the
11
- * prototype, that will be executed exactly once per entity instance. There we redefine given
11
+ * prototype that will be executed exactly once per entity instance. There we redefine the given
12
12
  * property on the entity instance, so shadowing the prototype setter.
13
13
  */
14
14
  private static defineBaseProperties;
@@ -1,4 +1,3 @@
1
- import { inspect } from 'node:util';
2
1
  import { EagerProps, EntityRepositoryType, HiddenProps, OptionalProps, PrimaryKeyProp, } from '../typings.js';
3
2
  import { EntityTransformer } from '../serialization/EntityTransformer.js';
4
3
  import { Reference } from './Reference.js';
@@ -6,6 +5,8 @@ import { Utils } from '../utils/Utils.js';
6
5
  import { WrappedEntity } from './WrappedEntity.js';
7
6
  import { ReferenceKind } from '../enums.js';
8
7
  import { helper } from './wrap.js';
8
+ import { inspect } from '../logging/inspect.js';
9
+ import { getEnv } from '../utils/env-vars.js';
9
10
  /**
10
11
  * @internal
11
12
  */
@@ -32,14 +33,14 @@ export class EntityHelper {
32
33
  const prototype = meta.prototype;
33
34
  if (!prototype.toJSON) { // toJSON can be overridden
34
35
  prototype.toJSON = function (...args) {
35
- return EntityTransformer.toObject(this, ...args.slice(meta.toJsonParams.length));
36
+ return EntityTransformer.toObject(this, ...args);
36
37
  };
37
38
  }
38
39
  }
39
40
  /**
40
- * As a performance optimization, we create entity state methods in a lazy manner. We first add
41
+ * As a performance optimization, we create entity state methods lazily. We first add
41
42
  * the `null` value to the prototype to reserve space in memory. Then we define a setter on the
42
- * prototype, that will be executed exactly once per entity instance. There we redefine given
43
+ * prototype that will be executed exactly once per entity instance. There we redefine the given
43
44
  * property on the entity instance, so shadowing the prototype setter.
44
45
  */
45
46
  static defineBaseProperties(meta, prototype, em) {
@@ -87,7 +88,7 @@ export class EntityHelper {
87
88
  });
88
89
  return;
89
90
  }
90
- if (prop.inherited || prop.primary || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
91
+ if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.embedded || isCollection) {
91
92
  return;
92
93
  }
93
94
  Object.defineProperty(meta.prototype, prop.name, {
@@ -98,13 +99,11 @@ export class EntityHelper {
98
99
  },
99
100
  set(val) {
100
101
  this.__helper.__data[prop.name] = val;
101
- this.__helper.__touched = !this.__helper.hydrator.isRunning();
102
102
  },
103
103
  enumerable: true,
104
104
  configurable: true,
105
105
  });
106
106
  this.__helper.__data[prop.name] = val;
107
- this.__helper.__touched = !this.__helper.hydrator.isRunning();
108
107
  },
109
108
  configurable: true,
110
109
  });
@@ -112,16 +111,27 @@ export class EntityHelper {
112
111
  }
113
112
  static defineCustomInspect(meta) {
114
113
  // @ts-ignore
115
- meta.prototype[inspect.custom] ??= function (depth = 2) {
116
- const object = { ...this };
114
+ meta.prototype[Symbol.for('nodejs.util.inspect.custom')] ??= function (depth = 2) {
115
+ const object = {};
116
+ const keys = new Set(Utils.keys(this));
117
+ for (const prop of meta.props) {
118
+ if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
119
+ object[prop.name] = this[prop.name];
120
+ }
121
+ }
122
+ for (const key of keys) {
123
+ if (!meta.properties[key]) {
124
+ object[key] = this[key];
125
+ }
126
+ }
117
127
  // ensure we dont have internal symbols in the POJO
118
128
  [OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps].forEach(sym => delete object[sym]);
119
129
  meta.props
120
130
  .filter(prop => object[prop.name] === undefined)
121
131
  .forEach(prop => delete object[prop.name]);
122
132
  const ret = inspect(object, { depth });
123
- let name = (this).constructor.name;
124
- const showEM = ['true', 't', '1'].includes(process.env.MIKRO_ORM_LOG_EM_ID?.toString().toLowerCase() ?? '');
133
+ let name = this.constructor.name;
134
+ const showEM = ['true', 't', '1'].includes(getEnv('MIKRO_ORM_LOG_EM_ID')?.toLowerCase() ?? '');
125
135
  if (showEM) {
126
136
  if (helper(this).__em) {
127
137
  name += ` [managed by ${helper(this).__em.id}]`;
@@ -152,10 +162,7 @@ export class EntityHelper {
152
162
  wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
153
163
  // when propagation from inside hydration, we set the FK to the entity data immediately
154
164
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
155
- wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta.primaryKeys, true);
156
- }
157
- else {
158
- wrapped.__touched = !hydrator.isRunning();
165
+ wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta, true);
159
166
  }
160
167
  EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
161
168
  },
@@ -172,6 +179,13 @@ export class EntityHelper {
172
179
  continue;
173
180
  }
174
181
  const inverse = value?.[prop2.name];
182
+ if (prop.ref && owner[prop.name]) {
183
+ // eslint-disable-next-line dot-notation
184
+ owner[prop.name]['property'] = prop;
185
+ }
186
+ if (Utils.isCollection(inverse) && inverse.isPartial()) {
187
+ continue;
188
+ }
175
189
  if (prop.kind === ReferenceKind.MANY_TO_ONE && Utils.isCollection(inverse) && inverse.isInitialized()) {
176
190
  inverse.addWithoutPropagation(owner);
177
191
  helper(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
@@ -210,6 +224,7 @@ export class EntityHelper {
210
224
  }
211
225
  if (old?.[prop2.name] != null) {
212
226
  delete helper(old).__data[prop2.name];
227
+ old[prop2.name] = null;
213
228
  }
214
229
  }
215
230
  static ensurePropagation(entity) {
@@ -1,7 +1,7 @@
1
- import type { ConnectionType, Dictionary, FilterQuery, PopulateOptions } from '../typings.js';
1
+ import type { AnyEntity, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
2
2
  import type { EntityManager } from '../EntityManager.js';
3
3
  import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
4
- import type { EntityField } from '../drivers/IDatabaseDriver.js';
4
+ import type { EntityField, FilterOptions } from '../drivers/IDatabaseDriver.js';
5
5
  import type { LoggingOptions } from '../logging/Logger.js';
6
6
  export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL, Excludes extends string = never> = {
7
7
  where?: FilterQuery<Entity>;
@@ -14,7 +14,7 @@ export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL
14
14
  lookup?: boolean;
15
15
  convertCustomTypes?: boolean;
16
16
  ignoreLazyScalarProperties?: boolean;
17
- filters?: Dictionary<boolean | Dictionary> | string[] | boolean;
17
+ filters?: FilterOptions;
18
18
  strategy?: LoadStrategy;
19
19
  lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
20
20
  schema?: string;
@@ -30,8 +30,8 @@ export declare class EntityLoader {
30
30
  * Loads specified relations in batch.
31
31
  * This will execute one query for each relation, that will populate it on all the specified entities.
32
32
  */
33
- populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: string, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
34
- normalizePopulate<Entity>(entityName: string, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean): PopulateOptions<Entity>[];
33
+ populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: EntityName<Entity>, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
34
+ normalizePopulate<Entity>(entityName: EntityName<Entity>, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean): PopulateOptions<Entity>[];
35
35
  private setSerializationContext;
36
36
  /**
37
37
  * Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
@@ -49,7 +49,8 @@ export declare class EntityLoader {
49
49
  private findChildren;
50
50
  private mergePrimaryCondition;
51
51
  private populateField;
52
- private findChildrenFromPivotTable;
52
+ /** @internal */
53
+ findChildrenFromPivotTable<Entity extends object>(filtered: Entity[], prop: EntityProperty<Entity>, options: Required<EntityLoaderOptions<Entity>>, orderBy?: QueryOrderMap<Entity>[], populate?: PopulateOptions<Entity>, pivotJoin?: boolean): Promise<AnyEntity[][]>;
53
54
  private extractChildCondition;
54
55
  private buildFields;
55
56
  private getChildReferences;