@mikro-orm/core 7.0.0-dev.2 → 7.0.0-dev.200

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 (210) hide show
  1. package/EntityManager.d.ts +111 -61
  2. package/EntityManager.js +346 -300
  3. package/MikroORM.d.ts +44 -35
  4. package/MikroORM.js +103 -143
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +1 -1
  7. package/cache/FileCacheAdapter.js +8 -7
  8. package/cache/GeneratedCacheAdapter.d.ts +0 -1
  9. package/cache/GeneratedCacheAdapter.js +0 -2
  10. package/cache/index.d.ts +0 -1
  11. package/cache/index.js +0 -1
  12. package/connections/Connection.d.ts +16 -7
  13. package/connections/Connection.js +23 -14
  14. package/drivers/DatabaseDriver.d.ts +25 -16
  15. package/drivers/DatabaseDriver.js +80 -35
  16. package/drivers/IDatabaseDriver.d.ts +47 -17
  17. package/entity/BaseEntity.d.ts +2 -2
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +95 -31
  20. package/entity/Collection.js +444 -102
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +13 -1
  24. package/entity/EntityFactory.js +88 -54
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +38 -15
  27. package/entity/EntityLoader.d.ts +8 -7
  28. package/entity/EntityLoader.js +134 -80
  29. package/entity/EntityRepository.d.ts +24 -4
  30. package/entity/EntityRepository.js +8 -2
  31. package/entity/Reference.d.ts +9 -12
  32. package/entity/Reference.js +34 -9
  33. package/entity/WrappedEntity.d.ts +2 -7
  34. package/entity/WrappedEntity.js +3 -8
  35. package/entity/defineEntity.d.ts +585 -0
  36. package/entity/defineEntity.js +533 -0
  37. package/entity/index.d.ts +3 -2
  38. package/entity/index.js +3 -2
  39. package/entity/utils.d.ts +7 -0
  40. package/entity/utils.js +16 -4
  41. package/entity/validators.d.ts +11 -0
  42. package/entity/validators.js +65 -0
  43. package/enums.d.ts +22 -6
  44. package/enums.js +15 -1
  45. package/errors.d.ts +23 -9
  46. package/errors.js +59 -21
  47. package/events/EventManager.d.ts +2 -1
  48. package/events/EventManager.js +19 -11
  49. package/events/EventSubscriber.d.ts +3 -1
  50. package/hydration/Hydrator.js +1 -2
  51. package/hydration/ObjectHydrator.d.ts +4 -4
  52. package/hydration/ObjectHydrator.js +53 -33
  53. package/index.d.ts +2 -2
  54. package/index.js +1 -2
  55. package/logging/DefaultLogger.d.ts +1 -1
  56. package/logging/DefaultLogger.js +1 -0
  57. package/logging/SimpleLogger.d.ts +1 -1
  58. package/logging/colors.d.ts +1 -1
  59. package/logging/colors.js +7 -6
  60. package/logging/index.d.ts +1 -0
  61. package/logging/index.js +1 -0
  62. package/logging/inspect.d.ts +2 -0
  63. package/logging/inspect.js +11 -0
  64. package/metadata/EntitySchema.d.ts +26 -26
  65. package/metadata/EntitySchema.js +82 -51
  66. package/metadata/MetadataDiscovery.d.ts +7 -10
  67. package/metadata/MetadataDiscovery.js +408 -335
  68. package/metadata/MetadataProvider.d.ts +11 -2
  69. package/metadata/MetadataProvider.js +46 -2
  70. package/metadata/MetadataStorage.d.ts +13 -11
  71. package/metadata/MetadataStorage.js +70 -37
  72. package/metadata/MetadataValidator.d.ts +17 -9
  73. package/metadata/MetadataValidator.js +100 -42
  74. package/metadata/discover-entities.d.ts +5 -0
  75. package/metadata/discover-entities.js +40 -0
  76. package/metadata/index.d.ts +1 -1
  77. package/metadata/index.js +1 -1
  78. package/metadata/types.d.ts +502 -0
  79. package/metadata/types.js +1 -0
  80. package/naming-strategy/AbstractNamingStrategy.d.ts +12 -4
  81. package/naming-strategy/AbstractNamingStrategy.js +14 -2
  82. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  83. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  84. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  85. package/naming-strategy/MongoNamingStrategy.js +6 -6
  86. package/naming-strategy/NamingStrategy.d.ts +24 -4
  87. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  88. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  89. package/not-supported.d.ts +2 -0
  90. package/not-supported.js +4 -0
  91. package/package.json +19 -11
  92. package/platforms/ExceptionConverter.js +1 -1
  93. package/platforms/Platform.d.ts +7 -13
  94. package/platforms/Platform.js +20 -43
  95. package/serialization/EntitySerializer.d.ts +5 -0
  96. package/serialization/EntitySerializer.js +47 -27
  97. package/serialization/EntityTransformer.js +28 -18
  98. package/serialization/SerializationContext.d.ts +6 -6
  99. package/serialization/SerializationContext.js +16 -13
  100. package/types/ArrayType.d.ts +1 -1
  101. package/types/ArrayType.js +2 -3
  102. package/types/BigIntType.d.ts +9 -6
  103. package/types/BigIntType.js +4 -1
  104. package/types/BlobType.d.ts +0 -1
  105. package/types/BlobType.js +0 -3
  106. package/types/BooleanType.d.ts +2 -1
  107. package/types/BooleanType.js +3 -0
  108. package/types/DecimalType.d.ts +6 -4
  109. package/types/DecimalType.js +3 -3
  110. package/types/DoubleType.js +2 -2
  111. package/types/EnumArrayType.js +1 -2
  112. package/types/JsonType.d.ts +1 -1
  113. package/types/JsonType.js +7 -2
  114. package/types/TinyIntType.js +1 -1
  115. package/types/Type.d.ts +2 -4
  116. package/types/Type.js +3 -3
  117. package/types/Uint8ArrayType.d.ts +0 -1
  118. package/types/Uint8ArrayType.js +1 -4
  119. package/types/index.d.ts +1 -1
  120. package/typings.d.ts +300 -140
  121. package/typings.js +62 -44
  122. package/unit-of-work/ChangeSet.d.ts +2 -6
  123. package/unit-of-work/ChangeSet.js +4 -5
  124. package/unit-of-work/ChangeSetComputer.d.ts +1 -3
  125. package/unit-of-work/ChangeSetComputer.js +26 -13
  126. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  127. package/unit-of-work/ChangeSetPersister.js +77 -35
  128. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  129. package/unit-of-work/CommitOrderCalculator.js +13 -13
  130. package/unit-of-work/IdentityMap.d.ts +12 -0
  131. package/unit-of-work/IdentityMap.js +39 -1
  132. package/unit-of-work/UnitOfWork.d.ts +23 -3
  133. package/unit-of-work/UnitOfWork.js +199 -106
  134. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  135. package/utils/AbstractSchemaGenerator.js +22 -17
  136. package/utils/AsyncContext.d.ts +6 -0
  137. package/utils/AsyncContext.js +42 -0
  138. package/utils/Configuration.d.ts +779 -207
  139. package/utils/Configuration.js +146 -190
  140. package/utils/ConfigurationLoader.d.ts +1 -54
  141. package/utils/ConfigurationLoader.js +1 -352
  142. package/utils/Cursor.d.ts +3 -6
  143. package/utils/Cursor.js +27 -11
  144. package/utils/DataloaderUtils.d.ts +15 -5
  145. package/utils/DataloaderUtils.js +65 -17
  146. package/utils/EntityComparator.d.ts +13 -9
  147. package/utils/EntityComparator.js +164 -89
  148. package/utils/QueryHelper.d.ts +14 -6
  149. package/utils/QueryHelper.js +88 -26
  150. package/utils/RawQueryFragment.d.ts +48 -25
  151. package/utils/RawQueryFragment.js +67 -66
  152. package/utils/RequestContext.js +2 -2
  153. package/utils/TransactionContext.js +2 -2
  154. package/utils/TransactionManager.d.ts +65 -0
  155. package/utils/TransactionManager.js +223 -0
  156. package/utils/Utils.d.ts +13 -120
  157. package/utils/Utils.js +104 -375
  158. package/utils/clone.js +8 -23
  159. package/utils/env-vars.d.ts +7 -0
  160. package/utils/env-vars.js +97 -0
  161. package/utils/fs-utils.d.ts +32 -0
  162. package/utils/fs-utils.js +178 -0
  163. package/utils/index.d.ts +2 -1
  164. package/utils/index.js +2 -1
  165. package/utils/upsert-utils.d.ts +9 -4
  166. package/utils/upsert-utils.js +55 -4
  167. package/decorators/Check.d.ts +0 -3
  168. package/decorators/Check.js +0 -13
  169. package/decorators/CreateRequestContext.d.ts +0 -3
  170. package/decorators/CreateRequestContext.js +0 -29
  171. package/decorators/Embeddable.d.ts +0 -8
  172. package/decorators/Embeddable.js +0 -11
  173. package/decorators/Embedded.d.ts +0 -18
  174. package/decorators/Embedded.js +0 -18
  175. package/decorators/Entity.d.ts +0 -18
  176. package/decorators/Entity.js +0 -13
  177. package/decorators/Enum.d.ts +0 -9
  178. package/decorators/Enum.js +0 -16
  179. package/decorators/Filter.d.ts +0 -2
  180. package/decorators/Filter.js +0 -8
  181. package/decorators/Formula.d.ts +0 -5
  182. package/decorators/Formula.js +0 -15
  183. package/decorators/Indexed.d.ts +0 -17
  184. package/decorators/Indexed.js +0 -20
  185. package/decorators/ManyToMany.d.ts +0 -40
  186. package/decorators/ManyToMany.js +0 -14
  187. package/decorators/ManyToOne.d.ts +0 -30
  188. package/decorators/ManyToOne.js +0 -14
  189. package/decorators/OneToMany.d.ts +0 -28
  190. package/decorators/OneToMany.js +0 -17
  191. package/decorators/OneToOne.d.ts +0 -24
  192. package/decorators/OneToOne.js +0 -7
  193. package/decorators/PrimaryKey.d.ts +0 -9
  194. package/decorators/PrimaryKey.js +0 -20
  195. package/decorators/Property.d.ts +0 -250
  196. package/decorators/Property.js +0 -32
  197. package/decorators/Transactional.d.ts +0 -13
  198. package/decorators/Transactional.js +0 -28
  199. package/decorators/hooks.d.ts +0 -16
  200. package/decorators/hooks.js +0 -47
  201. package/decorators/index.d.ts +0 -17
  202. package/decorators/index.js +0 -17
  203. package/entity/ArrayCollection.d.ts +0 -116
  204. package/entity/ArrayCollection.js +0 -395
  205. package/entity/EntityValidator.d.ts +0 -19
  206. package/entity/EntityValidator.js +0 -150
  207. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  208. package/metadata/ReflectMetadataProvider.js +0 -44
  209. package/utils/resolveContextProvider.d.ts +0 -10
  210. package/utils/resolveContextProvider.js +0 -28
