@mikro-orm/core 6.5.10-dev.9 → 6.6.0

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.
@@ -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 });
@@ -126,6 +124,12 @@ class UniversalPropertyOptionsBuilder {
126
124
  defaultRaw(defaultRaw) {
127
125
  return this.assignOptions({ defaultRaw });
128
126
  }
127
+ /**
128
+ * Allow controlling `filters` option. This will be overridden with `em.fork` or `FindOptions` if provided.
129
+ */
130
+ filters(filters) {
131
+ return this.assignOptions({ filters });
132
+ }
129
133
  /**
130
134
  * Set to map some SQL snippet for the entity.
131
135
  *
@@ -449,6 +453,9 @@ class UniversalPropertyOptionsBuilder {
449
453
  orphanRemoval(orphanRemoval = true) {
450
454
  return this.assignOptions({ orphanRemoval });
451
455
  }
456
+ accessor(accessor = true) {
457
+ return this.assignOptions({ accessor });
458
+ }
452
459
  }
453
460
  exports.UniversalPropertyOptionsBuilder = UniversalPropertyOptionsBuilder;
454
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
  }
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @packageDocumentation
3
3
  * @module core
4
4
  */
5
- export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, IndexCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, } from './typings';
5
+ export { Constructor, ConnectionType, Dictionary, PrimaryKeyProp, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, EntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, EntityMetadata, QBFilterQuery, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, EntityRepositoryType, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, MigrationDiff, GenerateOptions, FilterObject, IEntityGenerator, ISeedManager, EntityClassGroup, OptionalProps, EagerProps, HiddenProps, RequiredEntityData, CheckCallback, IndexCallback, SimpleColumnMeta, Rel, Ref, ScalarRef, EntityRef, ISchemaGenerator, UmzugMigration, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, Opt, EntityType, FromEntityType, Selected, IsSubset, NoInfer, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, Hidden, FilterValue, MergeLoaded, MergeSelected, Config, DefineConfig, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, } from './typings';
6
6
  export * from './enums';
7
7
  export * from './errors';
8
8
  export * from './exceptions';
@@ -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);
@@ -956,7 +987,7 @@ class MetadataDiscovery {
956
987
  newProp.items = Utils_1.Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
957
988
  }
958
989
  newProp.nullable = true;
959
- newProp.inherited = true;
990
+ newProp.inherited = !meta.root.properties[prop.name];
960
991
  meta.root.addProperty(newProp);
961
992
  });
962
993
  meta.collection = meta.root.collection;
