@mikro-orm/core 7.0.0-dev.32 → 7.0.0-dev.321

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 (216) hide show
  1. package/EntityManager.d.ts +71 -63
  2. package/EntityManager.js +365 -283
  3. package/MikroORM.d.ts +44 -35
  4. package/MikroORM.js +109 -142
  5. package/README.md +7 -4
  6. package/cache/FileCacheAdapter.d.ts +1 -2
  7. package/cache/FileCacheAdapter.js +19 -14
  8. package/cache/GeneratedCacheAdapter.d.ts +0 -1
  9. package/cache/GeneratedCacheAdapter.js +0 -2
  10. package/cache/index.d.ts +1 -2
  11. package/cache/index.js +0 -2
  12. package/connections/Connection.d.ts +12 -5
  13. package/connections/Connection.js +37 -15
  14. package/drivers/DatabaseDriver.d.ts +25 -18
  15. package/drivers/DatabaseDriver.js +144 -45
  16. package/drivers/IDatabaseDriver.d.ts +118 -23
  17. package/entity/BaseEntity.d.ts +63 -4
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +101 -29
  20. package/entity/Collection.js +473 -115
  21. package/entity/EntityAssigner.js +37 -25
  22. package/entity/EntityFactory.d.ts +7 -1
  23. package/entity/EntityFactory.js +116 -64
  24. package/entity/EntityHelper.d.ts +2 -2
  25. package/entity/EntityHelper.js +69 -27
  26. package/entity/EntityLoader.d.ts +11 -10
  27. package/entity/EntityLoader.js +264 -102
  28. package/entity/EntityRepository.d.ts +28 -8
  29. package/entity/EntityRepository.js +8 -2
  30. package/entity/PolymorphicRef.d.ts +12 -0
  31. package/entity/PolymorphicRef.js +18 -0
  32. package/entity/Reference.d.ts +2 -6
  33. package/entity/Reference.js +52 -19
  34. package/entity/WrappedEntity.d.ts +3 -8
  35. package/entity/WrappedEntity.js +6 -7
  36. package/entity/defineEntity.d.ts +525 -311
  37. package/entity/defineEntity.js +134 -290
  38. package/entity/index.d.ts +2 -2
  39. package/entity/index.js +2 -2
  40. package/entity/utils.d.ts +6 -1
  41. package/entity/utils.js +46 -11
  42. package/entity/validators.d.ts +11 -0
  43. package/entity/validators.js +66 -0
  44. package/enums.d.ts +8 -6
  45. package/enums.js +13 -17
  46. package/errors.d.ts +20 -10
  47. package/errors.js +63 -31
  48. package/events/EventManager.d.ts +2 -1
  49. package/events/EventManager.js +24 -13
  50. package/events/index.d.ts +1 -1
  51. package/events/index.js +0 -1
  52. package/exceptions.js +9 -2
  53. package/hydration/Hydrator.js +1 -2
  54. package/hydration/ObjectHydrator.d.ts +4 -4
  55. package/hydration/ObjectHydrator.js +105 -46
  56. package/index.d.ts +2 -2
  57. package/index.js +1 -2
  58. package/logging/DefaultLogger.d.ts +1 -1
  59. package/logging/DefaultLogger.js +3 -4
  60. package/logging/SimpleLogger.d.ts +1 -1
  61. package/logging/colors.d.ts +1 -1
  62. package/logging/colors.js +5 -7
  63. package/logging/index.d.ts +2 -1
  64. package/logging/index.js +1 -1
  65. package/logging/inspect.d.ts +2 -0
  66. package/logging/inspect.js +11 -0
  67. package/metadata/EntitySchema.d.ts +47 -23
  68. package/metadata/EntitySchema.js +103 -34
  69. package/metadata/MetadataDiscovery.d.ts +64 -9
  70. package/metadata/MetadataDiscovery.js +867 -354
  71. package/metadata/MetadataProvider.d.ts +11 -2
  72. package/metadata/MetadataProvider.js +71 -2
  73. package/metadata/MetadataStorage.d.ts +13 -11
  74. package/metadata/MetadataStorage.js +72 -41
  75. package/metadata/MetadataValidator.d.ts +32 -9
  76. package/metadata/MetadataValidator.js +214 -44
  77. package/metadata/discover-entities.d.ts +5 -0
  78. package/metadata/discover-entities.js +40 -0
  79. package/metadata/index.d.ts +1 -1
  80. package/metadata/index.js +0 -1
  81. package/metadata/types.d.ts +577 -0
  82. package/metadata/types.js +1 -0
  83. package/naming-strategy/AbstractNamingStrategy.d.ts +16 -4
  84. package/naming-strategy/AbstractNamingStrategy.js +26 -5
  85. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  86. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  87. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  88. package/naming-strategy/MongoNamingStrategy.js +6 -6
  89. package/naming-strategy/NamingStrategy.d.ts +28 -4
  90. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  91. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  92. package/naming-strategy/index.d.ts +1 -1
  93. package/naming-strategy/index.js +0 -1
  94. package/not-supported.d.ts +2 -0
  95. package/not-supported.js +8 -0
  96. package/package.json +47 -36
  97. package/platforms/ExceptionConverter.js +1 -1
  98. package/platforms/Platform.d.ts +33 -15
  99. package/platforms/Platform.js +125 -69
  100. package/serialization/EntitySerializer.d.ts +6 -3
  101. package/serialization/EntitySerializer.js +53 -29
  102. package/serialization/EntityTransformer.js +33 -21
  103. package/serialization/SerializationContext.d.ts +6 -6
  104. package/serialization/SerializationContext.js +4 -4
  105. package/types/ArrayType.d.ts +1 -1
  106. package/types/ArrayType.js +2 -3
  107. package/types/BigIntType.js +1 -1
  108. package/types/BlobType.d.ts +0 -1
  109. package/types/BlobType.js +0 -3
  110. package/types/BooleanType.d.ts +1 -0
  111. package/types/BooleanType.js +3 -0
  112. package/types/DecimalType.js +2 -2
  113. package/types/DoubleType.js +1 -1
  114. package/types/EnumArrayType.js +1 -2
  115. package/types/JsonType.d.ts +1 -1
  116. package/types/JsonType.js +7 -2
  117. package/types/TinyIntType.js +1 -1
  118. package/types/Type.d.ts +2 -4
  119. package/types/Type.js +3 -3
  120. package/types/Uint8ArrayType.d.ts +0 -1
  121. package/types/Uint8ArrayType.js +1 -4
  122. package/types/UuidType.d.ts +2 -0
  123. package/types/UuidType.js +14 -2
  124. package/types/index.d.ts +3 -2
  125. package/typings.d.ts +427 -170
  126. package/typings.js +100 -45
  127. package/unit-of-work/ChangeSet.d.ts +4 -6
  128. package/unit-of-work/ChangeSet.js +8 -9
  129. package/unit-of-work/ChangeSetComputer.d.ts +3 -8
  130. package/unit-of-work/ChangeSetComputer.js +49 -26
  131. package/unit-of-work/ChangeSetPersister.d.ts +13 -12
  132. package/unit-of-work/ChangeSetPersister.js +107 -44
  133. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  134. package/unit-of-work/CommitOrderCalculator.js +17 -15
  135. package/unit-of-work/IdentityMap.d.ts +12 -0
  136. package/unit-of-work/IdentityMap.js +39 -1
  137. package/unit-of-work/UnitOfWork.d.ts +34 -4
  138. package/unit-of-work/UnitOfWork.js +294 -107
  139. package/utils/AbstractMigrator.d.ts +101 -0
  140. package/utils/AbstractMigrator.js +303 -0
  141. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  142. package/utils/AbstractSchemaGenerator.js +30 -18
  143. package/utils/AsyncContext.d.ts +6 -0
  144. package/utils/AsyncContext.js +42 -0
  145. package/utils/Configuration.d.ts +796 -211
  146. package/utils/Configuration.js +160 -197
  147. package/utils/ConfigurationLoader.d.ts +1 -52
  148. package/utils/ConfigurationLoader.js +1 -330
  149. package/utils/Cursor.d.ts +0 -3
  150. package/utils/Cursor.js +29 -14
  151. package/utils/DataloaderUtils.d.ts +10 -5
  152. package/utils/DataloaderUtils.js +42 -22
  153. package/utils/EntityComparator.d.ts +16 -9
  154. package/utils/EntityComparator.js +202 -96
  155. package/utils/QueryHelper.d.ts +34 -7
  156. package/utils/QueryHelper.js +183 -72
  157. package/utils/RawQueryFragment.d.ts +28 -34
  158. package/utils/RawQueryFragment.js +37 -72
  159. package/utils/RequestContext.js +2 -2
  160. package/utils/TransactionContext.js +2 -2
  161. package/utils/TransactionManager.js +11 -7
  162. package/utils/Utils.d.ts +16 -127
  163. package/utils/Utils.js +106 -401
  164. package/utils/clone.js +13 -23
  165. package/utils/env-vars.d.ts +7 -0
  166. package/utils/env-vars.js +98 -0
  167. package/utils/fs-utils.d.ts +34 -0
  168. package/utils/fs-utils.js +193 -0
  169. package/utils/index.d.ts +1 -3
  170. package/utils/index.js +1 -3
  171. package/utils/upsert-utils.d.ts +9 -4
  172. package/utils/upsert-utils.js +51 -5
  173. package/decorators/Check.d.ts +0 -3
  174. package/decorators/Check.js +0 -13
  175. package/decorators/CreateRequestContext.d.ts +0 -3
  176. package/decorators/CreateRequestContext.js +0 -32
  177. package/decorators/Embeddable.d.ts +0 -8
  178. package/decorators/Embeddable.js +0 -11
  179. package/decorators/Embedded.d.ts +0 -12
  180. package/decorators/Embedded.js +0 -18
  181. package/decorators/Entity.d.ts +0 -33
  182. package/decorators/Entity.js +0 -12
  183. package/decorators/Enum.d.ts +0 -9
  184. package/decorators/Enum.js +0 -16
  185. package/decorators/Filter.d.ts +0 -2
  186. package/decorators/Filter.js +0 -8
  187. package/decorators/Formula.d.ts +0 -4
  188. package/decorators/Formula.js +0 -15
  189. package/decorators/Indexed.d.ts +0 -19
  190. package/decorators/Indexed.js +0 -20
  191. package/decorators/ManyToMany.d.ts +0 -42
  192. package/decorators/ManyToMany.js +0 -14
  193. package/decorators/ManyToOne.d.ts +0 -34
  194. package/decorators/ManyToOne.js +0 -14
  195. package/decorators/OneToMany.d.ts +0 -28
  196. package/decorators/OneToMany.js +0 -17
  197. package/decorators/OneToOne.d.ts +0 -28
  198. package/decorators/OneToOne.js +0 -7
  199. package/decorators/PrimaryKey.d.ts +0 -8
  200. package/decorators/PrimaryKey.js +0 -20
  201. package/decorators/Property.d.ts +0 -250
  202. package/decorators/Property.js +0 -32
  203. package/decorators/Transactional.d.ts +0 -14
  204. package/decorators/Transactional.js +0 -28
  205. package/decorators/hooks.d.ts +0 -16
  206. package/decorators/hooks.js +0 -47
  207. package/decorators/index.d.ts +0 -17
  208. package/decorators/index.js +0 -17
  209. package/entity/ArrayCollection.d.ts +0 -118
  210. package/entity/ArrayCollection.js +0 -407
  211. package/entity/EntityValidator.d.ts +0 -19
  212. package/entity/EntityValidator.js +0 -150
  213. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  214. package/metadata/ReflectMetadataProvider.js +0 -44
  215. package/utils/resolveContextProvider.d.ts +0 -10
  216. package/utils/resolveContextProvider.js +0 -28
