@mikro-orm/core 7.0.4 → 7.0.5-dev.1

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 +583 -884
  2. package/EntityManager.js +1895 -1922
  3. package/MikroORM.d.ts +74 -103
  4. package/MikroORM.js +179 -178
  5. package/README.md +1 -1
  6. package/cache/CacheAdapter.d.ts +36 -36
  7. package/cache/FileCacheAdapter.d.ts +24 -30
  8. package/cache/FileCacheAdapter.js +78 -80
  9. package/cache/GeneratedCacheAdapter.d.ts +20 -18
  10. package/cache/GeneratedCacheAdapter.js +30 -30
  11. package/cache/MemoryCacheAdapter.d.ts +20 -18
  12. package/cache/MemoryCacheAdapter.js +36 -35
  13. package/cache/NullCacheAdapter.d.ts +16 -16
  14. package/cache/NullCacheAdapter.js +24 -24
  15. package/connections/Connection.d.ts +84 -95
  16. package/connections/Connection.js +168 -165
  17. package/drivers/DatabaseDriver.d.ts +80 -186
  18. package/drivers/DatabaseDriver.js +443 -450
  19. package/drivers/IDatabaseDriver.d.ts +301 -440
  20. package/entity/BaseEntity.d.ts +83 -120
  21. package/entity/BaseEntity.js +43 -43
  22. package/entity/Collection.d.ts +179 -212
  23. package/entity/Collection.js +721 -727
  24. package/entity/EntityAssigner.d.ts +77 -88
  25. package/entity/EntityAssigner.js +230 -231
  26. package/entity/EntityFactory.d.ts +54 -66
  27. package/entity/EntityFactory.js +383 -425
  28. package/entity/EntityHelper.d.ts +22 -34
  29. package/entity/EntityHelper.js +267 -280
  30. package/entity/EntityIdentifier.d.ts +4 -4
  31. package/entity/EntityIdentifier.js +10 -10
  32. package/entity/EntityLoader.d.ts +72 -98
  33. package/entity/EntityLoader.js +723 -753
  34. package/entity/EntityRepository.d.ts +201 -316
  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 +82 -126
  39. package/entity/Reference.js +274 -278
  40. package/entity/WrappedEntity.d.ts +72 -115
  41. package/entity/WrappedEntity.js +166 -168
  42. package/entity/defineEntity.d.ts +636 -1315
  43. package/entity/defineEntity.js +518 -527
  44. package/entity/utils.d.ts +3 -13
  45. package/entity/utils.js +73 -71
  46. package/entity/validators.js +43 -43
  47. package/entity/wrap.js +8 -8
  48. package/enums.d.ts +253 -258
  49. package/enums.js +252 -251
  50. package/errors.d.ts +72 -114
  51. package/errors.js +253 -350
  52. package/events/EventManager.d.ts +14 -26
  53. package/events/EventManager.js +77 -79
  54. package/events/EventSubscriber.d.ts +29 -29
  55. package/events/TransactionEventBroadcaster.d.ts +8 -15
  56. package/events/TransactionEventBroadcaster.js +14 -14
  57. package/exceptions.d.ts +40 -23
  58. package/exceptions.js +52 -35
  59. package/hydration/Hydrator.d.ts +17 -42
  60. package/hydration/Hydrator.js +43 -43
  61. package/hydration/ObjectHydrator.d.ts +17 -50
  62. package/hydration/ObjectHydrator.js +416 -481
  63. package/index.d.ts +2 -116
  64. package/index.js +1 -10
  65. package/logging/DefaultLogger.d.ts +32 -34
  66. package/logging/DefaultLogger.js +86 -86
  67. package/logging/Logger.d.ts +41 -41
  68. package/logging/SimpleLogger.d.ts +11 -13
  69. package/logging/SimpleLogger.js +22 -22
  70. package/logging/colors.d.ts +6 -6
  71. package/logging/colors.js +10 -11
  72. package/logging/inspect.js +7 -7
  73. package/metadata/EntitySchema.d.ts +127 -211
  74. package/metadata/EntitySchema.js +398 -397
  75. package/metadata/MetadataDiscovery.d.ts +114 -114
  76. package/metadata/MetadataDiscovery.js +1870 -1951
  77. package/metadata/MetadataProvider.d.ts +21 -24
  78. package/metadata/MetadataProvider.js +84 -82
  79. package/metadata/MetadataStorage.d.ts +32 -38
  80. package/metadata/MetadataStorage.js +118 -118
  81. package/metadata/MetadataValidator.d.ts +39 -39
  82. package/metadata/MetadataValidator.js +338 -381
  83. package/metadata/discover-entities.d.ts +2 -5
  84. package/metadata/discover-entities.js +37 -35
  85. package/metadata/types.d.ts +531 -615
  86. package/naming-strategy/AbstractNamingStrategy.d.ts +39 -54
  87. package/naming-strategy/AbstractNamingStrategy.js +85 -90
  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 +99 -109
  93. package/naming-strategy/UnderscoreNamingStrategy.d.ts +7 -7
  94. package/naming-strategy/UnderscoreNamingStrategy.js +21 -21
  95. package/not-supported.js +4 -7
  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 +301 -310
  100. package/platforms/Platform.js +640 -663
  101. package/serialization/EntitySerializer.d.ts +26 -49
  102. package/serialization/EntitySerializer.js +218 -224
  103. package/serialization/EntityTransformer.d.ts +6 -10
  104. package/serialization/EntityTransformer.js +217 -219
  105. package/serialization/SerializationContext.d.ts +23 -27
  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 +10 -17
  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 +79 -83
  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 +49 -75
  158. package/types/index.js +26 -52
  159. package/typings.d.ts +737 -1250
  160. package/typings.js +231 -244
  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 +170 -178
  165. package/unit-of-work/ChangeSetPersister.d.ts +44 -63
  166. package/unit-of-work/ChangeSetPersister.js +421 -442
  167. package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
  168. package/unit-of-work/CommitOrderCalculator.js +88 -89
  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 +141 -181
  172. package/unit-of-work/UnitOfWork.js +1183 -1200
  173. package/utils/AbstractMigrator.d.ts +91 -111
  174. package/utils/AbstractMigrator.js +275 -275
  175. package/utils/AbstractSchemaGenerator.d.ts +34 -43
  176. package/utils/AbstractSchemaGenerator.js +122 -121
  177. package/utils/AsyncContext.d.ts +3 -3
  178. package/utils/AsyncContext.js +35 -34
  179. package/utils/Configuration.d.ts +808 -852
  180. package/utils/Configuration.js +344 -359
  181. package/utils/Cursor.d.ts +22 -40
  182. package/utils/Cursor.js +127 -135
  183. package/utils/DataloaderUtils.d.ts +43 -58
  184. package/utils/DataloaderUtils.js +198 -203
  185. package/utils/EntityComparator.d.ts +81 -98
  186. package/utils/EntityComparator.js +732 -828
  187. package/utils/NullHighlighter.d.ts +1 -1
  188. package/utils/NullHighlighter.js +3 -3
  189. package/utils/QueryHelper.d.ts +51 -79
  190. package/utils/QueryHelper.js +361 -372
  191. package/utils/RawQueryFragment.d.ts +34 -50
  192. package/utils/RawQueryFragment.js +105 -107
  193. package/utils/RequestContext.d.ts +32 -32
  194. package/utils/RequestContext.js +53 -52
  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 +197 -199
  199. package/utils/Utils.d.ts +145 -204
  200. package/utils/Utils.js +812 -812
  201. package/utils/clone.js +113 -104
  202. package/utils/env-vars.js +88 -90
  203. package/utils/fs-utils.d.ts +15 -15
  204. package/utils/fs-utils.js +181 -180
  205. package/utils/upsert-utils.d.ts +5 -20
  206. package/utils/upsert-utils.js +116 -114
