@mikro-orm/core 7.0.0-dev.5 → 7.0.0-dev.51
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 +81 -27
- package/EntityManager.js +287 -175
- package/MikroORM.d.ts +6 -6
- package/MikroORM.js +31 -74
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +2 -1
- package/cache/FileCacheAdapter.js +6 -4
- package/connections/Connection.d.ts +9 -5
- package/connections/Connection.js +16 -13
- package/decorators/Embedded.d.ts +5 -11
- package/decorators/Entity.d.ts +18 -3
- package/decorators/Indexed.d.ts +2 -2
- package/decorators/ManyToMany.d.ts +2 -0
- package/decorators/ManyToOne.d.ts +4 -0
- package/decorators/OneToOne.d.ts +4 -0
- package/decorators/Property.d.ts +53 -9
- package/decorators/Transactional.d.ts +1 -0
- package/decorators/Transactional.js +3 -3
- package/decorators/index.d.ts +1 -1
- package/drivers/DatabaseDriver.d.ts +10 -5
- package/drivers/DatabaseDriver.js +4 -4
- package/drivers/IDatabaseDriver.d.ts +28 -4
- package/entity/ArrayCollection.d.ts +6 -4
- package/entity/ArrayCollection.js +26 -9
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +3 -4
- package/entity/Collection.js +37 -17
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +9 -1
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +29 -11
- package/entity/EntityHelper.js +25 -8
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +69 -36
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityValidator.js +1 -1
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +30 -3
- package/entity/WrappedEntity.d.ts +0 -2
- package/entity/WrappedEntity.js +1 -5
- package/entity/defineEntity.d.ts +555 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +2 -0
- package/entity/index.js +2 -0
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +15 -3
- package/enums.d.ts +16 -3
- package/enums.js +13 -0
- package/errors.d.ts +6 -1
- package/errors.js +14 -4
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +35 -24
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +8 -4
- package/metadata/EntitySchema.js +39 -19
- package/metadata/MetadataDiscovery.d.ts +4 -4
- package/metadata/MetadataDiscovery.js +139 -122
- package/metadata/MetadataStorage.js +1 -1
- package/metadata/MetadataValidator.js +4 -3
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +7 -1
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/package.json +5 -5
- package/platforms/Platform.d.ts +5 -3
- package/platforms/Platform.js +4 -8
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +23 -5
- package/serialization/EntityTransformer.js +16 -6
- package/serialization/SerializationContext.js +14 -11
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +3 -0
- package/types/BooleanType.d.ts +1 -1
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +1 -1
- package/types/DoubleType.js +1 -1
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/index.d.ts +1 -1
- package/typings.d.ts +89 -49
- package/typings.js +31 -31
- package/unit-of-work/ChangeSetComputer.js +8 -3
- package/unit-of-work/ChangeSetPersister.d.ts +4 -2
- package/unit-of-work/ChangeSetPersister.js +37 -16
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +110 -53
- package/utils/AbstractSchemaGenerator.js +3 -1
- package/utils/Configuration.d.ts +200 -183
- package/utils/Configuration.js +137 -144
- package/utils/ConfigurationLoader.d.ts +9 -22
- package/utils/ConfigurationLoader.js +49 -72
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +3 -0
- package/utils/DataloaderUtils.d.ts +7 -2
- package/utils/DataloaderUtils.js +38 -7
- package/utils/EntityComparator.d.ts +6 -2
- package/utils/EntityComparator.js +104 -58
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +66 -5
- package/utils/RawQueryFragment.d.ts +36 -4
- package/utils/RawQueryFragment.js +34 -13
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +13 -11
- package/utils/Utils.js +82 -55
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +52 -1
package/EntityManager.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
2
|
import DataLoader from 'dataloader';
|
|
3
|
-
import { getOnConflictReturningFields } from './utils/upsert-utils.js';
|
|
3
|
+
import { getOnConflictReturningFields, getWhereCondition } from './utils/upsert-utils.js';
|
|
4
4
|
import { Utils } from './utils/Utils.js';
|
|
5
5
|
import { Cursor } from './utils/Cursor.js';
|
|
6
6
|
import { DataloaderUtils } from './utils/DataloaderUtils.js';
|
|
@@ -19,6 +19,8 @@ import { EventType, FlushMode, LoadStrategy, LockMode, PopulateHint, PopulatePat
|
|
|
19
19
|
import { EventManager } from './events/EventManager.js';
|
|
20
20
|
import { TransactionEventBroadcaster } from './events/TransactionEventBroadcaster.js';
|
|
21
21
|
import { OptimisticLockError, ValidationError } from './errors.js';
|
|
22
|
+
import { getLoadingStrategy } from './entity/utils.js';
|
|
23
|
+
import { TransactionManager } from './utils/TransactionManager.js';
|
|
22
24
|
/**
|
|
23
25
|
* The EntityManager is the central access point to ORM functionality. It is a facade to all different ORM subsystems
|
|
24
26
|
* such as UnitOfWork, Query Language, and Repository API.
|
|
@@ -36,6 +38,7 @@ export class EntityManager {
|
|
|
36
38
|
name;
|
|
37
39
|
refLoader = new DataLoader(DataloaderUtils.getRefBatchLoadFn(this));
|
|
38
40
|
colLoader = new DataLoader(DataloaderUtils.getColBatchLoadFn(this));
|
|
41
|
+
colLoaderMtoN = new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(this));
|
|
39
42
|
validator;
|
|
40
43
|
repositoryMap = {};
|
|
41
44
|
entityLoader;
|
|
@@ -137,7 +140,6 @@ export class EntityManager {
|
|
|
137
140
|
await em.entityLoader.populate(entityName, cached.data, populate, {
|
|
138
141
|
...options,
|
|
139
142
|
...em.getPopulateWhere(where, options),
|
|
140
|
-
convertCustomTypes: false,
|
|
141
143
|
ignoreLazyScalarProperties: true,
|
|
142
144
|
lookup: false,
|
|
143
145
|
});
|
|
@@ -148,8 +150,8 @@ export class EntityManager {
|
|
|
148
150
|
// save the original hint value so we know it was infer/all
|
|
149
151
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
150
152
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
151
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
152
|
-
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, ...options });
|
|
153
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
154
|
+
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
153
155
|
if (results.length === 0) {
|
|
154
156
|
await em.storeCache(options.cache, cached, []);
|
|
155
157
|
return [];
|
|
@@ -168,7 +170,6 @@ export class EntityManager {
|
|
|
168
170
|
await em.entityLoader.populate(entityName, unique, populate, {
|
|
169
171
|
...options,
|
|
170
172
|
...em.getPopulateWhere(where, options),
|
|
171
|
-
convertCustomTypes: false,
|
|
172
173
|
ignoreLazyScalarProperties: true,
|
|
173
174
|
lookup: false,
|
|
174
175
|
});
|
|
@@ -181,6 +182,61 @@ export class EntityManager {
|
|
|
181
182
|
}
|
|
182
183
|
return unique;
|
|
183
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Finds all entities and returns an async iterable (async generator) that yields results one by one.
|
|
187
|
+
* The results are merged and mapped to entity instances, without adding them to the identity map.
|
|
188
|
+
* You can disable merging by passing the options `{ mergeResults: false }`.
|
|
189
|
+
* With `mergeResults` disabled, to-many collections will contain at most one item, and you will get duplicate
|
|
190
|
+
* root entities when there are multiple items in the populated collection.
|
|
191
|
+
* This is useful for processing large datasets without loading everything into memory at once.
|
|
192
|
+
*
|
|
193
|
+
* ```ts
|
|
194
|
+
* const stream = em.stream(Book, { populate: ['author'] });
|
|
195
|
+
*
|
|
196
|
+
* for await (const book of stream) {
|
|
197
|
+
* // book is an instance of Book entity
|
|
198
|
+
* console.log(book.title, book.author.name);
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
async *stream(entityName, options = {}) {
|
|
203
|
+
const em = this.getContext();
|
|
204
|
+
em.prepareOptions(options);
|
|
205
|
+
options.strategy = 'joined';
|
|
206
|
+
await em.tryFlush(entityName, options);
|
|
207
|
+
entityName = Utils.className(entityName);
|
|
208
|
+
const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
|
|
209
|
+
em.validator.validateParams(where);
|
|
210
|
+
options.orderBy = options.orderBy || {};
|
|
211
|
+
options.populate = await em.preparePopulate(entityName, options);
|
|
212
|
+
const meta = this.metadata.get(entityName);
|
|
213
|
+
options = { ...options };
|
|
214
|
+
// save the original hint value so we know it was infer/all
|
|
215
|
+
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
216
|
+
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
217
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
218
|
+
const stream = em.driver.stream(entityName, where, {
|
|
219
|
+
ctx: em.transactionContext,
|
|
220
|
+
mapResults: false,
|
|
221
|
+
...options,
|
|
222
|
+
});
|
|
223
|
+
for await (const data of stream) {
|
|
224
|
+
const fork = em.fork();
|
|
225
|
+
const entity = fork.entityFactory.create(entityName, data, {
|
|
226
|
+
refresh: options.refresh,
|
|
227
|
+
schema: options.schema,
|
|
228
|
+
convertCustomTypes: true,
|
|
229
|
+
});
|
|
230
|
+
helper(entity).setSerializationContext({
|
|
231
|
+
populate: options.populate,
|
|
232
|
+
fields: options.fields,
|
|
233
|
+
exclude: options.exclude,
|
|
234
|
+
});
|
|
235
|
+
await fork.unitOfWork.dispatchOnLoadEvent();
|
|
236
|
+
fork.clear();
|
|
237
|
+
yield entity;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
184
240
|
/**
|
|
185
241
|
* Finds all entities of given type, optionally matching the `where` condition provided in the `options` parameter.
|
|
186
242
|
*/
|
|
@@ -200,15 +256,34 @@ export class EntityManager {
|
|
|
200
256
|
}
|
|
201
257
|
return { where: options.populateWhere };
|
|
202
258
|
}
|
|
259
|
+
// /**
|
|
260
|
+
// * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
261
|
+
// */
|
|
262
|
+
// addFilter<T1>(name: string, cond: FilterQuery<T1> | ((args: Dictionary) => MaybePromise<FilterQuery<T1>>), entityName?: EntityName<T1> | [EntityName<T1>], options?: boolean | Partial<FilterDef>): void;
|
|
263
|
+
//
|
|
264
|
+
// /**
|
|
265
|
+
// * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
266
|
+
// */
|
|
267
|
+
// addFilter<T1, T2>(name: string, cond: FilterQuery<T1 | T2> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2>>), entityName?: [EntityName<T1>, EntityName<T2>], options?: boolean | Partial<FilterDef>): void;
|
|
268
|
+
//
|
|
269
|
+
// /**
|
|
270
|
+
// * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
271
|
+
// */
|
|
272
|
+
// addFilter<T1, T2, T3>(name: string, cond: FilterQuery<T1 | T2 | T3> | ((args: Dictionary) => MaybePromise<FilterQuery<T1 | T2 | T3>>), entityName?: [EntityName<T1>, EntityName<T2>, EntityName<T3>], options?: boolean | Partial<FilterDef>): void;
|
|
273
|
+
//
|
|
274
|
+
// /**
|
|
275
|
+
// * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
276
|
+
// */
|
|
277
|
+
// addFilter(name: string, cond: Dictionary | ((args: Dictionary) => MaybePromise<FilterQuery<AnyEntity>>), entityName?: EntityName<AnyEntity> | EntityName<AnyEntity>[], options?: boolean | Partial<FilterDef>): void;
|
|
203
278
|
/**
|
|
204
279
|
* Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
|
|
205
280
|
*/
|
|
206
|
-
addFilter(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
options.entity = Utils.asArray(entityName).map(n => Utils.className(n));
|
|
281
|
+
addFilter(options) {
|
|
282
|
+
if (options.entity) {
|
|
283
|
+
options.entity = Utils.asArray(options.entity).map(n => Utils.className(n));
|
|
210
284
|
}
|
|
211
|
-
|
|
285
|
+
options.default ??= true;
|
|
286
|
+
this.getContext(false).filters[options.name] = options;
|
|
212
287
|
}
|
|
213
288
|
/**
|
|
214
289
|
* Sets filter parameter values globally inside context defined by this entity manager.
|
|
@@ -232,8 +307,8 @@ export class EntityManager {
|
|
|
232
307
|
/**
|
|
233
308
|
* Gets logger context for this entity manager.
|
|
234
309
|
*/
|
|
235
|
-
getLoggerContext() {
|
|
236
|
-
const em = this.getContext();
|
|
310
|
+
getLoggerContext(options) {
|
|
311
|
+
const em = options?.disableContextResolution ? this : this.getContext();
|
|
237
312
|
em.loggerContext ??= {};
|
|
238
313
|
return em.loggerContext;
|
|
239
314
|
}
|
|
@@ -283,28 +358,39 @@ export class EntityManager {
|
|
|
283
358
|
}
|
|
284
359
|
return ret;
|
|
285
360
|
}
|
|
286
|
-
async getJoinedFilters(meta,
|
|
361
|
+
async getJoinedFilters(meta, options) {
|
|
362
|
+
if (!this.config.get('filtersOnRelations') || !options.populate) {
|
|
363
|
+
return undefined;
|
|
364
|
+
}
|
|
287
365
|
const ret = {};
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
366
|
+
for (const hint of options.populate) {
|
|
367
|
+
const field = hint.field.split(':')[0];
|
|
368
|
+
const prop = meta.properties[field];
|
|
369
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
370
|
+
const joined = strategy === LoadStrategy.JOINED && prop.kind !== ReferenceKind.SCALAR;
|
|
371
|
+
if (!joined && !hint.filter) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
const filters = QueryHelper.mergePropertyFilters(prop.filters, options.filters);
|
|
375
|
+
const where = await this.applyFilters(prop.type, {}, filters, 'read', {
|
|
376
|
+
...options,
|
|
377
|
+
populate: hint.children,
|
|
378
|
+
});
|
|
379
|
+
const where2 = await this.getJoinedFilters(prop.targetMeta, {
|
|
380
|
+
...options,
|
|
381
|
+
filters,
|
|
382
|
+
populate: hint.children,
|
|
383
|
+
populateWhere: PopulateHint.ALL,
|
|
384
|
+
});
|
|
385
|
+
if (Utils.hasObjectKeys(where)) {
|
|
386
|
+
ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
|
|
387
|
+
}
|
|
388
|
+
if (where2 && Utils.hasObjectKeys(where2)) {
|
|
389
|
+
if (ret[field]) {
|
|
390
|
+
Utils.merge(ret[field], where2);
|
|
300
391
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Utils.merge(ret[field], where2);
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
ret[field] = where2;
|
|
307
|
-
}
|
|
392
|
+
else {
|
|
393
|
+
ret[field] = where2;
|
|
308
394
|
}
|
|
309
395
|
}
|
|
310
396
|
}
|
|
@@ -313,27 +399,45 @@ export class EntityManager {
|
|
|
313
399
|
/**
|
|
314
400
|
* 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.
|
|
315
401
|
*/
|
|
316
|
-
async autoJoinRefsForFilters(meta, options) {
|
|
317
|
-
if (!meta || !this.config.get('autoJoinRefsForFilters')) {
|
|
402
|
+
async autoJoinRefsForFilters(meta, options, parent) {
|
|
403
|
+
if (!meta || !this.config.get('autoJoinRefsForFilters') || options.filters === false) {
|
|
318
404
|
return;
|
|
319
405
|
}
|
|
320
|
-
const props = meta.relations.filter(prop => {
|
|
321
|
-
return !prop.object && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
322
|
-
&& ((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)));
|
|
323
|
-
});
|
|
324
406
|
const ret = options.populate;
|
|
325
|
-
for (const prop of
|
|
326
|
-
|
|
407
|
+
for (const prop of meta.relations) {
|
|
408
|
+
if (prop.object
|
|
409
|
+
|| ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
410
|
+
|| !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
|
|
411
|
+
|| (parent?.className === prop.targetMeta.root.className && parent.propName === prop.inversedBy)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
415
|
+
const cond = await this.applyFilters(prop.type, {}, options.filters, 'read', options);
|
|
327
416
|
if (!Utils.isEmpty(cond)) {
|
|
328
417
|
const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
|
|
329
|
-
|
|
330
|
-
|
|
418
|
+
let found = false;
|
|
419
|
+
for (const hint of populated) {
|
|
420
|
+
if (!hint.all) {
|
|
421
|
+
hint.filter = true;
|
|
422
|
+
}
|
|
423
|
+
const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
|
|
424
|
+
if (hint.field === `${prop.name}:ref` || (hint.filter && strategy === LoadStrategy.JOINED)) {
|
|
425
|
+
found = true;
|
|
426
|
+
}
|
|
331
427
|
}
|
|
332
|
-
|
|
428
|
+
if (!found) {
|
|
333
429
|
ret.push({ field: `${prop.name}:ref`, strategy: LoadStrategy.JOINED, filter: true });
|
|
334
430
|
}
|
|
335
431
|
}
|
|
336
432
|
}
|
|
433
|
+
for (const hint of ret) {
|
|
434
|
+
const [field, ref] = hint.field.split(':');
|
|
435
|
+
const prop = meta?.properties[field];
|
|
436
|
+
if (prop && !ref) {
|
|
437
|
+
hint.children ??= [];
|
|
438
|
+
await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { className: meta.root.className, propName: prop.name });
|
|
439
|
+
}
|
|
440
|
+
}
|
|
337
441
|
}
|
|
338
442
|
/**
|
|
339
443
|
* @internal
|
|
@@ -363,7 +467,7 @@ export class EntityManager {
|
|
|
363
467
|
let cond;
|
|
364
468
|
if (filter.cond instanceof Function) {
|
|
365
469
|
// @ts-ignore
|
|
366
|
-
const args = Utils.isPlainObject(options[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
470
|
+
const args = Utils.isPlainObject(options?.[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
367
471
|
if (!args && filter.cond.length > 0 && filter.args !== false) {
|
|
368
472
|
throw new Error(`No arguments provided for filter '${filter.name}'`);
|
|
369
473
|
}
|
|
@@ -372,13 +476,17 @@ export class EntityManager {
|
|
|
372
476
|
else {
|
|
373
477
|
cond = filter.cond;
|
|
374
478
|
}
|
|
375
|
-
|
|
479
|
+
cond = QueryHelper.processWhere({
|
|
376
480
|
where: cond,
|
|
377
481
|
entityName,
|
|
378
482
|
metadata: this.metadata,
|
|
379
483
|
platform: this.driver.getPlatform(),
|
|
380
484
|
aliased: type === 'read',
|
|
381
|
-
})
|
|
485
|
+
});
|
|
486
|
+
if (filter.strict) {
|
|
487
|
+
Object.defineProperty(cond, '__strict', { value: filter.strict, enumerable: false });
|
|
488
|
+
}
|
|
489
|
+
ret.push(cond);
|
|
382
490
|
}
|
|
383
491
|
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
|
|
384
492
|
return conds.length > 1 ? { $and: conds } : conds[0];
|
|
@@ -433,6 +541,10 @@ export class EntityManager {
|
|
|
433
541
|
* });
|
|
434
542
|
* ```
|
|
435
543
|
*
|
|
544
|
+
* The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
|
|
545
|
+
* returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
|
|
546
|
+
* of pages.
|
|
547
|
+
*
|
|
436
548
|
* The `Cursor` object provides the following interface:
|
|
437
549
|
*
|
|
438
550
|
* ```ts
|
|
@@ -442,7 +554,7 @@ export class EntityManager {
|
|
|
442
554
|
* User { ... },
|
|
443
555
|
* User { ... },
|
|
444
556
|
* ],
|
|
445
|
-
* totalCount: 50,
|
|
557
|
+
* totalCount: 50, // not included if `includeCount: false`
|
|
446
558
|
* startCursor: 'WzRd',
|
|
447
559
|
* endCursor: 'WzZd',
|
|
448
560
|
* hasPrevPage: true,
|
|
@@ -457,7 +569,9 @@ export class EntityManager {
|
|
|
457
569
|
if (Utils.isEmpty(options.orderBy)) {
|
|
458
570
|
throw new Error('Explicit `orderBy` option required');
|
|
459
571
|
}
|
|
460
|
-
const [entities, count] =
|
|
572
|
+
const [entities, count] = options.includeCount !== false
|
|
573
|
+
? await em.findAndCount(entityName, where, options)
|
|
574
|
+
: [await em.find(entityName, where, options)];
|
|
461
575
|
return new Cursor(entities, count, options, this.metadata.get(entityName));
|
|
462
576
|
}
|
|
463
577
|
/**
|
|
@@ -483,18 +597,31 @@ export class EntityManager {
|
|
|
483
597
|
async refresh(entity, options = {}) {
|
|
484
598
|
const fork = this.fork({ keepTransactionContext: true });
|
|
485
599
|
const entityName = entity.constructor.name;
|
|
600
|
+
const wrapped = helper(entity);
|
|
486
601
|
const reloaded = await fork.findOne(entityName, entity, {
|
|
487
|
-
schema:
|
|
602
|
+
schema: wrapped.__schema,
|
|
488
603
|
...options,
|
|
489
604
|
flushMode: FlushMode.COMMIT,
|
|
490
605
|
});
|
|
491
|
-
|
|
492
|
-
|
|
606
|
+
const em = this.getContext();
|
|
607
|
+
if (!reloaded) {
|
|
608
|
+
em.unitOfWork.unsetIdentity(entity);
|
|
609
|
+
return null;
|
|
493
610
|
}
|
|
494
|
-
|
|
495
|
-
|
|
611
|
+
let found = false;
|
|
612
|
+
for (const e of fork.unitOfWork.getIdentityMap()) {
|
|
613
|
+
const ref = em.getReference(e.constructor.name, helper(e).getPrimaryKey());
|
|
614
|
+
const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true });
|
|
615
|
+
em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, true);
|
|
616
|
+
Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
|
|
617
|
+
found ||= ref === entity;
|
|
618
|
+
}
|
|
619
|
+
if (!found) {
|
|
620
|
+
const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true });
|
|
621
|
+
em.config.getHydrator(this.metadata).hydrate(entity, wrapped.__meta, data, em.entityFactory, 'full', false, true);
|
|
622
|
+
Utils.merge(wrapped.__originalEntityData, this.comparator.prepareEntity(reloaded));
|
|
496
623
|
}
|
|
497
|
-
return
|
|
624
|
+
return entity;
|
|
498
625
|
}
|
|
499
626
|
/**
|
|
500
627
|
* Finds first entity matching your `where` query.
|
|
@@ -530,23 +657,25 @@ export class EntityManager {
|
|
|
530
657
|
options.populate = await em.preparePopulate(entityName, options);
|
|
531
658
|
const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
|
|
532
659
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
533
|
-
if (cached?.data) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
660
|
+
if (cached?.data !== undefined) {
|
|
661
|
+
if (cached.data) {
|
|
662
|
+
await em.entityLoader.populate(entityName, [cached.data], options.populate, {
|
|
663
|
+
...options,
|
|
664
|
+
...em.getPopulateWhere(where, options),
|
|
665
|
+
ignoreLazyScalarProperties: true,
|
|
666
|
+
lookup: false,
|
|
667
|
+
});
|
|
668
|
+
}
|
|
541
669
|
return cached.data;
|
|
542
670
|
}
|
|
543
671
|
options = { ...options };
|
|
544
672
|
// save the original hint value so we know it was infer/all
|
|
545
673
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
546
674
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
547
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
675
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
548
676
|
const data = await em.driver.findOne(entityName, where, {
|
|
549
677
|
ctx: em.transactionContext,
|
|
678
|
+
em,
|
|
550
679
|
...options,
|
|
551
680
|
});
|
|
552
681
|
if (!data) {
|
|
@@ -654,24 +783,7 @@ export class EntityManager {
|
|
|
654
783
|
}
|
|
655
784
|
}
|
|
656
785
|
}
|
|
657
|
-
|
|
658
|
-
const propIndex = !isRaw(unique) && unique.findIndex(p => data[p] != null);
|
|
659
|
-
if (options.onConflictFields || where == null) {
|
|
660
|
-
if (propIndex !== false && propIndex >= 0) {
|
|
661
|
-
where = { [unique[propIndex]]: data[unique[propIndex]] };
|
|
662
|
-
}
|
|
663
|
-
else if (meta.uniques.length > 0) {
|
|
664
|
-
for (const u of meta.uniques) {
|
|
665
|
-
if (Utils.asArray(u.properties).every(p => data[p] != null)) {
|
|
666
|
-
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
667
|
-
o[key] = data[key];
|
|
668
|
-
return o;
|
|
669
|
-
}, {});
|
|
670
|
-
break;
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
786
|
+
where = getWhereCondition(meta, options.onConflictFields, data, where).where;
|
|
675
787
|
data = QueryHelper.processObjectParams(data);
|
|
676
788
|
em.validator.validateParams(data, 'insert data');
|
|
677
789
|
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
@@ -716,6 +828,7 @@ export class EntityManager {
|
|
|
716
828
|
ctx: em.transactionContext,
|
|
717
829
|
convertCustomTypes: true,
|
|
718
830
|
connectionType: 'write',
|
|
831
|
+
schema: options.schema,
|
|
719
832
|
});
|
|
720
833
|
em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full', false, true);
|
|
721
834
|
}
|
|
@@ -813,31 +926,17 @@ export class EntityManager {
|
|
|
813
926
|
}
|
|
814
927
|
}
|
|
815
928
|
}
|
|
816
|
-
const unique = meta.props.filter(p => p.unique).map(p => p.name);
|
|
817
|
-
propIndex = unique.findIndex(p =>
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
where = { [unique[propIndex]]: row[unique[propIndex]] };
|
|
821
|
-
}
|
|
822
|
-
else if (meta.uniques.length > 0) {
|
|
823
|
-
for (const u of meta.uniques) {
|
|
824
|
-
if (Utils.asArray(u.properties).every(p => row[p] != null)) {
|
|
825
|
-
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
826
|
-
o[key] = row[key];
|
|
827
|
-
return o;
|
|
828
|
-
}, {});
|
|
829
|
-
break;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
row = QueryHelper.processObjectParams(row);
|
|
929
|
+
const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
930
|
+
propIndex = !isRaw(unique) && unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
931
|
+
const tmp = getWhereCondition(meta, options.onConflictFields, row, where);
|
|
932
|
+
propIndex = tmp.propIndex;
|
|
835
933
|
where = QueryHelper.processWhere({
|
|
836
|
-
where,
|
|
934
|
+
where: tmp.where,
|
|
837
935
|
entityName,
|
|
838
936
|
metadata: this.metadata,
|
|
839
937
|
platform: this.getPlatform(),
|
|
840
938
|
});
|
|
939
|
+
row = QueryHelper.processObjectParams(row);
|
|
841
940
|
em.validator.validateParams(row, 'insert data');
|
|
842
941
|
allData.push(row);
|
|
843
942
|
allWhere.push(where);
|
|
@@ -879,7 +978,7 @@ export class EntityManager {
|
|
|
879
978
|
const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
|
|
880
979
|
if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
|
|
881
980
|
const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
|
|
882
|
-
const add = new Set(propIndex >= 0 ? [unique[propIndex]] : []);
|
|
981
|
+
const add = new Set(propIndex !== false && propIndex >= 0 ? [unique[propIndex]] : []);
|
|
883
982
|
for (const cond of loadPK.values()) {
|
|
884
983
|
Utils.keys(cond).forEach(key => add.add(key));
|
|
885
984
|
}
|
|
@@ -896,6 +995,7 @@ export class EntityManager {
|
|
|
896
995
|
ctx: em.transactionContext,
|
|
897
996
|
convertCustomTypes: true,
|
|
898
997
|
connectionType: 'write',
|
|
998
|
+
schema: options.schema,
|
|
899
999
|
});
|
|
900
1000
|
for (const [entity, cond] of loadPK.entries()) {
|
|
901
1001
|
const row = data2.find(row => {
|
|
@@ -952,45 +1052,37 @@ export class EntityManager {
|
|
|
952
1052
|
}
|
|
953
1053
|
/**
|
|
954
1054
|
* Runs your callback wrapped inside a database transaction.
|
|
1055
|
+
*
|
|
1056
|
+
* If a transaction is already active, a new savepoint (nested transaction) will be created by default. This behavior
|
|
1057
|
+
* can be controlled via the `propagation` option. Use the provided EntityManager instance for all operations that
|
|
1058
|
+
* should be part of the transaction. You can safely use a global EntityManager instance from a DI container, as this
|
|
1059
|
+
* method automatically creates an async context for the transaction.
|
|
1060
|
+
*
|
|
1061
|
+
* **Concurrency note:** When running multiple transactions concurrently (e.g. in parallel requests or jobs), use the
|
|
1062
|
+
* `clear: true` option. This ensures the callback runs in a clear fork of the EntityManager, providing full isolation
|
|
1063
|
+
* between concurrent transactional handlers. Using `clear: true` is an alternative to forking explicitly and calling
|
|
1064
|
+
* the method on the new fork – it already provides the necessary isolation for safe concurrent usage.
|
|
1065
|
+
*
|
|
1066
|
+
* **Propagation note:** Changes made within a transaction (whether top-level or nested) are always propagated to the
|
|
1067
|
+
* parent context, unless the parent context is a global one. If you want to avoid that, fork the EntityManager first
|
|
1068
|
+
* and then call this method on the fork.
|
|
1069
|
+
*
|
|
1070
|
+
* **Example:**
|
|
1071
|
+
* ```ts
|
|
1072
|
+
* await em.transactional(async (em) => {
|
|
1073
|
+
* const author = new Author('Jon');
|
|
1074
|
+
* em.persist(author);
|
|
1075
|
+
* // flush is called automatically at the end of the callback
|
|
1076
|
+
* });
|
|
1077
|
+
* ```
|
|
955
1078
|
*/
|
|
956
1079
|
async transactional(cb, options = {}) {
|
|
957
1080
|
const em = this.getContext(false);
|
|
958
1081
|
if (this.disableTransactions || em.disableTransactions) {
|
|
959
1082
|
return cb(em);
|
|
960
1083
|
}
|
|
961
|
-
const
|
|
962
|
-
|
|
963
|
-
flushMode: options.flushMode,
|
|
964
|
-
cloneEventManager: true,
|
|
965
|
-
disableTransactions: options.ignoreNestedTransactions,
|
|
966
|
-
loggerContext: options.loggerContext,
|
|
967
|
-
});
|
|
968
|
-
options.ctx ??= em.transactionContext;
|
|
969
|
-
const propagateToUpperContext = !em.global || this.config.get('allowGlobalContext');
|
|
970
|
-
return TransactionContext.create(fork, async () => {
|
|
971
|
-
return fork.getConnection().transactional(async (trx) => {
|
|
972
|
-
fork.transactionContext = trx;
|
|
973
|
-
if (propagateToUpperContext) {
|
|
974
|
-
fork.eventManager.registerSubscriber({
|
|
975
|
-
afterFlush(args) {
|
|
976
|
-
args.uow.getChangeSets()
|
|
977
|
-
.filter(cs => [ChangeSetType.DELETE, ChangeSetType.DELETE_EARLY].includes(cs.type))
|
|
978
|
-
.forEach(cs => em.unitOfWork.unsetIdentity(cs.entity));
|
|
979
|
-
},
|
|
980
|
-
});
|
|
981
|
-
}
|
|
982
|
-
const ret = await cb(fork);
|
|
983
|
-
await fork.flush();
|
|
984
|
-
if (propagateToUpperContext) {
|
|
985
|
-
// ensure all entities from inner context are merged to the upper one
|
|
986
|
-
for (const entity of fork.unitOfWork.getIdentityMap()) {
|
|
987
|
-
em.unitOfWork.register(entity);
|
|
988
|
-
entity.__helper.__em = em;
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
return ret;
|
|
992
|
-
}, { ...options, eventBroadcaster: new TransactionEventBroadcaster(fork, { topLevelTransaction: !options.ctx }) });
|
|
993
|
-
});
|
|
1084
|
+
const manager = new TransactionManager(this);
|
|
1085
|
+
return manager.handle(cb, options);
|
|
994
1086
|
}
|
|
995
1087
|
/**
|
|
996
1088
|
* Starts new transaction bound to this EntityManager. Use `ctx` parameter to provide the parent when nesting transactions.
|
|
@@ -1170,22 +1262,35 @@ export class EntityManager {
|
|
|
1170
1262
|
* via second parameter. By default, it will return already loaded entities without modifying them.
|
|
1171
1263
|
*/
|
|
1172
1264
|
merge(entityName, data, options = {}) {
|
|
1173
|
-
const em = this.getContext();
|
|
1174
1265
|
if (Utils.isEntity(entityName)) {
|
|
1175
|
-
return
|
|
1266
|
+
return this.merge(entityName.constructor.name, entityName, data);
|
|
1176
1267
|
}
|
|
1268
|
+
const em = options.disableContextResolution ? this : this.getContext();
|
|
1177
1269
|
options.schema ??= em._schema;
|
|
1270
|
+
options.validate ??= true;
|
|
1271
|
+
options.cascade ??= true;
|
|
1178
1272
|
entityName = Utils.className(entityName);
|
|
1179
|
-
|
|
1273
|
+
if (options.validate) {
|
|
1274
|
+
em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1275
|
+
}
|
|
1180
1276
|
let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
|
|
1181
1277
|
if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
|
|
1182
1278
|
return entity;
|
|
1183
1279
|
}
|
|
1184
1280
|
const meta = em.metadata.find(entityName);
|
|
1185
1281
|
const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1282
|
+
const dataIsEntity = Utils.isEntity(data);
|
|
1283
|
+
if (options.keepIdentity && entity && dataIsEntity && entity !== data) {
|
|
1284
|
+
helper(entity).__data = helper(data).__data;
|
|
1285
|
+
helper(entity).__originalEntityData = helper(data).__originalEntityData;
|
|
1286
|
+
return entity;
|
|
1287
|
+
}
|
|
1288
|
+
entity = dataIsEntity ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
|
|
1289
|
+
if (options.validate) {
|
|
1290
|
+
em.validator.validate(entity, data, childMeta ?? meta);
|
|
1291
|
+
}
|
|
1292
|
+
const visited = options.cascade ? undefined : new Set([entity]);
|
|
1293
|
+
em.unitOfWork.merge(entity, visited);
|
|
1189
1294
|
return entity;
|
|
1190
1295
|
}
|
|
1191
1296
|
/**
|
|
@@ -1210,6 +1315,7 @@ export class EntityManager {
|
|
|
1210
1315
|
...options,
|
|
1211
1316
|
newEntity: !options.managed,
|
|
1212
1317
|
merge: options.managed,
|
|
1318
|
+
normalizeAccessors: true,
|
|
1213
1319
|
});
|
|
1214
1320
|
options.persist ??= em.config.get('persistOnCreate');
|
|
1215
1321
|
if (options.persist && !this.getMetadata(entityName).embeddable) {
|
|
@@ -1248,10 +1354,8 @@ export class EntityManager {
|
|
|
1248
1354
|
async count(entityName, where = {}, options = {}) {
|
|
1249
1355
|
const em = this.getContext(false);
|
|
1250
1356
|
// Shallow copy options since the object will be modified when deleting orderBy
|
|
1251
|
-
options = {
|
|
1252
|
-
|
|
1253
|
-
...options,
|
|
1254
|
-
};
|
|
1357
|
+
options = { ...options };
|
|
1358
|
+
em.prepareOptions(options);
|
|
1255
1359
|
entityName = Utils.className(entityName);
|
|
1256
1360
|
await em.tryFlush(entityName, options);
|
|
1257
1361
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
@@ -1261,15 +1365,15 @@ export class EntityManager {
|
|
|
1261
1365
|
const meta = em.metadata.find(entityName);
|
|
1262
1366
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
1263
1367
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
1264
|
-
options.populateFilter = await this.getJoinedFilters(meta,
|
|
1368
|
+
options.populateFilter = await this.getJoinedFilters(meta, options);
|
|
1265
1369
|
em.validator.validateParams(where);
|
|
1266
1370
|
delete options.orderBy;
|
|
1267
1371
|
const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
|
|
1268
1372
|
const cached = await em.tryCache(entityName, options.cache, cacheKey);
|
|
1269
|
-
if (cached?.data) {
|
|
1373
|
+
if (cached?.data !== undefined) {
|
|
1270
1374
|
return cached.data;
|
|
1271
1375
|
}
|
|
1272
|
-
const count = await em.driver.count(entityName, where, { ctx: em.transactionContext, ...options });
|
|
1376
|
+
const count = await em.driver.count(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
1273
1377
|
await em.storeCache(options.cache, cached, () => +count);
|
|
1274
1378
|
return +count;
|
|
1275
1379
|
}
|
|
@@ -1395,7 +1499,7 @@ export class EntityManager {
|
|
|
1395
1499
|
const em = this.getContext();
|
|
1396
1500
|
em.prepareOptions(options);
|
|
1397
1501
|
const entityName = arr[0].constructor.name;
|
|
1398
|
-
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate }, options.validate);
|
|
1502
|
+
const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
|
|
1399
1503
|
await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
|
|
1400
1504
|
return entities;
|
|
1401
1505
|
}
|
|
@@ -1431,6 +1535,9 @@ export class EntityManager {
|
|
|
1431
1535
|
for (const entity of em.unitOfWork.getIdentityMap()) {
|
|
1432
1536
|
fork.unitOfWork.register(entity);
|
|
1433
1537
|
}
|
|
1538
|
+
for (const entity of em.unitOfWork.getPersistStack()) {
|
|
1539
|
+
fork.unitOfWork.persist(entity);
|
|
1540
|
+
}
|
|
1434
1541
|
for (const entity of em.unitOfWork.getOrphanRemoveStack()) {
|
|
1435
1542
|
fork.unitOfWork.getOrphanRemoveStack().add(entity);
|
|
1436
1543
|
}
|
|
@@ -1452,6 +1559,12 @@ export class EntityManager {
|
|
|
1452
1559
|
getEntityFactory() {
|
|
1453
1560
|
return this.getContext().entityFactory;
|
|
1454
1561
|
}
|
|
1562
|
+
/**
|
|
1563
|
+
* @internal use `em.populate()` as the user facing API, this is exposed only for internal usage
|
|
1564
|
+
*/
|
|
1565
|
+
getEntityLoader() {
|
|
1566
|
+
return this.getContext().entityLoader;
|
|
1567
|
+
}
|
|
1455
1568
|
/**
|
|
1456
1569
|
* Gets the Hydrator used by the EntityManager.
|
|
1457
1570
|
*/
|
|
@@ -1548,7 +1661,6 @@ export class EntityManager {
|
|
|
1548
1661
|
...options,
|
|
1549
1662
|
...this.getPopulateWhere(where, options),
|
|
1550
1663
|
orderBy: options.populateOrderBy ?? options.orderBy,
|
|
1551
|
-
convertCustomTypes: false,
|
|
1552
1664
|
ignoreLazyScalarProperties: true,
|
|
1553
1665
|
lookup: false,
|
|
1554
1666
|
});
|
|
@@ -1671,7 +1783,7 @@ export class EntityManager {
|
|
|
1671
1783
|
throw new ValidationError(`Cannot combine 'fields' and 'exclude' option.`);
|
|
1672
1784
|
}
|
|
1673
1785
|
options.schema ??= this._schema;
|
|
1674
|
-
options.logging = Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
|
|
1786
|
+
options.logging = options.loggerContext = Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
|
|
1675
1787
|
}
|
|
1676
1788
|
/**
|
|
1677
1789
|
* @internal
|
|
@@ -1695,31 +1807,31 @@ export class EntityManager {
|
|
|
1695
1807
|
const em = this.getContext();
|
|
1696
1808
|
const cacheKey = Array.isArray(config) ? config[0] : JSON.stringify(key);
|
|
1697
1809
|
const cached = await em.resultCache.get(cacheKey);
|
|
1698
|
-
if (cached) {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
data = em.entityFactory.create(entityName, cached, {
|
|
1710
|
-
merge: true,
|
|
1711
|
-
convertCustomTypes: true,
|
|
1712
|
-
refresh,
|
|
1713
|
-
recomputeSnapshot: true,
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
else {
|
|
1717
|
-
data = cached;
|
|
1718
|
-
}
|
|
1719
|
-
await em.unitOfWork.dispatchOnLoadEvent();
|
|
1720
|
-
return { key: cacheKey, data };
|
|
1810
|
+
if (!cached) {
|
|
1811
|
+
return { key: cacheKey, data: cached };
|
|
1812
|
+
}
|
|
1813
|
+
let data;
|
|
1814
|
+
if (Array.isArray(cached) && merge) {
|
|
1815
|
+
data = cached.map(item => em.entityFactory.create(entityName, item, {
|
|
1816
|
+
merge: true,
|
|
1817
|
+
convertCustomTypes: true,
|
|
1818
|
+
refresh,
|
|
1819
|
+
recomputeSnapshot: true,
|
|
1820
|
+
}));
|
|
1721
1821
|
}
|
|
1722
|
-
|
|
1822
|
+
else if (Utils.isObject(cached) && merge) {
|
|
1823
|
+
data = em.entityFactory.create(entityName, cached, {
|
|
1824
|
+
merge: true,
|
|
1825
|
+
convertCustomTypes: true,
|
|
1826
|
+
refresh,
|
|
1827
|
+
recomputeSnapshot: true,
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
else {
|
|
1831
|
+
data = cached;
|
|
1832
|
+
}
|
|
1833
|
+
await em.unitOfWork.dispatchOnLoadEvent();
|
|
1834
|
+
return { key: cacheKey, data };
|
|
1723
1835
|
}
|
|
1724
1836
|
/**
|
|
1725
1837
|
* @internal
|