@mikro-orm/core 7.0.0-dev.4 → 7.0.0-dev.41

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 (117) hide show
  1. package/EntityManager.d.ts +84 -18
  2. package/EntityManager.js +265 -172
  3. package/MikroORM.d.ts +7 -5
  4. package/MikroORM.js +0 -1
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +2 -1
  7. package/cache/FileCacheAdapter.js +6 -4
  8. package/connections/Connection.d.ts +4 -2
  9. package/connections/Connection.js +2 -2
  10. package/decorators/Check.d.ts +2 -2
  11. package/decorators/Embeddable.d.ts +5 -5
  12. package/decorators/Embeddable.js +1 -1
  13. package/decorators/Embedded.d.ts +6 -12
  14. package/decorators/Entity.d.ts +18 -3
  15. package/decorators/Enum.d.ts +1 -1
  16. package/decorators/Formula.d.ts +1 -2
  17. package/decorators/Indexed.d.ts +2 -2
  18. package/decorators/ManyToMany.d.ts +4 -2
  19. package/decorators/ManyToOne.d.ts +6 -2
  20. package/decorators/OneToMany.d.ts +4 -4
  21. package/decorators/OneToOne.d.ts +5 -1
  22. package/decorators/PrimaryKey.d.ts +2 -3
  23. package/decorators/Property.d.ts +54 -4
  24. package/decorators/Transactional.d.ts +1 -0
  25. package/decorators/Transactional.js +3 -3
  26. package/decorators/index.d.ts +1 -1
  27. package/drivers/DatabaseDriver.d.ts +4 -3
  28. package/drivers/IDatabaseDriver.d.ts +22 -2
  29. package/entity/ArrayCollection.d.ts +4 -2
  30. package/entity/ArrayCollection.js +18 -6
  31. package/entity/Collection.d.ts +1 -2
  32. package/entity/Collection.js +19 -10
  33. package/entity/EntityAssigner.d.ts +1 -1
  34. package/entity/EntityAssigner.js +9 -1
  35. package/entity/EntityFactory.d.ts +7 -0
  36. package/entity/EntityFactory.js +29 -9
  37. package/entity/EntityHelper.js +25 -3
  38. package/entity/EntityLoader.d.ts +5 -4
  39. package/entity/EntityLoader.js +74 -37
  40. package/entity/EntityRepository.d.ts +1 -1
  41. package/entity/EntityValidator.js +1 -1
  42. package/entity/Reference.d.ts +9 -7
  43. package/entity/Reference.js +30 -3
  44. package/entity/WrappedEntity.js +1 -1
  45. package/entity/defineEntity.d.ts +561 -0
  46. package/entity/defineEntity.js +537 -0
  47. package/entity/index.d.ts +2 -0
  48. package/entity/index.js +2 -0
  49. package/entity/utils.d.ts +7 -0
  50. package/entity/utils.js +15 -3
  51. package/enums.d.ts +16 -3
  52. package/enums.js +13 -0
  53. package/errors.d.ts +6 -0
  54. package/errors.js +14 -0
  55. package/events/EventSubscriber.d.ts +3 -1
  56. package/hydration/ObjectHydrator.d.ts +4 -4
  57. package/hydration/ObjectHydrator.js +35 -24
  58. package/index.d.ts +2 -1
  59. package/index.js +1 -1
  60. package/logging/DefaultLogger.d.ts +1 -1
  61. package/logging/SimpleLogger.d.ts +1 -1
  62. package/metadata/EntitySchema.d.ts +8 -4
  63. package/metadata/EntitySchema.js +39 -19
  64. package/metadata/MetadataDiscovery.d.ts +1 -1
  65. package/metadata/MetadataDiscovery.js +88 -32
  66. package/metadata/MetadataStorage.js +1 -1
  67. package/metadata/MetadataValidator.js +4 -3
  68. package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
  69. package/naming-strategy/AbstractNamingStrategy.js +7 -1
  70. package/naming-strategy/NamingStrategy.d.ts +11 -1
  71. package/package.json +5 -5
  72. package/platforms/Platform.d.ts +5 -3
  73. package/platforms/Platform.js +4 -8
  74. package/serialization/EntitySerializer.d.ts +2 -0
  75. package/serialization/EntitySerializer.js +2 -2
  76. package/serialization/EntityTransformer.js +1 -1
  77. package/serialization/SerializationContext.js +14 -11
  78. package/types/BigIntType.d.ts +9 -6
  79. package/types/BigIntType.js +3 -0
  80. package/types/BooleanType.d.ts +1 -1
  81. package/types/DecimalType.d.ts +6 -4
  82. package/types/DecimalType.js +1 -1
  83. package/types/DoubleType.js +1 -1
  84. package/types/JsonType.d.ts +1 -1
  85. package/types/JsonType.js +7 -2
  86. package/types/Type.d.ts +2 -1
  87. package/types/Type.js +1 -1
  88. package/types/index.d.ts +1 -1
  89. package/typings.d.ts +88 -39
  90. package/typings.js +24 -4
  91. package/unit-of-work/ChangeSetComputer.js +3 -1
  92. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  93. package/unit-of-work/ChangeSetPersister.js +37 -16
  94. package/unit-of-work/UnitOfWork.d.ts +8 -1
  95. package/unit-of-work/UnitOfWork.js +109 -41
  96. package/utils/Configuration.d.ts +23 -5
  97. package/utils/Configuration.js +17 -3
  98. package/utils/ConfigurationLoader.d.ts +0 -2
  99. package/utils/ConfigurationLoader.js +2 -24
  100. package/utils/Cursor.d.ts +3 -3
  101. package/utils/Cursor.js +3 -0
  102. package/utils/DataloaderUtils.d.ts +7 -2
  103. package/utils/DataloaderUtils.js +38 -7
  104. package/utils/EntityComparator.d.ts +6 -2
  105. package/utils/EntityComparator.js +104 -58
  106. package/utils/QueryHelper.d.ts +9 -1
  107. package/utils/QueryHelper.js +66 -5
  108. package/utils/RawQueryFragment.d.ts +36 -2
  109. package/utils/RawQueryFragment.js +35 -1
  110. package/utils/TransactionManager.d.ts +65 -0
  111. package/utils/TransactionManager.js +218 -0
  112. package/utils/Utils.d.ts +11 -5
  113. package/utils/Utils.js +76 -33
  114. package/utils/index.d.ts +1 -0
  115. package/utils/index.js +1 -0
  116. package/utils/upsert-utils.d.ts +7 -2
  117. package/utils/upsert-utils.js +52 -1