@@ -3,15 +3,15 @@ import { helper } from '../entity/wrap.js';
3
3
  import { Reference } from '../entity/Reference.js';
4
4
  import { Utils } from './Utils.js';
5
5
  export class DataloaderUtils {
6
- static DataLoader;
7
- /**
8
- * Groups identified references by entity and returns a Map with the
9
- * class name as the index and the corresponding primary keys as the value.
10
- */
11
- static groupPrimaryKeysByEntityAndOpts(refsWithOpts) {
12
- const map = new Map();
13
- for (const [ref, opts] of refsWithOpts) {
14
- /* The key is a combination of the uniqueName (a unique table name based identifier) and a stringified version if the load options because we want
6
+ static DataLoader;
7
+ /**
8
+ * Groups identified references by entity and returns a Map with the
9
+ * class name as the index and the corresponding primary keys as the value.
10
+ */
11
+ static groupPrimaryKeysByEntityAndOpts(refsWithOpts) {
12
+ const map = new Map();
13
+ for (const [ref, opts] of refsWithOpts) {
14
+ /* The key is a combination of the uniqueName (a unique table name based identifier) and a stringified version if the load options because we want
15
15
  to map each combination of entities/options into separate find queries in order to return accurate results.
16
16
  This could be further optimized finding the "lowest common denominator" among the different options
17
17
  for each Entity and firing a single query for each Entity instead of Entity+options combination.
@@ -24,215 +24,210 @@ export class DataloaderUtils {
24
24
  Thus such approach should probably be configurable, if not opt-in.
25
25
  NOTE: meta + opts multi maps (https://github.com/martian17/ds-js) might be a more elegant way
26
26
  to implement this but not necessarily faster. */
27
- const key = `${helper(ref).__meta.uniqueName}|${JSON.stringify(opts ?? {})}`;
28
- let primaryKeysSet = map.get(key);
29
- if (primaryKeysSet == null) {
30
- primaryKeysSet = new Set();
31
- map.set(key, primaryKeysSet);
32
- }
33
- primaryKeysSet.add(helper(ref).getPrimaryKey());
27
+ const key = `${helper(ref).__meta.uniqueName}|${JSON.stringify(opts ?? {})}`;
28
+ let primaryKeysSet = map.get(key);
29
+ if (primaryKeysSet == null) {
30
+ primaryKeysSet = new Set();
31
+ map.set(key, primaryKeysSet);
32
+ }
33
+ primaryKeysSet.add(helper(ref).getPrimaryKey());
34
+ }
35
+ return map;
34
36
  }
35
- return map;
36
- }
37
- /**
38
- * Returns the reference dataloader batchLoadFn, which aggregates references by entity,
39
- * makes one query per entity and maps each input reference to the corresponding result.
40
- */
41
- static getRefBatchLoadFn(em) {
42
- return async refsWithOpts => {
43
- const groupedIdsMap = DataloaderUtils.groupPrimaryKeysByEntityAndOpts(refsWithOpts);
44
- const promises = Array.from(groupedIdsMap).map(([key, idsSet]) => {
45
- const uniqueName = key.substring(0, key.indexOf('|'));
46
- const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
47
- const meta = em.getMetadata().getByUniqueName(uniqueName);
48
- return em.find(meta.class, Array.from(idsSet), opts);
49
- });
50
- await Promise.all(promises);
51
- /* Instead of assigning each find result to the original reference we use a shortcut
37
+ /**
38
+ * Returns the reference dataloader batchLoadFn, which aggregates references by entity,
39
+ * makes one query per entity and maps each input reference to the corresponding result.
40
+ */
41
+ static getRefBatchLoadFn(em) {
42
+ return async (refsWithOpts) => {
43
+ const groupedIdsMap = DataloaderUtils.groupPrimaryKeysByEntityAndOpts(refsWithOpts);
44
+ const promises = Array.from(groupedIdsMap).map(([key, idsSet]) => {
45
+ const uniqueName = key.substring(0, key.indexOf('|'));
46
+ const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
47
+ const meta = em.getMetadata().getByUniqueName(uniqueName);
48
+ return em.find(meta.class, Array.from(idsSet), opts);
49
+ });
50
+ await Promise.all(promises);
51
+ /* Instead of assigning each find result to the original reference we use a shortcut
52
52
  which takes advantage of the already existing Mikro-ORM caching mechanism:
53
53
  when it calls ref.unwrap it will automatically retrieve the entity
54
54
  from the cache (it will hit the cache because of the previous find query).
55
55
  This trick won't be possible for collections where we will be forced to map the results. */
56
- return refsWithOpts.map(([ref]) => ref.unwrap());
57
- };
58
- }
59
- /**
60
- * Groups collections by entity and returns a Map whose keys are the entity names and whose values are filter Maps
61
- * which we can use to narrow down the find query to return just the items of the collections that have been dataloaded.
62
- * The entries of the filter Map will be used as the values of an $or operator so we end up with a query per entity.
63
- */
64
- static groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts) {
65
- const entitiesMap = new Map();
66
- for (const [col, opts] of collsWithOpts) {
67
- /*
56
+ return refsWithOpts.map(([ref]) => ref.unwrap());
57
+ };
58
+ }
59
+ /**
60
+ * Groups collections by entity and returns a Map whose keys are the entity names and whose values are filter Maps
61
+ * which we can use to narrow down the find query to return just the items of the collections that have been dataloaded.
62
+ * The entries of the filter Map will be used as the values of an $or operator so we end up with a query per entity.
63
+ */
64
+ static groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts) {
65
+ const entitiesMap = new Map();
66
+ for (const [col, opts] of collsWithOpts) {
67
+ /*
68
68
  We first get the entity name of the Collection and together with its options (see groupPrimaryKeysByEntityAndOpts
69
69
  for a full explanation) we use it as the key of the first Map.
70
70
  With that we know that we have to look for entities of this type (and with the same options) in order to fulfill the collection.
71
71
  The value is another Map which we can use to filter the find query to get results pertaining to the collections that have been dataloaded:
72
72
  its keys are the props we are going to filter to and its values are the corresponding PKs.
73
73
  */
74
- const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
75
- let filterMap = entitiesMap.get(key); // We are going to use this map to filter the entities pertaining to the collections that have been dataloaded.
76
- if (filterMap == null) {
77
- filterMap = new Map();
78
- entitiesMap.set(key, filterMap);
79
- }
80
- // The Collection dataloader relies on the inverse side of the relationship (inversedBy/mappedBy), which is going to be
81
- // the key of the filter Map and it's the prop that we use to filter the results pertaining to the Collection.
82
- const inversedProp = col.property.inversedBy ?? col.property.mappedBy; // Many to Many vs One to Many
83
- let primaryKeys = filterMap.get(inversedProp);
84
- if (primaryKeys == null) {
85
- primaryKeys = new Set();
86
- filterMap.set(inversedProp, primaryKeys);
87
- }
88
- // This is the PK that in conjunction with the filter Map key (the prop) will lead to this specific Collection
89
- primaryKeys.add(helper(col.owner).getPrimaryKey());
74
+ const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
75
+ let filterMap = entitiesMap.get(key); // We are going to use this map to filter the entities pertaining to the collections that have been dataloaded.
76
+ if (filterMap == null) {
77
+ filterMap = new Map();
78
+ entitiesMap.set(key, filterMap);
79
+ }
80
+ // The Collection dataloader relies on the inverse side of the relationship (inversedBy/mappedBy), which is going to be
81
+ // the key of the filter Map and it's the prop that we use to filter the results pertaining to the Collection.
82
+ const inversedProp = col.property.inversedBy ?? col.property.mappedBy; // Many to Many vs One to Many
83
+ let primaryKeys = filterMap.get(inversedProp);
84
+ if (primaryKeys == null) {
85
+ primaryKeys = new Set();
86
+ filterMap.set(inversedProp, primaryKeys);
87
+ }
88
+ // This is the PK that in conjunction with the filter Map key (the prop) will lead to this specific Collection
89
+ primaryKeys.add(helper(col.owner).getPrimaryKey());
90
+ }
91
+ return entitiesMap;
92
+ }
93
+ /**
94
+ * Turn the entity+options map into actual queries.
95
+ * The keys are the entity names + a stringified version of the options and the values are filter Maps which will be used as the values of an $or operator so we end up with a query per entity+opts.
96
+ * We must populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s).
97
+ * Together with the query the promises will also return the key which can be used to narrow down the results pertaining to a certain set of options.
98
+ */
99
+ static entitiesAndOptsMapToQueries(entitiesAndOptsMap, em) {
100
+ return Array.from(entitiesAndOptsMap, async ([key, filterMap]) => {
101
+ const uniqueName = key.substring(0, key.indexOf('|'));
102
+ const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
103
+ const meta = em.getMetadata().getByUniqueName(uniqueName);
104
+ const res = await em.find(meta.class, opts?.where != null && Object.keys(opts.where).length > 0
105
+ ? {
106
+ $and: [
107
+ {
108
+ $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
109
+ return { [prop]: Array.from(pks) };
110
+ }),
111
+ },
112
+ opts.where,
113
+ ],
114
+ }
115
+ : {
116
+ // The entries of the filter Map will be used as the values of the $or operator
117
+ $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
118
+ return { [prop]: Array.from(pks) };
119
+ }),
120
+ }, {
121
+ ...opts,
122
+ // We need to populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s)
123
+ populate: [
124
+ ...(opts.populate === false ? [] : (opts.populate ?? [])),
125
+ ...Array.from(filterMap.keys()).filter(
126
+ // We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
127
+ prop => meta.properties[prop]?.ref !== true),
128
+ ],
129
+ });
130
+ return [key, res];
131
+ });
90
132
  }