@@ -2,7 +2,8 @@ import { clone } from './clone.js';
2
2
  import { ReferenceKind } from '../enums.js';
3
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';
6
7
  export class EntityComparator {
7
8
  metadata;
8
9
  platform;
@@ -20,9 +21,9 @@ export class EntityComparator {
20
21
  /**
21
22
  * Computes difference between two entities.
22
23
  */
23
- diffEntities(entityName, a, b) {
24
+ diffEntities(entityName, a, b, options) {
24
25
  const comparator = this.getEntityComparator(entityName);
25
- return Utils.callCompiledFunction(comparator, a, b);
26
+ return Utils.callCompiledFunction(comparator, a, b, options);
26
27
  }
27
28
  matching(entityName, a, b) {
28
29
  const diff = this.diffEntities(entityName, a, b);
@@ -33,22 +34,22 @@ export class EntityComparator {
33
34
  * References will be mapped to primary keys, collections to arrays of primary keys.
34
35
  */
35
36
  prepareEntity(entity) {
36
- const generator = this.getSnapshotGenerator(entity.constructor.name);
37
+ const generator = this.getSnapshotGenerator(entity.constructor);
37
38
  return Utils.callCompiledFunction(generator, entity);
38
39
  }
39
40
  /**
40
41
  * Maps database columns to properties.
41
42
  */
42
- mapResult(entityName, result) {
43
- const mapper = this.getResultMapper(entityName);
43
+ mapResult(meta, result) {
44
+ const mapper = this.getResultMapper(meta);
44
45
  return Utils.callCompiledFunction(mapper, result);
45
46
  }
46
47
  /**
47
48
  * @internal Highly performance-sensitive method.
48
49
  */
49
50
  getPkGetter(meta) {
50
- const exists = this.pkGetters.get(meta.className);
51
- /* v8 ignore next 3 */
51
+ const exists = this.pkGetters.get(meta);
52
+ /* v8 ignore next */
52
53
  if (exists) {
53
54
  return exists;
54
55
  }
@@ -74,7 +75,7 @@ export class EntityComparator {
74
75
  lines.push(` if (entity${this.wrap(pk)} != null && (entity${this.wrap(pk)}.__entity || entity${this.wrap(pk)}.__reference)) {`);
75
76
  lines.push(` const pk = entity${this.wrap(pk)}.__helper.getPrimaryKey();`);
76
77
  if (meta.properties[pk].targetMeta.compositePK) {
77
- lines.push(` if (typeof pk === 'object') {`);
78
+ lines.push(` if (typeof pk === 'object' && pk != null) {`);
78
79
  lines.push(` return [`);
79
80
  for (const childPK of meta.properties[pk].targetMeta.primaryKeys) {
80
81
  lines.push(` pk${this.wrap(childPK)},`);
@@ -90,15 +91,15 @@ export class EntityComparator {
90
91
  const code = `// compiled pk serializer for entity ${meta.className}\n`
91
92
  + `return function(entity) {\n${lines.join('\n')}\n}`;
92
93
  const pkSerializer = Utils.createFunction(context, code);
93
- this.pkGetters.set(meta.className, pkSerializer);
94
+ this.pkGetters.set(meta, pkSerializer);
94
95
  return pkSerializer;
95
96
  }
96
97
  /**
97
98
  * @internal Highly performance-sensitive method.
98
99
  */
99
100
  getPkGetterConverted(meta) {
100
- const exists = this.pkGettersConverted.get(meta.className);
101
- /* v8 ignore next 3 */
101
+ const exists = this.pkGettersConverted.get(meta);
102
+ /* v8 ignore next */
102
103
  if (exists) {
103
104
  return exists;
104
105
  }
@@ -140,21 +141,22 @@ export class EntityComparator {
140
141
  const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n`
141
142
  + `return function(entity) {\n${lines.join('\n')}\n}`;
142
143
  const pkSerializer = Utils.createFunction(context, code);
143
- this.pkGettersConverted.set(meta.className, pkSerializer);
144
+ this.pkGettersConverted.set(meta, pkSerializer);
144
145
  return pkSerializer;
145
146
  }
146
147
  /**
147
148
  * @internal Highly performance-sensitive method.
148
149
  */
149
150
  getPkSerializer(meta) {
150
- const exists = this.pkSerializers.get(meta.className);
151
- /* v8 ignore next 3 */
151
+ const exists = this.pkSerializers.get(meta);
152
+ /* v8 ignore next */
152
153
  if (exists) {
153
154
  return exists;
154
155
  }
155
156
  const lines = [];
156
157
  const context = new Map();
157
158
  context.set('getCompositeKeyValue', (val) => Utils.flatten(Utils.getCompositeKeyValue(val, meta, 'convertToDatabaseValue', this.platform)));
159
+ context.set('getPrimaryKeyHash', (val) => Utils.getPrimaryKeyHash(Utils.asArray(val)));
158
160
  if (meta.primaryKeys.length > 1) {
159
161
  lines.push(` const pks = entity.__helper.__pk ? getCompositeKeyValue(entity.__helper.__pk) : [`);
160
162
  meta.primaryKeys.forEach(pk => {
@@ -170,30 +172,39 @@ export class EntityComparator {
170
172
  }
171
173
  else {
172
174
  const pk = meta.primaryKeys[0];
173
- if (meta.properties[pk].kind !== ReferenceKind.SCALAR) {
175
+ const prop = meta.properties[pk];
176
+ if (prop.kind !== ReferenceKind.SCALAR) {
174
177
  lines.push(` if (entity${this.wrap(pk)} != null && (entity${this.wrap(pk)}.__entity || entity${this.wrap(pk)}.__reference)) return entity${this.wrap(pk)}.__helper.getSerializedPrimaryKey();`);
175
178
  }
176
179
  const serializedPrimaryKey = meta.props.find(p => p.serializedPrimaryKey);
177
180
  if (serializedPrimaryKey) {
178
181
  lines.push(` return '' + entity.${serializedPrimaryKey.name};`);
179
182
  }
180
- lines.push(` return '' + entity.${meta.primaryKeys[0]};`);
183
+ else if (prop.customType) {
184
+ const convertorKey = this.registerCustomType(meta.properties[pk], context);
185
+ const idx = this.tmpIndex++;
186
+ lines.push(` const val_${idx} = convertToDatabaseValue_${convertorKey}(entity${this.wrap(pk)});`);
187
+ lines.push(` return getPrimaryKeyHash(val_${idx});`);
188
+ }
189
+ else {
190
+ lines.push(` return '' + entity${this.wrap(pk)};`);
191
+ }
181
192
  }
182
193
  const code = `// compiled pk serializer for entity ${meta.className}\n`
183
194
  + `return function(entity) {\n${lines.join('\n')}\n}`;
184
195
  const pkSerializer = Utils.createFunction(context, code);
185
- this.pkSerializers.set(meta.className, pkSerializer);
196
+ this.pkSerializers.set(meta, pkSerializer);
186
197
  return pkSerializer;
187
198
  }
188
199
  /**
189
200
  * @internal Highly performance-sensitive method.
190
201
  */
191
202
  getSnapshotGenerator(entityName) {
192
- const exists = this.snapshotGenerators.get(entityName);
203
+ const meta = this.metadata.find(entityName);
204
+ const exists = this.snapshotGenerators.get(meta);
193
205
  if (exists) {
194
206
  return exists;
195
207
  }
196
- const meta = this.metadata.find(entityName);
197
208
  const lines = [];
198
209
  const context = new Map();
199
210
  context.set('clone', clone);
@@ -211,7 +222,7 @@ export class EntityComparator {
211
222
  .forEach(prop => lines.push(this.getPropertySnapshot(meta, prop, context, this.wrap(prop.name), this.wrap(prop.name), [prop.name])));
212
223
  const code = `return function(entity) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
213
224
  const snapshotGenerator = Utils.createFunction(context, code);
214
- this.snapshotGenerators.set(entityName, snapshotGenerator);
225
+ this.snapshotGenerators.set(meta, snapshotGenerator);
215
226
  return snapshotGenerator;
216
227
  }
217
228
  /**
@@ -261,12 +272,11 @@ export class EntityComparator {
261
272
  /**
262
273
  * @internal Highly performance-sensitive method.
263
274
  */
264
- getResultMapper(entityName) {
265
- const exists = this.mappers.get(entityName);
275
+ getResultMapper(meta) {
276
+ const exists = this.mappers.get(meta);
266
277
  if (exists) {
267
278
  return exists;
268
279
  }
269
- const meta = this.metadata.get(entityName);
270
280
  const lines = [];
271
281
  const context = new Map();
272
282
  const tz = this.platform.getTimezone();
@@ -274,10 +284,14 @@ export class EntityComparator {
274
284
  lines.push(`${padding} if (${value} == null || ${value} instanceof Date) {`);
275
285
  lines.push(`${padding} ${key} = ${value};`);
276
286
  if (!tz || tz === 'local') {
287
+ lines.push(`${padding} } else if (typeof ${value} === 'bigint') {`);
288
+ lines.push(`${padding} ${key} = parseDate(Number(${value}));`);
277
289
  lines.push(`${padding} } else {`);
278
290
  lines.push(`${padding} ${key} = parseDate(${value});`);
279
291
  }
280
292
  else {
293
+ lines.push(`${padding} } else if (typeof ${value} === 'bigint') {`);
294
+ lines.push(`${padding} ${key} = parseDate(Number(${value}));`);
281
295
  lines.push(`${padding} } else if (typeof ${value} === 'number' || ${value}.includes('+') || ${value}.lastIndexOf('-') > 10 || ${value}.endsWith('Z')) {`);
282
296
  lines.push(`${padding} ${key} = parseDate(${value});`);
283
297
  lines.push(`${padding} } else {`);
@@ -286,61 +300,77 @@ export class EntityComparator {
286
300
  lines.push(`${padding} }`);
287
301
  };
288
302
  lines.push(` const mapped = {};`);
289
- meta.props.forEach(prop => {
290
- if (!prop.fieldNames) {
291
- return;
292
- }
293
- if (prop.targetMeta && prop.fieldNames.length > 1) {
294
- lines.push(` if (${prop.fieldNames.map(field => `typeof ${this.propName(field)} === 'undefined'`).join(' && ')}) {`);
295
- lines.push(` } else if (${prop.fieldNames.map(field => `${this.propName(field)} != null`).join(' && ')}) {`);
296
- lines.push(` ret${this.wrap(prop.name)} = ${this.createCompositeKeyArray(prop)};`);
297
- lines.push(...prop.fieldNames.map(field => ` ${this.propName(field, 'mapped')} = true;`));
298
- lines.push(` } else if (${prop.fieldNames.map(field => `${this.propName(field)} == null`).join(' && ')}) {\n ret${this.wrap(prop.name)} = null;`);
299
- lines.push(...prop.fieldNames.map(field => ` ${this.propName(field, 'mapped')} = true;`), ' }');
300
- return;
301
- }
302
- if (prop.embedded && (meta.embeddable || meta.properties[prop.embedded[0]].object)) {
303
- return;
304
- }
305
- if (prop.runtimeType === 'boolean') {
306
- lines.push(` if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
307
- lines.push(` ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : !!${this.propName(prop.fieldNames[0])};`);
308
- lines.push(` ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
309
- lines.push(` }`);
310
- }
311
- else if (prop.runtimeType === 'Date' && !this.platform.isNumericProperty(prop)) {
312
- lines.push(` if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
313
- context.set('parseDate', (value) => this.platform.parseDate(value));
314
- parseDate('ret' + this.wrap(prop.name), this.propName(prop.fieldNames[0]));
315
- lines.push(` ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
316
- lines.push(` }`);
317
- }
318
- else if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
319
- const idx = this.tmpIndex++;
320
- context.set(`mapEmbeddedResult_${idx}`, (data) => {
321
- const item = parseJsonSafe(data);
322
- if (Array.isArray(item)) {
323
- return item.map(row => row == null ? row : this.getResultMapper(prop.type)(row));
324
- }
325
- return item == null ? item : this.getResultMapper(prop.type)(item);
326
- });
327
- lines.push(` if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
328
- lines.push(` ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : mapEmbeddedResult_${idx}(${this.propName(prop.fieldNames[0])});`);
329
- lines.push(` ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
330
- lines.push(` }`);
303
+ const mapEntityProperties = (meta, padding = '') => {
304
+ for (const prop of meta.props) {
305
+ if (!prop.fieldNames) {
306
+ continue;
307
+ }
308
+ if (prop.targetMeta && prop.fieldNames.length > 1) {
309
+ lines.push(`${padding} if (${prop.fieldNames.map(field => `typeof ${this.propName(field)} === 'undefined'`).join(' && ')}) {`);
310
+ lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} != null`).join(' && ')}) {`);
311
+ lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.createCompositeKeyArray(prop)};`);
312
+ lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`));
313
+ lines.push(`${padding} } else if (${prop.fieldNames.map(field => `${this.propName(field)} == null`).join(' && ')}) {\n ret${this.wrap(prop.name)} = null;`);
314
+ lines.push(...prop.fieldNames.map(field => `${padding} ${this.propName(field, 'mapped')} = true;`), ' }');
315
+ continue;
316
+ }
317
+ if (prop.embedded && (meta.embeddable || meta.properties[prop.embedded[0]].object)) {
318
+ continue;
319
+ }
320
+ if (prop.runtimeType === 'boolean') {
321
+ lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
322
+ lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])} == null ? ${this.propName(prop.fieldNames[0])} : !!${this.propName(prop.fieldNames[0])};`);
323
+ lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
324
+ lines.push(`${padding} }`);
325
+ }
326
+ else if (prop.runtimeType === 'Date' && !this.platform.isNumericProperty(prop)) {
327
+ lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
328
+ context.set('parseDate', (value) => this.platform.parseDate(value));
329
+ parseDate('ret' + this.wrap(prop.name), this.propName(prop.fieldNames[0]), padding);
330
+ lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
331
+ lines.push(`${padding} }`);
332
+ }
333
+ else if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
334
+ const idx = this.tmpIndex++;
335
+ context.set(`mapEmbeddedResult_${idx}`, (data) => {
336
+ const item = parseJsonSafe(data);
337
+ if (Array.isArray(item)) {
338
+ return item.map(row => row == null ? row : this.getResultMapper(prop.targetMeta)(row));
339
+ }
340
+ return item == null ? item : this.getResultMapper(prop.targetMeta)(item);
341
+ });
342
+ lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
343
+ 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])});`);
344
+ lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
345
+ lines.push(`${padding} }`);
346
+ }
347
+ else if (prop.kind !== ReferenceKind.EMBEDDED) {
348
+ lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
349
+ lines.push(`${padding} ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])};`);
350
+ lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
351
+ lines.push(`${padding} }`);
352
+ }
331
353
  }
332
- else if (prop.kind !== ReferenceKind.EMBEDDED) {
333
- lines.push(` if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
334
- lines.push(` ret${this.wrap(prop.name)} = ${this.propName(prop.fieldNames[0])};`);
335
- lines.push(` ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
354
+ };
355
+ if (meta.polymorphs && meta.discriminatorColumn) {
356
+ for (const polymorph of meta.polymorphs) {
357
+ const first = polymorph === meta.polymorphs[0];
358
+ lines.push(` ${first ? '' : 'else '}if (${this.propName(meta.discriminatorColumn)} == '${polymorph.discriminatorValue}') {`);
359
+ mapEntityProperties(polymorph, ' ');
336
360
  lines.push(` }`);
337
361
  }
338
- });
339
- lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k]) ret[k] = result[k]; }`);
362
+ lines.push(` else {`);
363
+ mapEntityProperties(meta, ' ');
364
+ lines.push(` }`);
365
+ }
366
+ else {
367
+ mapEntityProperties(meta);
368
+ }
369
+ lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k] && ret[k] === undefined) ret[k] = result[k]; }`);
340
370
  const code = `// compiled mapper for entity ${meta.className}\n`
