@mikro-orm/core 7.0.0-dev.22 → 7.0.0-dev.24

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 (70) hide show
  1. package/EntityManager.d.ts +12 -2
  2. package/EntityManager.js +40 -53
  3. package/README.md +1 -2
  4. package/connections/Connection.d.ts +4 -2
  5. package/connections/Connection.js +2 -2
  6. package/decorators/Entity.d.ts +15 -0
  7. package/decorators/Indexed.d.ts +2 -2
  8. package/decorators/ManyToMany.d.ts +2 -0
  9. package/decorators/ManyToOne.d.ts +2 -0
  10. package/decorators/OneToOne.d.ts +2 -0
  11. package/decorators/Transactional.d.ts +1 -0
  12. package/decorators/Transactional.js +3 -3
  13. package/drivers/IDatabaseDriver.d.ts +4 -0
  14. package/entity/ArrayCollection.d.ts +3 -1
  15. package/entity/ArrayCollection.js +7 -2
  16. package/entity/Collection.js +3 -2
  17. package/entity/EntityFactory.d.ts +6 -0
  18. package/entity/EntityFactory.js +17 -6
  19. package/entity/EntityHelper.js +5 -1
  20. package/entity/EntityLoader.js +27 -19
  21. package/entity/Reference.d.ts +5 -0
  22. package/entity/Reference.js +16 -0
  23. package/entity/WrappedEntity.js +1 -1
  24. package/entity/defineEntity.d.ts +537 -0
  25. package/entity/defineEntity.js +690 -0
  26. package/entity/index.d.ts +2 -0
  27. package/entity/index.js +2 -0
  28. package/entity/utils.d.ts +7 -0
  29. package/entity/utils.js +15 -3
  30. package/enums.d.ts +15 -2
  31. package/enums.js +13 -0
  32. package/errors.d.ts +6 -0
  33. package/errors.js +14 -0
  34. package/hydration/ObjectHydrator.js +1 -1
  35. package/index.d.ts +1 -1
  36. package/metadata/EntitySchema.js +10 -2
  37. package/metadata/MetadataDiscovery.d.ts +0 -1
  38. package/metadata/MetadataDiscovery.js +27 -18
  39. package/package.json +3 -3
  40. package/platforms/Platform.d.ts +3 -1
  41. package/serialization/SerializationContext.js +13 -10
  42. package/types/BooleanType.d.ts +1 -1
  43. package/types/DecimalType.js +1 -1
  44. package/types/DoubleType.js +1 -1
  45. package/typings.d.ts +32 -10
  46. package/typings.js +21 -4
  47. package/unit-of-work/ChangeSetComputer.js +3 -1
  48. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  49. package/unit-of-work/ChangeSetPersister.js +14 -10
  50. package/unit-of-work/UnitOfWork.d.ts +2 -1
  51. package/unit-of-work/UnitOfWork.js +36 -13
  52. package/utils/Configuration.d.ts +7 -1
  53. package/utils/Configuration.js +1 -0
  54. package/utils/ConfigurationLoader.js +2 -2
  55. package/utils/Cursor.js +3 -0
  56. package/utils/DataloaderUtils.d.ts +6 -1
  57. package/utils/DataloaderUtils.js +37 -20
  58. package/utils/EntityComparator.d.ts +6 -2
  59. package/utils/EntityComparator.js +29 -8
  60. package/utils/QueryHelper.d.ts +6 -0
  61. package/utils/QueryHelper.js +47 -4
  62. package/utils/RawQueryFragment.d.ts +34 -0
  63. package/utils/RawQueryFragment.js +35 -1
  64. package/utils/TransactionManager.d.ts +65 -0
  65. package/utils/TransactionManager.js +199 -0
  66. package/utils/Utils.d.ts +2 -2
  67. package/utils/Utils.js +31 -7
  68. package/utils/index.d.ts +1 -0
  69. package/utils/index.js +1 -0
  70. package/utils/upsert-utils.js +9 -1
package/entity/index.d.ts CHANGED
@@ -11,3 +11,5 @@ export * from './Reference.js';
11
11
  export * from './BaseEntity.js';
12
12
  export * from './WrappedEntity.js';
13
13
  export * from './wrap.js';
