@yandjin-mikro-orm/core 6.1.4-rc-sti-changes-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 (264) hide show
  1. package/EntityManager.d.ts +553 -0
  2. package/EntityManager.js +1736 -0
  3. package/LICENSE +21 -0
  4. package/MikroORM.d.ts +102 -0
  5. package/MikroORM.js +258 -0
  6. package/README.md +383 -0
  7. package/cache/CacheAdapter.d.ts +40 -0
  8. package/cache/CacheAdapter.js +2 -0
  9. package/cache/FileCacheAdapter.d.ts +31 -0
  10. package/cache/FileCacheAdapter.js +90 -0
  11. package/cache/GeneratedCacheAdapter.d.ts +25 -0
  12. package/cache/GeneratedCacheAdapter.js +38 -0
  13. package/cache/MemoryCacheAdapter.d.ts +24 -0
  14. package/cache/MemoryCacheAdapter.js +44 -0
  15. package/cache/NullCacheAdapter.d.ts +19 -0
  16. package/cache/NullCacheAdapter.js +30 -0
  17. package/cache/index.d.ts +5 -0
  18. package/cache/index.js +21 -0
  19. package/connections/Connection.d.ts +85 -0
  20. package/connections/Connection.js +128 -0
  21. package/connections/index.d.ts +1 -0
  22. package/connections/index.js +17 -0
  23. package/decorators/Check.d.ts +3 -0
  24. package/decorators/Check.js +17 -0
  25. package/decorators/CreateRequestContext.d.ts +2 -0
  26. package/decorators/CreateRequestContext.js +31 -0
  27. package/decorators/Embeddable.d.ts +8 -0
  28. package/decorators/Embeddable.js +15 -0
  29. package/decorators/Embedded.d.ts +13 -0
  30. package/decorators/Embedded.js +21 -0
  31. package/decorators/EnsureRequestContext.d.ts +2 -0
  32. package/decorators/EnsureRequestContext.js +26 -0
  33. package/decorators/Entity.d.ts +18 -0
  34. package/decorators/Entity.js +17 -0
  35. package/decorators/Enum.d.ts +9 -0
  36. package/decorators/Enum.js +20 -0
  37. package/decorators/Filter.d.ts +2 -0
  38. package/decorators/Filter.js +12 -0
  39. package/decorators/Formula.d.ts +5 -0
  40. package/decorators/Formula.js +19 -0
  41. package/decorators/Indexed.d.ts +12 -0
  42. package/decorators/Indexed.js +25 -0
  43. package/decorators/ManyToMany.d.ts +21 -0
  44. package/decorators/ManyToMany.js +17 -0
  45. package/decorators/ManyToOne.d.ts +15 -0
  46. package/decorators/ManyToOne.js +17 -0
  47. package/decorators/OneToMany.d.ts +18 -0
  48. package/decorators/OneToMany.js +21 -0
  49. package/decorators/OneToOne.d.ts +12 -0
  50. package/decorators/OneToOne.js +11 -0
  51. package/decorators/PrimaryKey.d.ts +8 -0
  52. package/decorators/PrimaryKey.js +24 -0
  53. package/decorators/Property.d.ts +218 -0
  54. package/decorators/Property.js +35 -0
  55. package/decorators/Subscriber.d.ts +1 -0
  56. package/decorators/Subscriber.js +2 -0
  57. package/decorators/hooks.d.ts +16 -0
  58. package/decorators/hooks.js +60 -0
  59. package/decorators/index.d.ts +17 -0
  60. package/decorators/index.js +36 -0
  61. package/drivers/DatabaseDriver.d.ts +72 -0
  62. package/drivers/DatabaseDriver.js +358 -0
  63. package/drivers/IDatabaseDriver.d.ts +193 -0
  64. package/drivers/IDatabaseDriver.js +4 -0
  65. package/drivers/index.d.ts +2 -0
  66. package/drivers/index.js +18 -0
  67. package/entity/ArrayCollection.d.ts +113 -0
  68. package/entity/ArrayCollection.js +386 -0
  69. package/entity/BaseEntity.d.ts +22 -0
  70. package/entity/BaseEntity.js +47 -0
  71. package/entity/Collection.d.ts +104 -0
  72. package/entity/Collection.js +373 -0
  73. package/entity/EntityAssigner.d.ts +28 -0
  74. package/entity/EntityAssigner.js +226 -0
  75. package/entity/EntityFactory.d.ts +41 -0
  76. package/entity/EntityFactory.js +302 -0
  77. package/entity/EntityHelper.d.ts +29 -0
  78. package/entity/EntityHelper.js +250 -0
  79. package/entity/EntityIdentifier.d.ts +10 -0
  80. package/entity/EntityIdentifier.js +19 -0
  81. package/entity/EntityLoader.d.ts +65 -0
  82. package/entity/EntityLoader.js +579 -0
  83. package/entity/EntityRepository.d.ts +161 -0
  84. package/entity/EntityRepository.js +207 -0
  85. package/entity/EntityValidator.d.ts +19 -0
  86. package/entity/EntityValidator.js +152 -0
  87. package/entity/Reference.d.ts +89 -0
  88. package/entity/Reference.js +242 -0
  89. package/entity/WrappedEntity.d.ts +67 -0
  90. package/entity/WrappedEntity.js +146 -0
  91. package/entity/index.d.ts +13 -0
  92. package/entity/index.js +29 -0
  93. package/entity/wrap.d.ts +15 -0
  94. package/entity/wrap.js +26 -0
  95. package/enums.d.ts +160 -0
  96. package/enums.js +169 -0
  97. package/errors.d.ts +65 -0
  98. package/errors.js +222 -0
  99. package/events/EventManager.d.ts +17 -0
  100. package/events/EventManager.js +77 -0
  101. package/events/EventSubscriber.d.ts +39 -0
  102. package/events/EventSubscriber.js +2 -0
  103. package/events/TransactionEventBroadcaster.d.ts +11 -0
  104. package/events/TransactionEventBroadcaster.js +17 -0
  105. package/events/index.d.ts +3 -0
  106. package/events/index.js +19 -0
  107. package/exceptions.d.ts +104 -0
  108. package/exceptions.js +130 -0
  109. package/hydration/Hydrator.d.ts +23 -0
  110. package/hydration/Hydrator.js +51 -0
  111. package/hydration/ObjectHydrator.d.ts +24 -0
  112. package/hydration/ObjectHydrator.js +332 -0
  113. package/hydration/index.d.ts +2 -0
  114. package/hydration/index.js +18 -0
  115. package/index.d.ts +25 -0
  116. package/index.js +50 -0
  117. package/index.mjs +192 -0
  118. package/logging/DefaultLogger.d.ts +32 -0
  119. package/logging/DefaultLogger.js +90 -0
  120. package/logging/Logger.d.ts +56 -0
  121. package/logging/Logger.js +2 -0
  122. package/logging/SimpleLogger.d.ts +17 -0
  123. package/logging/SimpleLogger.js +31 -0
  124. package/logging/colors.d.ts +9 -0
  125. package/logging/colors.js +20 -0
  126. package/logging/index.d.ts +4 -0
  127. package/logging/index.js +20 -0
  128. package/metadata/EntitySchema.d.ts +74 -0
  129. package/metadata/EntitySchema.js +293 -0
  130. package/metadata/MetadataDiscovery.d.ts +71 -0
  131. package/metadata/MetadataDiscovery.js +1244 -0
  132. package/metadata/MetadataProvider.d.ts +11 -0
  133. package/metadata/MetadataProvider.js +23 -0
  134. package/metadata/MetadataStorage.d.ts +22 -0
  135. package/metadata/MetadataStorage.js +87 -0
  136. package/metadata/MetadataValidator.d.ts +24 -0
  137. package/metadata/MetadataValidator.js +213 -0
  138. package/metadata/ReflectMetadataProvider.d.ts +8 -0
  139. package/metadata/ReflectMetadataProvider.js +48 -0
  140. package/metadata/index.d.ts +6 -0
  141. package/metadata/index.js +22 -0
  142. package/naming-strategy/AbstractNamingStrategy.d.ts +18 -0
  143. package/naming-strategy/AbstractNamingStrategy.js +48 -0
  144. package/naming-strategy/EntityCaseNamingStrategy.d.ts +12 -0
  145. package/naming-strategy/EntityCaseNamingStrategy.js +32 -0
  146. package/naming-strategy/MongoNamingStrategy.d.ts +9 -0
  147. package/naming-strategy/MongoNamingStrategy.js +25 -0
  148. package/naming-strategy/NamingStrategy.d.ts +52 -0
  149. package/naming-strategy/NamingStrategy.js +2 -0
  150. package/naming-strategy/UnderscoreNamingStrategy.d.ts +10 -0
  151. package/naming-strategy/UnderscoreNamingStrategy.js +28 -0
  152. package/naming-strategy/index.d.ts +5 -0
  153. package/naming-strategy/index.js +21 -0
  154. package/package.json +70 -0
  155. package/platforms/ExceptionConverter.d.ts +5 -0
  156. package/platforms/ExceptionConverter.js +11 -0
  157. package/platforms/Platform.d.ts +201 -0
  158. package/platforms/Platform.js +452 -0
  159. package/platforms/index.d.ts +2 -0
  160. package/platforms/index.js +18 -0
  161. package/serialization/EntitySerializer.d.ts +34 -0
  162. package/serialization/EntitySerializer.js +206 -0
  163. package/serialization/EntityTransformer.d.ts +8 -0
  164. package/serialization/EntityTransformer.js +192 -0
  165. package/serialization/SerializationContext.d.ts +30 -0
  166. package/serialization/SerializationContext.js +111 -0
  167. package/serialization/index.d.ts +3 -0
  168. package/serialization/index.js +19 -0
  169. package/types/ArrayType.d.ts +13 -0
  170. package/types/ArrayType.js +47 -0
  171. package/types/BigIntType.d.ts +16 -0
  172. package/types/BigIntType.js +45 -0
  173. package/types/BlobType.d.ts +10 -0
  174. package/types/BlobType.js +27 -0
  175. package/types/BooleanType.d.ts +8 -0
  176. package/types/BooleanType.js +16 -0
  177. package/types/DateTimeType.d.ts +8 -0
  178. package/types/DateTimeType.js +16 -0
  179. package/types/DateType.d.ts +8 -0
  180. package/types/DateType.js +16 -0
  181. package/types/DecimalType.d.ts +11 -0
  182. package/types/DecimalType.js +22 -0
  183. package/types/DoubleType.d.ts +11 -0
  184. package/types/DoubleType.js +22 -0
  185. package/types/EnumArrayType.d.ts +9 -0
  186. package/types/EnumArrayType.js +32 -0
  187. package/types/EnumType.d.ts +8 -0
  188. package/types/EnumType.js +16 -0
  189. package/types/FloatType.d.ts +8 -0
  190. package/types/FloatType.js +16 -0
  191. package/types/IntegerType.d.ts +8 -0
  192. package/types/IntegerType.js +16 -0
  193. package/types/IntervalType.d.ts +8 -0
  194. package/types/IntervalType.js +16 -0
  195. package/types/JsonType.d.ts +13 -0
  196. package/types/JsonType.js +34 -0
  197. package/types/MediumIntType.d.ts +6 -0
  198. package/types/MediumIntType.js +10 -0
  199. package/types/SmallIntType.d.ts +8 -0
  200. package/types/SmallIntType.js +16 -0
  201. package/types/StringType.d.ts +8 -0
  202. package/types/StringType.js +16 -0
  203. package/types/TextType.d.ts +8 -0
  204. package/types/TextType.js +16 -0
  205. package/types/TimeType.d.ts +9 -0
  206. package/types/TimeType.js +23 -0
  207. package/types/TinyIntType.d.ts +8 -0
  208. package/types/TinyIntType.js +16 -0
  209. package/types/Type.d.ts +64 -0
  210. package/types/Type.js +84 -0
  211. package/types/Uint8ArrayType.d.ts +11 -0
  212. package/types/Uint8ArrayType.js +37 -0
  213. package/types/UnknownType.d.ts +7 -0
  214. package/types/UnknownType.js +13 -0
  215. package/types/UuidType.d.ts +7 -0
  216. package/types/UuidType.js +13 -0
  217. package/types/index.d.ts +75 -0
  218. package/types/index.js +77 -0
  219. package/typings.d.ts +767 -0
  220. package/typings.js +198 -0
  221. package/unit-of-work/ChangeSet.d.ts +34 -0
  222. package/unit-of-work/ChangeSet.js +62 -0
  223. package/unit-of-work/ChangeSetComputer.d.ts +26 -0
  224. package/unit-of-work/ChangeSetComputer.js +153 -0
  225. package/unit-of-work/ChangeSetPersister.d.ts +50 -0
  226. package/unit-of-work/ChangeSetPersister.js +361 -0
  227. package/unit-of-work/CommitOrderCalculator.d.ts +62 -0
  228. package/unit-of-work/CommitOrderCalculator.js +113 -0
  229. package/unit-of-work/IdentityMap.d.ts +17 -0
  230. package/unit-of-work/IdentityMap.js +84 -0
  231. package/unit-of-work/UnitOfWork.d.ts +124 -0
  232. package/unit-of-work/UnitOfWork.js +1013 -0
  233. package/unit-of-work/index.d.ts +6 -0
  234. package/unit-of-work/index.js +22 -0
  235. package/utils/AbstractSchemaGenerator.d.ts +38 -0
  236. package/utils/AbstractSchemaGenerator.js +101 -0
  237. package/utils/Configuration.d.ts +390 -0
  238. package/utils/Configuration.js +357 -0
  239. package/utils/ConfigurationLoader.d.ts +29 -0
  240. package/utils/ConfigurationLoader.js +282 -0
  241. package/utils/Cursor.d.ts +77 -0
  242. package/utils/Cursor.js +169 -0
  243. package/utils/DataloaderUtils.d.ts +43 -0
  244. package/utils/DataloaderUtils.js +194 -0
  245. package/utils/EntityComparator.d.ts +73 -0
  246. package/utils/EntityComparator.js +568 -0
  247. package/utils/NullHighlighter.d.ts +4 -0
  248. package/utils/NullHighlighter.js +9 -0
  249. package/utils/QueryHelper.d.ts +28 -0
  250. package/utils/QueryHelper.js +228 -0
  251. package/utils/RawQueryFragment.d.ts +96 -0
  252. package/utils/RawQueryFragment.js +188 -0
  253. package/utils/RequestContext.d.ts +34 -0
  254. package/utils/RequestContext.js +54 -0
  255. package/utils/TransactionContext.d.ts +19 -0
  256. package/utils/TransactionContext.js +34 -0
  257. package/utils/Utils.d.ts +274 -0
  258. package/utils/Utils.js +1073 -0
  259. package/utils/clone.d.ts +6 -0
  260. package/utils/clone.js +127 -0
  261. package/utils/index.d.ts +13 -0
  262. package/utils/index.js +29 -0
  263. package/utils/upsert-utils.d.ts +6 -0
  264. package/utils/upsert-utils.js +33 -0
