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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/EntityManager.d.ts +84 -18
  2. package/EntityManager.js +265 -172
  3. package/MikroORM.d.ts +7 -5
  4. package/MikroORM.js +0 -1
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +2 -1
  7. package/cache/FileCacheAdapter.js +6 -4
  8. package/connections/Connection.d.ts +4 -2
  9. package/connections/Connection.js +2 -2
  10. package/decorators/Check.d.ts +2 -2
  11. package/decorators/Embeddable.d.ts +5 -5
  12. package/decorators/Embeddable.js +1 -1
  13. package/decorators/Embedded.d.ts +6 -12
  14. package/decorators/Entity.d.ts +18 -3
  15. package/decorators/Enum.d.ts +1 -1
  16. package/decorators/Formula.d.ts +1 -2
  17. package/decorators/Indexed.d.ts +2 -2
  18. package/decorators/ManyToMany.d.ts +4 -2
  19. package/decorators/ManyToOne.d.ts +6 -2
  20. package/decorators/OneToMany.d.ts +4 -4
  21. package/decorators/OneToOne.d.ts +5 -1
  22. package/decorators/PrimaryKey.d.ts +2 -3
  23. package/decorators/Property.d.ts +54 -4
  24. package/decorators/Transactional.d.ts +1 -0
  25. package/decorators/Transactional.js +3 -3
  26. package/decorators/index.d.ts +1 -1
  27. package/drivers/DatabaseDriver.d.ts +4 -3
  28. package/drivers/IDatabaseDriver.d.ts +22 -2
  29. package/entity/ArrayCollection.d.ts +4 -2
  30. package/entity/ArrayCollection.js +18 -6
  31. package/entity/Collection.d.ts +1 -2
  32. package/entity/Collection.js +19 -10
  33. package/entity/EntityAssigner.d.ts +1 -1
  34. package/entity/EntityAssigner.js +9 -1
  35. package/entity/EntityFactory.d.ts +7 -0
  36. package/entity/EntityFactory.js +29 -9
  37. package/entity/EntityHelper.js +25 -3
  38. package/entity/EntityLoader.d.ts +5 -4
  39. package/entity/EntityLoader.js +74 -37
  40. package/entity/EntityRepository.d.ts +1 -1
  41. package/entity/EntityValidator.js +1 -1
  42. package/entity/Reference.d.ts +9 -7
  43. package/entity/Reference.js +30 -3
  44. package/entity/WrappedEntity.js +1 -1
  45. package/entity/defineEntity.d.ts +561 -0
  46. package/entity/defineEntity.js +537 -0
  47. package/entity/index.d.ts +2 -0
  48. package/entity/index.js +2 -0
  49. package/entity/utils.d.ts +7 -0
  50. package/entity/utils.js +15 -3
  51. package/enums.d.ts +16 -3
  52. package/enums.js +13 -0
  53. package/errors.d.ts +6 -0
  54. package/errors.js +14 -0
  55. package/events/EventSubscriber.d.ts +3 -1
  56. package/hydration/ObjectHydrator.d.ts +4 -4
  57. package/hydration/ObjectHydrator.js +35 -24
  58. package/index.d.ts +2 -1
  59. package/index.js +1 -1
  60. package/logging/DefaultLogger.d.ts +1 -1
  61. package/logging/SimpleLogger.d.ts +1 -1
  62. package/metadata/EntitySchema.d.ts +8 -4
  63. package/metadata/EntitySchema.js +39 -19
  64. package/metadata/MetadataDiscovery.d.ts +1 -1
  65. package/metadata/MetadataDiscovery.js +88 -32
  66. package/metadata/MetadataStorage.js +1 -1
  67. package/metadata/MetadataValidator.js +4 -3
  68. package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
  69. package/naming-strategy/AbstractNamingStrategy.js +7 -1
  70. package/naming-strategy/NamingStrategy.d.ts +11 -1
  71. package/package.json +5 -5
  72. package/platforms/Platform.d.ts +5 -3
  73. package/platforms/Platform.js +4 -8
  74. package/serialization/EntitySerializer.d.ts +2 -0
  75. package/serialization/EntitySerializer.js +2 -2
  76. package/serialization/EntityTransformer.js +1 -1
  77. package/serialization/SerializationContext.js +14 -11
  78. package/types/BigIntType.d.ts +9 -6
  79. package/types/BigIntType.js +3 -0
  80. package/types/BooleanType.d.ts +1 -1
  81. package/types/DecimalType.d.ts +6 -4
  82. package/types/DecimalType.js +1 -1
  83. package/types/DoubleType.js +1 -1
  84. package/types/JsonType.d.ts +1 -1
  85. package/types/JsonType.js +7 -2
  86. package/types/Type.d.ts +2 -1
  87. package/types/Type.js +1 -1
  88. package/types/index.d.ts +1 -1
  89. package/typings.d.ts +88 -39
  90. package/typings.js +24 -4
  91. package/unit-of-work/ChangeSetComputer.js +3 -1
  92. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  93. package/unit-of-work/ChangeSetPersister.js +37 -16
  94. package/unit-of-work/UnitOfWork.d.ts +8 -1
  95. package/unit-of-work/UnitOfWork.js +109 -41
  96. package/utils/Configuration.d.ts +23 -5
  97. package/utils/Configuration.js +17 -3
  98. package/utils/ConfigurationLoader.d.ts +0 -2
  99. package/utils/ConfigurationLoader.js +2 -24
  100. package/utils/Cursor.d.ts +3 -3
  101. package/utils/Cursor.js +3 -0
  102. package/utils/DataloaderUtils.d.ts +7 -2
  103. package/utils/DataloaderUtils.js +38 -7
  104. package/utils/EntityComparator.d.ts +6 -2
  105. package/utils/EntityComparator.js +104 -58
  106. package/utils/QueryHelper.d.ts +9 -1
  107. package/utils/QueryHelper.js +66 -5
  108. package/utils/RawQueryFragment.d.ts +36 -2
  109. package/utils/RawQueryFragment.js +35 -1
  110. package/utils/TransactionManager.d.ts +65 -0
  111. package/utils/TransactionManager.js +218 -0
  112. package/utils/Utils.d.ts +11 -5
  113. package/utils/Utils.js +76 -33
  114. package/utils/index.d.ts +1 -0
  115. package/utils/index.js +1 -0
  116. package/utils/upsert-utils.d.ts +7 -2
  117. package/utils/upsert-utils.js +52 -1