@@ -6,6 +6,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
6
6
  protected readonly items: Set<T>;
7
7
  protected initialized: boolean;
8
8
  protected dirty: boolean;
9
+ protected partial: boolean;
9
10
  protected snapshot: T[] | undefined;
10
11
  protected _count?: number;
11
12
  private _property?;
@@ -14,7 +15,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
14
15
  getItems(): T[];
15
16
  toArray<TT extends T>(): EntityDTO<TT>[];
16
17
  toJSON(): EntityDTO<T>[];
17
- getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string): U[];
18
+ getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string | string[]): U[];
18
19
  add(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]): void;
19
20
  /**
20
21
  * @internal
@@ -25,7 +26,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
25
26
  /**
26
27
  * @internal
27
28
  */
28
- hydrate(items: T[], forcePropagate?: boolean): void;
29
+ hydrate(items: T[], forcePropagate?: boolean, partial?: boolean): void;
29
30
  /**
30
31
  * Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
31
32
  * it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
@@ -83,6 +84,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
83
84
  count(): number;
84
85
  isInitialized(fully?: boolean): boolean;
85
86
  isDirty(): boolean;
87
+ isPartial(): boolean;
86
88
  isEmpty(): boolean;
87
89
  setDirty(dirty?: boolean): void;
88
90
  get length(): number;
@@ -9,6 +9,7 @@ export class ArrayCollection {
9
9
  items = new Set();
10
10
  initialized = true;
11
11
  dirty = false;
12
+ partial = false; // mark partially loaded collections, propagation is disabled for those
12
13
  snapshot = []; // used to create a diff of the collection at commit time, undefined marks overridden values so we need to wipe when flushing
13
14
  _count;
14
15
  _property;
@@ -40,15 +41,22 @@ export class ArrayCollection {
40
41
  }
41
42
  getIdentifiers(field) {
42
43
  const items = this.getItems();
44
+ const targetMeta = this.property.targetMeta;
43
45
  if (items.length === 0) {
44
46
  return [];
45
47
  }
46
- field ??= this.property.targetMeta.serializedPrimaryKey;
48
+ field ??= targetMeta.compositePK ? targetMeta.primaryKeys : targetMeta.serializedPrimaryKey;
49
+ const cb = (i, f) => {
50
+ if (Utils.isEntity(i[f], true)) {
51
+ return wrap(i[f], true).getPrimaryKey();
52
+ }
53
+ return i[f];
54
+ };
47
55
  return items.map(i => {
48
- if (Utils.isEntity(i[field], true)) {
49
- return wrap(i[field], true).getPrimaryKey();
56
+ if (Array.isArray(field)) {
57
+ return field.map(f => cb(i, f));
50
58
  }
51
- return i[field];
59
+ return cb(i, field);
52
60
  });
53
61
  }
54
62
  add(entity, ...entities) {
@@ -100,11 +108,12 @@ export class ArrayCollection {
100
108
  /**
101
109
  * @internal
102
110
  */
