@mikro-orm/core 7.0.0-dev.4 → 7.0.0-dev.40
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 +84 -18
- package/EntityManager.js +265 -172
- package/MikroORM.d.ts +7 -5
- package/MikroORM.js +0 -1
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +2 -1
- package/cache/FileCacheAdapter.js +6 -4
- package/connections/Connection.d.ts +4 -2
- package/connections/Connection.js +2 -2
- package/decorators/Check.d.ts +2 -2
- package/decorators/Embeddable.d.ts +5 -5
- package/decorators/Embeddable.js +1 -1
- package/decorators/Embedded.d.ts +6 -12
- package/decorators/Entity.d.ts +18 -3
- package/decorators/Enum.d.ts +1 -1
- package/decorators/Formula.d.ts +1 -2
- package/decorators/Indexed.d.ts +2 -2
- package/decorators/ManyToMany.d.ts +4 -2
- package/decorators/ManyToOne.d.ts +6 -2
- package/decorators/OneToMany.d.ts +4 -4
- package/decorators/OneToOne.d.ts +5 -1
- package/decorators/PrimaryKey.d.ts +2 -3
- package/decorators/Property.d.ts +54 -4
- package/decorators/Transactional.d.ts +1 -0
- package/decorators/Transactional.js +3 -3
- package/decorators/index.d.ts +1 -1
- package/drivers/DatabaseDriver.d.ts +4 -3
- package/drivers/IDatabaseDriver.d.ts +22 -2
- package/entity/ArrayCollection.d.ts +4 -2
- package/entity/ArrayCollection.js +18 -6
- package/entity/Collection.d.ts +1 -2
- package/entity/Collection.js +19 -10
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +9 -1
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +29 -9
- package/entity/EntityHelper.js +25 -3
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +74 -37
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityValidator.js +1 -1
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +30 -3
- package/entity/WrappedEntity.js +1 -1
- package/entity/defineEntity.d.ts +561 -0
- package/entity/defineEntity.js +537 -0
- package/entity/index.d.ts +2 -0
- package/entity/index.js +2 -0
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +15 -3
- package/enums.d.ts +16 -3
- package/enums.js +13 -0
- package/errors.d.ts +6 -0
- package/errors.js +14 -0
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +35 -24
- package/index.d.ts +2 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +8 -4
- package/metadata/EntitySchema.js +39 -19
- package/metadata/MetadataDiscovery.d.ts +1 -1
- package/metadata/MetadataDiscovery.js +88 -32
- package/metadata/MetadataStorage.js +1 -1
- package/metadata/MetadataValidator.js +4 -3
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +7 -1
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/package.json +5 -5
- package/platforms/Platform.d.ts +5 -3
- package/platforms/Platform.js +4 -8
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +2 -2
- package/serialization/EntityTransformer.js +1 -1
- package/serialization/SerializationContext.js +14 -11
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +3 -0
- package/types/BooleanType.d.ts +1 -1
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +1 -1
- package/types/DoubleType.js +1 -1
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/index.d.ts +1 -1
- package/typings.d.ts +88 -39
- package/typings.js +24 -4
- package/unit-of-work/ChangeSetComputer.js +3 -1
- package/unit-of-work/ChangeSetPersister.d.ts +4 -2
- package/unit-of-work/ChangeSetPersister.js +37 -16
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +109 -41
- package/utils/Configuration.d.ts +23 -5
- package/utils/Configuration.js +17 -3
- package/utils/ConfigurationLoader.d.ts +0 -2
- package/utils/ConfigurationLoader.js +2 -24
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +3 -0
- package/utils/DataloaderUtils.d.ts +7 -2
- package/utils/DataloaderUtils.js +38 -7
- package/utils/EntityComparator.d.ts +6 -2
- package/utils/EntityComparator.js +104 -58
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +66 -5
- package/utils/RawQueryFragment.d.ts +36 -2
- package/utils/RawQueryFragment.js +35 -1
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +218 -0
- package/utils/Utils.d.ts +11 -5
- package/utils/Utils.js +76 -33
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +52 -1
|
@@ -6,6 +6,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
6
6
|
protected readonly items: Set<T>;
|
|
7
7
|
protected initialized: boolean;
|
|
8
8
|
protected dirty: boolean;
|
|
9
|
+
protected partial: boolean;
|
|
9
10
|
protected snapshot: T[] | undefined;
|
|
10
11
|
protected _count?: number;
|
|
11
12
|
private _property?;
|
|
@@ -14,7 +15,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
14
15
|
getItems(): T[];
|
|
15
16
|
toArray<TT extends T>(): EntityDTO<TT>[];
|
|
16
17
|
toJSON(): EntityDTO<T>[];
|
|
17
|
-
getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string): U[];
|
|
18
|
+
getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string | string[]): U[];
|
|
18
19
|
add(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]): void;
|
|
19
20
|
/**
|
|
20
21
|
* @internal
|
|
@@ -25,7 +26,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
25
26
|
/**
|
|
26
27
|
* @internal
|
|
27
28
|
*/
|
|
28
|
-
hydrate(items: T[], forcePropagate?: boolean): void;
|
|
29
|
+
hydrate(items: T[], forcePropagate?: boolean, partial?: boolean): void;
|
|
29
30
|
/**
|
|
30
31
|
* Remove specified item(s) from the collection. Note that removing item from collection does not necessarily imply deleting the target entity,
|
|
31
32
|
* it means we are disconnecting the relation - removing items from collection, not removing entities from database - `Collection.remove()`
|
|
@@ -83,6 +84,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
|
|
|
83
84
|
count(): number;
|
|
84
85
|
isInitialized(fully?: boolean): boolean;
|
|
85
86
|
isDirty(): boolean;
|
|
87
|
+
isPartial(): boolean;
|
|
86
88
|
isEmpty(): boolean;
|
|
87
89
|
setDirty(dirty?: boolean): void;
|
|
88
90
|
get length(): number;
|
|
@@ -9,6 +9,7 @@ export class ArrayCollection {
|
|
|
9
9
|
items = new Set();
|
|
10
10
|
initialized = true;
|
|
11
11
|
dirty = false;
|
|
12
|
+
partial = false; // mark partially loaded collections, propagation is disabled for those
|
|
12
13
|
snapshot = []; // used to create a diff of the collection at commit time, undefined marks overridden values so we need to wipe when flushing
|
|
13
14
|
_count;
|
|
14
15
|
_property;
|
|
@@ -40,15 +41,22 @@ export class ArrayCollection {
|
|
|
40
41
|
}
|
|
41
42
|
getIdentifiers(field) {
|
|
42
43
|
const items = this.getItems();
|
|
44
|
+
const targetMeta = this.property.targetMeta;
|
|
43
45
|
if (items.length === 0) {
|
|
44
46
|
return [];
|
|
45
47
|
}
|
|
46
|
-
field ??=
|
|
48
|
+
field ??= targetMeta.compositePK ? targetMeta.primaryKeys : targetMeta.serializedPrimaryKey;
|
|
49
|
+
const cb = (i, f) => {
|
|
50
|
+
if (Utils.isEntity(i[f], true)) {
|
|
51
|
+
return wrap(i[f], true).getPrimaryKey();
|
|
52
|
+
}
|
|
53
|
+
return i[f];
|
|
54
|
+
};
|
|
47
55
|
return items.map(i => {
|
|
48
|
-
if (
|
|
49
|
-
return
|
|
56
|
+
if (Array.isArray(field)) {
|
|
57
|
+
return field.map(f => cb(i, f));
|
|
50
58
|
}
|
|
51
|
-
return i
|
|
59
|
+
return cb(i, field);
|
|
52
60
|
});
|
|
53
61
|
}
|
|
54
62
|
add(entity, ...entities) {
|
|
@@ -100,11 +108,12 @@ export class ArrayCollection {
|
|
|
100
108
|
/**
|
|
101
109
|
* @internal
|
|
102
110
|
*/
|
|
103
|
-
hydrate(items, forcePropagate) {
|
|
111
|
+
hydrate(items, forcePropagate, partial) {
|
|
104
112
|
for (let i = 0; i < this.items.size; i++) {
|
|
105
113
|
delete this[i];
|
|
106
114
|
}
|
|
107
115
|
this.initialized = true;
|
|
116
|
+
this.partial = !!partial;
|
|
108
117
|
this.items.clear();
|
|
109
118
|
this._count = 0;
|
|
110
119
|
this.add(items);
|
|
@@ -267,6 +276,9 @@ export class ArrayCollection {
|
|
|
267
276
|
isDirty() {
|
|
268
277
|
return this.dirty;
|
|
269
278
|
}
|
|
279
|
+
isPartial() {
|
|
280
|
+
return this.partial;
|
|
281
|
+
}
|
|
270
282
|
isEmpty() {
|
|
271
283
|
return this.count() === 0;
|
|
272
284
|
}
|
|
@@ -383,7 +395,7 @@ export class ArrayCollection {
|
|
|
383
395
|
/** @ignore */
|
|
384
396
|
[inspect.custom](depth = 2) {
|
|
385
397
|
const object = { ...this };
|
|
386
|
-
const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly'];
|
|
398
|
+
const hidden = ['items', 'owner', '_property', '_count', 'snapshot', '_populated', '_snapshot', '_lazyInitialized', '_em', 'readonly', 'partial'];
|
|
387
399
|
hidden.forEach(k => delete object[k]);
|
|
388
400
|
const ret = inspect(object, { depth });
|
|
389
401
|
const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
|
package/entity/Collection.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { EntityDTO, EntityKey, FilterQuery, Loaded, LoadedCollection, Popul
|
|
|
2
2
|
import { ArrayCollection } from './ArrayCollection.js';
|
|
3
3
|
import { Reference } from './Reference.js';
|
|
4
4
|
import type { Transaction } from '../connections/Connection.js';
|
|
5
|
-
import type {
|
|
5
|
+
import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
|
|
6
6
|
import type { EntityLoaderOptions } from './EntityLoader.js';
|
|
7
7
|
export interface MatchingOptions<T extends object, P extends string = never> extends FindOptions<T, P> {
|
|
8
8
|
where?: FilterQuery<T>;
|
|
@@ -12,7 +12,6 @@ export interface MatchingOptions<T extends object, P extends string = never> ext
|
|
|
12
12
|
export declare class Collection<T extends object, O extends object = object> extends ArrayCollection<T, O> {
|
|
13
13
|
private readonly?;
|
|
14
14
|
private _populated?;
|
|
15
|
-
private _em?;
|
|
16
15
|
private _snapshot?;
|
|
17
16
|
constructor(owner: O, items?: T[], initialized?: boolean);
|
|
18
17
|
/**
|
package/entity/Collection.js
CHANGED
|
@@ -4,10 +4,10 @@ import { ValidationError } from '../errors.js';
|
|
|
4
4
|
import { ReferenceKind, DataloaderType } from '../enums.js';
|
|
5
5
|
import { Reference } from './Reference.js';
|
|
6
6
|
import { helper } from './wrap.js';
|
|
7
|
+
import { QueryHelper } from '../utils/QueryHelper.js';
|
|
7
8
|
export class Collection extends ArrayCollection {
|
|
8
9
|
readonly;
|
|
9
10
|
_populated;
|
|
10
|
-
_em;
|
|
11
11
|
// this is for some reason needed for TS, otherwise it can fail with `Type instantiation is excessively deep and possibly infinite.`
|
|
12
12
|
_snapshot;
|
|
13
13
|
constructor(owner, items, initialized = true) {
|
|
@@ -33,6 +33,7 @@ export class Collection extends ArrayCollection {
|
|
|
33
33
|
async load(options = {}) {
|
|
34
34
|
if (this.isInitialized(true) && !options.refresh) {
|
|
35
35
|
const em = this.getEntityManager(this.items, false);
|
|
36
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
|
36
37
|
await em?.populate(this.items, options.populate, options);
|
|
37
38
|
this.setSerializationContext(options);
|
|
38
39
|
}
|
|
@@ -218,13 +219,24 @@ export class Collection extends ArrayCollection {
|
|
|
218
219
|
return this;
|
|
219
220
|
}
|
|
220
221
|
const em = this.getEntityManager();
|
|
222
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property.filters, options.filters) };
|
|
221
223
|
if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.COLLECTION].includes(em.config.getDataloaderType())) {
|
|
222
224
|
const order = [...this.items]; // copy order of references
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
const orderBy = this.createOrderBy(options.orderBy);
|
|
226
|
+
const customOrder = orderBy.length > 0;
|
|
227
|
+
const pivotTable = this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable();
|
|
228
|
+
const loader = pivotTable ? 'colLoaderMtoN' : 'colLoader';
|
|
229
|
+
const items = await em[loader].load([
|
|
230
|
+
this,
|
|
231
|
+
{ ...options, orderBy },
|
|
232
|
+
]);
|
|
233
|
+
if (this.property.kind === ReferenceKind.MANY_TO_MANY) {
|
|
234
|
+
this.initialized = true;
|
|
235
|
+
this.dirty = false;
|
|
236
|
+
if (!customOrder) {
|
|
237
|
+
this.reorderItems(items, order);
|
|
238
|
+
}
|
|
239
|
+
return this;
|
|
228
240
|
}
|
|
229
241
|
this.items.clear();
|
|
230
242
|
let i = 0;
|
|
@@ -254,7 +266,7 @@ export class Collection extends ArrayCollection {
|
|
|
254
266
|
}
|
|
255
267
|
getEntityManager(items = [], required = true) {
|
|
256
268
|
const wrapped = helper(this.owner);
|
|
257
|
-
let em =
|
|
269
|
+
let em = wrapped.__em;
|
|
258
270
|
if (!em) {
|
|
259
271
|
for (const i of items) {
|
|
260
272
|
if (i && helper(i).__em) {
|
|
@@ -263,9 +275,6 @@ export class Collection extends ArrayCollection {
|
|
|
263
275
|
}
|
|
264
276
|
}
|
|
265
277
|
}
|
|
266
|
-
if (em) {
|
|
267
|
-
Object.defineProperty(this, '_em', { value: em });
|
|
268
|
-
}
|
|
269
278
|
if (!em && required) {
|
|
270
279
|
throw ValidationError.entityNotManaged(this.owner);
|
|
271
280
|
}
|
|
@@ -36,7 +36,7 @@ export interface AssignOptions<Convert extends boolean> {
|
|
|
36
36
|
*/
|
|
37
37
|
onlyProperties?: boolean;
|
|
38
38
|
/**
|
|
39
|
-
* With `onlyOwnProperties` enabled, to-many relations are skipped, and payloads of
|
|
39
|
+
* With `onlyOwnProperties` enabled, inverse sides of to-many relations are skipped, and payloads of other relations are converted
|
|
40
40
|
* to foreign keys. Defaults to `false`.
|
|
41
41
|
*/
|
|
42
42
|
onlyOwnProperties?: boolean;
|
package/entity/EntityAssigner.js
CHANGED
|
@@ -42,9 +42,17 @@ export class EntityAssigner {
|
|
|
42
42
|
}
|
|
43
43
|
const prop = { ...props[propName], name: propName };
|
|
44
44
|
if (prop && options.onlyOwnProperties) {
|
|
45
|
-
if ([ReferenceKind.
|
|
45
|
+
if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
+
if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
49
|
+
if (!prop.owner) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
else if (value?.map) {
|
|
53
|
+
value = value.map((v) => Utils.extractPK(v, prop.targetMeta));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
48
56
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
49
57
|
value = Utils.extractPK(value, prop.targetMeta);
|
|
50
58
|
}
|
|
@@ -4,12 +4,18 @@ import type { EntityComparator } from '../utils/EntityComparator.js';
|
|
|
4
4
|
export interface FactoryOptions {
|
|
5
5
|
initialized?: boolean;
|
|
6
6
|
newEntity?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Property `onCreate` hooks are normally executed during `flush` operation.
|
|
9
|
+
* With this option, they will be processed early inside `em.create()` method.
|
|
10
|
+
*/
|
|
11
|
+
processOnCreateHooksEarly?: boolean;
|
|
7
12
|
merge?: boolean;
|
|
8
13
|
refresh?: boolean;
|
|
9
14
|
convertCustomTypes?: boolean;
|
|
10
15
|
recomputeSnapshot?: boolean;
|
|
11
16
|
schema?: string;
|
|
12
17
|
parentSchema?: string;
|
|
18
|
+
normalizeAccessors?: boolean;
|
|
13
19
|
}
|
|
14
20
|
export declare class EntityFactory {
|
|
15
21
|
private readonly em;
|
|
@@ -27,6 +33,7 @@ export declare class EntityFactory {
|
|
|
27
33
|
createEmbeddable<T extends object>(entityName: EntityName<T>, data: EntityData<T>, options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>): T;
|
|
28
34
|
getComparator(): EntityComparator;
|
|
29
35
|
private createEntity;
|
|
36
|
+
private assignDefaultValues;
|
|
30
37
|
private hydrate;
|
|
31
38
|
private findEntity;
|
|
32
39
|
private processDiscriminatorColumn;
|
package/entity/EntityFactory.js
CHANGED
|
@@ -4,6 +4,7 @@ import { EventType, ReferenceKind } from '../enums.js';
|
|
|
4
4
|
import { Reference } from './Reference.js';
|
|
5
5
|
import { helper } from './wrap.js';
|
|
6
6
|
import { EntityHelper } from './EntityHelper.js';
|
|
7
|
+
import { JsonType } from '../types/JsonType.js';
|
|
7
8
|
export class EntityFactory {
|
|
8
9
|
em;
|
|
9
10
|
driver;
|
|
@@ -45,6 +46,7 @@ export class EntityFactory {
|
|
|
45
46
|
let wrapped = exists && helper(exists);
|
|
46
47
|
if (wrapped && !options.refresh) {
|
|
47
48
|
wrapped.__processing = true;
|
|
49
|
+
Utils.dropUndefinedProperties(data);
|
|
48
50
|
this.mergeData(meta2, exists, data, options);
|
|
49
51
|
wrapped.__processing = false;
|
|
50
52
|
if (wrapped.isInitialized()) {
|
|
@@ -70,9 +72,11 @@ export class EntityFactory {
|
|
|
70
72
|
continue;
|
|
71
73
|
}
|
|
72
74
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
73
|
-
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta
|
|
75
|
+
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
76
|
+
}
|
|
77
|
+
if (prop.customType instanceof JsonType && this.platform.convertsJsonAutomatically()) {
|
|
78
|
+
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
|
|
74
79
|
}
|
|
75
|
-
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
82
|
}
|
|
@@ -112,7 +116,7 @@ export class EntityFactory {
|
|
|
112
116
|
if (meta.versionProperty && data[meta.versionProperty] && data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
|
|
113
117
|
diff[meta.versionProperty] = data[meta.versionProperty];
|
|
114
118
|
}
|
|
115
|
-
const diff2 = this.comparator.diffEntities(meta.className, existsData, data);
|
|
119
|
+
const diff2 = this.comparator.diffEntities(meta.className, existsData, data, { includeInverseSides: true });
|
|
116
120
|
// do not override values changed by user
|
|
117
121
|
Utils.keys(diff).forEach(key => delete diff2[key]);
|
|
118
122
|
Utils.keys(diff2).filter(key => {
|
|
@@ -135,6 +139,10 @@ export class EntityFactory {
|
|
|
135
139
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
136
140
|
diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
|
|
137
141
|
}
|
|
142
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) && prop.customType?.ensureComparable(meta, prop) && diff2[key] != null) {
|
|
143
|
+
const converted = prop.customType.convertToJSValue(diff2[key], this.platform, { force: true });
|
|
144
|
+
diff2[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { fromQuery: true });
|
|
145
|
+
}
|
|
138
146
|
originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
|
|
139
147
|
helper(entity).__loadedProperties.add(key);
|
|
140
148
|
});
|
|
@@ -152,6 +160,7 @@ export class EntityFactory {
|
|
|
152
160
|
this.create(prop.type, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
|
|
153
161
|
}
|
|
154
162
|
});
|
|
163
|
+
this.unitOfWork.normalizeEntityData(meta, originalEntityData);
|
|
155
164
|
helper(entity).__touched = false;
|
|
156
165
|
}
|
|
157
166
|
createReference(entityName, id, options = {}) {
|
|
@@ -170,8 +179,8 @@ export class EntityFactory {
|
|
|
170
179
|
if (Array.isArray(id)) {
|
|
171
180
|
id = Utils.getPrimaryKeyCondFromArray(id, meta);
|
|
172
181
|
}
|
|
173
|
-
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform
|
|
174
|
-
const exists = this.unitOfWork.getById(entityName, pks, schema);
|
|
182
|
+
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform);
|
|
183
|
+
const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
|
|
175
184
|
if (exists) {
|
|
176
185
|
return exists;
|
|
177
186
|
}
|
|
@@ -230,17 +239,28 @@ export class EntityFactory {
|
|
|
230
239
|
}
|
|
231
240
|
return entity;
|
|
232
241
|
}
|
|
242
|
+
assignDefaultValues(entity, meta) {
|
|
243
|
+
for (const prop of meta.props) {
|
|
244
|
+
if (prop.onCreate) {
|
|
245
|
+
entity[prop.name] ??= prop.onCreate(entity, this.em);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
233
249
|
hydrate(entity, meta, data, options) {
|
|
234
250
|
if (options.initialized) {
|
|
235
|
-
this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
|
|
251
|
+
this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
236
252
|
}
|
|
237
253
|
else {
|
|
238
|
-
this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
|
|
254
|
+
this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
239
255
|
}
|
|
240
256
|
Utils.keys(data).forEach(key => {
|
|
241
257
|
helper(entity)?.__loadedProperties.add(key);
|
|
242
258
|
helper(entity)?.__serializationContext.fields?.add(key);
|
|
243
259
|
});
|
|
260
|
+
const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this.config.get('processOnCreateHooksEarly');
|
|
261
|
+
if (options.newEntity && processOnCreateHooksEarly) {
|
|
262
|
+
this.assignDefaultValues(entity, meta);
|
|
263
|
+
}
|
|
244
264
|
}
|
|
245
265
|
findEntity(data, meta, options) {
|
|
246
266
|
const schema = this.driver.getSchemaName(meta, options);
|
|
@@ -250,7 +270,7 @@ export class EntityFactory {
|
|
|
250
270
|
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
|
251
271
|
return undefined;
|
|
252
272
|
}
|
|
253
|
-
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform);
|
|
273
|
+
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform, options.convertCustomTypes);
|
|
254
274
|
return this.unitOfWork.getById(meta.className, pks, schema);
|
|
255
275
|
}
|
|
256
276
|
processDiscriminatorColumn(meta, data) {
|
|
@@ -284,7 +304,7 @@ export class EntityFactory {
|
|
|
284
304
|
return meta.constructorParams.map(k => {
|
|
285
305
|
if (meta.properties[k] && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[k].kind) && data[k]) {
|
|
286
306
|
const pk = Reference.unwrapReference(data[k]);
|
|
287
|
-
const entity = this.unitOfWork.getById(meta.properties[k].type, pk, options.schema);
|
|
307
|
+
const entity = this.unitOfWork.getById(meta.properties[k].type, pk, options.schema, true);
|
|
288
308
|
if (entity) {
|
|
289
309
|
return entity;
|
|
290
310
|
}
|
package/entity/EntityHelper.js
CHANGED
|
@@ -87,7 +87,7 @@ export class EntityHelper {
|
|
|
87
87
|
});
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
-
if (prop.inherited || prop.primary || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
|
|
90
|
+
if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.trackChanges === false || prop.embedded || isCollection) {
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
93
|
Object.defineProperty(meta.prototype, prop.name, {
|
|
@@ -113,7 +113,18 @@ export class EntityHelper {
|
|
|
113
113
|
static defineCustomInspect(meta) {
|
|
114
114
|
// @ts-ignore
|
|
115
115
|
meta.prototype[inspect.custom] ??= function (depth = 2) {
|
|
116
|
-
const object = {
|
|
116
|
+
const object = {};
|
|
117
|
+
const keys = new Set(Utils.keys(this)); // .sort((a, b) => (meta.propertyOrder.get(a) ?? 0) - (meta.propertyOrder.get(b) ?? 0));
|
|
118
|
+
for (const prop of meta.props) {
|
|
119
|
+
if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
|
|
120
|
+
object[prop.name] = this[prop.name];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
for (const key of keys) {
|
|
124
|
+
if (!meta.properties[key]) {
|
|
125
|
+
object[key] = this[key];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
117
128
|
// ensure we dont have internal symbols in the POJO
|
|
118
129
|
[OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps].forEach(sym => delete object[sym]);
|
|
119
130
|
meta.props
|
|
@@ -146,10 +157,13 @@ export class EntityHelper {
|
|
|
146
157
|
set(val) {
|
|
147
158
|
const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
|
|
148
159
|
const old = Reference.unwrapReference(wrapped.__data[prop.name]);
|
|
160
|
+
if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
|
|
161
|
+
old[prop.inversedBy].removeWithoutPropagation(this);
|
|
162
|
+
}
|
|
149
163
|
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
|
150
164
|
// when propagation from inside hydration, we set the FK to the entity data immediately
|
|
151
165
|
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
|
152
|
-
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta
|
|
166
|
+
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta, true);
|
|
153
167
|
}
|
|
154
168
|
else {
|
|
155
169
|
wrapped.__touched = !hydrator.isRunning();
|
|
@@ -169,6 +183,13 @@ export class EntityHelper {
|
|
|
169
183
|
continue;
|
|
170
184
|
}
|
|
171
185
|
const inverse = value?.[prop2.name];
|
|
186
|
+
if (prop.ref && owner[prop.name]) {
|
|
187
|
+
// eslint-disable-next-line dot-notation
|
|
188
|
+
owner[prop.name]['property'] = prop;
|
|
189
|
+
}
|
|
190
|
+
if (Utils.isCollection(inverse) && inverse.isPartial()) {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
172
193
|
if (prop.kind === ReferenceKind.MANY_TO_ONE && Utils.isCollection(inverse) && inverse.isInitialized()) {
|
|
173
194
|
inverse.addWithoutPropagation(owner);
|
|
174
195
|
helper(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
|
|
@@ -207,6 +228,7 @@ export class EntityHelper {
|
|
|
207
228
|
}
|
|
208
229
|
if (old?.[prop2.name] != null) {
|
|
209
230
|
delete helper(old).__data[prop2.name];
|
|
231
|
+
old[prop2.name] = null;
|
|
210
232
|
}
|
|
211
233
|
}
|
|
212
234
|
static ensurePropagation(entity) {
|
package/entity/EntityLoader.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ConnectionType,
|
|
1
|
+
import type { AnyEntity, ConnectionType, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
|
|
4
|
-
import type { EntityField } from '../drivers/IDatabaseDriver.js';
|
|
4
|
+
import type { EntityField, FilterOptions } from '../drivers/IDatabaseDriver.js';
|
|
5
5
|
import type { LoggingOptions } from '../logging/Logger.js';
|
|
6
6
|
export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL, Excludes extends string = never> = {
|
|
7
7
|
where?: FilterQuery<Entity>;
|
|
@@ -14,7 +14,7 @@ export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL
|
|
|
14
14
|
lookup?: boolean;
|
|
15
15
|
convertCustomTypes?: boolean;
|
|
16
16
|
ignoreLazyScalarProperties?: boolean;
|
|
17
|
-
filters?:
|
|
17
|
+
filters?: FilterOptions;
|
|
18
18
|
strategy?: LoadStrategy;
|
|
19
19
|
lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
|
|
20
20
|
schema?: string;
|
|
@@ -49,7 +49,8 @@ export declare class EntityLoader {
|
|
|
49
49
|
private findChildren;
|
|
50
50
|
private mergePrimaryCondition;
|
|
51
51
|
private populateField;
|
|
52
|
-
|
|
52
|
+
/** @internal */
|
|
53
|
+
findChildrenFromPivotTable<Entity extends object>(filtered: Entity[], prop: EntityProperty<Entity>, options: Required<EntityLoaderOptions<Entity>>, orderBy?: QueryOrderMap<Entity>[], populate?: PopulateOptions<Entity>, pivotJoin?: boolean): Promise<AnyEntity[][]>;
|
|
53
54
|
private extractChildCondition;
|
|
54
55
|
private buildFields;
|
|
55
56
|
private getChildReferences;
|