@mikro-orm/core 7.0.0-dev.8 → 7.0.0-dev.80
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 +85 -48
- package/EntityManager.js +300 -225
- package/MikroORM.d.ts +40 -31
- package/MikroORM.js +98 -137
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +6 -5
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +11 -7
- package/connections/Connection.js +16 -14
- package/drivers/DatabaseDriver.d.ts +11 -5
- package/drivers/DatabaseDriver.js +17 -8
- package/drivers/IDatabaseDriver.d.ts +27 -5
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +98 -30
- package/entity/Collection.js +432 -93
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +15 -7
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +64 -41
- package/entity/EntityHelper.js +26 -9
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +73 -40
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +33 -6
- package/entity/WrappedEntity.d.ts +2 -4
- package/entity/WrappedEntity.js +1 -5
- package/entity/defineEntity.d.ts +549 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +21 -6
- package/enums.js +14 -1
- package/errors.d.ts +6 -2
- package/errors.js +14 -9
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +36 -25
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +9 -13
- package/metadata/EntitySchema.js +44 -26
- package/metadata/MetadataDiscovery.d.ts +6 -9
- package/metadata/MetadataDiscovery.js +167 -206
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +44 -2
- package/metadata/MetadataStorage.d.ts +1 -6
- package/metadata/MetadataStorage.js +6 -18
- package/metadata/MetadataValidator.d.ts +0 -7
- package/metadata/MetadataValidator.js +4 -13
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +480 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +8 -2
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +18 -10
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +6 -10
- package/platforms/Platform.js +14 -39
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +32 -14
- package/serialization/EntityTransformer.js +22 -12
- package/serialization/SerializationContext.js +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +8 -6
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +113 -77
- package/typings.js +41 -35
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +11 -9
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +58 -20
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +115 -57
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +11 -9
- package/utils/Configuration.d.ts +757 -206
- package/utils/Configuration.js +139 -187
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -1
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +54 -8
- package/utils/EntityComparator.d.ts +8 -4
- package/utils/EntityComparator.js +111 -64
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +70 -9
- package/utils/RawQueryFragment.d.ts +36 -4
- package/utils/RawQueryFragment.js +35 -14
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +8 -97
- package/utils/Utils.js +88 -303
- package/utils/clone.js +2 -3
- package/utils/env-vars.d.ts +3 -0
- package/utils/env-vars.js +87 -0
- package/utils/fs-utils.d.ts +12 -0
- package/utils/fs-utils.js +96 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -402
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
package/typings.js
CHANGED
|
@@ -32,7 +32,7 @@ export class EntityMetadata {
|
|
|
32
32
|
}
|
|
33
33
|
this.properties[prop.name] = prop;
|
|
34
34
|
this.propertyOrder.set(prop.name, this.props.length);
|
|
35
|
-
/* v8 ignore next
|
|
35
|
+
/* v8 ignore next */
|
|
36
36
|
if (sync) {
|
|
37
37
|
this.sync();
|
|
38
38
|
}
|
|
@@ -40,17 +40,34 @@ export class EntityMetadata {
|
|
|
40
40
|
removeProperty(name, sync = true) {
|
|
41
41
|
delete this.properties[name];
|
|
42
42
|
this.propertyOrder.delete(name);
|
|
43
|
-
/* v8 ignore next
|
|
43
|
+
/* v8 ignore next */
|
|
44
44
|
if (sync) {
|
|
45
45
|
this.sync();
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
getPrimaryProps() {
|
|
49
|
-
|
|
48
|
+
getPrimaryProps(flatten = false) {
|
|
49
|
+
const pks = this.primaryKeys.map(pk => this.properties[pk]);
|
|
50
|
+
if (flatten) {
|
|
51
|
+
return pks.flatMap(pk => {
|
|
52
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(pk.kind)) {
|
|
53
|
+
return pk.targetMeta.getPrimaryProps(true);
|
|
54
|
+
}
|
|
55
|
+
return [pk];
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return pks;
|
|
50
59
|
}
|
|
51
60
|
getPrimaryProp() {
|
|
52
61
|
return this.properties[this.primaryKeys[0]];
|
|
53
62
|
}
|
|
63
|
+
createColumnMappingObject() {
|
|
64
|
+
return Object.values(this.properties).reduce((o, prop) => {
|
|
65
|
+
if (prop.fieldNames) {
|
|
66
|
+
o[prop.name] = prop.fieldNames[0];
|
|
67
|
+
}
|
|
68
|
+
return o;
|
|
69
|
+
}, {});
|
|
70
|
+
}
|
|
54
71
|
get tableName() {
|
|
55
72
|
return this.collection;
|
|
56
73
|
}
|
|
@@ -66,23 +83,30 @@ export class EntityMetadata {
|
|
|
66
83
|
this.uniqueProps = this.props.filter(prop => prop.unique);
|
|
67
84
|
this.getterProps = this.props.filter(prop => prop.getter);
|
|
68
85
|
this.comparableProps = this.props.filter(prop => EntityComparator.isComparable(prop, this));
|
|
86
|
+
this.validateProps = this.props.filter(prop => {
|
|
87
|
+
if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return prop.kind === ReferenceKind.SCALAR && ['string', 'number', 'boolean', 'Date'].includes(prop.type);
|
|
91
|
+
});
|
|
69
92
|
this.hydrateProps = this.props.filter(prop => {
|
|
70
93
|
// `prop.userDefined` is either `undefined` or `false`
|
|
71
94
|
const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
|
|
72
95
|
// even if we don't have a setter, do not ignore value from database!
|
|
73
|
-
const onlyGetter = prop.getter && !prop.setter;
|
|
96
|
+
const onlyGetter = prop.getter && !prop.setter && prop.persist === false;
|
|
74
97
|
return !prop.inherited && prop.hydrate !== false && !discriminator && !prop.embedded && !onlyGetter;
|
|
75
98
|
});
|
|
76
|
-
this.trackingProps = this.hydrateProps
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
this.trackingProps = this.hydrateProps.filter(prop => {
|
|
100
|
+
return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
|
|
101
|
+
});
|
|
102
|
+
this.selfReferencing = this.relations.some(prop => {
|
|
103
|
+
return [this.className, this.root.className].includes(prop.targetMeta?.root.className ?? prop.type);
|
|
104
|
+
});
|
|
81
105
|
this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
|
|
82
106
|
this.virtual = !!this.expression;
|
|
83
107
|
if (config) {
|
|
84
108
|
for (const prop of this.props) {
|
|
85
|
-
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item =>
|
|
109
|
+
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
|
|
86
110
|
const name = config.getNamingStrategy().indexName(this.tableName, prop.fieldNames, 'check');
|
|
87
111
|
const exists = this.checks.findIndex(check => check.name === name);
|
|
88
112
|
if (exists !== -1) {
|
|
@@ -109,8 +133,7 @@ export class EntityMetadata {
|
|
|
109
133
|
this.props.forEach(prop => this.initIndexes(prop));
|
|
110
134
|
}
|
|
111
135
|
this.definedProperties = this.trackingProps.reduce((o, prop) => {
|
|
112
|
-
const
|
|
113
|
-
const isReference = [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
|
|
136
|
+
const isReference = (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
|
|
114
137
|
if (isReference) {
|
|
115
138
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
116
139
|
const meta = this;
|
|
@@ -123,13 +146,13 @@ export class EntityMetadata {
|
|
|
123
146
|
const hydrator = wrapped.hydrator;
|
|
124
147
|
const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
|
|
125
148
|
const old = Reference.unwrapReference(wrapped.__data[prop.name]);
|
|
149
|
+
if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
|
|
150
|
+
old[prop.inversedBy].removeWithoutPropagation(this);
|
|
151
|
+
}
|
|
126
152
|
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
|
127
153
|
// when propagation from inside hydration, we set the FK to the entity data immediately
|
|
128
154
|
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
|
129
|
-
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
wrapped.__touched = !hydrator.isRunning();
|
|
155
|
+
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta, true);
|
|
133
156
|
}
|
|
134
157
|
EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
|
|
135
158
|
},
|
|
@@ -137,23 +160,6 @@ export class EntityMetadata {
|
|
|
137
160
|
configurable: true,
|
|
138
161
|
};
|
|
139
162
|
}
|
|
140
|
-
if (prop.inherited || prop.primary || isCollection || prop.persist === false || prop.trackChanges === false || isReference || prop.embedded) {
|
|
141
|
-
return o;
|
|
142
|
-
}
|
|
143
|
-
o[prop.name] = {
|
|
144
|
-
get() {
|
|
145
|
-
return this.__helper.__data[prop.name];
|
|
146
|
-
},
|
|
147
|
-
set(val) {
|
|
148
|
-
if (typeof val === 'object' && !!val && '__raw' in val) {
|
|
149
|
-
val.assign();
|
|
150
|
-
}
|
|
151
|
-
this.__helper.__data[prop.name] = val;
|
|
152
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
153
|
-
},
|
|
154
|
-
enumerable: true,
|
|
155
|
-
configurable: true,
|
|
156
|
-
};
|
|
157
163
|
return o;
|
|
158
164
|
}, { __gettersDefined: { value: true, enumerable: false } });
|
|
159
165
|
}
|
|
@@ -175,7 +181,7 @@ export class EntityMetadata {
|
|
|
175
181
|
this.indexes.push({ properties: prop.name });
|
|
176
182
|
prop.index = false;
|
|
177
183
|
}
|
|
178
|
-
/* v8 ignore next
|
|
184
|
+
/* v8 ignore next */
|
|
179
185
|
if (owner && prop.fieldNames.length > 1 && prop.unique) {
|
|
180
186
|
this.uniques.push({ properties: prop.name });
|
|
181
187
|
prop.unique = false;
|
|
@@ -2,19 +2,17 @@ import { type Configuration } from '../utils/Configuration.js';
|
|
|
2
2
|
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
3
3
|
import type { AnyEntity } from '../typings.js';
|
|
4
4
|
import { ChangeSet } from './ChangeSet.js';
|
|
5
|
-
import { type EntityValidator } from '../entity/EntityValidator.js';
|
|
6
5
|
import { type Collection } from '../entity/Collection.js';
|
|
7
6
|
import type { Platform } from '../platforms/Platform.js';
|
|
8
7
|
import type { EntityManager } from '../EntityManager.js';
|
|
9
8
|
export declare class ChangeSetComputer {
|
|
10
|
-
private readonly validator;
|
|
11
9
|
private readonly collectionUpdates;
|
|
12
10
|
private readonly metadata;
|
|
13
11
|
private readonly platform;
|
|
14
12
|
private readonly config;
|
|
15
13
|
private readonly em;
|
|
16
14
|
private readonly comparator;
|
|
17
|
-
constructor(
|
|
15
|
+
constructor(collectionUpdates: Set<Collection<AnyEntity>>, metadata: MetadataStorage, platform: Platform, config: Configuration, em: EntityManager);
|
|
18
16
|
computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
|
|
19
17
|
/**
|
|
20
18
|
* Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { Utils } from '../utils/Utils.js';
|
|
2
2
|
import { ChangeSet, ChangeSetType } from './ChangeSet.js';
|
|
3
3
|
import { helper } from '../entity/wrap.js';
|
|
4
|
+
import { validateEntity } from '../entity/validators.js';
|
|
4
5
|
import { ReferenceKind } from '../enums.js';
|
|
5
6
|
export class ChangeSetComputer {
|
|
6
|
-
validator;
|
|
7
7
|
collectionUpdates;
|
|
8
8
|
metadata;
|
|
9
9
|
platform;
|
|
10
10
|
config;
|
|
11
11
|
em;
|
|
12
12
|
comparator;
|
|
13
|
-
constructor(
|
|
14
|
-
this.validator = validator;
|
|
13
|
+
constructor(collectionUpdates, metadata, platform, config, em) {
|
|
15
14
|
this.collectionUpdates = collectionUpdates;
|
|
16
15
|
this.metadata = metadata;
|
|
17
16
|
this.platform = platform;
|
|
@@ -34,20 +33,21 @@ export class ChangeSetComputer {
|
|
|
34
33
|
this.processPropertyInitializers(entity, prop, type, map);
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
|
-
if (type === ChangeSetType.UPDATE && !wrapped.__initialized
|
|
38
|
-
|
|
36
|
+
if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
|
|
37
|
+
const data = this.comparator.prepareEntity(entity);
|
|
38
|
+
if (Utils.equals(data, wrapped.__originalEntityData)) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
39
41
|
}
|
|
40
42
|
const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
|
|
41
43
|
changeSet.originalEntity = wrapped.__originalEntityData;
|
|
42
|
-
if (this.config.get('validate')) {
|
|
43
|
-
this.validator.validate(changeSet.entity, changeSet.payload, meta);
|
|
44
|
-
}
|
|
45
44
|
for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
|
|
46
45
|
this.processProperty(changeSet, prop);
|
|
47
46
|
}
|
|
48
47
|
if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
|
|
49
48
|
return null;
|
|
50
49
|
}
|
|
50
|
+
validateEntity(changeSet.entity, meta);
|
|
51
51
|
// Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
|
|
52
52
|
// to the `map` as we want to apply those only if something else changed.
|
|
53
53
|
if (type === ChangeSetType.UPDATE) {
|
|
@@ -141,7 +141,9 @@ export class ChangeSetComputer {
|
|
|
141
141
|
if (!target.isDirty() && changeSet.type !== ChangeSetType.CREATE) {
|
|
142
142
|
return;
|
|
143
143
|
}
|
|
144
|
-
|
|
144
|
+
if (target.isDirty()) {
|
|
145
|
+
this.collectionUpdates.add(target);
|
|
146
|
+
}
|
|
145
147
|
if (prop.owner && !this.platform.usesPivotTable()) {
|
|
146
148
|
changeSet.payload[prop.name] = target.getItems(false).map((item) => item.__helper.__identifier ?? item.__helper.getPrimaryKey());
|
|
147
149
|
}
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
import type { MetadataStorage } from '../metadata/MetadataStorage.js';
|
|
2
2
|
import type { Dictionary, EntityDictionary, EntityMetadata, IHydrator } from '../typings.js';
|
|
3
3
|
import { type EntityFactory } from '../entity/EntityFactory.js';
|
|
4
|
-
import { type EntityValidator } from '../entity/EntityValidator.js';
|
|
5
4
|
import { type ChangeSet } from './ChangeSet.js';
|
|
6
5
|
import { type Configuration } from '../utils/Configuration.js';
|
|
7
6
|
import type { DriverMethodOptions, IDatabaseDriver } from '../drivers/IDatabaseDriver.js';
|
|
7
|
+
import type { EntityManager } from '../EntityManager.js';
|
|
8
8
|
export declare class ChangeSetPersister {
|
|
9
9
|
private readonly driver;
|
|
10
10
|
private readonly metadata;
|
|
11
11
|
private readonly hydrator;
|
|
12
12
|
private readonly factory;
|
|
13
|
-
private readonly validator;
|
|
14
13
|
private readonly config;
|
|
14
|
+
private readonly em;
|
|
15
15
|
private readonly platform;
|
|
16
16
|
private readonly comparator;
|
|
17
17
|
private readonly usesReturningStatement;
|
|
18
|
-
constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory,
|
|
18
|
+
constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, config: Configuration, em: EntityManager);
|
|
19
19
|
executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
20
20
|
executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
21
21
|
executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
22
22
|
private runForEachSchema;
|
|
23
|
+
private validateRequired;
|
|
23
24
|
private processProperties;
|
|
24
25
|
private persistNewEntity;
|
|
25
26
|
private persistNewEntities;
|
|
26
|
-
private
|
|
27
|
+
private prepareOptions;
|
|
27
28
|
private persistNewEntitiesBatch;
|
|
28
29
|
private persistManagedEntity;
|
|
29
30
|
private persistManagedEntities;
|
|
@@ -3,25 +3,25 @@ import { helper } from '../entity/wrap.js';
|
|
|
3
3
|
import { ChangeSetType } from './ChangeSet.js';
|
|
4
4
|
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
5
5
|
import { Utils } from '../utils/Utils.js';
|
|
6
|
-
import { OptimisticLockError } from '../errors.js';
|
|
6
|
+
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
7
7
|
import { ReferenceKind } from '../enums.js';
|
|
8
8
|
export class ChangeSetPersister {
|
|
9
9
|
driver;
|
|
10
10
|
metadata;
|
|
11
11
|
hydrator;
|
|
12
12
|
factory;
|
|
13
|
-
validator;
|
|
14
13
|
config;
|
|
14
|
+
em;
|
|
15
15
|
platform;
|
|
16
16
|
comparator;
|
|
17
17
|
usesReturningStatement;
|
|
18
|
-
constructor(driver, metadata, hydrator, factory,
|
|
18
|
+
constructor(driver, metadata, hydrator, factory, config, em) {
|
|
19
19
|
this.driver = driver;
|
|
20
20
|
this.metadata = metadata;
|
|
21
21
|
this.hydrator = hydrator;
|
|
22
22
|
this.factory = factory;
|
|
23
|
-
this.validator = validator;
|
|
24
23
|
this.config = config;
|
|
24
|
+
this.em = em;
|
|
25
25
|
this.platform = this.driver.getPlatform();
|
|
26
26
|
this.comparator = this.config.getComparator(this.metadata);
|
|
27
27
|
this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
|
|
@@ -62,7 +62,7 @@ export class ChangeSetPersister {
|
|
|
62
62
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
63
63
|
const chunk = changeSets.slice(i, i + size);
|
|
64
64
|
const pks = chunk.map(cs => cs.getPrimaryKey());
|
|
65
|
-
options = this.
|
|
65
|
+
options = this.prepareOptions(meta, options);
|
|
66
66
|
await this.driver.nativeDelete(meta.root.className, { [pk]: { $in: pks } }, options);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -79,18 +79,37 @@ export class ChangeSetPersister {
|
|
|
79
79
|
await this[method](group, ...args, options, true);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
validateRequired(entity) {
|
|
83
|
+
const wrapped = helper(entity);
|
|
84
|
+
for (const prop of wrapped.__meta.props) {
|
|
85
|
+
if (!prop.nullable &&
|
|
86
|
+
!prop.autoincrement &&
|
|
87
|
+
!prop.default &&
|
|
88
|
+
!prop.defaultRaw &&
|
|
89
|
+
!prop.onCreate &&
|
|
90
|
+
!prop.generated &&
|
|
91
|
+
!prop.embedded &&
|
|
92
|
+
![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
|
|
93
|
+
prop.name !== wrapped.__meta.root.discriminatorColumn &&
|
|
94
|
+
prop.type !== 'ObjectId' &&
|
|
95
|
+
prop.persist !== false &&
|
|
96
|
+
entity[prop.name] == null) {
|
|
97
|
+
throw ValidationError.propertyRequired(entity, prop);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
82
101
|
processProperties(changeSet) {
|
|
83
102
|
const meta = this.metadata.find(changeSet.name);
|
|
84
103
|
for (const prop of meta.relations) {
|
|
85
104
|
this.processProperty(changeSet, prop);
|
|
86
105
|
}
|
|
87
106
|
if (changeSet.type === ChangeSetType.CREATE && this.config.get('validateRequired')) {
|
|
88
|
-
this.
|
|
107
|
+
this.validateRequired(changeSet.entity);
|
|
89
108
|
}
|
|
90
109
|
}
|
|
91
110
|
async persistNewEntity(meta, changeSet, options) {
|
|
92
111
|
const wrapped = helper(changeSet.entity);
|
|
93
|
-
options = this.
|
|
112
|
+
options = this.prepareOptions(meta, options, {
|
|
94
113
|
convertCustomTypes: false,
|
|
95
114
|
});
|
|
96
115
|
const res = await this.driver.nativeInsertMany(meta.className, [changeSet.payload], options);
|
|
@@ -116,15 +135,17 @@ export class ChangeSetPersister {
|
|
|
116
135
|
}
|
|
117
136
|
}
|
|
118
137
|
}
|
|
119
|
-
|
|
138
|
+
prepareOptions(meta, options, additionalOptions) {
|
|
139
|
+
const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
|
|
120
140
|
return {
|
|
121
141
|
...options,
|
|
122
142
|
...additionalOptions,
|
|
123
143
|
schema: options?.schema ?? meta.schema,
|
|
144
|
+
loggerContext,
|
|
124
145
|
};
|
|
125
146
|
}
|
|
126
147
|
async persistNewEntitiesBatch(meta, changeSets, options) {
|
|
127
|
-
options = this.
|
|
148
|
+
options = this.prepareOptions(meta, options, {
|
|
128
149
|
convertCustomTypes: false,
|
|
129
150
|
processCollections: false,
|
|
130
151
|
});
|
|
@@ -175,7 +196,7 @@ export class ChangeSetPersister {
|
|
|
175
196
|
}
|
|
176
197
|
async persistManagedEntitiesBatch(meta, changeSets, options) {
|
|
177
198
|
await this.checkOptimisticLocks(meta, changeSets, options);
|
|
178
|
-
options = this.
|
|
199
|
+
options = this.prepareOptions(meta, options, {
|
|
179
200
|
convertCustomTypes: false,
|
|
180
201
|
processCollections: false,
|
|
181
202
|
});
|
|
@@ -210,7 +231,9 @@ export class ChangeSetPersister {
|
|
|
210
231
|
// of using the raw value from db, we convert it back to the db value explicitly
|
|
211
232
|
value = prop.customType ? prop.customType.convertToDatabaseValue(insertId, this.platform, { mode: 'serialization' }) : value;
|
|
212
233
|
changeSet.payload[wrapped.__meta.primaryKeys[0]] = value;
|
|
213
|
-
wrapped.__identifier
|
|
234
|
+
if (wrapped.__identifier && !Array.isArray(wrapped.__identifier)) {
|
|
235
|
+
wrapped.__identifier.setValue(value);
|
|
236
|
+
}
|
|
214
237
|
}
|
|
215
238
|
/**
|
|
216
239
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
@@ -233,7 +256,7 @@ export class ChangeSetPersister {
|
|
|
233
256
|
}
|
|
234
257
|
async updateEntity(meta, changeSet, options) {
|
|
235
258
|
const cond = changeSet.getPrimaryKey(true);
|
|
236
|
-
options = this.
|
|
259
|
+
options = this.prepareOptions(meta, options, {
|
|
237
260
|
convertCustomTypes: false,
|
|
238
261
|
});
|
|
239
262
|
if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
|
|
@@ -260,7 +283,7 @@ export class ChangeSetPersister {
|
|
|
260
283
|
return cond;
|
|
261
284
|
});
|
|
262
285
|
const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
263
|
-
options = this.
|
|
286
|
+
options = this.prepareOptions(meta, options, {
|
|
264
287
|
fields: primaryKeys,
|
|
265
288
|
});
|
|
266
289
|
const res = await this.driver.find(meta.root.className, { $or }, options);
|
|
@@ -284,11 +307,22 @@ export class ChangeSetPersister {
|
|
|
284
307
|
async reloadVersionValues(meta, changeSets, options) {
|
|
285
308
|
const reloadProps = meta.versionProperty && !this.usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
286
309
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
.
|
|
310
|
+
for (const prop of meta.props) {
|
|
311
|
+
if (prop.persist === false) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (isRaw(changeSets[0].entity[prop.name])) {
|
|
315
|
+
reloadProps.push(prop);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
// do not reload things that already had a runtime value
|
|
319
|
+
if (changeSets[0].entity[prop.name] != null || prop.defaultRaw === 'null') {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
if (prop.autoincrement || prop.generated || prop.defaultRaw) {
|
|
323
|
+
reloadProps.push(prop);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
292
326
|
}
|
|
293
327
|
if (changeSets[0].type === ChangeSetType.UPDATE) {
|
|
294
328
|
const returning = new Set();
|
|
@@ -319,12 +353,12 @@ export class ChangeSetPersister {
|
|
|
319
353
|
}
|
|
320
354
|
return val;
|
|
321
355
|
});
|
|
322
|
-
options = this.
|
|
356
|
+
options = this.prepareOptions(meta, options, {
|
|
323
357
|
fields: Utils.unique(reloadProps.map(prop => prop.name)),
|
|
324
358
|
});
|
|
325
359
|
const data = await this.driver.find(meta.className, { [pk]: { $in: pks } }, options);
|
|
326
360
|
const map = new Map();
|
|
327
|
-
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta,
|
|
361
|
+
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
|
|
328
362
|
for (const changeSet of changeSets) {
|
|
329
363
|
const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
330
364
|
this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
|
|
@@ -338,6 +372,10 @@ export class ChangeSetPersister {
|
|
|
338
372
|
changeSet.payload[prop.name] = value.getValue();
|
|
339
373
|
return;
|
|
340
374
|
}
|
|
375
|
+
if (Array.isArray(value) && value.every(item => item instanceof EntityIdentifier)) {
|
|
376
|
+
changeSet.payload[prop.name] = value.map(item => item.getValue());
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
341
379
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && Array.isArray(value)) {
|
|
342
380
|
changeSet.payload[prop.name] = value.map(val => val instanceof EntityIdentifier ? val.getValue() : val);
|
|
343
381
|
return;
|
|
@@ -28,6 +28,12 @@ export declare class UnitOfWork {
|
|
|
28
28
|
private working;
|
|
29
29
|
constructor(em: EntityManager);
|
|
30
30
|
merge<T extends object>(entity: T, visited?: Set<AnyEntity>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Entity data can wary in its shape, e.g. we might get a deep relation graph with joined strategy, but for diffing,
|
|
33
|
+
* we need to normalize the shape, so relation values are only raw FKs. This method handles that.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
normalizeEntityData<T extends object>(meta: EntityMetadata<T>, data: EntityData<T>): void;
|
|
31
37
|
/**
|
|
32
38
|
* @internal
|
|
33
39
|
*/
|
|
@@ -39,7 +45,7 @@ export declare class UnitOfWork {
|
|
|
39
45
|
/**
|
|
40
46
|
* Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
|
|
41
47
|
*/
|
|
42
|
-
getById<T extends object>(entityName: string, id: Primary<T> | Primary<T>[], schema?: string): T | undefined;
|
|
48
|
+
getById<T extends object>(entityName: string, id: Primary<T> | Primary<T>[], schema?: string, convertCustomTypes?: boolean): T | undefined;
|
|
43
49
|
tryGetById<T extends object>(entityName: string, where: FilterQuery<T>, schema?: string, strict?: boolean): T | null;
|
|
44
50
|
/**
|
|
45
51
|
* Returns map of all managed entities.
|
|
@@ -103,6 +109,7 @@ export declare class UnitOfWork {
|
|
|
103
109
|
private commitDeleteChangeSets;
|
|
104
110
|
private commitExtraUpdates;
|
|
105
111
|
private commitCollectionUpdates;
|
|
112
|
+
private filterCollectionUpdates;
|
|
106
113
|
/**
|
|
107
114
|
* Orders change sets so FK constrains are maintained, ensures stable order (needed for node < 11)
|
|
108
115
|
*/
|