103
- hydrate(items, forcePropagate) {
111
+ hydrate(items, forcePropagate, partial) {
104
112
  for (let i = 0; i < this.items.size; i++) {
105
113
  delete this[i];
106
114
  }
107
115
  this.initialized = true;
116
+ this.partial = !!partial;
108
117
  this.items.clear();
109
118
  this._count = 0;
110
119
  this.add(items);
@@ -267,6 +276,9 @@ export class ArrayCollection {
267
276
  isDirty() {
268
277
  return this.dirty;
269
278
  }
279
+ isPartial() {
280
+ return this.partial;
281
+ }
270
282
  isEmpty() {
271
283
  return this.count() === 0;
272
284
  }
@@ -383,7 +395,7 @@ export class ArrayCollection {
383
395
  /** @ignore */
384
396
  [inspect.custom](depth = 2) {
385
397
  const object = { ...this };
386
- const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly'];
398
+ const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly', 'partial'];
387
399
  hidden.forEach(k => delete object[k]);
388
400
  const ret = inspect(object, { depth });
389
401
  const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
@@ -2,7 +2,7 @@ import type { EntityDTO, EntityKey, FilterQuery, Loaded, LoadedCollection, Popul
2
2
  import { ArrayCollection } from './ArrayCollection.js';
3
3
  import { Reference } from './Reference.js';
4
4
  import type { Transaction } from '../connections/Connection.js';
5
- import type { FindOptions, CountOptions } from '../drivers/IDatabaseDriver.js';
5
+ import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
6
6
  import type { EntityLoaderOptions } from './EntityLoader.js';
7
7
  export interface MatchingOptions<T extends object, P extends string = never> extends FindOptions<T, P> {
8
8
  where?: FilterQuery<T>;
@@ -12,7 +12,6 @@ export interface MatchingOptions<T extends object, P extends string = never> ext
12
12
  export declare class Collection<T extends object, O extends object = object> extends ArrayCollection<T, O> {
13
13
  private readonly?;
14
14
  private _populated?;
15
- private _em?;
16
15
  private _snapshot?;
17
16
  constructor(owner: O, items?: T[], initialized?: boolean);
18
17
  /**
@@ -4,10 +4,10 @@ import { ValidationError } from '../errors.js';
4
4
  import { ReferenceKind, DataloaderType } from '../enums.js';
5
5
  import { Reference } from './Reference.js';
6
6
  import { helper } from './wrap.js';
7
+ import { QueryHelper } from '../utils/QueryHelper.js';
7
8
  export class Collection extends ArrayCollection {
8
9
  readonly;
9
10
  _populated;
10
- _em;
11
11
  // this is for some reason needed for TS, otherwise it can fail with `Type instantiation is excessively deep and possibly infinite.`
12
12
  _snapshot;
13
13
  constructor(owner, items, initialized = true) {
@@ -33,6 +33,7 @@ export class Collection extends ArrayCollection {
33
33
  async load(options = {}) {
34
34
  if (this.isInitialized(true) && !options.refresh) {
35
35
  const em = this.getEntityManager(this.items, false);
36
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
36
37
  await em?.populate(this.items, options.populate, options);
37
38
  this.setSerializationContext(options);
38
39
  }
@@ -218,13 +219,24 @@ export class Collection extends ArrayCollection {
218
219
  return this;
219
220
  }
220
221
  const em = this.getEntityManager();
222
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
221
223
  if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
222
224
  const order = [...this.items]; // copy order of references
223
- const customOrder = !!options.orderBy;
224
- // eslint-disable-next-line dot-notation
225
- const items = await em['colLoader'].load([this, options]);
226
- if (!customOrder) {
227
- this.reorderItems(items, order);
225
+ const orderBy = this.createOrderBy(options.orderBy);
226
+ const customOrder = orderBy.length > 0;
227
+ const pivotTable = this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable();
228
+ const loader = pivotTable ? 'colLoaderMtoN' : 'colLoader';
229
+ const items = await em[loader].load([
230
+ this,
231
+ { ...options, orderBy },
232
+ ]);
233
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
234
+ this.initialized = true;
235
+ this.dirty = false;
236
+ if (!customOrder) {
237
+ this.reorderItems(items, order);
238
+ }
239
+ return this;
228
240
  }
229
241
  this.items.clear();
230
242
  let i = 0;
@@ -254,7 +266,7 @@ export class Collection extends ArrayCollection {
254
266
  }
255
267
  getEntityManager(items = [], required = true) {
256
268
  const wrapped = helper(this.owner);
257
- let em = (this._em ?? wrapped.__em);
269
+ let em = wrapped.__em;
258
270
  if (!em) {
259
271
  for (const i of items) {
260
272
  if (i && helper(i).__em) {
@@ -263,9 +275,6 @@ export class Collection extends ArrayCollection {
263
275
  }
264
276
  }
265
277
  }
266
- if (em) {
267
- Object.defineProperty(this, '_em', { value: em });
268
- }
269
278
  if (!em && required) {
270
279
  throw ValidationError.entityNotManaged(this.owner);
271
280
  }
@@ -36,7 +36,7 @@ export interface AssignOptions<Convert extends boolean> {
36
36
  */
37
37
  onlyProperties?: boolean;
38
38
  /**
39
- * With `onlyOwnProperties` enabled, to-many relations are skipped, and payloads of to-one relations are converted
39
+ * With `onlyOwnProperties` enabled, inverse sides of to-many relations are skipped, and payloads of other relations are converted
40
40
  * to foreign keys. Defaults to `false`.
41
41
  */
42
42
  onlyOwnProperties?: boolean;
@@ -42,9 +42,17 @@ export class EntityAssigner {
42
42
  }
43
43
  const prop = { ...props[propName], name: propName };
44
44
  if (prop && options.onlyOwnProperties) {
45
- if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
45
+ if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
46
46
  return;
47
47
  }
48
+ if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
49
+ if (!prop.owner) {
50
+ return;
51
+ }
52
+ else if (value?.map) {
53
+ value = value.map((v) => Utils.extractPK(v, prop.targetMeta));
54
+ }
55
+ }
48
56
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
49
57
  value = Utils.extractPK(value, prop.targetMeta);
50
58
  }
@@ -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;
@@ -45,6 +46,7 @@ export class EntityFactory {
45
46
  let wrapped = exists && helper(exists);
46
47
  if (wrapped && !options.refresh) {
47
48
  wrapped.__processing = true;
49
+ Utils.dropUndefinedProperties(data);
48
50
  this.mergeData(meta2, exists, data, options);
49
51
  wrapped.__processing = false;
50
52
  if (wrapped.isInitialized()) {
@@ -70,9 +72,11 @@ export class EntityFactory {
70
72
  continue;
71
73
  }
72
74
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
73
- data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
75
+ data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
76
+ }
77
+ if (prop.customType instanceof JsonType && this.platform.convertsJsonAutomatically()) {
78
+ data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
74
79
  }
75
- data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
76
80
  }
77
81
  }
78
82
  }
@@ -112,7 +116,7 @@ export class EntityFactory {
112
116
  if (meta.versionProperty && data[meta.versionProperty] && data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
113
117
  diff[meta.versionProperty] = data[meta.versionProperty];
114
118
  }
115
- const diff2 = this.comparator.diffEntities(meta.className, existsData, data);
119
+ const diff2 = this.comparator.diffEntities(meta.className, existsData, data, { includeInverseSides: true });
116
120
  // do not override values changed by user
117
121
  Utils.keys(diff).forEach(key => delete diff2[key]);
118
122
  Utils.keys(diff2).filter(key => {
@@ -135,6 +139,10 @@ export class EntityFactory {
135
139
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
136
140
  diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
137
141
  }
142
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) && prop.customType?.ensureComparable(meta, prop) && diff2[key] != null) {
143
+ const converted = prop.customType.convertToJSValue(diff2[key], this.platform, { force: true });
144
+ diff2[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { fromQuery: true });
145
+ }
138
146
  originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
139
147
  helper(entity).__loadedProperties.add(key);
140
148
  });
@@ -152,6 +160,7 @@ export class EntityFactory {
152
160
  this.create(prop.type, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
153
161
  }
154
162
  });
163
+ this.unitOfWork.normalizeEntityData(meta, originalEntityData);
155
164
  helper(entity).__touched = false;
156
165
  }
157
166
  createReference(entityName, id, options = {}) {
@@ -170,8 +179,8 @@ export class EntityFactory {
170
179
  if (Array.isArray(id)) {
171
180
  id = Utils.getPrimaryKeyCondFromArray(id, meta);
172
181
  }
173
- const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform, options.convertCustomTypes);
174
- const exists = this.unitOfWork.getById(entityName, pks, schema);
182
+ const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform);
183
+ const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
175
184
  if (exists) {
176
185
  return exists;
177
186
  }
@@ -230,17 +239,28 @@ export class EntityFactory {
230
239
  }
231
240
  return entity;
232
241
  }
242
+ assignDefaultValues(entity, meta) {
243
+ for (const prop of meta.props) {
244
+ if (prop.onCreate) {
245
+ entity[prop.name] ??= prop.onCreate(entity, this.em);
246
+ }
247
+ }
248
+ }
233
249
  hydrate(entity, meta, data, options) {
234
250
  if (options.initialized) {
235
- this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
251
+ this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
236
252
  }
237
253
  else {
238
- this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
254
+ this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
239
255
  }
240
256
  Utils.keys(data).forEach(key => {
241
257
  helper(entity)?.__loadedProperties.add(key);
242
258
  helper(entity)?.__serializationContext.fields?.add(key);
243
259
  });
260
+ const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this.config.get('processOnCreateHooksEarly');
261
+ if (options.newEntity && processOnCreateHooksEarly) {
262
+ this.assignDefaultValues(entity, meta);
263
+ }
244
264
  }
245
265
  findEntity(data, meta, options) {
246
266
  const schema = this.driver.getSchemaName(meta, options);
@@ -250,7 +270,7 @@ export class EntityFactory {
250
270
  if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
251
271
  return undefined;
252
272
  }
253
- const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform);
273
+ const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform, options.convertCustomTypes);
254
274
  return this.unitOfWork.getById(meta.className, pks, schema);