91
- return entitiesMap;
92
- }
93
- /**
94
- * Turn the entity+options map into actual queries.
95
- * The keys are the entity names + a stringified version of the options and the values are filter Maps which will be used as the values of an $or operator so we end up with a query per entity+opts.
96
- * We must populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s).
97
- * Together with the query the promises will also return the key which can be used to narrow down the results pertaining to a certain set of options.
98
- */
99
- static entitiesAndOptsMapToQueries(entitiesAndOptsMap, em) {
100
- return Array.from(entitiesAndOptsMap, async ([key, filterMap]) => {
101
- const uniqueName = key.substring(0, key.indexOf('|'));
102
- const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
103
- const meta = em.getMetadata().getByUniqueName(uniqueName);
104
- const res = await em.find(
105
- meta.class,
106
- opts?.where != null && Object.keys(opts.where).length > 0
107
- ? {
108
- $and: [
109
- {
110
- $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
111
- return { [prop]: Array.from(pks) };
112
- }),
113
- },
114
- opts.where,
115
- ],
133
+ /**
134
+ * Creates a filter which returns the results pertaining to a certain collection.
135
+ * First checks if the Entity type matches, then retrieves the inverse side of the relationship
136
+ * where the filtering will be done in order to match the target collection.
137
+ */
138
+ static getColFilter(collection) {
139
+ return (result) => {
140
+ // There is no need to check if Entity matches because we already matched the key which is entity+options.
141
+ // This is the inverse side of the relationship where the filtering will be done in order to match the target collection
142
+ // Either inversedBy or mappedBy exist because we already checked in groupInversedOrMappedKeysByEntity
143
+ const inverseProp = collection.property.inversedBy ?? collection.property.mappedBy;
144
+ const target = Reference.unwrapReference(result[inverseProp]);
145
+ if (target instanceof Collection) {
146
+ for (const item of target) {
147
+ if (item === collection.owner) {
148
+ return true;
149
+ }
150
+ }
116
151
  }
117
- : {
118
- // The entries of the filter Map will be used as the values of the $or operator
119
- $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
120
- return { [prop]: Array.from(pks) };
121
- }),
122
- },
123
- {
124
- ...opts,
125
- // We need to populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s)
126
- populate: [
127
- ...(opts.populate === false ? [] : (opts.populate ?? [])),
128
- ...Array.from(filterMap.keys()).filter(
129
- // We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
130
- prop => meta.properties[prop]?.ref !== true,
131
- ),
132
- ],
133
- },
134
- );
135
- return [key, res];
136
- });
137
- }
138
- /**
139
- * Creates a filter which returns the results pertaining to a certain collection.
140
- * First checks if the Entity type matches, then retrieves the inverse side of the relationship
141
- * where the filtering will be done in order to match the target collection.
142
- */
143
- static getColFilter(collection) {
144
- return result => {
145
- // There is no need to check if Entity matches because we already matched the key which is entity+options.
146
- // This is the inverse side of the relationship where the filtering will be done in order to match the target collection
147
- // Either inversedBy or mappedBy exist because we already checked in groupInversedOrMappedKeysByEntity
148
- const inverseProp = collection.property.inversedBy ?? collection.property.mappedBy;
149
- const target = Reference.unwrapReference(result[inverseProp]);
150
- if (target instanceof Collection) {
151
- for (const item of target) {
152
- if (item === collection.owner) {
153
- return true;
154
- }
152
+ else if (target) {
153
+ return target === collection.owner;
154
+ }
155
+ return false;
156
+ };
157
+ }
158
+ /**
159
+ * Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
160
+ * makes one query per entity and maps each input collection to the corresponding result.
161
+ */
162
+ static getColBatchLoadFn(em) {
163
+ return async (collsWithOpts) => {
164
+ const entitiesAndOptsMap = DataloaderUtils.groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts);
165
+ const promises = DataloaderUtils.entitiesAndOptsMapToQueries(entitiesAndOptsMap, em);
166
+ const resultsMap = new Map(await Promise.all(promises));
167
+ // We need to filter the results in order to map each input collection
168
+ // to a subset of each query matching the collection items.
169
+ return collsWithOpts.map(([col, opts]) => {
170
+ const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
171
+ const entities = resultsMap.get(key);
172
+ if (entities == null) {
173
+ // Should never happen
174
+ /* v8 ignore next */
175
+ throw new Error('Cannot match results');
176
+ }
177
+ return entities.filter(DataloaderUtils.getColFilter(col));
178
+ });
179
+ };
180
+ }
181
+ /**
182
+ * Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
183
+ * makes one query per entity and maps each input collection to the corresponding result.
184
+ */
185
+ static getManyToManyColBatchLoadFn(em) {
186
+ return async (collsWithOpts) => {
187
+ const groups = new Map();
188
+ for (const [col, opts] of collsWithOpts) {
189
+ const key = `${col.property.targetMeta.uniqueName}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
190
+ const value = groups.get(key) ?? [];
191
+ value.push([col, opts ?? {}]);
192
+ groups.set(key, value);
193
+ }
194
+ const ret = [];
195
+ for (const group of groups.values()) {
196
+ const prop = group[0][0].property;
197
+ const options = {};
198
+ const wrap = (cond) => ({ [prop.name]: cond });
199
+ const orderBy = Utils.asArray(group[0][1]?.orderBy).map(o => wrap(o));
200
+ const populate = wrap(group[0][1]?.populate);
201
+ const owners = group.map(c => c[0].owner);
202
+ const $or = [];
203
+ // a bit of a hack, but we need to prefix the key, since we have only a column name, not a property name
204
+ const alias = em.config.getNamingStrategy().aliasName(Utils.className(prop.pivotEntity), 0);
205
+ const fk = `${alias}.${Utils.getPrimaryKeyHash(prop.joinColumns)}`;
206
+ for (const c of group) {
207
+ $or.push({ $and: [c[1]?.where ?? {}, { [fk]: c[0].owner }] });
208
+ options.refresh ??= c[1]?.refresh;
209
+ }
210
+ options.where = wrap({ $or });
211
+ const r = await em
212
+ .getEntityLoader()
213
+ .findChildrenFromPivotTable(owners, prop, options, orderBy, populate, group[0][1]?.ref);
214
+ ret.push(...r);
215
+ }
216
+ return ret;
217
+ };
218
+ }
219
+ static async getDataLoader() {
220
+ if (this.DataLoader) {
221
+ return this.DataLoader;
155
222
  }
156
- } else if (target) {
157
- return target === collection.owner;
158
- }
159
- return false;
160
- };
161
- }
162
- /**
163
- * Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
164
- * makes one query per entity and maps each input collection to the corresponding result.
165
- */
166
- static getColBatchLoadFn(em) {
167
- return async collsWithOpts => {
168
- const entitiesAndOptsMap = DataloaderUtils.groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts);
169
- const promises = DataloaderUtils.entitiesAndOptsMapToQueries(entitiesAndOptsMap, em);
170
- const resultsMap = new Map(await Promise.all(promises));
171
- // We need to filter the results in order to map each input collection
172
- // to a subset of each query matching the collection items.
173
- return collsWithOpts.map(([col, opts]) => {
174
- const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
175
- const entities = resultsMap.get(key);
176
- if (entities == null) {
177
- // Should never happen
178
- /* v8 ignore next */
179
- throw new Error('Cannot match results');
223
+ try {
224
+ const mod = await import('dataloader');
225
+ const DataLoader = mod.default;
226
+ return (this.DataLoader ??= DataLoader);
180
227
  }
181
- return entities.filter(DataloaderUtils.getColFilter(col));
182
- });
183
- };
184
- }
185
- /**
186
- * Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
187
- * makes one query per entity and maps each input collection to the corresponding result.
188
- */
189
- static getManyToManyColBatchLoadFn(em) {
190
- return async collsWithOpts => {
191
- const groups = new Map();
192
- for (const [col, opts] of collsWithOpts) {
193
- const key = `${col.property.targetMeta.uniqueName}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
194
- const value = groups.get(key) ?? [];
195
- value.push([col, opts ?? {}]);
196
- groups.set(key, value);
197
- }
198
- const ret = [];
199
- for (const group of groups.values()) {
200
- const prop = group[0][0].property;
201
- const options = {};
202
- const wrap = cond => ({ [prop.name]: cond });
203
- const orderBy = Utils.asArray(group[0][1]?.orderBy).map(o => wrap(o));
204
- const populate = wrap(group[0][1]?.populate);
205
- const owners = group.map(c => c[0].owner);
206
- const $or = [];
207
- // a bit of a hack, but we need to prefix the key, since we have only a column name, not a property name
208
- const alias = em.config.getNamingStrategy().aliasName(Utils.className(prop.pivotEntity), 0);
209
- const fk = `${alias}.${Utils.getPrimaryKeyHash(prop.joinColumns)}`;
210
- for (const c of group) {
211
- $or.push({ $and: [c[1]?.where ?? {}, { [fk]: c[0].owner }] });
212
- options.refresh ??= c[1]?.refresh;
228
+ catch {
229
+ /* v8 ignore next */
230
+ throw new Error("DataLoader is not found, make sure `dataloader` package is installed in your project's dependencies.");
213
231
  }
214
- options.where = wrap({ $or });
215
- const r = await em
216
- .getEntityLoader()
217
- .findChildrenFromPivotTable(owners, prop, options, orderBy, populate, group[0][1]?.ref);
218
- ret.push(...r);
219
- }
220
- return ret;
221
- };
222
- }
223
- static async getDataLoader() {
224
- if (this.DataLoader) {
225
- return this.DataLoader;
226
- }
227
- try {
228
- const mod = await import('dataloader');
229
- const DataLoader = mod.default;
230
- return (this.DataLoader ??= DataLoader);
231
- } catch {
232
- /* v8 ignore next */
233
- throw new Error(
234
- "DataLoader is not found, make sure `dataloader` package is installed in your project's dependencies.",
235
- );
236
232
  }
237
- }
238
233
  }
@@ -1,21 +1,9 @@
1
- import type {
2
- EntityData,
3
- EntityDictionary,
4
- EntityMetadata,
5
- EntityName,
6
- EntityProperty,
7
- IMetadataStorage,
8
- Primary,
9
- } from '../typings.js';
1
+ import type { EntityData, EntityDictionary, EntityMetadata, EntityName, EntityProperty, IMetadataStorage, Primary } from '../typings.js';
10
2
  import type { Platform } from '../platforms/Platform.js';
11
3
  import type { Configuration } from './Configuration.js';
12
- type Comparator<T> = (
13
- a: T,
14
- b: T,
15
- options?: {
4
+ type Comparator<T> = (a: T, b: T, options?: {
16
5
  includeInverseSides?: boolean;
17
- },
18
- ) => EntityData<T>;
6
+ }) => EntityData<T>;
19
7
  type ResultMapper<T> = (result: EntityData<T>) => EntityData<T> | null;
20
8
  type SnapshotGenerator<T> = (entity: T) => EntityData<T>;
21
9
  type PkGetter<T> = (entity: T) => Primary<T>;
@@ -23,88 +11,83 @@ type PkSerializer<T> = (entity: T) => string;
23
11
  type CompositeKeyPart = string | CompositeKeyPart[];
24
12
  /** @internal Generates and caches JIT-compiled functions for comparing, snapshotting, and mapping entity data. */
25
13
  export declare class EntityComparator {
26
- #private;
27
- constructor(metadata: IMetadataStorage, platform: Platform, config?: Configuration);
28
- /**
29
- * Computes difference between two entities.
30
- */
31
- diffEntities<T extends object>(
32
- entityName: EntityName<T>,
33
- a: EntityData<T>,
34
- b: EntityData<T>,
35
- options?: {
36
- includeInverseSides?: boolean;
37
- },
38
- ): EntityData<T>;
39
- /** Returns true if two entity snapshots are identical (no differences). */
40
- matching<T extends object>(entityName: EntityName<T>, a: EntityData<T>, b: EntityData<T>): boolean;
41
- /**
42
- * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
43
- * References will be mapped to primary keys, collections to arrays of primary keys.
44
- */
45
- prepareEntity<T extends object>(entity: T): EntityData<T>;
46
- /**
47
- * Maps database columns to properties.
48
- */
49
- mapResult<T>(meta: EntityMetadata<T>, result: EntityDictionary<T>): EntityData<T>;
50
- /**
51
- * @internal Highly performance-sensitive method.
52
- */
53
- getPkGetter<T>(meta: EntityMetadata<T>): PkGetter<T>;
54
- /**
55
- * @internal Highly performance-sensitive method.
56
- */
57
- getPkGetterConverted<T>(meta: EntityMetadata<T>): PkGetter<T>;
58
- /**
59
- * @internal Highly performance-sensitive method.
60
- */
61
- getPkSerializer<T>(meta: EntityMetadata<T>): PkSerializer<T>;
62
- /**
63
- * @internal Highly performance-sensitive method.
64
- */
65
- getSnapshotGenerator<T>(entityName: EntityName<T>): SnapshotGenerator<T>;
66
- /**
67
- * @internal
68
- */
69
- propName(name: string, parent?: string): string;
70
- /**
71
- * @internal respects nested composite keys, e.g. `[1, [2, 3]]`
72
- */
73
- createCompositeKeyArray(prop: EntityProperty, parents?: EntityProperty[]): string;
74
- /**
75
- * @internal
76
- */
77
- formatCompositeKeyPart(part: CompositeKeyPart): string;
78
- /**
79
- * @internal Highly performance-sensitive method.
80
- */
81
- getResultMapper<T>(meta: EntityMetadata<T>): ResultMapper<T>;
82
- private getPropertyCondition;
83
- private getEmbeddedArrayPropertySnapshot;
84
- /**
85
- * we need to serialize only object embeddables, and only the top level ones, so root object embeddable
86
- * properties and first child nested object embeddables with inlined parent
87
- */
88
- private shouldSerialize;
89
- private getEmbeddedPropertySnapshot;
90
- private registerCustomType;
91
- private getPropertySnapshot;
92
- /**
93
- * @internal Highly performance-sensitive method.
94
- */
95
- getEntityComparator<T extends object>(entityName: EntityName<T>): Comparator<T>;
96
- private getGenericComparator;
97
- private getPropertyComparator;
98
- private wrap;
99
- private safeKey;
100
- /**
101
- * Sets the toArray helper in the context if not already set.
102
- * Used for converting composite PKs to arrays.
103
- */
104
- private setToArrayHelper;
105
- /**
106
- * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
107
- */
108
- static isComparable<T>(prop: EntityProperty<T>, root: EntityMetadata): boolean;
14
+ #private;
15
+ constructor(metadata: IMetadataStorage, platform: Platform, config?: Configuration);
16
+ /**
17
+ * Computes difference between two entities.
18
+ */
19
+ diffEntities<T extends object>(entityName: EntityName<T>, a: EntityData<T>, b: EntityData<T>, options?: {
20
+ includeInverseSides?: boolean;
21
+ }): EntityData<T>;
22
+ /** Returns true if two entity snapshots are identical (no differences). */
23
+ matching<T extends object>(entityName: EntityName<T>, a: EntityData<T>, b: EntityData<T>): boolean;
24
+ /**
25
+ * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
26
+ * References will be mapped to primary keys, collections to arrays of primary keys.
27
+ */
28
+ prepareEntity<T extends object>(entity: T): EntityData<T>;
29
+ /**
30
+ * Maps database columns to properties.
31
+ */
32
+ mapResult<T>(meta: EntityMetadata<T>, result: EntityDictionary<T>): EntityData<T>;
33
+ /**
34
+ * @internal Highly performance-sensitive method.
35
+ */
36
+ getPkGetter<T>(meta: EntityMetadata<T>): PkGetter<T>;
37
+ /**
38
+ * @internal Highly performance-sensitive method.
39
+ */
40
+ getPkGetterConverted<T>(meta: EntityMetadata<T>): PkGetter<T>;
41
+ /**
42
+ * @internal Highly performance-sensitive method.
43
+ */
44
+ getPkSerializer<T>(meta: EntityMetadata<T>): PkSerializer<T>;
45
+ /**
46
+ * @internal Highly performance-sensitive method.
47
+ */
48
+ getSnapshotGenerator<T>(entityName: EntityName<T>): SnapshotGenerator<T>;
49
+ /**
50
+ * @internal
51
+ */
52
+ propName(name: string, parent?: string): string;
53
+ /**
54
+ * @internal respects nested composite keys, e.g. `[1, [2, 3]]`
55
+ */
56
+ createCompositeKeyArray(prop: EntityProperty, parents?: EntityProperty[]): string;
57
+ /**
58
+ * @internal
59
+ */
60
+ formatCompositeKeyPart(part: CompositeKeyPart): string;
61
+ /**
62
+ * @internal Highly performance-sensitive method.
63
+ */
64
+ getResultMapper<T>(meta: EntityMetadata<T>): ResultMapper<T>;
65
+ private getPropertyCondition;
66
+ private getEmbeddedArrayPropertySnapshot;
67
+ /**
68
+ * we need to serialize only object embeddables, and only the top level ones, so root object embeddable
69
+ * properties and first child nested object embeddables with inlined parent
70
+ */
71
+ private shouldSerialize;
72
+ private getEmbeddedPropertySnapshot;
73
+ private registerCustomType;
74
+ private getPropertySnapshot;
75
+ /**
76
+ * @internal Highly performance-sensitive method.
77
+ */
78
+ getEntityComparator<T extends object>(entityName: EntityName<T>): Comparator<T>;
79
+ private getGenericComparator;
80
+ private getPropertyComparator;
81
+ private wrap;
82
+ private safeKey;
83
+ /**
84
+ * Sets the toArray helper in the context if not already set.
85
+ * Used for converting composite PKs to arrays.
86
+ */
87
+ private setToArrayHelper;
88
+ /**
89
+ * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
90
+ */
91
+ static isComparable<T>(prop: EntityProperty<T>, root: EntityMetadata): boolean;
109
92
  }
110
93
  export {};