14
+ export * from './defineEntity.js';
15
+ export * from './utils.js';
package/entity/index.js CHANGED
@@ -11,3 +11,5 @@ export * from './Reference.js';
11
11
  export * from './BaseEntity.js';
12
12
  export * from './WrappedEntity.js';
13
13
  export * from './wrap.js';
14
+ export * from './defineEntity.js';
15
+ export * from './utils.js';
package/entity/utils.d.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import type { EntityMetadata, PopulateOptions } from '../typings.js';
2
+ import { LoadStrategy, ReferenceKind } from '../enums.js';
2
3
  /**
3
4
  * @internal
4
5
  */
5
6
  export declare function expandDotPaths<Entity>(meta: EntityMetadata<Entity>, populate?: readonly (string | PopulateOptions<Entity>)[], normalized?: boolean): PopulateOptions<Entity>[];
7
+ /**
8
+ * Returns the loading strategy based on the provided hint.
9
+ * If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
10
+ * @internal
11
+ */
12
+ export declare function getLoadingStrategy(strategy: LoadStrategy | `${LoadStrategy}`, kind: ReferenceKind): LoadStrategy.SELECT_IN | LoadStrategy.JOINED;
package/entity/utils.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PopulatePath, ReferenceKind } from '../enums.js';
2
- import { Utils } from '@mikro-orm/core';
1
+ import { LoadStrategy, PopulatePath, ReferenceKind } from '../enums.js';
2
+ import { Utils } from '../utils/Utils.js';
3
3
  /**
4
4
  * Expands `books.perex` like populate to use `children` array instead of the dot syntax
5
5
  */