@@ -1,5 +1,6 @@
1
- import type { EntityData, EntityDictionary, EntityMetadata, EntityProperty, IMetadataStorage } from '../typings.js';
1
+ import type { EntityData, EntityDictionary, EntityMetadata, EntityName, EntityProperty, IMetadataStorage } from '../typings.js';
2
2
  import type { Platform } from '../platforms/Platform.js';
3
+ import type { Configuration } from './Configuration.js';
3
4
  type Comparator<T> = (a: T, b: T, options?: {
4
5
  includeInverseSides?: boolean;
5
6
  }) => EntityData<T>;
@@ -9,6 +10,7 @@ type CompositeKeyPart = string | CompositeKeyPart[];
9
10
  export declare class EntityComparator {
10
11
  private readonly metadata;
11
12
  private readonly platform;
13
+ private readonly config?;
12
14
  private readonly comparators;
13
15
  private readonly mappers;
14
16
  private readonly snapshotGenerators;
@@ -16,23 +18,23 @@ export declare class EntityComparator {
16
18
  private readonly pkGettersConverted;
17
19
  private readonly pkSerializers;
18
20
  private tmpIndex;
19
- constructor(metadata: IMetadataStorage, platform: Platform);
21
+ constructor(metadata: IMetadataStorage, platform: Platform, config?: Configuration | undefined);
20
22
  /**
21
23
  * Computes difference between two entities.
22
24
  */
23
- diffEntities<T>(entityName: string, a: EntityData<T>, b: EntityData<T>, options?: {
25
+ diffEntities<T extends object>(entityName: EntityName<T>, a: EntityData<T>, b: EntityData<T>, options?: {
24
26
  includeInverseSides?: boolean;
25
27
  }): EntityData<T>;
26
- matching<T>(entityName: string, a: EntityData<T>, b: EntityData<T>): boolean;
28
+ matching<T extends object>(entityName: EntityName<T>, a: EntityData<T>, b: EntityData<T>): boolean;
27
29
  /**
28
30
  * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
29
31
  * References will be mapped to primary keys, collections to arrays of primary keys.
30
32
  */
31
- prepareEntity<T>(entity: T): EntityData<T>;
33
+ prepareEntity<T extends object>(entity: T): EntityData<T>;
32
34
  /**
33
35
  * Maps database columns to properties.
34
36
  */
35
- mapResult<T>(entityName: string, result: EntityDictionary<T>): EntityData<T>;
37
+ mapResult<T>(meta: EntityMetadata<T>, result: EntityDictionary<T>): EntityData<T>;
36
38
  /**
37
39
  * @internal Highly performance-sensitive method.
38
40
  */
@@ -48,7 +50,7 @@ export declare class EntityComparator {
48
50
  /**
49
51
  * @internal Highly performance-sensitive method.
50
52
  */
51
- getSnapshotGenerator<T>(entityName: string): SnapshotGenerator<T>;
53
+ getSnapshotGenerator<T>(entityName: EntityName<T>): SnapshotGenerator<T>;
52
54
  /**
53
55
  * @internal
54
56
  */
@@ -64,7 +66,7 @@ export declare class EntityComparator {
64
66
  /**
65
67
  * @internal Highly performance-sensitive method.
66
68
  */
67
- getResultMapper<T>(entityName: string): ResultMapper<T>;
69
+ getResultMapper<T>(meta: EntityMetadata<T>): ResultMapper<T>;
68
70
  private getPropertyCondition;
69
71
  private getEmbeddedArrayPropertySnapshot;
70
72
  /**
@@ -78,11 +80,16 @@ export declare class EntityComparator {
78
80
  /**
79
81
  * @internal Highly performance-sensitive method.
80
82
  */
81
- getEntityComparator<T extends object>(entityName: string): Comparator<T>;
83
+ getEntityComparator<T extends object>(entityName: EntityName<T>): Comparator<T>;
82
84
  private getGenericComparator;
83
85
  private getPropertyComparator;
84
86
  private wrap;
85
87
  private safeKey;
88
+ /**
89
+ * Sets the toArray helper in the context if not already set.
90
+ * Used for converting composite PKs to arrays.
91
+ */
92
+ private setToArrayHelper;
86
93
  /**
87
94
  * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
88
95
  */
@@ -1,11 +1,14 @@
1
1
  import { clone } from './clone.js';
2
2
  import { ReferenceKind } from '../enums.js';
3
- import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils } from './Utils.js';
3
+ import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils, } from './Utils.js';
4
4
  import { JsonType } from '../types/JsonType.js';
5
- import { RawQueryFragment } from './RawQueryFragment.js';
5
+ import { Raw } from './RawQueryFragment.js';
6
+ import { EntityIdentifier } from '../entity/EntityIdentifier.js';
7
+ import { PolymorphicRef } from '../entity/PolymorphicRef.js';
6
8
  export class EntityComparator {
7
9
  metadata;
8
10
  platform;
11
+ config;
9
12
  comparators = new Map();
10
13
  mappers = new Map();
11
14
  snapshotGenerators = new Map();
@@ -13,9 +16,10 @@ export class EntityComparator {
13
16
  pkGettersConverted = new Map();
14
17
  pkSerializers = new Map();
15
18
  tmpIndex = 0;
16
- constructor(metadata, platform) {
19
+ constructor(metadata, platform, config) {
17
20
  this.metadata = metadata;
18
21
  this.platform = platform;
22
+ this.config = config;
19
23
  }
20
24
  /**
21
25
  * Computes difference between two entities.
@@ -33,22 +37,22 @@ export class EntityComparator {
33
37
  * References will be mapped to primary keys, collections to arrays of primary keys.
34
38
  */
35
39
  prepareEntity(entity) {
36
- const generator = this.getSnapshotGenerator(entity.constructor.name);
40
+ const generator = this.getSnapshotGenerator(entity.constructor);
37
41
  return Utils.callCompiledFunction(generator, entity);
38
42
  }
39
43
  /**
40
44
  * Maps database columns to properties.
41
45
  */
42
- mapResult(entityName, result) {
43
- const mapper = this.getResultMapper(entityName);
46
+ mapResult(meta, result) {
47
+ const mapper = this.getResultMapper(meta);
44
48
  return Utils.callCompiledFunction(mapper, result);
45
49
  }
46
50
  /**
47
51
  * @internal Highly performance-sensitive method.
48
52
  */
49
53
  getPkGetter(meta) {
50
- const exists = this.pkGetters.get(meta.className);
51
- /* v8 ignore next 3 */
54
+ const exists = this.pkGetters.get(meta);
55
+ /* v8 ignore next */
52
56
  if (exists) {
53
57
  return exists;
54
58
  }
@@ -87,18 +91,18 @@ export class EntityComparator {
87
91
  }
88
92
  lines.push(` return entity${this.wrap(pk)};`);
89
93
  }
90
- const code = `// compiled pk serializer for entity ${meta.className}\n`
91
- + `return function(entity) {\n${lines.join('\n')}\n}`;
92
- const pkSerializer = Utils.createFunction(context, code);
93
- this.pkGetters.set(meta.className, pkSerializer);
94
+ const code = `// compiled pk getter for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
95
+ const fnKey = `pkGetter-${meta.uniqueName}`;
96
+ const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
97
+ this.pkGetters.set(meta, pkSerializer);
94
98
  return pkSerializer;
95
99
  }
96
100
  /**
97
101
  * @internal Highly performance-sensitive method.
98
102
  */
99
103
  getPkGetterConverted(meta) {
100
- const exists = this.pkGettersConverted.get(meta.className);
101
- /* v8 ignore next 3 */
104
+ const exists = this.pkGettersConverted.get(meta);
105
+ /* v8 ignore next */
102
106
  if (exists) {
103
107
  return exists;
104
108
  }
@@ -137,18 +141,19 @@ export class EntityComparator {
137
141
  lines.push(` return entity${this.wrap(pk)};`);
138
142
  }
139
143
  }
140
- const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n`
141
- + `return function(entity) {\n${lines.join('\n')}\n}`;
142
- const pkSerializer = Utils.createFunction(context, code);
143
- this.pkGettersConverted.set(meta.className, pkSerializer);
144
+ const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n` +
145
+ `return function(entity) {\n${lines.join('\n')}\n}`;
146
+ const fnKey = `pkGetterConverted-${meta.uniqueName}`;
147
+ const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
148
+ this.pkGettersConverted.set(meta, pkSerializer);
144
149
  return pkSerializer;
145
150
  }
146
151
  /**
147
152
  * @internal Highly performance-sensitive method.
148
153
  */
149
154
  getPkSerializer(meta) {
150
- const exists = this.pkSerializers.get(meta.className);
151
- /* v8 ignore next 3 */
155
+ const exists = this.pkSerializers.get(meta);
156
+ /* v8 ignore next */
152
157
  if (exists) {
153
158
  return exists;
154
159
  }
@@ -189,26 +194,26 @@ export class EntityComparator {
189
194
  lines.push(` return '' + entity${this.wrap(pk)};`);
190
195
  }
191
196
  }
192
- const code = `// compiled pk serializer for entity ${meta.className}\n`
193
- + `return function(entity) {\n${lines.join('\n')}\n}`;
194
- const pkSerializer = Utils.createFunction(context, code);
195
- this.pkSerializers.set(meta.className, pkSerializer);
197
+ const code = `// compiled pk serializer for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
198
+ const fnKey = `pkSerializer-${meta.uniqueName}`;
199
+ const pkSerializer = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
200
+ this.pkSerializers.set(meta, pkSerializer);
196
201
  return pkSerializer;
197
202
  }
198
203
  /**
199
204
  * @internal Highly performance-sensitive method.
200
205
  */
201
206
  getSnapshotGenerator(entityName) {
202
- const exists = this.snapshotGenerators.get(entityName);
207
+ const meta = this.metadata.find(entityName);
208
+ const exists = this.snapshotGenerators.get(meta);
203
209
  if (exists) {
204
210
  return exists;
205
211
  }
206
- const meta = this.metadata.find(entityName);
207
212
  const lines = [];
208
213
  const context = new Map();
209
214
  context.set('clone', clone);
210
215
  context.set('cloneEmbeddable', (o) => this.platform.cloneEmbeddable(o)); // do not clone prototypes
211
- if (meta.discriminatorValue) {
216
+ if (meta.root.inheritanceType === 'sti' && meta.discriminatorValue) {
212
217
  lines.push(` ret${this.wrap(meta.root.discriminatorColumn)} = '${meta.discriminatorValue}'`);
213
218
  }
214
219
  const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
@@ -220,8 +225,9 @@ export class EntityComparator {
220
225
  })
221
226
  .forEach(prop => lines.push(this.getPropertySnapshot(meta, prop, context, this.wrap(prop.name), this.wrap(prop.name), [prop.name])));
222
227
  const code = `return function(entity) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
223
- const snapshotGenerator = Utils.createFunction(context, code);
224
- this.snapshotGenerators.set(entityName, snapshotGenerator);
228
+ const fnKey = `snapshotGenerator-${meta.uniqueName}`;
229
+ const snapshotGenerator = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
230
+ this.snapshotGenerators.set(meta, snapshotGenerator);
225
231
  return snapshotGenerator;
226
232
  }
227
233
  /**
@@ -265,29 +271,33 @@ export class EntityComparator {
265
271
  if (part.length === 1) {
266
272
  return this.formatCompositeKeyPart(part[0]);
267
273
  }
268
- const formatted = part.map(this.formatCompositeKeyPart).join(', ');
274
+ const formatted = part.map(p => this.formatCompositeKeyPart(p)).join(', ');
269
275
  return `[${formatted}]`;
270
276
  }
271
277
  /**
272
278
  * @internal Highly performance-sensitive method.
273
279
  */
274
- getResultMapper(entityName) {
275
- const exists = this.mappers.get(entityName);
280
+ getResultMapper(meta) {
281
+ const exists = this.mappers.get(meta);
276
282
  if (exists) {
277
283
  return exists;
278
284
  }
279
- const meta = this.metadata.get(entityName);
280
285
  const lines = [];
281
286
  const context = new Map();
287
+ context.set('PolymorphicRef', PolymorphicRef);
282
288
  const tz = this.platform.getTimezone();
283
289
  const parseDate = (key, value, padding = '') => {
284
290
  lines.push(`${padding} if (${value} == null || ${value} instanceof Date) {`);
285
291
  lines.push(`${padding} ${key} = ${value};`);
286
292
  if (!tz || tz === 'local') {
293
+ lines.push(`${padding} } else if (typeof ${value} === 'bigint') {`);
294
+ lines.push(`${padding} ${key} = parseDate(Number(${value}));`);
287
295
  lines.push(`${padding} } else {`);
288
296
  lines.push(`${padding} ${key} = parseDate(${value});`);
289
297
  }
290
298
  else {
299
+ lines.push(`${padding} } else if (typeof ${value} === 'bigint') {`);
300
+ lines.push(`${padding} ${key} = parseDate(Number(${value}));`);
291
301
  lines.push(`${padding} } else if (typeof ${value} === 'number' || ${value}.includes('+') || ${value}.lastIndexOf('-') > 10 || ${value}.endsWith('Z')) {`);
292
302
  lines.push(`${padding} ${key} = parseDate(${value});`);
293
303
  lines.push(`${padding} } else {`);
@@ -301,12 +311,28 @@ export class EntityComparator {
301
311
  if (!prop.fieldNames) {
302
312
  continue;
303
313
  }
314
+ if (prop.polymorphic && prop.fieldNames.length >= 2) {
315
+ const discriminatorField = prop.fieldNames[0];
316
+ const idFields = prop.fieldNames.slice(1);
317
+ lines.push(`${padding} if (${prop.fieldNames.map(field => `typeof ${this.propName(field)} === 'undefined'`).join(' && ')}) {`);
318
+ lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} != null`).join(' && ')}) {`);
319
+ if (idFields.length === 1) {
320
+ lines.push(`${padding} ret${this.wrap(prop.name)} = new PolymorphicRef(${this.propName(discriminatorField)}, ${this.propName(idFields[0])});`);
321
+ }
322
+ else {
323
+ lines.push(`${padding} ret${this.wrap(prop.name)} = new PolymorphicRef(${this.propName(discriminatorField)}, [${idFields.map(f => this.propName(f)).join(', ')}]);`);
324
+ }
325
+ lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`));
326
+ lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} == null`).join(' && ')}) {\n${padding} ret${this.wrap(prop.name)} = null;`);
327
+ lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`), ' }');
328
+ continue;
329
+ }
304
330
  if (prop.targetMeta && prop.fieldNames.length > 1) {
305
331
  lines.push(`${padding} if (${prop.fieldNames.map(field => `typeof ${this.propName(field)} === 'undefined'`).join(' && ')}) {`);
306
332
  lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} != null`).join(' && ')}) {`);
307
333
  lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.createCompositeKeyArray(prop)};`);
308
334
  lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`));
309
- lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} == null`).join(' && ')}) {\n ret${this.wrap(prop.name)} = null;`);
335
+ lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} == null`).join(' && ')}) {\n${padding} ret${this.wrap(prop.name)} = null;`);
310
336
  lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`), ' }');
311
337
  continue;
312
338
  }
@@ -331,9 +357,9 @@ export class EntityComparator {
331
357
  context.set(`mapEmbeddedResult_${idx}`, (data) => {
332
358
  const item = parseJsonSafe(data);
333
359
  if (Array.isArray(item)) {
334
- return item.map(row => row == null ? row : this.getResultMapper(prop.type)(row));
360
+ return item.map(row => (row == null ? row : this.getResultMapper(prop.targetMeta)(row)));
335
361
  }
336
- return item == null ? item : this.getResultMapper(prop.type)(item);
362
+ return item == null ? item : this.getResultMapper(prop.targetMeta)(item);
337
363
  });
338
364
  lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
339
365
  lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : mapEmbeddedResult_${idx}(${this.propName(prop.fieldNames[0])});`);
