@mikro-orm/core 7.0.0-dev.1 → 7.0.0-dev.100

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 (281) hide show
  1. package/EntityManager.d.ts +96 -58
  2. package/EntityManager.js +465 -395
  3. package/MikroORM.d.ts +45 -35
  4. package/MikroORM.js +109 -160
  5. package/README.md +3 -2
  6. package/cache/CacheAdapter.js +1 -2
  7. package/cache/FileCacheAdapter.d.ts +2 -2
  8. package/cache/FileCacheAdapter.js +20 -27
  9. package/cache/GeneratedCacheAdapter.d.ts +2 -3
  10. package/cache/GeneratedCacheAdapter.js +1 -7
  11. package/cache/MemoryCacheAdapter.d.ts +1 -1
  12. package/cache/MemoryCacheAdapter.js +1 -5
  13. package/cache/NullCacheAdapter.d.ts +1 -1
  14. package/cache/NullCacheAdapter.js +1 -5
  15. package/cache/index.d.ts +4 -5
  16. package/cache/index.js +4 -21
  17. package/connections/Connection.d.ts +22 -14
  18. package/connections/Connection.js +27 -23
  19. package/connections/index.d.ts +1 -1
  20. package/connections/index.js +1 -17
  21. package/drivers/DatabaseDriver.d.ts +25 -15
  22. package/drivers/DatabaseDriver.js +77 -64
  23. package/drivers/IDatabaseDriver.d.ts +40 -16
  24. package/drivers/IDatabaseDriver.js +1 -4
  25. package/drivers/index.d.ts +2 -2
  26. package/drivers/index.js +2 -18
  27. package/entity/BaseEntity.d.ts +6 -7
  28. package/entity/BaseEntity.js +16 -23
  29. package/entity/Collection.d.ts +98 -34
  30. package/entity/Collection.js +466 -131
  31. package/entity/EntityAssigner.d.ts +3 -3
  32. package/entity/EntityAssigner.js +67 -64
  33. package/entity/EntityFactory.d.ts +10 -3
  34. package/entity/EntityFactory.js +112 -91
  35. package/entity/EntityHelper.d.ts +2 -2
  36. package/entity/EntityHelper.js +66 -53
  37. package/entity/EntityIdentifier.d.ts +1 -1
  38. package/entity/EntityIdentifier.js +1 -5
  39. package/entity/EntityLoader.d.ts +8 -7
  40. package/entity/EntityLoader.js +161 -128
  41. package/entity/EntityRepository.d.ts +8 -8
  42. package/entity/EntityRepository.js +7 -11
  43. package/entity/Reference.d.ts +10 -13
  44. package/entity/Reference.js +64 -46
  45. package/entity/WrappedEntity.d.ts +12 -17
  46. package/entity/WrappedEntity.js +22 -31
  47. package/entity/defineEntity.d.ts +568 -0
  48. package/entity/defineEntity.js +529 -0
  49. package/entity/index.d.ts +14 -13
  50. package/entity/index.js +14 -29
  51. package/entity/utils.d.ts +8 -1
  52. package/entity/utils.js +22 -13
  53. package/entity/validators.d.ts +11 -0
  54. package/entity/validators.js +65 -0
  55. package/entity/wrap.d.ts +1 -1
  56. package/entity/wrap.js +2 -6
  57. package/enums.d.ts +24 -9
  58. package/enums.js +50 -41
  59. package/errors.d.ts +11 -3
  60. package/errors.js +42 -32
  61. package/events/EventManager.d.ts +5 -4
  62. package/events/EventManager.js +26 -22
  63. package/events/EventSubscriber.d.ts +8 -5
  64. package/events/EventSubscriber.js +1 -2
  65. package/events/TransactionEventBroadcaster.d.ts +3 -3
  66. package/events/TransactionEventBroadcaster.js +1 -5
  67. package/events/index.d.ts +3 -3
  68. package/events/index.js +3 -19
  69. package/exceptions.js +18 -39
  70. package/hydration/Hydrator.d.ts +5 -5
  71. package/hydration/Hydrator.js +2 -6
  72. package/hydration/ObjectHydrator.d.ts +7 -7
  73. package/hydration/ObjectHydrator.js +58 -50
  74. package/hydration/index.d.ts +2 -2
  75. package/hydration/index.js +2 -18
  76. package/index.d.ts +21 -21
  77. package/index.js +20 -46
  78. package/logging/DefaultLogger.d.ts +2 -2
  79. package/logging/DefaultLogger.js +10 -13
  80. package/logging/Logger.d.ts +1 -1
  81. package/logging/Logger.js +1 -2
  82. package/logging/SimpleLogger.d.ts +3 -3
  83. package/logging/SimpleLogger.js +2 -6
  84. package/logging/colors.js +1 -5
  85. package/logging/index.d.ts +5 -4
  86. package/logging/index.js +5 -20
  87. package/logging/inspect.d.ts +2 -0
  88. package/logging/inspect.js +16 -0
  89. package/metadata/EntitySchema.d.ts +14 -10
  90. package/metadata/EntitySchema.js +78 -64
  91. package/metadata/MetadataDiscovery.d.ts +11 -14
  92. package/metadata/MetadataDiscovery.js +278 -317
  93. package/metadata/MetadataProvider.d.ts +13 -4
  94. package/metadata/MetadataProvider.js +47 -8
  95. package/metadata/MetadataStorage.d.ts +2 -7
  96. package/metadata/MetadataStorage.js +19 -35
  97. package/metadata/MetadataValidator.d.ts +3 -10
  98. package/metadata/MetadataValidator.js +51 -64
  99. package/metadata/discover-entities.d.ts +5 -0
  100. package/metadata/discover-entities.js +40 -0
  101. package/metadata/index.d.ts +6 -6
  102. package/metadata/index.js +6 -22
  103. package/metadata/types.d.ts +480 -0
  104. package/metadata/types.js +1 -0
  105. package/naming-strategy/AbstractNamingStrategy.d.ts +7 -3
  106. package/naming-strategy/AbstractNamingStrategy.js +11 -9
  107. package/naming-strategy/EntityCaseNamingStrategy.d.ts +1 -1
  108. package/naming-strategy/EntityCaseNamingStrategy.js +2 -6
  109. package/naming-strategy/MongoNamingStrategy.d.ts +1 -1
  110. package/naming-strategy/MongoNamingStrategy.js +2 -6
  111. package/naming-strategy/NamingStrategy.d.ts +12 -2
  112. package/naming-strategy/NamingStrategy.js +1 -2
  113. package/naming-strategy/UnderscoreNamingStrategy.d.ts +1 -1
  114. package/naming-strategy/UnderscoreNamingStrategy.js +2 -6
  115. package/naming-strategy/index.d.ts +5 -5
  116. package/naming-strategy/index.js +5 -21
  117. package/not-supported.d.ts +2 -0
  118. package/not-supported.js +4 -0
  119. package/package.json +19 -20
  120. package/platforms/ExceptionConverter.d.ts +2 -2
  121. package/platforms/ExceptionConverter.js +4 -8
  122. package/platforms/Platform.d.ts +15 -22
  123. package/platforms/Platform.js +58 -88
  124. package/platforms/index.d.ts +2 -2
  125. package/platforms/index.js +2 -18
  126. package/serialization/EntitySerializer.d.ts +4 -2
  127. package/serialization/EntitySerializer.js +64 -51
  128. package/serialization/EntityTransformer.d.ts +1 -1
  129. package/serialization/EntityTransformer.js +48 -42
  130. package/serialization/SerializationContext.d.ts +2 -2
  131. package/serialization/SerializationContext.js +24 -25
  132. package/serialization/index.d.ts +3 -3
  133. package/serialization/index.js +3 -19
  134. package/types/ArrayType.d.ts +3 -3
  135. package/types/ArrayType.js +6 -11
  136. package/types/BigIntType.d.ts +12 -9
  137. package/types/BigIntType.js +6 -6
  138. package/types/BlobType.d.ts +3 -4
  139. package/types/BlobType.js +2 -11
  140. package/types/BooleanType.d.ts +5 -4
  141. package/types/BooleanType.js +5 -6
  142. package/types/CharacterType.d.ts +3 -3
  143. package/types/CharacterType.js +2 -6
  144. package/types/DateTimeType.d.ts +3 -3
  145. package/types/DateTimeType.js +2 -6
  146. package/types/DateType.d.ts +3 -3
  147. package/types/DateType.js +2 -6
  148. package/types/DecimalType.d.ts +9 -7
  149. package/types/DecimalType.js +5 -8
  150. package/types/DoubleType.d.ts +3 -3
  151. package/types/DoubleType.js +4 -7
  152. package/types/EnumArrayType.d.ts +4 -4
  153. package/types/EnumArrayType.js +4 -10
  154. package/types/EnumType.d.ts +3 -3
  155. package/types/EnumType.js +2 -6
  156. package/types/FloatType.d.ts +3 -3
  157. package/types/FloatType.js +2 -6
  158. package/types/IntegerType.d.ts +3 -3
  159. package/types/IntegerType.js +2 -6
  160. package/types/IntervalType.d.ts +3 -3
  161. package/types/IntervalType.js +2 -6
  162. package/types/JsonType.d.ts +4 -4
  163. package/types/JsonType.js +9 -8
  164. package/types/MediumIntType.d.ts +3 -3
  165. package/types/MediumIntType.js +2 -6
  166. package/types/SmallIntType.d.ts +3 -3
  167. package/types/SmallIntType.js +2 -6
  168. package/types/StringType.d.ts +3 -3
  169. package/types/StringType.js +2 -6
  170. package/types/TextType.d.ts +3 -3
  171. package/types/TextType.js +2 -6
  172. package/types/TimeType.d.ts +3 -3
  173. package/types/TimeType.js +4 -8
  174. package/types/TinyIntType.d.ts +3 -3
  175. package/types/TinyIntType.js +3 -6
  176. package/types/Type.d.ts +4 -6
  177. package/types/Type.js +6 -10
  178. package/types/Uint8ArrayType.d.ts +3 -4
  179. package/types/Uint8ArrayType.js +3 -12
  180. package/types/UnknownType.d.ts +3 -3
  181. package/types/UnknownType.js +2 -6
  182. package/types/UuidType.d.ts +3 -3
  183. package/types/UuidType.js +2 -6
  184. package/types/index.d.ts +25 -25
  185. package/types/index.js +52 -79
  186. package/typings.d.ts +134 -93
  187. package/typings.js +67 -65
  188. package/unit-of-work/ChangeSet.d.ts +1 -4
  189. package/unit-of-work/ChangeSet.js +13 -17
  190. package/unit-of-work/ChangeSetComputer.d.ts +8 -9
  191. package/unit-of-work/ChangeSetComputer.js +36 -38
  192. package/unit-of-work/ChangeSetPersister.d.ts +11 -9
  193. package/unit-of-work/ChangeSetPersister.js +100 -65
  194. package/unit-of-work/CommitOrderCalculator.d.ts +1 -1
  195. package/unit-of-work/CommitOrderCalculator.js +6 -10
  196. package/unit-of-work/IdentityMap.d.ts +1 -1
  197. package/unit-of-work/IdentityMap.js +1 -5
  198. package/unit-of-work/UnitOfWork.d.ts +16 -8
  199. package/unit-of-work/UnitOfWork.js +266 -209
  200. package/unit-of-work/index.d.ts +6 -6
  201. package/unit-of-work/index.js +6 -22
  202. package/utils/AbstractSchemaGenerator.d.ts +11 -11
  203. package/utils/AbstractSchemaGenerator.js +21 -20
  204. package/utils/Configuration.d.ts +774 -224
  205. package/utils/Configuration.js +166 -216
  206. package/utils/ConfigurationLoader.d.ts +1 -53
  207. package/utils/ConfigurationLoader.js +1 -367
  208. package/utils/Cursor.d.ts +6 -9
  209. package/utils/Cursor.js +25 -25
  210. package/utils/DataloaderUtils.d.ts +18 -8
  211. package/utils/DataloaderUtils.js +63 -21
  212. package/utils/EntityComparator.d.ts +9 -5
  213. package/utils/EntityComparator.js +155 -108
  214. package/utils/NullHighlighter.d.ts +1 -1
  215. package/utils/NullHighlighter.js +1 -5
  216. package/utils/QueryHelper.d.ts +12 -4
  217. package/utils/QueryHelper.js +110 -53
  218. package/utils/RawQueryFragment.d.ts +37 -14
  219. package/utils/RawQueryFragment.js +50 -33
  220. package/utils/RequestContext.d.ts +2 -2
  221. package/utils/RequestContext.js +3 -7
  222. package/utils/TransactionContext.d.ts +1 -1
  223. package/utils/TransactionContext.js +4 -8
  224. package/utils/TransactionManager.d.ts +65 -0
  225. package/utils/TransactionManager.js +223 -0
  226. package/utils/Utils.d.ts +16 -100
  227. package/utils/Utils.js +114 -332
  228. package/utils/clone.js +7 -11
  229. package/utils/env-vars.d.ts +3 -0
  230. package/utils/env-vars.js +87 -0
  231. package/utils/fs-utils.d.ts +12 -0
  232. package/utils/fs-utils.js +97 -0
  233. package/utils/index.d.ts +14 -13
  234. package/utils/index.js +14 -29
  235. package/utils/upsert-utils.d.ts +8 -3
  236. package/utils/upsert-utils.js +57 -10
  237. package/decorators/Check.d.ts +0 -3
  238. package/decorators/Check.js +0 -16
  239. package/decorators/CreateRequestContext.d.ts +0 -3
  240. package/decorators/CreateRequestContext.js +0 -33
  241. package/decorators/Embeddable.d.ts +0 -8
  242. package/decorators/Embeddable.js +0 -14
  243. package/decorators/Embedded.d.ts +0 -18
  244. package/decorators/Embedded.js +0 -20
  245. package/decorators/Entity.d.ts +0 -18
  246. package/decorators/Entity.js +0 -16
  247. package/decorators/Enum.d.ts +0 -9
  248. package/decorators/Enum.js +0 -19
  249. package/decorators/Filter.d.ts +0 -2
  250. package/decorators/Filter.js +0 -11
  251. package/decorators/Formula.d.ts +0 -5
  252. package/decorators/Formula.js +0 -18
  253. package/decorators/Indexed.d.ts +0 -17
  254. package/decorators/Indexed.js +0 -24
  255. package/decorators/ManyToMany.d.ts +0 -40
  256. package/decorators/ManyToMany.js +0 -16
  257. package/decorators/ManyToOne.d.ts +0 -30
  258. package/decorators/ManyToOne.js +0 -16
  259. package/decorators/OneToMany.d.ts +0 -28
  260. package/decorators/OneToMany.js +0 -20
  261. package/decorators/OneToOne.d.ts +0 -24
  262. package/decorators/OneToOne.js +0 -10
  263. package/decorators/PrimaryKey.d.ts +0 -9
  264. package/decorators/PrimaryKey.js +0 -23
  265. package/decorators/Property.d.ts +0 -250
  266. package/decorators/Property.js +0 -34
  267. package/decorators/Transactional.d.ts +0 -13
  268. package/decorators/Transactional.js +0 -31
  269. package/decorators/hooks.d.ts +0 -16
  270. package/decorators/hooks.js +0 -59
  271. package/decorators/index.d.ts +0 -17
  272. package/decorators/index.js +0 -36
  273. package/entity/ArrayCollection.d.ts +0 -116
  274. package/entity/ArrayCollection.js +0 -399
  275. package/entity/EntityValidator.d.ts +0 -19
  276. package/entity/EntityValidator.js +0 -154
  277. package/index.mjs +0 -199
  278. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  279. package/metadata/ReflectMetadataProvider.js +0 -48
  280. package/utils/resolveContextProvider.d.ts +0 -10
  281. package/utils/resolveContextProvider.js +0 -31
