@mikro-orm/core 7.0.0-dev.30 → 7.0.0-dev.300
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.
- package/EntityManager.d.ts +68 -60
- package/EntityManager.js +290 -259
- package/MikroORM.d.ts +44 -35
- package/MikroORM.js +109 -142
- package/README.md +2 -0
- package/cache/FileCacheAdapter.d.ts +1 -2
- package/cache/FileCacheAdapter.js +18 -11
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +12 -5
- package/connections/Connection.js +21 -12
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +119 -36
- package/drivers/IDatabaseDriver.d.ts +118 -23
- package/entity/BaseEntity.d.ts +63 -4
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +101 -29
- package/entity/Collection.js +436 -104
- package/entity/EntityAssigner.js +17 -17
- package/entity/EntityFactory.d.ts +7 -1
- package/entity/EntityFactory.js +87 -55
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +57 -19
- package/entity/EntityLoader.d.ts +11 -10
- package/entity/EntityLoader.js +213 -82
- package/entity/EntityRepository.d.ts +28 -8
- package/entity/EntityRepository.js +8 -2
- package/entity/PolymorphicRef.d.ts +12 -0
- package/entity/PolymorphicRef.js +18 -0
- package/entity/Reference.d.ts +1 -5
- package/entity/Reference.js +15 -11
- package/entity/WrappedEntity.d.ts +3 -8
- package/entity/WrappedEntity.js +2 -7
- package/entity/defineEntity.d.ts +526 -310
- package/entity/defineEntity.js +134 -290
- package/entity/index.d.ts +2 -2
- package/entity/index.js +2 -2
- package/entity/utils.d.ts +6 -1
- package/entity/utils.js +34 -1
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +8 -6
- package/enums.js +2 -1
- package/errors.d.ts +20 -10
- package/errors.js +55 -23
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +79 -34
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +47 -23
- package/metadata/EntitySchema.js +92 -33
- package/metadata/MetadataDiscovery.d.ts +64 -9
- package/metadata/MetadataDiscovery.js +782 -325
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +66 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +72 -39
- package/metadata/MetadataValidator.d.ts +32 -9
- package/metadata/MetadataValidator.js +196 -41
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +577 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +16 -4
- package/naming-strategy/AbstractNamingStrategy.js +20 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +28 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +22 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +11 -15
- package/platforms/Platform.js +24 -44
- package/serialization/EntitySerializer.d.ts +6 -3
- package/serialization/EntitySerializer.js +46 -26
- package/serialization/EntityTransformer.js +33 -21
- package/serialization/SerializationContext.d.ts +6 -6
- package/serialization/SerializationContext.js +3 -3
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +1 -0
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.js +2 -2
- package/types/DoubleType.js +1 -1
- package/types/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +412 -155
- package/typings.js +99 -44
- package/unit-of-work/ChangeSet.d.ts +4 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +3 -8
- package/unit-of-work/ChangeSetComputer.js +41 -20
- package/unit-of-work/ChangeSetPersister.d.ts +13 -12
- package/unit-of-work/ChangeSetPersister.js +94 -36
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +12 -0
- package/unit-of-work/IdentityMap.js +39 -1
- package/unit-of-work/UnitOfWork.d.ts +27 -3
- package/unit-of-work/UnitOfWork.js +248 -90
- package/utils/AbstractMigrator.d.ts +101 -0
- package/utils/AbstractMigrator.js +305 -0
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +28 -17
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +795 -211
- package/utils/Configuration.js +153 -194
- package/utils/ConfigurationLoader.d.ts +1 -52
- package/utils/ConfigurationLoader.js +1 -330
- package/utils/Cursor.d.ts +0 -3
- package/utils/Cursor.js +24 -11
- package/utils/DataloaderUtils.d.ts +10 -5
- package/utils/DataloaderUtils.js +29 -12
- package/utils/EntityComparator.d.ts +16 -9
- package/utils/EntityComparator.js +154 -56
- package/utils/QueryHelper.d.ts +18 -6
- package/utils/QueryHelper.js +76 -23
- package/utils/RawQueryFragment.d.ts +28 -34
- package/utils/RawQueryFragment.js +35 -71
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.js +9 -6
- package/utils/Utils.d.ts +15 -126
- package/utils/Utils.js +80 -382
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +34 -0
- package/utils/fs-utils.js +196 -0
- package/utils/index.d.ts +1 -3
- package/utils/index.js +1 -3
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +46 -3
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -12
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -33
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -42
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -34
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -28
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -14
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -118
- package/entity/ArrayCollection.js +0 -407
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
package/EntityManager.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import DataLoader from 'dataloader';
|
|
3
|
-
import { getOnConflictReturningFields } from './utils/upsert-utils.js';
|
|
1
|
+
import { getOnConflictReturningFields, getWhereCondition } from './utils/upsert-utils.js';
|
|
4
2
|
import { Utils } from './utils/Utils.js';
|
|
5
3
|
import { Cursor } from './utils/Cursor.js';
|
|
6
|
-
import { DataloaderUtils } from './utils/DataloaderUtils.js';
|
|
7
4
|
import { QueryHelper } from './utils/QueryHelper.js';
|
|
8
5
|
import { TransactionContext } from './utils/TransactionContext.js';
|
|
9
|
-
import { isRaw,
|
|
6
|
+
import { isRaw, Raw } from './utils/RawQueryFragment.js';
|
|
10
7
|
import { EntityFactory } from './entity/EntityFactory.js';
|
|
11
8
|
import { EntityAssigner } from './entity/EntityAssigner.js';
|
|
12
|
-
import {
|
|
9
|
+
import { validateEmptyWhere, validateParams, validatePrimaryKey, validateProperty } from './entity/validators.js';
|
|
13
10
|
import { EntityLoader } from './entity/EntityLoader.js';
|
|
14
11
|
import { Reference } from './entity/Reference.js';
|
|
15
12
|
import { helper } from './entity/wrap.js';
|
|
@@ -19,7 +16,7 @@ import { EventType, FlushMode, LoadStrategy, LockMode, PopulateHint, PopulatePat
|
|
|
19
16
|
import { EventManager } from './events/EventManager.js';
|
|
20
17
|
import { TransactionEventBroadcaster } from './events/TransactionEventBroadcaster.js';
|
|
21
18
|
import { OptimisticLockError, ValidationError } from './errors.js';
|
|
22
|
-
import { getLoadingStrategy } from './entity/utils.js';
|
|
19
|
+
import { applyPopulateHints, getLoadingStrategy } from './entity/utils.js';
|
|
23
20
|
import { TransactionManager } from './utils/TransactionManager.js';
|
|
24
21
|
/**
|
|
25
22
|
* The EntityManager is the central access point to ORM functionality. It is a facade to all different ORM subsystems
|
|
@@ -36,11 +33,8 @@ export class EntityManager {
|
|
|
36
33
|
_id = EntityManager.counter++;
|
|
37
34
|
global = false;
|
|
38
35
|
name;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
colLoaderMtoN = new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(this));
|
|
42
|
-
validator;
|
|
43
|
-
repositoryMap = {};
|
|
36
|
+
loaders = {};
|
|
37
|
+
repositoryMap = new Map();
|
|
44
38
|
entityLoader;
|
|
45
39
|
comparator;
|
|
46
40
|
entityFactory;
|
|
@@ -64,7 +58,6 @@ export class EntityManager {
|
|
|
64
58
|
this.eventManager = eventManager;
|
|
65
59
|
this.entityLoader = new EntityLoader(this);
|
|
66
60
|
this.name = this.config.get('contextName');
|
|
67
|
-
this.validator = new EntityValidator(this.config.get('strict'));
|
|
68
61
|
this.comparator = this.config.getComparator(this.metadata);
|
|
69
62
|
this.resultCache = this.config.getResultCacheAdapter();
|
|
70
63
|
this.disableTransactions = this.config.get('disableTransactions');
|
|
@@ -94,13 +87,12 @@ export class EntityManager {
|
|
|
94
87
|
* Gets repository for given entity. You can pass either string name or entity class reference.
|
|
95
88
|
*/
|
|
96
89
|
getRepository(entityName) {
|
|
97
|
-
|
|
98
|
-
if (!this.repositoryMap
|
|
99
|
-
const meta = this.metadata.get(entityName);
|
|
90
|
+
const meta = this.metadata.get(entityName);
|
|
91
|
+
if (!this.repositoryMap.has(meta)) {
|
|
100
92
|
const RepositoryClass = this.config.getRepositoryClass(meta.repository);
|
|
101
|
-
this.repositoryMap
|
|
93
|
+
this.repositoryMap.set(meta, new RepositoryClass(this, entityName));
|
|
102
94
|
}
|
|
103
|
-
return this.repositoryMap
|
|
95
|
+
return this.repositoryMap.get(meta);
|
|
104
96
|
}
|
|
105
97
|
/**
|
|
106
98
|
* Shortcut for `em.getRepository()`.
|
|
@@ -108,12 +100,6 @@ export class EntityManager {
|
|
|
108
100
|
repo(entityName) {
|
|
109
101
|
return this.getRepository(entityName);
|
|
110
102
|
}
|
|
111
|
-
/**
|
|
112
|
-
* Gets EntityValidator instance
|
|
113
|
-
*/
|
|
114
|
-
getValidator() {
|
|
115
|
-
return this.validator;
|
|
116
|
-
}
|
|
117
103
|
/**
|
|
118
104
|
* Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
|
|
119
105
|
*/
|
|
@@ -128,10 +114,15 @@ export class EntityManager {
|
|
|
128
114
|
const em = this.getContext();
|
|
129
115
|
em.prepareOptions(options);
|
|
130
116
|
await em.tryFlush(entityName, options);
|
|
131
|
-
entityName = Utils.className(entityName);
|
|
132
117
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
133
|
-
|
|
134
|
-
|
|
118
|
+
validateParams(where);
|
|
119
|
+
const meta = this.metadata.get(entityName);
|
|
120
|
+
if (meta.orderBy) {
|
|
121
|
+
options.orderBy = QueryHelper.mergeOrderBy(options.orderBy, meta.orderBy);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
options.orderBy ??= {};
|
|
125
|
+
}
|
|
135
126
|
options.populate = await em.preparePopulate(entityName, options);
|
|
136
127
|
const populate = options.populate;
|
|
137
128
|
const cacheKey = em.cacheKey(entityName, options, 'em.find', where);
|
|
@@ -145,12 +136,12 @@ export class EntityManager {
|
|
|
145
136
|
});
|
|
146
137
|
return cached.data;
|
|
147
138
|
}
|
|
148
|
-
const meta = this.metadata.get(entityName);
|
|
149
139
|
options = { ...options };
|
|
150
140
|
// save the original hint value so we know it was infer/all
|
|
151
141
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
152
142
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
153
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
143
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
144
|
+
await em.processUnionWhere(entityName, options, 'read');
|
|
154
145
|
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
155
146
|
if (results.length === 0) {
|
|
156
147
|
await em.storeCache(options.cache, cached, []);
|
|
@@ -182,6 +173,60 @@ export class EntityManager {
|
|
|
182
173
|
}
|
|
183
174
|
return unique;
|
|
184
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Finds all entities and returns an async iterable (async generator) that yields results one by one.
|
|
178
|
+
* The results are merged and mapped to entity instances, without adding them to the identity map.
|
|
179
|
+
* You can disable merging by passing the options `{ mergeResults: false }`.
|
|
180
|
+
* With `mergeResults` disabled, to-many collections will contain at most one item, and you will get duplicate
|
|
181
|
+
* root entities when there are multiple items in the populated collection.
|
|
182
|
+
* This is useful for processing large datasets without loading everything into memory at once.
|
|
183
|
+
*
|
|
184
|
+
* ```ts
|
|
185
|
+
* const stream = em.stream(Book, { populate: ['author'] });
|
|
186
|
+
*
|
|
187
|
+
* for await (const book of stream) {
|
|
188
|
+
* // book is an instance of Book entity
|
|
189
|
+
* console.log(book.title, book.author.name);
|
|
190
|
+
* }
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
async *stream(entityName, options = {}) {
|
|
194
|
+
const em = this.getContext();
|
|
195
|
+
em.prepareOptions(options);
|
|
196
|
+
options.strategy = 'joined';
|
|
197
|
+
await em.tryFlush(entityName, options);
|
|
198
|
+
const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
|
|
199
|
+
validateParams(where);
|
|
200
|
+
options.orderBy = options.orderBy || {};
|
|
201
|
+
options.populate = await em.preparePopulate(entityName, options);
|
|
202
|
+
const meta = this.metadata.get(entityName);
|
|
203
|
+
options = { ...options };
|
|
204
|
+
// save the original hint value so we know it was infer/all
|
|
205
|
+
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
206
|
+
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
207
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
208
|
+
const stream = em.driver.stream(entityName, where, {
|
|
209
|
+
ctx: em.transactionContext,
|
|
210
|
+
mapResults: false,
|
|
211
|
+
...options,
|
|
212
|
+
});
|
|
213
|
+
for await (const data of stream) {
|
|
214
|
+
const fork = em.fork();
|
|
215
|
+
const entity = fork.entityFactory.create(entityName, data, {
|
|
216
|
+
refresh: options.refresh,
|
|
217
|
+
schema: options.schema,
|
|
218
|
+
convertCustomTypes: true,
|
|
219
|
+
});
|
|
220
|
+
helper(entity).setSerializationContext({
|
|
221
|
+
populate: options.populate,
|
|
222
|
+
fields: options.fields,
|
|
223
|
+
exclude: options.exclude,
|
|
224
|
+
});
|
|
225
|
+
await fork.unitOfWork.dispatchOnLoadEvent();
|
|
226
|
+
fork.clear();
|
|
227
|
+
yield entity;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
185
230
|
/**
|
|
186
231
|
* Finds all entities of given type, optionally matching the `where` condition provided in the `options` parameter.
|
|
187
232
|
*/
|
|
@@ -195,7 +240,7 @@ export class EntityManager {
|
|
|
195
240
|
if (options.populateWhere === PopulateHint.ALL) {
|
|
196
241
|
return { where: {}, populateWhere: options.populateWhere };
|
|
197
242
|
}
|
|
198
|
-
/* v8 ignore next
|
|
243
|
+
/* v8 ignore next */
|
|
199
244
|
if (options.populateWhere === PopulateHint.INFER) {
|
|
200
245
|
return { where, populateWhere: options.populateWhere };
|
|
201
246
|
}
|
|
@@ -204,12 +249,12 @@ export class EntityManager {
|
|
|
204
249
|
/**
|
|
205
250
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
206
251
|
*/
|
|
207
|
-
addFilter(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
options.entity = Utils.asArray(entityName).map(n => Utils.className(n));
|
|
252
|
+
addFilter(options) {
|
|
253
|
+
if (options.entity) {
|
|
254
|
+
options.entity = Utils.asArray(options.entity).map(n => Utils.className(n));
|
|
211
255
|
}
|
|
212
|
-
|
|
256
|
+
options.default ??= true;
|
|
257
|
+
this.getContext(false).filters[options.name] = options;
|
|
213
258
|
}
|
|
214
259
|
/**
|
|
215
260
|
* Sets filter parameter values globally inside context defined by this entity manager.
|
|
@@ -254,21 +299,29 @@ export class EntityManager {
|
|
|
254
299
|
where = this.applyDiscriminatorCondition(entityName, where);
|
|
255
300
|
return where;
|
|
256
301
|
}
|
|
302
|
+
async processUnionWhere(entityName, options, type) {
|
|
303
|
+
if (options.unionWhere?.length) {
|
|
304
|
+
if (!this.driver.getPlatform().supportsUnionWhere()) {
|
|
305
|
+
throw new Error(`unionWhere is only supported on SQL drivers`);
|
|
306
|
+
}
|
|
307
|
+
options.unionWhere = await Promise.all(options.unionWhere.map(branch => this.processWhere(entityName, branch, options, type)));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
257
310
|
// this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
|
|
258
311
|
applyDiscriminatorCondition(entityName, where) {
|
|
259
312
|
const meta = this.metadata.find(entityName);
|
|
260
|
-
if (!meta?.discriminatorValue) {
|
|
313
|
+
if (meta?.root.inheritanceType !== 'sti' || !meta?.discriminatorValue) {
|
|
261
314
|
return where;
|
|
262
315
|
}
|
|
263
|
-
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.
|
|
316
|
+
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.get(cls));
|
|
264
317
|
const children = [];
|
|
265
318
|
const lookUpChildren = (ret, type) => {
|
|
266
319
|
const children = types.filter(meta2 => meta2.extends === type);
|
|
267
|
-
children.forEach(m => lookUpChildren(ret, m.
|
|
320
|
+
children.forEach(m => lookUpChildren(ret, m.class));
|
|
268
321
|
ret.push(...children.filter(c => c.discriminatorValue));
|
|
269
322
|
return children;
|
|
270
323
|
};
|
|
271
|
-
lookUpChildren(children, meta.
|
|
324
|
+
lookUpChildren(children, meta.class);
|
|
272
325
|
/* v8 ignore next */
|
|
273
326
|
where[meta.root.discriminatorColumn] = children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue;
|
|
274
327
|
return where;
|
|
@@ -284,60 +337,77 @@ export class EntityManager {
|
|
|
284
337
|
}
|
|
285
338
|
return ret;
|
|
286
339
|
}
|
|
287
|
-
async getJoinedFilters(meta,
|
|
340
|
+
async getJoinedFilters(meta, options) {
|
|
341
|
+
// If user provided populateFilter, merge it with computed filters
|
|
342
|
+
const userFilter = options.populateFilter;
|
|
343
|
+
if (!this.config.get('filtersOnRelations') || !options.populate) {
|
|
344
|
+
return userFilter;
|
|
345
|
+
}
|
|
288
346
|
const ret = {};
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
347
|
+
for (const hint of options.populate) {
|
|
348
|
+
const field = hint.field.split(':')[0];
|
|
349
|
+
const prop = meta.properties[field];
|
|
350
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
351
|
+
const joined = strategy === LoadStrategy.JOINED && prop.kind !== ReferenceKind.SCALAR;
|
|
352
|
+
if (!joined && !hint.filter) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
const filters = QueryHelper.mergePropertyFilters(prop.filters, options.filters);
|
|
356
|
+
const where = await this.applyFilters(prop.targetMeta.class, {}, filters, 'read', {
|
|
357
|
+
...options,
|
|
358
|
+
populate: hint.children,
|
|
359
|
+
});
|
|
360
|
+
const where2 = await this.getJoinedFilters(prop.targetMeta, {
|
|
361
|
+
...options,
|
|
362
|
+
filters,
|
|
363
|
+
populate: hint.children,
|
|
364
|
+
populateWhere: PopulateHint.ALL,
|
|
365
|
+
});
|
|
366
|
+
if (Utils.hasObjectKeys(where)) {
|
|
367
|
+
ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
|
|
368
|
+
}
|
|
369
|
+
if (where2 && Utils.hasObjectKeys(where2)) {
|
|
370
|
+
if (ret[field]) {
|
|
371
|
+
Utils.merge(ret[field], where2);
|
|
302
372
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
Utils.merge(ret[field], where2);
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
ret[field] = where2;
|
|
309
|
-
}
|
|
373
|
+
else {
|
|
374
|
+
ret[field] = where2;
|
|
310
375
|
}
|
|
311
376
|
}
|
|
312
377
|
}
|
|
313
|
-
|
|
378
|
+
// Merge user-provided populateFilter with computed filters
|
|
379
|
+
if (userFilter) {
|
|
380
|
+
Utils.merge(ret, userFilter);
|
|
381
|
+
}
|
|
382
|
+
return Utils.hasObjectKeys(ret) ? ret : undefined;
|
|
314
383
|
}
|
|
315
384
|
/**
|
|
316
385
|
* When filters are active on M:1 or 1:1 relations, we need to ref join them eagerly as they might affect the FK value.
|
|
317
386
|
*/
|
|
318
|
-
async autoJoinRefsForFilters(meta, options) {
|
|
319
|
-
if (!meta || !this.config.get('autoJoinRefsForFilters')) {
|
|
387
|
+
async autoJoinRefsForFilters(meta, options, parent) {
|
|
388
|
+
if (!meta || !this.config.get('autoJoinRefsForFilters') || options.filters === false) {
|
|
320
389
|
return;
|
|
321
390
|
}
|
|
322
|
-
const props = meta.relations.filter(prop => {
|
|
323
|
-
return !prop.object && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
324
|
-
&& ((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)));
|
|
325
|
-
});
|
|
326
391
|
const ret = options.populate;
|
|
327
|
-
for (const prop of
|
|
328
|
-
|
|
392
|
+
for (const prop of meta.relations) {
|
|
393
|
+
if (prop.object
|
|
394
|
+
|| ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
395
|
+
|| !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
396
|
+
|| (parent?.class === prop.targetMeta.root.class && parent.propName === prop.inversedBy)) {
|
|
397
|
+
continue;
|
|
398
|
+
}
|
|
399
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
400
|
+
const cond = await this.applyFilters(prop.targetMeta.class, {}, options.filters, 'read', options);
|
|
329
401
|
if (!Utils.isEmpty(cond)) {
|
|
330
402
|
const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
|
|
331
403
|
let found = false;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
found = true;
|
|
340
|
-
}
|
|
404
|
+
for (const hint of populated) {
|
|
405
|
+
if (!hint.all) {
|
|
406
|
+
hint.filter = true;
|
|
407
|
+
}
|
|
408
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
409
|
+
if (hint.field === `${prop.name}:ref` || (hint.filter && strategy === LoadStrategy.JOINED)) {
|
|
410
|
+
found = true;
|
|
341
411
|
}
|
|
342
412
|
}
|
|
343
413
|
if (!found) {
|
|
@@ -345,21 +415,26 @@ export class EntityManager {
|
|
|
345
415
|
}
|
|
346
416
|
}
|
|
347
417
|
}
|
|
418
|
+
for (const hint of ret) {
|
|
419
|
+
const [field, ref] = hint.field.split(':');
|
|
420
|
+
const prop = meta?.properties[field];
|
|
421
|
+
if (prop && !ref) {
|
|
422
|
+
hint.children ??= [];
|
|
423
|
+
await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { class: meta.root.class, propName: prop.name });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
348
426
|
}
|
|
349
427
|
/**
|
|
350
428
|
* @internal
|
|
351
429
|
*/
|
|
352
430
|
async applyFilters(entityName, where, options, type, findOptions) {
|
|
353
|
-
const meta = this.metadata.
|
|
431
|
+
const meta = this.metadata.get(entityName);
|
|
354
432
|
const filters = [];
|
|
355
433
|
const ret = [];
|
|
356
|
-
if (!meta) {
|
|
357
|
-
return where;
|
|
358
|
-
}
|
|
359
434
|
const active = new Set();
|
|
360
435
|
const push = (source) => {
|
|
361
436
|
const activeFilters = QueryHelper
|
|
362
|
-
.getActiveFilters(
|
|
437
|
+
.getActiveFilters(meta, options, source)
|
|
363
438
|
.filter(f => !active.has(f.name));
|
|
364
439
|
filters.push(...activeFilters);
|
|
365
440
|
activeFilters.forEach(f => active.add(f.name));
|
|
@@ -374,24 +449,28 @@ export class EntityManager {
|
|
|
374
449
|
let cond;
|
|
375
450
|
if (filter.cond instanceof Function) {
|
|
376
451
|
// @ts-ignore
|
|
377
|
-
const args = Utils.isPlainObject(options[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
452
|
+
const args = Utils.isPlainObject(options?.[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
378
453
|
if (!args && filter.cond.length > 0 && filter.args !== false) {
|
|
379
454
|
throw new Error(`No arguments provided for filter '${filter.name}'`);
|
|
380
455
|
}
|
|
381
|
-
cond = await filter.cond(args, type, this, findOptions, entityName);
|
|
456
|
+
cond = await filter.cond(args, type, this, findOptions, Utils.className(entityName));
|
|
382
457
|
}
|
|
383
458
|
else {
|
|
384
459
|
cond = filter.cond;
|
|
385
460
|
}
|
|
386
|
-
|
|
461
|
+
cond = QueryHelper.processWhere({
|
|
387
462
|
where: cond,
|
|
388
463
|
entityName,
|
|
389
464
|
metadata: this.metadata,
|
|
390
465
|
platform: this.driver.getPlatform(),
|
|
391
466
|
aliased: type === 'read',
|
|
392
|
-
})
|
|
467
|
+
});
|
|
468
|
+
if (filter.strict) {
|
|
469
|
+
Object.defineProperty(cond, '__strict', { value: filter.strict, enumerable: false });
|
|
470
|
+
}
|
|
471
|
+
ret.push(cond);
|
|
393
472
|
}
|
|
394
|
-
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
|
|
473
|
+
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c) || Raw.hasObjectFragments(c));
|
|
395
474
|
return conds.length > 1 ? { $and: conds } : conds[0];
|
|
396
475
|
}
|
|
397
476
|
/**
|
|
@@ -402,12 +481,10 @@ export class EntityManager {
|
|
|
402
481
|
const em = this.getContext(false);
|
|
403
482
|
await em.tryFlush(entityName, options);
|
|
404
483
|
options.flushMode = 'commit'; // do not try to auto flush again
|
|
405
|
-
return
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
]);
|
|
410
|
-
});
|
|
484
|
+
return Promise.all([
|
|
485
|
+
em.find(entityName, where, options),
|
|
486
|
+
em.count(entityName, where, options),
|
|
487
|
+
]);
|
|
411
488
|
}
|
|
412
489
|
/**
|
|
413
490
|
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as {@apilink Cursor} object.
|
|
@@ -423,21 +500,21 @@ export class EntityManager {
|
|
|
423
500
|
* - POJO/entity instance
|
|
424
501
|
*
|
|
425
502
|
* ```ts
|
|
426
|
-
* const currentCursor = await em.findByCursor(User, {
|
|
503
|
+
* const currentCursor = await em.findByCursor(User, {
|
|
427
504
|
* first: 10,
|
|
428
505
|
* after: previousCursor, // cursor instance
|
|
429
506
|
* orderBy: { id: 'desc' },
|
|
430
507
|
* });
|
|
431
508
|
*
|
|
432
509
|
* // to fetch next page
|
|
433
|
-
* const nextCursor = await em.findByCursor(User, {
|
|
510
|
+
* const nextCursor = await em.findByCursor(User, {
|
|
434
511
|
* first: 10,
|
|
435
512
|
* after: currentCursor.endCursor, // opaque string
|
|
436
513
|
* orderBy: { id: 'desc' },
|
|
437
514
|
* });
|
|
438
515
|
*
|
|
439
516
|
* // to fetch next page
|
|
440
|
-
* const nextCursor2 = await em.findByCursor(User, {
|
|
517
|
+
* const nextCursor2 = await em.findByCursor(User, {
|
|
441
518
|
* first: 10,
|
|
442
519
|
* after: { id: lastSeenId }, // entity-like POJO
|
|
443
520
|
* orderBy: { id: 'desc' },
|
|
@@ -465,16 +542,16 @@ export class EntityManager {
|
|
|
465
542
|
* }
|
|
466
543
|
* ```
|
|
467
544
|
*/
|
|
468
|
-
async findByCursor(entityName,
|
|
545
|
+
async findByCursor(entityName, options) {
|
|
469
546
|
const em = this.getContext(false);
|
|
470
|
-
entityName = Utils.className(entityName);
|
|
471
547
|
options.overfetch ??= true;
|
|
472
|
-
|
|
548
|
+
options.where ??= {};
|
|
549
|
+
if (Utils.isEmpty(options.orderBy) && !Raw.hasObjectFragments(options.orderBy)) {
|
|
473
550
|
throw new Error('Explicit `orderBy` option required');
|
|
474
551
|
}
|
|
475
552
|
const [entities, count] = options.includeCount !== false
|
|
476
|
-
? await em.findAndCount(entityName, where, options)
|
|
477
|
-
: [await em.find(entityName, where, options)];
|
|
553
|
+
? await em.findAndCount(entityName, options.where, options)
|
|
554
|
+
: [await em.find(entityName, options.where, options)];
|
|
478
555
|
return new Cursor(entities, count, options, this.metadata.get(entityName));
|
|
479
556
|
}
|
|
480
557
|
/**
|
|
@@ -486,9 +563,9 @@ export class EntityManager {
|
|
|
486
563
|
const ret = await this.refresh(entity, options);
|
|
487
564
|
if (!ret) {
|
|
488
565
|
options.failHandler ??= this.config.get('findOneOrFailHandler');
|
|
489
|
-
const
|
|
490
|
-
const where =
|
|
491
|
-
throw options.failHandler(
|
|
566
|
+
const wrapped = helper(entity);
|
|
567
|
+
const where = wrapped.getPrimaryKey();
|
|
568
|
+
throw options.failHandler(wrapped.__meta.className, where);
|
|
492
569
|
}
|
|
493
570
|
return ret;
|
|
494
571
|
}
|
|
@@ -499,9 +576,9 @@ export class EntityManager {
|
|
|
499
576
|
*/
|
|
500
577
|
async refresh(entity, options = {}) {
|
|
501
578
|
const fork = this.fork({ keepTransactionContext: true });
|
|
502
|
-
const
|
|
503
|
-
const reloaded = await fork.findOne(
|
|
504
|
-
schema:
|
|
579
|
+
const wrapped = helper(entity);
|
|
580
|
+
const reloaded = await fork.findOne(wrapped.__meta.class, entity, {
|
|
581
|
+
schema: wrapped.__schema,
|
|
505
582
|
...options,
|
|
506
583
|
flushMode: FlushMode.COMMIT,
|
|
507
584
|
});
|
|
@@ -512,16 +589,16 @@ export class EntityManager {
|
|
|
512
589
|
}
|
|
513
590
|
let found = false;
|
|
514
591
|
for (const e of fork.unitOfWork.getIdentityMap()) {
|
|
515
|
-
const ref = em.getReference(e.constructor
|
|
516
|
-
const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true });
|
|
517
|
-
em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false,
|
|
518
|
-
helper(ref).__originalEntityData
|
|
592
|
+
const ref = em.getReference(e.constructor, helper(e).getPrimaryKey());
|
|
593
|
+
const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true, convertCustomTypes: false });
|
|
594
|
+
em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, false);
|
|
595
|
+
Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
|
|
519
596
|
found ||= ref === entity;
|
|
520
597
|
}
|
|
521
598
|
if (!found) {
|
|
522
|
-
const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true });
|
|
523
|
-
em.config.getHydrator(this.metadata).hydrate(entity,
|
|
524
|
-
|
|
599
|
+
const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true, convertCustomTypes: true });
|
|
600
|
+
em.config.getHydrator(this.metadata).hydrate(entity, wrapped.__meta, data, em.entityFactory, 'full', false, true);
|
|
601
|
+
Utils.merge(wrapped.__originalEntityData, this.comparator.prepareEntity(reloaded));
|
|
525
602
|
}
|
|
526
603
|
return entity;
|
|
527
604
|
}
|
|
@@ -537,7 +614,6 @@ export class EntityManager {
|
|
|
537
614
|
return ret;
|
|
538
615
|
}
|
|
539
616
|
const em = this.getContext();
|
|
540
|
-
entityName = Utils.className(entityName);
|
|
541
617
|
em.prepareOptions(options);
|
|
542
618
|
let entity = em.unitOfWork.tryGetById(entityName, where, options.schema);
|
|
543
619
|
// query for a not managed entity which is already in the identity map as it
|
|
@@ -549,13 +625,13 @@ export class EntityManager {
|
|
|
549
625
|
await em.tryFlush(entityName, options);
|
|
550
626
|
const meta = em.metadata.get(entityName);
|
|
551
627
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
552
|
-
|
|
628
|
+
validateEmptyWhere(where);
|
|
553
629
|
em.checkLockRequirements(options.lockMode, meta);
|
|
554
|
-
const isOptimisticLocking =
|
|
630
|
+
const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.OPTIMISTIC;
|
|
555
631
|
if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
|
|
556
632
|
return em.lockAndPopulate(meta, entity, where, options);
|
|
557
633
|
}
|
|
558
|
-
|
|
634
|
+
validateParams(where);
|
|
559
635
|
options.populate = await em.preparePopulate(entityName, options);
|
|
560
636
|
const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
|
|
561
637
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
@@ -574,7 +650,8 @@ export class EntityManager {
|
|
|
574
650
|
// save the original hint value so we know it was infer/all
|
|
575
651
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
576
652
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
577
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
653
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
654
|
+
await em.processUnionWhere(entityName, options, 'read');
|
|
578
655
|
const data = await em.driver.findOne(entityName, where, {
|
|
579
656
|
ctx: em.transactionContext,
|
|
580
657
|
em,
|
|
@@ -615,10 +692,10 @@ export class EntityManager {
|
|
|
615
692
|
if (!entity || isStrictViolation) {
|
|
616
693
|
const key = options.strict ? 'findExactlyOneOrFailHandler' : 'findOneOrFailHandler';
|
|
617
694
|
options.failHandler ??= this.config.get(key);
|
|
618
|
-
|
|
695
|
+
const name = Utils.className(entityName);
|
|
619
696
|
/* v8 ignore next */
|
|
620
697
|
where = Utils.isEntity(where) ? helper(where).getPrimaryKey() : where;
|
|
621
|
-
throw options.failHandler(
|
|
698
|
+
throw options.failHandler(name, where);
|
|
622
699
|
}
|
|
623
700
|
return entity;
|
|
624
701
|
}
|
|
@@ -658,11 +735,11 @@ export class EntityManager {
|
|
|
658
735
|
let where;
|
|
659
736
|
let entity = null;
|
|
660
737
|
if (data === undefined) {
|
|
661
|
-
entityName = entityNameOrEntity.constructor
|
|
738
|
+
entityName = entityNameOrEntity.constructor;
|
|
662
739
|
data = entityNameOrEntity;
|
|
663
740
|
}
|
|
664
741
|
else {
|
|
665
|
-
entityName =
|
|
742
|
+
entityName = entityNameOrEntity;
|
|
666
743
|
}
|
|
667
744
|
const meta = this.metadata.get(entityName);
|
|
668
745
|
const convertCustomTypes = !Utils.isEntity(data);
|
|
@@ -685,26 +762,9 @@ export class EntityManager {
|
|
|
685
762
|
}
|
|
686
763
|
}
|
|
687
764
|
}
|
|
688
|
-
|
|
689
|
-
const propIndex = !isRaw(unique) && unique.findIndex(p => data[p] != null);
|
|
690
|
-
if (options.onConflictFields || where == null) {
|
|
691
|
-
if (propIndex !== false && propIndex >= 0) {
|
|
692
|
-
where = { [unique[propIndex]]: data[unique[propIndex]] };
|
|
693
|
-
}
|
|
694
|
-
else if (meta.uniques.length > 0) {
|
|
695
|
-
for (const u of meta.uniques) {
|
|
696
|
-
if (Utils.asArray(u.properties).every(p => data[p] != null)) {
|
|
697
|
-
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
698
|
-
o[key] = data[key];
|
|
699
|
-
return o;
|
|
700
|
-
}, {});
|
|
701
|
-
break;
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
}
|
|
765
|
+
where = getWhereCondition(meta, options.onConflictFields, data, where).where;
|
|
706
766
|
data = QueryHelper.processObjectParams(data);
|
|
707
|
-
|
|
767
|
+
validateParams(data, 'insert data');
|
|
708
768
|
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
709
769
|
await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity: data, em, meta }, meta);
|
|
710
770
|
}
|
|
@@ -742,7 +802,7 @@ export class EntityManager {
|
|
|
742
802
|
where[meta.primaryKeys[0]] = ret.insertId;
|
|
743
803
|
}
|
|
744
804
|
}
|
|
745
|
-
const data2 = await this.driver.findOne(meta.
|
|
805
|
+
const data2 = await this.driver.findOne(meta.class, where, {
|
|
746
806
|
fields: returning,
|
|
747
807
|
ctx: em.transactionContext,
|
|
748
808
|
convertCustomTypes: true,
|
|
@@ -797,11 +857,11 @@ export class EntityManager {
|
|
|
797
857
|
let entityName;
|
|
798
858
|
let propIndex;
|
|
799
859
|
if (data === undefined) {
|
|
800
|
-
entityName = entityNameOrEntity[0].constructor
|
|
860
|
+
entityName = entityNameOrEntity[0].constructor;
|
|
801
861
|
data = entityNameOrEntity;
|
|
802
862
|
}
|
|
803
863
|
else {
|
|
804
|
-
entityName =
|
|
864
|
+
entityName = entityNameOrEntity;
|
|
805
865
|
}
|
|
806
866
|
const batchSize = options.batchSize ?? this.config.get('batchSize');
|
|
807
867
|
if (data.length > batchSize) {
|
|
@@ -845,32 +905,18 @@ export class EntityManager {
|
|
|
845
905
|
}
|
|
846
906
|
}
|
|
847
907
|
}
|
|
848
|
-
const unique = meta.props.filter(p => p.unique).map(p => p.name);
|
|
849
|
-
propIndex = unique.findIndex(p =>
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
where = { [unique[propIndex]]: row[unique[propIndex]] };
|
|
853
|
-
}
|
|
854
|
-
else if (meta.uniques.length > 0) {
|
|
855
|
-
for (const u of meta.uniques) {
|
|
856
|
-
if (Utils.asArray(u.properties).every(p => row[p] != null)) {
|
|
857
|
-
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
858
|
-
o[key] = row[key];
|
|
859
|
-
return o;
|
|
860
|
-
}, {});
|
|
861
|
-
break;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
row = QueryHelper.processObjectParams(row);
|
|
908
|
+
const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
909
|
+
propIndex = !isRaw(unique) && unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
910
|
+
const tmp = getWhereCondition(meta, options.onConflictFields, row, where);
|
|
911
|
+
propIndex = tmp.propIndex;
|
|
867
912
|
where = QueryHelper.processWhere({
|
|
868
|
-
where,
|
|
913
|
+
where: tmp.where,
|
|
869
914
|
entityName,
|
|
870
915
|
metadata: this.metadata,
|
|
871
916
|
platform: this.getPlatform(),
|
|
872
917
|
});
|
|
873
|
-
|
|
918
|
+
row = QueryHelper.processObjectParams(row);
|
|
919
|
+
validateParams(row, 'insert data');
|
|
874
920
|
allData.push(row);
|
|
875
921
|
allWhere.push(where);
|
|
876
922
|
}
|
|
@@ -911,7 +957,7 @@ export class EntityManager {
|
|
|
911
957
|
const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
|
|
912
958
|
if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
|
|
913
959
|
const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
|
|
914
|
-
const add = new Set(propIndex >= 0 ? [unique[propIndex]] : []);
|
|
960
|
+
const add = new Set(propIndex !== false && propIndex >= 0 ? [unique[propIndex]] : []);
|
|
915
961
|
for (const cond of loadPK.values()) {
|
|
916
962
|
Utils.keys(cond).forEach(key => add.add(key));
|
|
917
963
|
}
|
|
@@ -923,7 +969,7 @@ export class EntityManager {
|
|
|
923
969
|
where.$or[idx][prop] = item[prop];
|
|
924
970
|
});
|
|
925
971
|
});
|
|
926
|
-
const data2 = await this.driver.find(meta.
|
|
972
|
+
const data2 = await this.driver.find(meta.class, where, {
|
|
927
973
|
fields: returning.concat(...add).concat(...(Array.isArray(uniqueFields) ? uniqueFields : [])),
|
|
928
974
|
ctx: em.transactionContext,
|
|
929
975
|
convertCustomTypes: true,
|
|
@@ -940,7 +986,7 @@ export class EntityManager {
|
|
|
940
986
|
});
|
|
941
987
|
return this.comparator.matching(entityName, cond, tmp);
|
|
942
988
|
});
|
|
943
|
-
/* v8 ignore next
|
|
989
|
+
/* v8 ignore next */
|
|
944
990
|
if (!row) {
|
|
945
991
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
946
992
|
}
|
|
@@ -963,7 +1009,7 @@ export class EntityManager {
|
|
|
963
1009
|
}, {});
|
|
964
1010
|
return this.comparator.matching(entityName, cond, pk);
|
|
965
1011
|
});
|
|
966
|
-
/* v8 ignore next
|
|
1012
|
+
/* v8 ignore next */
|
|
967
1013
|
if (!row) {
|
|
968
1014
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
969
1015
|
}
|
|
@@ -1076,11 +1122,11 @@ export class EntityManager {
|
|
|
1076
1122
|
em.prepareOptions(options);
|
|
1077
1123
|
let entityName;
|
|
1078
1124
|
if (data === undefined) {
|
|
1079
|
-
entityName = entityNameOrEntity.constructor
|
|
1125
|
+
entityName = entityNameOrEntity.constructor;
|
|
1080
1126
|
data = entityNameOrEntity;
|
|
1081
1127
|
}
|
|
1082
1128
|
else {
|
|
1083
|
-
entityName =
|
|
1129
|
+
entityName = entityNameOrEntity;
|
|
1084
1130
|
}
|
|
1085
1131
|
if (Utils.isEntity(data)) {
|
|
1086
1132
|
if (options.schema && helper(data).getSchema() == null) {
|
|
@@ -1099,7 +1145,7 @@ export class EntityManager {
|
|
|
1099
1145
|
return cs.getPrimaryKey();
|
|
1100
1146
|
}
|
|
1101
1147
|
data = QueryHelper.processObjectParams(data);
|
|
1102
|
-
|
|
1148
|
+
validateParams(data, 'insert data');
|
|
1103
1149
|
const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1104
1150
|
return res.insertId;
|
|
1105
1151
|
}
|
|
@@ -1111,11 +1157,11 @@ export class EntityManager {
|
|
|
1111
1157
|
em.prepareOptions(options);
|
|
1112
1158
|
let entityName;
|
|
1113
1159
|
if (data === undefined) {
|
|
1114
|
-
entityName = entityNameOrEntities[0].constructor
|
|
1160
|
+
entityName = entityNameOrEntities[0].constructor;
|
|
1115
1161
|
data = entityNameOrEntities;
|
|
1116
1162
|
}
|
|
1117
1163
|
else {
|
|
1118
|
-
entityName =
|
|
1164
|
+
entityName = entityNameOrEntities;
|
|
1119
1165
|
}
|
|
1120
1166
|
if (data.length === 0) {
|
|
1121
1167
|
return [];
|
|
@@ -1139,7 +1185,7 @@ export class EntityManager {
|
|
|
1139
1185
|
return css.map(cs => cs.getPrimaryKey());
|
|
1140
1186
|
}
|
|
1141
1187
|
data = data.map(row => QueryHelper.processObjectParams(row));
|
|
1142
|
-
data.forEach(row =>
|
|
1188
|
+
data.forEach(row => validateParams(row, 'insert data'));
|
|
1143
1189
|
const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1144
1190
|
if (res.insertedIds) {
|
|
1145
1191
|
return res.insertedIds;
|
|
@@ -1152,12 +1198,12 @@ export class EntityManager {
|
|
|
1152
1198
|
async nativeUpdate(entityName, where, data, options = {}) {
|
|
1153
1199
|
const em = this.getContext(false);
|
|
1154
1200
|
em.prepareOptions(options);
|
|
1155
|
-
|
|
1201
|
+
await em.processUnionWhere(entityName, options, 'update');
|
|
1156
1202
|
data = QueryHelper.processObjectParams(data);
|
|
1157
1203
|
where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, ...options });
|
|
1204
|
+
validateParams(data, 'update data');
|
|
1205
|
+
validateParams(where, 'update condition');
|
|
1206
|
+
const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, em, ...options });
|
|
1161
1207
|
return res.affectedRows;
|
|
1162
1208
|
}
|
|
1163
1209
|
/**
|
|
@@ -1166,28 +1212,29 @@ export class EntityManager {
|
|
|
1166
1212
|
async nativeDelete(entityName, where, options = {}) {
|
|
1167
1213
|
const em = this.getContext(false);
|
|
1168
1214
|
em.prepareOptions(options);
|
|
1169
|
-
|
|
1215
|
+
await em.processUnionWhere(entityName, options, 'delete');
|
|
1170
1216
|
where = await em.processWhere(entityName, where, options, 'delete');
|
|
1171
|
-
|
|
1172
|
-
const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
|
|
1217
|
+
validateParams(where, 'delete condition');
|
|
1218
|
+
const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
1173
1219
|
return res.affectedRows;
|
|
1174
1220
|
}
|
|
1175
1221
|
/**
|
|
1176
1222
|
* Maps raw database result to an entity and merges it to this EntityManager.
|
|
1177
1223
|
*/
|
|
1178
1224
|
map(entityName, result, options = {}) {
|
|
1179
|
-
entityName = Utils.className(entityName);
|
|
1180
1225
|
const meta = this.metadata.get(entityName);
|
|
1181
1226
|
const data = this.driver.mapResult(result, meta);
|
|
1182
|
-
Object.keys(data)
|
|
1227
|
+
for (const k of Object.keys(data)) {
|
|
1183
1228
|
const prop = meta.properties[k];
|
|
1184
|
-
if (prop
|
|
1185
|
-
|
|
1229
|
+
if (prop?.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
|
|
1230
|
+
validateProperty(prop, data[k], data);
|
|
1186
1231
|
}
|
|
1187
|
-
}
|
|
1232
|
+
}
|
|
1188
1233
|
return this.merge(entityName, data, {
|
|
1189
1234
|
convertCustomTypes: true,
|
|
1190
|
-
refresh: true,
|
|
1235
|
+
refresh: true,
|
|
1236
|
+
validate: false,
|
|
1237
|
+
...options,
|
|
1191
1238
|
});
|
|
1192
1239
|
}
|
|
1193
1240
|
/**
|
|
@@ -1196,32 +1243,19 @@ export class EntityManager {
|
|
|
1196
1243
|
*/
|
|
1197
1244
|
merge(entityName, data, options = {}) {
|
|
1198
1245
|
if (Utils.isEntity(entityName)) {
|
|
1199
|
-
return this.merge(entityName.constructor
|
|
1246
|
+
return this.merge(entityName.constructor, entityName, data);
|
|
1200
1247
|
}
|
|
1201
1248
|
const em = options.disableContextResolution ? this : this.getContext();
|
|
1202
1249
|
options.schema ??= em._schema;
|
|
1203
1250
|
options.validate ??= true;
|
|
1204
1251
|
options.cascade ??= true;
|
|
1205
|
-
|
|
1206
|
-
if (options.validate) {
|
|
1207
|
-
em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1208
|
-
}
|
|
1252
|
+
validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1209
1253
|
let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
|
|
1210
1254
|
if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
|
|
1211
1255
|
return entity;
|
|
1212
1256
|
}
|
|
1213
|
-
const meta = em.metadata.find(entityName);
|
|
1214
|
-
const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
|
|
1215
1257
|
const dataIsEntity = Utils.isEntity(data);
|
|
1216
|
-
if (options.keepIdentity && entity && dataIsEntity && entity !== data) {
|
|
1217
|
-
helper(entity).__data = helper(data).__data;
|
|
1218
|
-
helper(entity).__originalEntityData = helper(data).__originalEntityData;
|
|
1219
|
-
return entity;
|
|
1220
|
-
}
|
|
1221
1258
|
entity = dataIsEntity ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
|
|
1222
|
-
if (options.validate) {
|
|
1223
|
-
em.validator.validate(entity, data, childMeta ?? meta);
|
|
1224
|
-
}
|
|
1225
1259
|
const visited = options.cascade ? undefined : new Set([entity]);
|
|
1226
1260
|
em.unitOfWork.merge(entity, visited);
|
|
1227
1261
|
return entity;
|
|
@@ -1248,6 +1282,7 @@ export class EntityManager {
|
|
|
1248
1282
|
...options,
|
|
1249
1283
|
newEntity: !options.managed,
|
|
1250
1284
|
merge: options.managed,
|
|
1285
|
+
normalizeAccessors: true,
|
|
1251
1286
|
});
|
|
1252
1287
|
options.persist ??= em.config.get('persistOnCreate');
|
|
1253
1288
|
if (options.persist && !this.getMetadata(entityName).embeddable) {
|
|
@@ -1267,7 +1302,7 @@ export class EntityManager {
|
|
|
1267
1302
|
getReference(entityName, id, options = {}) {
|
|
1268
1303
|
options.schema ??= this.schema;
|
|
1269
1304
|
options.convertCustomTypes ??= false;
|
|
1270
|
-
const meta = this.metadata.get(
|
|
1305
|
+
const meta = this.metadata.get(entityName);
|
|
1271
1306
|
if (Utils.isPrimaryKey(id)) {
|
|
1272
1307
|
if (meta.compositePK) {
|
|
1273
1308
|
throw ValidationError.invalidCompositeIdentifier(meta);
|
|
@@ -1288,7 +1323,6 @@ export class EntityManager {
|
|
|
1288
1323
|
// Shallow copy options since the object will be modified when deleting orderBy
|
|
1289
1324
|
options = { ...options };
|
|
1290
1325
|
em.prepareOptions(options);
|
|
1291
|
-
entityName = Utils.className(entityName);
|
|
1292
1326
|
await em.tryFlush(entityName, options);
|
|
1293
1327
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
1294
1328
|
options.populate = await em.preparePopulate(entityName, options);
|
|
@@ -1297,9 +1331,10 @@ export class EntityManager {
|
|
|
1297
1331
|
const meta = em.metadata.find(entityName);
|
|
1298
1332
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
1299
1333
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
1300
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
1301
|
-
|
|
1334
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
1335
|
+
validateParams(where);
|
|
1302
1336
|
delete options.orderBy;
|
|
1337
|
+
await em.processUnionWhere(entityName, options, 'read');
|
|
1303
1338
|
const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
|
|
1304
1339
|
const cached = await em.tryCache(entityName, options.cache, cacheKey);
|
|
1305
1340
|
if (cached?.data !== undefined) {
|
|
@@ -1324,7 +1359,7 @@ export class EntityManager {
|
|
|
1324
1359
|
for (const ent of entities) {
|
|
1325
1360
|
if (!Utils.isEntity(ent, true)) {
|
|
1326
1361
|
/* v8 ignore next */
|
|
1327
|
-
const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor
|
|
1362
|
+
const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor) : undefined;
|
|
1328
1363
|
throw ValidationError.notDiscoveredEntity(ent, meta);
|
|
1329
1364
|
}
|
|
1330
1365
|
// do not cascade just yet, cascading of entities in persist stack is done when flushing
|
|
@@ -1332,13 +1367,6 @@ export class EntityManager {
|
|
|
1332
1367
|
}
|
|
1333
1368
|
return this;
|
|
1334
1369
|
}
|
|
1335
|
-
/**
|
|
1336
|
-
* Persists your entity immediately, flushing all not yet persisted changes to the database too.
|
|
1337
|
-
* Equivalent to `em.persist(e).flush()`.
|
|
1338
|
-
*/
|
|
1339
|
-
async persistAndFlush(entity) {
|
|
1340
|
-
await this.persist(entity).flush();
|
|
1341
|
-
}
|
|
1342
1370
|
/**
|
|
1343
1371
|
* Marks entity for removal.
|
|
1344
1372
|
* A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
|
|
@@ -1362,13 +1390,6 @@ export class EntityManager {
|
|
|
1362
1390
|
}
|
|
1363
1391
|
return em;
|
|
1364
1392
|
}
|
|
1365
|
-
/**
|
|
1366
|
-
* Removes an entity instance immediately, flushing all not yet persisted changes to the database too.
|
|
1367
|
-
* Equivalent to `em.remove(e).flush()`
|
|
1368
|
-
*/
|
|
1369
|
-
async removeAndFlush(entity) {
|
|
1370
|
-
await this.remove(entity).flush();
|
|
1371
|
-
}
|
|
1372
1393
|
/**
|
|
1373
1394
|
* Flushes all changes to objects that have been queued up to now to the database.
|
|
1374
1395
|
* This effectively synchronizes the in-memory state of managed objects with the database.
|
|
@@ -1382,7 +1403,6 @@ export class EntityManager {
|
|
|
1382
1403
|
async tryFlush(entityName, options) {
|
|
1383
1404
|
const em = this.getContext();
|
|
1384
1405
|
const flushMode = options.flushMode ?? em.flushMode ?? em.config.get('flushMode');
|
|
1385
|
-
entityName = Utils.className(entityName);
|
|
1386
1406
|
const meta = em.metadata.get(entityName);
|
|
1387
1407
|
if (flushMode === FlushMode.COMMIT) {
|
|
1388
1408
|
return;
|
|
@@ -1401,7 +1421,6 @@ export class EntityManager {
|
|
|
1401
1421
|
* Checks whether given property can be populated on the entity.
|
|
1402
1422
|
*/
|
|
1403
1423
|
canPopulate(entityName, property) {
|
|
1404
|
-
entityName = Utils.className(entityName);
|
|
1405
1424
|
// eslint-disable-next-line prefer-const
|
|
1406
1425
|
let [p, ...parts] = property.split('.');
|
|
1407
1426
|
const meta = this.metadata.find(entityName);
|
|
@@ -1411,12 +1430,11 @@ export class EntityManager {
|
|
|
1411
1430
|
if (p.includes(':')) {
|
|
1412
1431
|
p = p.split(':', 2)[0];
|
|
1413
1432
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1433
|
+
// For TPT inheritance, check the entity's own properties, not just the root's
|
|
1434
|
+
// For STI, meta.properties includes all properties anyway
|
|
1435
|
+
const ret = p in meta.properties;
|
|
1418
1436
|
if (parts.length > 0) {
|
|
1419
|
-
return this.canPopulate(
|
|
1437
|
+
return this.canPopulate(meta.properties[p].targetMeta.class, parts.join('.'));
|
|
1420
1438
|
}
|
|
1421
1439
|
return ret;
|
|
1422
1440
|
}
|
|
@@ -1430,8 +1448,8 @@ export class EntityManager {
|
|
|
1430
1448
|
}
|
|
1431
1449
|
const em = this.getContext();
|
|
1432
1450
|
em.prepareOptions(options);
|
|
1433
|
-
const entityName = arr[0].constructor
|
|
1434
|
-
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate }, options.validate);
|
|
1451
|
+
const entityName = arr[0].constructor;
|
|
1452
|
+
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
|
|
1435
1453
|
await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
|
|
1436
1454
|
return entities;
|
|
1437
1455
|
}
|
|
@@ -1559,7 +1577,6 @@ export class EntityManager {
|
|
|
1559
1577
|
*/
|
|
1560
1578
|
getMetadata(entityName) {
|
|
1561
1579
|
if (entityName) {
|
|
1562
|
-
entityName = Utils.className(entityName);
|
|
1563
1580
|
return this.metadata.get(entityName);
|
|
1564
1581
|
}
|
|
1565
1582
|
return this.metadata;
|
|
@@ -1588,8 +1605,8 @@ export class EntityManager {
|
|
|
1588
1605
|
lockTableAliases: options.lockTableAliases,
|
|
1589
1606
|
});
|
|
1590
1607
|
}
|
|
1591
|
-
const preparedPopulate = await this.preparePopulate(meta.
|
|
1592
|
-
await this.entityLoader.populate(meta.
|
|
1608
|
+
const preparedPopulate = await this.preparePopulate(meta.class, options);
|
|
1609
|
+
await this.entityLoader.populate(meta.class, [entity], preparedPopulate, {
|
|
1593
1610
|
...options,
|
|
1594
1611
|
...this.getPopulateWhere(where, options),
|
|
1595
1612
|
orderBy: options.populateOrderBy ?? options.orderBy,
|
|
@@ -1609,6 +1626,7 @@ export class EntityManager {
|
|
|
1609
1626
|
return ret;
|
|
1610
1627
|
}, []);
|
|
1611
1628
|
}
|
|
1629
|
+
/** @internal */
|
|
1612
1630
|
async preparePopulate(entityName, options, validate = true) {
|
|
1613
1631
|
if (options.populate === false) {
|
|
1614
1632
|
return [];
|
|
@@ -1649,13 +1667,13 @@ export class EntityManager {
|
|
|
1649
1667
|
options.populate = pruneToOneRelations(meta, this.buildFields(options.fields));
|
|
1650
1668
|
}
|
|
1651
1669
|
if (!options.populate) {
|
|
1652
|
-
const populate = this.entityLoader.normalizePopulate(entityName, [], options.strategy);
|
|
1670
|
+
const populate = this.entityLoader.normalizePopulate(entityName, [], options.strategy, true, options.exclude);
|
|
1653
1671
|
await this.autoJoinRefsForFilters(meta, { ...options, populate });
|
|
1654
1672
|
return populate;
|
|
1655
1673
|
}
|
|
1656
1674
|
if (typeof options.populate !== 'boolean') {
|
|
1657
1675
|
options.populate = Utils.asArray(options.populate).map(field => {
|
|
1658
|
-
/* v8 ignore next
|
|
1676
|
+
/* v8 ignore next */
|
|
1659
1677
|
if (typeof field === 'boolean' || field === PopulatePath.ALL) {
|
|
1660
1678
|
return [{ field: meta.primaryKeys[0], strategy: options.strategy, all: !!field }]; //
|
|
1661
1679
|
}
|
|
@@ -1665,24 +1683,27 @@ export class EntityManager {
|
|
|
1665
1683
|
options.flags.push(QueryFlag.INFER_POPULATE);
|
|
1666
1684
|
return [];
|
|
1667
1685
|
}
|
|
1668
|
-
if (
|
|
1686
|
+
if (typeof field === 'string') {
|
|
1669
1687
|
return [{ field, strategy: options.strategy }];
|
|
1670
1688
|
}
|
|
1671
1689
|
return [field];
|
|
1672
1690
|
}).flat();
|
|
1673
1691
|
}
|
|
1674
|
-
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy);
|
|
1692
|
+
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy, true, options.exclude);
|
|
1675
1693
|
const invalid = populate.find(({ field }) => !this.canPopulate(entityName, field));
|
|
1676
1694
|
if (validate && invalid) {
|
|
1677
1695
|
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
|
1678
1696
|
}
|
|
1679
1697
|
await this.autoJoinRefsForFilters(meta, { ...options, populate });
|
|
1680
|
-
|
|
1698
|
+
for (const field of populate) {
|
|
1681
1699
|
// force select-in strategy when populating all relations as otherwise we could cause infinite loops when self-referencing
|
|
1682
1700
|
const all = field.all ?? (Array.isArray(options.populate) && options.populate.includes('*'));
|
|
1683
1701
|
field.strategy = all ? LoadStrategy.SELECT_IN : (options.strategy ?? field.strategy);
|
|
1684
|
-
|
|
1685
|
-
|
|
1702
|
+
}
|
|
1703
|
+
if (options.populateHints) {
|
|
1704
|
+
applyPopulateHints(populate, options.populateHints);
|
|
1705
|
+
}
|
|
1706
|
+
return populate;
|
|
1686
1707
|
}
|
|
1687
1708
|
/**
|
|
1688
1709
|
* when the entity is found in identity map, we check if it was partially loaded or we are trying to populate
|
|
@@ -1702,7 +1723,7 @@ export class EntityManager {
|
|
|
1702
1723
|
return !inlineEmbedded && !prop.lazy && !helper(entity).__loadedProperties.has(prop.name);
|
|
1703
1724
|
});
|
|
1704
1725
|
}
|
|
1705
|
-
if (autoRefresh) {
|
|
1726
|
+
if (autoRefresh || options.filters) {
|
|
1706
1727
|
return true;
|
|
1707
1728
|
}
|
|
1708
1729
|
if (Array.isArray(options.populate)) {
|
|
@@ -1726,7 +1747,7 @@ export class EntityManager {
|
|
|
1726
1747
|
for (const k of ['ctx', 'strategy', 'flushMode', 'logging', 'loggerContext']) {
|
|
1727
1748
|
delete opts[k];
|
|
1728
1749
|
}
|
|
1729
|
-
return [entityName, method, opts, where];
|
|
1750
|
+
return [Utils.className(entityName), method, opts, where];
|
|
1730
1751
|
}
|
|
1731
1752
|
/**
|
|
1732
1753
|
* @internal
|
|
@@ -1743,21 +1764,17 @@ export class EntityManager {
|
|
|
1743
1764
|
return { key: cacheKey, data: cached };
|
|
1744
1765
|
}
|
|
1745
1766
|
let data;
|
|
1767
|
+
const createOptions = {
|
|
1768
|
+
merge: true,
|
|
1769
|
+
convertCustomTypes: false,
|
|
1770
|
+
refresh,
|
|
1771
|
+
recomputeSnapshot: true,
|
|
1772
|
+
};
|
|
1746
1773
|
if (Array.isArray(cached) && merge) {
|
|
1747
|
-
data = cached.map(item => em.entityFactory.create(entityName, item,
|
|
1748
|
-
merge: true,
|
|
1749
|
-
convertCustomTypes: true,
|
|
1750
|
-
refresh,
|
|
1751
|
-
recomputeSnapshot: true,
|
|
1752
|
-
}));
|
|
1774
|
+
data = cached.map(item => em.entityFactory.create(entityName, item, createOptions));
|
|
1753
1775
|
}
|
|
1754
1776
|
else if (Utils.isObject(cached) && merge) {
|
|
1755
|
-
data = em.entityFactory.create(entityName, cached,
|
|
1756
|
-
merge: true,
|
|
1757
|
-
convertCustomTypes: true,
|
|
1758
|
-
refresh,
|
|
1759
|
-
recomputeSnapshot: true,
|
|
1760
|
-
});
|
|
1777
|
+
data = em.entityFactory.create(entityName, cached, createOptions);
|
|
1761
1778
|
}
|
|
1762
1779
|
else {
|
|
1763
1780
|
data = cached;
|
|
@@ -1772,7 +1789,7 @@ export class EntityManager {
|
|
|
1772
1789
|
config ??= this.config.get('resultCache').global;
|
|
1773
1790
|
if (config) {
|
|
1774
1791
|
const em = this.getContext();
|
|
1775
|
-
const expiration = Array.isArray(config) ? config[1] : (
|
|
1792
|
+
const expiration = Array.isArray(config) ? config[1] : (typeof config === 'number' ? config : undefined);
|
|
1776
1793
|
await em.resultCache.set(key.key, data instanceof Function ? data() : data, '', expiration);
|
|
1777
1794
|
}
|
|
1778
1795
|
}
|
|
@@ -1805,6 +1822,20 @@ export class EntityManager {
|
|
|
1805
1822
|
set schema(schema) {
|
|
1806
1823
|
this.getContext(false)._schema = schema ?? undefined;
|
|
1807
1824
|
}
|
|
1825
|
+
/** @internal */
|
|
1826
|
+
async getDataLoader(type) {
|
|
1827
|
+
const em = this.getContext();
|
|
1828
|
+
if (em.loaders[type]) {
|
|
1829
|
+
return em.loaders[type];
|
|
1830
|
+
}
|
|
1831
|
+
const { DataloaderUtils } = await import('@mikro-orm/core/dataloader');
|
|
1832
|
+
const DataLoader = await DataloaderUtils.getDataLoader();
|
|
1833
|
+
switch (type) {
|
|
1834
|
+
case 'ref': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getRefBatchLoadFn(em)));
|
|
1835
|
+
case '1:m': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getColBatchLoadFn(em)));
|
|
1836
|
+
case 'm:n': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(em)));
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1808
1839
|
/**
|
|
1809
1840
|
* Returns the ID of this EntityManager. Respects the context, so global EM will give you the contextual ID
|
|
1810
1841
|
* if executed inside request context handler.
|
|
@@ -1813,7 +1844,7 @@ export class EntityManager {
|
|
|
1813
1844
|
return this.getContext(false)._id;
|
|
1814
1845
|
}
|
|
1815
1846
|
/** @ignore */
|
|
1816
|
-
[inspect.custom]() {
|
|
1847
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
1817
1848
|
return `[EntityManager<${this.id}>]`;
|
|
1818
1849
|
}
|
|
1819
1850
|
}
|