@mikro-orm/core 7.0.0-dev.29 → 7.0.0-dev.291
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 +67 -60
- package/EntityManager.js +275 -257
- 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 +118 -35
- package/drivers/IDatabaseDriver.d.ts +75 -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 +50 -17
- 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 +10 -15
- package/platforms/Platform.js +21 -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,11 @@ 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);
|
|
154
144
|
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
155
145
|
if (results.length === 0) {
|
|
156
146
|
await em.storeCache(options.cache, cached, []);
|
|
@@ -182,6 +172,60 @@ export class EntityManager {
|
|
|
182
172
|
}
|
|
183
173
|
return unique;
|
|
184
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Finds all entities and returns an async iterable (async generator) that yields results one by one.
|
|
177
|
+
* The results are merged and mapped to entity instances, without adding them to the identity map.
|
|
178
|
+
* You can disable merging by passing the options `{ mergeResults: false }`.
|
|
179
|
+
* With `mergeResults` disabled, to-many collections will contain at most one item, and you will get duplicate
|
|
180
|
+
* root entities when there are multiple items in the populated collection.
|
|
181
|
+
* This is useful for processing large datasets without loading everything into memory at once.
|
|
182
|
+
*
|
|
183
|
+
* ```ts
|
|
184
|
+
* const stream = em.stream(Book, { populate: ['author'] });
|
|
185
|
+
*
|
|
186
|
+
* for await (const book of stream) {
|
|
187
|
+
* // book is an instance of Book entity
|
|
188
|
+
* console.log(book.title, book.author.name);
|
|
189
|
+
* }
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
async *stream(entityName, options = {}) {
|
|
193
|
+
const em = this.getContext();
|
|
194
|
+
em.prepareOptions(options);
|
|
195
|
+
options.strategy = 'joined';
|
|
196
|
+
await em.tryFlush(entityName, options);
|
|
197
|
+
const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
|
|
198
|
+
validateParams(where);
|
|
199
|
+
options.orderBy = options.orderBy || {};
|
|
200
|
+
options.populate = await em.preparePopulate(entityName, options);
|
|
201
|
+
const meta = this.metadata.get(entityName);
|
|
202
|
+
options = { ...options };
|
|
203
|
+
// save the original hint value so we know it was infer/all
|
|
204
|
+
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
205
|
+
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
206
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
207
|
+
const stream = em.driver.stream(entityName, where, {
|
|
208
|
+
ctx: em.transactionContext,
|
|
209
|
+
mapResults: false,
|
|
210
|
+
...options,
|
|
211
|
+
});
|
|
212
|
+
for await (const data of stream) {
|
|
213
|
+
const fork = em.fork();
|
|
214
|
+
const entity = fork.entityFactory.create(entityName, data, {
|
|
215
|
+
refresh: options.refresh,
|
|
216
|
+
schema: options.schema,
|
|
217
|
+
convertCustomTypes: true,
|
|
218
|
+
});
|
|
219
|
+
helper(entity).setSerializationContext({
|
|
220
|
+
populate: options.populate,
|
|
221
|
+
fields: options.fields,
|
|
222
|
+
exclude: options.exclude,
|
|
223
|
+
});
|
|
224
|
+
await fork.unitOfWork.dispatchOnLoadEvent();
|
|
225
|
+
fork.clear();
|
|
226
|
+
yield entity;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
185
229
|
/**
|
|
186
230
|
* Finds all entities of given type, optionally matching the `where` condition provided in the `options` parameter.
|
|
187
231
|
*/
|
|
@@ -195,7 +239,7 @@ export class EntityManager {
|
|
|
195
239
|
if (options.populateWhere === PopulateHint.ALL) {
|
|
196
240
|
return { where: {}, populateWhere: options.populateWhere };
|
|
197
241
|
}
|
|
198
|
-
/* v8 ignore next
|
|
242
|
+
/* v8 ignore next */
|
|
199
243
|
if (options.populateWhere === PopulateHint.INFER) {
|
|
200
244
|
return { where, populateWhere: options.populateWhere };
|
|
201
245
|
}
|
|
@@ -204,12 +248,12 @@ export class EntityManager {
|
|
|
204
248
|
/**
|
|
205
249
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
206
250
|
*/
|
|
207
|
-
addFilter(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
options.entity = Utils.asArray(entityName).map(n => Utils.className(n));
|
|
251
|
+
addFilter(options) {
|
|
252
|
+
if (options.entity) {
|
|
253
|
+
options.entity = Utils.asArray(options.entity).map(n => Utils.className(n));
|
|
211
254
|
}
|
|
212
|
-
|
|
255
|
+
options.default ??= true;
|
|
256
|
+
this.getContext(false).filters[options.name] = options;
|
|
213
257
|
}
|
|
214
258
|
/**
|
|
215
259
|
* Sets filter parameter values globally inside context defined by this entity manager.
|
|
@@ -257,18 +301,18 @@ export class EntityManager {
|
|
|
257
301
|
// this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
|
|
258
302
|
applyDiscriminatorCondition(entityName, where) {
|
|
259
303
|
const meta = this.metadata.find(entityName);
|
|
260
|
-
if (!meta?.discriminatorValue) {
|
|
304
|
+
if (meta?.root.inheritanceType !== 'sti' || !meta?.discriminatorValue) {
|
|
261
305
|
return where;
|
|
262
306
|
}
|
|
263
|
-
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.
|
|
307
|
+
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.get(cls));
|
|
264
308
|
const children = [];
|
|
265
309
|
const lookUpChildren = (ret, type) => {
|
|
266
310
|
const children = types.filter(meta2 => meta2.extends === type);
|
|
267
|
-
children.forEach(m => lookUpChildren(ret, m.
|
|
311
|
+
children.forEach(m => lookUpChildren(ret, m.class));
|
|
268
312
|
ret.push(...children.filter(c => c.discriminatorValue));
|
|
269
313
|
return children;
|
|
270
314
|
};
|
|
271
|
-
lookUpChildren(children, meta.
|
|
315
|
+
lookUpChildren(children, meta.class);
|
|
272
316
|
/* v8 ignore next */
|
|
273
317
|
where[meta.root.discriminatorColumn] = children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue;
|
|
274
318
|
return where;
|
|
@@ -284,60 +328,77 @@ export class EntityManager {
|
|
|
284
328
|
}
|
|
285
329
|
return ret;
|
|
286
330
|
}
|
|
287
|
-
async getJoinedFilters(meta,
|
|
331
|
+
async getJoinedFilters(meta, options) {
|
|
332
|
+
// If user provided populateFilter, merge it with computed filters
|
|
333
|
+
const userFilter = options.populateFilter;
|
|
334
|
+
if (!this.config.get('filtersOnRelations') || !options.populate) {
|
|
335
|
+
return userFilter;
|
|
336
|
+
}
|
|
288
337
|
const ret = {};
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
338
|
+
for (const hint of options.populate) {
|
|
339
|
+
const field = hint.field.split(':')[0];
|
|
340
|
+
const prop = meta.properties[field];
|
|
341
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
342
|
+
const joined = strategy === LoadStrategy.JOINED && prop.kind !== ReferenceKind.SCALAR;
|
|
343
|
+
if (!joined && !hint.filter) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const filters = QueryHelper.mergePropertyFilters(prop.filters, options.filters);
|
|
347
|
+
const where = await this.applyFilters(prop.targetMeta.class, {}, filters, 'read', {
|
|
348
|
+
...options,
|
|
349
|
+
populate: hint.children,
|
|
350
|
+
});
|
|
351
|
+
const where2 = await this.getJoinedFilters(prop.targetMeta, {
|
|
352
|
+
...options,
|
|
353
|
+
filters,
|
|
354
|
+
populate: hint.children,
|
|
355
|
+
populateWhere: PopulateHint.ALL,
|
|
356
|
+
});
|
|
357
|
+
if (Utils.hasObjectKeys(where)) {
|
|
358
|
+
ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
|
|
359
|
+
}
|
|
360
|
+
if (where2 && Utils.hasObjectKeys(where2)) {
|
|
361
|
+
if (ret[field]) {
|
|
362
|
+
Utils.merge(ret[field], where2);
|
|
302
363
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
Utils.merge(ret[field], where2);
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
ret[field] = where2;
|
|
309
|
-
}
|
|
364
|
+
else {
|
|
365
|
+
ret[field] = where2;
|
|
310
366
|
}
|
|
311
367
|
}
|
|
312
368
|
}
|
|
313
|
-
|
|
369
|
+
// Merge user-provided populateFilter with computed filters
|
|
370
|
+
if (userFilter) {
|
|
371
|
+
Utils.merge(ret, userFilter);
|
|
372
|
+
}
|
|
373
|
+
return Utils.hasObjectKeys(ret) ? ret : undefined;
|
|
314
374
|
}
|
|
315
375
|
/**
|
|
316
376
|
* 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
377
|
*/
|
|
318
|
-
async autoJoinRefsForFilters(meta, options) {
|
|
319
|
-
if (!meta || !this.config.get('autoJoinRefsForFilters')) {
|
|
378
|
+
async autoJoinRefsForFilters(meta, options, parent) {
|
|
379
|
+
if (!meta || !this.config.get('autoJoinRefsForFilters') || options.filters === false) {
|
|
320
380
|
return;
|
|
321
381
|
}
|
|
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
382
|
const ret = options.populate;
|
|
327
|
-
for (const prop of
|
|
328
|
-
|
|
383
|
+
for (const prop of meta.relations) {
|
|
384
|
+
if (prop.object
|
|
385
|
+
|| ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
386
|
+
|| !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
387
|
+
|| (parent?.class === prop.targetMeta.root.class && parent.propName === prop.inversedBy)) {
|
|
388
|
+
continue;
|
|
389
|
+
}
|
|
390
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
391
|
+
const cond = await this.applyFilters(prop.targetMeta.class, {}, options.filters, 'read', options);
|
|
329
392
|
if (!Utils.isEmpty(cond)) {
|
|
330
393
|
const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
|
|
331
394
|
let found = false;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
found = true;
|
|
340
|
-
}
|
|
395
|
+
for (const hint of populated) {
|
|
396
|
+
if (!hint.all) {
|
|
397
|
+
hint.filter = true;
|
|
398
|
+
}
|
|
399
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
400
|
+
if (hint.field === `${prop.name}:ref` || (hint.filter && strategy === LoadStrategy.JOINED)) {
|
|
401
|
+
found = true;
|
|
341
402
|
}
|
|
342
403
|
}
|
|
343
404
|
if (!found) {
|
|
@@ -345,21 +406,26 @@ export class EntityManager {
|
|
|
345
406
|
}
|
|
346
407
|
}
|
|
347
408
|
}
|
|
409
|
+
for (const hint of ret) {
|
|
410
|
+
const [field, ref] = hint.field.split(':');
|
|
411
|
+
const prop = meta?.properties[field];
|
|
412
|
+
if (prop && !ref) {
|
|
413
|
+
hint.children ??= [];
|
|
414
|
+
await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { class: meta.root.class, propName: prop.name });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
348
417
|
}
|
|
349
418
|
/**
|
|
350
419
|
* @internal
|
|
351
420
|
*/
|
|
352
421
|
async applyFilters(entityName, where, options, type, findOptions) {
|
|
353
|
-
const meta = this.metadata.
|
|
422
|
+
const meta = this.metadata.get(entityName);
|
|
354
423
|
const filters = [];
|
|
355
424
|
const ret = [];
|
|
356
|
-
if (!meta) {
|
|
357
|
-
return where;
|
|
358
|
-
}
|
|
359
425
|
const active = new Set();
|
|
360
426
|
const push = (source) => {
|
|
361
427
|
const activeFilters = QueryHelper
|
|
362
|
-
.getActiveFilters(
|
|
428
|
+
.getActiveFilters(meta, options, source)
|
|
363
429
|
.filter(f => !active.has(f.name));
|
|
364
430
|
filters.push(...activeFilters);
|
|
365
431
|
activeFilters.forEach(f => active.add(f.name));
|
|
@@ -374,24 +440,28 @@ export class EntityManager {
|
|
|
374
440
|
let cond;
|
|
375
441
|
if (filter.cond instanceof Function) {
|
|
376
442
|
// @ts-ignore
|
|
377
|
-
const args = Utils.isPlainObject(options[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
443
|
+
const args = Utils.isPlainObject(options?.[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
378
444
|
if (!args && filter.cond.length > 0 && filter.args !== false) {
|
|
379
445
|
throw new Error(`No arguments provided for filter '${filter.name}'`);
|
|
380
446
|
}
|
|
381
|
-
cond = await filter.cond(args, type, this, findOptions, entityName);
|
|
447
|
+
cond = await filter.cond(args, type, this, findOptions, Utils.className(entityName));
|
|
382
448
|
}
|
|
383
449
|
else {
|
|
384
450
|
cond = filter.cond;
|
|
385
451
|
}
|
|
386
|
-
|
|
452
|
+
cond = QueryHelper.processWhere({
|
|
387
453
|
where: cond,
|
|
388
454
|
entityName,
|
|
389
455
|
metadata: this.metadata,
|
|
390
456
|
platform: this.driver.getPlatform(),
|
|
391
457
|
aliased: type === 'read',
|
|
392
|
-
})
|
|
458
|
+
});
|
|
459
|
+
if (filter.strict) {
|
|
460
|
+
Object.defineProperty(cond, '__strict', { value: filter.strict, enumerable: false });
|
|
461
|
+
}
|
|
462
|
+
ret.push(cond);
|
|
393
463
|
}
|
|
394
|
-
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
|
|
464
|
+
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c) || Raw.hasObjectFragments(c));
|
|
395
465
|
return conds.length > 1 ? { $and: conds } : conds[0];
|
|
396
466
|
}
|
|
397
467
|
/**
|
|
@@ -402,12 +472,10 @@ export class EntityManager {
|
|
|
402
472
|
const em = this.getContext(false);
|
|
403
473
|
await em.tryFlush(entityName, options);
|
|
404
474
|
options.flushMode = 'commit'; // do not try to auto flush again
|
|
405
|
-
return
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
]);
|
|
410
|
-
});
|
|
475
|
+
return Promise.all([
|
|
476
|
+
em.find(entityName, where, options),
|
|
477
|
+
em.count(entityName, where, options),
|
|
478
|
+
]);
|
|
411
479
|
}
|
|
412
480
|
/**
|
|
413
481
|
* Calls `em.find()` and `em.count()` with the same arguments (where applicable) and returns the results as {@apilink Cursor} object.
|
|
@@ -423,21 +491,21 @@ export class EntityManager {
|
|
|
423
491
|
* - POJO/entity instance
|
|
424
492
|
*
|
|
425
493
|
* ```ts
|
|
426
|
-
* const currentCursor = await em.findByCursor(User, {
|
|
494
|
+
* const currentCursor = await em.findByCursor(User, {
|
|
427
495
|
* first: 10,
|
|
428
496
|
* after: previousCursor, // cursor instance
|
|
429
497
|
* orderBy: { id: 'desc' },
|
|
430
498
|
* });
|
|
431
499
|
*
|
|
432
500
|
* // to fetch next page
|
|
433
|
-
* const nextCursor = await em.findByCursor(User, {
|
|
501
|
+
* const nextCursor = await em.findByCursor(User, {
|
|
434
502
|
* first: 10,
|
|
435
503
|
* after: currentCursor.endCursor, // opaque string
|
|
436
504
|
* orderBy: { id: 'desc' },
|
|
437
505
|
* });
|
|
438
506
|
*
|
|
439
507
|
* // to fetch next page
|
|
440
|
-
* const nextCursor2 = await em.findByCursor(User, {
|
|
508
|
+
* const nextCursor2 = await em.findByCursor(User, {
|
|
441
509
|
* first: 10,
|
|
442
510
|
* after: { id: lastSeenId }, // entity-like POJO
|
|
443
511
|
* orderBy: { id: 'desc' },
|
|
@@ -465,16 +533,16 @@ export class EntityManager {
|
|
|
465
533
|
* }
|
|
466
534
|
* ```
|
|
467
535
|
*/
|
|
468
|
-
async findByCursor(entityName,
|
|
536
|
+
async findByCursor(entityName, options) {
|
|
469
537
|
const em = this.getContext(false);
|
|
470
|
-
entityName = Utils.className(entityName);
|
|
471
538
|
options.overfetch ??= true;
|
|
472
|
-
|
|
539
|
+
options.where ??= {};
|
|
540
|
+
if (Utils.isEmpty(options.orderBy) && !Raw.hasObjectFragments(options.orderBy)) {
|
|
473
541
|
throw new Error('Explicit `orderBy` option required');
|
|
474
542
|
}
|
|
475
543
|
const [entities, count] = options.includeCount !== false
|
|
476
|
-
? await em.findAndCount(entityName, where, options)
|
|
477
|
-
: [await em.find(entityName, where, options)];
|
|
544
|
+
? await em.findAndCount(entityName, options.where, options)
|
|
545
|
+
: [await em.find(entityName, options.where, options)];
|
|
478
546
|
return new Cursor(entities, count, options, this.metadata.get(entityName));
|
|
479
547
|
}
|
|
480
548
|
/**
|
|
@@ -486,9 +554,9 @@ export class EntityManager {
|
|
|
486
554
|
const ret = await this.refresh(entity, options);
|
|
487
555
|
if (!ret) {
|
|
488
556
|
options.failHandler ??= this.config.get('findOneOrFailHandler');
|
|
489
|
-
const
|
|
490
|
-
const where =
|
|
491
|
-
throw options.failHandler(
|
|
557
|
+
const wrapped = helper(entity);
|
|
558
|
+
const where = wrapped.getPrimaryKey();
|
|
559
|
+
throw options.failHandler(wrapped.__meta.className, where);
|
|
492
560
|
}
|
|
493
561
|
return ret;
|
|
494
562
|
}
|
|
@@ -499,9 +567,9 @@ export class EntityManager {
|
|
|
499
567
|
*/
|
|
500
568
|
async refresh(entity, options = {}) {
|
|
501
569
|
const fork = this.fork({ keepTransactionContext: true });
|
|
502
|
-
const
|
|
503
|
-
const reloaded = await fork.findOne(
|
|
504
|
-
schema:
|
|
570
|
+
const wrapped = helper(entity);
|
|
571
|
+
const reloaded = await fork.findOne(wrapped.__meta.class, entity, {
|
|
572
|
+
schema: wrapped.__schema,
|
|
505
573
|
...options,
|
|
506
574
|
flushMode: FlushMode.COMMIT,
|
|
507
575
|
});
|
|
@@ -512,16 +580,16 @@ export class EntityManager {
|
|
|
512
580
|
}
|
|
513
581
|
let found = false;
|
|
514
582
|
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
|
|
583
|
+
const ref = em.getReference(e.constructor, helper(e).getPrimaryKey());
|
|
584
|
+
const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true, convertCustomTypes: false });
|
|
585
|
+
em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, false);
|
|
586
|
+
Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
|
|
519
587
|
found ||= ref === entity;
|
|
520
588
|
}
|
|
521
589
|
if (!found) {
|
|
522
|
-
const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true });
|
|
523
|
-
em.config.getHydrator(this.metadata).hydrate(entity,
|
|
524
|
-
|
|
590
|
+
const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true, convertCustomTypes: true });
|
|
591
|
+
em.config.getHydrator(this.metadata).hydrate(entity, wrapped.__meta, data, em.entityFactory, 'full', false, true);
|
|
592
|
+
Utils.merge(wrapped.__originalEntityData, this.comparator.prepareEntity(reloaded));
|
|
525
593
|
}
|
|
526
594
|
return entity;
|
|
527
595
|
}
|
|
@@ -537,7 +605,6 @@ export class EntityManager {
|
|
|
537
605
|
return ret;
|
|
538
606
|
}
|
|
539
607
|
const em = this.getContext();
|
|
540
|
-
entityName = Utils.className(entityName);
|
|
541
608
|
em.prepareOptions(options);
|
|
542
609
|
let entity = em.unitOfWork.tryGetById(entityName, where, options.schema);
|
|
543
610
|
// query for a not managed entity which is already in the identity map as it
|
|
@@ -549,13 +616,13 @@ export class EntityManager {
|
|
|
549
616
|
await em.tryFlush(entityName, options);
|
|
550
617
|
const meta = em.metadata.get(entityName);
|
|
551
618
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
552
|
-
|
|
619
|
+
validateEmptyWhere(where);
|
|
553
620
|
em.checkLockRequirements(options.lockMode, meta);
|
|
554
|
-
const isOptimisticLocking =
|
|
621
|
+
const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.OPTIMISTIC;
|
|
555
622
|
if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
|
|
556
623
|
return em.lockAndPopulate(meta, entity, where, options);
|
|
557
624
|
}
|
|
558
|
-
|
|
625
|
+
validateParams(where);
|
|
559
626
|
options.populate = await em.preparePopulate(entityName, options);
|
|
560
627
|
const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
|
|
561
628
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
@@ -574,7 +641,7 @@ export class EntityManager {
|
|
|
574
641
|
// save the original hint value so we know it was infer/all
|
|
575
642
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
576
643
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
577
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
644
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
578
645
|
const data = await em.driver.findOne(entityName, where, {
|
|
579
646
|
ctx: em.transactionContext,
|
|
580
647
|
em,
|
|
@@ -615,10 +682,10 @@ export class EntityManager {
|
|
|
615
682
|
if (!entity || isStrictViolation) {
|
|
616
683
|
const key = options.strict ? 'findExactlyOneOrFailHandler' : 'findOneOrFailHandler';
|
|
617
684
|
options.failHandler ??= this.config.get(key);
|
|
618
|
-
|
|
685
|
+
const name = Utils.className(entityName);
|
|
619
686
|
/* v8 ignore next */
|
|
620
687
|
where = Utils.isEntity(where) ? helper(where).getPrimaryKey() : where;
|
|
621
|
-
throw options.failHandler(
|
|
688
|
+
throw options.failHandler(name, where);
|
|
622
689
|
}
|
|
623
690
|
return entity;
|
|
624
691
|
}
|
|
@@ -658,11 +725,11 @@ export class EntityManager {
|
|
|
658
725
|
let where;
|
|
659
726
|
let entity = null;
|
|
660
727
|
if (data === undefined) {
|
|
661
|
-
entityName = entityNameOrEntity.constructor
|
|
728
|
+
entityName = entityNameOrEntity.constructor;
|
|
662
729
|
data = entityNameOrEntity;
|
|
663
730
|
}
|
|
664
731
|
else {
|
|
665
|
-
entityName =
|
|
732
|
+
entityName = entityNameOrEntity;
|
|
666
733
|
}
|
|
667
734
|
const meta = this.metadata.get(entityName);
|
|
668
735
|
const convertCustomTypes = !Utils.isEntity(data);
|
|
@@ -685,26 +752,9 @@ export class EntityManager {
|
|
|
685
752
|
}
|
|
686
753
|
}
|
|
687
754
|
}
|
|
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
|
-
}
|
|
755
|
+
where = getWhereCondition(meta, options.onConflictFields, data, where).where;
|
|
706
756
|
data = QueryHelper.processObjectParams(data);
|
|
707
|
-
|
|
757
|
+
validateParams(data, 'insert data');
|
|
708
758
|
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
709
759
|
await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity: data, em, meta }, meta);
|
|
710
760
|
}
|
|
@@ -742,7 +792,7 @@ export class EntityManager {
|
|
|
742
792
|
where[meta.primaryKeys[0]] = ret.insertId;
|
|
743
793
|
}
|
|
744
794
|
}
|
|
745
|
-
const data2 = await this.driver.findOne(meta.
|
|
795
|
+
const data2 = await this.driver.findOne(meta.class, where, {
|
|
746
796
|
fields: returning,
|
|
747
797
|
ctx: em.transactionContext,
|
|
748
798
|
convertCustomTypes: true,
|
|
@@ -797,11 +847,11 @@ export class EntityManager {
|
|
|
797
847
|
let entityName;
|
|
798
848
|
let propIndex;
|
|
799
849
|
if (data === undefined) {
|
|
800
|
-
entityName = entityNameOrEntity[0].constructor
|
|
850
|
+
entityName = entityNameOrEntity[0].constructor;
|
|
801
851
|
data = entityNameOrEntity;
|
|
802
852
|
}
|
|
803
853
|
else {
|
|
804
|
-
entityName =
|
|
854
|
+
entityName = entityNameOrEntity;
|
|
805
855
|
}
|
|
806
856
|
const batchSize = options.batchSize ?? this.config.get('batchSize');
|
|
807
857
|
if (data.length > batchSize) {
|
|
@@ -845,32 +895,18 @@ export class EntityManager {
|
|
|
845
895
|
}
|
|
846
896
|
}
|
|
847
897
|
}
|
|
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);
|
|
898
|
+
const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
899
|
+
propIndex = !isRaw(unique) && unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
900
|
+
const tmp = getWhereCondition(meta, options.onConflictFields, row, where);
|
|
901
|
+
propIndex = tmp.propIndex;
|
|
867
902
|
where = QueryHelper.processWhere({
|
|
868
|
-
where,
|
|
903
|
+
where: tmp.where,
|
|
869
904
|
entityName,
|
|
870
905
|
metadata: this.metadata,
|
|
871
906
|
platform: this.getPlatform(),
|
|
872
907
|
});
|
|
873
|
-
|
|
908
|
+
row = QueryHelper.processObjectParams(row);
|
|
909
|
+
validateParams(row, 'insert data');
|
|
874
910
|
allData.push(row);
|
|
875
911
|
allWhere.push(where);
|
|
876
912
|
}
|
|
@@ -911,7 +947,7 @@ export class EntityManager {
|
|
|
911
947
|
const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
|
|
912
948
|
if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
|
|
913
949
|
const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
|
|
914
|
-
const add = new Set(propIndex >= 0 ? [unique[propIndex]] : []);
|
|
950
|
+
const add = new Set(propIndex !== false && propIndex >= 0 ? [unique[propIndex]] : []);
|
|
915
951
|
for (const cond of loadPK.values()) {
|
|
916
952
|
Utils.keys(cond).forEach(key => add.add(key));
|
|
917
953
|
}
|
|
@@ -923,7 +959,7 @@ export class EntityManager {
|
|
|
923
959
|
where.$or[idx][prop] = item[prop];
|
|
924
960
|
});
|
|
925
961
|
});
|
|
926
|
-
const data2 = await this.driver.find(meta.
|
|
962
|
+
const data2 = await this.driver.find(meta.class, where, {
|
|
927
963
|
fields: returning.concat(...add).concat(...(Array.isArray(uniqueFields) ? uniqueFields : [])),
|
|
928
964
|
ctx: em.transactionContext,
|
|
929
965
|
convertCustomTypes: true,
|
|
@@ -940,7 +976,7 @@ export class EntityManager {
|
|
|
940
976
|
});
|
|
941
977
|
return this.comparator.matching(entityName, cond, tmp);
|
|
942
978
|
});
|
|
943
|
-
/* v8 ignore next
|
|
979
|
+
/* v8 ignore next */
|
|
944
980
|
if (!row) {
|
|
945
981
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
946
982
|
}
|
|
@@ -963,7 +999,7 @@ export class EntityManager {
|
|
|
963
999
|
}, {});
|
|
964
1000
|
return this.comparator.matching(entityName, cond, pk);
|
|
965
1001
|
});
|
|
966
|
-
/* v8 ignore next
|
|
1002
|
+
/* v8 ignore next */
|
|
967
1003
|
if (!row) {
|
|
968
1004
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
969
1005
|
}
|
|
@@ -1076,11 +1112,11 @@ export class EntityManager {
|
|
|
1076
1112
|
em.prepareOptions(options);
|
|
1077
1113
|
let entityName;
|
|
1078
1114
|
if (data === undefined) {
|
|
1079
|
-
entityName = entityNameOrEntity.constructor
|
|
1115
|
+
entityName = entityNameOrEntity.constructor;
|
|
1080
1116
|
data = entityNameOrEntity;
|
|
1081
1117
|
}
|
|
1082
1118
|
else {
|
|
1083
|
-
entityName =
|
|
1119
|
+
entityName = entityNameOrEntity;
|
|
1084
1120
|
}
|
|
1085
1121
|
if (Utils.isEntity(data)) {
|
|
1086
1122
|
if (options.schema && helper(data).getSchema() == null) {
|
|
@@ -1099,7 +1135,7 @@ export class EntityManager {
|
|
|
1099
1135
|
return cs.getPrimaryKey();
|
|
1100
1136
|
}
|
|
1101
1137
|
data = QueryHelper.processObjectParams(data);
|
|
1102
|
-
|
|
1138
|
+
validateParams(data, 'insert data');
|
|
1103
1139
|
const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1104
1140
|
return res.insertId;
|
|
1105
1141
|
}
|
|
@@ -1111,11 +1147,11 @@ export class EntityManager {
|
|
|
1111
1147
|
em.prepareOptions(options);
|
|
1112
1148
|
let entityName;
|
|
1113
1149
|
if (data === undefined) {
|
|
1114
|
-
entityName = entityNameOrEntities[0].constructor
|
|
1150
|
+
entityName = entityNameOrEntities[0].constructor;
|
|
1115
1151
|
data = entityNameOrEntities;
|
|
1116
1152
|
}
|
|
1117
1153
|
else {
|
|
1118
|
-
entityName =
|
|
1154
|
+
entityName = entityNameOrEntities;
|
|
1119
1155
|
}
|
|
1120
1156
|
if (data.length === 0) {
|
|
1121
1157
|
return [];
|
|
@@ -1139,7 +1175,7 @@ export class EntityManager {
|
|
|
1139
1175
|
return css.map(cs => cs.getPrimaryKey());
|
|
1140
1176
|
}
|
|
1141
1177
|
data = data.map(row => QueryHelper.processObjectParams(row));
|
|
1142
|
-
data.forEach(row =>
|
|
1178
|
+
data.forEach(row => validateParams(row, 'insert data'));
|
|
1143
1179
|
const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1144
1180
|
if (res.insertedIds) {
|
|
1145
1181
|
return res.insertedIds;
|
|
@@ -1152,11 +1188,10 @@ export class EntityManager {
|
|
|
1152
1188
|
async nativeUpdate(entityName, where, data, options = {}) {
|
|
1153
1189
|
const em = this.getContext(false);
|
|
1154
1190
|
em.prepareOptions(options);
|
|
1155
|
-
entityName = Utils.className(entityName);
|
|
1156
1191
|
data = QueryHelper.processObjectParams(data);
|
|
1157
1192
|
where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
|
|
1158
|
-
|
|
1159
|
-
|
|
1193
|
+
validateParams(data, 'update data');
|
|
1194
|
+
validateParams(where, 'update condition');
|
|
1160
1195
|
const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, ...options });
|
|
1161
1196
|
return res.affectedRows;
|
|
1162
1197
|
}
|
|
@@ -1166,9 +1201,8 @@ export class EntityManager {
|
|
|
1166
1201
|
async nativeDelete(entityName, where, options = {}) {
|
|
1167
1202
|
const em = this.getContext(false);
|
|
1168
1203
|
em.prepareOptions(options);
|
|
1169
|
-
entityName = Utils.className(entityName);
|
|
1170
1204
|
where = await em.processWhere(entityName, where, options, 'delete');
|
|
1171
|
-
|
|
1205
|
+
validateParams(where, 'delete condition');
|
|
1172
1206
|
const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
|
|
1173
1207
|
return res.affectedRows;
|
|
1174
1208
|
}
|
|
@@ -1176,18 +1210,19 @@ export class EntityManager {
|
|
|
1176
1210
|
* Maps raw database result to an entity and merges it to this EntityManager.
|
|
1177
1211
|
*/
|
|
1178
1212
|
map(entityName, result, options = {}) {
|
|
1179
|
-
entityName = Utils.className(entityName);
|
|
1180
1213
|
const meta = this.metadata.get(entityName);
|
|
1181
1214
|
const data = this.driver.mapResult(result, meta);
|
|
1182
|
-
Object.keys(data)
|
|
1215
|
+
for (const k of Object.keys(data)) {
|
|
1183
1216
|
const prop = meta.properties[k];
|
|
1184
|
-
if (prop
|
|
1185
|
-
|
|
1217
|
+
if (prop?.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
|
|
1218
|
+
validateProperty(prop, data[k], data);
|
|
1186
1219
|
}
|
|
1187
|
-
}
|
|
1220
|
+
}
|
|
1188
1221
|
return this.merge(entityName, data, {
|
|
1189
1222
|
convertCustomTypes: true,
|
|
1190
|
-
refresh: true,
|
|
1223
|
+
refresh: true,
|
|
1224
|
+
validate: false,
|
|
1225
|
+
...options,
|
|
1191
1226
|
});
|
|
1192
1227
|
}
|
|
1193
1228
|
/**
|
|
@@ -1196,32 +1231,19 @@ export class EntityManager {
|
|
|
1196
1231
|
*/
|
|
1197
1232
|
merge(entityName, data, options = {}) {
|
|
1198
1233
|
if (Utils.isEntity(entityName)) {
|
|
1199
|
-
return this.merge(entityName.constructor
|
|
1234
|
+
return this.merge(entityName.constructor, entityName, data);
|
|
1200
1235
|
}
|
|
1201
1236
|
const em = options.disableContextResolution ? this : this.getContext();
|
|
1202
1237
|
options.schema ??= em._schema;
|
|
1203
1238
|
options.validate ??= true;
|
|
1204
1239
|
options.cascade ??= true;
|
|
1205
|
-
|
|
1206
|
-
if (options.validate) {
|
|
1207
|
-
em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1208
|
-
}
|
|
1240
|
+
validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1209
1241
|
let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
|
|
1210
1242
|
if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
|
|
1211
1243
|
return entity;
|
|
1212
1244
|
}
|
|
1213
|
-
const meta = em.metadata.find(entityName);
|
|
1214
|
-
const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
|
|
1215
1245
|
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
1246
|
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
1247
|
const visited = options.cascade ? undefined : new Set([entity]);
|
|
1226
1248
|
em.unitOfWork.merge(entity, visited);
|
|
1227
1249
|
return entity;
|
|
@@ -1248,6 +1270,7 @@ export class EntityManager {
|
|
|
1248
1270
|
...options,
|
|
1249
1271
|
newEntity: !options.managed,
|
|
1250
1272
|
merge: options.managed,
|
|
1273
|
+
normalizeAccessors: true,
|
|
1251
1274
|
});
|
|
1252
1275
|
options.persist ??= em.config.get('persistOnCreate');
|
|
1253
1276
|
if (options.persist && !this.getMetadata(entityName).embeddable) {
|
|
@@ -1267,7 +1290,7 @@ export class EntityManager {
|
|
|
1267
1290
|
getReference(entityName, id, options = {}) {
|
|
1268
1291
|
options.schema ??= this.schema;
|
|
1269
1292
|
options.convertCustomTypes ??= false;
|
|
1270
|
-
const meta = this.metadata.get(
|
|
1293
|
+
const meta = this.metadata.get(entityName);
|
|
1271
1294
|
if (Utils.isPrimaryKey(id)) {
|
|
1272
1295
|
if (meta.compositePK) {
|
|
1273
1296
|
throw ValidationError.invalidCompositeIdentifier(meta);
|
|
@@ -1288,7 +1311,6 @@ export class EntityManager {
|
|
|
1288
1311
|
// Shallow copy options since the object will be modified when deleting orderBy
|
|
1289
1312
|
options = { ...options };
|
|
1290
1313
|
em.prepareOptions(options);
|
|
1291
|
-
entityName = Utils.className(entityName);
|
|
1292
1314
|
await em.tryFlush(entityName, options);
|
|
1293
1315
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
1294
1316
|
options.populate = await em.preparePopulate(entityName, options);
|
|
@@ -1297,8 +1319,8 @@ export class EntityManager {
|
|
|
1297
1319
|
const meta = em.metadata.find(entityName);
|
|
1298
1320
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
1299
1321
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
1300
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
1301
|
-
|
|
1322
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
1323
|
+
validateParams(where);
|
|
1302
1324
|
delete options.orderBy;
|
|
1303
1325
|
const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
|
|
1304
1326
|
const cached = await em.tryCache(entityName, options.cache, cacheKey);
|
|
@@ -1324,7 +1346,7 @@ export class EntityManager {
|
|
|
1324
1346
|
for (const ent of entities) {
|
|
1325
1347
|
if (!Utils.isEntity(ent, true)) {
|
|
1326
1348
|
/* v8 ignore next */
|
|
1327
|
-
const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor
|
|
1349
|
+
const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor) : undefined;
|
|
1328
1350
|
throw ValidationError.notDiscoveredEntity(ent, meta);
|
|
1329
1351
|
}
|
|
1330
1352
|
// do not cascade just yet, cascading of entities in persist stack is done when flushing
|
|
@@ -1332,13 +1354,6 @@ export class EntityManager {
|
|
|
1332
1354
|
}
|
|
1333
1355
|
return this;
|
|
1334
1356
|
}
|
|
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
1357
|
/**
|
|
1343
1358
|
* Marks entity for removal.
|
|
1344
1359
|
* A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
|
|
@@ -1362,13 +1377,6 @@ export class EntityManager {
|
|
|
1362
1377
|
}
|
|
1363
1378
|
return em;
|
|
1364
1379
|
}
|
|
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
1380
|
/**
|
|
1373
1381
|
* Flushes all changes to objects that have been queued up to now to the database.
|
|
1374
1382
|
* This effectively synchronizes the in-memory state of managed objects with the database.
|
|
@@ -1382,7 +1390,6 @@ export class EntityManager {
|
|
|
1382
1390
|
async tryFlush(entityName, options) {
|
|
1383
1391
|
const em = this.getContext();
|
|
1384
1392
|
const flushMode = options.flushMode ?? em.flushMode ?? em.config.get('flushMode');
|
|
1385
|
-
entityName = Utils.className(entityName);
|
|
1386
1393
|
const meta = em.metadata.get(entityName);
|
|
1387
1394
|
if (flushMode === FlushMode.COMMIT) {
|
|
1388
1395
|
return;
|
|
@@ -1401,7 +1408,6 @@ export class EntityManager {
|
|
|
1401
1408
|
* Checks whether given property can be populated on the entity.
|
|
1402
1409
|
*/
|
|
1403
1410
|
canPopulate(entityName, property) {
|
|
1404
|
-
entityName = Utils.className(entityName);
|
|
1405
1411
|
// eslint-disable-next-line prefer-const
|
|
1406
1412
|
let [p, ...parts] = property.split('.');
|
|
1407
1413
|
const meta = this.metadata.find(entityName);
|
|
@@ -1411,12 +1417,11 @@ export class EntityManager {
|
|
|
1411
1417
|
if (p.includes(':')) {
|
|
1412
1418
|
p = p.split(':', 2)[0];
|
|
1413
1419
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1420
|
+
// For TPT inheritance, check the entity's own properties, not just the root's
|
|
1421
|
+
// For STI, meta.properties includes all properties anyway
|
|
1422
|
+
const ret = p in meta.properties;
|
|
1418
1423
|
if (parts.length > 0) {
|
|
1419
|
-
return this.canPopulate(
|
|
1424
|
+
return this.canPopulate(meta.properties[p].targetMeta.class, parts.join('.'));
|
|
1420
1425
|
}
|
|
1421
1426
|
return ret;
|
|
1422
1427
|
}
|
|
@@ -1430,8 +1435,8 @@ export class EntityManager {
|
|
|
1430
1435
|
}
|
|
1431
1436
|
const em = this.getContext();
|
|
1432
1437
|
em.prepareOptions(options);
|
|
1433
|
-
const entityName = arr[0].constructor
|
|
1434
|
-
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate }, options.validate);
|
|
1438
|
+
const entityName = arr[0].constructor;
|
|
1439
|
+
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
|
|
1435
1440
|
await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
|
|
1436
1441
|
return entities;
|
|
1437
1442
|
}
|
|
@@ -1559,7 +1564,6 @@ export class EntityManager {
|
|
|
1559
1564
|
*/
|
|
1560
1565
|
getMetadata(entityName) {
|
|
1561
1566
|
if (entityName) {
|
|
1562
|
-
entityName = Utils.className(entityName);
|
|
1563
1567
|
return this.metadata.get(entityName);
|
|
1564
1568
|
}
|
|
1565
1569
|
return this.metadata;
|
|
@@ -1588,8 +1592,8 @@ export class EntityManager {
|
|
|
1588
1592
|
lockTableAliases: options.lockTableAliases,
|
|
1589
1593
|
});
|
|
1590
1594
|
}
|
|
1591
|
-
const preparedPopulate = await this.preparePopulate(meta.
|
|
1592
|
-
await this.entityLoader.populate(meta.
|
|
1595
|
+
const preparedPopulate = await this.preparePopulate(meta.class, options);
|
|
1596
|
+
await this.entityLoader.populate(meta.class, [entity], preparedPopulate, {
|
|
1593
1597
|
...options,
|
|
1594
1598
|
...this.getPopulateWhere(where, options),
|
|
1595
1599
|
orderBy: options.populateOrderBy ?? options.orderBy,
|
|
@@ -1609,6 +1613,7 @@ export class EntityManager {
|
|
|
1609
1613
|
return ret;
|
|
1610
1614
|
}, []);
|
|
1611
1615
|
}
|
|
1616
|
+
/** @internal */
|
|
1612
1617
|
async preparePopulate(entityName, options, validate = true) {
|
|
1613
1618
|
if (options.populate === false) {
|
|
1614
1619
|
return [];
|
|
@@ -1649,13 +1654,13 @@ export class EntityManager {
|
|
|
1649
1654
|
options.populate = pruneToOneRelations(meta, this.buildFields(options.fields));
|
|
1650
1655
|
}
|
|
1651
1656
|
if (!options.populate) {
|
|
1652
|
-
const populate = this.entityLoader.normalizePopulate(entityName, [], options.strategy);
|
|
1657
|
+
const populate = this.entityLoader.normalizePopulate(entityName, [], options.strategy, true, options.exclude);
|
|
1653
1658
|
await this.autoJoinRefsForFilters(meta, { ...options, populate });
|
|
1654
1659
|
return populate;
|
|
1655
1660
|
}
|
|
1656
1661
|
if (typeof options.populate !== 'boolean') {
|
|
1657
1662
|
options.populate = Utils.asArray(options.populate).map(field => {
|
|
1658
|
-
/* v8 ignore next
|
|
1663
|
+
/* v8 ignore next */
|
|
1659
1664
|
if (typeof field === 'boolean' || field === PopulatePath.ALL) {
|
|
1660
1665
|
return [{ field: meta.primaryKeys[0], strategy: options.strategy, all: !!field }]; //
|
|
1661
1666
|
}
|
|
@@ -1665,24 +1670,27 @@ export class EntityManager {
|
|
|
1665
1670
|
options.flags.push(QueryFlag.INFER_POPULATE);
|
|
1666
1671
|
return [];
|
|
1667
1672
|
}
|
|
1668
|
-
if (
|
|
1673
|
+
if (typeof field === 'string') {
|
|
1669
1674
|
return [{ field, strategy: options.strategy }];
|
|
1670
1675
|
}
|
|
1671
1676
|
return [field];
|
|
1672
1677
|
}).flat();
|
|
1673
1678
|
}
|
|
1674
|
-
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy);
|
|
1679
|
+
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy, true, options.exclude);
|
|
1675
1680
|
const invalid = populate.find(({ field }) => !this.canPopulate(entityName, field));
|
|
1676
1681
|
if (validate && invalid) {
|
|
1677
1682
|
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
|
1678
1683
|
}
|
|
1679
1684
|
await this.autoJoinRefsForFilters(meta, { ...options, populate });
|
|
1680
|
-
|
|
1685
|
+
for (const field of populate) {
|
|
1681
1686
|
// force select-in strategy when populating all relations as otherwise we could cause infinite loops when self-referencing
|
|
1682
1687
|
const all = field.all ?? (Array.isArray(options.populate) && options.populate.includes('*'));
|
|
1683
1688
|
field.strategy = all ? LoadStrategy.SELECT_IN : (options.strategy ?? field.strategy);
|
|
1684
|
-
|
|
1685
|
-
|
|
1689
|
+
}
|
|
1690
|
+
if (options.populateHints) {
|
|
1691
|
+
applyPopulateHints(populate, options.populateHints);
|
|
1692
|
+
}
|
|
1693
|
+
return populate;
|
|
1686
1694
|
}
|
|
1687
1695
|
/**
|
|
1688
1696
|
* when the entity is found in identity map, we check if it was partially loaded or we are trying to populate
|
|
@@ -1702,7 +1710,7 @@ export class EntityManager {
|
|
|
1702
1710
|
return !inlineEmbedded && !prop.lazy && !helper(entity).__loadedProperties.has(prop.name);
|
|
1703
1711
|
});
|
|
1704
1712
|
}
|
|
1705
|
-
if (autoRefresh) {
|
|
1713
|
+
if (autoRefresh || options.filters) {
|
|
1706
1714
|
return true;
|
|
1707
1715
|
}
|
|
1708
1716
|
if (Array.isArray(options.populate)) {
|
|
@@ -1726,7 +1734,7 @@ export class EntityManager {
|
|
|
1726
1734
|
for (const k of ['ctx', 'strategy', 'flushMode', 'logging', 'loggerContext']) {
|
|
1727
1735
|
delete opts[k];
|
|
1728
1736
|
}
|
|
1729
|
-
return [entityName, method, opts, where];
|
|
1737
|
+
return [Utils.className(entityName), method, opts, where];
|
|
1730
1738
|
}
|
|
1731
1739
|
/**
|
|
1732
1740
|
* @internal
|
|
@@ -1743,21 +1751,17 @@ export class EntityManager {
|
|
|
1743
1751
|
return { key: cacheKey, data: cached };
|
|
1744
1752
|
}
|
|
1745
1753
|
let data;
|
|
1754
|
+
const createOptions = {
|
|
1755
|
+
merge: true,
|
|
1756
|
+
convertCustomTypes: false,
|
|
1757
|
+
refresh,
|
|
1758
|
+
recomputeSnapshot: true,
|
|
1759
|
+
};
|
|
1746
1760
|
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
|
-
}));
|
|
1761
|
+
data = cached.map(item => em.entityFactory.create(entityName, item, createOptions));
|
|
1753
1762
|
}
|
|
1754
1763
|
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
|
-
});
|
|
1764
|
+
data = em.entityFactory.create(entityName, cached, createOptions);
|
|
1761
1765
|
}
|
|
1762
1766
|
else {
|
|
1763
1767
|
data = cached;
|
|
@@ -1772,7 +1776,7 @@ export class EntityManager {
|
|
|
1772
1776
|
config ??= this.config.get('resultCache').global;
|
|
1773
1777
|
if (config) {
|
|
1774
1778
|
const em = this.getContext();
|
|
1775
|
-
const expiration = Array.isArray(config) ? config[1] : (
|
|
1779
|
+
const expiration = Array.isArray(config) ? config[1] : (typeof config === 'number' ? config : undefined);
|
|
1776
1780
|
await em.resultCache.set(key.key, data instanceof Function ? data() : data, '', expiration);
|
|
1777
1781
|
}
|
|
1778
1782
|
}
|
|
@@ -1805,6 +1809,20 @@ export class EntityManager {
|
|
|
1805
1809
|
set schema(schema) {
|
|
1806
1810
|
this.getContext(false)._schema = schema ?? undefined;
|
|
1807
1811
|
}
|
|
1812
|
+
/** @internal */
|
|
1813
|
+
async getDataLoader(type) {
|
|
1814
|
+
const em = this.getContext();
|
|
1815
|
+
if (em.loaders[type]) {
|
|
1816
|
+
return em.loaders[type];
|
|
1817
|
+
}
|
|
1818
|
+
const { DataloaderUtils } = await import('@mikro-orm/core/dataloader');
|
|
1819
|
+
const DataLoader = await DataloaderUtils.getDataLoader();
|
|
1820
|
+
switch (type) {
|
|
1821
|
+
case 'ref': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getRefBatchLoadFn(em)));
|
|
1822
|
+
case '1:m': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getColBatchLoadFn(em)));
|
|
1823
|
+
case 'm:n': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(em)));
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1808
1826
|
/**
|
|
1809
1827
|
* Returns the ID of this EntityManager. Respects the context, so global EM will give you the contextual ID
|
|
1810
1828
|
* if executed inside request context handler.
|
|
@@ -1813,7 +1831,7 @@ export class EntityManager {
|
|
|
1813
1831
|
return this.getContext(false)._id;
|
|
1814
1832
|
}
|
|
1815
1833
|
/** @ignore */
|
|
1816
|
-
[inspect.custom]() {
|
|
1834
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
1817
1835
|
return `[EntityManager<${this.id}>]`;
|
|
1818
1836
|
}
|
|
1819
1837
|
}
|