@@ -1,20 +1,29 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Collection = void 0;
4
- const ArrayCollection_1 = require("./ArrayCollection");
5
- const Utils_1 = require("../utils/Utils");
6
- const errors_1 = require("../errors");
7
- const enums_1 = require("../enums");
8
- const Reference_1 = require("./Reference");
9
- const wrap_1 = require("./wrap");
10
- class Collection extends ArrayCollection_1.ArrayCollection {
1
+ import { Utils } from '../utils/Utils.js';
2
+ import { MetadataError, ValidationError } from '../errors.js';
3
+ import { DataloaderType, ReferenceKind } from '../enums.js';
4
+ import { Reference } from './Reference.js';
5
+ import { helper, wrap } from './wrap.js';
6
+ import { QueryHelper } from '../utils/QueryHelper.js';
7
+ import { inspect } from '../logging/inspect.js';
8
+ export class Collection {
9
+ owner;
10
+ items = new Set();
11
+ initialized = true;
12
+ dirty = false;
13
+ partial = false; // mark partially loaded collections, propagation is disabled for those
14
+ snapshot = []; // used to create a diff of the collection at commit time, undefined marks overridden values so we need to wipe when flushing
11
15
  readonly;
16
+ _count;
17
+ _property;
12
18
  _populated;
13
- _em;
14
- // this is for some reason needed for TS, otherwise it can fail with `Type instantiation is excessively deep and possibly infinite.`
15
- _snapshot;
16
19
  constructor(owner, items, initialized = true) {
17
- super(owner, items);
20
+ this.owner = owner;
21
+ /* v8 ignore next */
22
+ if (items) {
23
+ let i = 0;
24
+ this.items = new Set(items);
25
+ this.items.forEach(item => this[i++] = item);
26
+ }
18
27
  this.initialized = !!items || initialized;
19
28
  }
20
29
  /**
@@ -22,7 +31,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
22
31
  */
23
32
  static create(owner, prop, items, initialized) {
24
33
  const coll = new Collection(owner, undefined, initialized);
25
- coll.property = (0, wrap_1.helper)(owner).__meta.properties[prop];
34
+ coll.property = helper(owner).__meta.properties[prop];
26
35
  owner[prop] = coll;
27
36
  if (items) {
28
37
  coll.set(items);
@@ -36,6 +45,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
36
45
  async load(options = {}) {
37
46
  if (this.isInitialized(true) && !options.refresh) {
38
47
  const em = this.getEntityManager(this.items, false);
48
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
39
49
  await em?.populate(this.items, options.populate, options);
40
50
  this.setSerializationContext(options);
41
51
  }
@@ -45,7 +55,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
45
55
  return this;
46
56
  }
47
57
  setSerializationContext(options) {
48
- (0, wrap_1.helper)(this.owner).setSerializationContext({
58
+ helper(this.owner).setSerializationContext({
49
59
  populate: Array.isArray(options.populate)
50
60
  ? options.populate.map(hint => `${this.property.name}.${hint}`)
51
61
  : options.populate ?? [this.property.name],
@@ -56,7 +66,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
56
66
  */
57
67
  async loadItems(options) {
58
68
  await this.load(options);
59
- return super.getItems();
69
+ return this.getItems(false);
60
70
  }
61
71
  /**
62
72
  * Gets the count of collection items from database instead of counting loaded items.
@@ -65,11 +75,11 @@ class Collection extends ArrayCollection_1.ArrayCollection {
65
75
  async loadCount(options = {}) {
66
76
  options = typeof options === 'boolean' ? { refresh: options } : options;
67
77
  const { refresh, where, ...countOptions } = options;
68
- if (!refresh && !where && Utils_1.Utils.isDefined(this._count)) {
78
+ if (!refresh && !where && this._count != null) {
69
79
  return this._count;
70
80
  }
71
81
  const em = this.getEntityManager();
72
- if (!em.getPlatform().usesPivotTable() && this.property.kind === enums_1.ReferenceKind.MANY_TO_MANY && this.property.owner) {
82
+ if (!em.getPlatform().usesPivotTable() && this.property.kind === ReferenceKind.MANY_TO_MANY && this.property.owner) {
73
83
  return this._count = this.length;
74
84
  }
75
85
  const cond = this.createLoadCountCondition(where ?? {});
@@ -84,10 +94,10 @@ class Collection extends ArrayCollection_1.ArrayCollection {
84
94
  const { where, ctx, ...opts } = options;
85
95
  opts.orderBy = this.createOrderBy(opts.orderBy);
86
96
  let items;
87
- if (this.property.kind === enums_1.ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable()) {
97
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable()) {
88
98
  const cond = await em.applyFilters(this.property.type, where, options.filters ?? {}, 'read');
89
- const map = await em.getDriver().loadFromPivotTable(this.property, [(0, wrap_1.helper)(this.owner).__primaryKeys], cond, opts.orderBy, ctx, options);
90
- items = map[(0, wrap_1.helper)(this.owner).getSerializedPrimaryKey()].map((item) => em.merge(this.property.type, item, { convertCustomTypes: true }));
99
+ const map = await em.getDriver().loadFromPivotTable(this.property, [helper(this.owner).__primaryKeys], cond, opts.orderBy, ctx, options);
100
+ items = map[helper(this.owner).getSerializedPrimaryKey()].map((item) => em.merge(this.property.type, item, { convertCustomTypes: true }));
91
101
  }
92
102
  else {
93
103
  items = await em.find(this.property.type, this.createCondition(where), opts);
@@ -107,98 +117,97 @@ class Collection extends ArrayCollection_1.ArrayCollection {
107
117
  if (check) {
108
118
  this.checkInitialized();
109
119
  }
110
- return super.getItems();
120
+ return [...this.items];
111
121
  }
112
122
  toJSON() {
113
123
  if (!this.isInitialized()) {
114
124
  return [];
115
125
  }
116
- return super.toJSON();
126
+ return this.toArray();
117
127
  }
118
128
  add(entity, ...entities) {
119
- entities = Utils_1.Utils.asArray(entity).concat(entities);
120
- const unwrapped = entities.map(i => Reference_1.Reference.unwrapReference(i));
121
- unwrapped.forEach(entity => this.validateItemType(entity));
122
- this.modify('add', unwrapped);
129
+ entities = Utils.asArray(entity).concat(entities);
130
+ const unwrapped = entities.map(i => Reference.unwrapReference(i));
131
+ this.validateModification(unwrapped);
132
+ const em = this.getEntityManager(entities, false);
133
+ let added = 0;
134
+ for (const item of entities) {
135
+ const entity = Reference.unwrapReference(item);
136
+ if (!this.contains(entity, false)) {
137
+ this.incrementCount(1);
138
+ this[this.items.size] = entity;
139
+ this.items.add(entity);
140
+ added++;
141
+ this.dirty = true;
142
+ this.propagate(entity, 'add');
143
+ }
144
+ }
145
+ if (this.property.kind === ReferenceKind.ONE_TO_MANY && em) {
146
+ em.persist(entities);
147
+ }
123
148
  this.cancelOrphanRemoval(unwrapped);
149
+ return added;
124
150
  }
125
151
  /**
126
- * @inheritDoc
152
+ * Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
153
+ * it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
154
+ * is not the same as `em.remove()`. If we want to delete the entity by removing it from collection, we need to enable `orphanRemoval: true`,
155
+ * which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
127
156
  */
128
157
  remove(entity, ...entities) {
129
158
  if (entity instanceof Function) {
159
+ let removed = 0;
130
160
  for (const item of this.items) {
131
161
  if (entity(item)) {
132
- this.remove(item);
162
+ removed += this.remove(item);
133
163
  }
134
164
  }
135
- return;
165
+ return removed;
136
166
  }
137
- entities = Utils_1.Utils.asArray(entity).concat(entities);
138
- const unwrapped = entities.map(i => Reference_1.Reference.unwrapReference(i));
139
- this.modify('remove', unwrapped);
140
- const em = this.getEntityManager(unwrapped, false);
141
- if (this.property.orphanRemoval && em) {
142
- for (const item of unwrapped) {
143
- em.getUnitOfWork().scheduleOrphanRemoval(item);
167
+ this.checkInitialized();
168
+ entities = Utils.asArray(entity).concat(entities);
169
+ const unwrapped = entities.map(i => Reference.unwrapReference(i));
170
+ this.validateModification(unwrapped);
171
+ const em = this.getEntityManager(entities, false);
172
+ let removed = 0;
173
+ for (const item of entities) {
174
+ if (!item) {
175
+ continue;
176
+ }
177
+ const entity = Reference.unwrapReference(item);
178
+ if (this.items.delete(entity)) {
179
+ this.incrementCount(-1);
180
+ delete this[this.items.size]; // remove last item
181
+ this.propagate(entity, 'remove');
182
+ removed++;
183
+ this.dirty = true;
144
184
  }
185
+ if (this.property.orphanRemoval && em) {
186
+ em.getUnitOfWork().scheduleOrphanRemoval(entity);
187
+ }
188
+ }
189
+ if (this.property.kind === ReferenceKind.ONE_TO_MANY && !this.property.orphanRemoval && em) {
190
+ em.persist(entities);
191
+ }
192
+ if (removed > 0) {
193
+ Object.assign(this, [...this.items]); // reassign array access
145
194
  }
195
+ return removed;
146
196
  }
147
197
  contains(item, check = true) {
148
198
  if (check) {
149
199
  this.checkInitialized();
150
200
  }
151
- return super.contains(item);
201
+ const entity = Reference.unwrapReference(item);
202
+ return this.items.has(entity);
152
203
  }
153
204
  count() {
154
205
  this.checkInitialized();
155
- return super.count();
206
+ return this.items.size;
156
207
  }
157
208
  isEmpty() {
158
209
  this.checkInitialized();
159
- return super.isEmpty();
160
- }
161
- /**
162
- * @inheritDoc
163
- */
164
- slice(start, end) {
165
- this.checkInitialized();
166
- return super.slice(start, end);
167
- }
168
- /**
169
- * @inheritDoc
170
- */
171
- exists(cb) {
172
- this.checkInitialized();
173
- return super.exists(cb);
174
- }
175
- /**
176
- * @inheritDoc
177
- */
178
- find(cb) {
179
- this.checkInitialized();
180
- return super.find(cb);
181
- }
182
- /**
183
- * @inheritDoc
184
- */
185
- filter(cb) {
186
- this.checkInitialized();
187
- return super.filter(cb);
188
- }
189
- /**
190
- * @inheritDoc
191
- */
192
- map(mapper) {
193
- this.checkInitialized();
194
- return super.map(mapper);
195
- }
196
- /**
197
- * @inheritDoc
198
- */
199
- indexBy(key, valueKey) {
200
- this.checkInitialized();
201
- return super.indexBy(key, valueKey);
210
+ return this.count() === 0;
202
211
  }
203
212
  shouldPopulate(populated) {
204
213
  if (!this.isInitialized(true)) {
@@ -221,13 +230,21 @@ class Collection extends ArrayCollection_1.ArrayCollection {
221
230
  return this;
222
231
  }
223
232
  const em = this.getEntityManager();
224
- if (options.dataloader ?? [enums_1.DataloaderType.ALL, enums_1.DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
233
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
234
+ if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
225
235
  const order = [...this.items]; // copy order of references
226
- const customOrder = !!options.orderBy;
227
- // eslint-disable-next-line dot-notation
228
- const items = await em['colLoader'].load([this, options]);
229
- if (!customOrder) {
230
- this.reorderItems(items, order);
236
+ const orderBy = this.createOrderBy(options.orderBy);
237
+ const customOrder = orderBy.length > 0;
238
+ const pivotTable = this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable();
239
+ const loader = await em.getDataLoader(pivotTable ? 'm:n' : '1:m');
240
+ const items = await loader.load([this, { ...options, orderBy }]);
241
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
242
+ this.initialized = true;
243
+ this.dirty = false;
244
+ if (!customOrder) {
245
+ this.reorderItems(items, order);
246
+ }
247
+ return this;
231
248
  }
232
249
  this.items.clear();
233
250
  let i = 0;
@@ -243,7 +260,7 @@ class Collection extends ArrayCollection_1.ArrayCollection {
243
260
  ? options.populate.map(f => f === '*' ? f : `${this.property.name}.${f}`)
244
261
  : [`${this.property.name}${options.ref ? ':ref' : ''}`];
245
262
  const schema = this.property.targetMeta.schema === '*'
246
- ? (0, wrap_1.helper)(this.owner).__schema
263
+ ? helper(this.owner).__schema
247
264
  : undefined;
248
265
  await em.populate(this.owner, populate, {
249
266
  refresh: true,
@@ -256,27 +273,24 @@ class Collection extends ArrayCollection_1.ArrayCollection {
256
273
  return this;
257
274
  }
258
275
  getEntityManager(items = [], required = true) {
259
- const wrapped = (0, wrap_1.helper)(this.owner);
260
- let em = (this._em ?? wrapped.__em);
276
+ const wrapped = helper(this.owner);
277
+ let em = wrapped.__em;
261
278
  if (!em) {
262
279
  for (const i of items) {
263
- if (i && (0, wrap_1.helper)(i).__em) {
264
- em = (0, wrap_1.helper)(i).__em;
280
+ if (i && helper(i).__em) {
281
+ em = helper(i).__em;
265
282
  break;
266
283
  }
267
284
  }
268
285
  }
269
- if (em) {
270
- Object.defineProperty(this, '_em', { value: em });
271
- }
272
286
  if (!em && required) {
273
- throw errors_1.ValidationError.entityNotManaged(this.owner);
287
+ throw ValidationError.entityNotManaged(this.owner);
274
288
  }
275
289
  return em;
276
290
  }
277
291
  createCondition(cond = {}) {
278
- if (this.property.kind === enums_1.ReferenceKind.ONE_TO_MANY) {
279
- cond[this.property.mappedBy] = (0, wrap_1.helper)(this.owner).getPrimaryKey();
292
+ if (this.property.kind === ReferenceKind.ONE_TO_MANY) {
293
+ cond[this.property.mappedBy] = helper(this.owner).getPrimaryKey();
280
294
  }
281
295
  else { // MANY_TO_MANY
282
296
  this.createManyToManyCondition(cond);
@@ -284,10 +298,10 @@ class Collection extends ArrayCollection_1.ArrayCollection {
284
298
  return cond;
285
299
  }
286
300
  createOrderBy(orderBy = []) {
287
- if (Utils_1.Utils.isEmpty(orderBy) && this.property.orderBy) {
301
+ if (Utils.isEmpty(orderBy) && this.property.orderBy) {
288
302
  orderBy = this.property.orderBy;
289
303
  }
290
- return Utils_1.Utils.asArray(orderBy);
304
+ return Utils.asArray(orderBy);
291
305
  }
292
306
  createManyToManyCondition(cond) {
293
307
  const dict = cond;
@@ -295,17 +309,17 @@ class Collection extends ArrayCollection_1.ArrayCollection {
295
309
  // we know there is at least one item as it was checked in load method
296
310
  const pk = this.property.targetMeta.primaryKeys[0];
297
311
  dict[pk] = { $in: [] };
298
- this.items.forEach(item => dict[pk].$in.push((0, wrap_1.helper)(item).getPrimaryKey()));
312
+ this.items.forEach(item => dict[pk].$in.push(helper(item).getPrimaryKey()));
299
313
  }
300
314
  else {
301
- dict[this.property.mappedBy] = (0, wrap_1.helper)(this.owner).getPrimaryKey();
315
+ dict[this.property.mappedBy] = helper(this.owner).getPrimaryKey();
302
316
  }
303
317
  }
304
318
  createLoadCountCondition(cond) {
305
- const wrapped = (0, wrap_1.helper)(this.owner);
319
+ const wrapped = helper(this.owner);
306
320
  const val = wrapped.__meta.compositePK ? { $in: wrapped.__primaryKeys } : wrapped.getPrimaryKey();
307
321
  const dict = cond;
308
- if (this.property.kind === enums_1.ReferenceKind.ONE_TO_MANY) {
322
+ if (this.property.kind === ReferenceKind.ONE_TO_MANY) {
309
323
  dict[this.property.mappedBy] = val;
310
324
  }
311
325
  else {
@@ -314,24 +328,16 @@ class Collection extends ArrayCollection_1.ArrayCollection {
314
328
  }
315
329
  return cond;
316
330
  }
317
- modify(method, items) {
318
- if (method === 'remove') {
319
- this.checkInitialized();
320
- }
321
- this.validateModification(items);
322
- super[method](items);
323
- this.setDirty();
324
- }
325
331
  checkInitialized() {
326
332
  if (!this.isInitialized()) {
327
- throw new Error(`Collection<${this.property.type}> of entity ${this.owner.constructor.name}[${(0, wrap_1.helper)(this.owner).getSerializedPrimaryKey()}] not initialized`);
333
+ throw new Error(`Collection<${this.property.type}> of entity ${this.owner.constructor.name}[${helper(this.owner).getSerializedPrimaryKey()}] not initialized`);
328
334
  }
329
335
  }
330
336
  /**
331
337
  * re-orders items after searching with `$in` operator
332
338
  */
333
339
  reorderItems(items, order) {
334
- if (this.property.kind === enums_1.ReferenceKind.MANY_TO_MANY && this.property.owner) {
340
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY && this.property.owner) {
335
341
  items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
336
342
  }
337
343
  }
@@ -344,33 +350,362 @@ class Collection extends ArrayCollection_1.ArrayCollection {
344
350
  em.getUnitOfWork().cancelOrphanRemoval(item);
345
351
  }
346
352
  }
347
- validateItemType(item) {
348
- if (!Utils_1.Utils.isEntity(item)) {
349
- throw errors_1.ValidationError.notEntity(this.owner, this.property, item);
350
- }
351
- }
352
353
  validateModification(items) {
353
354
  if (this.readonly) {
354
- throw errors_1.ValidationError.cannotModifyReadonlyCollection(this.owner, this.property);
355
- }
356
- // currently we allow persisting to inverse sides only in SQL drivers
357
- if (this.property.pivotTable || !this.property.mappedBy) {
358
- return;
355
+ throw ValidationError.cannotModifyReadonlyCollection(this.owner, this.property);
359
356
  }
360
357
  const check = (item) => {
361
- if (!item || (0, wrap_1.helper)(item).__initialized) {
358
+ if (!item) {
359
+ return false;
360
+ }
361
+ if (!Utils.isEntity(item)) {
362
+ throw ValidationError.notEntity(this.owner, this.property, item);
363
+ }
364
+ // currently we allow persisting to inverse sides only in SQL drivers
365
+ if (this.property.pivotTable || !this.property.mappedBy) {
362
366
  return false;
363
367
  }
364
- return !item[this.property.mappedBy] && this.property.kind === enums_1.ReferenceKind.MANY_TO_MANY;
368
+ if (helper(item).__initialized) {
369
+ return false;
370
+ }
371
+ return !item[this.property.mappedBy] && this.property.kind === ReferenceKind.MANY_TO_MANY;
365
372
  };
366
373
  // throw if we are modifying inverse side of M:N collection when owning side is initialized (would be ignored when persisting)
367
- if (items.find(item => check(item))) {
368
- throw errors_1.ValidationError.cannotModifyInverseCollection(this.owner, this.property);
374
+ if (items.some(item => check(item))) {
375
+ throw ValidationError.cannotModifyInverseCollection(this.owner, this.property);
376
+ }
377
+ }
378
+ toArray() {
379
+ if (this.items.size === 0) {
380
+ return [];
381
+ }
382
+ return this.map(item => wrap(item).toJSON());
383
+ }
384
+ getIdentifiers(field) {
385
+ const items = this.getItems();
386
+ const targetMeta = this.property.targetMeta;
387
+ if (items.length === 0) {
388
+ return [];
389
+ }
390
+ field ??= targetMeta.compositePK ? targetMeta.primaryKeys : (targetMeta.serializedPrimaryKey ?? targetMeta.primaryKeys[0]);
391
+ const cb = (i, f) => {
392
+ if (Utils.isEntity(i[f], true)) {
393
+ return wrap(i[f], true).getPrimaryKey();
394
+ }
395
+ return i[f];
396
+ };
397
+ return items.map(i => {
398
+ if (Array.isArray(field)) {
399
+ return field.map(f => cb(i, f));
400
+ }
401
+ return cb(i, field);
402
+ });
403
+ }
404
+ /**
405
+ * @internal
406
+ */
407
+ addWithoutPropagation(entity) {
408
+ if (!this.contains(entity, false)) {
409
+ this.incrementCount(1);
410
+ this[this.items.size] = entity;
411
+ this.items.add(entity);
412
+ this.dirty = true;
413
+ }
414
+ }
415
+ set(items) {
416
+ if (!this.initialized) {
417
+ this.initialized = true;
418
+ this.snapshot = undefined;
419
+ }
420
+ if (this.compare(Utils.asArray(items).map(item => Reference.unwrapReference(item)))) {
421
+ return;
422
+ }
423
+ this.remove(this.items);
424
+ this.add(items);
425
+ }
426
+ compare(items) {
427
+ if (items.length !== this.items.size) {
428
+ return false;
429
+ }
430
+ let idx = 0;
431
+ for (const item of this.items) {
432
+ if (item !== items[idx++]) {
433
+ return false;
434
+ }
435
+ }
436
+ return true;
437
+ }
438
+ /**
439
+ * @internal
440
+ */
441
+ hydrate(items, forcePropagate, partial) {
442
+ for (let i = 0; i < this.items.size; i++) {
443
+ delete this[i];
444
+ }
445
+ this.initialized = true;
446
+ this.partial = !!partial;
447
+ this.items.clear();
448
+ this._count = 0;
449
+ this.add(items);
450
+ this.takeSnapshot(forcePropagate);
451
+ }
452
+ /**
453
+ * Remove all items from the collection. Note that removing items from collection does not necessarily imply deleting the target entity,
454
+ * it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
455
+ * is not the same as `em.remove()`. If we want to delete the entity by removing it from collection, we need to enable `orphanRemoval: true`,
456
+ * which tells the ORM we don't want orphaned entities to exist, so we know those should be removed.
457
+ */
458
+ removeAll() {
459
+ if (!this.initialized) {
460
+ this.initialized = true;
461
+ this.snapshot = undefined;
462
+ }
463
+ this.remove(this.items);
464
+ this.dirty = true;
465
+ }
466
+ /**
467
+ * @internal
468
+ */
469
+ removeWithoutPropagation(entity) {
470
+ if (!this.items.delete(entity)) {
471
+ return;
472
+ }
473
+ this.incrementCount(-1);
474
+ delete this[this.items.size];
475
+ Object.assign(this, [...this.items]);
476
+ this.dirty = true;
477
+ }
478
+ /**
479
+ * Extracts a slice of the collection items starting at position start to end (exclusive) of the collection.
480
+ * If end is null it returns all elements from start to the end of the collection.
481
+ */
482
+ slice(start = 0, end) {
483
+ this.checkInitialized();
484
+ let index = 0;
485
+ end ??= this.items.size;
486
+ const items = [];
487
+ for (const item of this.items) {
488
+ if (index === end) {
489
+ break;
490
+ }
491
+ if (index >= start && index < end) {
492
+ items.push(item);
493
+ }
494
+ index++;
495
+ }
496
+ return items;
497
+ }
498
+ /**
499
+ * Tests for the existence of an element that satisfies the given predicate.
500
+ */
501
+ exists(cb) {
502
+ this.checkInitialized();
503
+ for (const item of this.items) {
504
+ if (cb(item)) {
505
+ return true;
506
+ }
507
+ }
508
+ return false;
509
+ }
510
+ /**
511
+ * Returns the first element of this collection that satisfies the predicate.
512
+ */
513
+ find(cb) {
514
+ this.checkInitialized();
515
+ let index = 0;
516
+ for (const item of this.items) {
517
+ if (cb(item, index++)) {
518
+ return item;
519
+ }
369
520
  }
521
+ return undefined;
522
+ }
523
+ /**
524
+ * Extracts a subset of the collection items.
525
+ */
526
+ filter(cb) {
527
+ this.checkInitialized();
528
+ const items = [];
529
+ let index = 0;
530
+ for (const item of this.items) {
531
+ if (cb(item, index++)) {
532
+ items.push(item);
533
+ }
534
+ }
535
+ return items;
536
+ }
537
+ /**
538
+ * Maps the collection items based on your provided mapper function.
539
+ */
540
+ map(mapper) {
541
+ this.checkInitialized();
542
+ const items = [];
543
+ let index = 0;
544
+ for (const item of this.items) {
545
+ items.push(mapper(item, index++));
546
+ }
547
+ return items;
548
+ }
549
+ /**
550
+ * Maps the collection items based on your provided mapper function to a single object.
551
+ */
552
+ reduce(cb, initial = {}) {
553
+ this.checkInitialized();
554
+ let index = 0;
555
+ for (const item of this.items) {
556
+ initial = cb(initial, item, index++);
557
+ }
558
+ return initial;
559
+ }
560
+ /**
561
+ * Maps the collection items to a dictionary, indexed by the key you specify.
562
+ * If there are more items with the same key, only the first one will be present.
563
+ */
564
+ indexBy(key, valueKey) {
565
+ return this.reduce((obj, item) => {
566
+ obj[item[key]] ??= valueKey ? item[valueKey] : item;
567
+ return obj;
568
+ }, {});
569
+ }
570
+ isInitialized(fully = false) {
571
+ if (!this.initialized || !fully) {
572
+ return this.initialized;
573
+ }
574
+ for (const item of this.items) {
575
+ if (!helper(item).__initialized) {
576
+ return false;
577
+ }
578
+ }
579
+ return true;
580
+ }
581
+ isDirty() {
582
+ return this.dirty;
583
+ }
584
+ isPartial() {
585
+ return this.partial;
586
+ }
587
+ setDirty(dirty = true) {
588
+ this.dirty = dirty;
589
+ }
590
+ get length() {
591
+ return this.count();
592
+ }
593
+ *[Symbol.iterator]() {
594
+ for (const item of this.getItems()) {
595
+ yield item;
596
+ }
597
+ }
598
+ /**
599
+ * @internal
600
+ */
601
+ takeSnapshot(forcePropagate) {
602
+ this.snapshot = [...this.items];
603
+ this.dirty = false;
604
+ if (this.property.owner || forcePropagate) {
605
+ this.items.forEach(item => {
606
+ this.propagate(item, 'takeSnapshot');
607
+ });
608
+ }
609
+ }
610
+ /**
611
+ * @internal
612
+ */
613
+ getSnapshot() {
614
+ return this.snapshot;
615
+ }
616
+ /**
617
+ * @internal
618
+ */
619
+ get property() {
620
+ if (!this._property) {
621
+ const meta = wrap(this.owner, true).__meta;
622
+ /* v8 ignore next */
623
+ if (!meta) {
624
+ throw MetadataError.fromUnknownEntity(this.owner.constructor.name, 'Collection.property getter, maybe you just forgot to initialize the ORM?');
625
+ }
626
+ this._property = meta.relations.find(prop => this.owner[prop.name] === this);
627
+ }
628
+ return this._property;
629
+ }
630
+ /**
631
+ * @internal
632
+ */
633
+ set property(prop) {
634
+ this._property = prop;
635
+ }
636
+ propagate(item, method) {
637
+ if (this.property.owner && this.property.inversedBy) {
638
+ this.propagateToInverseSide(item, method);
639
+ }
640
+ else if (!this.property.owner && this.property.mappedBy) {
641
+ this.propagateToOwningSide(item, method);
642
+ }
643
+ }
644
+ propagateToInverseSide(item, method) {
645
+ const collection = item[this.property.inversedBy];
646
+ if (this.shouldPropagateToCollection(collection, method)) {
647
+ method = method === 'takeSnapshot' ? method : (method + 'WithoutPropagation');
648
+ collection[method](this.owner);
649
+ }
650
+ }
651
+ propagateToOwningSide(item, method) {
652
+ const mappedBy = this.property.mappedBy;
653
+ const collection = item[mappedBy];
654
+ if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
655
+ if (this.shouldPropagateToCollection(collection, method)) {
656
+ collection[method](this.owner);
657
+ }
658
+ }
659
+ else if (this.property.kind === ReferenceKind.ONE_TO_MANY && method !== 'takeSnapshot') {
660
+ const prop2 = this.property.targetMeta.properties[mappedBy];
661
+ const owner = prop2.mapToPk ? helper(this.owner).getPrimaryKey() : this.owner;
662
+ const value = method === 'add' ? owner : null;
663
+ if (this.property.orphanRemoval && method === 'remove') {
664
+ // cache the PK before we propagate, as its value might be needed when flushing
665
+ helper(item).__pk = helper(item).getPrimaryKey();
666
+ }
667
+ if (!prop2.nullable && prop2.deleteRule !== 'cascade' && method === 'remove') {
668
+ if (!this.property.orphanRemoval) {
669
+ throw ValidationError.cannotRemoveFromCollectionWithoutOrphanRemoval(this.owner, this.property);
670
+ }
671
+ return;
672
+ }
673
+ // skip if already propagated
674
+ if (Reference.unwrapReference(item[mappedBy]) !== value) {
675
+ item[mappedBy] = value;
676
+ }
677
+ }
678
+ }
679
+ shouldPropagateToCollection(collection, method) {
680
+ if (!collection) {
681
+ return false;
682
+ }
683
+ switch (method) {
684
+ case 'add':
685
+ return !collection.contains(this.owner, false);
686
+ case 'remove':
687
+ return collection.isInitialized() && collection.contains(this.owner, false);
688
+ case 'takeSnapshot':
689
+ return collection.isDirty();
690
+ }
691
+ }
692
+ incrementCount(value) {
693
+ if (typeof this._count === 'number' && this.initialized) {
694
+ this._count += value;
695
+ }
696
+ }
697
+ /** @ignore */
698
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
699
+ const object = { ...this };
700
+ const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_lazyInitialized', '_em', 'readonly', 'partial'];
701
+ hidden.forEach(k => delete object[k]);
702
+ const ret = inspect(object, { depth });
703
+ const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
704
+ return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
370
705
  }
371
706
  }
372
- exports.Collection = Collection;
373
707
  Object.defineProperties(Collection.prototype, {
374
708
  $: { get() { return this; } },
375
709
  get: { get() { return () => this; } },
710
+ __collection: { value: true, enumerable: false, writable: false },
376
711
  });