255
275
  }
256
276
  processDiscriminatorColumn(meta, data) {
@@ -284,7 +304,7 @@ export class EntityFactory {
284
304
  return meta.constructorParams.map(k => {
285
305
  if (meta.properties[k] && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[k].kind) && data[k]) {
286
306
  const pk = Reference.unwrapReference(data[k]);
287
- const entity = this.unitOfWork.getById(meta.properties[k].type, pk, options.schema);
307
+ const entity = this.unitOfWork.getById(meta.properties[k].type, pk, options.schema, true);
288
308
  if (entity) {
289
309
  return entity;
290
310
  }
@@ -87,7 +87,7 @@ export class EntityHelper {
87
87
  });
88
88
  return;
89
89
  }
90
- if (prop.inherited || prop.primary || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
90
+ if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
91
91
  return;
92
92
  }
93
93
  Object.defineProperty(meta.prototype, prop.name, {
@@ -113,7 +113,18 @@ export class EntityHelper {
113
113
  static defineCustomInspect(meta) {
114
114
  // @ts-ignore
115
115
  meta.prototype[inspect.custom] ??= function (depth = 2) {
116
- const object = { ...this };
116
+ const object = {};
117
+ const keys = new Set(Utils.keys(this)); // .sort((a, b) => (meta.propertyOrder.get(a) ?? 0) - (meta.propertyOrder.get(b) ?? 0));
118
+ for (const prop of meta.props) {
119
+ if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
120
+ object[prop.name] = this[prop.name];
121
+ }
122
+ }
123
+ for (const key of keys) {
124
+ if (!meta.properties[key]) {
125
+ object[key] = this[key];
126
+ }
127
+ }
117
128
  // ensure we dont have internal symbols in the POJO
118
129
  [OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps].forEach(sym => delete object[sym]);
119
130
  meta.props
@@ -146,10 +157,13 @@ export class EntityHelper {
146
157
  set(val) {
147
158
  const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
148
159
  const old = Reference.unwrapReference(wrapped.__data[prop.name]);
160
+ if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
161
+ old[prop.inversedBy].removeWithoutPropagation(this);
162
+ }
149
163
  wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
150
164
  // when propagation from inside hydration, we set the FK to the entity data immediately
151
165
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
152
- wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta.primaryKeys, true);
166
+ wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta, true);
153
167
  }
154
168
  else {
155
169
  wrapped.__touched = !hydrator.isRunning();
@@ -169,6 +183,13 @@ export class EntityHelper {
169
183
  continue;
170
184
  }
171
185
  const inverse = value?.[prop2.name];
186
+ if (prop.ref && owner[prop.name]) {
187
+ // eslint-disable-next-line dot-notation
188
+ owner[prop.name]['property'] = prop;
189
+ }
190
+ if (Utils.isCollection(inverse) && inverse.isPartial()) {
191
+ continue;
192
+ }
172
193
  if (prop.kind === ReferenceKind.MANY_TO_ONE && Utils.isCollection(inverse) && inverse.isInitialized()) {
173
194
  inverse.addWithoutPropagation(owner);
174
195
  helper(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
@@ -207,6 +228,7 @@ export class EntityHelper {
207
228
  }
208
229
  if (old?.[prop2.name] != null) {
209
230
  delete helper(old).__data[prop2.name];
231
+ old[prop2.name] = null;
210
232
  }
211
233
  }
212
234
  static ensurePropagation(entity) {
@@ -1,7 +1,7 @@
1
- import type { ConnectionType, Dictionary, FilterQuery, PopulateOptions } from '../typings.js';
1
+ import type { AnyEntity, ConnectionType, 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;
@@ -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;