@mikro-orm/core 7.0.0-dev.4 → 7.0.0-dev.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EntityManager.d.ts +84 -18
- package/EntityManager.js +265 -172
- package/MikroORM.d.ts +7 -5
- package/MikroORM.js +0 -1
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +2 -1
- package/cache/FileCacheAdapter.js +6 -4
- package/connections/Connection.d.ts +4 -2
- package/connections/Connection.js +2 -2
- package/decorators/Check.d.ts +2 -2
- package/decorators/Embeddable.d.ts +5 -5
- package/decorators/Embeddable.js +1 -1
- package/decorators/Embedded.d.ts +6 -12
- package/decorators/Entity.d.ts +18 -3
- package/decorators/Enum.d.ts +1 -1
- package/decorators/Formula.d.ts +1 -2
- package/decorators/Indexed.d.ts +2 -2
- package/decorators/ManyToMany.d.ts +4 -2
- package/decorators/ManyToOne.d.ts +6 -2
- package/decorators/OneToMany.d.ts +4 -4
- package/decorators/OneToOne.d.ts +5 -1
- package/decorators/PrimaryKey.d.ts +2 -3
- package/decorators/Property.d.ts +54 -4
- package/decorators/Transactional.d.ts +1 -0
- package/decorators/Transactional.js +3 -3
- package/decorators/index.d.ts +1 -1
- package/drivers/DatabaseDriver.d.ts +4 -3
- package/drivers/IDatabaseDriver.d.ts +22 -2
- package/entity/ArrayCollection.d.ts +4 -2
- package/entity/ArrayCollection.js +18 -6
- package/entity/Collection.d.ts +1 -2
- package/entity/Collection.js +19 -10
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +9 -1
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +29 -9
- package/entity/EntityHelper.js +25 -3
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +74 -37
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityValidator.js +1 -1
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +30 -3
- package/entity/WrappedEntity.js +1 -1
- package/entity/defineEntity.d.ts +561 -0
- package/entity/defineEntity.js +537 -0
- package/entity/index.d.ts +2 -0
- package/entity/index.js +2 -0
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +15 -3
- package/enums.d.ts +16 -3
- package/enums.js +13 -0
- package/errors.d.ts +6 -0
- package/errors.js +14 -0
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +35 -24
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +8 -4
- package/metadata/EntitySchema.js +39 -19
- package/metadata/MetadataDiscovery.d.ts +1 -1
- package/metadata/MetadataDiscovery.js +88 -32
- package/metadata/MetadataStorage.js +1 -1
- package/metadata/MetadataValidator.js +4 -3
- 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 +5 -5
- package/platforms/Platform.d.ts +5 -3
- package/platforms/Platform.js +4 -8
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +2 -2
- package/serialization/EntityTransformer.js +1 -1
- package/serialization/SerializationContext.js +14 -11
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +3 -0
- package/types/BooleanType.d.ts +1 -1
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +1 -1
- package/types/DoubleType.js +1 -1
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/index.d.ts +1 -1
- package/typings.d.ts +88 -39
- package/typings.js +24 -4
- package/unit-of-work/ChangeSetComputer.js +3 -1
- package/unit-of-work/ChangeSetPersister.d.ts +4 -2
- package/unit-of-work/ChangeSetPersister.js +37 -16
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +109 -41
- package/utils/Configuration.d.ts +23 -5
- package/utils/Configuration.js +17 -3
- package/utils/ConfigurationLoader.d.ts +0 -2
- package/utils/ConfigurationLoader.js +2 -24
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +3 -0
- package/utils/DataloaderUtils.d.ts +7 -2
- package/utils/DataloaderUtils.js +38 -7
- package/utils/EntityComparator.d.ts +6 -2
- package/utils/EntityComparator.js +104 -58
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +66 -5
- package/utils/RawQueryFragment.d.ts +36 -2
- package/utils/RawQueryFragment.js +35 -1
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +218 -0
- package/utils/Utils.d.ts +11 -5
- package/utils/Utils.js +76 -33
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +52 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, extname } from 'node:path';
|
|
2
|
-
import
|
|
2
|
+
import { glob } from 'tinyglobby';
|
|
3
3
|
import { EntityMetadata, } from '../typings.js';
|
|
4
4
|
import { Utils } from '../utils/Utils.js';
|
|
5
5
|
import { MetadataValidator } from './MetadataValidator.js';
|
|
@@ -7,7 +7,7 @@ import { MetadataStorage } from './MetadataStorage.js';
|
|
|
7
7
|
import { EntitySchema } from './EntitySchema.js';
|
|
8
8
|
import { Cascade, ReferenceKind } from '../enums.js';
|
|
9
9
|
import { MetadataError } from '../errors.js';
|
|
10
|
-
import { ArrayType, BigIntType, BlobType, DecimalType, DoubleType, EnumArrayType, IntervalType, JsonType, t, Type, Uint8ArrayType, UnknownType, } from '../types/index.js';
|
|
10
|
+
import { ArrayType, BigIntType, BlobType, DateType, DecimalType, DoubleType, EnumArrayType, IntervalType, JsonType, t, Type, Uint8ArrayType, UnknownType, } from '../types/index.js';
|
|
11
11
|
import { colors } from '../logging/colors.js';
|
|
12
12
|
import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
|
|
13
13
|
export class MetadataDiscovery {
|
|
@@ -74,11 +74,42 @@ export class MetadataDiscovery {
|
|
|
74
74
|
});
|
|
75
75
|
return discovered;
|
|
76
76
|
}
|
|
77
|
+
initAccessors(meta) {
|
|
78
|
+
for (const prop of Object.values(meta.properties)) {
|
|
79
|
+
if (!prop.accessor || meta.properties[prop.accessor]) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
|
|
83
|
+
if (desc?.get || desc?.set) {
|
|
84
|
+
this.initFieldName(prop);
|
|
85
|
+
const accessor = prop.name;
|
|
86
|
+
prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
|
|
87
|
+
if (prop.accessor === true) {
|
|
88
|
+
prop.getter = prop.setter = true;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
prop.getter = prop.setter = false;
|
|
92
|
+
}
|
|
93
|
+
prop.accessor = accessor;
|
|
94
|
+
prop.serializedName ??= accessor;
|
|
95
|
+
Utils.renameKey(meta.properties, accessor, prop.name);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const name = prop.name;
|
|
99
|
+
prop.name = prop.accessor;
|
|
100
|
+
this.initFieldName(prop);
|
|
101
|
+
prop.serializedName ??= prop.accessor;
|
|
102
|
+
prop.name = name;
|
|
103
|
+
prop.trackChanges = false;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
77
107
|
processDiscoveredEntities(discovered) {
|
|
78
108
|
for (const meta of discovered) {
|
|
79
109
|
let i = 1;
|
|
80
110
|
Object.values(meta.properties).forEach(prop => meta.propertyOrder.set(prop.name, i++));
|
|
81
111
|
Object.values(meta.properties).forEach(prop => this.initPolyEmbeddables(prop, discovered));
|
|
112
|
+
this.initAccessors(meta);
|
|
82
113
|
}
|
|
83
114
|
// ignore base entities (not annotated with @Entity)
|
|
84
115
|
const filtered = discovered.filter(meta => meta.root.name);
|
|
@@ -173,7 +204,8 @@ export class MetadataDiscovery {
|
|
|
173
204
|
}
|
|
174
205
|
tryDiscoverTargets(targets) {
|
|
175
206
|
for (const target of targets) {
|
|
176
|
-
|
|
207
|
+
const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
|
|
208
|
+
if (isDiscoverable && target.name && !this.metadata.has(target.name)) {
|
|
177
209
|
this.discoverReferences([target]);
|
|
178
210
|
this.discoverMissingTargets();
|
|
179
211
|
}
|
|
@@ -181,7 +213,7 @@ export class MetadataDiscovery {
|
|
|
181
213
|
}
|
|
182
214
|
async discoverDirectories(paths) {
|
|
183
215
|
paths = paths.map(path => Utils.normalizePath(path));
|
|
184
|
-
const files = await
|
|
216
|
+
const files = await glob(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
|
|
185
217
|
this.logger.log('discovery', `- processing ${colors.cyan('' + files.length)} files`);
|
|
186
218
|
const found = [];
|
|
187
219
|
for (const filepath of files) {
|
|
@@ -227,6 +259,9 @@ export class MetadataDiscovery {
|
|
|
227
259
|
if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.className)) {
|
|
228
260
|
this.discoverReferences([parent]);
|
|
229
261
|
}
|
|
262
|
+
if (typeof parent === 'function' && parent.name && !this.metadata.has(parent.name)) {
|
|
263
|
+
this.discoverReferences([parent]);
|
|
264
|
+
}
|
|
230
265
|
/* v8 ignore next 3 */
|
|
231
266
|
if (!meta.class) {
|
|
232
267
|
continue;
|
|
@@ -264,7 +299,8 @@ export class MetadataDiscovery {
|
|
|
264
299
|
// initialize global metadata for given entity
|
|
265
300
|
MetadataStorage.getMetadata(entity.meta.className, filepath);
|
|
266
301
|
}
|
|
267
|
-
|
|
302
|
+
const meta = Utils.copy(entity.meta, false);
|
|
303
|
+
return EntitySchema.fromMetadata(meta);
|
|
268
304
|
}
|
|
269
305
|
const path = entity[MetadataStorage.PATH_SYMBOL];
|
|
270
306
|
if (path) {
|
|
@@ -618,7 +654,7 @@ export class MetadataDiscovery {
|
|
|
618
654
|
}
|
|
619
655
|
data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
|
|
620
656
|
data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
|
|
621
|
-
return this.metadata.set(data.className, data);
|
|
657
|
+
return this.metadata.set(data.className, EntitySchema.fromMetadata(data).init().meta);
|
|
622
658
|
}
|
|
623
659
|
defineFixedOrderProperty(prop, targetType) {
|
|
624
660
|
const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
|
|
@@ -653,6 +689,7 @@ export class MetadataDiscovery {
|
|
|
653
689
|
autoincrement: false,
|
|
654
690
|
updateRule: prop.updateRule,
|
|
655
691
|
deleteRule: prop.deleteRule,
|
|
692
|
+
createForeignKeyConstraint: prop.createForeignKeyConstraint,
|
|
656
693
|
};
|
|
657
694
|
if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
|
|
658
695
|
ret.updateRule ??= 'no action';
|
|
@@ -765,6 +802,7 @@ export class MetadataDiscovery {
|
|
|
765
802
|
delete prop.default;
|
|
766
803
|
if (properties[prop.name] && properties[prop.name].type !== prop.type) {
|
|
767
804
|
properties[prop.name].type = `${properties[prop.name].type} | ${prop.type}`;
|
|
805
|
+
properties[prop.name].runtimeType = 'any';
|
|
768
806
|
return properties[prop.name];
|
|
769
807
|
}
|
|
770
808
|
return properties[prop.name] = prop;
|
|
@@ -819,9 +857,16 @@ export class MetadataDiscovery {
|
|
|
819
857
|
}
|
|
820
858
|
return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
|
|
821
859
|
};
|
|
860
|
+
const isParentArray = (prop) => {
|
|
861
|
+
if (prop.array) {
|
|
862
|
+
return true;
|
|
863
|
+
}
|
|
864
|
+
return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
|
|
865
|
+
};
|
|
822
866
|
const rootProperty = getRootProperty(embeddedProp);
|
|
823
867
|
const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
|
|
824
868
|
const object = isParentObject(embeddedProp);
|
|
869
|
+
const array = isParentArray(embeddedProp);
|
|
825
870
|
this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
|
|
826
871
|
// the prefix of the parent cannot be a boolean; it already passed here
|
|
827
872
|
const prefix = this.getPrefix(embeddedProp, parentProperty);
|
|
@@ -834,7 +879,8 @@ export class MetadataDiscovery {
|
|
|
834
879
|
meta.propertyOrder.set(name, (order += 0.01));
|
|
835
880
|
embeddedProp.embeddedProps[prop.name] = meta.properties[name];
|
|
836
881
|
meta.properties[name].persist ??= embeddedProp.persist;
|
|
837
|
-
|
|
882
|
+
const refInArray = array && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
|
|
883
|
+
if (embeddedProp.nullable || refInArray) {
|
|
838
884
|
meta.properties[name].nullable = true;
|
|
839
885
|
}
|
|
840
886
|
if (meta.properties[name].fieldNames) {
|
|
@@ -872,6 +918,7 @@ export class MetadataDiscovery {
|
|
|
872
918
|
meta.properties[name].persist = false; // only virtual as we store the whole object
|
|
873
919
|
meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
|
|
874
920
|
meta.properties[name].object = true;
|
|
921
|
+
this.initCustomType(meta, meta.properties[name], false, true);
|
|
875
922
|
}
|
|
876
923
|
this.initEmbeddables(meta, meta.properties[name], visited);
|
|
877
924
|
}
|
|
@@ -905,11 +952,13 @@ export class MetadataDiscovery {
|
|
|
905
952
|
}
|
|
906
953
|
if (!meta.root.discriminatorMap) {
|
|
907
954
|
meta.root.discriminatorMap = {};
|
|
908
|
-
const children = metadata
|
|
909
|
-
|
|
955
|
+
const children = metadata
|
|
956
|
+
.filter(m => m.root.className === meta.root.className && !m.abstract)
|
|
957
|
+
.sort((a, b) => a.className.localeCompare(b.className));
|
|
958
|
+
for (const m of children) {
|
|
910
959
|
const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
|
|
911
960
|
meta.root.discriminatorMap[name] = m.className;
|
|
912
|
-
}
|
|
961
|
+
}
|
|
913
962
|
}
|
|
914
963
|
meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, className]) => className === meta.className)?.[0];
|
|
915
964
|
if (!meta.root.properties[meta.root.discriminatorColumn]) {
|
|
@@ -922,7 +971,7 @@ export class MetadataDiscovery {
|
|
|
922
971
|
}
|
|
923
972
|
let i = 1;
|
|
924
973
|
Object.values(meta.properties).forEach(prop => {
|
|
925
|
-
const newProp =
|
|
974
|
+
const newProp = { ...prop };
|
|
926
975
|
if (meta.root.properties[prop.name] && meta.root.properties[prop.name].type !== prop.type) {
|
|
927
976
|
const name = newProp.name;
|
|
928
977
|
this.initFieldName(newProp, newProp.object);
|
|
@@ -938,12 +987,13 @@ export class MetadataDiscovery {
|
|
|
938
987
|
newProp.items = Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
|
|
939
988
|
}
|
|
940
989
|
newProp.nullable = true;
|
|
941
|
-
newProp.inherited =
|
|
990
|
+
newProp.inherited = !meta.root.properties[prop.name];
|
|
942
991
|
meta.root.addProperty(newProp);
|
|
943
992
|
});
|
|
944
993
|
meta.collection = meta.root.collection;
|
|
945
994
|
meta.root.indexes = Utils.unique([...meta.root.indexes, ...meta.indexes]);
|
|
946
995
|
meta.root.uniques = Utils.unique([...meta.root.uniques, ...meta.uniques]);
|
|
996
|
+
meta.root.checks = Utils.unique([...meta.root.checks, ...meta.checks]);
|
|
947
997
|
}
|
|
948
998
|
createDiscriminatorProperty(meta) {
|
|
949
999
|
meta.addProperty({
|
|
@@ -962,7 +1012,7 @@ export class MetadataDiscovery {
|
|
|
962
1012
|
}
|
|
963
1013
|
}
|
|
964
1014
|
initCheckConstraints(meta) {
|
|
965
|
-
const map =
|
|
1015
|
+
const map = meta.createColumnMappingObject();
|
|
966
1016
|
for (const check of meta.checks) {
|
|
967
1017
|
const columns = check.property ? meta.properties[check.property].fieldNames : [];
|
|
968
1018
|
check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
|
|
@@ -997,20 +1047,12 @@ export class MetadataDiscovery {
|
|
|
997
1047
|
}
|
|
998
1048
|
return;
|
|
999
1049
|
}
|
|
1000
|
-
const map =
|
|
1050
|
+
const map = meta.createColumnMappingObject();
|
|
1001
1051
|
if (prop.generated instanceof Function) {
|
|
1002
1052
|
prop.generated = prop.generated(map);
|
|
1003
1053
|
}
|
|
1004
1054
|
}
|
|
1005
|
-
|
|
1006
|
-
return Object.values(meta.properties).reduce((o, prop) => {
|
|
1007
|
-
if (prop.fieldNames) {
|
|
1008
|
-
o[prop.name] = prop.fieldNames[0];
|
|
1009
|
-
}
|
|
1010
|
-
return o;
|
|
1011
|
-
}, {});
|
|
1012
|
-
}
|
|
1013
|
-
getDefaultVersionValue(prop) {
|
|
1055
|
+
getDefaultVersionValue(meta, prop) {
|
|
1014
1056
|
if (typeof prop.defaultRaw !== 'undefined') {
|
|
1015
1057
|
return prop.defaultRaw;
|
|
1016
1058
|
}
|
|
@@ -1018,14 +1060,15 @@ export class MetadataDiscovery {
|
|
|
1018
1060
|
if (prop.default != null) {
|
|
1019
1061
|
return '' + this.platform.quoteVersionValue(prop.default, prop);
|
|
1020
1062
|
}
|
|
1021
|
-
|
|
1063
|
+
this.initCustomType(meta, prop, true);
|
|
1064
|
+
const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
|
|
1065
|
+
if (type === 'Date') {
|
|
1022
1066
|
prop.length ??= this.platform.getDefaultVersionLength();
|
|
1023
1067
|
return this.platform.getCurrentTimestampSQL(prop.length);
|
|
1024
1068
|
}
|
|
1025
1069
|
return '1';
|
|
1026
1070
|
}
|
|
1027
1071
|
inferDefaultValue(meta, prop) {
|
|
1028
|
-
/* v8 ignore next 3 */
|
|
1029
1072
|
if (!meta.class) {
|
|
1030
1073
|
return;
|
|
1031
1074
|
}
|
|
@@ -1061,7 +1104,7 @@ export class MetadataDiscovery {
|
|
|
1061
1104
|
prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
|
|
1062
1105
|
return;
|
|
1063
1106
|
}
|
|
1064
|
-
if (
|
|
1107
|
+
if (Array.isArray(prop.default) && prop.customType) {
|
|
1065
1108
|
val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
|
|
1066
1109
|
}
|
|
1067
1110
|
prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
|
|
@@ -1089,13 +1132,13 @@ export class MetadataDiscovery {
|
|
|
1089
1132
|
if (prop.version) {
|
|
1090
1133
|
this.initDefaultValue(prop);
|
|
1091
1134
|
meta.versionProperty = prop.name;
|
|
1092
|
-
prop.defaultRaw = this.getDefaultVersionValue(prop);
|
|
1135
|
+
prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
|
|
1093
1136
|
}
|
|
1094
1137
|
if (prop.concurrencyCheck && !prop.primary) {
|
|
1095
1138
|
meta.concurrencyCheckKeys.add(prop.name);
|
|
1096
1139
|
}
|
|
1097
1140
|
}
|
|
1098
|
-
initCustomType(meta, prop) {
|
|
1141
|
+
initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
|
|
1099
1142
|
// `prop.type` might be actually instance of custom type class
|
|
1100
1143
|
if (Type.isMappedType(prop.type) && !prop.customType) {
|
|
1101
1144
|
prop.customType = prop.type;
|
|
@@ -1106,21 +1149,31 @@ export class MetadataDiscovery {
|
|
|
1106
1149
|
prop.customType = new prop.type();
|
|
1107
1150
|
prop.type = prop.customType.constructor.name;
|
|
1108
1151
|
}
|
|
1152
|
+
if (simple) {
|
|
1153
|
+
return;
|
|
1154
|
+
}
|
|
1109
1155
|
if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
|
|
1110
1156
|
prop.customType = new JsonType();
|
|
1111
1157
|
}
|
|
1112
1158
|
if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
|
|
1113
1159
|
prop.customType = new JsonType();
|
|
1114
1160
|
}
|
|
1161
|
+
if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
|
|
1162
|
+
prop.customType = new JsonType();
|
|
1163
|
+
}
|
|
1115
1164
|
if (!prop.customType && prop.array && prop.items) {
|
|
1116
1165
|
prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
|
|
1117
1166
|
}
|
|
1167
|
+
const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
|
|
1168
|
+
if (objectEmbeddable && !prop.customType && isArray) {
|
|
1169
|
+
prop.customType = new JsonType();
|
|
1170
|
+
}
|
|
1118
1171
|
// for number arrays we make sure to convert the items to numbers
|
|
1119
1172
|
if (!prop.customType && prop.type === 'number[]') {
|
|
1120
1173
|
prop.customType = new ArrayType(i => +i);
|
|
1121
1174
|
}
|
|
1122
1175
|
// `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
|
|
1123
|
-
if (!prop.customType &&
|
|
1176
|
+
if (!prop.customType && isArray) {
|
|
1124
1177
|
prop.customType = new ArrayType();
|
|
1125
1178
|
}
|
|
1126
1179
|
if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
|
|
@@ -1131,9 +1184,9 @@ export class MetadataDiscovery {
|
|
|
1131
1184
|
}
|
|
1132
1185
|
const mappedType = this.getMappedType(prop);
|
|
1133
1186
|
if (prop.fieldNames?.length === 1 && !prop.customType) {
|
|
1134
|
-
[BigIntType, DoubleType, DecimalType, IntervalType]
|
|
1187
|
+
[BigIntType, DoubleType, DecimalType, IntervalType, DateType]
|
|
1135
1188
|
.filter(type => mappedType instanceof type)
|
|
1136
|
-
.forEach(type => prop.customType = new type());
|
|
1189
|
+
.forEach((type) => prop.customType = new type());
|
|
1137
1190
|
}
|
|
1138
1191
|
if (prop.customType && !prop.columnTypes) {
|
|
1139
1192
|
const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
|
|
@@ -1144,6 +1197,9 @@ export class MetadataDiscovery {
|
|
|
1144
1197
|
prop.runtimeType ??= prop.customType.runtimeType;
|
|
1145
1198
|
}
|
|
1146
1199
|
}
|
|
1200
|
+
else if (prop.runtimeType === 'object') {
|
|
1201
|
+
prop.runtimeType = mappedType.runtimeType;
|
|
1202
|
+
}
|
|
1147
1203
|
else {
|
|
1148
1204
|
prop.runtimeType ??= mappedType.runtimeType;
|
|
1149
1205
|
}
|
|
@@ -1158,7 +1214,7 @@ export class MetadataDiscovery {
|
|
|
1158
1214
|
prop.customType.mode = prop.runtimeType.toLowerCase();
|
|
1159
1215
|
}
|
|
1160
1216
|
}
|
|
1161
|
-
if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !
|
|
1217
|
+
if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
|
|
1162
1218
|
prop.type = prop.customType.name;
|
|
1163
1219
|
}
|
|
1164
1220
|
if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && this.metadata.get(prop.type).compositePK) {
|
|
@@ -10,7 +10,7 @@ export class MetadataStorage {
|
|
|
10
10
|
this.metadata = Utils.copy(metadata, false);
|
|
11
11
|
}
|
|
12
12
|
static getMetadata(entity, path) {
|
|
13
|
-
const key = entity && path ? entity + '-' + Utils.hash(path) : null;
|
|
13
|
+
const key = entity && path ? entity + '-' + Utils.hash(path, undefined, 'sha256') : null;
|
|
14
14
|
if (key && !MetadataStorage.metadata[key]) {
|
|
15
15
|
MetadataStorage.metadata[key] = new EntityMetadata({ className: entity, path });
|
|
16
16
|
}
|
|
@@ -100,14 +100,15 @@ export class MetadataValidator {
|
|
|
100
100
|
if (!prop.type) {
|
|
101
101
|
throw MetadataError.fromWrongTypeDefinition(meta, prop);
|
|
102
102
|
}
|
|
103
|
+
const targetMeta = metadata.find(prop.type);
|
|
103
104
|
// references do have type of known entity
|
|
104
|
-
if (!
|
|
105
|
+
if (!targetMeta) {
|
|
105
106
|
throw MetadataError.fromWrongTypeDefinition(meta, prop);
|
|
106
107
|
}
|
|
107
|
-
if (
|
|
108
|
+
if (targetMeta.abstract && !targetMeta.discriminatorColumn && !targetMeta.embeddable) {
|
|
108
109
|
throw MetadataError.targetIsAbstract(meta, prop);
|
|
109
110
|
}
|
|
110
|
-
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.persist === false &&
|
|
111
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.persist === false && targetMeta.compositePK && options.checkNonPersistentCompositeProps) {
|
|
111
112
|
throw MetadataError.nonPersistentCompositeProp(meta, prop);
|
|
112
113
|
}
|
|
113
114
|
}
|
|
@@ -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
|
*/
|
|
@@ -48,7 +48,13 @@ export class AbstractNamingStrategy {
|
|
|
48
48
|
* @inheritDoc
|
|
49
49
|
*/
|
|
50
50
|
getEnumClassName(columnName, tableName, schemaName) {
|
|
51
|
-
return this.getEntityName(`${tableName}_${columnName}
|
|
51
|
+
return this.getEntityName(tableName ? `${tableName}_${columnName}` : columnName, schemaName);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @inheritDoc
|
|
55
|
+
*/
|
|
56
|
+
getEnumTypeName(columnName, tableName, schemaName) {
|
|
57
|
+
return 'T' + this.getEnumClassName(columnName, tableName, schemaName);
|
|
52
58
|
}
|
|
53
59
|
/**
|
|
54
60
|
* @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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.41",
|
|
5
5
|
"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.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"dataloader": "2.2.3",
|
|
55
|
-
"dotenv": "
|
|
55
|
+
"dotenv": "17.2.3",
|
|
56
56
|
"esprima": "4.0.1",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
57
|
+
"mikro-orm": "7.0.0-dev.41",
|
|
58
|
+
"reflect-metadata": "0.2.2",
|
|
59
|
+
"tinyglobby": "0.2.13"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/platforms/Platform.d.ts
CHANGED
|
@@ -158,7 +158,7 @@ export declare abstract class Platform {
|
|
|
158
158
|
getFullTextIndexExpression(indexName: string, schemaName: string | undefined, tableName: string, columns: SimpleColumnMeta[]): string;
|
|
159
159
|
convertsJsonAutomatically(): boolean;
|
|
160
160
|
convertJsonToDatabaseValue(value: unknown, context?: TransformContext): unknown;
|
|
161
|
-
convertJsonToJSValue(value: unknown,
|
|
161
|
+
convertJsonToJSValue(value: unknown, context?: TransformContext): unknown;
|
|
162
162
|
convertDateToJSValue(value: string | Date): string;
|
|
163
163
|
convertIntervalToJSValue(value: string): unknown;
|
|
164
164
|
convertIntervalToDatabaseValue(value: unknown): unknown;
|
|
@@ -175,7 +175,9 @@ export declare abstract class Platform {
|
|
|
175
175
|
getExtension<T>(extensionName: string, extensionKey: string, moduleName: string, em: EntityManager): T;
|
|
176
176
|
getSchemaGenerator(driver: IDatabaseDriver, em?: EntityManager): ISchemaGenerator;
|
|
177
177
|
processDateProperty(value: unknown): string | number | Date;
|
|
178
|
-
quoteIdentifier(id: string
|
|
178
|
+
quoteIdentifier(id: string | {
|
|
179
|
+
toString: () => string;
|
|
180
|
+
}, quote?: string): string;
|
|
179
181
|
quoteValue(value: any): string;
|
|
180
182
|
escape(value: any): string;
|
|
181
183
|
formatQuery(sql: string, params: readonly any[]): string;
|
|
@@ -193,7 +195,7 @@ export declare abstract class Platform {
|
|
|
193
195
|
getDefaultPrimaryName(tableName: string, columns: string[]): string;
|
|
194
196
|
supportsCustomPrimaryKeyNames(): boolean;
|
|
195
197
|
isPopulated<T>(key: string, populate: readonly PopulateOptions<T>[] | boolean): boolean;
|
|
196
|
-
shouldHaveColumn<T>(prop: EntityProperty<T>, populate: readonly PopulateOptions<T>[] | boolean, exclude?: string[], includeFormulas?: boolean): boolean;
|
|
198
|
+
shouldHaveColumn<T>(prop: EntityProperty<T>, populate: readonly PopulateOptions<T>[] | boolean, exclude?: string[], includeFormulas?: boolean, ignoreInlineEmbeddables?: boolean): boolean;
|
|
197
199
|
/**
|
|
198
200
|
* Currently not supported due to how knex does complex sqlite diffing (always based on current schema)
|
|
199
201
|
*/
|
package/platforms/Platform.js
CHANGED
|
@@ -133,7 +133,7 @@ export class Platform {
|
|
|
133
133
|
return true;
|
|
134
134
|
}
|
|
135
135
|
isBigIntProperty(prop) {
|
|
136
|
-
return prop.columnTypes
|
|
136
|
+
return prop.columnTypes?.[0] === 'bigint';
|
|
137
137
|
}
|
|
138
138
|
getDefaultSchemaName() {
|
|
139
139
|
return undefined;
|
|
@@ -288,11 +288,7 @@ export class Platform {
|
|
|
288
288
|
convertJsonToDatabaseValue(value, context) {
|
|
289
289
|
return JSON.stringify(value);
|
|
290
290
|
}
|
|
291
|
-
convertJsonToJSValue(value,
|
|
292
|
-
const isObjectEmbedded = prop.embedded && prop.object;
|
|
293
|
-
if ((this.convertsJsonAutomatically() || isObjectEmbedded) && ['json', 'jsonb', this.getJsonDeclarationSQL()].includes(prop.columnTypes[0])) {
|
|
294
|
-
return value;
|
|
295
|
-
}
|
|
291
|
+
convertJsonToJSValue(value, context) {
|
|
296
292
|
return parseJsonSafe(value);
|
|
297
293
|
}
|
|
298
294
|
convertDateToJSValue(value) {
|
|
@@ -455,7 +451,7 @@ export class Platform {
|
|
|
455
451
|
isPopulated(key, populate) {
|
|
456
452
|
return populate === true || (populate !== false && populate.some(p => p.field === key || p.all));
|
|
457
453
|
}
|
|
458
|
-
shouldHaveColumn(prop, populate, exclude, includeFormulas = true) {
|
|
454
|
+
shouldHaveColumn(prop, populate, exclude, includeFormulas = true, ignoreInlineEmbeddables = true) {
|
|
459
455
|
if (exclude?.includes(prop.name)) {
|
|
460
456
|
return false;
|
|
461
457
|
}
|
|
@@ -475,7 +471,7 @@ export class Platform {
|
|
|
475
471
|
return true;
|
|
476
472
|
}
|
|
477
473
|
if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
478
|
-
return
|
|
474
|
+
return prop.object || ignoreInlineEmbeddables;
|
|
479
475
|
}
|
|
480
476
|
return prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner;
|
|
481
477
|
}
|
|
@@ -17,6 +17,8 @@ export interface SerializeOptions<T, P extends string = never, E extends string
|
|
|
17
17
|
forceObject?: boolean;
|
|
18
18
|
/** Ignore custom property serializers. */
|
|
19
19
|
ignoreSerializers?: boolean;
|
|
20
|
+
/** Include properties marked as `hidden`. */
|
|
21
|
+
includeHidden?: boolean;
|
|
20
22
|
/** Skip properties with `null` value. */
|
|
21
23
|
skipNull?: boolean;
|
|
22
24
|
/** Only include properties for a specific group. If a property does not specify any group, it will be included, otherwise only properties with a matching group are included. */
|
|
@@ -15,8 +15,8 @@ function isVisible(meta, propName, options) {
|
|
|
15
15
|
if (options.exclude?.find(item => item === propName)) {
|
|
16
16
|
return false;
|
|
17
17
|
}
|
|
18
|
-
const visible = prop && !prop.hidden;
|
|
19
|
-
const prefixed = prop && !prop.primary && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
|
|
18
|
+
const visible = prop && !(prop.hidden && !options.includeHidden);
|
|
19
|
+
const prefixed = prop && !prop.primary && !prop.accessor && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
|
|
20
20
|
return visible && !prefixed;
|
|
21
21
|
}
|
|
22
22
|
function isPopulated(propName, options) {
|
|
@@ -6,7 +6,7 @@ import { isRaw } from '../utils/RawQueryFragment.js';
|
|
|
6
6
|
function isVisible(meta, propName, ignoreFields = []) {
|
|
7
7
|
const prop = meta.properties[propName];
|
|
8
8
|
const visible = prop && !prop.hidden;
|
|
9
|
-
const prefixed = prop && !prop.primary && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
|
|
9
|
+
const prefixed = prop && !prop.primary && !prop.accessor && propName.startsWith('_'); // ignore prefixed properties, if it's not a PK
|
|
10
10
|
return visible && !prefixed && !ignoreFields.includes(propName);
|
|
11
11
|
}
|
|
12
12
|
export class EntityTransformer {
|
|
@@ -37,7 +37,7 @@ export class SerializationContext {
|
|
|
37
37
|
leave(entityName, prop) {
|
|
38
38
|
const last = this.path.pop();
|
|
39
39
|
/* v8 ignore next 3 */
|
|
40
|
-
if (
|
|
40
|
+
if (last?.[0] !== entityName || last[1] !== prop) {
|
|
41
41
|
throw new Error(`Trying to leave wrong property: ${entityName}.${prop} instead of ${last?.join('.')}`);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -73,18 +73,21 @@ export class SerializationContext {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
isMarkedAsPopulated(entityName, prop) {
|
|
76
|
-
let populate = this.populate;
|
|
76
|
+
let populate = this.populate ?? [];
|
|
77
77
|
for (const segment of this.path) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
const hints = populate.filter(p => p.field === segment[1]);
|
|
79
|
+
if (hints.length > 0) {
|
|
80
|
+
const childHints = [];
|
|
81
|
+
for (const hint of hints) {
|
|
82
|
+
// we need to check for cycles here too, as we could fall into endless loops for bidirectional relations
|
|
83
|
+
if (hint.all) {
|
|
84
|
+
return !this.path.find(([cls, item]) => entityName === cls && prop === item);
|
|
85
|
+
}
|
|
86
|
+
if (hint.children) {
|
|
87
|
+
childHints.push(...hint.children);
|
|
88
|
+
}
|
|
86
89
|
}
|
|
87
|
-
populate =
|
|
90
|
+
populate = childHints;
|
|
88
91
|
}
|
|
89
92
|
}
|
|
90
93
|
return !!populate?.some(p => p.field === prop);
|
package/types/BigIntType.d.ts
CHANGED
|
@@ -5,12 +5,15 @@ import type { EntityProperty } from '../typings.js';
|
|
|
5
5
|
* This type will automatically convert string values returned from the database to native JS bigints (default)
|
|
6
6
|
* or numbers (safe only for values up to `Number.MAX_SAFE_INTEGER`), or strings, depending on the `mode`.
|
|
7
7
|
*/
|
|
8
|
-
export declare class BigIntType extends
|
|
9
|
-
mode?:
|
|
10
|
-
constructor(mode?:
|
|
11
|
-
convertToDatabaseValue(value:
|
|
12
|
-
convertToJSValue(value: string | bigint | null | undefined):
|
|
13
|
-
toJSON(value:
|
|
8
|
+
export declare class BigIntType<Mode extends 'bigint' | 'number' | 'string' = 'bigint'> extends Type<JSTypeByMode<Mode> | null | undefined, string | null | undefined> {
|
|
9
|
+
mode?: Mode | undefined;
|
|
10
|
+
constructor(mode?: Mode | undefined);
|
|
11
|
+
convertToDatabaseValue(value: JSTypeByMode<Mode> | null | undefined): string | null | undefined;
|
|
12
|
+
convertToJSValue(value: string | bigint | null | undefined): JSTypeByMode<Mode> | null | undefined;
|
|
13
|
+
toJSON(value: JSTypeByMode<Mode> | null | undefined): JSTypeByMode<Mode> | null | undefined;
|
|
14
14
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
15
15
|
compareAsType(): string;
|
|
16
|
+
compareValues(a: string, b: string): boolean;
|
|
16
17
|
}
|
|
18
|
+
type JSTypeByMode<Mode extends 'bigint' | 'number' | 'string'> = Mode extends 'bigint' ? bigint : Mode extends 'number' ? number : string;
|
|
19
|
+
export {};
|
package/types/BigIntType.js
CHANGED
package/types/BooleanType.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from './Type.js';
|
|
2
2
|
import type { Platform } from '../platforms/Platform.js';
|
|
3
3
|
import type { EntityProperty } from '../typings.js';
|
|
4
|
-
export declare class BooleanType extends Type<
|
|
4
|
+
export declare class BooleanType extends Type<boolean | null | undefined, boolean | null | undefined> {
|
|
5
5
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
6
6
|
compareAsType(): string;
|
|
7
7
|
ensureComparable(): boolean;
|
package/types/DecimalType.d.ts
CHANGED
|
@@ -4,12 +4,14 @@ import type { EntityProperty } from '../typings.js';
|
|
|
4
4
|
/**
|
|
5
5
|
* Type that maps an SQL DECIMAL to a JS string or number.
|
|
6
6
|
*/
|
|
7
|
-
export declare class DecimalType extends
|
|
8
|
-
mode?:
|
|
9
|
-
constructor(mode?:
|
|
10
|
-
convertToJSValue(value: string):
|
|
7
|
+
export declare class DecimalType<Mode extends 'number' | 'string' = 'string'> extends Type<JSTypeByMode<Mode>, string> {
|
|
8
|
+
mode?: Mode | undefined;
|
|
9
|
+
constructor(mode?: Mode | undefined);
|
|
10
|
+
convertToJSValue(value: string): JSTypeByMode<Mode>;
|
|
11
11
|
compareValues(a: string, b: string): boolean;
|
|
12
12
|
private format;
|
|
13
13
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
14
14
|
compareAsType(): string;
|
|
15
15
|
}
|
|
16
|
+
type JSTypeByMode<Mode extends 'number' | 'string'> = Mode extends 'number' ? number : string;
|
|
17
|
+
export {};
|