@mikro-orm/core 7.0.0-dev.1 → 7.0.0-dev.11
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 +25 -16
- package/EntityManager.js +219 -209
- package/MikroORM.d.ts +7 -6
- package/MikroORM.js +33 -45
- package/cache/CacheAdapter.js +1 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +18 -26
- package/cache/GeneratedCacheAdapter.d.ts +2 -2
- package/cache/GeneratedCacheAdapter.js +1 -5
- package/cache/MemoryCacheAdapter.d.ts +1 -1
- package/cache/MemoryCacheAdapter.js +1 -5
- package/cache/NullCacheAdapter.d.ts +1 -1
- package/cache/NullCacheAdapter.js +1 -5
- package/cache/index.d.ts +5 -5
- package/cache/index.js +5 -21
- package/connections/Connection.d.ts +7 -7
- package/connections/Connection.js +8 -12
- package/connections/index.d.ts +1 -1
- package/connections/index.js +1 -17
- package/decorators/Check.d.ts +2 -2
- package/decorators/Check.js +5 -8
- package/decorators/CreateRequestContext.d.ts +1 -1
- package/decorators/CreateRequestContext.js +13 -14
- package/decorators/Embeddable.d.ts +5 -5
- package/decorators/Embeddable.js +4 -7
- package/decorators/Embedded.d.ts +3 -3
- package/decorators/Embedded.js +10 -12
- package/decorators/Entity.d.ts +6 -6
- package/decorators/Entity.js +5 -9
- package/decorators/Enum.d.ts +3 -3
- package/decorators/Enum.js +7 -10
- package/decorators/Filter.d.ts +1 -1
- package/decorators/Filter.js +3 -6
- package/decorators/Formula.d.ts +2 -3
- package/decorators/Formula.js +7 -10
- package/decorators/Indexed.d.ts +10 -8
- package/decorators/Indexed.js +7 -11
- package/decorators/ManyToMany.d.ts +4 -4
- package/decorators/ManyToMany.js +10 -12
- package/decorators/ManyToOne.d.ts +4 -4
- package/decorators/ManyToOne.js +10 -12
- package/decorators/OneToMany.d.ts +6 -6
- package/decorators/OneToMany.js +11 -14
- package/decorators/OneToOne.d.ts +4 -4
- package/decorators/OneToOne.js +4 -7
- package/decorators/PrimaryKey.d.ts +3 -4
- package/decorators/PrimaryKey.js +10 -13
- package/decorators/Property.d.ts +6 -6
- package/decorators/Property.js +10 -12
- package/decorators/Transactional.d.ts +2 -2
- package/decorators/Transactional.js +7 -10
- package/decorators/hooks.js +23 -35
- package/decorators/index.d.ts +17 -17
- package/decorators/index.js +17 -36
- package/drivers/DatabaseDriver.d.ts +13 -12
- package/drivers/DatabaseDriver.js +60 -64
- package/drivers/IDatabaseDriver.d.ts +16 -13
- package/drivers/IDatabaseDriver.js +1 -4
- package/drivers/index.d.ts +2 -2
- package/drivers/index.js +2 -18
- package/entity/ArrayCollection.d.ts +3 -3
- package/entity/ArrayCollection.js +38 -35
- package/entity/BaseEntity.d.ts +6 -6
- package/entity/BaseEntity.js +17 -21
- package/entity/Collection.d.ts +6 -7
- package/entity/Collection.js +47 -51
- package/entity/EntityAssigner.d.ts +2 -2
- package/entity/EntityAssigner.js +58 -63
- package/entity/EntityFactory.d.ts +3 -3
- package/entity/EntityFactory.js +62 -63
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +44 -45
- package/entity/EntityIdentifier.d.ts +1 -1
- package/entity/EntityIdentifier.js +1 -5
- package/entity/EntityLoader.d.ts +5 -5
- package/entity/EntityLoader.js +106 -98
- package/entity/EntityRepository.d.ts +7 -7
- package/entity/EntityRepository.js +7 -11
- package/entity/EntityValidator.d.ts +1 -1
- package/entity/EntityValidator.js +25 -29
- package/entity/Reference.d.ts +4 -8
- package/entity/Reference.js +35 -42
- package/entity/WrappedEntity.d.ts +12 -12
- package/entity/WrappedEntity.js +23 -27
- package/entity/index.d.ts +13 -13
- package/entity/index.js +13 -29
- package/entity/utils.d.ts +1 -1
- package/entity/utils.js +9 -12
- package/entity/wrap.d.ts +1 -1
- package/entity/wrap.js +2 -6
- package/enums.d.ts +3 -3
- package/enums.js +37 -41
- package/errors.d.ts +1 -1
- package/errors.js +15 -24
- package/events/EventManager.d.ts +3 -3
- package/events/EventManager.js +8 -12
- package/events/EventSubscriber.d.ts +8 -5
- package/events/EventSubscriber.js +1 -2
- package/events/TransactionEventBroadcaster.d.ts +3 -3
- package/events/TransactionEventBroadcaster.js +1 -5
- package/events/index.d.ts +3 -3
- package/events/index.js +3 -19
- package/exceptions.js +18 -39
- package/hydration/Hydrator.d.ts +5 -5
- package/hydration/Hydrator.js +3 -6
- package/hydration/ObjectHydrator.d.ts +3 -3
- package/hydration/ObjectHydrator.js +26 -28
- package/hydration/index.d.ts +2 -2
- package/hydration/index.js +2 -18
- package/index.d.ts +21 -21
- package/index.js +21 -46
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +9 -13
- package/logging/Logger.d.ts +1 -1
- package/logging/Logger.js +1 -2
- package/logging/SimpleLogger.d.ts +2 -2
- package/logging/SimpleLogger.js +2 -6
- package/logging/colors.js +1 -5
- package/logging/index.d.ts +4 -4
- package/logging/index.js +4 -20
- package/metadata/EntitySchema.d.ts +14 -6
- package/metadata/EntitySchema.js +41 -45
- package/metadata/MetadataDiscovery.d.ts +7 -7
- package/metadata/MetadataDiscovery.js +181 -180
- package/metadata/MetadataProvider.d.ts +2 -2
- package/metadata/MetadataProvider.js +4 -7
- package/metadata/MetadataStorage.d.ts +2 -2
- package/metadata/MetadataStorage.js +15 -19
- package/metadata/MetadataValidator.d.ts +4 -4
- package/metadata/MetadataValidator.js +52 -55
- package/metadata/ReflectMetadataProvider.d.ts +2 -2
- package/metadata/ReflectMetadataProvider.js +8 -12
- package/metadata/index.d.ts +6 -6
- package/metadata/index.js +6 -22
- package/naming-strategy/AbstractNamingStrategy.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +4 -8
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +2 -6
- package/naming-strategy/MongoNamingStrategy.d.ts +1 -1
- package/naming-strategy/MongoNamingStrategy.js +2 -6
- package/naming-strategy/NamingStrategy.d.ts +1 -1
- package/naming-strategy/NamingStrategy.js +1 -2
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +1 -1
- package/naming-strategy/UnderscoreNamingStrategy.js +2 -6
- package/naming-strategy/index.d.ts +5 -5
- package/naming-strategy/index.js +5 -21
- package/package.json +6 -15
- package/platforms/ExceptionConverter.d.ts +2 -2
- package/platforms/ExceptionConverter.js +4 -8
- package/platforms/Platform.d.ts +10 -10
- package/platforms/Platform.js +57 -61
- package/platforms/index.d.ts +2 -2
- package/platforms/index.js +2 -18
- package/serialization/EntitySerializer.d.ts +2 -2
- package/serialization/EntitySerializer.js +36 -41
- package/serialization/EntityTransformer.d.ts +1 -1
- package/serialization/EntityTransformer.js +27 -31
- package/serialization/SerializationContext.d.ts +2 -2
- package/serialization/SerializationContext.js +10 -14
- package/serialization/index.d.ts +3 -3
- package/serialization/index.js +3 -19
- package/types/ArrayType.d.ts +3 -3
- package/types/ArrayType.js +7 -11
- package/types/BigIntType.d.ts +4 -3
- package/types/BigIntType.js +6 -6
- package/types/BlobType.d.ts +3 -3
- package/types/BlobType.js +2 -8
- package/types/BooleanType.d.ts +3 -3
- package/types/BooleanType.js +2 -6
- package/types/CharacterType.d.ts +3 -3
- package/types/CharacterType.js +2 -6
- package/types/DateTimeType.d.ts +3 -3
- package/types/DateTimeType.js +2 -6
- package/types/DateType.d.ts +3 -3
- package/types/DateType.js +2 -6
- package/types/DecimalType.d.ts +3 -3
- package/types/DecimalType.js +4 -7
- package/types/DoubleType.d.ts +3 -3
- package/types/DoubleType.js +3 -6
- package/types/EnumArrayType.d.ts +4 -4
- package/types/EnumArrayType.js +5 -10
- package/types/EnumType.d.ts +3 -3
- package/types/EnumType.js +2 -6
- package/types/FloatType.d.ts +3 -3
- package/types/FloatType.js +2 -6
- package/types/IntegerType.d.ts +3 -3
- package/types/IntegerType.js +2 -6
- package/types/IntervalType.d.ts +3 -3
- package/types/IntervalType.js +2 -6
- package/types/JsonType.d.ts +3 -3
- package/types/JsonType.js +2 -6
- package/types/MediumIntType.d.ts +3 -3
- package/types/MediumIntType.js +2 -6
- package/types/SmallIntType.d.ts +3 -3
- package/types/SmallIntType.js +2 -6
- package/types/StringType.d.ts +3 -3
- package/types/StringType.js +2 -6
- package/types/TextType.d.ts +3 -3
- package/types/TextType.js +2 -6
- package/types/TimeType.d.ts +3 -3
- package/types/TimeType.js +4 -8
- package/types/TinyIntType.d.ts +3 -3
- package/types/TinyIntType.js +3 -6
- package/types/Type.d.ts +2 -2
- package/types/Type.js +5 -9
- package/types/Uint8ArrayType.d.ts +3 -3
- package/types/Uint8ArrayType.js +3 -9
- package/types/UnknownType.d.ts +3 -3
- package/types/UnknownType.js +2 -6
- package/types/UuidType.d.ts +3 -3
- package/types/UuidType.js +2 -6
- package/types/index.d.ts +25 -25
- package/types/index.js +52 -79
- package/typings.d.ts +33 -28
- package/typings.js +37 -38
- package/unit-of-work/ChangeSet.d.ts +1 -1
- package/unit-of-work/ChangeSet.js +13 -17
- package/unit-of-work/ChangeSetComputer.d.ts +8 -7
- package/unit-of-work/ChangeSetComputer.js +26 -30
- package/unit-of-work/ChangeSetPersister.d.ts +7 -6
- package/unit-of-work/ChangeSetPersister.js +51 -48
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -1
- package/unit-of-work/CommitOrderCalculator.js +6 -10
- package/unit-of-work/IdentityMap.d.ts +1 -1
- package/unit-of-work/IdentityMap.js +1 -5
- package/unit-of-work/UnitOfWork.d.ts +8 -7
- package/unit-of-work/UnitOfWork.js +193 -178
- package/unit-of-work/index.d.ts +6 -6
- package/unit-of-work/index.js +6 -22
- package/utils/AbstractSchemaGenerator.d.ts +6 -6
- package/utils/AbstractSchemaGenerator.js +12 -13
- package/utils/Configuration.d.ts +26 -27
- package/utils/Configuration.js +50 -55
- package/utils/ConfigurationLoader.d.ts +9 -8
- package/utils/ConfigurationLoader.js +71 -86
- package/utils/Cursor.d.ts +6 -6
- package/utils/Cursor.js +22 -25
- package/utils/DataloaderUtils.d.ts +4 -4
- package/utils/DataloaderUtils.js +12 -16
- package/utils/EntityComparator.d.ts +2 -2
- package/utils/EntityComparator.js +109 -97
- package/utils/NullHighlighter.d.ts +1 -1
- package/utils/NullHighlighter.js +1 -5
- package/utils/QueryHelper.d.ts +3 -3
- package/utils/QueryHelper.js +47 -51
- package/utils/RawQueryFragment.d.ts +1 -1
- package/utils/RawQueryFragment.js +22 -25
- package/utils/RequestContext.d.ts +2 -2
- package/utils/RequestContext.js +3 -7
- package/utils/TransactionContext.d.ts +1 -1
- package/utils/TransactionContext.js +4 -8
- package/utils/Utils.d.ts +16 -12
- package/utils/Utils.js +96 -95
- package/utils/clone.js +8 -11
- package/utils/index.d.ts +13 -13
- package/utils/index.js +13 -29
- package/utils/resolveContextProvider.d.ts +3 -3
- package/utils/resolveContextProvider.js +9 -12
- package/utils/upsert-utils.d.ts +3 -3
- package/utils/upsert-utils.js +5 -9
- package/index.mjs +0 -199
package/EntityManager.js
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
import DataLoader from 'dataloader';
|
|
3
|
+
import { getOnConflictReturningFields } from './utils/upsert-utils.js';
|
|
4
|
+
import { Utils } from './utils/Utils.js';
|
|
5
|
+
import { Cursor } from './utils/Cursor.js';
|
|
6
|
+
import { DataloaderUtils } from './utils/DataloaderUtils.js';
|
|
7
|
+
import { QueryHelper } from './utils/QueryHelper.js';
|
|
8
|
+
import { TransactionContext } from './utils/TransactionContext.js';
|
|
9
|
+
import { isRaw, RawQueryFragment } from './utils/RawQueryFragment.js';
|
|
10
|
+
import { EntityFactory } from './entity/EntityFactory.js';
|
|
11
|
+
import { EntityAssigner } from './entity/EntityAssigner.js';
|
|
12
|
+
import { EntityValidator } from './entity/EntityValidator.js';
|
|
13
|
+
import { EntityLoader } from './entity/EntityLoader.js';
|
|
14
|
+
import { Reference } from './entity/Reference.js';
|
|
15
|
+
import { helper } from './entity/wrap.js';
|
|
16
|
+
import { ChangeSet, ChangeSetType } from './unit-of-work/ChangeSet.js';
|
|
17
|
+
import { UnitOfWork } from './unit-of-work/UnitOfWork.js';
|
|
18
|
+
import { EventType, FlushMode, LoadStrategy, LockMode, PopulateHint, PopulatePath, QueryFlag, ReferenceKind, SCALAR_TYPES, } from './enums.js';
|
|
19
|
+
import { EventManager } from './events/EventManager.js';
|
|
20
|
+
import { TransactionEventBroadcaster } from './events/TransactionEventBroadcaster.js';
|
|
21
|
+
import { OptimisticLockError, ValidationError } from './errors.js';
|
|
21
22
|
/**
|
|
22
23
|
* The EntityManager is the central access point to ORM functionality. It is a facade to all different ORM subsystems
|
|
23
24
|
* such as UnitOfWork, Query Language, and Repository API.
|
|
24
25
|
* @template {IDatabaseDriver} Driver current driver type
|
|
25
26
|
*/
|
|
26
|
-
class EntityManager {
|
|
27
|
+
export class EntityManager {
|
|
27
28
|
config;
|
|
28
29
|
driver;
|
|
29
30
|
metadata;
|
|
@@ -33,8 +34,8 @@ class EntityManager {
|
|
|
33
34
|
_id = EntityManager.counter++;
|
|
34
35
|
global = false;
|
|
35
36
|
name;
|
|
36
|
-
refLoader = new
|
|
37
|
-
colLoader = new
|
|
37
|
+
refLoader = new DataLoader(DataloaderUtils.getRefBatchLoadFn(this));
|
|
38
|
+
colLoader = new DataLoader(DataloaderUtils.getColBatchLoadFn(this));
|
|
38
39
|
validator;
|
|
39
40
|
repositoryMap = {};
|
|
40
41
|
entityLoader;
|
|
@@ -52,20 +53,20 @@ class EntityManager {
|
|
|
52
53
|
/**
|
|
53
54
|
* @internal
|
|
54
55
|
*/
|
|
55
|
-
constructor(config, driver, metadata, useContext = true, eventManager = new
|
|
56
|
+
constructor(config, driver, metadata, useContext = true, eventManager = new EventManager(config.get('subscribers'))) {
|
|
56
57
|
this.config = config;
|
|
57
58
|
this.driver = driver;
|
|
58
59
|
this.metadata = metadata;
|
|
59
60
|
this.useContext = useContext;
|
|
60
61
|
this.eventManager = eventManager;
|
|
61
|
-
this.entityLoader = new
|
|
62
|
+
this.entityLoader = new EntityLoader(this);
|
|
62
63
|
this.name = this.config.get('contextName');
|
|
63
|
-
this.validator = new
|
|
64
|
+
this.validator = new EntityValidator(this.config.get('strict'));
|
|
64
65
|
this.comparator = this.config.getComparator(this.metadata);
|
|
65
66
|
this.resultCache = this.config.getResultCacheAdapter();
|
|
66
67
|
this.disableTransactions = this.config.get('disableTransactions');
|
|
67
|
-
this.entityFactory = new
|
|
68
|
-
this.unitOfWork = new
|
|
68
|
+
this.entityFactory = new EntityFactory(this);
|
|
69
|
+
this.unitOfWork = new UnitOfWork(this);
|
|
69
70
|
}
|
|
70
71
|
/**
|
|
71
72
|
* Gets the Driver instance used by this EntityManager.
|
|
@@ -90,7 +91,7 @@ class EntityManager {
|
|
|
90
91
|
* Gets repository for given entity. You can pass either string name or entity class reference.
|
|
91
92
|
*/
|
|
92
93
|
getRepository(entityName) {
|
|
93
|
-
entityName =
|
|
94
|
+
entityName = Utils.className(entityName);
|
|
94
95
|
if (!this.repositoryMap[entityName]) {
|
|
95
96
|
const meta = this.metadata.get(entityName);
|
|
96
97
|
const RepositoryClass = this.config.getRepositoryClass(meta.repository);
|
|
@@ -124,7 +125,7 @@ class EntityManager {
|
|
|
124
125
|
const em = this.getContext();
|
|
125
126
|
em.prepareOptions(options);
|
|
126
127
|
await em.tryFlush(entityName, options);
|
|
127
|
-
entityName =
|
|
128
|
+
entityName = Utils.className(entityName);
|
|
128
129
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
129
130
|
em.validator.validateParams(where);
|
|
130
131
|
options.orderBy = options.orderBy || {};
|
|
@@ -148,7 +149,7 @@ class EntityManager {
|
|
|
148
149
|
options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
149
150
|
options.populateWhere = this.createPopulateWhere({ ...where }, options);
|
|
150
151
|
options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
|
|
151
|
-
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, ...options });
|
|
152
|
+
const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
|
|
152
153
|
if (results.length === 0) {
|
|
153
154
|
await em.storeCache(options.cache, cached, []);
|
|
154
155
|
return [];
|
|
@@ -163,7 +164,7 @@ class EntityManager {
|
|
|
163
164
|
});
|
|
164
165
|
ret.push(entity);
|
|
165
166
|
}
|
|
166
|
-
const unique =
|
|
167
|
+
const unique = Utils.unique(ret);
|
|
167
168
|
await em.entityLoader.populate(entityName, unique, populate, {
|
|
168
169
|
...options,
|
|
169
170
|
...em.getPopulateWhere(where, options),
|
|
@@ -176,7 +177,7 @@ class EntityManager {
|
|
|
176
177
|
await em.storeCache(options.cache, cached, () => ret);
|
|
177
178
|
}
|
|
178
179
|
else {
|
|
179
|
-
await em.storeCache(options.cache, cached, () => unique.map(e =>
|
|
180
|
+
await em.storeCache(options.cache, cached, () => unique.map(e => helper(e).toPOJO()));
|
|
180
181
|
}
|
|
181
182
|
return unique;
|
|
182
183
|
}
|
|
@@ -190,11 +191,11 @@ class EntityManager {
|
|
|
190
191
|
if (options.populateWhere === undefined) {
|
|
191
192
|
options.populateWhere = this.config.get('populateWhere');
|
|
192
193
|
}
|
|
193
|
-
if (options.populateWhere ===
|
|
194
|
+
if (options.populateWhere === PopulateHint.ALL) {
|
|
194
195
|
return { where: {}, populateWhere: options.populateWhere };
|
|
195
196
|
}
|
|
196
|
-
/*
|
|
197
|
-
if (options.populateWhere ===
|
|
197
|
+
/* v8 ignore next 3 */
|
|
198
|
+
if (options.populateWhere === PopulateHint.INFER) {
|
|
198
199
|
return { where, populateWhere: options.populateWhere };
|
|
199
200
|
}
|
|
200
201
|
return { where: options.populateWhere };
|
|
@@ -205,7 +206,7 @@ class EntityManager {
|
|
|
205
206
|
addFilter(name, cond, entityName, enabled = true) {
|
|
206
207
|
const options = { name, cond, default: enabled };
|
|
207
208
|
if (entityName) {
|
|
208
|
-
options.entity =
|
|
209
|
+
options.entity = Utils.asArray(entityName).map(n => Utils.className(n));
|
|
209
210
|
}
|
|
210
211
|
this.getContext(false).filters[name] = options;
|
|
211
212
|
}
|
|
@@ -240,7 +241,7 @@ class EntityManager {
|
|
|
240
241
|
this.getContext(false).flushMode = flushMode;
|
|
241
242
|
}
|
|
242
243
|
async processWhere(entityName, where, options, type) {
|
|
243
|
-
where =
|
|
244
|
+
where = QueryHelper.processWhere({
|
|
244
245
|
where,
|
|
245
246
|
entityName,
|
|
246
247
|
metadata: this.metadata,
|
|
@@ -249,7 +250,7 @@ class EntityManager {
|
|
|
249
250
|
aliased: type === 'read',
|
|
250
251
|
});
|
|
251
252
|
where = (await this.applyFilters(entityName, where, options.filters ?? {}, type, options));
|
|
252
|
-
where =
|
|
253
|
+
where = this.applyDiscriminatorCondition(entityName, where);
|
|
253
254
|
return where;
|
|
254
255
|
}
|
|
255
256
|
// this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
|
|
@@ -267,18 +268,18 @@ class EntityManager {
|
|
|
267
268
|
return children;
|
|
268
269
|
};
|
|
269
270
|
lookUpChildren(children, meta.className);
|
|
270
|
-
/*
|
|
271
|
+
/* v8 ignore next */
|
|
271
272
|
where[meta.root.discriminatorColumn] = children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue;
|
|
272
273
|
return where;
|
|
273
274
|
}
|
|
274
275
|
createPopulateWhere(cond, options) {
|
|
275
276
|
const ret = {};
|
|
276
277
|
const populateWhere = options.populateWhere ?? this.config.get('populateWhere');
|
|
277
|
-
if (populateWhere ===
|
|
278
|
-
|
|
278
|
+
if (populateWhere === PopulateHint.INFER) {
|
|
279
|
+
Utils.merge(ret, cond);
|
|
279
280
|
}
|
|
280
281
|
else if (typeof populateWhere === 'object') {
|
|
281
|
-
|
|
282
|
+
Utils.merge(ret, populateWhere);
|
|
282
283
|
}
|
|
283
284
|
return ret;
|
|
284
285
|
}
|
|
@@ -288,18 +289,18 @@ class EntityManager {
|
|
|
288
289
|
for (const hint of options.populate) {
|
|
289
290
|
const field = hint.field.split(':')[0];
|
|
290
291
|
const prop = meta.properties[field];
|
|
291
|
-
const joined = (prop.strategy || options.strategy || hint.strategy || this.config.get('loadStrategy')) ===
|
|
292
|
+
const joined = (prop.strategy || options.strategy || hint.strategy || this.config.get('loadStrategy')) === LoadStrategy.JOINED && prop.kind !== ReferenceKind.SCALAR;
|
|
292
293
|
if (!joined && !hint.filter) {
|
|
293
294
|
continue;
|
|
294
295
|
}
|
|
295
296
|
const where = await this.applyFilters(prop.type, {}, options.filters ?? {}, 'read', { ...options, populate: hint.children });
|
|
296
|
-
const where2 = await this.getJoinedFilters(prop.targetMeta, {}, { ...options, populate: hint.children, populateWhere:
|
|
297
|
-
if (
|
|
297
|
+
const where2 = await this.getJoinedFilters(prop.targetMeta, {}, { ...options, populate: hint.children, populateWhere: PopulateHint.ALL });
|
|
298
|
+
if (Utils.hasObjectKeys(where)) {
|
|
298
299
|
ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
|
|
299
300
|
}
|
|
300
|
-
if (
|
|
301
|
+
if (Utils.hasObjectKeys(where2)) {
|
|
301
302
|
if (ret[field]) {
|
|
302
|
-
|
|
303
|
+
Utils.merge(ret[field], where2);
|
|
303
304
|
}
|
|
304
305
|
else {
|
|
305
306
|
ret[field] = where2;
|
|
@@ -317,19 +318,19 @@ class EntityManager {
|
|
|
317
318
|
return;
|
|
318
319
|
}
|
|
319
320
|
const props = meta.relations.filter(prop => {
|
|
320
|
-
return !prop.object && [
|
|
321
|
+
return !prop.object && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
|
|
321
322
|
&& ((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)));
|
|
322
323
|
});
|
|
323
324
|
const ret = options.populate;
|
|
324
325
|
for (const prop of props) {
|
|
325
326
|
const cond = await this.applyFilters(prop.type, {}, options.filters ?? {}, 'read', options);
|
|
326
|
-
if (!
|
|
327
|
+
if (!Utils.isEmpty(cond)) {
|
|
327
328
|
const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
|
|
328
329
|
if (populated.length > 0) {
|
|
329
330
|
populated.forEach(hint => hint.filter = true);
|
|
330
331
|
}
|
|
331
332
|
else {
|
|
332
|
-
ret.push({ field: `${prop.name}:ref`, strategy:
|
|
333
|
+
ret.push({ field: `${prop.name}:ref`, strategy: LoadStrategy.JOINED, filter: true });
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
336
|
}
|
|
@@ -346,7 +347,7 @@ class EntityManager {
|
|
|
346
347
|
}
|
|
347
348
|
const active = new Set();
|
|
348
349
|
const push = (source) => {
|
|
349
|
-
const activeFilters =
|
|
350
|
+
const activeFilters = QueryHelper
|
|
350
351
|
.getActiveFilters(entityName, options, source)
|
|
351
352
|
.filter(f => !active.has(f.name));
|
|
352
353
|
filters.push(...activeFilters);
|
|
@@ -362,16 +363,16 @@ class EntityManager {
|
|
|
362
363
|
let cond;
|
|
363
364
|
if (filter.cond instanceof Function) {
|
|
364
365
|
// @ts-ignore
|
|
365
|
-
const args =
|
|
366
|
+
const args = Utils.isPlainObject(options[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
366
367
|
if (!args && filter.cond.length > 0 && filter.args !== false) {
|
|
367
368
|
throw new Error(`No arguments provided for filter '${filter.name}'`);
|
|
368
369
|
}
|
|
369
|
-
cond = await filter.cond(args, type, this, findOptions);
|
|
370
|
+
cond = await filter.cond(args, type, this, findOptions, entityName);
|
|
370
371
|
}
|
|
371
372
|
else {
|
|
372
373
|
cond = filter.cond;
|
|
373
374
|
}
|
|
374
|
-
ret.push(
|
|
375
|
+
ret.push(QueryHelper.processWhere({
|
|
375
376
|
where: cond,
|
|
376
377
|
entityName,
|
|
377
378
|
metadata: this.metadata,
|
|
@@ -379,7 +380,7 @@ class EntityManager {
|
|
|
379
380
|
aliased: type === 'read',
|
|
380
381
|
}));
|
|
381
382
|
}
|
|
382
|
-
const conds = [...ret, where].filter(c =>
|
|
383
|
+
const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
|
|
383
384
|
return conds.length > 1 ? { $and: conds } : conds[0];
|
|
384
385
|
}
|
|
385
386
|
/**
|
|
@@ -390,7 +391,7 @@ class EntityManager {
|
|
|
390
391
|
const em = this.getContext(false);
|
|
391
392
|
await em.tryFlush(entityName, options);
|
|
392
393
|
options.flushMode = 'commit'; // do not try to auto flush again
|
|
393
|
-
return
|
|
394
|
+
return RawQueryFragment.run(async () => {
|
|
394
395
|
return Promise.all([
|
|
395
396
|
em.find(entityName, where, options),
|
|
396
397
|
em.count(entityName, where, options),
|
|
@@ -432,6 +433,10 @@ class EntityManager {
|
|
|
432
433
|
* });
|
|
433
434
|
* ```
|
|
434
435
|
*
|
|
436
|
+
* The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
|
|
437
|
+
* returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
|
|
438
|
+
* of pages.
|
|
439
|
+
*
|
|
435
440
|
* The `Cursor` object provides the following interface:
|
|
436
441
|
*
|
|
437
442
|
* ```ts
|
|
@@ -441,7 +446,7 @@ class EntityManager {
|
|
|
441
446
|
* User { ... },
|
|
442
447
|
* User { ... },
|
|
443
448
|
* ],
|
|
444
|
-
* totalCount: 50,
|
|
449
|
+
* totalCount: 50, // not included if `includeCount: false`
|
|
445
450
|
* startCursor: 'WzRd',
|
|
446
451
|
* endCursor: 'WzZd',
|
|
447
452
|
* hasPrevPage: true,
|
|
@@ -451,13 +456,15 @@ class EntityManager {
|
|
|
451
456
|
*/
|
|
452
457
|
async findByCursor(entityName, where, options) {
|
|
453
458
|
const em = this.getContext(false);
|
|
454
|
-
entityName =
|
|
459
|
+
entityName = Utils.className(entityName);
|
|
455
460
|
options.overfetch ??= true;
|
|
456
|
-
if (
|
|
461
|
+
if (Utils.isEmpty(options.orderBy)) {
|
|
457
462
|
throw new Error('Explicit `orderBy` option required');
|
|
458
463
|
}
|
|
459
|
-
const [entities, count] =
|
|
460
|
-
|
|
464
|
+
const [entities, count] = options.includeCount !== false
|
|
465
|
+
? await em.findAndCount(entityName, where, options)
|
|
466
|
+
: [await em.find(entityName, where, options)];
|
|
467
|
+
return new Cursor(entities, count, options, this.metadata.get(entityName));
|
|
461
468
|
}
|
|
462
469
|
/**
|
|
463
470
|
* Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been
|
|
@@ -469,7 +476,7 @@ class EntityManager {
|
|
|
469
476
|
if (!ret) {
|
|
470
477
|
options.failHandler ??= this.config.get('findOneOrFailHandler');
|
|
471
478
|
const entityName = entity.constructor.name;
|
|
472
|
-
const where =
|
|
479
|
+
const where = helper(entity).getPrimaryKey();
|
|
473
480
|
throw options.failHandler(entityName, where);
|
|
474
481
|
}
|
|
475
482
|
return ret;
|
|
@@ -483,12 +490,12 @@ class EntityManager {
|
|
|
483
490
|
const fork = this.fork({ keepTransactionContext: true });
|
|
484
491
|
const entityName = entity.constructor.name;
|
|
485
492
|
const reloaded = await fork.findOne(entityName, entity, {
|
|
486
|
-
schema:
|
|
493
|
+
schema: helper(entity).__schema,
|
|
487
494
|
...options,
|
|
488
|
-
flushMode:
|
|
495
|
+
flushMode: FlushMode.COMMIT,
|
|
489
496
|
});
|
|
490
497
|
if (reloaded) {
|
|
491
|
-
this.config.getHydrator(this.metadata).hydrate(entity,
|
|
498
|
+
this.config.getHydrator(this.metadata).hydrate(entity, helper(entity).__meta, helper(reloaded).toPOJO(), this.getEntityFactory(), 'full');
|
|
492
499
|
}
|
|
493
500
|
else {
|
|
494
501
|
this.getUnitOfWork().unsetIdentity(entity);
|
|
@@ -507,13 +514,13 @@ class EntityManager {
|
|
|
507
514
|
return ret;
|
|
508
515
|
}
|
|
509
516
|
const em = this.getContext();
|
|
510
|
-
entityName =
|
|
517
|
+
entityName = Utils.className(entityName);
|
|
511
518
|
em.prepareOptions(options);
|
|
512
519
|
let entity = em.unitOfWork.tryGetById(entityName, where, options.schema);
|
|
513
520
|
// query for a not managed entity which is already in the identity map as it
|
|
514
521
|
// was provided with a PK this entity does not exist in the db, there can't
|
|
515
522
|
// be any relations to it, so no need to deal with the populate hint
|
|
516
|
-
if (entity && !
|
|
523
|
+
if (entity && !helper(entity).__managed) {
|
|
517
524
|
return entity;
|
|
518
525
|
}
|
|
519
526
|
await em.tryFlush(entityName, options);
|
|
@@ -521,7 +528,7 @@ class EntityManager {
|
|
|
521
528
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
522
529
|
em.validator.validateEmptyWhere(where);
|
|
523
530
|
em.checkLockRequirements(options.lockMode, meta);
|
|
524
|
-
const isOptimisticLocking = !
|
|
531
|
+
const isOptimisticLocking = !Utils.isDefined(options.lockMode) || options.lockMode === LockMode.OPTIMISTIC;
|
|
525
532
|
if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
|
|
526
533
|
return em.lockAndPopulate(meta, entity, where, options);
|
|
527
534
|
}
|
|
@@ -546,6 +553,7 @@ class EntityManager {
|
|
|
546
553
|
options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
|
|
547
554
|
const data = await em.driver.findOne(entityName, where, {
|
|
548
555
|
ctx: em.transactionContext,
|
|
556
|
+
em,
|
|
549
557
|
...options,
|
|
550
558
|
});
|
|
551
559
|
if (!data) {
|
|
@@ -560,7 +568,7 @@ class EntityManager {
|
|
|
560
568
|
});
|
|
561
569
|
await em.lockAndPopulate(meta, entity, where, options);
|
|
562
570
|
await em.unitOfWork.dispatchOnLoadEvent();
|
|
563
|
-
await em.storeCache(options.cache, cached, () =>
|
|
571
|
+
await em.storeCache(options.cache, cached, () => helper(entity).toPOJO());
|
|
564
572
|
return entity;
|
|
565
573
|
}
|
|
566
574
|
/**
|
|
@@ -583,9 +591,9 @@ class EntityManager {
|
|
|
583
591
|
if (!entity || isStrictViolation) {
|
|
584
592
|
const key = options.strict ? 'findExactlyOneOrFailHandler' : 'findOneOrFailHandler';
|
|
585
593
|
options.failHandler ??= this.config.get(key);
|
|
586
|
-
entityName =
|
|
587
|
-
/*
|
|
588
|
-
where =
|
|
594
|
+
entityName = Utils.className(entityName);
|
|
595
|
+
/* v8 ignore next */
|
|
596
|
+
where = Utils.isEntity(where) ? helper(where).getPrimaryKey() : where;
|
|
589
597
|
throw options.failHandler(entityName, where);
|
|
590
598
|
}
|
|
591
599
|
return entity;
|
|
@@ -630,22 +638,22 @@ class EntityManager {
|
|
|
630
638
|
data = entityNameOrEntity;
|
|
631
639
|
}
|
|
632
640
|
else {
|
|
633
|
-
entityName =
|
|
641
|
+
entityName = Utils.className(entityNameOrEntity);
|
|
634
642
|
}
|
|
635
643
|
const meta = this.metadata.get(entityName);
|
|
636
|
-
const convertCustomTypes = !
|
|
637
|
-
if (
|
|
644
|
+
const convertCustomTypes = !Utils.isEntity(data);
|
|
645
|
+
if (Utils.isEntity(data)) {
|
|
638
646
|
entity = data;
|
|
639
|
-
if (
|
|
647
|
+
if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
|
|
640
648
|
em.entityFactory.mergeData(meta, entity, data, { initialized: true });
|
|
641
649
|
return entity;
|
|
642
650
|
}
|
|
643
|
-
where =
|
|
651
|
+
where = helper(entity).getPrimaryKey();
|
|
644
652
|
data = em.comparator.prepareEntity(entity);
|
|
645
653
|
}
|
|
646
654
|
else {
|
|
647
|
-
data =
|
|
648
|
-
where =
|
|
655
|
+
data = Utils.copy(QueryHelper.processParams(data));
|
|
656
|
+
where = Utils.extractPK(data, meta);
|
|
649
657
|
if (where && !this.config.get('upsertManaged')) {
|
|
650
658
|
const exists = em.unitOfWork.getById(entityName, where, options.schema);
|
|
651
659
|
if (exists) {
|
|
@@ -654,15 +662,15 @@ class EntityManager {
|
|
|
654
662
|
}
|
|
655
663
|
}
|
|
656
664
|
const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
657
|
-
const propIndex = !
|
|
665
|
+
const propIndex = !isRaw(unique) && unique.findIndex(p => data[p] != null);
|
|
658
666
|
if (options.onConflictFields || where == null) {
|
|
659
667
|
if (propIndex !== false && propIndex >= 0) {
|
|
660
668
|
where = { [unique[propIndex]]: data[unique[propIndex]] };
|
|
661
669
|
}
|
|
662
670
|
else if (meta.uniques.length > 0) {
|
|
663
671
|
for (const u of meta.uniques) {
|
|
664
|
-
if (
|
|
665
|
-
where =
|
|
672
|
+
if (Utils.asArray(u.properties).every(p => data[p] != null)) {
|
|
673
|
+
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
666
674
|
o[key] = data[key];
|
|
667
675
|
return o;
|
|
668
676
|
}, {});
|
|
@@ -671,10 +679,10 @@ class EntityManager {
|
|
|
671
679
|
}
|
|
672
680
|
}
|
|
673
681
|
}
|
|
674
|
-
data =
|
|
682
|
+
data = QueryHelper.processObjectParams(data);
|
|
675
683
|
em.validator.validateParams(data, 'insert data');
|
|
676
|
-
if (em.eventManager.hasListeners(
|
|
677
|
-
await em.eventManager.dispatchEvent(
|
|
684
|
+
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
685
|
+
await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity: data, em, meta }, meta);
|
|
678
686
|
}
|
|
679
687
|
const ret = await em.driver.nativeUpdate(entityName, where, data, {
|
|
680
688
|
ctx: em.transactionContext,
|
|
@@ -688,9 +696,9 @@ class EntityManager {
|
|
|
688
696
|
initialized: true,
|
|
689
697
|
schema: options.schema,
|
|
690
698
|
});
|
|
691
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
692
|
-
const returning =
|
|
693
|
-
if (options.onConflictAction === 'ignore' || !
|
|
699
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where) ? Object.keys(where) : meta.primaryKeys);
|
|
700
|
+
const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
|
|
701
|
+
if (options.onConflictAction === 'ignore' || !helper(entity).hasPrimaryKey() || (returning.length > 0 && !(this.getPlatform().usesReturningStatement() && ret.row))) {
|
|
694
702
|
const where = {};
|
|
695
703
|
if (Array.isArray(uniqueFields)) {
|
|
696
704
|
for (const prop of uniqueFields) {
|
|
@@ -716,13 +724,13 @@ class EntityManager {
|
|
|
716
724
|
convertCustomTypes: true,
|
|
717
725
|
connectionType: 'write',
|
|
718
726
|
});
|
|
719
|
-
em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full');
|
|
727
|
+
em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full', false, true);
|
|
720
728
|
}
|
|
721
729
|
// recompute the data as there might be some values missing (e.g. those with db column defaults)
|
|
722
730
|
const snapshot = this.comparator.prepareEntity(entity);
|
|
723
731
|
em.unitOfWork.register(entity, snapshot, { refresh: true });
|
|
724
|
-
if (em.eventManager.hasListeners(
|
|
725
|
-
await em.eventManager.dispatchEvent(
|
|
732
|
+
if (em.eventManager.hasListeners(EventType.afterUpsert, meta)) {
|
|
733
|
+
await em.eventManager.dispatchEvent(EventType.afterUpsert, { entity, em, meta }, meta);
|
|
726
734
|
}
|
|
727
735
|
return entity;
|
|
728
736
|
}
|
|
@@ -768,19 +776,19 @@ class EntityManager {
|
|
|
768
776
|
data = entityNameOrEntity;
|
|
769
777
|
}
|
|
770
778
|
else {
|
|
771
|
-
entityName =
|
|
779
|
+
entityName = Utils.className(entityNameOrEntity);
|
|
772
780
|
}
|
|
773
781
|
const batchSize = options.batchSize ?? this.config.get('batchSize');
|
|
774
782
|
if (data.length > batchSize) {
|
|
775
783
|
const ret = [];
|
|
776
784
|
for (let i = 0; i < data.length; i += batchSize) {
|
|
777
785
|
const chunk = data.slice(i, i + batchSize);
|
|
778
|
-
ret.push(...await this.upsertMany(entityName, chunk, options));
|
|
786
|
+
ret.push(...(await this.upsertMany(entityName, chunk, options)));
|
|
779
787
|
}
|
|
780
788
|
return ret;
|
|
781
789
|
}
|
|
782
790
|
const meta = this.metadata.get(entityName);
|
|
783
|
-
const convertCustomTypes = !
|
|
791
|
+
const convertCustomTypes = !Utils.isEntity(data[0]);
|
|
784
792
|
const allData = [];
|
|
785
793
|
const allWhere = [];
|
|
786
794
|
const entities = new Map();
|
|
@@ -788,20 +796,20 @@ class EntityManager {
|
|
|
788
796
|
for (let i = 0; i < data.length; i++) {
|
|
789
797
|
let row = data[i];
|
|
790
798
|
let where;
|
|
791
|
-
if (
|
|
799
|
+
if (Utils.isEntity(row)) {
|
|
792
800
|
const entity = row;
|
|
793
|
-
if (
|
|
801
|
+
if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
|
|
794
802
|
em.entityFactory.mergeData(meta, entity, row, { initialized: true });
|
|
795
803
|
entities.set(entity, row);
|
|
796
804
|
entitiesByData.set(row, entity);
|
|
797
805
|
continue;
|
|
798
806
|
}
|
|
799
|
-
where =
|
|
807
|
+
where = helper(entity).getPrimaryKey();
|
|
800
808
|
row = em.comparator.prepareEntity(entity);
|
|
801
809
|
}
|
|
802
810
|
else {
|
|
803
|
-
row = data[i] =
|
|
804
|
-
where =
|
|
811
|
+
row = data[i] = Utils.copy(QueryHelper.processParams(row));
|
|
812
|
+
where = Utils.extractPK(row, meta);
|
|
805
813
|
if (where && !this.config.get('upsertManaged')) {
|
|
806
814
|
const exists = em.unitOfWork.getById(entityName, where, options.schema);
|
|
807
815
|
if (exists) {
|
|
@@ -820,8 +828,8 @@ class EntityManager {
|
|
|
820
828
|
}
|
|
821
829
|
else if (meta.uniques.length > 0) {
|
|
822
830
|
for (const u of meta.uniques) {
|
|
823
|
-
if (
|
|
824
|
-
where =
|
|
831
|
+
if (Utils.asArray(u.properties).every(p => row[p] != null)) {
|
|
832
|
+
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
825
833
|
o[key] = row[key];
|
|
826
834
|
return o;
|
|
827
835
|
}, {});
|
|
@@ -830,8 +838,8 @@ class EntityManager {
|
|
|
830
838
|
}
|
|
831
839
|
}
|
|
832
840
|
}
|
|
833
|
-
row =
|
|
834
|
-
where =
|
|
841
|
+
row = QueryHelper.processObjectParams(row);
|
|
842
|
+
where = QueryHelper.processWhere({
|
|
835
843
|
where,
|
|
836
844
|
entityName,
|
|
837
845
|
metadata: this.metadata,
|
|
@@ -844,10 +852,10 @@ class EntityManager {
|
|
|
844
852
|
if (entities.size === data.length) {
|
|
845
853
|
return [...entities.keys()];
|
|
846
854
|
}
|
|
847
|
-
if (em.eventManager.hasListeners(
|
|
855
|
+
if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
|
|
848
856
|
for (const dto of data) {
|
|
849
857
|
const entity = entitiesByData.get(dto) ?? dto;
|
|
850
|
-
await em.eventManager.dispatchEvent(
|
|
858
|
+
await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity, em, meta }, meta);
|
|
851
859
|
}
|
|
852
860
|
}
|
|
853
861
|
const res = await em.driver.nativeUpdateMany(entityName, allWhere, allData, {
|
|
@@ -860,27 +868,27 @@ class EntityManager {
|
|
|
860
868
|
entitiesByData.clear();
|
|
861
869
|
const loadPK = new Map();
|
|
862
870
|
allData.forEach((row, i) => {
|
|
863
|
-
em.unitOfWork.getChangeSetPersister().mapReturnedValues(
|
|
864
|
-
const entity =
|
|
871
|
+
em.unitOfWork.getChangeSetPersister().mapReturnedValues(Utils.isEntity(data[i]) ? data[i] : null, Utils.isEntity(data[i]) ? {} : data[i], res.rows?.[i], meta, true);
|
|
872
|
+
const entity = Utils.isEntity(data[i]) ? data[i] : em.entityFactory.create(entityName, row, {
|
|
865
873
|
refresh: true,
|
|
866
874
|
initialized: true,
|
|
867
875
|
schema: options.schema,
|
|
868
876
|
});
|
|
869
|
-
if (!
|
|
877
|
+
if (!helper(entity).hasPrimaryKey()) {
|
|
870
878
|
loadPK.set(entity, allWhere[i]);
|
|
871
879
|
}
|
|
872
880
|
entities.set(entity, row);
|
|
873
881
|
entitiesByData.set(row, entity);
|
|
874
882
|
});
|
|
875
883
|
// skip if we got the PKs via returning statement (`rows`)
|
|
876
|
-
const uniqueFields = options.onConflictFields ?? (
|
|
877
|
-
const returning =
|
|
884
|
+
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
|
|
885
|
+
const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
|
|
878
886
|
const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
|
|
879
887
|
if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
|
|
880
888
|
const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
|
|
881
889
|
const add = new Set(propIndex >= 0 ? [unique[propIndex]] : []);
|
|
882
890
|
for (const cond of loadPK.values()) {
|
|
883
|
-
|
|
891
|
+
Utils.keys(cond).forEach(key => add.add(key));
|
|
884
892
|
}
|
|
885
893
|
const where = { $or: [] };
|
|
886
894
|
data.forEach((item, idx) => {
|
|
@@ -906,11 +914,11 @@ class EntityManager {
|
|
|
906
914
|
});
|
|
907
915
|
return this.comparator.matching(entityName, cond, tmp);
|
|
908
916
|
});
|
|
909
|
-
/*
|
|
917
|
+
/* v8 ignore next 3 */
|
|
910
918
|
if (!row) {
|
|
911
919
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
912
920
|
}
|
|
913
|
-
em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full');
|
|
921
|
+
em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full', false, true);
|
|
914
922
|
}
|
|
915
923
|
if (loadPK.size !== data2.length && Array.isArray(uniqueFields)) {
|
|
916
924
|
for (let i = 0; i < allData.length; i++) {
|
|
@@ -929,7 +937,7 @@ class EntityManager {
|
|
|
929
937
|
}, {});
|
|
930
938
|
return this.comparator.matching(entityName, cond, pk);
|
|
931
939
|
});
|
|
932
|
-
/*
|
|
940
|
+
/* v8 ignore next 3 */
|
|
933
941
|
if (!row) {
|
|
934
942
|
throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
|
|
935
943
|
}
|
|
@@ -942,9 +950,9 @@ class EntityManager {
|
|
|
942
950
|
const snapshot = this.comparator.prepareEntity(entity);
|
|
943
951
|
em.unitOfWork.register(entity, snapshot, { refresh: true });
|
|
944
952
|
}
|
|
945
|
-
if (em.eventManager.hasListeners(
|
|
953
|
+
if (em.eventManager.hasListeners(EventType.afterUpsert, meta)) {
|
|
946
954
|
for (const [entity] of entities) {
|
|
947
|
-
await em.eventManager.dispatchEvent(
|
|
955
|
+
await em.eventManager.dispatchEvent(EventType.afterUpsert, { entity, em, meta }, meta);
|
|
948
956
|
}
|
|
949
957
|
}
|
|
950
958
|
return [...entities.keys()];
|
|
@@ -966,14 +974,14 @@ class EntityManager {
|
|
|
966
974
|
});
|
|
967
975
|
options.ctx ??= em.transactionContext;
|
|
968
976
|
const propagateToUpperContext = !em.global || this.config.get('allowGlobalContext');
|
|
969
|
-
return
|
|
977
|
+
return TransactionContext.create(fork, async () => {
|
|
970
978
|
return fork.getConnection().transactional(async (trx) => {
|
|
971
979
|
fork.transactionContext = trx;
|
|
972
980
|
if (propagateToUpperContext) {
|
|
973
981
|
fork.eventManager.registerSubscriber({
|
|
974
982
|
afterFlush(args) {
|
|
975
983
|
args.uow.getChangeSets()
|
|
976
|
-
.filter(cs => [
|
|
984
|
+
.filter(cs => [ChangeSetType.DELETE, ChangeSetType.DELETE_EARLY].includes(cs.type))
|
|
977
985
|
.forEach(cs => em.unitOfWork.unsetIdentity(cs.entity));
|
|
978
986
|
},
|
|
979
987
|
});
|
|
@@ -988,7 +996,7 @@ class EntityManager {
|
|
|
988
996
|
}
|
|
989
997
|
}
|
|
990
998
|
return ret;
|
|
991
|
-
}, { ...options, eventBroadcaster: new
|
|
999
|
+
}, { ...options, eventBroadcaster: new TransactionEventBroadcaster(fork, { topLevelTransaction: !options.ctx }) });
|
|
992
1000
|
});
|
|
993
1001
|
}
|
|
994
1002
|
/**
|
|
@@ -1001,7 +1009,7 @@ class EntityManager {
|
|
|
1001
1009
|
const em = this.getContext(false);
|
|
1002
1010
|
em.transactionContext = await em.getConnection('write').begin({
|
|
1003
1011
|
...options,
|
|
1004
|
-
eventBroadcaster: new
|
|
1012
|
+
eventBroadcaster: new TransactionEventBroadcaster(em, { topLevelTransaction: !options.ctx }),
|
|
1005
1013
|
});
|
|
1006
1014
|
}
|
|
1007
1015
|
/**
|
|
@@ -1014,10 +1022,10 @@ class EntityManager {
|
|
|
1014
1022
|
return;
|
|
1015
1023
|
}
|
|
1016
1024
|
if (!em.transactionContext) {
|
|
1017
|
-
throw
|
|
1025
|
+
throw ValidationError.transactionRequired();
|
|
1018
1026
|
}
|
|
1019
1027
|
await em.flush();
|
|
1020
|
-
await em.getConnection('write').commit(em.transactionContext, new
|
|
1028
|
+
await em.getConnection('write').commit(em.transactionContext, new TransactionEventBroadcaster(em));
|
|
1021
1029
|
delete em.transactionContext;
|
|
1022
1030
|
}
|
|
1023
1031
|
/**
|
|
@@ -1029,9 +1037,9 @@ class EntityManager {
|
|
|
1029
1037
|
}
|
|
1030
1038
|
const em = this.getContext(false);
|
|
1031
1039
|
if (!em.transactionContext) {
|
|
1032
|
-
throw
|
|
1040
|
+
throw ValidationError.transactionRequired();
|
|
1033
1041
|
}
|
|
1034
|
-
await em.getConnection('write').rollback(em.transactionContext, new
|
|
1042
|
+
await em.getConnection('write').rollback(em.transactionContext, new TransactionEventBroadcaster(em));
|
|
1035
1043
|
delete em.transactionContext;
|
|
1036
1044
|
em.unitOfWork.clearActionsQueue();
|
|
1037
1045
|
}
|
|
@@ -1039,7 +1047,7 @@ class EntityManager {
|
|
|
1039
1047
|
* Runs your callback wrapped inside a database transaction.
|
|
1040
1048
|
*/
|
|
1041
1049
|
async lock(entity, lockMode, options = {}) {
|
|
1042
|
-
options =
|
|
1050
|
+
options = Utils.isPlainObject(options) ? options : { lockVersion: options };
|
|
1043
1051
|
await this.getUnitOfWork().lock(entity, { lockMode, ...options });
|
|
1044
1052
|
}
|
|
1045
1053
|
/**
|
|
@@ -1054,25 +1062,25 @@ class EntityManager {
|
|
|
1054
1062
|
data = entityNameOrEntity;
|
|
1055
1063
|
}
|
|
1056
1064
|
else {
|
|
1057
|
-
entityName =
|
|
1065
|
+
entityName = Utils.className(entityNameOrEntity);
|
|
1058
1066
|
}
|
|
1059
|
-
if (
|
|
1060
|
-
if (options.schema &&
|
|
1061
|
-
|
|
1067
|
+
if (Utils.isEntity(data)) {
|
|
1068
|
+
if (options.schema && helper(data).getSchema() == null) {
|
|
1069
|
+
helper(data).setSchema(options.schema);
|
|
1062
1070
|
}
|
|
1063
|
-
if (!
|
|
1071
|
+
if (!helper(data).__managed) {
|
|
1064
1072
|
// the entity might have been created via `em.create()`, which adds it to the persist stack automatically
|
|
1065
1073
|
em.unitOfWork.getPersistStack().delete(data);
|
|
1066
1074
|
// it can be also in the identity map if it had a PK value already
|
|
1067
1075
|
em.unitOfWork.unsetIdentity(data);
|
|
1068
1076
|
}
|
|
1069
|
-
const meta =
|
|
1077
|
+
const meta = helper(data).__meta;
|
|
1070
1078
|
const payload = em.comparator.prepareEntity(data);
|
|
1071
|
-
const cs = new
|
|
1079
|
+
const cs = new ChangeSet(data, ChangeSetType.CREATE, payload, meta);
|
|
1072
1080
|
await em.unitOfWork.getChangeSetPersister().executeInserts([cs], { ctx: em.transactionContext, ...options });
|
|
1073
1081
|
return cs.getPrimaryKey();
|
|
1074
1082
|
}
|
|
1075
|
-
data =
|
|
1083
|
+
data = QueryHelper.processObjectParams(data);
|
|
1076
1084
|
em.validator.validateParams(data, 'insert data');
|
|
1077
1085
|
const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1078
1086
|
return res.insertId;
|
|
@@ -1089,30 +1097,30 @@ class EntityManager {
|
|
|
1089
1097
|
data = entityNameOrEntities;
|
|
1090
1098
|
}
|
|
1091
1099
|
else {
|
|
1092
|
-
entityName =
|
|
1100
|
+
entityName = Utils.className(entityNameOrEntities);
|
|
1093
1101
|
}
|
|
1094
1102
|
if (data.length === 0) {
|
|
1095
1103
|
return [];
|
|
1096
1104
|
}
|
|
1097
|
-
if (
|
|
1098
|
-
const meta =
|
|
1105
|
+
if (Utils.isEntity(data[0])) {
|
|
1106
|
+
const meta = helper(data[0]).__meta;
|
|
1099
1107
|
const css = data.map(row => {
|
|
1100
|
-
if (options.schema &&
|
|
1101
|
-
|
|
1108
|
+
if (options.schema && helper(row).getSchema() == null) {
|
|
1109
|
+
helper(row).setSchema(options.schema);
|
|
1102
1110
|
}
|
|
1103
|
-
if (!
|
|
1111
|
+
if (!helper(row).__managed) {
|
|
1104
1112
|
// the entity might have been created via `em.create()`, which adds it to the persist stack automatically
|
|
1105
1113
|
em.unitOfWork.getPersistStack().delete(row);
|
|
1106
1114
|
// it can be also in the identity map if it had a PK value already
|
|
1107
1115
|
em.unitOfWork.unsetIdentity(row);
|
|
1108
1116
|
}
|
|
1109
1117
|
const payload = em.comparator.prepareEntity(row);
|
|
1110
|
-
return new
|
|
1118
|
+
return new ChangeSet(row, ChangeSetType.CREATE, payload, meta);
|
|
1111
1119
|
});
|
|
1112
1120
|
await em.unitOfWork.getChangeSetPersister().executeInserts(css, { ctx: em.transactionContext, ...options });
|
|
1113
1121
|
return css.map(cs => cs.getPrimaryKey());
|
|
1114
1122
|
}
|
|
1115
|
-
data = data.map(row =>
|
|
1123
|
+
data = data.map(row => QueryHelper.processObjectParams(row));
|
|
1116
1124
|
data.forEach(row => em.validator.validateParams(row, 'insert data'));
|
|
1117
1125
|
const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
|
|
1118
1126
|
if (res.insertedIds) {
|
|
@@ -1126,8 +1134,8 @@ class EntityManager {
|
|
|
1126
1134
|
async nativeUpdate(entityName, where, data, options = {}) {
|
|
1127
1135
|
const em = this.getContext(false);
|
|
1128
1136
|
em.prepareOptions(options);
|
|
1129
|
-
entityName =
|
|
1130
|
-
data =
|
|
1137
|
+
entityName = Utils.className(entityName);
|
|
1138
|
+
data = QueryHelper.processObjectParams(data);
|
|
1131
1139
|
where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
|
|
1132
1140
|
em.validator.validateParams(data, 'update data');
|
|
1133
1141
|
em.validator.validateParams(where, 'update condition');
|
|
@@ -1140,7 +1148,7 @@ class EntityManager {
|
|
|
1140
1148
|
async nativeDelete(entityName, where, options = {}) {
|
|
1141
1149
|
const em = this.getContext(false);
|
|
1142
1150
|
em.prepareOptions(options);
|
|
1143
|
-
entityName =
|
|
1151
|
+
entityName = Utils.className(entityName);
|
|
1144
1152
|
where = await em.processWhere(entityName, where, options, 'delete');
|
|
1145
1153
|
em.validator.validateParams(where, 'delete condition');
|
|
1146
1154
|
const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
|
|
@@ -1150,12 +1158,12 @@ class EntityManager {
|
|
|
1150
1158
|
* Maps raw database result to an entity and merges it to this EntityManager.
|
|
1151
1159
|
*/
|
|
1152
1160
|
map(entityName, result, options = {}) {
|
|
1153
|
-
entityName =
|
|
1161
|
+
entityName = Utils.className(entityName);
|
|
1154
1162
|
const meta = this.metadata.get(entityName);
|
|
1155
1163
|
const data = this.driver.mapResult(result, meta);
|
|
1156
1164
|
Object.keys(data).forEach(k => {
|
|
1157
1165
|
const prop = meta.properties[k];
|
|
1158
|
-
if (prop && prop.kind ===
|
|
1166
|
+
if (prop && prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.includes(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
|
|
1159
1167
|
data[k] = this.validator.validateProperty(prop, data[k], data);
|
|
1160
1168
|
}
|
|
1161
1169
|
});
|
|
@@ -1170,19 +1178,19 @@ class EntityManager {
|
|
|
1170
1178
|
*/
|
|
1171
1179
|
merge(entityName, data, options = {}) {
|
|
1172
1180
|
const em = this.getContext();
|
|
1173
|
-
if (
|
|
1181
|
+
if (Utils.isEntity(entityName)) {
|
|
1174
1182
|
return em.merge(entityName.constructor.name, entityName, data);
|
|
1175
1183
|
}
|
|
1176
1184
|
options.schema ??= em._schema;
|
|
1177
|
-
entityName =
|
|
1185
|
+
entityName = Utils.className(entityName);
|
|
1178
1186
|
em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
|
|
1179
1187
|
let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
|
|
1180
|
-
if (entity &&
|
|
1188
|
+
if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
|
|
1181
1189
|
return entity;
|
|
1182
1190
|
}
|
|
1183
1191
|
const meta = em.metadata.find(entityName);
|
|
1184
1192
|
const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
|
|
1185
|
-
entity =
|
|
1193
|
+
entity = Utils.isEntity(data) ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
|
|
1186
1194
|
em.validator.validate(entity, data, childMeta ?? meta);
|
|
1187
1195
|
em.unitOfWork.merge(entity);
|
|
1188
1196
|
return entity;
|
|
@@ -1220,7 +1228,7 @@ class EntityManager {
|
|
|
1220
1228
|
* Shortcut for `wrap(entity).assign(data, { em })`
|
|
1221
1229
|
*/
|
|
1222
1230
|
assign(entity, data, options = {}) {
|
|
1223
|
-
return
|
|
1231
|
+
return EntityAssigner.assign(entity, data, { em: this.getContext(), ...options });
|
|
1224
1232
|
}
|
|
1225
1233
|
/**
|
|
1226
1234
|
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
|
@@ -1228,16 +1236,16 @@ class EntityManager {
|
|
|
1228
1236
|
getReference(entityName, id, options = {}) {
|
|
1229
1237
|
options.schema ??= this.schema;
|
|
1230
1238
|
options.convertCustomTypes ??= false;
|
|
1231
|
-
const meta = this.metadata.get(
|
|
1232
|
-
if (
|
|
1239
|
+
const meta = this.metadata.get(Utils.className(entityName));
|
|
1240
|
+
if (Utils.isPrimaryKey(id)) {
|
|
1233
1241
|
if (meta.compositePK) {
|
|
1234
|
-
throw
|
|
1242
|
+
throw ValidationError.invalidCompositeIdentifier(meta);
|
|
1235
1243
|
}
|
|
1236
1244
|
id = [id];
|
|
1237
1245
|
}
|
|
1238
1246
|
const entity = this.getEntityFactory().createReference(entityName, id, { merge: true, ...options });
|
|
1239
1247
|
if (options.wrapped) {
|
|
1240
|
-
return
|
|
1248
|
+
return Reference.create(entity);
|
|
1241
1249
|
}
|
|
1242
1250
|
return entity;
|
|
1243
1251
|
}
|
|
@@ -1251,7 +1259,7 @@ class EntityManager {
|
|
|
1251
1259
|
schema: em._schema,
|
|
1252
1260
|
...options,
|
|
1253
1261
|
};
|
|
1254
|
-
entityName =
|
|
1262
|
+
entityName = Utils.className(entityName);
|
|
1255
1263
|
await em.tryFlush(entityName, options);
|
|
1256
1264
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
1257
1265
|
options.populate = await em.preparePopulate(entityName, options);
|
|
@@ -1278,20 +1286,20 @@ class EntityManager {
|
|
|
1278
1286
|
*/
|
|
1279
1287
|
persist(entity) {
|
|
1280
1288
|
const em = this.getContext();
|
|
1281
|
-
if (
|
|
1289
|
+
if (Utils.isEntity(entity)) {
|
|
1282
1290
|
// do not cascade just yet, cascading of entities in persist stack is done when flushing
|
|
1283
1291
|
em.unitOfWork.persist(entity, undefined, { cascade: false });
|
|
1284
1292
|
return em;
|
|
1285
1293
|
}
|
|
1286
|
-
const entities =
|
|
1294
|
+
const entities = Utils.asArray(entity);
|
|
1287
1295
|
for (const ent of entities) {
|
|
1288
|
-
if (!
|
|
1289
|
-
/*
|
|
1296
|
+
if (!Utils.isEntity(ent, true)) {
|
|
1297
|
+
/* v8 ignore next */
|
|
1290
1298
|
const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor.name) : undefined;
|
|
1291
|
-
throw
|
|
1299
|
+
throw ValidationError.notDiscoveredEntity(ent, meta);
|
|
1292
1300
|
}
|
|
1293
1301
|
// do not cascade just yet, cascading of entities in persist stack is done when flushing
|
|
1294
|
-
em.unitOfWork.persist(
|
|
1302
|
+
em.unitOfWork.persist(Reference.unwrapReference(ent), undefined, { cascade: false });
|
|
1295
1303
|
}
|
|
1296
1304
|
return this;
|
|
1297
1305
|
}
|
|
@@ -1310,18 +1318,18 @@ class EntityManager {
|
|
|
1310
1318
|
*/
|
|
1311
1319
|
remove(entity) {
|
|
1312
1320
|
const em = this.getContext();
|
|
1313
|
-
if (
|
|
1321
|
+
if (Utils.isEntity(entity)) {
|
|
1314
1322
|
// do not cascade just yet, cascading of entities in persist stack is done when flushing
|
|
1315
1323
|
em.unitOfWork.remove(entity, undefined, { cascade: false });
|
|
1316
1324
|
return em;
|
|
1317
1325
|
}
|
|
1318
|
-
const entities =
|
|
1326
|
+
const entities = Utils.asArray(entity, true);
|
|
1319
1327
|
for (const ent of entities) {
|
|
1320
|
-
if (!
|
|
1328
|
+
if (!Utils.isEntity(ent, true)) {
|
|
1321
1329
|
throw new Error(`You need to pass entity instance or reference to 'em.remove()'. To remove entities by condition, use 'em.nativeDelete()'.`);
|
|
1322
1330
|
}
|
|
1323
1331
|
// do not cascade just yet, cascading of entities in remove stack is done when flushing
|
|
1324
|
-
em.unitOfWork.remove(
|
|
1332
|
+
em.unitOfWork.remove(Reference.unwrapReference(ent), undefined, { cascade: false });
|
|
1325
1333
|
}
|
|
1326
1334
|
return em;
|
|
1327
1335
|
}
|
|
@@ -1345,12 +1353,12 @@ class EntityManager {
|
|
|
1345
1353
|
async tryFlush(entityName, options) {
|
|
1346
1354
|
const em = this.getContext();
|
|
1347
1355
|
const flushMode = options.flushMode ?? em.flushMode ?? em.config.get('flushMode');
|
|
1348
|
-
entityName =
|
|
1356
|
+
entityName = Utils.className(entityName);
|
|
1349
1357
|
const meta = em.metadata.get(entityName);
|
|
1350
|
-
if (flushMode ===
|
|
1358
|
+
if (flushMode === FlushMode.COMMIT) {
|
|
1351
1359
|
return;
|
|
1352
1360
|
}
|
|
1353
|
-
if (flushMode ===
|
|
1361
|
+
if (flushMode === FlushMode.ALWAYS || em.getUnitOfWork().shouldAutoFlush(meta)) {
|
|
1354
1362
|
await em.flush();
|
|
1355
1363
|
}
|
|
1356
1364
|
}
|
|
@@ -1364,7 +1372,7 @@ class EntityManager {
|
|
|
1364
1372
|
* Checks whether given property can be populated on the entity.
|
|
1365
1373
|
*/
|
|
1366
1374
|
canPopulate(entityName, property) {
|
|
1367
|
-
entityName =
|
|
1375
|
+
entityName = Utils.className(entityName);
|
|
1368
1376
|
// eslint-disable-next-line prefer-const
|
|
1369
1377
|
let [p, ...parts] = property.split('.');
|
|
1370
1378
|
const meta = this.metadata.find(entityName);
|
|
@@ -1387,7 +1395,7 @@ class EntityManager {
|
|
|
1387
1395
|
* Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
|
|
1388
1396
|
*/
|
|
1389
1397
|
async populate(entities, populate, options = {}) {
|
|
1390
|
-
const arr =
|
|
1398
|
+
const arr = Utils.asArray(entities);
|
|
1391
1399
|
if (arr.length === 0) {
|
|
1392
1400
|
return entities;
|
|
1393
1401
|
}
|
|
@@ -1408,7 +1416,7 @@ class EntityManager {
|
|
|
1408
1416
|
options.freshEventManager ??= false;
|
|
1409
1417
|
options.cloneEventManager ??= false;
|
|
1410
1418
|
const eventManager = options.freshEventManager
|
|
1411
|
-
? new
|
|
1419
|
+
? new EventManager(em.config.get('subscribers'))
|
|
1412
1420
|
: options.cloneEventManager
|
|
1413
1421
|
? em.eventManager.clone()
|
|
1414
1422
|
: em.eventManager;
|
|
@@ -1423,13 +1431,16 @@ class EntityManager {
|
|
|
1423
1431
|
fork.transactionContext = em.transactionContext;
|
|
1424
1432
|
}
|
|
1425
1433
|
fork.filters = { ...em.filters };
|
|
1426
|
-
fork.filterParams =
|
|
1427
|
-
fork.loggerContext =
|
|
1434
|
+
fork.filterParams = Utils.copy(em.filterParams);
|
|
1435
|
+
fork.loggerContext = Utils.merge({}, em.loggerContext, options.loggerContext);
|
|
1428
1436
|
fork._schema = options.schema ?? em._schema;
|
|
1429
1437
|
if (!options.clear) {
|
|
1430
1438
|
for (const entity of em.unitOfWork.getIdentityMap()) {
|
|
1431
1439
|
fork.unitOfWork.register(entity);
|
|
1432
1440
|
}
|
|
1441
|
+
for (const entity of em.unitOfWork.getPersistStack()) {
|
|
1442
|
+
fork.unitOfWork.persist(entity);
|
|
1443
|
+
}
|
|
1433
1444
|
for (const entity of em.unitOfWork.getOrphanRemoveStack()) {
|
|
1434
1445
|
fork.unitOfWork.getOrphanRemoveStack().add(entity);
|
|
1435
1446
|
}
|
|
@@ -1465,14 +1476,14 @@ class EntityManager {
|
|
|
1465
1476
|
if (!this.useContext) {
|
|
1466
1477
|
return this;
|
|
1467
1478
|
}
|
|
1468
|
-
let em =
|
|
1479
|
+
let em = TransactionContext.getEntityManager(this.name); // prefer the tx context
|
|
1469
1480
|
if (em) {
|
|
1470
1481
|
return em;
|
|
1471
1482
|
}
|
|
1472
1483
|
// no explicit tx started
|
|
1473
1484
|
em = this.config.get('context')(this.name) ?? this;
|
|
1474
1485
|
if (validate && !this.config.get('allowGlobalContext') && em.global) {
|
|
1475
|
-
throw
|
|
1486
|
+
throw ValidationError.cannotUseGlobalContext();
|
|
1476
1487
|
}
|
|
1477
1488
|
return em;
|
|
1478
1489
|
}
|
|
@@ -1513,7 +1524,7 @@ class EntityManager {
|
|
|
1513
1524
|
*/
|
|
1514
1525
|
getMetadata(entityName) {
|
|
1515
1526
|
if (entityName) {
|
|
1516
|
-
entityName =
|
|
1527
|
+
entityName = Utils.className(entityName);
|
|
1517
1528
|
return this.metadata.get(entityName);
|
|
1518
1529
|
}
|
|
1519
1530
|
return this.metadata;
|
|
@@ -1528,15 +1539,15 @@ class EntityManager {
|
|
|
1528
1539
|
if (!mode) {
|
|
1529
1540
|
return;
|
|
1530
1541
|
}
|
|
1531
|
-
if (mode ===
|
|
1532
|
-
throw
|
|
1542
|
+
if (mode === LockMode.OPTIMISTIC && !meta.versionProperty) {
|
|
1543
|
+
throw OptimisticLockError.notVersioned(meta);
|
|
1533
1544
|
}
|
|
1534
|
-
if ([
|
|
1535
|
-
throw
|
|
1545
|
+
if ([LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_WRITE].includes(mode) && !this.isInTransaction()) {
|
|
1546
|
+
throw ValidationError.transactionRequired();
|
|
1536
1547
|
}
|
|
1537
1548
|
}
|
|
1538
1549
|
async lockAndPopulate(meta, entity, where, options) {
|
|
1539
|
-
if (!meta.virtual && options.lockMode ===
|
|
1550
|
+
if (!meta.virtual && options.lockMode === LockMode.OPTIMISTIC) {
|
|
1540
1551
|
await this.lock(entity, options.lockMode, {
|
|
1541
1552
|
lockVersion: options.lockVersion,
|
|
1542
1553
|
lockTableAliases: options.lockTableAliases,
|
|
@@ -1555,8 +1566,8 @@ class EntityManager {
|
|
|
1555
1566
|
}
|
|
1556
1567
|
buildFields(fields) {
|
|
1557
1568
|
return fields.reduce((ret, f) => {
|
|
1558
|
-
if (
|
|
1559
|
-
|
|
1569
|
+
if (Utils.isPlainObject(f)) {
|
|
1570
|
+
Utils.keys(f).forEach(ff => ret.push(...this.buildFields(f[ff]).map(field => `${ff}.${field}`)));
|
|
1560
1571
|
}
|
|
1561
1572
|
else {
|
|
1562
1573
|
ret.push(f);
|
|
@@ -1575,12 +1586,12 @@ class EntityManager {
|
|
|
1575
1586
|
const pruneToOneRelations = (meta, fields) => {
|
|
1576
1587
|
const ret = [];
|
|
1577
1588
|
for (let field of fields) {
|
|
1578
|
-
if (field ===
|
|
1579
|
-
ret.push(...meta.props.filter(prop => prop.lazy || [
|
|
1589
|
+
if (field === PopulatePath.ALL || field.startsWith(`${PopulatePath.ALL}.`)) {
|
|
1590
|
+
ret.push(...meta.props.filter(prop => prop.lazy || [ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind)).map(prop => prop.name));
|
|
1580
1591
|
continue;
|
|
1581
1592
|
}
|
|
1582
1593
|
field = field.split(':')[0];
|
|
1583
|
-
if (!field.includes('.') && ![
|
|
1594
|
+
if (!field.includes('.') && ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[field].kind)) {
|
|
1584
1595
|
ret.push(field);
|
|
1585
1596
|
continue;
|
|
1586
1597
|
}
|
|
@@ -1599,7 +1610,7 @@ class EntityManager {
|
|
|
1599
1610
|
ret.push(...inner.map(c => `${key}.${c}`));
|
|
1600
1611
|
}
|
|
1601
1612
|
}
|
|
1602
|
-
return
|
|
1613
|
+
return Utils.unique(ret);
|
|
1603
1614
|
};
|
|
1604
1615
|
options.populate = pruneToOneRelations(meta, this.buildFields(options.fields));
|
|
1605
1616
|
}
|
|
@@ -1609,18 +1620,18 @@ class EntityManager {
|
|
|
1609
1620
|
return populate;
|
|
1610
1621
|
}
|
|
1611
1622
|
if (typeof options.populate !== 'boolean') {
|
|
1612
|
-
options.populate =
|
|
1613
|
-
/*
|
|
1614
|
-
if (typeof field === 'boolean' || field ===
|
|
1623
|
+
options.populate = Utils.asArray(options.populate).map(field => {
|
|
1624
|
+
/* v8 ignore next 3 */
|
|
1625
|
+
if (typeof field === 'boolean' || field === PopulatePath.ALL) {
|
|
1615
1626
|
return [{ field: meta.primaryKeys[0], strategy: options.strategy, all: !!field }]; //
|
|
1616
1627
|
}
|
|
1617
1628
|
// will be handled in QueryBuilder when processing the where condition via CriteriaNode
|
|
1618
|
-
if (field ===
|
|
1629
|
+
if (field === PopulatePath.INFER) {
|
|
1619
1630
|
options.flags ??= [];
|
|
1620
|
-
options.flags.push(
|
|
1631
|
+
options.flags.push(QueryFlag.INFER_POPULATE);
|
|
1621
1632
|
return [];
|
|
1622
1633
|
}
|
|
1623
|
-
if (
|
|
1634
|
+
if (Utils.isString(field)) {
|
|
1624
1635
|
return [{ field, strategy: options.strategy }];
|
|
1625
1636
|
}
|
|
1626
1637
|
return [field];
|
|
@@ -1629,13 +1640,13 @@ class EntityManager {
|
|
|
1629
1640
|
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy);
|
|
1630
1641
|
const invalid = populate.find(({ field }) => !this.canPopulate(entityName, field));
|
|
1631
1642
|
if (validate && invalid) {
|
|
1632
|
-
throw
|
|
1643
|
+
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
|
1633
1644
|
}
|
|
1634
1645
|
await this.autoJoinRefsForFilters(meta, { ...options, populate });
|
|
1635
1646
|
return populate.map(field => {
|
|
1636
1647
|
// force select-in strategy when populating all relations as otherwise we could cause infinite loops when self-referencing
|
|
1637
1648
|
const all = field.all ?? (Array.isArray(options.populate) && options.populate.includes('*'));
|
|
1638
|
-
field.strategy = all ?
|
|
1649
|
+
field.strategy = all ? LoadStrategy.SELECT_IN : (options.strategy ?? field.strategy);
|
|
1639
1650
|
return field;
|
|
1640
1651
|
});
|
|
1641
1652
|
}
|
|
@@ -1644,33 +1655,33 @@ class EntityManager {
|
|
|
1644
1655
|
* some additional lazy properties, if so, we reload and merge the data from database
|
|
1645
1656
|
*/
|
|
1646
1657
|
shouldRefresh(meta, entity, options) {
|
|
1647
|
-
if (!
|
|
1658
|
+
if (!helper(entity).__initialized || options.refresh) {
|
|
1648
1659
|
return true;
|
|
1649
1660
|
}
|
|
1650
1661
|
let autoRefresh;
|
|
1651
1662
|
if (options.fields) {
|
|
1652
|
-
autoRefresh = options.fields.some(field => !
|
|
1663
|
+
autoRefresh = options.fields.some(field => !helper(entity).__loadedProperties.has(field));
|
|
1653
1664
|
}
|
|
1654
1665
|
else {
|
|
1655
1666
|
autoRefresh = meta.comparableProps.some(prop => {
|
|
1656
|
-
const inlineEmbedded = prop.kind ===
|
|
1657
|
-
return !inlineEmbedded && !prop.lazy && !
|
|
1667
|
+
const inlineEmbedded = prop.kind === ReferenceKind.EMBEDDED && !prop.object;
|
|
1668
|
+
return !inlineEmbedded && !prop.lazy && !helper(entity).__loadedProperties.has(prop.name);
|
|
1658
1669
|
});
|
|
1659
1670
|
}
|
|
1660
1671
|
if (autoRefresh) {
|
|
1661
1672
|
return true;
|
|
1662
1673
|
}
|
|
1663
1674
|
if (Array.isArray(options.populate)) {
|
|
1664
|
-
return options.populate.some(field => !
|
|
1675
|
+
return options.populate.some(field => !helper(entity).__loadedProperties.has(field));
|
|
1665
1676
|
}
|
|
1666
1677
|
return !!options.populate;
|
|
1667
1678
|
}
|
|
1668
1679
|
prepareOptions(options) {
|
|
1669
|
-
if (!
|
|
1670
|
-
throw new
|
|
1680
|
+
if (!Utils.isEmpty(options.fields) && !Utils.isEmpty(options.exclude)) {
|
|
1681
|
+
throw new ValidationError(`Cannot combine 'fields' and 'exclude' option.`);
|
|
1671
1682
|
}
|
|
1672
1683
|
options.schema ??= this._schema;
|
|
1673
|
-
options.logging =
|
|
1684
|
+
options.logging = Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
|
|
1674
1685
|
}
|
|
1675
1686
|
/**
|
|
1676
1687
|
* @internal
|
|
@@ -1704,7 +1715,7 @@ class EntityManager {
|
|
|
1704
1715
|
recomputeSnapshot: true,
|
|
1705
1716
|
}));
|
|
1706
1717
|
}
|
|
1707
|
-
else if (
|
|
1718
|
+
else if (Utils.isObject(cached) && merge) {
|
|
1708
1719
|
data = em.entityFactory.create(entityName, cached, {
|
|
1709
1720
|
merge: true,
|
|
1710
1721
|
convertCustomTypes: true,
|
|
@@ -1727,7 +1738,7 @@ class EntityManager {
|
|
|
1727
1738
|
config ??= this.config.get('resultCache').global;
|
|
1728
1739
|
if (config) {
|
|
1729
1740
|
const em = this.getContext();
|
|
1730
|
-
const expiration = Array.isArray(config) ? config[1] : (
|
|
1741
|
+
const expiration = Array.isArray(config) ? config[1] : (Utils.isNumber(config) ? config : undefined);
|
|
1731
1742
|
await em.resultCache.set(key.key, data instanceof Function ? data() : data, '', expiration);
|
|
1732
1743
|
}
|
|
1733
1744
|
}
|
|
@@ -1768,8 +1779,7 @@ class EntityManager {
|
|
|
1768
1779
|
return this.getContext(false)._id;
|
|
1769
1780
|
}
|
|
1770
1781
|
/** @ignore */
|
|
1771
|
-
[
|
|
1782
|
+
[inspect.custom]() {
|
|
1772
1783
|
return `[EntityManager<${this.id}>]`;
|
|
1773
1784
|
}
|
|
1774
1785
|
}
|
|
1775
|
-
exports.EntityManager = EntityManager;
|