@@ -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
@@ -12,7 +12,11 @@ export declare abstract class AbstractNamingStrategy implements NamingStrategy {
12
12
  /**
13
13
  * @inheritDoc
14
14
  */
15
- getEnumClassName(columnName: string, tableName: string, schemaName?: string): string;
15
+ getEnumClassName(columnName: string, tableName: string | undefined, schemaName?: string): string;
16
+ /**
17
+ * @inheritDoc
18
+ */
19
+ getEnumTypeName(columnName: string, tableName: string | undefined, schemaName?: string): string;
16
20
  /**
17
21
  * @inheritDoc
18
22
  */
@@ -51,7 +51,13 @@ class AbstractNamingStrategy {
51
51
  * @inheritDoc
52
52
  */
53
53
  getEnumClassName(columnName, tableName, schemaName) {
54
- return this.getEntityName(`${tableName}_${columnName}`, schemaName);
54
+ return this.getEntityName(tableName ? `${tableName}_${columnName}` : columnName, schemaName);
55
+ }
56
+ /**
57
+ * @inheritDoc
58
+ */
59
+ getEnumTypeName(columnName, tableName, schemaName) {
60
+ return 'T' + this.getEnumClassName(columnName, tableName, schemaName);
55
61
  }
56
62
  /**
57
63
  * @inheritDoc
@@ -25,7 +25,17 @@ export interface NamingStrategy {
25
25
  *
26
26
  * @return A new class name that will be used for the enum.
27
27
  */
28
- getEnumClassName(columnName: string, tableName: string, schemaName?: string): string;
28
+ getEnumClassName(columnName: string, tableName: string | undefined, schemaName?: string): string;
29
+ /**
30
+ * Get an enum type name. Used with `enumType: 'dictionary'` and `enumType: 'union-type'` entity generator option.
31
+ *
32
+ * @param columnName The column name which has the enum.
33
+ * @param tableName The table name of the column.
34
+ * @param schemaName The schema name of the column.
35
+ *
36
+ * @return A new type name that will be used for the enum.
37
+ */
38
+ getEnumTypeName(columnName: string, tableName: string | undefined, schemaName?: string): string;
29
39
  /**
30
40
  * Get an enum option name for a given enum value.
31
41
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
- "version": "6.5.10-dev.9",
3
+ "version": "6.6.0",
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.9",
67
+ "mikro-orm": "6.6.0",
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
@@ -10,7 +10,7 @@ import type { Configuration, RawQueryFragment } from './utils';
10
10
  import type { EntityManager } from './EntityManager';
11
11
  import type { EmbeddedPrefixMode } from './decorators/Embedded';
12
12
  import type { EventSubscriber } from './events';
13
- import type { FindOneOptions, FindOptions, LoadHint } from './drivers';
13
+ import type { FilterOptions, FindOneOptions, FindOptions, LoadHint } from './drivers';
14
14
  export type Constructor<T = unknown> = new (...args: any[]) => T;
15
15
  export type Dictionary<T = any> = {
16
16
  [k: string]: T;
@@ -351,6 +351,7 @@ export interface EntityProperty<Owner = any, Target = any> {
351
351
  default?: string | number | boolean | null;
352
352
  defaultRaw?: string;
353
353
  formula?: (alias: string) => string;
354
+ filters?: FilterOptions;
354
355
  prefix?: string | boolean;
355
356
  prefixMode?: EmbeddedPrefixMode;
356
357
  embedded?: [EntityKey<Owner>, EntityKey<Owner>];
@@ -378,6 +379,7 @@ export interface EntityProperty<Owner = any, Target = any> {
378
379
  setter?: boolean;
379
380
  getter?: boolean;
380
381
  getterName?: keyof Owner;
382
+ accessor?: EntityKey<Owner>;
381
383
  cascade: Cascade[];
382
384
  orphanRemoval?: boolean;
383
385
  onCreate?: (entity: Owner, em: EntityManager) => any;
@@ -577,7 +579,9 @@ export interface GenerateOptions {
577
579
  undefinedDefaults?: boolean;
578
580
  bidirectionalRelations?: boolean;
579
581
  identifiedReferences?: boolean;
580
- entitySchema?: boolean;
582
+ entityDefinition?: 'decorators' | 'defineEntity' | 'entitySchema';
583
+ inferEntityType?: boolean;
584
+ enumMode?: 'ts-enum' | 'union-type' | 'dictionary';
581
585
  esmImport?: boolean;
582
586
  scalarTypeInDecorator?: boolean;
583
587
  scalarPropertiesForRelations?: 'always' | 'never' | 'smart';
@@ -592,6 +596,8 @@ export interface GenerateOptions {
592
596
  coreImportsPrefix?: string;
593
597
  onInitialMetadata?: MetadataProcessor;
594
598
  onProcessedMetadata?: MetadataProcessor;
599
+ /** @deprecated use `entityDefinition: 'entitySchema'` instead */
600
+ entitySchema?: boolean;
595
601
  }
596
602
  export interface IEntityGenerator {
597
603
  generate(options?: GenerateOptions): Promise<string[]>;
@@ -710,6 +716,7 @@ export type FilterDef = {
710
716
  default?: boolean;
711
717
  entity?: string[];
712
718
  args?: boolean;
719
+ strict?: boolean;
713
720
  };
714
721
  export type Populate<T, P extends string = never> = readonly AutoPath<T, P, `${PopulatePath}`>[] | false;
715
722
  export type PopulateOptions<T> = {
@@ -813,11 +820,11 @@ export interface IHydrator {
813
820
  * Hydrates the whole entity. This process handles custom type conversions, creating missing Collection instances,
814
821
  * mapping FKs to entity instances, as well as merging those entities.
815
822
  */
816
- 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;
817
824
  /**
818
825
  * Hydrates primary keys only
819
826
  */
820
- 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;
821
828
  isRunning(): boolean;
822
829
  }
823
830
  export interface HydratorConstructor {
@@ -61,6 +61,7 @@ export declare class Configuration<D extends IDatabaseDriver = IDatabaseDriver,
61
61
  onQuery: (sql: string) => string;
62
62
  autoJoinOneToOneOwner: true;
63
63
  autoJoinRefsForFilters: true;
64
+ filtersOnRelations: true;
64
65
  propagationOnPrototype: true;
65
66
  populateAfterFlush: true;
66
67
  serialization: {
@@ -117,6 +118,8 @@ export declare class Configuration<D extends IDatabaseDriver = IDatabaseDriver,
117
118
  identifiedReferences: false;
118
119
  scalarTypeInDecorator: false;
119
120
  scalarPropertiesForRelations: "never";
121
+ entityDefinition: "decorators";
122
+ enumMode: "ts-enum";
120
123
  fileName: (className: string) => string;
121
124
  onlyPurePivotTables: false;
122
125
  outputPurePivotTables: false;
@@ -337,6 +340,7 @@ export interface MikroORMOptions<D extends IDatabaseDriver = IDatabaseDriver, EM
337
340
  onQuery: (sql: string, params: unknown[]) => string;
338
341
  autoJoinOneToOneOwner: boolean;
339
342
  autoJoinRefsForFilters: boolean;
343
+ filtersOnRelations: boolean;
340
344
  propagationOnPrototype: boolean;
341
345
  populateAfterFlush: boolean;
342
346
  serialization: {
@@ -55,6 +55,7 @@ class Configuration {
55
55
  onQuery: sql => sql,
56
56
  autoJoinOneToOneOwner: true,
57
57
  autoJoinRefsForFilters: true,
58
+ filtersOnRelations: true,
58
59
  propagationOnPrototype: true,
59
60
  populateAfterFlush: true,
60
61
  serialization: {
@@ -111,6 +112,8 @@ class Configuration {
111
112
  identifiedReferences: false,
112
113
  scalarTypeInDecorator: false,
113
114
  scalarPropertiesForRelations: 'never',
115
+ entityDefinition: 'decorators',
116
+ enumMode: 'ts-enum',
114
117
  fileName: (className) => className,
115
118
  onlyPurePivotTables: false,
116
119
  outputPurePivotTables: false,
@@ -339,6 +342,9 @@ class Configuration {
339
342
  Object.keys(this.options.filters).forEach(key => {
340
343
  this.options.filters[key].default ??= true;
341
344
  });
345
+ if (!this.options.filtersOnRelations) {
346
+ this.options.autoJoinRefsForFilters ??= false;
347
+ }
342
348
  this.options.subscribers = Utils_1.Utils.unique(this.options.subscribers).map(subscriber => {
343
349
  return subscriber.constructor.name === 'Function' ? new subscriber() : subscriber;
344
350
  });
@@ -350,6 +356,9 @@ class Configuration {
350
356
  sync() {
351
357
  process.env.MIKRO_ORM_COLORS = '' + this.options.colors;
352
358
  this.options.tsNode = this.options.preferTs;
359
+ if (this.options.entityGenerator.entitySchema) {
360
+ this.options.entityGenerator.entityDefinition = 'entitySchema';
361
+ }
353
362
  this.logger.setDebugMode(this.options.debug);
354
363
  }
355
364
  /**
@@ -420,11 +420,21 @@ class EntityComparator {
420
420
  }
421
421
  getEmbeddedPropertySnapshot(meta, prop, context, level, path, dataKey, object = prop.object) {
422
422
  const padding = ' '.repeat(level * 2);
423
+ const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
423
424
  let ret = `${level === 1 ? '' : '\n'}`;
424
425
  if (object) {
425
- const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
426
426
  ret += `${padding}if (${nullCond}) ret${dataKey} = null;\n`;
427
427
  }
428
+ else {
429
+ ret += `${padding}if (${nullCond}) {\n`;
430
+ ret += meta.props.filter(p => p.embedded?.[0] === prop.name
431
+ // object for JSON embeddable
432
+ && (p.object || (p.persist !== false))).map(childProp => {
433
+ const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
434
+ return `${padding} ret${childDataKey} = null;`;
435
+ }).join('\n') + `\n`;
436
+ ret += `${padding}}\n`;
437
+ }
428
438
  const cond = `entity${path.map(k => this.wrap(k)).join('')} != null`;
429
439
  ret += `${padding}if (${cond}) {\n`;
430
440
  if (object) {
@@ -1,6 +1,7 @@
1
1
  import type { Dictionary, EntityMetadata, EntityProperty, FilterDef, FilterQuery } from '../typings';
2
2
  import type { Platform } from '../platforms';
3
3
  import type { MetadataStorage } from '../metadata/MetadataStorage';
4
+ import type { FilterOptions } from '../drivers/IDatabaseDriver';
4
5
  /** @internal */
5
6
  export declare class QueryHelper {
6
7
  static readonly SUPPORTED_OPERATORS: string[];
@@ -13,7 +14,8 @@ export declare class QueryHelper {
13
14
  static liftGroupOperators<T extends object>(where: Dictionary, meta: EntityMetadata<T>, metadata: MetadataStorage, key?: string): string | undefined;
14
15
  static inlinePrimaryKeyObjects<T extends object>(where: Dictionary, meta: EntityMetadata<T>, metadata: MetadataStorage, key?: string): boolean;
15
16
  static processWhere<T extends object>(options: ProcessWhereOptions<T>): FilterQuery<T>;
16
- static getActiveFilters(entityName: string, options: Dictionary<boolean | Dictionary> | string[] | boolean, filters: Dictionary<FilterDef>): FilterDef[];
17
+ static getActiveFilters(entityName: string, options: FilterOptions | undefined, filters: Dictionary<FilterDef>): FilterDef[];
18
+ static mergePropertyFilters(propFilters: FilterOptions | undefined, options: FilterOptions | undefined): FilterOptions | undefined;
17
19
  static isFilterActive(entityName: string, filterName: string, filter: FilterDef, options: Dictionary<boolean | Dictionary>): boolean;
18
20
  static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>;
19
21
  private static isSupportedOperator;
@@ -205,6 +205,24 @@ class QueryHelper {
205
205
  return filters[f];
206
206
  });
207
207
  }
208
+ static mergePropertyFilters(propFilters, options) {
209
+ if (!options || !propFilters || options === true || propFilters === true) {
210
+ return options ?? propFilters;
211
+ }
212
+ if (Array.isArray(propFilters)) {
213
+ propFilters = propFilters.reduce((o, item) => {
214
+ o[item] = true;
215
+ return o;
216
+ }, {});
217
+ }
218
+ if (Array.isArray(options)) {
219
+ options = options.reduce((o, item) => {
220
+ o[item] = true;
221
+ return o;
222
+ }, {});
223
+ }
224
+ return Utils_1.Utils.mergeConfig({}, propFilters, options);
225
+ }
208
226
  static isFilterActive(entityName, filterName, filter, options) {
209
227
  if (filter.entity && !filter.entity.includes(entityName)) {
210
228
  return false;
@@ -89,7 +89,7 @@ export declare const ALIAS_REPLACEMENT_RE = "\\[::alias::\\]";
89
89
  * export class Author { ... }
90
90
  * ```
91
91
  */
92
- export declare function raw<T extends object = any, R = any>(sql: EntityKey<T> | EntityKey<T>[] | AnyString | ((alias: string) => string) | RawQueryFragment, params?: readonly unknown[] | Dictionary<unknown>): R;
92
+ export declare function raw<T extends object = any, R = any>(sql: EntityKey<T> | EntityKey<T>[] | AnyString | ((alias: string) => string) | RawQueryFragment, params?: readonly unknown[] | Dictionary<unknown>): NoInfer<R>;
93
93
  /**
94
94
  * Alternative to the `raw()` helper allowing to use it as a tagged template function for the simple cases.
95
95
  *
@@ -106,7 +106,7 @@ export declare function raw<T extends object = any, R = any>(sql: EntityKey<T> |
106
106
  */
107
107
  export declare function sql(sql: readonly string[], ...values: unknown[]): any;
108
108
  export declare namespace sql {
109
- var ref: <T extends object>(...keys: string[]) => RawQueryFragment;
109
+ var ref: <T extends object>(...keys: string[]) => NoInfer<RawQueryFragment>;
110
110
  var now: (length?: number) => string;
111
111
  var lower: <T extends object>(key: string | ((alias: string) => string)) => string;
112
112
  var upper: <T extends object>(key: string | ((alias: string) => string)) => string;
package/utils/Utils.js CHANGED
@@ -717,11 +717,11 @@ class Utils {
717
717
  return simple;
718
718
  }
719
719
  const objectType = Object.prototype.toString.call(value);
720
- const type = objectType.match(/\[object (\w+)]/)[1];
720
+ const type = objectType.match(/^\[object (.+)]$/)[1];
721
721
  if (type === 'Uint8Array') {
722
722
  return 'Buffer';
723
723
  }
724
- return ['Date', 'Buffer', 'RegExp'].includes(type) ? type : type.toLowerCase();
724
+ return type;
725
725
  }
726
726
  /**
727
727
  * Checks whether the value is POJO (e.g. `{ foo: 'bar' }`, and not instance of `Foo`)