@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120
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 -56
- package/EntityManager.js +332 -293
- package/MikroORM.d.ts +41 -32
- package/MikroORM.js +100 -140
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +8 -7
- 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 +16 -7
- package/connections/Connection.js +23 -14
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +35 -19
- package/drivers/IDatabaseDriver.d.ts +38 -17
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -30
- package/entity/Collection.js +439 -99
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +72 -53
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +30 -15
- package/entity/EntityLoader.d.ts +7 -6
- package/entity/EntityLoader.js +84 -72
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityRepository.js +2 -2
- package/entity/Reference.d.ts +6 -5
- package/entity/Reference.js +34 -9
- package/entity/WrappedEntity.d.ts +2 -7
- package/entity/WrappedEntity.js +3 -8
- package/entity/defineEntity.d.ts +568 -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 +17 -9
- package/errors.js +41 -21
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +50 -33
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +13 -17
- package/metadata/EntitySchema.js +67 -51
- package/metadata/MetadataDiscovery.d.ts +6 -10
- package/metadata/MetadataDiscovery.js +289 -298
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +46 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +70 -37
- package/metadata/MetadataValidator.d.ts +2 -9
- package/metadata/MetadataValidator.js +22 -38
- 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 +8 -4
- package/naming-strategy/AbstractNamingStrategy.js +8 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +14 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +6 -13
- package/platforms/Platform.js +17 -43
- package/serialization/EntitySerializer.d.ts +5 -0
- package/serialization/EntitySerializer.js +47 -27
- package/serialization/EntityTransformer.js +28 -18
- package/serialization/SerializationContext.d.ts +6 -6
- 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/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +124 -86
- package/typings.js +50 -42
- package/unit-of-work/ChangeSet.d.ts +2 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +14 -12
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +65 -33
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/UnitOfWork.d.ts +10 -3
- package/unit-of-work/UnitOfWork.js +139 -96
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +18 -16
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +753 -207
- package/utils/Configuration.js +145 -190
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +0 -3
- package/utils/Cursor.js +9 -6
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +65 -17
- package/utils/EntityComparator.d.ts +13 -9
- package/utils/EntityComparator.js +85 -43
- package/utils/QueryHelper.d.ts +14 -6
- package/utils/QueryHelper.js +87 -25
- package/utils/RawQueryFragment.d.ts +48 -25
- package/utils/RawQueryFragment.js +66 -70
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +12 -119
- package/utils/Utils.js +97 -373
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +32 -0
- package/utils/fs-utils.js +178 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +9 -4
- 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
|
@@ -25,38 +25,56 @@ export class EntityMetadata {
|
|
|
25
25
|
this.referencingProperties = [];
|
|
26
26
|
this.concurrencyCheckKeys = new Set();
|
|
27
27
|
Object.assign(this, meta);
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const name = meta.className ?? meta.name;
|
|
29
|
+
if (!this.class && name) {
|
|
30
|
+
this.class = ({ [name]: class {
|
|
31
|
+
} })[name];
|
|
32
32
|
}
|
|
33
|
+
}
|
|
34
|
+
addProperty(prop) {
|
|
33
35
|
this.properties[prop.name] = prop;
|
|
34
36
|
this.propertyOrder.set(prop.name, this.props.length);
|
|
35
|
-
|
|
36
|
-
if (sync) {
|
|
37
|
-
this.sync();
|
|
38
|
-
}
|
|
37
|
+
this.sync();
|
|
39
38
|
}
|
|
40
39
|
removeProperty(name, sync = true) {
|
|
41
40
|
delete this.properties[name];
|
|
42
41
|
this.propertyOrder.delete(name);
|
|
43
|
-
/* v8 ignore next 3 */
|
|
44
42
|
if (sync) {
|
|
45
43
|
this.sync();
|
|
46
44
|
}
|
|
47
45
|
}
|
|
48
|
-
getPrimaryProps() {
|
|
49
|
-
|
|
46
|
+
getPrimaryProps(flatten = false) {
|
|
47
|
+
const pks = this.primaryKeys.map(pk => this.properties[pk]);
|
|
48
|
+
if (flatten) {
|
|
49
|
+
return pks.flatMap(pk => {
|
|
50
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(pk.kind)) {
|
|
51
|
+
return pk.targetMeta.getPrimaryProps(true);
|
|
52
|
+
}
|
|
53
|
+
return [pk];
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return pks;
|
|
50
57
|
}
|
|
51
58
|
getPrimaryProp() {
|
|
52
59
|
return this.properties[this.primaryKeys[0]];
|
|
53
60
|
}
|
|
61
|
+
createColumnMappingObject() {
|
|
62
|
+
return Object.values(this.properties).reduce((o, prop) => {
|
|
63
|
+
if (prop.fieldNames) {
|
|
64
|
+
o[prop.name] = prop.fieldNames[0];
|
|
65
|
+
}
|
|
66
|
+
return o;
|
|
67
|
+
}, {});
|
|
68
|
+
}
|
|
54
69
|
get tableName() {
|
|
55
70
|
return this.collection;
|
|
56
71
|
}
|
|
57
72
|
set tableName(name) {
|
|
58
73
|
this.collection = name;
|
|
59
74
|
}
|
|
75
|
+
get uniqueName() {
|
|
76
|
+
return this.tableName + '_' + this._id;
|
|
77
|
+
}
|
|
60
78
|
sync(initIndexes = false, config) {
|
|
61
79
|
this.root ??= this;
|
|
62
80
|
const props = Object.values(this.properties).sort((a, b) => this.propertyOrder.get(a.name) - this.propertyOrder.get(b.name));
|
|
@@ -66,23 +84,30 @@ export class EntityMetadata {
|
|
|
66
84
|
this.uniqueProps = this.props.filter(prop => prop.unique);
|
|
67
85
|
this.getterProps = this.props.filter(prop => prop.getter);
|
|
68
86
|
this.comparableProps = this.props.filter(prop => EntityComparator.isComparable(prop, this));
|
|
87
|
+
this.validateProps = this.props.filter(prop => {
|
|
88
|
+
if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return prop.kind === ReferenceKind.SCALAR && ['string', 'number', 'boolean', 'Date'].includes(prop.type);
|
|
92
|
+
});
|
|
69
93
|
this.hydrateProps = this.props.filter(prop => {
|
|
70
94
|
// `prop.userDefined` is either `undefined` or `false`
|
|
71
95
|
const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
|
|
72
96
|
// even if we don't have a setter, do not ignore value from database!
|
|
73
|
-
const onlyGetter = prop.getter && !prop.setter;
|
|
97
|
+
const onlyGetter = prop.getter && !prop.setter && prop.persist === false;
|
|
74
98
|
return !prop.inherited && prop.hydrate !== false && !discriminator && !prop.embedded && !onlyGetter;
|
|
75
99
|
});
|
|
76
|
-
this.trackingProps = this.hydrateProps
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
100
|
+
this.trackingProps = this.hydrateProps.filter(prop => {
|
|
101
|
+
return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
|
|
102
|
+
});
|
|
103
|
+
this.selfReferencing = this.relations.some(prop => {
|
|
104
|
+
return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
|
|
105
|
+
});
|
|
81
106
|
this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
|
|
82
107
|
this.virtual = !!this.expression;
|
|
83
108
|
if (config) {
|
|
84
109
|
for (const prop of this.props) {
|
|
85
|
-
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item =>
|
|
110
|
+
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
|
|
86
111
|
const name = config.getNamingStrategy().indexName(this.tableName, prop.fieldNames, 'check');
|
|
87
112
|
const exists = this.checks.findIndex(check => check.name === name);
|
|
88
113
|
if (exists !== -1) {
|
|
@@ -109,8 +134,7 @@ export class EntityMetadata {
|
|
|
109
134
|
this.props.forEach(prop => this.initIndexes(prop));
|
|
110
135
|
}
|
|
111
136
|
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;
|
|
137
|
+
const isReference = (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
|
|
114
138
|
if (isReference) {
|
|
115
139
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
116
140
|
const meta = this;
|
|
@@ -129,10 +153,7 @@ export class EntityMetadata {
|
|
|
129
153
|
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
|
130
154
|
// when propagation from inside hydration, we set the FK to the entity data immediately
|
|
131
155
|
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
|
132
|
-
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
wrapped.__touched = !hydrator.isRunning();
|
|
156
|
+
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta, true);
|
|
136
157
|
}
|
|
137
158
|
EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
|
|
138
159
|
},
|
|
@@ -140,23 +161,6 @@ export class EntityMetadata {
|
|
|
140
161
|
configurable: true,
|
|
141
162
|
};
|
|
142
163
|
}
|
|
143
|
-
if (prop.inherited || prop.primary || isCollection || prop.persist === false || prop.trackChanges === false || isReference || prop.embedded) {
|
|
144
|
-
return o;
|
|
145
|
-
}
|
|
146
|
-
o[prop.name] = {
|
|
147
|
-
get() {
|
|
148
|
-
return this.__helper.__data[prop.name];
|
|
149
|
-
},
|
|
150
|
-
set(val) {
|
|
151
|
-
if (typeof val === 'object' && !!val && '__raw' in val) {
|
|
152
|
-
val.assign();
|
|
153
|
-
}
|
|
154
|
-
this.__helper.__data[prop.name] = val;
|
|
155
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
156
|
-
},
|
|
157
|
-
enumerable: true,
|
|
158
|
-
configurable: true,
|
|
159
|
-
};
|
|
160
164
|
return o;
|
|
161
165
|
}, { __gettersDefined: { value: true, enumerable: false } });
|
|
162
166
|
}
|
|
@@ -178,7 +182,7 @@ export class EntityMetadata {
|
|
|
178
182
|
this.indexes.push({ properties: prop.name });
|
|
179
183
|
prop.index = false;
|
|
180
184
|
}
|
|
181
|
-
/* v8 ignore next
|
|
185
|
+
/* v8 ignore next */
|
|
182
186
|
if (owner && prop.fieldNames.length > 1 && prop.unique) {
|
|
183
187
|
this.uniques.push({ properties: prop.name });
|
|
184
188
|
prop.unique = false;
|
|
@@ -188,4 +192,8 @@ export class EntityMetadata {
|
|
|
188
192
|
clone() {
|
|
189
193
|
return this;
|
|
190
194
|
}
|
|
195
|
+
/** @ignore */
|
|
196
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
197
|
+
return `[${this.constructor.name}<${this.className}>]`;
|
|
198
|
+
}
|
|
191
199
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import type { EntityData, EntityMetadata, EntityDictionary, Primary } from '../typings.js';
|
|
3
2
|
export declare class ChangeSet<T extends object> {
|
|
4
3
|
entity: T;
|
|
@@ -10,13 +9,10 @@ export declare class ChangeSet<T extends object> {
|
|
|
10
9
|
constructor(entity: T, type: ChangeSetType, payload: EntityDictionary<T>, meta: EntityMetadata<T>);
|
|
11
10
|
getPrimaryKey(object?: boolean): Primary<T> | null;
|
|
12
11
|
getSerializedPrimaryKey(): string | null;
|
|
13
|
-
/** @ignore */
|
|
14
|
-
[inspect.custom](depth?: number): string;
|
|
15
12
|
}
|
|
16
13
|
export interface ChangeSet<T> {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
collection: string;
|
|
14
|
+
meta: EntityMetadata<T>;
|
|
15
|
+
rootMeta: EntityMetadata<T>;
|
|
20
16
|
schema?: string;
|
|
21
17
|
type: ChangeSetType;
|
|
22
18
|
entity: T;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import { helper } from '../entity/wrap.js';
|
|
3
2
|
import { Utils } from '../utils/Utils.js';
|
|
3
|
+
import { inspect } from '../logging/inspect.js';
|
|
4
4
|
export class ChangeSet {
|
|
5
5
|
entity;
|
|
6
6
|
type;
|
|
@@ -13,9 +13,8 @@ export class ChangeSet {
|
|
|
13
13
|
this.type = type;
|
|
14
14
|
this.payload = payload;
|
|
15
15
|
this.meta = meta;
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.collection = meta.root.collection;
|
|
16
|
+
this.meta = meta;
|
|
17
|
+
this.rootMeta = meta.root;
|
|
19
18
|
this.schema = helper(entity).__schema ?? meta.root.schema;
|
|
20
19
|
}
|
|
21
20
|
getPrimaryKey(object = false) {
|
|
@@ -46,7 +45,7 @@ export class ChangeSet {
|
|
|
46
45
|
return this.serializedPrimaryKey;
|
|
47
46
|
}
|
|
48
47
|
/** @ignore */
|
|
49
|
-
[inspect.custom](depth = 2) {
|
|
48
|
+
[Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
|
|
50
49
|
const object = { ...this };
|
|
51
50
|
const hidden = ['meta', 'serializedPrimaryKey'];
|
|
52
51
|
hidden.forEach(k => delete object[k]);
|
|
@@ -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;
|
|
@@ -20,7 +19,7 @@ export class ChangeSetComputer {
|
|
|
20
19
|
this.comparator = this.config.getComparator(this.metadata);
|
|
21
20
|
}
|
|
22
21
|
computeChangeSet(entity) {
|
|
23
|
-
const meta = this.metadata.get(entity.constructor
|
|
22
|
+
const meta = this.metadata.get(entity.constructor);
|
|
24
23
|
if (meta.readonly) {
|
|
25
24
|
return null;
|
|
26
25
|
}
|
|
@@ -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) {
|
|
@@ -91,7 +91,7 @@ export class ChangeSetComputer {
|
|
|
91
91
|
computePayload(entity, ignoreUndefined = false) {
|
|
92
92
|
const data = this.comparator.prepareEntity(entity);
|
|
93
93
|
const wrapped = helper(entity);
|
|
94
|
-
const entityName = wrapped.__meta.
|
|
94
|
+
const entityName = wrapped.__meta.class;
|
|
95
95
|
const originalEntityData = wrapped.__originalEntityData;
|
|
96
96
|
if (!wrapped.__initialized) {
|
|
97
97
|
for (const prop of wrapped.__meta.primaryKeys) {
|
|
@@ -132,7 +132,7 @@ export class ChangeSetComputer {
|
|
|
132
132
|
const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
|
|
133
133
|
targets.forEach(([target, idx]) => {
|
|
134
134
|
if (!target.__helper.hasPrimaryKey()) {
|
|
135
|
-
Utils.setPayloadProperty(changeSet.payload,
|
|
135
|
+
Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, target.__helper.__identifier, idx);
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
138
|
}
|
|
@@ -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();
|
|
@@ -30,7 +30,7 @@ export class ChangeSetPersister {
|
|
|
30
30
|
if (!withSchema) {
|
|
31
31
|
return this.runForEachSchema(changeSets, 'executeInserts', options);
|
|
32
32
|
}
|
|
33
|
-
const meta =
|
|
33
|
+
const meta = changeSets[0].meta;
|
|
34
34
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
35
35
|
if (changeSets.length > 1 && this.config.get('useBatchInserts', this.platform.usesBatchInserts())) {
|
|
36
36
|
return this.persistNewEntities(meta, changeSets, options);
|
|
@@ -43,7 +43,7 @@ export class ChangeSetPersister {
|
|
|
43
43
|
if (!withSchema) {
|
|
44
44
|
return this.runForEachSchema(changeSets, 'executeUpdates', options, batched);
|
|
45
45
|
}
|
|
46
|
-
const meta =
|
|
46
|
+
const meta = changeSets[0].meta;
|
|
47
47
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
48
48
|
if (batched && changeSets.length > 1 && this.config.get('useBatchUpdates', this.platform.usesBatchUpdates())) {
|
|
49
49
|
return this.persistManagedEntities(meta, changeSets, options);
|
|
@@ -62,8 +62,8 @@ 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.
|
|
66
|
-
await this.driver.nativeDelete(meta.root.
|
|
65
|
+
options = this.prepareOptions(meta, options);
|
|
66
|
+
await this.driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
async runForEachSchema(changeSets, method, options, ...args) {
|
|
@@ -79,21 +79,40 @@ 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
|
-
const meta =
|
|
102
|
+
const meta = changeSet.meta;
|
|
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
|
-
const res = await this.driver.nativeInsertMany(meta.
|
|
115
|
+
const res = await this.driver.nativeInsertMany(meta.class, [changeSet.payload], options);
|
|
97
116
|
if (!wrapped.hasPrimaryKey()) {
|
|
98
117
|
this.mapPrimaryKey(meta, res.insertId, changeSet);
|
|
99
118
|
}
|
|
@@ -116,19 +135,21 @@ 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
|
});
|
|
131
|
-
const res = await this.driver.nativeInsertMany(meta.
|
|
152
|
+
const res = await this.driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
|
|
132
153
|
for (let i = 0; i < changeSets.length; i++) {
|
|
133
154
|
const changeSet = changeSets[i];
|
|
134
155
|
const wrapped = helper(changeSet.entity);
|
|
@@ -146,7 +167,7 @@ export class ChangeSetPersister {
|
|
|
146
167
|
}
|
|
147
168
|
}
|
|
148
169
|
async persistManagedEntity(changeSet, options) {
|
|
149
|
-
const meta =
|
|
170
|
+
const meta = changeSet.meta;
|
|
150
171
|
const res = await this.updateEntity(meta, changeSet, options);
|
|
151
172
|
this.checkOptimisticLock(meta, changeSet, res);
|
|
152
173
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
@@ -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
|
});
|
|
@@ -187,7 +208,7 @@ export class ChangeSetPersister {
|
|
|
187
208
|
cond.push(where);
|
|
188
209
|
payload.push(changeSet.payload);
|
|
189
210
|
}
|
|
190
|
-
const res = await this.driver.nativeUpdateMany(meta.
|
|
211
|
+
const res = await this.driver.nativeUpdateMany(meta.class, cond, payload, options);
|
|
191
212
|
const map = new Map();
|
|
192
213
|
res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
|
|
193
214
|
for (const changeSet of changeSets) {
|
|
@@ -235,17 +256,17 @@ export class ChangeSetPersister {
|
|
|
235
256
|
}
|
|
236
257
|
async updateEntity(meta, changeSet, options) {
|
|
237
258
|
const cond = changeSet.getPrimaryKey(true);
|
|
238
|
-
options = this.
|
|
259
|
+
options = this.prepareOptions(meta, options, {
|
|
239
260
|
convertCustomTypes: false,
|
|
240
261
|
});
|
|
241
262
|
if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
|
|
242
|
-
return this.driver.nativeUpdate(changeSet.
|
|
263
|
+
return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
243
264
|
}
|
|
244
265
|
if (meta.versionProperty) {
|
|
245
266
|
cond[meta.versionProperty] = this.platform.quoteVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
246
267
|
}
|
|
247
268
|
this.checkConcurrencyKeys(meta, changeSet, cond);
|
|
248
|
-
return this.driver.nativeUpdate(changeSet.
|
|
269
|
+
return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
249
270
|
}
|
|
250
271
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
251
272
|
if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
|
|
@@ -262,10 +283,10 @@ export class ChangeSetPersister {
|
|
|
262
283
|
return cond;
|
|
263
284
|
});
|
|
264
285
|
const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
265
|
-
options = this.
|
|
286
|
+
options = this.prepareOptions(meta, options, {
|
|
266
287
|
fields: primaryKeys,
|
|
267
288
|
});
|
|
268
|
-
const res = await this.driver.find(meta.root.
|
|
289
|
+
const res = await this.driver.find(meta.root.class, { $or }, options);
|
|
269
290
|
if (res.length !== changeSets.length) {
|
|
270
291
|
const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
|
|
271
292
|
const entity = changeSets.find(cs => {
|
|
@@ -286,11 +307,22 @@ export class ChangeSetPersister {
|
|
|
286
307
|
async reloadVersionValues(meta, changeSets, options) {
|
|
287
308
|
const reloadProps = meta.versionProperty && !this.usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
288
309
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
.
|
|
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
|
+
}
|
|
294
326
|
}
|
|
295
327
|
if (changeSets[0].type === ChangeSetType.UPDATE) {
|
|
296
328
|
const returning = new Set();
|
|
@@ -321,12 +353,12 @@ export class ChangeSetPersister {
|
|
|
321
353
|
}
|
|
322
354
|
return val;
|
|
323
355
|
});
|
|
324
|
-
options = this.
|
|
356
|
+
options = this.prepareOptions(meta, options, {
|
|
325
357
|
fields: Utils.unique(reloadProps.map(prop => prop.name)),
|
|
326
358
|
});
|
|
327
|
-
const data = await this.driver.find(meta.
|
|
359
|
+
const data = await this.driver.find(meta.class, { [pk]: { $in: pks } }, options);
|
|
328
360
|
const map = new Map();
|
|
329
|
-
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta,
|
|
361
|
+
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
|
|
330
362
|
for (const changeSet of changeSets) {
|
|
331
363
|
const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
332
364
|
this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
|
|
@@ -334,7 +366,7 @@ export class ChangeSetPersister {
|
|
|
334
366
|
}
|
|
335
367
|
}
|
|
336
368
|
processProperty(changeSet, prop) {
|
|
337
|
-
const meta =
|
|
369
|
+
const meta = changeSet.meta;
|
|
338
370
|
const value = changeSet.payload[prop.name]; // for inline embeddables
|
|
339
371
|
if (value instanceof EntityIdentifier) {
|
|
340
372
|
changeSet.payload[prop.name] = value.getValue();
|
|
@@ -367,7 +399,7 @@ export class ChangeSetPersister {
|
|
|
367
399
|
if ((!this.usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
|
|
368
400
|
return;
|
|
369
401
|
}
|
|
370
|
-
const mapped = this.comparator.mapResult(meta
|
|
402
|
+
const mapped = this.comparator.mapResult(meta, row);
|
|
371
403
|
if (entity) {
|
|
372
404
|
this.hydrator.hydrate(entity, meta, mapped, this.factory, 'full', false, true);
|
|
373
405
|
}
|