@@ -0,0 +1,77 @@
1
+ /// <reference types="node" />
2
+ import { inspect } from 'util';
3
+ import type { EntityMetadata, FilterObject, Loaded } from '../typings';
4
+ import type { FindByCursorOptions, OrderDefinition } from '../drivers/IDatabaseDriver';
5
+ import { type QueryOrder } from '../enums';
6
+ /**
7
+ * As an alternative to the offset-based pagination with `limit` and `offset`, we can paginate based on a cursor.
8
+ * A cursor is an opaque string that defines a specific place in ordered entity graph. You can use `em.findByCursor()`
9
+ * to access those options. Under the hood, it will call `em.find()` and `em.count()` just like the `em.findAndCount()`
10
+ * method, but will use the cursor options instead.
11
+ *
12
+ * Supports `before`, `after`, `first` and `last` options while disallowing `limit` and `offset`. Explicit `orderBy` option is required.
13
+ *
14
+ * Use `first` and `after` for forward pagination, or `last` and `before` for backward pagination.
15
+ *
16
+ * - `first` and `last` are numbers and serve as an alternative to `offset`, those options are mutually exclusive, use only one at a time
17
+ * - `before` and `after` specify the previous cursor value
18
+ *
19
+ * ```ts
20
+ * const currentCursor = await em.findByCursor(User, {}, {
21
+ * first: 10,
22
+ * after: previousCursor, // can be either string or `Cursor` instance
23
+ * orderBy: { id: 'desc' },
24
+ * });
25
+ *
26
+ * // to fetch next page
27
+ * const nextCursor = await em.findByCursor(User, {}, {
28
+ * first: 10,
29
+ * after: currentCursor.endCursor, // or currentCursor.endCursor
30
+ * orderBy: { id: 'desc' },
31
+ * });
32
+ * ```
33
+ *
34
+ * The `Cursor` object provides the following interface:
35
+ *
36
+ * ```ts
37
+ * Cursor<User> {
38
+ * items: [
39
+ * User { ... },
40
+ * User { ... },
41
+ * User { ... },
42
+ * ...
43
+ * ],
44
+ * totalCount: 50,
45
+ * length: 10,
46
+ * startCursor: 'WzRd',
47
+ * endCursor: 'WzZd',
48
+ * hasPrevPage: true,
49
+ * hasNextPage: true,
50
+ * }
51
+ * ```
52
+ */
53
+ export declare class Cursor<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never> {
54
+ readonly items: Loaded<Entity, Hint, Fields, Excludes>[];
55
+ readonly totalCount: number;
56
+ readonly hasPrevPage: boolean;
57
+ readonly hasNextPage: boolean;
58
+ private readonly definition;
59
+ constructor(items: Loaded<Entity, Hint, Fields, Excludes>[], totalCount: number, options: FindByCursorOptions<Entity, Hint, Fields, Excludes>, meta: EntityMetadata<Entity>);
60
+ get startCursor(): string | null;
61
+ get endCursor(): string | null;
62
+ /**
63
+ * Computes the cursor value for a given entity.
64
+ */
65
+ from(entity: Entity | Loaded<Entity, Hint, Fields, Excludes>): string;
66
+ [Symbol.iterator](): IterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
67
+ get length(): number;
68
+ /**
69
+ * Computes the cursor value for given entity and order definition.
70
+ */
71
+ static for<Entity extends object>(meta: EntityMetadata<Entity>, entity: FilterObject<Entity>, orderBy: OrderDefinition<Entity>): string;
72
+ static encode(value: unknown[]): string;
73
+ static decode(value: string): unknown[];
74
+ static getDefinition<Entity extends object>(meta: EntityMetadata<Entity>, orderBy: OrderDefinition<Entity>): [never, QueryOrder][];
75
+ /** @ignore */
76
+ [inspect.custom](): string;
77
+ }
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Cursor = void 0;
4
+ const util_1 = require("util");
5
+ const Utils_1 = require("./Utils");
6
+ const enums_1 = require("../enums");
7
+ const Reference_1 = require("../entity/Reference");
8
+ const wrap_1 = require("../entity/wrap");
9
+ const RawQueryFragment_1 = require("../utils/RawQueryFragment");
10
+ const errors_1 = require("../errors");
11
+ /**
12
+ * As an alternative to the offset-based pagination with `limit` and `offset`, we can paginate based on a cursor.
13
+ * A cursor is an opaque string that defines a specific place in ordered entity graph. You can use `em.findByCursor()`
14
+ * to access those options. Under the hood, it will call `em.find()` and `em.count()` just like the `em.findAndCount()`
15
+ * method, but will use the cursor options instead.
16
+ *
17
+ * Supports `before`, `after`, `first` and `last` options while disallowing `limit` and `offset`. Explicit `orderBy` option is required.
18
+ *
19
+ * Use `first` and `after` for forward pagination, or `last` and `before` for backward pagination.
20
+ *
21
+ * - `first` and `last` are numbers and serve as an alternative to `offset`, those options are mutually exclusive, use only one at a time
22
+ * - `before` and `after` specify the previous cursor value
23
+ *
24
+ * ```ts
25
+ * const currentCursor = await em.findByCursor(User, {}, {
26
+ * first: 10,
27
+ * after: previousCursor, // can be either string or `Cursor` instance
28
+ * orderBy: { id: 'desc' },
29
+ * });
30
+ *
31
+ * // to fetch next page
32
+ * const nextCursor = await em.findByCursor(User, {}, {
33
+ * first: 10,
34
+ * after: currentCursor.endCursor, // or currentCursor.endCursor
35
+ * orderBy: { id: 'desc' },
36
+ * });
37
+ * ```
38
+ *
39
+ * The `Cursor` object provides the following interface:
40
+ *
41
+ * ```ts
42
+ * Cursor<User> {
43
+ * items: [
44
+ * User { ... },
45
+ * User { ... },
46
+ * User { ... },
47
+ * ...
48
+ * ],
49
+ * totalCount: 50,
50
+ * length: 10,
51
+ * startCursor: 'WzRd',
52
+ * endCursor: 'WzZd',
53
+ * hasPrevPage: true,
54
+ * hasNextPage: true,
55
+ * }
56
+ * ```
57
+ */
58
+ class Cursor {
59
+ items;
60
+ totalCount;
61
+ hasPrevPage;
62
+ hasNextPage;
63
+ definition;
64
+ constructor(items, totalCount, options, meta) {
65
+ this.items = items;
66
+ this.totalCount = totalCount;
67
+ const { first, last, before, after, orderBy, overfetch } = options;
68
+ const limit = first || last;
69
+ const isLast = !first && !!last;
70
+ const hasMorePages = !!overfetch && limit != null && items.length > limit;
71
+ this.hasPrevPage = before || after ? true : (isLast && hasMorePages);
72
+ this.hasNextPage = !(isLast && !before && !after) && hasMorePages;
73
+ if (hasMorePages) {
74
+ if (isLast) {
75
+ items.shift();
76
+ }
77
+ else {
78
+ items.pop();
79
+ }
80
+ }
81
+ this.definition = Cursor.getDefinition(meta, orderBy);
82
+ }
83
+ get startCursor() {
84
+ if (this.items.length === 0) {
85
+ return null;
86
+ }
87
+ return this.from(this.items[0]);
88
+ }
89
+ get endCursor() {
90
+ if (this.items.length === 0) {
91
+ return null;
92
+ }
93
+ return this.from(this.items[this.items.length - 1]);
94
+ }
95
+ /**
96
+ * Computes the cursor value for a given entity.
97
+ */
98
+ from(entity) {
99
+ const processEntity = (entity, prop, direction, object = false) => {
100
+ if (Utils_1.Utils.isPlainObject(direction)) {
101
+ const value = Utils_1.Utils.keys(direction).reduce((o, key) => {
102
+ Object.assign(o, processEntity(Reference_1.Reference.unwrapReference(entity[prop]), key, direction[key], true));
103
+ return o;
104
+ }, {});
105
+ return ({ [prop]: value });
106
+ }
107
+ if (entity[prop] == null) {
108
+ throw errors_1.CursorError.entityNotPopulated(entity, prop);
109
+ }
110
+ let value = entity[prop];
111
+ if (Utils_1.Utils.isEntity(value, true)) {
112
+ value = (0, wrap_1.helper)(value).getPrimaryKey();
113
+ }
114
+ if (object) {
115
+ return ({ [prop]: value });
116
+ }
117
+ return value;
118
+ };
119
+ const value = this.definition.map(([key, direction]) => processEntity(entity, key, direction));
120
+ return Cursor.encode(value);
121
+ }
122
+ *[Symbol.iterator]() {
123
+ for (const item of this.items) {
124
+ yield item;
125
+ }
126
+ }
127
+ get length() {
128
+ return this.items.length;
129
+ }
130
+ /**
131
+ * Computes the cursor value for given entity and order definition.
132
+ */
133
+ static for(meta, entity, orderBy) {
134
+ const definition = this.getDefinition(meta, orderBy);
135
+ return Cursor.encode(definition.map(([key]) => entity[key]));
136
+ }
137
+ static encode(value) {
138
+ return Buffer.from(JSON.stringify(value)).toString('base64url');
139
+ }
140
+ static decode(value) {
141
+ return JSON.parse(Buffer.from(value, 'base64url').toString('utf8'));
142
+ }
143
+ static getDefinition(meta, orderBy) {
144
+ return Utils_1.Utils.asArray(orderBy).flatMap(order => {
145
+ const ret = [];
146
+ for (const key of Utils_1.Utils.keys(order)) {
147
+ if (RawQueryFragment_1.RawQueryFragment.isKnownFragment(key)) {
148
+ ret.push([key, order[key]]);
149
+ continue;
150
+ }
151
+ const prop = meta.properties[key];
152
+ if (!prop || !([enums_1.ReferenceKind.SCALAR, enums_1.ReferenceKind.EMBEDDED, enums_1.ReferenceKind.MANY_TO_ONE].includes(prop.kind) || (prop.kind === enums_1.ReferenceKind.ONE_TO_ONE && prop.owner))) {
153
+ continue;
154
+ }
155
+ ret.push([prop.name, order[prop.name]]);
156
+ }
157
+ return ret;
158
+ });
159
+ }
160
+ /* istanbul ignore next */
161
+ /** @ignore */
162
+ [util_1.inspect.custom]() {
163
+ const type = this.items[0]?.constructor.name;
164
+ const { items, startCursor, endCursor, hasPrevPage, hasNextPage, totalCount, length } = this;
165
+ const options = (0, util_1.inspect)({ startCursor, endCursor, totalCount, hasPrevPage, hasNextPage, items, length }, { depth: 0 });
166
+ return `Cursor${type ? `<${type}>` : ''} ${options.replace('items: [Array]', 'items: [...]')}`;
167
+ }
168
+ }
169
+ exports.Cursor = Cursor;
@@ -0,0 +1,43 @@
1
+ import type { Primary, Ref } from '../typings';
2
+ import { Collection, type InitCollectionOptions } from '../entity/Collection';
3
+ import { type EntityManager } from '../EntityManager';
4
+ import type DataLoader from 'dataloader';
5
+ import { DataloaderType } from '../enums';
6
+ import { type LoadReferenceOptions } from '../entity/Reference';
7
+ export declare class DataloaderUtils {
8
+ /**
9
+ * Groups identified references by entity and returns a Map with the
10
+ * class name as the index and the corresponging primary keys as the value.
11
+ */
12
+ static groupPrimaryKeysByEntityAndOpts(refsWithOpts: readonly [Ref<any>, Omit<LoadReferenceOptions<any, any>, 'dataloader'>?][]): Map<string, Set<Primary<any>>>;
13
+ /**
14
+ * Returns the reference dataloader batchLoadFn, which aggregates references by entity,
15
+ * makes one query per entity and maps each input reference to the corresponging result.
16
+ */
17
+ static getRefBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Ref<any>, Omit<LoadReferenceOptions<any, any>, 'dataloader'>?], any>;
18
+ /**
19
+ * Groups collections by entity and returns a Map whose keys are the entity names and whose values are filter Maps
20
+ * which we can use to narrow down the find query to return just the items of the collections that have been dataloaded.
21
+ * 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.
22
+ */
23
+ static groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts: readonly [Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?][]): Map<string, Map<string, Set<Primary<any>>>>;
24
+ /**
25
+ * Turn the entity+options map into actual queries.
26
+ * The keys are the entity names + a strigified 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.
27
+ * We must populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s).
28
+ * 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.
29
+ */
30
+ static entitiesAndOptsMapToQueries(entitiesAndOptsMap: Map<string, Map<string, Set<Primary<any>>>>, em: EntityManager): Promise<[string, any[]]>[];
31
+ /**
32
+ * Creates a filter which returns the results pertaining to a certain collection.
33
+ * First checks if the Entity type matches, then retrieves the inverse side of the relationship
34
+ * where the filtering will be done in order to match the target collection.
35
+ */
36
+ static getColFilter<T, S extends T>(collection: Collection<any, object>): (result: T) => result is S;
37
+ /**
38
+ * Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
39
+ * makes one query per entity and maps each input collection to the corresponging result.
40
+ */
41
+ static getColBatchLoadFn(em: EntityManager): DataLoader.BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
42
+ static getDataloaderType(dataloaderCfg: DataloaderType | boolean): DataloaderType;
43
+ }
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DataloaderUtils = void 0;
4
+ const Collection_1 = require("../entity/Collection");
5
+ const wrap_1 = require("../entity/wrap");
6
+ const enums_1 = require("../enums");
7
+ class DataloaderUtils {
8
+ /**
9
+ * Groups identified references by entity and returns a Map with the
10
+ * class name as the index and the corresponging primary keys as the value.
11
+ */
12
+ static groupPrimaryKeysByEntityAndOpts(refsWithOpts) {
13
+ const map = new Map();
14
+ for (const [ref, opts] of refsWithOpts) {
15
+ /* The key is a combination of the className and a stringified version if the load options because we want
16
+ to map each combination of entities/options into separate find queries in order to return accurate results.
17
+ This could be further optimized finding the "lowest common denominator" among the different options
18
+ for each Entity and firing a single query for each Entity instead of Entity+options combination.
19
+ The former is the approach taken by the out-of-tree "find" dataloader: https://github.com/darkbasic/mikro-orm-dataloaders
20
+ In real-world scenarios (GraphQL) most of the time you will end up batching the same sets of options anyway,
21
+ so we end up getting most of the benefits with the much simpler implementation.
22
+ Also there are scenarios where the single query per entity implementation may end up being slower, for example
23
+ if the vast majority of the refereces batched for a certain entity don't have populate options while a few ones have
24
+ a wildcard populate so you end up doing the additional joins for all the entities.
25
+ Thus such approach should probably be configurable, if not opt-in.
26
+ NOTE: meta + opts multi maps (https://github.com/martian17/ds-js) might be a more elegant way
27
+ to implement this but not necessarily faster. */
28
+ const key = `${(0, wrap_1.helper)(ref).__meta.className}|${JSON.stringify(opts ?? {})}`;
29
+ let primaryKeysSet = map.get(key);
30
+ if (primaryKeysSet == null) {
31
+ primaryKeysSet = new Set();
32
+ map.set(key, primaryKeysSet);
33
+ }
34
+ primaryKeysSet.add((0, wrap_1.helper)(ref).getPrimaryKey());
35
+ }
36
+ return map;
37
+ }
38
+ /**
39
+ * Returns the reference dataloader batchLoadFn, which aggregates references by entity,
40
+ * makes one query per entity and maps each input reference to the corresponging result.
41
+ */
42
+ static getRefBatchLoadFn(em) {
43
+ return async (refsWithOpts) => {
44
+ const groupedIdsMap = DataloaderUtils.groupPrimaryKeysByEntityAndOpts(refsWithOpts);
45
+ const promises = Array.from(groupedIdsMap).map(([key, idsSet]) => {
46
+ const className = key.substring(0, key.indexOf('|'));
47
+ const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
48
+ return em.find(className, 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
+ which takes advantage of the already existing Mikro-ORM caching mechanism:
53
+ when it calls ref.unwrap it will automatically retrieve the entity
54
+ from the cache (it will hit the cache because of the previous find query).
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
+ /*
68
+ We first get the entity name of the Collection and together with its options (see groupPrimaryKeysByEntityAndOpts
69
+ for a full explanation) we use it as the key of the first Map.
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
+ 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
+ its keys are the props we are going to filter to and its values are the corresponding PKs.
73
+ */
74
+ const key = `${col.property.targetMeta.className}|${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((0, wrap_1.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 strigified 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 className = key.substring(0, key.indexOf('|'));
102
+ const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
103
+ const res = await em.find(className, opts?.where != null && Object.keys(opts.where).length > 0 ?
104
+ {
105
+ $and: [
106
+ {
107
+ $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
108
+ return ({ [prop]: Array.from(pks) });
109
+ }),
110
+ },
111
+ opts.where,
112
+ ],
113
+ } : {
114
+ // The entries of the filter Map will be used as the values of the $or operator
115
+ $or: Array.from(filterMap.entries()).map(([prop, pks]) => {
116
+ return ({ [prop]: Array.from(pks) });
117
+ }),
118
+ }, {
119
+ ...opts,
120
+ // 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)
121
+ populate: [
122
+ ...(opts.populate === false ? [] : opts.populate ?? []),
123
+ ...(opts.ref ? [':ref'] : []),
124
+ ...Array.from(filterMap.keys()).filter(
125
+ // 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
126
+ prop => em.getMetadata(className).properties[prop]?.ref !== true),
127
+ ],
128
+ });
129
+ return [key, res];
130
+ });
131
+ }
132
+ /**
133
+ * Creates a filter which returns the results pertaining to a certain collection.
134
+ * First checks if the Entity type matches, then retrieves the inverse side of the relationship
135
+ * where the filtering will be done in order to match the target collection.
136
+ */
137
+ static getColFilter(collection) {
138
+ return (result) => {
139
+ // There is no need to check if Entity matches because we already matched the key which is entity+options.
140
+ // This is the inverse side of the relationship where the filtering will be done in order to match the target collection
141
+ // Either inversedBy or mappedBy exist because we already checked in groupInversedOrMappedKeysByEntity
142
+ const refOrCol = result[(collection.property.inversedBy ?? collection.property.mappedBy)];
143
+ if (refOrCol instanceof Collection_1.Collection) {
144
+ // The inverse side is a Collection
145
+ // We keep the result if any of PKs of the inverse side matches the PK of the collection owner
146
+ for (const item of refOrCol.getItems()) {
147
+ if ((0, wrap_1.helper)(item).getSerializedPrimaryKey() === (0, wrap_1.helper)(collection.owner).getSerializedPrimaryKey()) {
148
+ return true;
149
+ }
150
+ }
151
+ }
152
+ else {
153
+ // The inverse side is a Reference
154
+ // We keep the result if the PK of the inverse side matches the PK of the collection owner
155
+ return (0, wrap_1.helper)(refOrCol).getSerializedPrimaryKey() === (0, wrap_1.helper)(collection.owner).getSerializedPrimaryKey();
156
+ }
157
+ return false;
158
+ };
159
+ }
160
+ /**
161
+ * Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
162
+ * makes one query per entity and maps each input collection to the corresponging result.
163
+ */
164
+ static getColBatchLoadFn(em) {
165
+ return async (collsWithOpts) => {
166
+ const entitiesAndOptsMap = DataloaderUtils.groupInversedOrMappedKeysByEntityAndOpts(collsWithOpts);
167
+ const promises = DataloaderUtils.entitiesAndOptsMapToQueries(entitiesAndOptsMap, em);
168
+ const resultsMap = new Map(await Promise.all(promises));
169
+ // We need to filter the results in order to map each input collection
170
+ // to a subset of each query matching the collection items.
171
+ return collsWithOpts.map(([col, opts]) => {
172
+ const key = `${col.property.targetMeta.className}|${JSON.stringify(opts ?? {})}`;
173
+ const entities = resultsMap.get(key);
174
+ if (entities == null) {
175
+ // Should never happen
176
+ /* istanbul ignore next */
177
+ throw new Error('Cannot match results');
178
+ }
179
+ return entities.filter(DataloaderUtils.getColFilter(col));
180
+ });
181
+ };
182
+ }
183
+ static getDataloaderType(dataloaderCfg) {
184
+ switch (dataloaderCfg) {
185
+ case true:
186
+ return enums_1.DataloaderType.ALL;
187
+ case false:
188
+ return enums_1.DataloaderType.NONE;
189
+ default:
190
+ return dataloaderCfg;
191
+ }
192
+ }
193
+ }
194
+ exports.DataloaderUtils = DataloaderUtils;
@@ -0,0 +1,73 @@
1
+ import type { EntityData, EntityDictionary, EntityMetadata, EntityProperty, IMetadataStorage } from '../typings';
2
+ import type { Platform } from '../platforms';
3
+ type Comparator<T> = (a: T, b: T) => EntityData<T>;
4
+ type ResultMapper<T> = (result: EntityData<T>) => EntityData<T> | null;
5
+ type SnapshotGenerator<T> = (entity: T) => EntityData<T>;
6
+ export declare class EntityComparator {
7
+ private readonly metadata;
8
+ private readonly platform;
9
+ private readonly comparators;
10
+ private readonly mappers;
11
+ private readonly snapshotGenerators;
12
+ private readonly pkGetters;
13
+ private readonly pkGettersConverted;
14
+ private readonly pkSerializers;
15
+ private tmpIndex;
16
+ constructor(metadata: IMetadataStorage, platform: Platform);
17
+ /**
18
+ * Computes difference between two entities.
19
+ */
20
+ diffEntities<T>(entityName: string, a: EntityData<T>, b: EntityData<T>): EntityData<T>;
21
+ matching<T>(entityName: string, a: EntityData<T>, b: EntityData<T>): boolean;
22
+ /**
23
+ * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
24
+ * References will be mapped to primary keys, collections to arrays of primary keys.
25
+ */
26
+ prepareEntity<T>(entity: T): EntityData<T>;
27
+ /**
28
+ * Maps database columns to properties.
29
+ */
30
+ mapResult<T>(entityName: string, result: EntityDictionary<T>): EntityData<T>;
31
+ /**
32
+ * @internal Highly performance-sensitive method.
33
+ */
34
+ getPkGetter<T>(meta: EntityMetadata<T>): any;
35
+ /**
36
+ * @internal Highly performance-sensitive method.
37
+ */
38
+ getPkGetterConverted<T>(meta: EntityMetadata<T>): any;
39
+ /**
40
+ * @internal Highly performance-sensitive method.
41
+ */
42
+ getPkSerializer<T>(meta: EntityMetadata<T>): any;
43
+ /**
44
+ * @internal Highly performance-sensitive method.
45
+ */
46
+ getSnapshotGenerator<T>(entityName: string): SnapshotGenerator<T>;
47
+ /**
48
+ * @internal Highly performance-sensitive method.
49
+ */
50
+ getResultMapper<T>(entityName: string): ResultMapper<T>;
51
+ private getPropertyCondition;
52
+ private getEmbeddedArrayPropertySnapshot;
53
+ /**
54
+ * we need to serialize only object embeddables, and only the top level ones, so root object embeddable
55
+ * properties and first child nested object embeddables with inlined parent
56
+ */
57
+ private shouldSerialize;
58
+ private getEmbeddedPropertySnapshot;
59
+ private getPropertySnapshot;
60
+ /**
61
+ * @internal Highly performance-sensitive method.
62
+ */
63
+ getEntityComparator<T extends object>(entityName: string): Comparator<T>;
64
+ private getGenericComparator;
65
+ private getPropertyComparator;
66
+ private wrap;
67
+ private safeKey;
68
+ /**
69
+ * perf: used to generate list of comparable properties during discovery, so we speed up the runtime comparison
70
+ */
71
+ static isComparable<T>(prop: EntityProperty<T>, root: EntityMetadata): boolean;
72
+ }
73
+ export {};