@mikro-orm/core 7.0.9-dev.9 → 7.0.9

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 (206) hide show
  1. package/EntityManager.d.ts +884 -583
  2. package/EntityManager.js +1926 -1899
  3. package/MikroORM.d.ts +103 -74
  4. package/MikroORM.js +177 -179
  5. package/README.md +1 -1
  6. package/cache/CacheAdapter.d.ts +36 -36
  7. package/cache/FileCacheAdapter.d.ts +30 -24
  8. package/cache/FileCacheAdapter.js +80 -78
  9. package/cache/GeneratedCacheAdapter.d.ts +18 -20
  10. package/cache/GeneratedCacheAdapter.js +30 -30
  11. package/cache/MemoryCacheAdapter.d.ts +18 -20
  12. package/cache/MemoryCacheAdapter.js +35 -36
  13. package/cache/NullCacheAdapter.d.ts +16 -16
  14. package/cache/NullCacheAdapter.js +24 -24
  15. package/connections/Connection.d.ts +95 -84
  16. package/connections/Connection.js +165 -168
  17. package/drivers/DatabaseDriver.d.ts +187 -81
  18. package/drivers/DatabaseDriver.js +450 -444
  19. package/drivers/IDatabaseDriver.d.ts +440 -301
  20. package/entity/BaseEntity.d.ts +120 -83
  21. package/entity/BaseEntity.js +43 -43
  22. package/entity/Collection.d.ts +215 -181
  23. package/entity/Collection.js +730 -724
  24. package/entity/EntityAssigner.d.ts +88 -77
  25. package/entity/EntityAssigner.js +231 -230
  26. package/entity/EntityFactory.d.ts +67 -55
  27. package/entity/EntityFactory.js +457 -414
  28. package/entity/EntityHelper.d.ts +35 -23
  29. package/entity/EntityHelper.js +291 -279
  30. package/entity/EntityIdentifier.d.ts +4 -4
  31. package/entity/EntityIdentifier.js +10 -10
  32. package/entity/EntityLoader.d.ts +98 -72
  33. package/entity/EntityLoader.js +792 -761
  34. package/entity/EntityRepository.d.ts +316 -201
  35. package/entity/EntityRepository.js +213 -213
  36. package/entity/PolymorphicRef.d.ts +5 -5
  37. package/entity/PolymorphicRef.js +10 -10
  38. package/entity/Reference.d.ts +127 -83
  39. package/entity/Reference.js +281 -277
  40. package/entity/WrappedEntity.d.ts +115 -72
  41. package/entity/WrappedEntity.js +168 -166
  42. package/entity/defineEntity.d.ts +1359 -654
  43. package/entity/defineEntity.js +527 -518
  44. package/entity/utils.d.ts +13 -3
  45. package/entity/utils.js +71 -73
  46. package/entity/validators.js +43 -43
  47. package/entity/wrap.js +8 -8
  48. package/enums.d.ts +258 -253
  49. package/enums.js +251 -252
  50. package/errors.d.ts +114 -72
  51. package/errors.js +350 -253
  52. package/events/EventManager.d.ts +26 -14
  53. package/events/EventManager.js +79 -77
  54. package/events/EventSubscriber.d.ts +29 -29
  55. package/events/TransactionEventBroadcaster.d.ts +15 -8
  56. package/events/TransactionEventBroadcaster.js +14 -14
  57. package/exceptions.d.ts +23 -40
  58. package/exceptions.js +35 -52
  59. package/hydration/Hydrator.d.ts +42 -17
  60. package/hydration/Hydrator.js +43 -43
  61. package/hydration/ObjectHydrator.d.ts +50 -17
  62. package/hydration/ObjectHydrator.js +483 -418
  63. package/index.d.ts +116 -2
  64. package/index.js +10 -1
  65. package/logging/DefaultLogger.d.ts +34 -32
  66. package/logging/DefaultLogger.js +86 -86
  67. package/logging/Logger.d.ts +41 -41
  68. package/logging/SimpleLogger.d.ts +13 -11
  69. package/logging/SimpleLogger.js +22 -22
  70. package/logging/colors.d.ts +6 -6
  71. package/logging/colors.js +11 -10
  72. package/logging/inspect.js +7 -7
  73. package/metadata/EntitySchema.d.ts +214 -130
  74. package/metadata/EntitySchema.js +411 -412
  75. package/metadata/MetadataDiscovery.d.ts +114 -114
  76. package/metadata/MetadataDiscovery.js +1957 -1879
  77. package/metadata/MetadataProvider.d.ts +29 -26
  78. package/metadata/MetadataProvider.js +95 -97
  79. package/metadata/MetadataStorage.d.ts +38 -32
  80. package/metadata/MetadataStorage.js +118 -118
  81. package/metadata/MetadataValidator.d.ts +39 -39
  82. package/metadata/MetadataValidator.js +381 -338
  83. package/metadata/discover-entities.d.ts +5 -2
  84. package/metadata/discover-entities.js +35 -37
  85. package/metadata/types.d.ts +615 -531
  86. package/naming-strategy/AbstractNamingStrategy.d.ts +54 -39
  87. package/naming-strategy/AbstractNamingStrategy.js +90 -85
  88. package/naming-strategy/EntityCaseNamingStrategy.d.ts +6 -6
  89. package/naming-strategy/EntityCaseNamingStrategy.js +22 -22
  90. package/naming-strategy/MongoNamingStrategy.d.ts +6 -6
  91. package/naming-strategy/MongoNamingStrategy.js +18 -18
  92. package/naming-strategy/NamingStrategy.d.ts +109 -99
  93. package/naming-strategy/UnderscoreNamingStrategy.d.ts +7 -7
  94. package/naming-strategy/UnderscoreNamingStrategy.js +21 -21
  95. package/not-supported.js +7 -4
  96. package/package.json +1 -1
  97. package/platforms/ExceptionConverter.d.ts +1 -1
  98. package/platforms/ExceptionConverter.js +4 -4
  99. package/platforms/Platform.d.ts +312 -303
  100. package/platforms/Platform.js +695 -642
  101. package/serialization/EntitySerializer.d.ts +49 -26
  102. package/serialization/EntitySerializer.js +224 -218
  103. package/serialization/EntityTransformer.d.ts +10 -6
  104. package/serialization/EntityTransformer.js +219 -217
  105. package/serialization/SerializationContext.d.ts +27 -23
  106. package/serialization/SerializationContext.js +105 -105
  107. package/types/ArrayType.d.ts +8 -8
  108. package/types/ArrayType.js +33 -33
  109. package/types/BigIntType.d.ts +17 -10
  110. package/types/BigIntType.js +37 -37
  111. package/types/BlobType.d.ts +3 -3
  112. package/types/BlobType.js +13 -13
  113. package/types/BooleanType.d.ts +4 -4
  114. package/types/BooleanType.js +12 -12
  115. package/types/CharacterType.d.ts +2 -2
  116. package/types/CharacterType.js +6 -6
  117. package/types/DateTimeType.d.ts +5 -5
  118. package/types/DateTimeType.js +15 -15
  119. package/types/DateType.d.ts +5 -5
  120. package/types/DateType.js +15 -15
  121. package/types/DecimalType.d.ts +7 -7
  122. package/types/DecimalType.js +26 -26
  123. package/types/DoubleType.d.ts +3 -3
  124. package/types/DoubleType.js +12 -12
  125. package/types/EnumArrayType.d.ts +5 -5
  126. package/types/EnumArrayType.js +24 -24
  127. package/types/EnumType.d.ts +3 -3
  128. package/types/EnumType.js +11 -11
  129. package/types/FloatType.d.ts +3 -3
  130. package/types/FloatType.js +9 -9
  131. package/types/IntegerType.d.ts +3 -3
  132. package/types/IntegerType.js +9 -9
  133. package/types/IntervalType.d.ts +4 -4
  134. package/types/IntervalType.js +12 -12
  135. package/types/JsonType.d.ts +8 -8
  136. package/types/JsonType.js +32 -32
  137. package/types/MediumIntType.d.ts +1 -1
  138. package/types/MediumIntType.js +3 -3
  139. package/types/SmallIntType.d.ts +3 -3
  140. package/types/SmallIntType.js +9 -9
  141. package/types/StringType.d.ts +4 -4
  142. package/types/StringType.js +12 -12
  143. package/types/TextType.d.ts +3 -3
  144. package/types/TextType.js +9 -9
  145. package/types/TimeType.d.ts +5 -5
  146. package/types/TimeType.js +17 -17
  147. package/types/TinyIntType.d.ts +3 -3
  148. package/types/TinyIntType.js +10 -10
  149. package/types/Type.d.ts +83 -79
  150. package/types/Type.js +82 -82
  151. package/types/Uint8ArrayType.d.ts +4 -4
  152. package/types/Uint8ArrayType.js +21 -21
  153. package/types/UnknownType.d.ts +4 -4
  154. package/types/UnknownType.js +12 -12
  155. package/types/UuidType.d.ts +5 -5
  156. package/types/UuidType.js +19 -19
  157. package/types/index.d.ts +75 -49
  158. package/types/index.js +52 -26
  159. package/typings.d.ts +1254 -741
  160. package/typings.js +244 -233
  161. package/unit-of-work/ChangeSet.d.ts +26 -26
  162. package/unit-of-work/ChangeSet.js +56 -56
  163. package/unit-of-work/ChangeSetComputer.d.ts +12 -12
  164. package/unit-of-work/ChangeSetComputer.js +187 -179
  165. package/unit-of-work/ChangeSetPersister.d.ts +69 -50
  166. package/unit-of-work/ChangeSetPersister.js +465 -442
  167. package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
  168. package/unit-of-work/CommitOrderCalculator.js +89 -88
  169. package/unit-of-work/IdentityMap.d.ts +31 -31
  170. package/unit-of-work/IdentityMap.js +105 -105
  171. package/unit-of-work/UnitOfWork.d.ts +181 -141
  172. package/unit-of-work/UnitOfWork.js +1236 -1222
  173. package/utils/AbstractMigrator.d.ts +111 -91
  174. package/utils/AbstractMigrator.js +275 -275
  175. package/utils/AbstractSchemaGenerator.d.ts +43 -34
  176. package/utils/AbstractSchemaGenerator.js +121 -122
  177. package/utils/AsyncContext.d.ts +3 -3
  178. package/utils/AsyncContext.js +34 -35
  179. package/utils/Configuration.d.ts +852 -808
  180. package/utils/Configuration.js +359 -344
  181. package/utils/Cursor.d.ts +40 -22
  182. package/utils/Cursor.js +135 -127
  183. package/utils/DataloaderUtils.d.ts +58 -43
  184. package/utils/DataloaderUtils.js +203 -198
  185. package/utils/EntityComparator.d.ts +99 -82
  186. package/utils/EntityComparator.js +829 -737
  187. package/utils/NullHighlighter.d.ts +1 -1
  188. package/utils/NullHighlighter.js +3 -3
  189. package/utils/QueryHelper.d.ts +79 -51
  190. package/utils/QueryHelper.js +372 -361
  191. package/utils/RawQueryFragment.d.ts +50 -34
  192. package/utils/RawQueryFragment.js +107 -105
  193. package/utils/RequestContext.d.ts +32 -32
  194. package/utils/RequestContext.js +52 -53
  195. package/utils/TransactionContext.d.ts +16 -16
  196. package/utils/TransactionContext.js +27 -27
  197. package/utils/TransactionManager.d.ts +58 -58
  198. package/utils/TransactionManager.js +199 -197
  199. package/utils/Utils.d.ts +204 -145
  200. package/utils/Utils.js +815 -815
  201. package/utils/clone.js +105 -114
  202. package/utils/env-vars.js +90 -88
  203. package/utils/fs-utils.d.ts +15 -15
  204. package/utils/fs-utils.js +180 -181
  205. package/utils/upsert-utils.d.ts +20 -5
  206. package/utils/upsert-utils.js +114 -116