@@ -34,7 +34,6 @@ export function expandDotPaths(meta, populate, normalized = false) {
34
34
  p.field = f;
35
35
  p.children ??= [];
36
36
  const prop = meta.properties[p.field];
37
- p.strategy ??= prop.strategy;
38
37
  if (parts[0] === PopulatePath.ALL) {
39
38
  prop.targetMeta.props
40
39
  .filter(prop => prop.lazy || prop.kind !== ReferenceKind.SCALAR)
@@ -55,3 +54,16 @@ export function expandDotPaths(meta, populate, normalized = false) {
55
54
  }
56
55
  return ret;
57
56
  }
57
+ /**
58
+ * Returns the loading strategy based on the provided hint.
59
+ * If `BALANCED` strategy is used, it will return JOINED if the property is a to-one relation.
60
+ * @internal
61
+ */
62
+ export function getLoadingStrategy(strategy, kind) {
63
+ if (strategy === LoadStrategy.BALANCED) {
64
+ return [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(kind)
65
+ ? LoadStrategy.JOINED
66
+ : LoadStrategy.SELECT_IN;
67
+ }
68
+ return strategy;
69
+ }
package/enums.d.ts CHANGED
@@ -85,7 +85,9 @@ export declare enum QueryFlag {
85
85
  INCLUDE_LAZY_FORMULAS = "INCLUDE_LAZY_FORMULAS",
86
86
  AUTO_JOIN_ONE_TO_ONE_OWNER = "AUTO_JOIN_ONE_TO_ONE_OWNER",
87
87
  INFER_POPULATE = "INFER_POPULATE",
88
- IDENTITY_INSERT = "IDENTITY_INSERT"
88
+ DISABLE_NESTED_INNER_JOIN = "DISABLE_NESTED_INNER_JOIN",
89
+ IDENTITY_INSERT = "IDENTITY_INSERT",// mssql only
90
+ OUTPUT_TABLE = "OUTPUT_TABLE"
89
91
  }
90
92
  export declare const SCALAR_TYPES: string[];
91
93
  export declare enum ReferenceKind {
@@ -108,7 +110,8 @@ export declare enum Cascade {
108
110
  }
109
111
  export declare enum LoadStrategy {
110
112
  SELECT_IN = "select-in",
111
- JOINED = "joined"
113
+ JOINED = "joined",
114
+ BALANCED = "balanced"
112
115
  }
113
116
  export declare enum DataloaderType {
114
117
  NONE = 0,
@@ -156,8 +159,18 @@ export declare enum EventType {
156
159
  }
157
160
  export declare const EventTypeMap: Record<EventType, number>;
158
161
  export type TransactionEventType = EventType.beforeTransactionStart | EventType.afterTransactionStart | EventType.beforeTransactionCommit | EventType.afterTransactionCommit | EventType.beforeTransactionRollback | EventType.afterTransactionRollback;
162
+ export declare enum TransactionPropagation {
163
+ REQUIRED = "required",
164
+ REQUIRES_NEW = "requires_new",
165
+ NESTED = "nested",
166
+ NOT_SUPPORTED = "not_supported",
167
+ SUPPORTS = "supports",
168
+ MANDATORY = "mandatory",
169
+ NEVER = "never"
170
+ }
159
171
  export interface TransactionOptions {
160
172
  ctx?: Transaction;
173
+ propagation?: TransactionPropagation;
161
174
  isolationLevel?: IsolationLevel;
162
175
  readOnly?: boolean;
163
176
  clear?: boolean;
package/enums.js CHANGED
@@ -95,7 +95,9 @@ export var QueryFlag;
95
95
  QueryFlag["INCLUDE_LAZY_FORMULAS"] = "INCLUDE_LAZY_FORMULAS";
96
96
  QueryFlag["AUTO_JOIN_ONE_TO_ONE_OWNER"] = "AUTO_JOIN_ONE_TO_ONE_OWNER";
97
97
  QueryFlag["INFER_POPULATE"] = "INFER_POPULATE";
98
+ QueryFlag["DISABLE_NESTED_INNER_JOIN"] = "DISABLE_NESTED_INNER_JOIN";
98
99
  QueryFlag["IDENTITY_INSERT"] = "IDENTITY_INSERT";
100
+ QueryFlag["OUTPUT_TABLE"] = "OUTPUT_TABLE";
99
101
  })(QueryFlag || (QueryFlag = {}));
100
102
  export const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp'];
101
103
  export var ReferenceKind;
@@ -122,6 +124,7 @@ export var LoadStrategy;
122
124
  (function (LoadStrategy) {
123
125
  LoadStrategy["SELECT_IN"] = "select-in";
124
126
  LoadStrategy["JOINED"] = "joined";
127
+ LoadStrategy["BALANCED"] = "balanced";
125
128
  })(LoadStrategy || (LoadStrategy = {}));
126
129
  export var DataloaderType;
127
130
  (function (DataloaderType) {
@@ -175,6 +178,16 @@ export const EventTypeMap = Object.keys(EventType).reduce((a, b, i) => {
175
178
  a[b] = i;
176
179
  return a;
177
180
  }, {});
181
+ export var TransactionPropagation;
182
+ (function (TransactionPropagation) {
183
+ TransactionPropagation["REQUIRED"] = "required";
184
+ TransactionPropagation["REQUIRES_NEW"] = "requires_new";
185
+ TransactionPropagation["NESTED"] = "nested";
186
+ TransactionPropagation["NOT_SUPPORTED"] = "not_supported";
187
+ TransactionPropagation["SUPPORTS"] = "supports";
188
+ TransactionPropagation["MANDATORY"] = "mandatory";
189
+ TransactionPropagation["NEVER"] = "never";
190
+ })(TransactionPropagation || (TransactionPropagation = {}));
178
191
  export class PlainObject {
179
192
  }
180
193
  export var DeferMode;
package/errors.d.ts CHANGED
@@ -24,6 +24,7 @@ export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Er
24
24
  static cannotCommit(): ValidationError;
25
25
  static cannotUseGlobalContext(): ValidationError;
26
26
  static cannotUseOperatorsInsideEmbeddables(className: string, propName: string, payload: unknown): ValidationError;
27
+ static cannotUseGroupOperatorsInsideScalars(className: string, propName: string, payload: unknown): ValidationError;
27
28
  static invalidEmbeddableQuery(className: string, propName: string, embeddableType: string): ValidationError;
28
29
  }
29
30
  export declare class CursorError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
@@ -66,3 +67,8 @@ export declare class NotFoundError<T extends AnyEntity = AnyEntity> extends Vali
66
67
  static findOneFailed(name: string, where: Dictionary | IPrimaryKey): NotFoundError;
67
68
  static findExactlyOneFailed(name: string, where: Dictionary | IPrimaryKey): NotFoundError;
68
69
  }
70
+ export declare class TransactionStateError extends ValidationError {
71
+ static requiredTransactionNotFound(propagation: string): TransactionStateError;
72
+ static transactionNotAllowed(propagation: string): TransactionStateError;
73
+ static invalidPropagation(propagation: string): TransactionStateError;
74
+ }
package/errors.js CHANGED
@@ -94,6 +94,9 @@ export class ValidationError extends Error {
94
94
  static cannotUseOperatorsInsideEmbeddables(className, propName, payload) {
95
95
  return new ValidationError(`Using operators inside embeddables is not allowed, move the operator above. (property: ${className}.${propName}, payload: ${inspect(payload)})`);
96
96
  }
97
+ static cannotUseGroupOperatorsInsideScalars(className, propName, payload) {
98
+ return new ValidationError(`Using group operators ($and/$or) inside scalar properties is not allowed, move the operator above. (property: ${className}.${propName}, payload: ${inspect(payload)})`);
99
+ }
97
100
  static invalidEmbeddableQuery(className, propName, embeddableType) {
98
101
  return new ValidationError(`Invalid query for entity '${className}', property '${propName}' does not exist in embeddable '${embeddableType}'`);
99
102
  }
@@ -220,3 +223,14 @@ export class NotFoundError extends ValidationError {
220
223
  return new NotFoundError(`Wrong number of ${name} entities found for query ${inspect(where)}, expected exactly one`);
221
224
  }
222
225
  }
226
+ export class TransactionStateError extends ValidationError {
227
+ static requiredTransactionNotFound(propagation) {
228
+ return new TransactionStateError(`No existing transaction found for transaction marked with propagation "${propagation}"`);
229
+ }
230
+ static transactionNotAllowed(propagation) {
231
+ return new TransactionStateError(`Existing transaction found for transaction marked with propagation "${propagation}"`);
232
+ }
233
+ static invalidPropagation(propagation) {
234
+ return new TransactionStateError(`Unsupported transaction propagation type: ${propagation}`);
235
+ }
236
+ }
@@ -63,7 +63,7 @@ export class ObjectHydrator extends Hydrator {
63
63
  const ret = [];
64
64
  const idx = this.tmpIndex++;
65
65
  const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
66
- if (prop.getter && !prop.setter) {
66
+ if (prop.getter && !prop.setter && prop.persist === false) {
67
67
  return [];
68
68
  }
69
69
  if (prop.ref) {
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, 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, } from './typings.js';
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, } from './typings.js';
6
6
  export * from './enums.js';
7
7
  export * from './errors.js';
8
8
  export * from './exceptions.js';
@@ -99,6 +99,8 @@ export class EntitySchema {
99
99
  if (prop.fieldNames && !prop.joinColumns) {
100
100
  prop.joinColumns = prop.fieldNames;
101
101
  }
102
+ // By default, the foreign key constraint is created on the relation
103
+ Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
102
104
  this.addProperty(name, type, prop);
103
105
  }
104
106
  addManyToMany(name, type, options) {
@@ -108,6 +110,8 @@ export class EntitySchema {
108
110
  }
109
111
  if (options.owner) {
110
112
  Utils.renameKey(options, 'mappedBy', 'inversedBy');
113
+ // By default, the foreign key constraint is created on the relation
114
+ Utils.defaultValue(options, 'createForeignKeyConstraint', true);
111
115
  }
112
116
  const prop = this.createProperty(ReferenceKind.MANY_TO_MANY, options);
113
117
  this.addProperty(name, type, prop);
@@ -120,8 +124,12 @@ export class EntitySchema {
120
124
  const prop = this.createProperty(ReferenceKind.ONE_TO_ONE, options);
121
125
  Utils.defaultValue(prop, 'owner', !!prop.inversedBy || !prop.mappedBy);
122
126
  Utils.defaultValue(prop, 'unique', prop.owner);
123
- if (prop.owner && options.mappedBy) {
124
- Utils.renameKey(prop, 'mappedBy', 'inversedBy');
127
+ if (prop.owner) {
128
+ if (options.mappedBy) {
129
+ Utils.renameKey(prop, 'mappedBy', 'inversedBy');
130
+ }
131
+ // By default, the foreign key constraint is created on the relation
132
+ Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
125
133
  }
126
134
  if (prop.joinColumns && !prop.fieldNames) {
127
135
  prop.fieldNames = prop.joinColumns;
@@ -54,7 +54,6 @@ export declare class MetadataDiscovery {
54
54
  private initAutoincrement;
55
55
  private initCheckConstraints;
56
56
  private initGeneratedColumn;
57
- private createColumnMappingObject;
58
57
  private getDefaultVersionValue;
59
58
  private inferDefaultValue;
60
59
  private initDefaultValue;
@@ -619,7 +619,7 @@ export class MetadataDiscovery {
619
619
  }
620
620
  data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
621
621
  data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
622
- return this.metadata.set(data.className, data);
622
+ return this.metadata.set(data.className, EntitySchema.fromMetadata(data).init().meta);
623
623
  }
624
624
  defineFixedOrderProperty(prop, targetType) {
625
625
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
@@ -654,6 +654,7 @@ export class MetadataDiscovery {
654
654
  autoincrement: false,
655
655
  updateRule: prop.updateRule,
656
656
  deleteRule: prop.deleteRule,
657
+ createForeignKeyConstraint: prop.createForeignKeyConstraint,
657
658
  };
658
659
  if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
659
660
  ret.updateRule ??= 'no action';
@@ -821,9 +822,16 @@ export class MetadataDiscovery {
821
822
  }
822
823
  return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
823
824
  };
825
+ const isParentArray = (prop) => {
826
+ if (prop.array) {
827
+ return true;
828
+ }
829
+ return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
830
+ };
824
831
  const rootProperty = getRootProperty(embeddedProp);
825
832
  const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
826
833
  const object = isParentObject(embeddedProp);
834
+ const array = isParentArray(embeddedProp);
827
835
  this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
828
836
  // the prefix of the parent cannot be a boolean; it already passed here
829
837
  const prefix = this.getPrefix(embeddedProp, parentProperty);
@@ -836,7 +844,8 @@ export class MetadataDiscovery {
836
844
  meta.propertyOrder.set(name, (order += 0.01));
837
845
  embeddedProp.embeddedProps[prop.name] = meta.properties[name];
838
846
  meta.properties[name].persist ??= embeddedProp.persist;
839
- if (embeddedProp.nullable) {
847
+ const refInArray = array && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
848
+ if (embeddedProp.nullable || refInArray) {
840
849
  meta.properties[name].nullable = true;
841
850
  }
842
851
  if (meta.properties[name].fieldNames) {
@@ -874,7 +883,7 @@ export class MetadataDiscovery {
874
883
  meta.properties[name].persist = false; // only virtual as we store the whole object
875
884
  meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
876
885
  meta.properties[name].object = true;
877
- this.initCustomType(meta, meta.properties[name], true);
886
+ this.initCustomType(meta, meta.properties[name], false, true);
878
887
  }
879
888
  this.initEmbeddables(meta, meta.properties[name], visited);
880
889
  }
@@ -968,7 +977,7 @@ export class MetadataDiscovery {
968
977
  }
969
978
  }
970
979
  initCheckConstraints(meta) {
971
- const map = this.createColumnMappingObject(meta);
980
+ const map = meta.createColumnMappingObject();
972
981
  for (const check of meta.checks) {
973
982
  const columns = check.property ? meta.properties[check.property].fieldNames : [];
974
983
  check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
@@ -1003,20 +1012,12 @@ export class MetadataDiscovery {
1003
1012
  }
1004
1013
  return;
1005
1014
  }
1006
- const map = this.createColumnMappingObject(meta);
1015
+ const map = meta.createColumnMappingObject();
1007
1016
  if (prop.generated instanceof Function) {
1008
1017
  prop.generated = prop.generated(map);
1009
1018
  }
1010
1019
  }
1011
- createColumnMappingObject(meta) {
1012
- return Object.values(meta.properties).reduce((o, prop) => {
1013
- if (prop.fieldNames) {
1014
- o[prop.name] = prop.fieldNames[0];
1015
- }
1016
- return o;
1017
- }, {});
1018
- }
1019
- getDefaultVersionValue(prop) {
1020
+ getDefaultVersionValue(meta, prop) {
1020
1021
  if (typeof prop.defaultRaw !== 'undefined') {
1021
1022
  return prop.defaultRaw;
1022
1023
  }
@@ -1024,7 +1025,9 @@ export class MetadataDiscovery {
1024
1025
  if (prop.default != null) {
1025
1026
  return '' + this.platform.quoteVersionValue(prop.default, prop);
1026
1027
  }
1027
- if (prop.type.toLowerCase() === 'date') {
1028
+ this.initCustomType(meta, prop, true);
1029
+ const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
1030
+ if (type === 'Date') {
1028
1031
  prop.length ??= this.platform.getDefaultVersionLength();
1029
1032
  return this.platform.getCurrentTimestampSQL(prop.length);
1030
1033
  }
@@ -1067,7 +1070,7 @@ export class MetadataDiscovery {
1067
1070
  prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
1068
1071
  return;
1069
1072
  }
1070
- if (prop.customType instanceof ArrayType && Array.isArray(prop.default)) {
1073
+ if (Array.isArray(prop.default) && prop.customType) {
1071
1074
  val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
1072
1075
  }
1073
1076
  prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
@@ -1095,13 +1098,13 @@ export class MetadataDiscovery {
1095
1098
  if (prop.version) {
1096
1099
  this.initDefaultValue(prop);
1097
1100
  meta.versionProperty = prop.name;
1098
- prop.defaultRaw = this.getDefaultVersionValue(prop);
1101
+ prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
1099
1102
  }
1100
1103
  if (prop.concurrencyCheck && !prop.primary) {
1101
1104
  meta.concurrencyCheckKeys.add(prop.name);
1102
1105
  }
1103
1106
  }
1104
- initCustomType(meta, prop, objectEmbeddable = false) {
1107
+ initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
1105
1108
  // `prop.type` might be actually instance of custom type class
1106
1109
  if (Type.isMappedType(prop.type) && !prop.customType) {
1107
1110
  prop.customType = prop.type;
@@ -1112,12 +1115,18 @@ export class MetadataDiscovery {
1112
1115
  prop.customType = new prop.type();
1113
1116
  prop.type = prop.customType.constructor.name;
1114
1117
  }
1118
+ if (simple) {
1119
+ return;
1120
+ }
1115
1121
  if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
1116
1122
  prop.customType = new JsonType();
1117
1123
  }
1118
1124
  if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1119
1125
  prop.customType = new JsonType();
1120
1126
  }
1127
+ if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
1128
+ prop.customType = new JsonType();
1129
+ }
1121
1130
  if (!prop.customType && prop.array && prop.items) {
1122
1131
  prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1123
1132
  }
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.22",
4
+ "version": "7.0.0-dev.24",
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,9 +52,9 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "dataloader": "2.2.3",
55
- "dotenv": "16.5.0",
55
+ "dotenv": "17.2.1",
56
56
  "esprima": "4.0.1",
57
- "mikro-orm": "7.0.0-dev.22",
57
+ "mikro-orm": "7.0.0-dev.24",
58
58
  "reflect-metadata": "0.2.2",
59
59
  "tinyglobby": "0.2.13"
60
60
  }
@@ -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;
@@ -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);
@@ -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;
@@ -13,7 +13,7 @@ export class DecimalType extends Type {
13
13
  if ((this.mode ?? this.prop?.runtimeType) === 'number') {
14
14
  return +value;
15
15
  }
16
- return value;
16
+ return String(value);
17
17
  }
18
18
  compareValues(a, b) {
19
19
  return this.format(a) === this.format(b);
@@ -8,7 +8,7 @@ export class DoubleType extends Type {
8
8
  if (this.prop?.runtimeType === 'number') {
9
9
  return +value;
10
10
  }
11
- return value;
11
+ return String(value);
12
12
  }
13
13
  getColumnType(prop, platform) {
14
14
  return platform.getDoubleDeclarationSQL();
package/typings.d.ts CHANGED
@@ -53,11 +53,15 @@ export declare const EagerProps: unique symbol;
53
53
  export declare const HiddenProps: unique symbol;
54
54
  export declare const Config: unique symbol;
55
55
  declare const __optional: unique symbol;
56
+ declare const __requiredNullable: unique symbol;
56
57
  declare const __hidden: unique symbol;
57
58
  declare const __config: unique symbol;
58
59
  export type Opt<T = unknown> = T & {
59
60
  [__optional]?: 1;
60
61
  };
62
+ export type RequiredNullable<T = never> = (T & {
63
+ [__requiredNullable]?: 1;
64
+ }) | null;
61
65
  export type Hidden<T = unknown> = T & {
62
66
  [__hidden]?: 1;
63
67
  };
@@ -82,6 +86,7 @@ export type Primary<T> = IsAny<T> extends true ? any : T extends {
82
86
  } ? ReadonlyPrimary<PK> : T extends {
83
87
  id?: infer PK;
84
88
  } ? ReadonlyPrimary<PK> : T;
89
+ /** @internal */
85
90
  export type PrimaryProperty<T> = T extends {
86
91
  [PrimaryKeyProp]?: infer PK;
87
92
  } ? (PK extends keyof T ? PK : (PK extends any[] ? PK[number] : never)) : T extends {
@@ -224,7 +229,9 @@ export type EntityDataProp<T, C extends boolean> = T extends Date ? string | Dat
224
229
  __runtime?: infer Runtime;
225
230
  __raw?: infer Raw;
226
231
  } ? (C extends true ? Raw : Runtime) : T extends Reference<infer U> ? EntityDataNested<U, C> : T extends ScalarReference<infer U> ? EntityDataProp<U, C> : T extends Collection<infer U, any> ? U | U[] | EntityDataNested<U, C> | EntityDataNested<U, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | EntityDataNested<U, C> | EntityDataNested<U, C>[] : U[] | EntityDataNested<U, C>[] : EntityDataNested<T, C>;
227
- export type RequiredEntityDataProp<T, O, C extends boolean> = T extends Date ? string | Date : T extends Scalar ? T : T extends {
232
+ export type RequiredEntityDataProp<T, O, C extends boolean> = T extends Date ? string | Date : Exclude<T, null> extends {
233
+ [__requiredNullable]?: 1;
234
+ } ? T | null : T extends Scalar ? T : T extends {
228
235
  __runtime?: infer Runtime;
229
236
  __raw?: infer Raw;
230
237
  } ? (C extends true ? Raw : Runtime) : T extends Reference<infer U> ? RequiredEntityDataNested<U, O, C> : T extends ScalarReference<infer U> ? RequiredEntityDataProp<U, O, C> : T extends Collection<infer U, any> ? U | U[] | RequiredEntityDataNested<U, O, C> | RequiredEntityDataNested<U, O, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | RequiredEntityDataNested<U, O, C> | RequiredEntityDataNested<U, O, C>[] : U[] | RequiredEntityDataNested<U, O, C>[] : RequiredEntityDataNested<T, O, C>;
@@ -239,7 +246,12 @@ type ExplicitlyOptionalProps<T> = (T extends {
239
246
  type NullableKeys<T, V = null> = {
240
247
  [K in keyof T]: V extends T[K] ? K : never;
241
248
  }[keyof T];
242
- type ProbablyOptionalProps<T> = PrimaryProperty<T> | ExplicitlyOptionalProps<T> | NonNullable<NullableKeys<T, null | undefined>>;
249
+ type RequiredNullableKeys<T> = {
250
+ [K in keyof T]: Exclude<T[K], null> extends {
251
+ [__requiredNullable]?: 1;
252
+ } ? K : never;
253
+ }[keyof T];
254
+ type ProbablyOptionalProps<T> = PrimaryProperty<T> | ExplicitlyOptionalProps<T> | Exclude<NonNullable<NullableKeys<T, null | undefined>>, RequiredNullableKeys<T>>;
243
255
  type IsOptional<T, K extends keyof T, I> = T[K] extends Collection<any, any> ? true : ExtractType<T[K]> extends I ? true : K extends ProbablyOptionalProps<T> ? true : false;
244
256
  type RequiredKeys<T, K extends keyof T, I> = IsOptional<T, K, I> extends false ? CleanKeys<T, K> : never;
245
257
  type OptionalKeys<T, K extends keyof T, I> = IsOptional<T, K, I> extends false ? never : CleanKeys<T, K>;
@@ -297,8 +309,14 @@ export type EntityDTO<T, C extends TypeConfig = never> = {
297
309
  [K in keyof T as DTOOptionalKeys<T, K>]?: EntityDTOProp<T, T[K], C> | AddOptional<T[K]>;
298
310
  };
299
311
  type TargetKeys<T> = T extends EntityClass<infer P> ? keyof P : keyof T;
300
- type CheckKey<T> = IsUnknown<T> extends false ? TargetKeys<T> : string;
301
- export type CheckCallback<T> = (columns: Record<CheckKey<T>, string>) => string;
312
+ type PropertyName<T> = IsUnknown<T> extends false ? TargetKeys<T> : string;
313
+ type TableName = {
314
+ name: string;
315
+ schema?: string;
316
+ toString: () => string;
317
+ };
318
+ export type IndexCallback<T> = (table: TableName, columns: Record<PropertyName<T>, string>, indexName: string) => string | RawQueryFragment;
319
+ export type CheckCallback<T> = (columns: Record<PropertyName<T>, string>) => string;
302
320
  export type GeneratedColumnCallback<T> = (columns: Record<keyof T, string>) => string;
303
321
  export interface CheckConstraint<T = any> {
304
322
  name?: string;
@@ -394,6 +412,7 @@ export interface EntityProperty<Owner = any, Target = any> {
394
412
  optional?: boolean;
395
413
  ignoreSchemaChanges?: ('type' | 'extra' | 'default')[];
396
414
  deferMode?: DeferMode;
415
+ createForeignKeyConstraint: boolean;
397
416
  foreignKeyName?: string;
398
417
  }
399
418
  export declare class EntityMetadata<T = any> {
@@ -403,8 +422,9 @@ export declare class EntityMetadata<T = any> {
403
422
  constructor(meta?: Partial<EntityMetadata>);
404
423
  addProperty(prop: Partial<EntityProperty<T>>, sync?: boolean): void;
405
424
  removeProperty(name: string, sync?: boolean): void;
406
- getPrimaryProps(): EntityProperty<T>[];
425
+ getPrimaryProps(flatten?: boolean): EntityProperty<T>[];
407
426
  getPrimaryProp(): EntityProperty<T>;
427
+ createColumnMappingObject(): Dictionary<any>;
408
428
  get tableName(): string;
409
429
  set tableName(name: string);
410
430
  sync(initIndexes?: boolean, config?: Configuration): void;
@@ -456,18 +476,18 @@ export interface EntityMetadata<T = any> {
456
476
  uniqueProps: EntityProperty<T>[];
457
477
  getterProps: EntityProperty<T>[];
458
478
  indexes: {
459
- properties: EntityKey<T> | EntityKey<T>[];
479
+ properties?: EntityKey<T> | EntityKey<T>[];
460
480
  name?: string;
461
481
  type?: string;
462
482
  options?: Dictionary;
463
- expression?: string;
483
+ expression?: string | IndexCallback<T>;
464
484
  }[];
465
485
  uniques: {
466
- properties: EntityKey<T> | EntityKey<T>[];
486
+ properties?: EntityKey<T> | EntityKey<T>[];
467
487
  name?: string;
468
488
  options?: Dictionary;
469
- expression?: string;
470
- deferMode?: DeferMode;
489
+ expression?: string | IndexCallback<T>;
490
+ deferMode?: DeferMode | `${DeferMode}`;
471
491
  }[];
472
492
  checks: CheckConstraint<T>[];
473
493
  repositoryClass?: string;
@@ -486,6 +506,7 @@ export interface EntityMetadata<T = any> {
486
506
  polymorphs?: EntityMetadata[];
487
507
  root: EntityMetadata<T>;
488
508
  definedProperties: Dictionary;
509
+ hasTriggers?: boolean;
489
510
  /** @internal can be used for computed numeric cache keys */
490
511
  readonly _id: number;
491
512
  }
@@ -699,6 +720,7 @@ export type PopulateOptions<T> = {
699
720
  strategy?: LoadStrategy;
700
721
  all?: boolean;
701
722
  filter?: boolean;
723
+ joinType?: 'inner join' | 'left join';
702
724
  children?: PopulateOptions<T[keyof T]>[];
703
725
  };
704
726
  type Loadable<T extends object> = Collection<T, any> | Reference<T> | Ref<T> | readonly T[];