341
371
  + `return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
342
372
  const resultMapper = Utils.createFunction(context, code);
343
- this.mappers.set(entityName, resultMapper);
373
+ this.mappers.set(meta, resultMapper);
344
374
  return resultMapper;
345
375
  }
346
376
  getPropertyCondition(path) {
@@ -391,11 +421,21 @@ export class EntityComparator {
391
421
  }
392
422
  getEmbeddedPropertySnapshot(meta, prop, context, level, path, dataKey, object = prop.object) {
393
423
  const padding = ' '.repeat(level * 2);
424
+ const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
394
425
  let ret = `${level === 1 ? '' : '\n'}`;
395
426
  if (object) {
396
- const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
397
427
  ret += `${padding}if (${nullCond}) ret${dataKey} = null;\n`;
398
428
  }
429
+ else {
430
+ ret += `${padding}if (${nullCond}) {\n`;
431
+ ret += meta.props.filter(p => p.embedded?.[0] === prop.name
432
+ // object for JSON embeddable
433
+ && (p.object || (p.persist !== false))).map(childProp => {
434
+ const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
435
+ return `${padding} ret${childDataKey} = null;`;
436
+ }).join('\n') + `\n`;
437
+ ret += `${padding}}\n`;
438
+ }
399
439
  const cond = `entity${path.map(k => this.wrap(k)).join('')} != null`;
400
440
  ret += `${padding}if (${cond}) {\n`;
401
441
  if (object) {
@@ -440,8 +480,8 @@ export class EntityComparator {
440
480
  registerCustomType(prop, context) {
441
481
  const convertorKey = this.safeKey(prop.name);
442
482
  context.set(`convertToDatabaseValue_${convertorKey}`, (val) => {
443
- /* v8 ignore next 3 */
444
- if (RawQueryFragment.isKnownFragment(val)) {
483
+ /* v8 ignore next */
484
+ if (Raw.isKnownFragment(val)) {
445
485
  return val;
446
486
  }
447
487
  return prop.customType.convertToDatabaseValue(val, this.platform, { mode: 'serialization' });
@@ -470,6 +510,23 @@ export class EntityComparator {
470
510
  ret += ` ret${dataKey} = entity${entityKey};\n`;
471
511
  }
472
512
  }
513
+ else if (prop.targetKey) {
514
+ // When targetKey is set, extract that property value instead of the PK
515
+ const targetProp = prop.targetMeta?.properties[prop.targetKey];
516
+ ret += ` if (entity${entityKey} === null) {\n`;
517
+ ret += ` ret${dataKey} = null;\n`;
518
+ ret += ` } else if (typeof entity${entityKey} !== 'undefined') {\n`;
519
+ ret += ` const val${level} = entity${entityKey}${unwrap};\n`;
520
+ if (targetProp?.customType) {
521
+ // If targetKey property has a custom type, convert to database value
522
+ const convertorKey = this.registerCustomType(targetProp, context);
523
+ ret += ` ret${dataKey} = convertToDatabaseValue_${convertorKey}(val${level}?.${prop.targetKey});\n`;
524
+ }
525
+ else {
526
+ ret += ` ret${dataKey} = val${level}?.${prop.targetKey};\n`;
527
+ }
528
+ ret += ` }\n`;
529
+ }
473
530
  else {
474
531
  const toArray = (val) => {
475
532
  if (Utils.isPlainObject(val)) {
@@ -478,8 +535,11 @@ export class EntityComparator {
478
535
  return val;
479
536
  };
480
537
  context.set('toArray', toArray);
538
+ context.set('EntityIdentifier', EntityIdentifier);
481
539
  ret += ` if (entity${entityKey} === null) {\n`;
482
540
  ret += ` ret${dataKey} = null;\n`;
541
+ ret += ` } else if (entity${entityKey}?.__helper.__identifier && !entity${entityKey}.__helper.hasPrimaryKey()) {\n`;
542
+ ret += ` ret${dataKey} = entity${entityKey}?.__helper.__identifier;\n`;
483
543
  ret += ` } else if (typeof entity${entityKey} !== 'undefined') {\n`;
484
544
  ret += ` ret${dataKey} = toArray(entity${entityKey}.__helper.getPrimaryKey(true));\n`;
485
545
  ret += ` }\n`;
@@ -503,11 +563,11 @@ export class EntityComparator {
503
563
  * @internal Highly performance-sensitive method.
504
564
  */
505
565
  getEntityComparator(entityName) {
506
- const exists = this.comparators.get(entityName);
566
+ const meta = this.metadata.find(entityName);
567
+ const exists = this.comparators.get(meta);
507
568
  if (exists) {
508
569
  return exists;
509
570
  }
510
- const meta = this.metadata.find(entityName);
511
571
  const lines = [];
512
572
  const context = new Map();
513
573
  context.set('compareArrays', compareArrays);
@@ -515,17 +575,27 @@ export class EntityComparator {
515
575
  context.set('compareBuffers', compareBuffers);
516
576
  context.set('compareObjects', compareObjects);
517
577
  context.set('equals', equals);
518
- meta.comparableProps.forEach(prop => {
578
+ for (const prop of meta.comparableProps) {
519
579
  lines.push(this.getPropertyComparator(prop, context));
520
- });
580
+ }
581
+ // also compare 1:1 inverse sides, important for `factory.mergeData`
582
+ lines.push(`if (options?.includeInverseSides) {`);
583
+ for (const prop of meta.bidirectionalRelations) {
584
+ if (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && prop.hydrate !== false) {
585
+ lines.push(this.getPropertyComparator(prop, context));
586
+ }
587
+ }
588
+ lines.push(`}`);
521
589
  const code = `// compiled comparator for entity ${meta.className}\n`
522
- + `return function(last, current) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
590
+ + `return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
523
591
  const comparator = Utils.createFunction(context, code);
524
- this.comparators.set(entityName, comparator);
592
+ this.comparators.set(meta, comparator);
525
593
  return comparator;
526
594
  }