@@ -363,10 +389,11 @@ export class EntityComparator {
363
389
  mapEntityProperties(meta);
364
390
  }
365
391
  lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k] && ret[k] === undefined) ret[k] = result[k]; }`);
366
- const code = `// compiled mapper for entity ${meta.className}\n`
367
- + `return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
368
- const resultMapper = Utils.createFunction(context, code);
369
- this.mappers.set(entityName, resultMapper);
392
+ const code = `// compiled mapper for entity ${meta.className}\n` +
393
+ `return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
394
+ const fnKey = `resultMapper-${meta.uniqueName}`;
395
+ const resultMapper = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
396
+ this.mappers.set(meta, resultMapper);
370
397
  return resultMapper;
371
398
  }
372
399
  getPropertyCondition(path) {
@@ -377,12 +404,12 @@ export class EntityComparator {
377
404
  let tail = '';
378
405
  return parts
379
406
  .map(k => {
380
- if (k.match(/^\[idx_\d+]$/)) {
407
+ if (/^\[idx_\d+]$/.exec(k)) {
381
408
  tail += k;
382
409
  return '';
383
410
  }
384
411
  const mapped = `typeof entity${tail ? '.' + tail : ''}${this.wrap(k)} !== 'undefined'`;
385
- tail += tail ? ('.' + k) : k;
412
+ tail += tail ? '.' + k : k;
386
413
  return mapped;
387
414
  })
388
415
  .filter(k => k)
@@ -417,11 +444,25 @@ export class EntityComparator {
417
444
  }
418
445
  getEmbeddedPropertySnapshot(meta, prop, context, level, path, dataKey, object = prop.object) {
419
446
  const padding = ' '.repeat(level * 2);
420
- let ret = `${level === 1 ? '' : '\n'}`;
447
+ const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
448
+ let ret = level === 1 ? '' : '\n';
421
449
  if (object) {
422
- const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
423
450
  ret += `${padding}if (${nullCond}) ret${dataKey} = null;\n`;
424
451
  }
452
+ else {
453
+ ret += `${padding}if (${nullCond}) {\n`;
454
+ ret +=
455
+ meta.props
456
+ .filter(p => p.embedded?.[0] === prop.name &&
457
+ // object for JSON embeddable
458
+ (p.object || p.persist !== false))
459
+ .map(childProp => {
460
+ const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
461
+ return `${padding} ret${childDataKey} = null;`;
462
+ })
463
+ .join('\n') + `\n`;
464
+ ret += `${padding}}\n`;
465
+ }
425
466
  const cond = `entity${path.map(k => this.wrap(k)).join('')} != null`;
426
467
  ret += `${padding}if (${cond}) {\n`;
427
468
  if (object) {
@@ -436,28 +477,34 @@ export class EntityComparator {
436
477
  }
437
478
  return true;
438
479
  }
439
- ret += meta.props.filter(p => p.embedded?.[0] === prop.name
440
- // object for JSON embeddable
441
- && (p.object || (p.persist !== false))).map(childProp => {
442
- const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
443
- const childEntityKey = [...path, childProp.embedded[1]].map(k => this.wrap(k)).join('');
444
- const childCond = `typeof entity${childEntityKey} !== 'undefined'`;
445
- if (childProp.kind === ReferenceKind.EMBEDDED) {
446
- return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level + 1, prop.object);
447
- }
448
- if (childProp.kind !== ReferenceKind.SCALAR) {
449
- return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level, prop.object)
450
- .split('\n').map(l => padding + l).join('\n');
451
- }
452
- if (shouldProcessCustomType(childProp)) {
453
- const convertorKey = this.registerCustomType(childProp, context);
454
- if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
455
- return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
480
+ ret +=
481
+ meta.props
482
+ .filter(p => p.embedded?.[0] === prop.name &&
483
+ // object for JSON embeddable
484
+ (p.object || p.persist !== false))
485
+ .map(childProp => {
486
+ const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
487
+ const childEntityKey = [...path, childProp.embedded[1]].map(k => this.wrap(k)).join('');
488
+ const childCond = `typeof entity${childEntityKey} !== 'undefined'`;
489
+ if (childProp.kind === ReferenceKind.EMBEDDED) {
490
+ return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level + 1, prop.object);
456
491
  }
457
- return `${padding} if (${childCond}) ret${childDataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${childEntityKey}));`;
458
- }
459
- return `${padding} if (${childCond}) ret${childDataKey} = clone(entity${childEntityKey});`;
460
- }).join('\n') + `\n`;
492
+ if (childProp.kind !== ReferenceKind.SCALAR) {
493
+ return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level, prop.object)
494
+ .split('\n')
495
+ .map(l => padding + l)
496
+ .join('\n');
497
+ }
498
+ if (shouldProcessCustomType(childProp)) {
499
+ const convertorKey = this.registerCustomType(childProp, context);
500
+ if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
501
+ return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
502
+ }
503
+ return `${padding} if (${childCond}) ret${childDataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${childEntityKey}));`;
504
+ }
505
+ return `${padding} if (${childCond}) ret${childDataKey} = clone(entity${childEntityKey});`;
506
+ })
507
+ .join('\n') + `\n`;
461
508
  if (this.shouldSerialize(prop, dataKey)) {
462
509
  return `${ret + padding} ret${dataKey} = cloneEmbeddable(ret${dataKey});\n${padding}}`;
463
510
  }
@@ -466,8 +513,8 @@ export class EntityComparator {
466
513
  registerCustomType(prop, context) {
467
514
  const convertorKey = this.safeKey(prop.name);
468
515
  context.set(`convertToDatabaseValue_${convertorKey}`, (val) => {
469
- /* v8 ignore next 3 */
470
- if (RawQueryFragment.isKnownFragment(val)) {
516
+ /* v8 ignore next */
517
+ if (Raw.isKnownFragment(val)) {
471
518
  return val;
472
519
  }
473
520
  return prop.customType.convertToDatabaseValue(val, this.platform, { mode: 'serialization' });
@@ -496,16 +543,51 @@ export class EntityComparator {
496
543
  ret += ` ret${dataKey} = entity${entityKey};\n`;
497
544
  }
498
545
  }
546
+ else if (prop.polymorphic) {
547
+ const discriminatorMapKey = `discriminatorMapReverse_${prop.name}`;
548
+ const reverseMap = new Map();
549
+ for (const [key, value] of Object.entries(prop.discriminatorMap)) {
550
+ reverseMap.set(value, key);
551
+ }
552
+ context.set(discriminatorMapKey, reverseMap);
553
+ this.setToArrayHelper(context);
554
+ context.set('EntityIdentifier', EntityIdentifier);
555
+ context.set('PolymorphicRef', PolymorphicRef);
556
+ ret += ` if (entity${entityKey} === null) {\n`;
557
+ ret += ` ret${dataKey} = null;\n`;
558
+ ret += ` } else if (typeof entity${entityKey} !== 'undefined') {\n`;
559
+ ret += ` const val${level} = entity${entityKey}${unwrap};\n`;
560
+ ret += ` const discriminator = ${discriminatorMapKey}.get(val${level}?.constructor);\n`;
561
+ ret += ` const pk = val${level}?.__helper?.__identifier && !val${level}?.__helper?.hasPrimaryKey()\n`;
562
+ ret += ` ? val${level}.__helper.__identifier\n`;
563
+ ret += ` : toArray(val${level}?.__helper?.getPrimaryKey(true));\n`;
564
+ ret += ` ret${dataKey} = new PolymorphicRef(discriminator, pk);\n`;
565
+ ret += ` }\n`;
566
+ }
567
+ else if (prop.targetKey) {
568
+ // When targetKey is set, extract that property value instead of the PK
569
+ const targetProp = prop.targetMeta?.properties[prop.targetKey];
570
+ ret += ` if (entity${entityKey} === null) {\n`;
571
+ ret += ` ret${dataKey} = null;\n`;
572
+ ret += ` } else if (typeof entity${entityKey} !== 'undefined') {\n`;
573
+ ret += ` const val${level} = entity${entityKey}${unwrap};\n`;
574
+ if (targetProp?.customType) {
575
+ // If targetKey property has a custom type, convert to database value
576
+ const convertorKey = this.registerCustomType(targetProp, context);
577
+ ret += ` ret${dataKey} = convertToDatabaseValue_${convertorKey}(val${level}?.${prop.targetKey});\n`;
578
+ }
579
+ else {
580
+ ret += ` ret${dataKey} = val${level}?.${prop.targetKey};\n`;
581
+ }
582
+ ret += ` }\n`;
583
+ }
499
584
  else {
500
- const toArray = (val) => {
501
- if (Utils.isPlainObject(val)) {
502
- return Object.values(val).map(v => toArray(v));
503
- }
504
- return val;
505
- };
506
- context.set('toArray', toArray);
585
+ this.setToArrayHelper(context);
586
+ context.set('EntityIdentifier', EntityIdentifier);
507
587
  ret += ` if (entity${entityKey} === null) {\n`;
508
588
  ret += ` ret${dataKey} = null;\n`;
589
+ ret += ` } else if (entity${entityKey}?.__helper.__identifier && !entity${entityKey}.__helper.hasPrimaryKey()) {\n`;
590
+ ret += ` ret${dataKey} = entity${entityKey}?.__helper.__identifier;\n`;
509
591
  ret += ` } else if (typeof entity${entityKey} !== 'undefined') {\n`;
510
592
  ret += ` ret${dataKey} = toArray(entity${entityKey}.__helper.getPrimaryKey(true));\n`;
511
593
  ret += ` }\n`;
@@ -517,7 +599,7 @@ export class EntityComparator {
517
599
  if (['number', 'string', 'boolean', 'bigint'].includes(prop.customType.compareAsType().toLowerCase())) {
518
600
  return ret + ` ret${dataKey} = convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap});\n }\n`;
519
601
  }
520
- return ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n`;
602
+ return (ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n`);
521
603
  }
522
604
  if (prop.runtimeType === 'Date') {
523
605
  context.set('processDateProperty', this.platform.processDateProperty.bind(this.platform));
@@ -529,11 +611,11 @@ export class EntityComparator {
529
611
  * @internal Highly performance-sensitive method.
530
612
  */
531
613
  getEntityComparator(entityName) {
532
- const exists = this.comparators.get(entityName);
614
+ const meta = this.metadata.find(entityName);
615
+ const exists = this.comparators.get(meta);
533
616
  if (exists) {
534
617
  return exists;
535
618
  }
536
- const meta = this.metadata.find(entityName);
537
619
  const lines = [];
538
620
  const context = new Map();
539
621
  context.set('compareArrays', compareArrays);
@@ -542,10 +624,7 @@ export class EntityComparator {
542
624
  context.set('compareObjects', compareObjects);
543
625
  context.set('equals', equals);
544
626
  for (const prop of meta.comparableProps) {
545
- // skip properties that are not hydrated
546
- if (prop.hydrate !== false) {
547
- lines.push(this.getPropertyComparator(prop, context));
548
- }
627
+ lines.push(this.getPropertyComparator(prop, context));
549
628
  }
550
629
  // also compare 1:1 inverse sides, important for `factory.mergeData`
551
630
  lines.push(`if (options?.includeInverseSides) {`);
@@ -555,37 +634,48 @@ export class EntityComparator {
555
634
  }
556
635
  }
557
636
  lines.push(`}`);
558
- const code = `// compiled comparator for entity ${meta.className}\n`
559
- + `return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
560
- const comparator = Utils.createFunction(context, code);
561
- this.comparators.set(entityName, comparator);
637
+ const code = `// compiled comparator for entity ${meta.className}\n` +
638
+ `return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
639
+ const fnKey = `comparator-${meta.uniqueName}`;
640
+ const comparator = Utils.createFunction(context, code, this.config?.get('compiledFunctions'), fnKey);
641
+ this.comparators.set(meta, comparator);
562
642
  return comparator;
563
643
  }
564
644
  getGenericComparator(prop, cond) {
565
- return ` if (current${prop} === null && last${prop} === undefined) {\n` +
645
+ return (` if (current${prop} === null && last${prop} === undefined) {\n` +
566
646
  ` diff${prop} = current${prop};\n` +
567
647
  ` } else if (current${prop} == null && last${prop} == null) {\n\n` +
568
648
  ` } else if ((current${prop} != null && last${prop} == null) || (current${prop} == null && last${prop} != null)) {\n` +
569
649
  ` diff${prop} = current${prop};\n` +
570
650
  ` } else if (${cond}) {\n` +
571
651
  ` diff${prop} = current${prop};\n` +
572
- ` }\n`;
652
+ ` }\n`);
573
653
  }
574
654
  getPropertyComparator(prop, context) {
575
655
  let type = prop.type.toLowerCase();
576
656
  if (prop.kind !== ReferenceKind.SCALAR && prop.kind !== ReferenceKind.EMBEDDED) {
577
- const meta2 = this.metadata.find(prop.type);
578
- if (meta2.primaryKeys.length > 1) {
579
- type = 'array';
657
+ if (prop.polymorphic) {
658
+ type = 'object';
580
659
  }
581
660
  else {
582
- type = meta2.properties[meta2.primaryKeys[0]].type.toLowerCase();
661
+ const meta2 = prop.targetMeta;
662
+ if (meta2.primaryKeys.length > 1) {
663
+ type = 'array';
664
+ }
665
+ else {
666
+ type = meta2.getPrimaryProp().type.toLowerCase();
667
+ }
583
668
  }
584
669
  }
585
670
  if (prop.customType) {
586
671
  if (prop.customType.compareValues) {
587
672
  const idx = this.tmpIndex++;
588
- context.set(`compareValues_${idx}`, (a, b) => prop.customType.compareValues(a, b));
673
+ context.set(`compareValues_${idx}`, (a, b) => {
674
+ if (Raw.isKnownFragment(a) || Raw.isKnownFragment(b)) {
675
+ return Raw.getKnownFragment(a) === Raw.getKnownFragment(b);
676
+ }
677
+ return prop.customType.compareValues(a, b);
678
+ });
589
679
  return this.getGenericComparator(this.wrap(prop.name), `!compareValues_${idx}(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
590
680
  }
591
681
  type = prop.customType.compareAsType().toLowerCase();
@@ -605,10 +695,10 @@ export class EntityComparator {
605
695
  if (['buffer', 'uint8array'].includes(type)) {
606
696
  return this.getGenericComparator(this.wrap(prop.name), `!compareBuffers(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
607
697
  }
608
- if (['date'].includes(type)) {
698
+ if (type === 'date') {
609
699
  return this.getGenericComparator(this.wrap(prop.name), `last${this.wrap(prop.name)}.valueOf() !== current${this.wrap(prop.name)}.valueOf()`);
610
700
  }
611
- if (['objectid'].includes(type)) {
701
+ if (type === 'objectid') {
612
702
  // We might be comparing PK to object, in case we compare with cached data of populated entity
613
703
  // in such case we just ignore the comparison and fallback to `equals()` (which will still mark
614
704
  // it as not equal as we compare PK to plain object).
@@ -618,14 +708,30 @@ export class EntityComparator {
618
708
  return this.getGenericComparator(this.wrap(prop.name), `!equals(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
619
709
  }
620
710
  wrap(key) {
621
- if (key.match(/^\[.*]$/)) {
711
+ if (/^\[.*]$/.exec(key)) {
622
712
  return key;
623
713
  }
624
- return key.match(/^\w+$/) ? `.${key}` : `['${key}']`;
714
+ return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
625
715
  }
626
716
  safeKey(key) {
627
717
  return key.replace(/\W/g, '_');
628
718
  }
719
+ /**
720
+ * Sets the toArray helper in the context if not already set.
721
+ * Used for converting composite PKs to arrays.
722
+ */
723
+ setToArrayHelper(context) {
724
+ if (context.has('toArray')) {
725
+ return;
726
+ }
727
+ const toArray = (val) => {
728
+ if (Utils.isPlainObject(val)) {
729
+ return Object.values(val).map(v => toArray(v));
730
+ }
731
+ return val;
732
+ };
733
+ context.set('toArray', toArray);
734
+ }
629
735
  /**
630
736
  * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
631
737
  */