@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.
- package/EntityManager.d.ts +12 -9
- package/EntityManager.js +71 -47
- package/decorators/Property.d.ts +53 -3
- package/entity/Collection.js +2 -0
- package/entity/EntityFactory.d.ts +1 -0
- package/entity/EntityFactory.js +6 -3
- package/entity/EntityHelper.js +17 -2
- package/entity/EntityLoader.d.ts +3 -3
- package/entity/EntityLoader.js +20 -2
- package/entity/Reference.d.ts +1 -0
- package/entity/Reference.js +6 -2
- package/entity/defineEntity.d.ts +10 -6
- package/entity/defineEntity.js +9 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +25 -22
- package/index.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +1 -0
- package/metadata/MetadataDiscovery.js +34 -4
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +7 -1
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/package.json +2 -2
- package/serialization/EntitySerializer.js +1 -1
- package/serialization/EntityTransformer.js +1 -1
- package/typings.d.ts +11 -4
- package/utils/Configuration.d.ts +4 -0
- package/utils/Configuration.js +9 -0
- package/utils/EntityComparator.js +11 -1
- package/utils/QueryHelper.d.ts +3 -1
- package/utils/QueryHelper.js +18 -0
- package/utils/RawQueryFragment.d.ts +2 -2
- package/utils/Utils.js +2 -2
package/entity/defineEntity.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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[
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
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}
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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 {
|
package/utils/Configuration.d.ts
CHANGED
|
@@ -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: {
|
package/utils/Configuration.js
CHANGED
|
@@ -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) {
|
package/utils/QueryHelper.d.ts
CHANGED
|
@@ -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:
|
|
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;
|
package/utils/QueryHelper.js
CHANGED
|
@@ -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(
|
|
720
|
+
const type = objectType.match(/^\[object (.+)]$/)[1];
|
|
721
721
|
if (type === 'Uint8Array') {
|
|
722
722
|
return 'Buffer';
|
|
723
723
|
}
|
|
724
|
-
return
|
|
724
|
+
return type;
|
|
725
725
|
}
|
|
726
726
|
/**
|
|
727
727
|
* Checks whether the value is POJO (e.g. `{ foo: 'bar' }`, and not instance of `Foo`)
|