@@ -1,5 +1,5 @@
1
1
  import { basename, extname } from 'node:path';
2
- import globby from 'globby';
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
- if (typeof target === 'function' && target.name && !this.metadata.has(target.name)) {
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 globby(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
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
- return entity;
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
- if (embeddedProp.nullable) {
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.filter(m => m.root.className === meta.root.className && !m.abstract);
909
- children.forEach(m => {
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 = Utils.copy(prop, false);
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 = true;
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 = this.createColumnMappingObject(meta);
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 = this.createColumnMappingObject(meta);
1050
+ const map = meta.createColumnMappingObject();
1001
1051
  if (prop.generated instanceof Function) {
1002
1052
  prop.generated = prop.generated(map);
1003
1053
  }
1004
1054
  }
1005
- createColumnMappingObject(meta) {
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
- if (prop.type.toLowerCase() === 'date') {
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 (prop.customType instanceof ArrayType && Array.isArray(prop.default)) {
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 && (prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]'))) {
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 && !prop.type?.toString().endsWith('[]')) {
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 (!metadata.find(prop.type)) {
105
+ if (!targetMeta) {
105
106
  throw MetadataError.fromWrongTypeDefinition(meta, prop);
106
107
  }
107
- if (metadata.find(prop.type).abstract && !metadata.find(prop.type).discriminatorColumn) {
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 && metadata.find(prop.type).compositePK && options.checkNonPersistentCompositeProps) {
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}`, schemaName);
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",
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": "16.4.7",
55
+ "dotenv": "17.2.3",
56
56
  "esprima": "4.0.1",
57
- "globby": "11.1.0",
58
- "mikro-orm": "7.0.0-dev.4",
59
- "reflect-metadata": "0.2.2"
57
+ "mikro-orm": "7.0.0-dev.41",
58
+ "reflect-metadata": "0.2.2",
59
+ "tinyglobby": "0.2.13"
60
60
  }
61
61
  }
@@ -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, prop: EntityProperty): 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, quote?: string): 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
  */
@@ -133,7 +133,7 @@ export class Platform {
133
133
  return true;
134
134
  }
135
135
  isBigIntProperty(prop) {
136
- return prop.columnTypes && prop.columnTypes[0] === 'bigint';
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, prop) {
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 !!prop.object;
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 (!last || last[0] !== entityName || last[1] !== prop) {
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
- if (!populate) {
79
- return false;
80
- }
81
- const exists = populate.find(p => p.field === segment[1]);
82
- if (exists) {
83
- // we need to check for cycles here too, as we could fall into endless loops for bidirectional relations
84
- if (exists.all) {
85
- return !this.path.find(([cls, item]) => entityName === cls && prop === item);
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 = exists.children;
90
+ populate = childHints;
88
91
  }
89
92
  }
90
93
  return !!populate?.some(p => p.field === prop);
@@ -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 Type<string | bigint | number | null | undefined, string | null | undefined> {
9
- mode?: "bigint" | "number" | "string" | undefined;
10
- constructor(mode?: "bigint" | "number" | "string" | undefined);
11
- convertToDatabaseValue(value: string | bigint | null | undefined): string | null | undefined;
12
- convertToJSValue(value: string | bigint | null | undefined): bigint | number | string | null | undefined;
13
- toJSON(value: string | bigint | null | undefined): string | bigint | null | undefined;
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 {};
@@ -42,4 +42,7 @@ export class BigIntType extends Type {
42
42
  compareAsType() {
43
43
  return this.mode ?? 'bigint';
44
44
  }
45
+ compareValues(a, b) {
46
+ return String(a) === String(b);
47
+ }
45
48
  }
@@ -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<number | null | undefined, number | null | undefined> {
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;
@@ -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 Type<string | number, string> {
8
- mode?: "number" | "string" | undefined;
9
- constructor(mode?: "number" | "string" | undefined);
10
- convertToJSValue(value: string): number | 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 {};