@@ -9,431 +9,496 @@ import { Raw } from '../utils/RawQueryFragment.js';
9
9
  import { ValidationError } from '../errors.js';
10
10
  /** @internal JIT-compiled hydrator that converts raw database rows into entity instances with optimized generated code. */
11
11
  export class ObjectHydrator extends Hydrator {
12
- #hydrators = {
13
- 'full~true': new Map(),
14
- 'full~false': new Map(),
15
- 'reference~true': new Map(),
16
- 'reference~false': new Map(),
17
- };
18
- #tmpIndex = 0;
19
- /**
20
- * @inheritDoc
21
- */
22
- hydrate(entity, meta, data, factory, type, newEntity = false, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
23
- const hydrate = this.getEntityHydrator(meta, type, normalizeAccessors);
24
- const running = this.running;
25
- // the running state is used to consider propagation as hydration, saving the values directly to the entity data,
26
- // but we don't want that for new entities, their propagation should result in entity updates when flushing
27
- this.running = !newEntity;
28
- Utils.callCompiledFunction(hydrate, entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors);
29
- this.running = running;
30
- }
31
- /**
32
- * @inheritDoc
33
- */
34
- hydrateReference(entity, meta, data, factory, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
35
- const hydrate = this.getEntityHydrator(meta, 'reference', normalizeAccessors);
36
- const running = this.running;
37
- this.running = true;
38
- Utils.callCompiledFunction(hydrate, entity, data, factory, false, convertCustomTypes, schema, parentSchema, normalizeAccessors);
39
- this.running = running;
12
+ #hydrators = {
13
+ 'full~true': new Map(),
14
+ 'full~false': new Map(),
15
+ 'reference~true': new Map(),
16
+ 'reference~false': new Map(),
17
+ };
18
+ #tmpIndex = 0;
19
+ /**
20
+ * @inheritDoc
21
+ */
22
+ hydrate(
23
+ entity,
24
+ meta,
25
+ data,
26
+ factory,
27
+ type,
28
+ newEntity = false,
29
+ convertCustomTypes = false,
30
+ schema,
31
+ parentSchema,
32
+ normalizeAccessors,
33
+ ) {
34
+ const hydrate = this.getEntityHydrator(meta, type, normalizeAccessors);
35
+ const running = this.running;
36
+ // the running state is used to consider propagation as hydration, saving the values directly to the entity data,
37
+ // but we don't want that for new entities, their propagation should result in entity updates when flushing
38
+ this.running = !newEntity;
39
+ Utils.callCompiledFunction(
40
+ hydrate,
41
+ entity,
42
+ data,
43
+ factory,
44
+ newEntity,
45
+ convertCustomTypes,
46
+ schema,
47
+ parentSchema,
48
+ normalizeAccessors,
49
+ );
50
+ this.running = running;
51
+ }
52
+ /**
53
+ * @inheritDoc
54
+ */
55
+ hydrateReference(entity, meta, data, factory, convertCustomTypes = false, schema, parentSchema, normalizeAccessors) {
56
+ const hydrate = this.getEntityHydrator(meta, 'reference', normalizeAccessors);
57
+ const running = this.running;
58
+ this.running = true;
59
+ Utils.callCompiledFunction(
60
+ hydrate,
61
+ entity,
62
+ data,
63
+ factory,
64
+ false,
65
+ convertCustomTypes,
66
+ schema,
67
+ parentSchema,
68
+ normalizeAccessors,
69
+ );
70
+ this.running = running;
71
+ }
72
+ /**
73
+ * @internal Highly performance-sensitive method.
74
+ */
75
+ getEntityHydrator(meta, type, normalizeAccessors = false) {
76
+ const key = `${type}~${normalizeAccessors}`;
77
+ const exists = this.#hydrators[key].get(meta.class);
78
+ if (exists) {
79
+ return exists;
40
80
  }
41
- /**
42
- * @internal Highly performance-sensitive method.
43
- */
44
- getEntityHydrator(meta, type, normalizeAccessors = false) {
45
- const key = `${type}~${normalizeAccessors}`;
46
- const exists = this.#hydrators[key].get(meta.class);
47
- if (exists) {
48
- return exists;
81
+ const lines = [];
82
+ const context = new Map();
83
+ const props = this.getProperties(meta, type);
84
+ context.set('isPrimaryKey', Utils.isPrimaryKey);
85
+ context.set('isEntity', EntityHelper.isEntity);
86
+ context.set('isScalarReference', ScalarReference.isScalarReference);
87
+ context.set('Collection', Collection);
88
+ context.set('Reference', Reference);
89
+ context.set('PolymorphicRef', PolymorphicRef);
90
+ context.set('ValidationError', ValidationError);
91
+ const registerCustomType = (prop, convertorKey, method, context) => {
92
+ context.set(`${method}_${convertorKey}`, val => {
93
+ /* v8 ignore next */
94
+ if (Raw.isKnownFragment(val)) {
95
+ return val;
49
96
  }
50
- const lines = [];
51
- const context = new Map();
52
- const props = this.getProperties(meta, type);
53
- context.set('isPrimaryKey', Utils.isPrimaryKey);
54
- context.set('isEntity', EntityHelper.isEntity);
55
- context.set('isScalarReference', ScalarReference.isScalarReference);
56
- context.set('Collection', Collection);
57
- context.set('Reference', Reference);
58
- context.set('PolymorphicRef', PolymorphicRef);
59
- context.set('ValidationError', ValidationError);
60
- const registerCustomType = (prop, convertorKey, method, context) => {
61
- context.set(`${method}_${convertorKey}`, (val) => {
62
- /* v8 ignore next */
63
- if (Raw.isKnownFragment(val)) {
64
- return val;
65
- }
66
- return prop.customType[method](val, this.platform, { mode: 'serialization' });
67
- });
68
- return convertorKey;
69
- };
70
- const hydrateScalar = (prop, path, dataKey) => {
71
- const entityKey = path.map(k => this.wrap(k)).join('');
72
- const tz = this.platform.getTimezone();
73
- const convertorKey = path
74
- .filter(k => !/\[idx_\d+]/.exec(k))
75
- .map(k => this.safeKey(k))
76
- .join('_');
77
- const ret = [];
78
- const idx = this.#tmpIndex++;
79
- const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
80
- if (prop.getter && !prop.setter && prop.persist === false) {
81
- return [];
82
- }
83
- if (prop.ref) {
84
- context.set('ScalarReference', ScalarReference);
85
- ret.push(` const oldValue_${idx} = entity${entityKey};`);
86
- }
87
- ret.push(` if (data${dataKey} === null) {`);
88
- if (prop.ref) {
89
- ret.push(` entity${entityKey} = new ScalarReference();`);
90
- ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
91
- ret.push(` entity${entityKey}.set(${nullVal});`);
92
- }
93
- else {
94
- ret.push(` entity${entityKey} = ${nullVal};`);
95
- }
96
- ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
97
- if (prop.customType) {
98
- registerCustomType(prop, convertorKey, 'convertToJSValue', context);
99
- registerCustomType(prop, convertorKey, 'convertToDatabaseValue', context);
100
- ret.push(` if (convertCustomTypes) {`, ` const value = convertToJSValue_${convertorKey}(data${dataKey});`);
101
- if (prop.customType.ensureComparable(meta, prop)) {
102
- ret.push(` data${dataKey} = convertToDatabaseValue_${convertorKey}(value);`);
103
- }
104
- ret.push(` entity${entityKey} = value;`, ` } else {`, ` entity${entityKey} = data${dataKey};`, ` }`);
105
- }
106
- else if (prop.runtimeType === 'boolean') {
107
- ret.push(` entity${entityKey} = !!data${dataKey};`);
108
- }
109
- else if (prop.runtimeType === 'Date' && !this.platform.isNumericProperty(prop)) {
110
- ret.push(` if (data${dataKey} instanceof Date) {`);
111
- ret.push(` entity${entityKey} = data${dataKey};`);
112
- if (!tz || tz === 'local') {
113
- ret.push(` } else {`);
114
- ret.push(` entity${entityKey} = new Date(data${dataKey});`);
115
- }
116
- else {
117
- ret.push(` } else if (typeof data${dataKey} === 'number' || data${dataKey}.includes('+') || data${dataKey}.lastIndexOf('-') > 10 || data${dataKey}.endsWith('Z')) {`);
118
- ret.push(` entity${entityKey} = new Date(data${dataKey});`);
119
- ret.push(` } else {`);
120
- ret.push(` entity${entityKey} = new Date(data${dataKey} + '${tz}');`);
121
- }
122
- ret.push(` }`);
123
- }
124
- else {
125
- ret.push(` entity${entityKey} = data${dataKey};`);
126
- }
127
- if (prop.ref) {
128
- ret.push(` const value = isScalarReference(entity${entityKey}) ? entity${entityKey}.unwrap() : entity${entityKey};`);
129
- ret.push(` entity${entityKey} = oldValue_${idx} ?? new ScalarReference(value);`);
130
- ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
131
- ret.push(` entity${entityKey}.set(value);`);
132
- }
133
- ret.push(` }`);
134
- if (prop.ref) {
135
- ret.push(` if (!entity${entityKey}) {`);
136
- ret.push(` entity${entityKey} = new ScalarReference();`);
137
- ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
138
- ret.push(` }`);
139
- }
140
- return ret;
141
- };
142
- const hydrateToOne = (prop, dataKey, entityKey) => {
143
- const ret = [];
144
- const method = type === 'reference' ? 'createReference' : 'create';
145
- const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
146
- ret.push(` if (data${dataKey} === null) {\n entity${entityKey} = ${nullVal};`);
147
- ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
148
- // For polymorphic: instanceof check; for regular: isPrimaryKey() check
149
- const pkCheck = prop.polymorphic
150
- ? `data${dataKey} instanceof PolymorphicRef`
151
- : `isPrimaryKey(data${dataKey}, true)`;
152
- ret.push(` if (${pkCheck}) {`);
153
- // When targetKey is set, pass the key option to createReference so it uses the alternate key
154
- const keyOption = prop.targetKey ? `, key: '${prop.targetKey}'` : '';
155
- if (prop.polymorphic) {
156
- // For polymorphic: target class from discriminator map, PK from data.id
157
- const discriminatorMapKey = this.safeKey(`discriminatorMap_${prop.name}_${this.#tmpIndex++}`);
158
- context.set(discriminatorMapKey, prop.discriminatorMap);
159
- ret.push(` const targetClass = ${discriminatorMapKey}[data${dataKey}.discriminator];`);
160
- ret.push(` if (!targetClass) throw new ValidationError(\`Unknown discriminator value '\${data${dataKey}.discriminator}' for polymorphic relation '${prop.name}'. Valid values: \${Object.keys(${discriminatorMapKey}).join(', ')}\`);`);
161
- if (prop.ref) {
162
- ret.push(` entity${entityKey} = Reference.create(factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`);
163
- }
164
- else {
165
- ret.push(` entity${entityKey} = factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`);
166
- }
167
- }
168
- else {
169
- // For regular: fixed target class, PK is the data itself
170
- const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
171
- context.set(targetKey, prop.targetMeta.class);
172
- if (prop.ref) {
173
- ret.push(` entity${entityKey} = Reference.create(factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`);
174
- }
175
- else {
176
- ret.push(` entity${entityKey} = factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`);
177
- }
178
- }
179
- ret.push(` } else if (data${dataKey} && typeof data${dataKey} === 'object') {`);
180
- // For full entity hydration, polymorphic needs to determine target class from entity itself
181
- let hydrateTargetExpr;
182
- if (prop.polymorphic) {
183
- hydrateTargetExpr = `data${dataKey}.constructor`;
184
- }
185
- else {
186
- const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
187
- context.set(targetKey, prop.targetMeta.class);
188
- hydrateTargetExpr = targetKey;
189
- }
190
- if (prop.ref) {
191
- ret.push(` entity${entityKey} = Reference.create(factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema }));`);
192
- }
193
- else {
194
- ret.push(` entity${entityKey} = factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema });`);
195
- }
196
- ret.push(` }`);
197
- ret.push(` }`);
198
- if (prop.kind === ReferenceKind.ONE_TO_ONE) {
199
- const meta2 = this.metadata.get(prop.targetMeta.class);
200
- const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
201
- if (prop2 && !prop2.mapToPk) {
202
- ret.push(` if (data${dataKey} && entity${entityKey} && !entity${entityKey}.${this.safeKey(prop2.name)}) {`);
203
- ret.push(` entity${entityKey}.${prop.ref ? 'unwrap().' : ''}${this.safeKey(prop2.name)} = ${prop2.ref ? 'Reference.create(entity)' : 'entity'};`);
204
- ret.push(` }`);
205
- }
206
- }
207
- if (prop.customType?.ensureComparable(meta, prop)) {
208
- registerCustomType(prop, this.safeKey(prop.name), 'convertToDatabaseValue', context);
209
- ret.push(` if (data${dataKey} != null && typeof data${dataKey} !== 'object' && convertCustomTypes) {`);
210
- ret.push(` data${dataKey} = convertToDatabaseValue_${this.safeKey(prop.name)}(entity${entityKey}.__helper.getPrimaryKey());`);
211
- ret.push(` }`);
212
- }
213
- return ret;
214
- };
215
- const hydrateToMany = (prop, dataKey, entityKey) => {
216
- const ret = [];
217
- ret.push(...this.createCollectionItemMapper(prop, context));
218
- ret.push(` if (data${dataKey} && !Array.isArray(data${dataKey}) && typeof data${dataKey} === 'object') {`);
219
- ret.push(` data${dataKey} = [data${dataKey}];`);
220
- ret.push(` }`);
221
- ret.push(` if (Array.isArray(data${dataKey})) {`);
222
- ret.push(` const items = data${dataKey}.map(value => createCollectionItem_${this.safeKey(prop.name)}(value, entity));`);
223
- ret.push(` const coll = Collection.create(entity, '${prop.name}', items, newEntity);`);
224
- ret.push(` if (newEntity) {`);
225
- ret.push(` coll.setDirty();`);
226
- ret.push(` } else {`);
227
- ret.push(` coll.takeSnapshot(true);`);
228
- ret.push(` }`);
229
- ret.push(` } else if (!entity${entityKey} && data${dataKey} instanceof Collection) {`);
230
- ret.push(` entity${entityKey} = data${dataKey};`);
231
- if (!this.platform.usesPivotTable() && prop.owner && prop.kind === ReferenceKind.MANY_TO_MANY) {
232
- ret.push(` } else if (!entity${entityKey} && Array.isArray(data${dataKey})) {`);
233
- const items = this.platform.usesPivotTable() || !prop.owner ? 'undefined' : '[]';
234
- ret.push(` const coll = Collection.create(entity, '${prop.name}', ${items}, !!data${dataKey} || newEntity);`);
235
- ret.push(` coll.setDirty(false);`);
236
- }
237
- ret.push(` } else if (!entity${entityKey}) {`);
238
- ret.push(` const coll = Collection.create(entity, '${prop.name}', undefined, newEntity);`);
239
- ret.push(` coll.setDirty(false);`);
240
- ret.push(` }`);
241
- return ret;
242
- };
243
- const registerEmbeddedPrototype = (prop, path) => {
244
- const convertorKey = path
245
- .filter(k => !/\[idx_\d+]/.exec(k))
246
- .map(k => this.safeKey(k))
247
- .join('_');
248
- if (prop.targetMeta?.polymorphs) {
249
- prop.targetMeta.polymorphs.forEach(meta => {
250
- context.set(`prototype_${convertorKey}_${meta.className}`, meta.prototype);
251
- });
252
- }
253
- else {
254
- context.set(`prototype_${convertorKey}`, prop.embeddable.prototype);
255
- }
256
- };
257
- const parseObjectEmbeddable = (prop, dataKey, ret) => {
258
- if (!this.platform.convertsJsonAutomatically() && (prop.object || prop.array)) {
259
- context.set('parseJsonSafe', parseJsonSafe);
260
- ret.push(` if (typeof data${dataKey} === 'string') {`, ` data${dataKey} = parseJsonSafe(data${dataKey});`, ` }`);
261
- }
262
- };
263
- const createCond = (prop, dataKey, cond) => {
264
- const conds = [];
265
- if (prop.object) {
266
- conds.push(`data${dataKey} ${cond ?? '!= null'}`);
267
- }
268
- else {
269
- const notNull = cond ?? (prop.nullable ? '!= null' : '!== undefined');
270
- meta.props
271
- .filter(p => p.embedded?.[0] === prop.name)
272
- .forEach(p => {
273
- if (p.kind === ReferenceKind.EMBEDDED && !p.object && !p.array) {
274
- conds.push(...createCond(p, dataKey + this.wrap(p.embedded[1]), cond));
275
- return;
276
- }
277
- conds.push(`data${this.wrap(p.name)} ${notNull}`);
278
- });
279
- }
280
- return conds;
281
- };
282
- const hydrateEmbedded = (prop, path, dataKey) => {
283
- const entityKey = path.map(k => this.wrap(k)).join('');
284
- const ret = [];
285
- registerEmbeddedPrototype(prop, path);
286
- parseObjectEmbeddable(prop, dataKey, ret);
287
- ret.push(` if (${createCond(prop, dataKey).join(' || ')}) {`);
288
- if (prop.object) {
289
- ret.push(` const embeddedData = data${dataKey};`);
290
- }
291
- else {
292
- ret.push(` const embeddedData = {`);
293
- for (const childProp of Object.values(prop.embeddedProps)) {
294
- const key = /^\w+$/.exec(childProp.embedded[1]) ? childProp.embedded[1] : `'${childProp.embedded[1]}'`;
295
- ret.push(` ${key}: data${this.wrap(childProp.name)},`);
296
- }
297
- ret.push(` };`);
298
- }
299
- if (prop.targetMeta?.polymorphs) {
300
- prop.targetMeta.polymorphs.forEach(childMeta => {
301
- const childProp = prop.embeddedProps[prop.targetMeta.discriminatorColumn];
302
- const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
303
- context.set(childMeta.className, childMeta.class);
304
- // weak comparison as we can have numbers that might have been converted to strings due to being object keys
305
- ret.push(` if (data${childDataKey} == '${childMeta.discriminatorValue}') {`);
306
- ret.push(` if (entity${entityKey} == null) {`);
307
- ret.push(` entity${entityKey} = factory.createEmbeddable(${childMeta.className}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`);
308
- ret.push(` }`);
309
- meta.props
310
- .filter(p => p.embedded?.[0] === prop.name)
311
- .forEach(childProp => {
312
- const childDataKey = prop.object
313
- ? dataKey + this.wrap(childProp.embedded[1])
314
- : this.wrap(childProp.name);
315
- const prop2 = childMeta.properties[childProp.embedded[1]];
316
- const prop3 = {
317
- ...prop2,
318
- name: childProp.name,
319
- embedded: childProp.embedded,
320
- embeddedProps: childProp.embeddedProps,
321
- };
322
- ret.push(
323
- // eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
324
- ...hydrateProperty(prop3, childProp.object, [...path, childProp.embedded[1]], childDataKey).map(l => ' ' + l));
325
- });
326
- ret.push(` }`);
327
- });
328
- }
329
- else {
330
- const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
331
- context.set(targetKey, prop.targetMeta.class);
332
- ret.push(` if (entity${entityKey} == null) {`);
333
- ret.push(` entity${entityKey} = factory.createEmbeddable(${targetKey}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`);
334
- ret.push(` }`);
335
- meta.props
336
- .filter(p => p.embedded?.[0] === prop.name)
337
- .forEach(childProp => {
338
- const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
339
- ret.push(
340
- // eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
341
- ...hydrateProperty(childProp, prop.object, [...path, childProp.embedded[1]], childDataKey).map(l => ' ' + l));
342
- });
343
- }
344
- /* v8 ignore next */
345
- const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
346
- if (prop.object) {
347
- ret.push(` } else if (data${dataKey} === null) {`);
348
- }
349
- else {
350
- ret.push(` } else if (${createCond(prop, dataKey, '=== null').join(' && ')}) {`);
351
- }
352
- ret.push(` entity${entityKey} = ${nullVal};`);
353
- ret.push(` }`);
354
- return ret;
355
- };
356
- const hydrateEmbeddedArray = (prop, path, dataKey) => {
357
- const entityKey = path.map(k => this.wrap(k)).join('');
358
- const ret = [];
359
- const idx = this.#tmpIndex++;
360
- registerEmbeddedPrototype(prop, path);
361
- parseObjectEmbeddable(prop, dataKey, ret);
362
- ret.push(` if (Array.isArray(data${dataKey})) {`);
363
- ret.push(` entity${entityKey} = [];`);
364
- ret.push(` data${dataKey}.forEach((_, idx_${idx}) => {`);
365
- ret.push(...hydrateEmbedded(prop, [...path, `[idx_${idx}]`], `${dataKey}[idx_${idx}]`).map(l => ' ' + l));
366
- ret.push(` });`);
367
- ret.push(` }`);
368
- return ret;
369
- };
370
- const hydrateProperty = (prop, object = prop.object, path = [prop.name], dataKey) => {
371
- const entityKey = path.map(k => this.wrap(k)).join('');
372
- dataKey =
373
- dataKey ?? (object ? entityKey : this.wrap(normalizeAccessors ? (prop.accessor ?? prop.name) : prop.name));
374
- const ret = [];
375
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.mapToPk) {
376
- ret.push(...hydrateToOne(prop, dataKey, entityKey));
377
- }
378
- else if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
379
- ret.push(...hydrateToMany(prop, dataKey, entityKey));
380
- }
381
- else if (prop.kind === ReferenceKind.EMBEDDED) {
382
- if (prop.array) {
383
- ret.push(...hydrateEmbeddedArray(prop, path, dataKey));
384
- }
385
- else {
386
- ret.push(...hydrateEmbedded(prop, path, dataKey));
387
- if (!prop.object) {
388
- ret.push(...hydrateEmbedded({ ...prop, object: true }, path, dataKey));
389
- }
390
- }
391
- }
392
- else {
393
- // ReferenceKind.SCALAR
394
- ret.push(...hydrateScalar(prop, path, dataKey));
395
- }
396
- if (this.config.get('forceUndefined')) {
397
- ret.push(` if (data${dataKey} === null) entity${entityKey} = undefined;`);
398
- }
399
- return ret;
400
- };
401
- for (const prop of props) {
402
- lines.push(...hydrateProperty(prop));
97
+ return prop.customType[method](val, this.platform, { mode: 'serialization' });
98
+ });
99
+ return convertorKey;
100
+ };
101
+ const hydrateScalar = (prop, path, dataKey) => {
102
+ const entityKey = path.map(k => this.wrap(k)).join('');
103
+ const tz = this.platform.getTimezone();
104
+ const convertorKey = path
105
+ .filter(k => !/\[idx_\d+]/.exec(k))
106
+ .map(k => this.safeKey(k))
107
+ .join('_');
108
+ const ret = [];
109
+ const idx = this.#tmpIndex++;
110
+ const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
111
+ if (prop.getter && !prop.setter && prop.persist === false) {
112
+ return [];
113
+ }
114
+ if (prop.ref) {
115
+ context.set('ScalarReference', ScalarReference);
116
+ ret.push(` const oldValue_${idx} = entity${entityKey};`);
117
+ }
118
+ ret.push(` if (data${dataKey} === null) {`);
119
+ if (prop.ref) {
120
+ ret.push(` entity${entityKey} = new ScalarReference();`);
121
+ ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
122
+ ret.push(` entity${entityKey}.set(${nullVal});`);
123
+ } else {
124
+ ret.push(` entity${entityKey} = ${nullVal};`);
125
+ }
126
+ ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
127
+ if (prop.customType) {
128
+ registerCustomType(prop, convertorKey, 'convertToJSValue', context);
129
+ registerCustomType(prop, convertorKey, 'convertToDatabaseValue', context);
130
+ ret.push(
131
+ ` if (convertCustomTypes) {`,
132
+ ` const value = convertToJSValue_${convertorKey}(data${dataKey});`,
133
+ );
134
+ if (prop.customType.ensureComparable(meta, prop)) {
135
+ ret.push(` data${dataKey} = convertToDatabaseValue_${convertorKey}(value);`);
403
136
  }
404
- const code = `// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n` +
405
- `return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n` +
406
- `${lines.join('\n')}\n}`;
407
- const fnKey = `hydrator-${meta.uniqueName}-${type}-${normalizeAccessors}`;
408
- const hydrator = Utils.createFunction(context, code, this.config.get('compiledFunctions'), fnKey);
409
- this.#hydrators[key].set(meta.class, hydrator);
410
- return hydrator;
411
- }
412
- createCollectionItemMapper(prop, context) {
413
- const meta = this.metadata.get(prop.targetMeta.class);
414
- const lines = [];
415
- lines.push(` const createCollectionItem_${this.safeKey(prop.name)} = (value, entity) => {`);
416
- const prop2 = prop.targetMeta.properties[prop.mappedBy];
417
- if (prop.kind === ReferenceKind.ONE_TO_MANY && prop2.primary) {
418
- lines.push(` if (typeof value === 'object' && value?.['${prop2.name}'] == null) {`);
419
- lines.push(` value = { ...value, ['${prop2.name}']: Reference.wrapReference(entity, { ref: ${prop2.ref} }) };`);
420
- lines.push(` }`);
137
+ ret.push(
138
+ ` entity${entityKey} = value;`,
139
+ ` } else {`,
140
+ ` entity${entityKey} = data${dataKey};`,
141
+ ` }`,
142
+ );
143
+ } else if (prop.runtimeType === 'boolean') {
144
+ ret.push(` entity${entityKey} = !!data${dataKey};`);
145
+ } else if (prop.runtimeType === 'Date' && !this.platform.isNumericProperty(prop)) {
146
+ ret.push(` if (data${dataKey} instanceof Date) {`);
147
+ ret.push(` entity${entityKey} = data${dataKey};`);
148
+ if (!tz || tz === 'local') {
149
+ ret.push(` } else {`);
150
+ ret.push(` entity${entityKey} = new Date(data${dataKey});`);
151
+ } else {
152
+ ret.push(
153
+ ` } else if (typeof data${dataKey} === 'number' || data${dataKey}.includes('+') || data${dataKey}.lastIndexOf('-') > 10 || data${dataKey}.endsWith('Z')) {`,
154
+ );
155
+ ret.push(` entity${entityKey} = new Date(data${dataKey});`);
156
+ ret.push(` } else {`);
157
+ ret.push(` entity${entityKey} = new Date(data${dataKey} + '${tz}');`);
158
+ }
159
+ ret.push(` }`);
160
+ } else {
161
+ ret.push(` entity${entityKey} = data${dataKey};`);
162
+ }
163
+ if (prop.ref) {
164
+ ret.push(
165
+ ` const value = isScalarReference(entity${entityKey}) ? entity${entityKey}.unwrap() : entity${entityKey};`,
166
+ );
167
+ ret.push(` entity${entityKey} = oldValue_${idx} ?? new ScalarReference(value);`);
168
+ ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
169
+ ret.push(` entity${entityKey}.set(value);`);
170
+ }
171
+ ret.push(` }`);
172
+ if (prop.ref) {
173
+ ret.push(` if (!entity${entityKey}) {`);
174
+ ret.push(` entity${entityKey} = new ScalarReference();`);
175
+ ret.push(` entity${entityKey}.bind(entity, '${prop.name}');`);
176
+ ret.push(` }`);
177
+ }
178
+ return ret;
179
+ };
180
+ const hydrateToOne = (prop, dataKey, entityKey) => {
181
+ const ret = [];
182
+ const method = type === 'reference' ? 'createReference' : 'create';
183
+ const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
184
+ ret.push(` if (data${dataKey} === null) {\n entity${entityKey} = ${nullVal};`);
185
+ ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
186
+ // For polymorphic: instanceof check; for regular: isPrimaryKey() check
187
+ const pkCheck = prop.polymorphic
188
+ ? `data${dataKey} instanceof PolymorphicRef`
189
+ : `isPrimaryKey(data${dataKey}, true)`;
190
+ ret.push(` if (${pkCheck}) {`);
191
+ // When targetKey is set, pass the key option to createReference so it uses the alternate key
192
+ const keyOption = prop.targetKey ? `, key: '${prop.targetKey}'` : '';
193
+ if (prop.polymorphic) {
194
+ // For polymorphic: target class from discriminator map, PK from data.id
195
+ const discriminatorMapKey = this.safeKey(`discriminatorMap_${prop.name}_${this.#tmpIndex++}`);
196
+ context.set(discriminatorMapKey, prop.discriminatorMap);
197
+ ret.push(` const targetClass = ${discriminatorMapKey}[data${dataKey}.discriminator];`);
198
+ ret.push(
199
+ ` if (!targetClass) throw new ValidationError(\`Unknown discriminator value '\${data${dataKey}.discriminator}' for polymorphic relation '${prop.name}'. Valid values: \${Object.keys(${discriminatorMapKey}).join(', ')}\`);`,
200
+ );
201
+ if (prop.ref) {
202
+ ret.push(
203
+ ` entity${entityKey} = Reference.create(factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`,
204
+ );
205
+ } else {
206
+ ret.push(
207
+ ` entity${entityKey} = factory.createReference(targetClass, data${dataKey}.id, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`,
208
+ );
421
209
  }
210
+ } else {
211
+ // For regular: fixed target class, PK is the data itself
422
212
  const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
423
213
  context.set(targetKey, prop.targetMeta.class);
424
- lines.push(` if (isPrimaryKey(value, ${meta.compositePK})) return factory.createReference(${targetKey}, value, { convertCustomTypes, schema, normalizeAccessors, merge: true });`);
425
- lines.push(` if (value && isEntity(value)) return value;`);
426
- lines.push(` return factory.create(${targetKey}, value, { newEntity, convertCustomTypes, schema, normalizeAccessors, merge: true });`);
427
- lines.push(` }`);
428
- return lines;
429
- }
430
- wrap(key) {
431
- if (/^\[.*]$/.exec(key)) {
432
- return key;
214
+ if (prop.ref) {
215
+ ret.push(
216
+ ` entity${entityKey} = Reference.create(factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} }));`,
217
+ );
218
+ } else {
219
+ ret.push(
220
+ ` entity${entityKey} = factory.createReference(${targetKey}, data${dataKey}, { merge: true, convertCustomTypes, normalizeAccessors, schema${keyOption} });`,
221
+ );
222
+ }
223
+ }
224
+ ret.push(` } else if (data${dataKey} && typeof data${dataKey} === 'object') {`);
225
+ // For full entity hydration, polymorphic needs to determine target class from entity itself
226
+ let hydrateTargetExpr;
227
+ if (prop.polymorphic) {
228
+ hydrateTargetExpr = `data${dataKey}.constructor`;
229
+ } else {
230
+ const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
231
+ context.set(targetKey, prop.targetMeta.class);
232
+ hydrateTargetExpr = targetKey;
233
+ }
234
+ if (prop.ref) {
235
+ ret.push(
236
+ ` entity${entityKey} = Reference.create(factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema }));`,
237
+ );
238
+ } else {
239
+ ret.push(
240
+ ` entity${entityKey} = factory.${method}(${hydrateTargetExpr}, data${dataKey}, { initialized: true, merge: true, newEntity, convertCustomTypes, normalizeAccessors, schema });`,
241
+ );
242
+ }
243
+ ret.push(` }`);
244
+ ret.push(` }`);
245
+ if (prop.kind === ReferenceKind.ONE_TO_ONE) {
246
+ const meta2 = this.metadata.get(prop.targetMeta.class);
247
+ const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
248
+ if (prop2 && !prop2.mapToPk) {
249
+ ret.push(` if (data${dataKey} && entity${entityKey} && !entity${entityKey}.${this.safeKey(prop2.name)}) {`);
250
+ ret.push(
251
+ ` entity${entityKey}.${prop.ref ? 'unwrap().' : ''}${this.safeKey(prop2.name)} = ${prop2.ref ? 'Reference.create(entity)' : 'entity'};`,
252
+ );
253
+ ret.push(` }`);
254
+ }
255
+ }
256
+ if (prop.customType?.ensureComparable(meta, prop)) {
257
+ registerCustomType(prop, this.safeKey(prop.name), 'convertToDatabaseValue', context);
258
+ ret.push(` if (data${dataKey} != null && typeof data${dataKey} !== 'object' && convertCustomTypes) {`);
259
+ ret.push(
260
+ ` data${dataKey} = convertToDatabaseValue_${this.safeKey(prop.name)}(entity${entityKey}.__helper.getPrimaryKey());`,
261
+ );
262
+ ret.push(` }`);
263
+ }
264
+ return ret;
265
+ };
266
+ const hydrateToMany = (prop, dataKey, entityKey) => {
267
+ const ret = [];
268
+ ret.push(...this.createCollectionItemMapper(prop, context));
269
+ ret.push(` if (data${dataKey} && !Array.isArray(data${dataKey}) && typeof data${dataKey} === 'object') {`);
270
+ ret.push(` data${dataKey} = [data${dataKey}];`);
271
+ ret.push(` }`);
272
+ ret.push(` if (Array.isArray(data${dataKey})) {`);
273
+ ret.push(
274
+ ` const items = data${dataKey}.map(value => createCollectionItem_${this.safeKey(prop.name)}(value, entity));`,
275
+ );
276
+ ret.push(` const coll = Collection.create(entity, '${prop.name}', items, newEntity);`);
277
+ ret.push(` if (newEntity) {`);
278
+ ret.push(` coll.setDirty();`);
279
+ ret.push(` } else {`);
280
+ ret.push(` coll.takeSnapshot(true);`);
281
+ ret.push(` }`);
282
+ ret.push(` } else if (!entity${entityKey} && data${dataKey} instanceof Collection) {`);
283
+ ret.push(` entity${entityKey} = data${dataKey};`);
284
+ if (!this.platform.usesPivotTable() && prop.owner && prop.kind === ReferenceKind.MANY_TO_MANY) {
285
+ ret.push(` } else if (!entity${entityKey} && Array.isArray(data${dataKey})) {`);
286
+ const items = this.platform.usesPivotTable() || !prop.owner ? 'undefined' : '[]';
287
+ ret.push(
288
+ ` const coll = Collection.create(entity, '${prop.name}', ${items}, !!data${dataKey} || newEntity);`,
289
+ );
290
+ ret.push(` coll.setDirty(false);`);
291
+ }
292
+ ret.push(` } else if (!entity${entityKey}) {`);
293
+ ret.push(` const coll = Collection.create(entity, '${prop.name}', undefined, newEntity);`);
294
+ ret.push(` coll.setDirty(false);`);
295
+ ret.push(` }`);
296
+ return ret;
297
+ };
298
+ const registerEmbeddedPrototype = (prop, path) => {
299
+ const convertorKey = path
300
+ .filter(k => !/\[idx_\d+]/.exec(k))
301
+ .map(k => this.safeKey(k))
302
+ .join('_');
303
+ if (prop.targetMeta?.polymorphs) {
304
+ prop.targetMeta.polymorphs.forEach(meta => {
305
+ context.set(`prototype_${convertorKey}_${meta.className}`, meta.prototype);
306
+ });
307
+ } else {
308
+ context.set(`prototype_${convertorKey}`, prop.embeddable.prototype);
309
+ }
310
+ };
311
+ const parseObjectEmbeddable = (prop, dataKey, ret) => {
312
+ if (!this.platform.convertsJsonAutomatically() && (prop.object || prop.array)) {
313
+ context.set('parseJsonSafe', parseJsonSafe);
314
+ ret.push(
315
+ ` if (typeof data${dataKey} === 'string') {`,
316
+ ` data${dataKey} = parseJsonSafe(data${dataKey});`,
317
+ ` }`,
318
+ );
319
+ }
320
+ };
321
+ const createCond = (prop, dataKey, cond) => {
322
+ const conds = [];
323
+ if (prop.object) {
324
+ conds.push(`data${dataKey} ${cond ?? '!= null'}`);
325
+ } else {
326
+ const notNull = cond ?? (prop.nullable ? '!= null' : '!== undefined');
327
+ meta.props
328
+ .filter(p => p.embedded?.[0] === prop.name)
329
+ .forEach(p => {
330
+ if (p.kind === ReferenceKind.EMBEDDED && !p.object && !p.array) {
331
+ conds.push(...createCond(p, dataKey + this.wrap(p.embedded[1]), cond));
332
+ return;
333
+ }
334
+ conds.push(`data${this.wrap(p.name)} ${notNull}`);
335
+ });
336
+ }
337
+ return conds;
338
+ };
339
+ const hydrateEmbedded = (prop, path, dataKey) => {
340
+ const entityKey = path.map(k => this.wrap(k)).join('');
341
+ const ret = [];
342
+ registerEmbeddedPrototype(prop, path);
343
+ parseObjectEmbeddable(prop, dataKey, ret);
344
+ ret.push(` if (${createCond(prop, dataKey).join(' || ')}) {`);
345
+ if (prop.object) {
346
+ ret.push(` const embeddedData = data${dataKey};`);
347
+ } else {
348
+ ret.push(` const embeddedData = {`);
349
+ for (const childProp of Object.values(prop.embeddedProps)) {
350
+ const key = /^\w+$/.exec(childProp.embedded[1]) ? childProp.embedded[1] : `'${childProp.embedded[1]}'`;
351
+ ret.push(` ${key}: data${this.wrap(childProp.name)},`);
433
352
  }
434
- return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
353
+ ret.push(` };`);
354
+ }
355
+ if (prop.targetMeta?.polymorphs) {
356
+ prop.targetMeta.polymorphs.forEach(childMeta => {
357
+ const childProp = prop.embeddedProps[prop.targetMeta.discriminatorColumn];
358
+ const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
359
+ context.set(childMeta.className, childMeta.class);
360
+ // weak comparison as we can have numbers that might have been converted to strings due to being object keys
361
+ ret.push(` if (data${childDataKey} == '${childMeta.discriminatorValue}') {`);
362
+ ret.push(` if (entity${entityKey} == null) {`);
363
+ ret.push(
364
+ ` entity${entityKey} = factory.createEmbeddable(${childMeta.className}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`,
365
+ );
366
+ ret.push(` }`);
367
+ meta.props
368
+ .filter(p => p.embedded?.[0] === prop.name)
369
+ .forEach(childProp => {
370
+ const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
371
+ const prop2 = childMeta.properties[childProp.embedded[1]];
372
+ const prop3 = {
373
+ ...prop2,
374
+ name: childProp.name,
375
+ embedded: childProp.embedded,
376
+ embeddedProps: childProp.embeddedProps,
377
+ };
378
+ ret.push(
379
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
380
+ ...hydrateProperty(prop3, childProp.object, [...path, childProp.embedded[1]], childDataKey).map(
381
+ l => ' ' + l,
382
+ ),
383
+ );
384
+ });
385
+ ret.push(` }`);
386
+ });
387
+ } else {
388
+ const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
389
+ context.set(targetKey, prop.targetMeta.class);
390
+ ret.push(` if (entity${entityKey} == null) {`);
391
+ ret.push(
392
+ ` entity${entityKey} = factory.createEmbeddable(${targetKey}, embeddedData, { newEntity, convertCustomTypes, normalizeAccessors });`,
393
+ );
394
+ ret.push(` }`);
395
+ meta.props
396
+ .filter(p => p.embedded?.[0] === prop.name)
397
+ .forEach(childProp => {
398
+ const childDataKey = prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
399
+ ret.push(
400
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define, no-use-before-define
401
+ ...hydrateProperty(childProp, prop.object, [...path, childProp.embedded[1]], childDataKey).map(
402
+ l => ' ' + l,
403
+ ),
404
+ );
405
+ });
406
+ }
407
+ /* v8 ignore next */
408
+ const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
409
+ if (prop.object) {
410
+ ret.push(` } else if (data${dataKey} === null) {`);
411
+ } else {
412
+ ret.push(` } else if (${createCond(prop, dataKey, '=== null').join(' && ')}) {`);
413
+ }
414
+ ret.push(` entity${entityKey} = ${nullVal};`);
415
+ ret.push(` }`);
416
+ return ret;
417
+ };
418
+ const hydrateEmbeddedArray = (prop, path, dataKey) => {
419
+ const entityKey = path.map(k => this.wrap(k)).join('');
420
+ const ret = [];
421
+ const idx = this.#tmpIndex++;
422
+ registerEmbeddedPrototype(prop, path);
423
+ parseObjectEmbeddable(prop, dataKey, ret);
424
+ ret.push(` if (Array.isArray(data${dataKey})) {`);
425
+ ret.push(` entity${entityKey} = [];`);
426
+ ret.push(` data${dataKey}.forEach((_, idx_${idx}) => {`);
427
+ ret.push(...hydrateEmbedded(prop, [...path, `[idx_${idx}]`], `${dataKey}[idx_${idx}]`).map(l => ' ' + l));
428
+ ret.push(` });`);
429
+ ret.push(` }`);
430
+ return ret;
431
+ };
432
+ const hydrateProperty = (prop, object = prop.object, path = [prop.name], dataKey) => {
433
+ const entityKey = path.map(k => this.wrap(k)).join('');
434
+ dataKey =
435
+ dataKey ?? (object ? entityKey : this.wrap(normalizeAccessors ? (prop.accessor ?? prop.name) : prop.name));
436
+ const ret = [];
437
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.mapToPk) {
438
+ ret.push(...hydrateToOne(prop, dataKey, entityKey));
439
+ } else if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
440
+ ret.push(...hydrateToMany(prop, dataKey, entityKey));
441
+ } else if (prop.kind === ReferenceKind.EMBEDDED) {
442
+ if (prop.array) {
443
+ ret.push(...hydrateEmbeddedArray(prop, path, dataKey));
444
+ } else {
445
+ ret.push(...hydrateEmbedded(prop, path, dataKey));
446
+ if (!prop.object) {
447
+ ret.push(...hydrateEmbedded({ ...prop, object: true }, path, dataKey));
448
+ }
449
+ }
450
+ } else {
451
+ // ReferenceKind.SCALAR
452
+ ret.push(...hydrateScalar(prop, path, dataKey));
453
+ }
454
+ if (this.config.get('forceUndefined')) {
455
+ ret.push(` if (data${dataKey} === null) entity${entityKey} = undefined;`);
456
+ }
457
+ return ret;
458
+ };
459
+ for (const prop of props) {
460
+ lines.push(...hydrateProperty(prop));
461
+ }
462
+ const code =
463
+ `// compiled hydrator for entity ${meta.className} (${type + normalizeAccessors ? ' normalized' : ''})\n` +
464
+ `return function(entity, data, factory, newEntity, convertCustomTypes, schema, parentSchema, normalizeAccessors) {\n` +
465
+ `${lines.join('\n')}\n}`;
466
+ const fnKey = `hydrator-${meta.uniqueName}-${type}-${normalizeAccessors}`;
467
+ const hydrator = Utils.createFunction(context, code, this.config.get('compiledFunctions'), fnKey);
468
+ this.#hydrators[key].set(meta.class, hydrator);
469
+ return hydrator;
470
+ }
471
+ createCollectionItemMapper(prop, context) {
472
+ const meta = this.metadata.get(prop.targetMeta.class);
473
+ const lines = [];
474
+ lines.push(` const createCollectionItem_${this.safeKey(prop.name)} = (value, entity) => {`);
475
+ const prop2 = prop.targetMeta.properties[prop.mappedBy];
476
+ if (prop.kind === ReferenceKind.ONE_TO_MANY && prop2.primary) {
477
+ lines.push(` if (typeof value === 'object' && value?.['${prop2.name}'] == null) {`);
478
+ lines.push(
479
+ ` value = { ...value, ['${prop2.name}']: Reference.wrapReference(entity, { ref: ${prop2.ref} }) };`,
480
+ );
481
+ lines.push(` }`);
435
482
  }
436
- safeKey(key) {
437
- return key.replace(/\W/g, '_');
483
+ const targetKey = this.safeKey(`${prop.targetMeta.tableName}_${this.#tmpIndex++}`);
484
+ context.set(targetKey, prop.targetMeta.class);
485
+ lines.push(
486
+ ` if (isPrimaryKey(value, ${meta.compositePK})) return factory.createReference(${targetKey}, value, { convertCustomTypes, schema, normalizeAccessors, merge: true });`,
487
+ );
488
+ lines.push(` if (value && isEntity(value)) return value;`);
489
+ lines.push(
490
+ ` return factory.create(${targetKey}, value, { newEntity, convertCustomTypes, schema, normalizeAccessors, merge: true });`,
491
+ );
492
+ lines.push(` }`);
493
+ return lines;
494
+ }
495
+ wrap(key) {
496
+ if (/^\[.*]$/.exec(key)) {
497
+ return key;
438
498
  }
499
+ return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
500
+ }
501
+ safeKey(key) {
502
+ return key.replace(/\W/g, '_');
503
+ }
439
504
  }