527
595
  getGenericComparator(prop, cond) {
528
- return ` if (current${prop} == null && last${prop} == null) {\n\n` +
596
+ return ` if (current${prop} === null && last${prop} === undefined) {\n` +
597
+ ` diff${prop} = current${prop};\n` +
598
+ ` } else if (current${prop} == null && last${prop} == null) {\n\n` +
529
599
  ` } else if ((current${prop} != null && last${prop} == null) || (current${prop} == null && last${prop} != null)) {\n` +
530
600
  ` diff${prop} = current${prop};\n` +
531
601
  ` } else if (${cond}) {\n` +
@@ -535,18 +605,23 @@ export class EntityComparator {
535
605
  getPropertyComparator(prop, context) {
536
606
  let type = prop.type.toLowerCase();
537
607
  if (prop.kind !== ReferenceKind.SCALAR && prop.kind !== ReferenceKind.EMBEDDED) {
538
- const meta2 = this.metadata.find(prop.type);
608
+ const meta2 = prop.targetMeta;
539
609
  if (meta2.primaryKeys.length > 1) {
540
610
  type = 'array';
541
611
  }
542
612
  else {
543
- type = meta2.properties[meta2.primaryKeys[0]].type.toLowerCase();
613
+ type = meta2.getPrimaryProp().type.toLowerCase();
544
614
  }
545
615
  }
546
616
  if (prop.customType) {
547
617
  if (prop.customType.compareValues) {
548
618
  const idx = this.tmpIndex++;
549
- context.set(`compareValues_${idx}`, (a, b) => prop.customType.compareValues(a, b));
619
+ context.set(`compareValues_${idx}`, (a, b) => {
620
+ if (Raw.isKnownFragment(a) || Raw.isKnownFragment(b)) {
621
+ return Raw.getKnownFragment(a) === Raw.getKnownFragment(b);
622
+ }
623
+ return prop.customType.compareValues(a, b);
624
+ });
550
625
  return this.getGenericComparator(this.wrap(prop.name), `!compareValues_${idx}(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
551
626
  }
552
627
  type = prop.customType.compareAsType().toLowerCase();
@@ -566,10 +641,10 @@ export class EntityComparator {
566
641
  if (['buffer', 'uint8array'].includes(type)) {
567
642
  return this.getGenericComparator(this.wrap(prop.name), `!compareBuffers(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
568
643
  }
569
- if (['date'].includes(type)) {
644
+ if (type === 'date') {
570
645
  return this.getGenericComparator(this.wrap(prop.name), `last${this.wrap(prop.name)}.valueOf() !== current${this.wrap(prop.name)}.valueOf()`);
571
646
  }
572
- if (['objectid'].includes(type)) {
647
+ if (type === 'objectid') {
573
648
  // We might be comparing PK to object, in case we compare with cached data of populated entity
574
649
  // in such case we just ignore the comparison and fallback to `equals()` (which will still mark
575
650
  // it as not equal as we compare PK to plain object).
@@ -591,7 +666,7 @@ export class EntityComparator {
591
666
  * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
592
667
  */
593
668
  static isComparable(prop, root) {
594
- const virtual = prop.persist === false || prop.generated;
669
+ const virtual = prop.persist === false || (prop.generated && !prop.primary);
595
670
  const inverse = prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner;
596
671
  const discriminator = prop.name === root.discriminatorColumn;
597
672
  const collection = prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY;
@@ -1,14 +1,22 @@
1
- import type { Dictionary, EntityMetadata, EntityProperty, FilterDef, FilterQuery } from '../typings.js';
1
+ import type { Dictionary, EntityMetadata, EntityName, EntityProperty, FilterDef, FilterQuery } from '../typings.js';
2
2
  import type { Platform } from '../platforms/Platform.js';
3
3
  import type { MetadataStorage } from '../metadata/MetadataStorage.js';
4
+ import type { FilterOptions } from '../drivers/IDatabaseDriver.js';
5
+ /** @internal */
4
6
  export declare class QueryHelper {
5
7
  static readonly SUPPORTED_OPERATORS: string[];
6
8
  static processParams(params: unknown): any;
7
- static processObjectParams<T extends object>(params?: T): T;
9
+ static processObjectParams<T extends Dictionary>(params?: T): T;
10
+ /**
11
+ * converts `{ account: { $or: [ [Object], [Object] ] } }`
12
+ * to `{ $or: [ { account: [Object] }, { account: [Object] } ] }`
13
+ */
14
+ static liftGroupOperators<T extends object>(where: Dictionary, meta: EntityMetadata<T>, metadata: MetadataStorage, key?: string): string | undefined;
8
15
  static inlinePrimaryKeyObjects<T extends object>(where: Dictionary, meta: EntityMetadata<T>, metadata: MetadataStorage, key?: string): boolean;
9
16
  static processWhere<T extends object>(options: ProcessWhereOptions<T>): FilterQuery<T>;
10
- static getActiveFilters(entityName: string, options: Dictionary<boolean | Dictionary> | string[] | boolean, filters: Dictionary<FilterDef>): FilterDef[];
11
- static isFilterActive(entityName: string, filterName: string, filter: FilterDef, options: Dictionary<boolean | Dictionary>): boolean;
17
+ static getActiveFilters<T>(meta: EntityMetadata<T>, options: FilterOptions | undefined, filters: Dictionary<FilterDef>): FilterDef[];
18
+ static mergePropertyFilters(propFilters: FilterOptions | undefined, options: FilterOptions | undefined): FilterOptions | undefined;
19
+ static isFilterActive<T>(meta: EntityMetadata<T>, filterName: string, filter: FilterDef, options: Dictionary<boolean | Dictionary>): boolean;
12
20
  static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>;
13
21
  private static isSupportedOperator;
14
22
  private static processJsonCondition;
@@ -17,11 +25,11 @@ export declare class QueryHelper {
17
25
  }
18
26
  interface ProcessWhereOptions<T> {
19
27
  where: FilterQuery<T>;
20
- entityName: string;
28
+ entityName: EntityName<T>;
21
29
  metadata: MetadataStorage;
22
30
  platform: Platform;
23
31
  aliased?: boolean;
24
- aliasMap?: Dictionary<string>;
32
+ aliasMap?: Dictionary<EntityName>;
25
33
  convertCustomTypes?: boolean;
26
34
  root?: boolean;
27
35
  type?: 'where' | 'orderBy';