@mikro-orm/core 6.5.10-dev.25 → 6.5.10-dev.27

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.
package/EntityManager.js CHANGED
@@ -1227,6 +1227,7 @@ class EntityManager {
1227
1227
  ...options,
1228
1228
  newEntity: !options.managed,
1229
1229
  merge: options.managed,
1230
+ normalizeAccessors: true,
1230
1231
  });
1231
1232
  options.persist ??= em.config.get('persistOnCreate');
1232
1233
  if (options.persist && !this.getMetadata(entityName).embeddable) {
@@ -162,7 +162,7 @@ export interface PropertyOptions<Owner> {
162
162
  * Set true to define the properties as setter. (virtual)
163
163
  *
164
164
  * @example
165
- * ```
165
+ * ```ts
166
166
  * @Property({ setter: true })
167
167
  * set address(value: string) {
168
168
  * this._address = value.toLocaleLowerCase();
@@ -174,7 +174,7 @@ export interface PropertyOptions<Owner> {
174
174
  * Set true to define the properties as getter. (virtual)
175
175
  *
176
176
  * @example
177
- * ```
177
+ * ```ts
178
178
  * @Property({ getter: true })
179
179
  * get fullName() {
180
180
  * return this.firstName + this.lastName;
@@ -187,7 +187,7 @@ export interface PropertyOptions<Owner> {
187
187
  * to the method name.
188
188
  *
189
189
  * @example
190
- * ```
190
+ * ```ts
191
191
  * @Property({ getter: true })
192
192
  * getFullName() {
193
193
  * return this.firstName + this.lastName;
@@ -195,6 +195,53 @@ export interface PropertyOptions<Owner> {
195
195
  * ```
196
196
  */
197
197
  getterName?: keyof Owner;
198
+ /**
199
+ * When using a private property backed by a public get/set pair, use the `accessor` option to point to the other side.
200
+ *
201
+ * > The `fieldName` will be inferred based on the accessor name unless specified explicitly.
202
+ *
203
+ * If the `accessor` option points to something, the ORM will use the backing property directly.
204
+ *
205
+ * @example
206
+ * ```ts
207
+ * @Entity()
208
+ * export class User {
209
+ * // the ORM will use the backing field directly
210
+ * @Property({ accessor: 'email' })
211
+ * private _email: string;
212
+ *
213
+ * get email() {
214
+ * return this._email;
215
+ * }
216
+ *
217
+ * set email() {
218
+ * return this._email;
219
+ * }
220
+ * }
221
+ *```
222
+ *
223
+ * If you want to the ORM to use your accessor internally too, use `accessor: true` on the get/set property instead.
224
+ * This is handy if you want to use a native private property for the backing field.
225
+ *
226
+ * @example
227
+ * ```ts
228
+ * @Entity({ forceConstructor: true })
229
+ * export class User {
230
+ * #email: string;
231
+ *
232
+ * // the ORM will use the accessor internally
233
+ * @Property({ accessor: true })
234
+ * get email() {
235
+ * return this.#email;
236
+ * }
237
+ *
238
+ * set email() {
239
+ * return this.#email;
240
+ * }
241
+ * }
242
+ * ```
243
+ */
244
+ accessor?: keyof Owner | boolean;
198
245
  /**
199
246
  * Set to define serialized primary key for MongoDB. (virtual)
200
247
  * Alias for `@SerializedPrimaryKey()` decorator.
@@ -15,6 +15,7 @@ export interface FactoryOptions {
15
15
  recomputeSnapshot?: boolean;
16
16
  schema?: string;
17
17
  parentSchema?: string;
18
+ normalizeAccessors?: boolean;
18
19
  }
19
20
  export declare class EntityFactory {
20
21
  private readonly em;
@@ -7,6 +7,7 @@ const enums_1 = require("../enums");
7
7
  const Reference_1 = require("./Reference");
8
8
  const wrap_1 = require("./wrap");
9
9
  const EntityHelper_1 = require("./EntityHelper");
10
+ const JsonType_1 = require("../types/JsonType");
10
11
  class EntityFactory {
11
12
  em;
12
13
  driver;
@@ -76,7 +77,9 @@ class EntityFactory {
76
77
  if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils_1.Utils.isPlainObject(data[prop.name])) {
77
78
  data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
78
79
  }
79
- data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
80
+ if (prop.customType instanceof JsonType_1.JsonType && this.platform.convertsJsonAutomatically()) {
81
+ data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
82
+ }
80
83
  }
81
84
  }
82
85
  }
@@ -248,10 +251,10 @@ class EntityFactory {
248
251
  }
249
252
  hydrate(entity, meta, data, options) {
250
253
  if (options.initialized) {
251
- this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
254
+ this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
252
255
  }
253
256
  else {
254
- this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
257
+ this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
255
258
  }
256
259
  Utils_1.Utils.keys(data).forEach(key => {
257
260
  (0, wrap_1.helper)(entity)?.__loadedProperties.add(key);
@@ -90,7 +90,7 @@ class EntityHelper {
90
90
  });
91
91
  return;
92
92
  }
93
- if (prop.inherited || prop.primary || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
93
+ if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
94
94
  return;
95
95
  }
96
96
  Object.defineProperty(meta.prototype, prop.name, {
@@ -116,7 +116,18 @@ class EntityHelper {
116
116
  static defineCustomInspect(meta) {
117
117
  // @ts-ignore
118
118
  meta.prototype[node_util_1.inspect.custom] ??= function (depth = 2) {
119
- const object = { ...this };
119
+ const object = {};
120
+ const keys = new Set(Utils_1.Utils.keys(this)); // .sort((a, b) => (meta.propertyOrder.get(a) ?? 0) - (meta.propertyOrder.get(b) ?? 0));
121
+ for (const prop of meta.props) {
122
+ if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
123
+ object[prop.name] = this[prop.name];
124
+ }
125
+ }
126
+ for (const key of keys) {
127
+ if (!meta.properties[key]) {
128
+ object[key] = this[key];
129
+ }
130
+ }
120
131
  // ensure we dont have internal symbols in the POJO
121
132
  [typings_1.OptionalProps, typings_1.EntityRepositoryType, typings_1.PrimaryKeyProp, typings_1.EagerProps, typings_1.HiddenProps].forEach(sym => delete object[sym]);
122
133
  meta.props
@@ -111,14 +111,12 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
111
111
  returning(returning?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
112
112
  /**
113
113
  * Automatically set the property value when entity gets created, executed during flush operation.
114
- * @param entity
115
114
  */
116
115
  onCreate(onCreate: (entity: any, em: EntityManager) => Value): Pick<UniversalPropertyOptionsBuilder<Value, Options & {
117
116
  onCreate: (...args: any[]) => any;
118
117
  }, IncludeKeys>, IncludeKeys>;
119
118
  /**
120
119
  * Automatically update the property value every time entity gets updated, executed during flush operation.
121
- * @param entity
122
120
  */
123
121
  onUpdate(onUpdate: (entity: any, em: EntityManager) => Value): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
124
122
  /**
@@ -366,6 +364,7 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
366
364
  foreignKeyName(foreignKeyName: string): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
367
365
  /** Remove the entity when it gets disconnected from the relationship (see {@doclink cascading | Cascading}). */
368
366
  orphanRemoval(orphanRemoval?: boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
367
+ accessor(accessor?: string | boolean): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
369
368
  }
370
369
  export interface EmptyOptions extends Partial<Record<UniversalPropertyKeys, unknown>> {
371
370
  }
@@ -100,14 +100,12 @@ class UniversalPropertyOptionsBuilder {
100
100
  }
101
101
  /**
102
102
  * Automatically set the property value when entity gets created, executed during flush operation.
103
- * @param entity
104
103
  */
105
104
  onCreate(onCreate) {
106
105
  return this.assignOptions({ onCreate });
107
106
  }
108
107
  /**
109
108
  * Automatically update the property value every time entity gets updated, executed during flush operation.
110
- * @param entity
111
109
  */
112
110
  onUpdate(onUpdate) {
113
111
  return this.assignOptions({ onUpdate });
@@ -455,6 +453,9 @@ class UniversalPropertyOptionsBuilder {
455
453
  orphanRemoval(orphanRemoval = true) {
456
454
  return this.assignOptions({ orphanRemoval });
457
455
  }
456
+ accessor(accessor = true) {
457
+ return this.assignOptions({ accessor });
458
+ }
458
459
  }
459
460
  exports.UniversalPropertyOptionsBuilder = UniversalPropertyOptionsBuilder;
460
461
  /** @internal */
@@ -1,22 +1,22 @@
1
1
  import type { EntityData, EntityMetadata } from '../typings';
2
2
  import { Hydrator } from './Hydrator';
3
3
  import type { EntityFactory } from '../entity/EntityFactory';
4
- type EntityHydrator<T extends object> = (entity: T, data: EntityData<T>, factory: EntityFactory, newEntity: boolean, convertCustomTypes: boolean, schema?: string, parentSchema?: string) => void;
4
+ type EntityHydrator<T extends object> = (entity: T, data: EntityData<T>, factory: EntityFactory, newEntity: boolean, convertCustomTypes: boolean, schema?: string, parentSchema?: string, normalizeAccessors?: boolean) => void;
5
5
  export declare class ObjectHydrator extends Hydrator {
6
6
  private readonly hydrators;
7
7
  private tmpIndex;
8
8
  /**
9
9
  * @inheritDoc
10
10
  */
11
- hydrate<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, type: 'full' | 'reference', newEntity?: boolean, convertCustomTypes?: boolean, schema?: string, parentSchema?: string): void;
11
+ hydrate<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, type: 'full' | 'reference', newEntity?: boolean, convertCustomTypes?: boolean, schema?: string, parentSchema?: string, normalizeAccessors?: boolean): void;
12
12
  /**
13
13
  * @inheritDoc
14
14
  */
15
- hydrateReference<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, convertCustomTypes?: boolean, schema?: string, parentSchema?: string): void;
15
+ hydrateReference<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, convertCustomTypes?: boolean, schema?: string, parentSchema?: string, normalizeAccessors?: boolean): void;
16
16
  /**
17
17
  * @internal Highly performance-sensitive method.
18
18
  */
19
- getEntityHydrator<T extends object>(meta: EntityMetadata<T>, type: 'full' | 'reference'): EntityHydrator<T>;
19
+ getEntityHydrator<T extends object>(meta: EntityMetadata<T>, type: 'full' | 'reference', normalizeAccessors?: boolean): EntityHydrator<T>;
20
20
  private createCollectionItemMapper;
21
21
  private wrap;
22
22
  private safeKey;
@@ -9,37 +9,40 @@ const enums_1 = require("../enums");
9
9
  const RawQueryFragment_1 = require("../utils/RawQueryFragment");
10
10
  class ObjectHydrator extends Hydrator_1.Hydrator {
11
11
  hydrators = {
12
- full: new Map(),
13
- reference: new Map(),
12
+ 'full~true': new Map(),
13
+ 'full~false': new Map(),
14
+ 'reference~true': new Map(),
15
+ 'reference~false': new Map(),
14
16
  };
15
17
  tmpIndex = 0;
16
18
  /**
17
19
  * @inheritDoc
18
20
  */
19
- hydrate(entity, meta, data, factory, type, newEntity = false, convertCustomTypes = false, schema, parentSchema) {
20
- const hydrate = this.getEntityHydrator(meta, type);
21
+ hydrate(entity, meta, data, factory, type, newEntity = false, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
22
+ const hydrate = this.getEntityHydrator(meta, type, normalizeAccessors);
21
23
  const running = this.running;
22
24
  // the running state is used to consider propagation as hydration, saving the values directly to the entity data,
23
25
  // but we don't want that for new entities, their propagation should result in entity updates when flushing
24
26
  this.running = !newEntity;
25
- Utils_1.Utils.callCompiledFunction(hydrate, entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema);
27
+ Utils_1.Utils.callCompiledFunction(hydrate, entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors);
26
28
  this.running = running;
27
29
  }
28
30
  /**
29
31
  * @inheritDoc
30
32
  */
31
- hydrateReference(entity, meta, data, factory, convertCustomTypes = false, schema, parentSchema) {
32
- const hydrate = this.getEntityHydrator(meta, 'reference');
33
+ hydrateReference(entity, meta, data, factory, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
34
+ const hydrate = this.getEntityHydrator(meta, 'reference', normalizeAccessors);
33
35
  const running = this.running;
34
36
  this.running = true;
35
- Utils_1.Utils.callCompiledFunction(hydrate, entity, data, factory, false, convertCustomTypes, schema, parentSchema);
37
+ Utils_1.Utils.callCompiledFunction(hydrate, entity, data, factory, false, convertCustomTypes, schema, parentSchema, normalizeAccessors);
36
38
  this.running = running;
37
39
  }
38
40
  /**
39
41
  * @internal Highly performance-sensitive method.
40
42
  */
41
- getEntityHydrator(meta, type) {
42
- const exists = this.hydrators[type].get(meta.className);
43
+ getEntityHydrator(meta, type, normalizeAccessors = false) {
44
+ const key = `${type}~${normalizeAccessors}`;
45
+ const exists = this.hydrators[key].get(meta.className);
43
46
  if (exists) {
44
47
  return exists;
45
48
  }
@@ -135,17 +138,17 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
135
138
  ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
136
139
  ret.push(` if (isPrimaryKey(data${dataKey}, true)) {`);
137
140
  if (prop.ref) {
138
- ret.push(` entity${entityKey} = Reference.create(factory.createReference('${prop.type}', data${dataKey}, { merge: true, convertCustomTypes, schema }));`);
141
+ ret.push(` entity${entityKey} = Reference.create(factory.createReference('${prop.type}', data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema }));`);
139
142
  }
140
143
  else {
141
- ret.push(` entity${entityKey} = factory.createReference('${prop.type}', data${dataKey}, { merge: true, convertCustomTypes, schema });`);
144
+ ret.push(` entity${entityKey} = factory.createReference('${prop.type}', data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema });`);
142
145
  }
143
146
  ret.push(` } else if (data${dataKey} && typeof data${dataKey} === 'object') {`);
144
147
  if (prop.ref) {
145
- ret.push(` entity${entityKey} = Reference.create(factory.${method}('${prop.type}', data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, schema }));`);
148
+ ret.push(` entity${entityKey} = Reference.create(factory.${method}('${prop.type}', data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema }));`);
146
149
  }
147
150
  else {
148
- ret.push(` entity${entityKey} = factory.${method}('${prop.type}', data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, schema });`);
151
+ ret.push(` entity${entityKey} = factory.${method}('${prop.type}', data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema });`);
149
152
  }
150
153
  ret.push(` }`);
151
154
  ret.push(` }`);
@@ -254,7 +257,7 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
254
257
  // weak comparison as we can have numbers that might have been converted to strings due to being object keys
255
258
  ret.push(` if (data${childDataKey} == '${childMeta.discriminatorValue}') {`);
256
259
  ret.push(` if (entity${entityKey} == null) {`);
257
- ret.push(` entity${entityKey} = factory.createEmbeddable('${childMeta.className}', embeddedData, { newEntity, convertCustomTypes });`);
260
+ ret.push(` entity${entityKey} = factory.createEmbeddable('${childMeta.className}', embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`);
258
261
  ret.push(` }`);
259
262
  meta.props
260
263
  .filter(p => p.embedded?.[0] === prop.name)
@@ -275,7 +278,7 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
275
278
  }
276
279
  else {
277
280
  ret.push(` if (entity${entityKey} == null) {`);
278
- ret.push(` entity${entityKey} = factory.createEmbeddable('${prop.targetMeta.className}', embeddedData, { newEntity, convertCustomTypes });`);
281
+ ret.push(` entity${entityKey} = factory.createEmbeddable('${prop.targetMeta.className}', embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`);
279
282
  ret.push(` }`);
280
283
  meta.props
281
284
  .filter(p => p.embedded?.[0] === prop.name)
@@ -313,7 +316,7 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
313
316
  };
314
317
  const hydrateProperty = (prop, object = prop.object, path = [prop.name], dataKey) => {
315
318
  const entityKey = path.map(k => this.wrap(k)).join('');
316
- dataKey = dataKey ?? (object ? entityKey : this.wrap(prop.name));
319
+ dataKey = dataKey ?? (object ? entityKey : this.wrap(normalizeAccessors ? (prop.accessor ?? prop.name) : prop.name));
317
320
  const ret = [];
318
321
  if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.mapToPk) {
319
322
  ret.push(...hydrateToOne(prop, dataKey, entityKey));
@@ -343,11 +346,11 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
343
346
  for (const prop of props) {
344
347
  lines.push(...hydrateProperty(prop));
345
348
  }
346
- const code = `// compiled hydrator for entity ${meta.className} (${type})\n`
347
- + `return function(entity, data, factory, newEntity, convertCustomTypes, schema) {\n`
349
+ const code = `// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n`
350
+ + `return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n`
348
351
  + `${lines.join('\n')}\n}`;
349
352
  const hydrator = Utils_1.Utils.createFunction(context, code);
350
- this.hydrators[type].set(meta.className, hydrator);
353
+ this.hydrators[key].set(meta.className, hydrator);
351
354
  return hydrator;
352
355
  }
353
356
  createCollectionItemMapper(prop) {
@@ -360,9 +363,9 @@ class ObjectHydrator extends Hydrator_1.Hydrator {
360
363
  lines.push(` value = { ...value, ['${prop2.name}']: Reference.wrapReference(entity, { ref: ${prop2.ref} }) };`);
361
364
  lines.push(` }`);
362
365
  }
363
- lines.push(` if (isPrimaryKey(value, ${meta.compositePK})) return factory.createReference('${prop.type}', value, { convertCustomTypes, schema, merge: true });`);
366
+ lines.push(` if (isPrimaryKey(value, ${meta.compositePK})) return factory.createReference('${prop.type}', value, { convertCustomTypes, schema, normalizeAccessors, merge: true });`);
364
367
  lines.push(` if (value && value.__entity) return value;`);
365
- lines.push(` return factory.create('${prop.type}', value, { newEntity, convertCustomTypes, schema, merge: true });`);
368
+ lines.push(` return factory.create('${prop.type}', value, { newEntity, convertCustomTypes, schema, normalizeAccessors, merge: true });`);
366
369
  lines.push(` }`);
367
370
  return lines;
368
371
  }
@@ -18,6 +18,7 @@ export declare class MetadataDiscovery {
18
18
  discover(preferTsNode?: boolean): Promise<MetadataStorage>;
19
19
  discoverSync(preferTsNode?: boolean): MetadataStorage;
20
20
  private mapDiscoveredEntities;
21
+ private initAccessors;
21
22
  processDiscoveredEntities(discovered: EntityMetadata[]): EntityMetadata[];
22
23
  private findEntities;
23
24
  private discoverMissingTargets;
@@ -76,11 +76,42 @@ class MetadataDiscovery {
76
76
  });
77
77
  return discovered;
78
78
  }
79
+ initAccessors(meta) {
80
+ for (const prop of Object.values(meta.properties)) {
81
+ if (!prop.accessor || meta.properties[prop.accessor]) {
82
+ continue;
83
+ }
84
+ const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
85
+ if (desc?.get || desc?.set) {
86
+ this.initFieldName(prop);
87
+ const accessor = prop.name;
88
+ prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
89
+ if (prop.accessor === true) {
90
+ prop.getter = prop.setter = true;
91
+ }
92
+ else {
93
+ prop.getter = prop.setter = false;
94
+ }
95
+ prop.accessor = accessor;
96
+ prop.serializedName ??= accessor;
97
+ Utils_1.Utils.renameKey(meta.properties, accessor, prop.name);
98
+ }
99
+ else {
100
+ const name = prop.name;
101
+ prop.name = prop.accessor;
102
+ this.initFieldName(prop);
103
+ prop.serializedName ??= prop.accessor;
104
+ prop.name = name;
105
+ prop.trackChanges = false;
106
+ }
107
+ }
108
+ }
79
109
  processDiscoveredEntities(discovered) {
80
110
  for (const meta of discovered) {
81
111
  let i = 1;
82
112
  Object.values(meta.properties).forEach(prop => meta.propertyOrder.set(prop.name, i++));
83
113
  Object.values(meta.properties).forEach(prop => this.initPolyEmbeddables(prop, discovered));
114
+ this.initAccessors(meta);
84
115
  }
85
116
  // ignore base entities (not annotated with @Entity)
86
117
  const filtered = discovered.filter(meta => meta.root.name);
@@ -1026,8 +1057,7 @@ class MetadataDiscovery {
1026
1057
  return '1';
1027
1058
  }
1028
1059
  inferDefaultValue(meta, prop) {
1029
- /* istanbul ignore next */
1030
- if (!meta.class) {
1060
+ if (!meta.class || !this.config.get('discovery').inferDefaultValues) {
1031
1061
  return;
1032
1062
  }
1033
1063
  try {
@@ -1036,7 +1066,7 @@ class MetadataDiscovery {
1036
1066
  const entity1 = new meta.class();
1037
1067
  const entity2 = new meta.class();
1038
1068
  // we compare the two values by reference, this will discard things like `new Date()` or `Date.now()`
1039
- if (this.config.get('discovery').inferDefaultValues && prop.default === undefined && entity1[prop.name] != null && entity1[prop.name] === entity2[prop.name] && entity1[prop.name] !== now) {
1069
+ if (prop.default === undefined && entity1[prop.name] != null && entity1[prop.name] === entity2[prop.name] && entity1[prop.name] !== now) {
1040
1070
  prop.default ??= entity1[prop.name];
1041
1071
  }
1042
1072
  // if the default value is null, infer nullability
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "6.5.10-dev.25",
3
+ "version": "6.5.10-dev.27",
4
4
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",
@@ -64,7 +64,7 @@
64
64
  "esprima": "4.0.1",
65
65
  "fs-extra": "11.3.2",
66
66
  "globby": "11.1.0",
67
- "mikro-orm": "6.5.10-dev.25",
67
+ "mikro-orm": "6.5.10-dev.27",
68
68
  "reflect-metadata": "0.2.2"
69
69
  }
70
70
  }
@@ -19,7 +19,7 @@ function isVisible(meta, propName, options) {
19
19
  return false;
20
20
  }
21
21
  const visible = prop && !(prop.hidden && !options.includeHidden);
22
- const prefixed = prop && !prop.primary && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
22
+ const prefixed = prop && !prop.primary && !prop.accessor && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
23
23
  return visible && !prefixed;
24
24
  }
25
25
  function isPopulated(propName, options) {
@@ -8,7 +8,7 @@ const SerializationContext_1 = require("./SerializationContext");
8
8
  function isVisible(meta, propName, ignoreFields = []) {
9
9
  const prop = meta.properties[propName];
10
10
  const visible = prop && !prop.hidden;
11
- const prefixed = prop && !prop.primary && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
11
+ const prefixed = prop && !prop.primary && !prop.accessor && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
12
12
  return visible && !prefixed && !ignoreFields.includes(propName);
13
13
  }
14
14
  class EntityTransformer {
package/typings.d.ts CHANGED
@@ -379,6 +379,7 @@ export interface EntityProperty<Owner = any, Target = any> {
379
379
  setter?: boolean;
380
380
  getter?: boolean;
381
381
  getterName?: keyof Owner;
382
+ accessor?: EntityKey<Owner>;
382
383
  cascade: Cascade[];
383
384
  orphanRemoval?: boolean;
384
385
  onCreate?: (entity: Owner, em: EntityManager) => any;
@@ -819,11 +820,11 @@ export interface IHydrator {
819
820
  * Hydrates the whole entity. This process handles custom type conversions, creating missing Collection instances,
820
821
  * mapping FKs to entity instances, as well as merging those entities.
821
822
  */
822
- hydrate<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, type: 'full' | 'reference', newEntity?: boolean, convertCustomTypes?: boolean, schema?: string, parentSchema?: string): void;
823
+ hydrate<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, type: 'full' | 'reference', newEntity?: boolean, convertCustomTypes?: boolean, schema?: string, parentSchema?: string, normalizeAccessors?: boolean): void;
823
824
  /**
824
825
  * Hydrates primary keys only
825
826
  */
826
- hydrateReference<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, convertCustomTypes?: boolean, schema?: string, parentSchema?: string): void;
827
+ hydrateReference<T extends object>(entity: T, meta: EntityMetadata<T>, data: EntityData<T>, factory: EntityFactory, convertCustomTypes?: boolean, schema?: string, parentSchema?: string, normalizeAccessors?: boolean): void;
827
828
  isRunning(): boolean;
828
829
  }
829
830
  export interface HydratorConstructor {