@mikro-orm/core 7.0.0-dev.114 → 7.0.0-dev.115
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 +8 -8
- package/EntityManager.js +40 -60
- package/MikroORM.d.ts +1 -1
- package/MikroORM.js +2 -3
- package/drivers/DatabaseDriver.d.ts +11 -11
- package/drivers/DatabaseDriver.js +7 -8
- package/drivers/IDatabaseDriver.d.ts +10 -10
- package/entity/Collection.js +5 -5
- package/entity/EntityAssigner.js +9 -9
- package/entity/EntityFactory.js +14 -17
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +2 -2
- package/entity/EntityLoader.d.ts +3 -3
- package/entity/EntityLoader.js +17 -16
- package/entity/WrappedEntity.js +1 -1
- package/entity/defineEntity.d.ts +11 -11
- package/errors.d.ts +8 -8
- package/errors.js +14 -13
- package/hydration/ObjectHydrator.js +23 -16
- package/metadata/EntitySchema.d.ts +5 -5
- package/metadata/EntitySchema.js +23 -21
- package/metadata/MetadataDiscovery.d.ts +2 -3
- package/metadata/MetadataDiscovery.js +117 -90
- package/metadata/MetadataProvider.js +2 -0
- package/metadata/MetadataStorage.d.ts +13 -6
- package/metadata/MetadataStorage.js +64 -19
- package/metadata/MetadataValidator.d.ts +2 -2
- package/metadata/MetadataValidator.js +22 -28
- package/metadata/types.d.ts +3 -3
- package/package.json +1 -1
- package/serialization/EntitySerializer.js +2 -2
- package/serialization/EntityTransformer.js +6 -6
- package/serialization/SerializationContext.d.ts +6 -6
- package/typings.d.ts +16 -14
- package/typings.js +15 -10
- package/unit-of-work/ChangeSet.d.ts +2 -3
- package/unit-of-work/ChangeSet.js +2 -3
- package/unit-of-work/ChangeSetComputer.js +3 -3
- package/unit-of-work/ChangeSetPersister.js +14 -14
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/UnitOfWork.d.ts +3 -3
- package/unit-of-work/UnitOfWork.js +46 -45
- package/utils/AbstractSchemaGenerator.js +7 -7
- package/utils/Configuration.d.ts +0 -5
- package/utils/DataloaderUtils.js +13 -11
- package/utils/EntityComparator.d.ts +6 -6
- package/utils/EntityComparator.js +22 -24
- package/utils/QueryHelper.d.ts +5 -5
- package/utils/QueryHelper.js +7 -7
- package/utils/TransactionManager.js +1 -1
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +1 -2
- package/utils/env-vars.js +0 -1
|
@@ -2,6 +2,7 @@ import { EntityMetadata } from '../typings.js';
|
|
|
2
2
|
import { Utils } from '../utils/Utils.js';
|
|
3
3
|
import { MetadataError } from '../errors.js';
|
|
4
4
|
import { EntityHelper } from '../entity/EntityHelper.js';
|
|
5
|
+
import { EntitySchema } from './EntitySchema.js';
|
|
5
6
|
function getGlobalStorage(namespace) {
|
|
6
7
|
const key = `mikro-orm-${namespace}`;
|
|
7
8
|
globalThis[key] = globalThis[key] || {};
|
|
@@ -10,9 +11,19 @@ function getGlobalStorage(namespace) {
|
|
|
10
11
|
export class MetadataStorage {
|
|
11
12
|
static PATH_SYMBOL = Symbol('MetadataStorage.PATH_SYMBOL');
|
|
12
13
|
static metadata = getGlobalStorage('metadata');
|
|
13
|
-
metadata;
|
|
14
|
+
metadata = new Map();
|
|
15
|
+
idMap;
|
|
16
|
+
classNameMap;
|
|
17
|
+
uniqueNameMap;
|
|
14
18
|
constructor(metadata = {}) {
|
|
15
|
-
this.
|
|
19
|
+
this.idMap = {};
|
|
20
|
+
this.uniqueNameMap = {};
|
|
21
|
+
this.classNameMap = Utils.copy(metadata, false);
|
|
22
|
+
for (const meta of Object.values(this.classNameMap)) {
|
|
23
|
+
this.idMap[meta._id] = meta;
|
|
24
|
+
this.uniqueNameMap[meta.uniqueName] = meta;
|
|
25
|
+
this.metadata.set(meta.class, meta);
|
|
26
|
+
}
|
|
16
27
|
}
|
|
17
28
|
static getMetadata(entity, path) {
|
|
18
29
|
const key = entity && path ? entity + '-' + Utils.hash(path) : null;
|
|
@@ -33,40 +44,74 @@ export class MetadataStorage {
|
|
|
33
44
|
getAll() {
|
|
34
45
|
return this.metadata;
|
|
35
46
|
}
|
|
36
|
-
get(entityName, init = false
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
47
|
+
get(entityName, init = false) {
|
|
48
|
+
const exists = this.find(entityName);
|
|
49
|
+
if (exists) {
|
|
50
|
+
return exists;
|
|
40
51
|
}
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
const className = Utils.className(entityName);
|
|
53
|
+
if (!init) {
|
|
54
|
+
throw MetadataError.missingMetadata(className);
|
|
43
55
|
}
|
|
44
|
-
|
|
56
|
+
const meta = new EntityMetadata({ class: entityName, name: className });
|
|
57
|
+
this.set(entityName, meta);
|
|
58
|
+
return meta;
|
|
45
59
|
}
|
|
46
60
|
find(entityName) {
|
|
47
61
|
if (!entityName) {
|
|
48
62
|
return;
|
|
49
63
|
}
|
|
50
|
-
|
|
51
|
-
|
|
64
|
+
const meta = this.metadata.get(entityName);
|
|
65
|
+
if (meta) {
|
|
66
|
+
return meta;
|
|
67
|
+
}
|
|
68
|
+
if (entityName instanceof EntitySchema) {
|
|
69
|
+
return this.metadata.get(entityName.meta.class) ?? entityName.meta;
|
|
70
|
+
}
|
|
71
|
+
return this.classNameMap[Utils.className(entityName)];
|
|
52
72
|
}
|
|
53
|
-
has(
|
|
54
|
-
return
|
|
73
|
+
has(entityName) {
|
|
74
|
+
return this.metadata.has(entityName);
|
|
55
75
|
}
|
|
56
|
-
set(
|
|
57
|
-
|
|
76
|
+
set(entityName, meta) {
|
|
77
|
+
this.metadata.set(entityName, meta);
|
|
78
|
+
this.idMap[meta._id] = meta;
|
|
79
|
+
this.uniqueNameMap[meta.uniqueName] = meta;
|
|
80
|
+
this.classNameMap[Utils.className(entityName)] = meta;
|
|
81
|
+
return meta;
|
|
58
82
|
}
|
|
59
|
-
reset(
|
|
60
|
-
|
|
83
|
+
reset(entityName) {
|
|
84
|
+
const meta = this.find(entityName);
|
|
85
|
+
if (meta) {
|
|
86
|
+
this.metadata.delete(meta.class);
|
|
87
|
+
delete this.idMap[meta._id];
|
|
88
|
+
delete this.uniqueNameMap[meta.uniqueName];
|
|
89
|
+
delete this.classNameMap[meta.className];
|
|
90
|
+
}
|
|
61
91
|
}
|
|
62
92
|
decorate(em) {
|
|
63
|
-
|
|
93
|
+
[...this.metadata.values()]
|
|
64
94
|
.filter(meta => meta.prototype)
|
|
65
95
|
.forEach(meta => EntityHelper.decorate(meta, em));
|
|
66
96
|
}
|
|
67
97
|
*[Symbol.iterator]() {
|
|
68
|
-
for (const meta of
|
|
98
|
+
for (const meta of this.metadata.values()) {
|
|
69
99
|
yield meta;
|
|
70
100
|
}
|
|
71
101
|
}
|
|
102
|
+
getById(id) {
|
|
103
|
+
return this.idMap[id];
|
|
104
|
+
}
|
|
105
|
+
getByClassName(className, validate = true) {
|
|
106
|
+
return this.validate(this.classNameMap[className], className, validate);
|
|
107
|
+
}
|
|
108
|
+
getByUniqueName(uniqueName, validate = true) {
|
|
109
|
+
return this.validate(this.uniqueNameMap[uniqueName], uniqueName, validate);
|
|
110
|
+
}
|
|
111
|
+
validate(meta, id, validate) {
|
|
112
|
+
if (!meta && validate) {
|
|
113
|
+
throw MetadataError.missingMetadata(id);
|
|
114
|
+
}
|
|
115
|
+
return meta;
|
|
116
|
+
}
|
|
72
117
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { EntityMetadata } from '../typings.js';
|
|
1
|
+
import type { EntityMetadata, EntityName } from '../typings.js';
|
|
2
2
|
import { type MetadataDiscoveryOptions } from '../utils/Configuration.js';
|
|
3
3
|
import type { MetadataStorage } from './MetadataStorage.js';
|
|
4
4
|
/**
|
|
5
5
|
* @internal
|
|
6
6
|
*/
|
|
7
7
|
export declare class MetadataValidator {
|
|
8
|
-
validateEntityDefinition<T>(metadata: MetadataStorage, name:
|
|
8
|
+
validateEntityDefinition<T>(metadata: MetadataStorage, name: EntityName<T>, options: MetadataDiscoveryOptions): void;
|
|
9
9
|
validateDiscovered(discovered: EntityMetadata[], options: MetadataDiscoveryOptions): void;
|
|
10
10
|
private validateReference;
|
|
11
11
|
private validateBidirectional;
|
|
@@ -28,11 +28,11 @@ export class MetadataValidator {
|
|
|
28
28
|
this.validateIndexes(meta, meta.uniques ?? [], 'unique');
|
|
29
29
|
for (const prop of Utils.values(meta.properties)) {
|
|
30
30
|
if (prop.kind !== ReferenceKind.SCALAR) {
|
|
31
|
-
this.validateReference(meta, prop,
|
|
32
|
-
this.validateBidirectional(meta, prop
|
|
31
|
+
this.validateReference(meta, prop, options);
|
|
32
|
+
this.validateBidirectional(meta, prop);
|
|
33
33
|
}
|
|
34
|
-
else if (metadata.
|
|
35
|
-
throw MetadataError.propertyTargetsEntityType(meta, prop, metadata.
|
|
34
|
+
else if (metadata.getByClassName(prop.type, false)) {
|
|
35
|
+
throw MetadataError.propertyTargetsEntityType(meta, prop, metadata.getByClassName(prop.type));
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -40,17 +40,13 @@ export class MetadataValidator {
|
|
|
40
40
|
if (discovered.length === 0 && options.warnWhenNoEntities) {
|
|
41
41
|
throw MetadataError.noEntityDiscovered();
|
|
42
42
|
}
|
|
43
|
-
const duplicates = Utils.findDuplicates(discovered.map(meta => meta.className));
|
|
44
|
-
if (duplicates.length > 0 && options.checkDuplicateEntities) {
|
|
45
|
-
throw MetadataError.duplicateEntityDiscovered(duplicates);
|
|
46
|
-
}
|
|
47
43
|
const tableNames = discovered.filter(meta => !meta.abstract && meta === meta.root && (meta.tableName || meta.collection) && meta.schema !== '*');
|
|
48
44
|
const duplicateTableNames = Utils.findDuplicates(tableNames.map(meta => {
|
|
49
45
|
const tableName = meta.tableName || meta.collection;
|
|
50
46
|
return (meta.schema ? '.' + meta.schema : '') + tableName;
|
|
51
47
|
}));
|
|
52
|
-
if (duplicateTableNames.length > 0 && options.checkDuplicateTableNames
|
|
53
|
-
throw MetadataError.duplicateEntityDiscovered(duplicateTableNames
|
|
48
|
+
if (duplicateTableNames.length > 0 && options.checkDuplicateTableNames) {
|
|
49
|
+
throw MetadataError.duplicateEntityDiscovered(duplicateTableNames);
|
|
54
50
|
}
|
|
55
51
|
// validate we found at least one entity (not just abstract/base entities)
|
|
56
52
|
if (discovered.filter(meta => meta.name).length === 0 && options.warnWhenNoEntities) {
|
|
@@ -61,7 +57,7 @@ export class MetadataValidator {
|
|
|
61
57
|
.replace(/\[]$/, '') // remove array suffix
|
|
62
58
|
.replace(/\((.*)\)/, '$1'); // unwrap union types
|
|
63
59
|
const name = (p) => {
|
|
64
|
-
if (typeof p === 'function') {
|
|
60
|
+
if (typeof p === 'function' && !p.prototype) {
|
|
65
61
|
return Utils.className(p());
|
|
66
62
|
}
|
|
67
63
|
return Utils.className(p);
|
|
@@ -85,12 +81,12 @@ export class MetadataValidator {
|
|
|
85
81
|
}
|
|
86
82
|
});
|
|
87
83
|
}
|
|
88
|
-
validateReference(meta, prop,
|
|
84
|
+
validateReference(meta, prop, options) {
|
|
89
85
|
// references do have types
|
|
90
86
|
if (!prop.type) {
|
|
91
87
|
throw MetadataError.fromWrongTypeDefinition(meta, prop);
|
|
92
88
|
}
|
|
93
|
-
const targetMeta =
|
|
89
|
+
const targetMeta = prop.targetMeta;
|
|
94
90
|
// references do have type of known entity
|
|
95
91
|
if (!targetMeta) {
|
|
96
92
|
throw MetadataError.fromWrongTypeDefinition(meta, prop);
|
|
@@ -102,30 +98,27 @@ export class MetadataValidator {
|
|
|
102
98
|
throw MetadataError.nonPersistentCompositeProp(meta, prop);
|
|
103
99
|
}
|
|
104
100
|
}
|
|
105
|
-
validateBidirectional(meta, prop
|
|
101
|
+
validateBidirectional(meta, prop) {
|
|
106
102
|
if (prop.inversedBy) {
|
|
107
|
-
|
|
108
|
-
this.validateOwningSide(meta, prop, inverse, metadata);
|
|
103
|
+
this.validateOwningSide(meta, prop);
|
|
109
104
|
}
|
|
110
105
|
else if (prop.mappedBy) {
|
|
111
|
-
|
|
112
|
-
this.validateInverseSide(meta, prop, inverse, metadata);
|
|
106
|
+
this.validateInverseSide(meta, prop);
|
|
113
107
|
}
|
|
114
|
-
else {
|
|
108
|
+
else if (prop.kind === ReferenceKind.ONE_TO_MANY && !prop.mappedBy) {
|
|
115
109
|
// 1:m property has `mappedBy`
|
|
116
|
-
|
|
117
|
-
throw MetadataError.fromMissingOption(meta, prop, 'mappedBy');
|
|
118
|
-
}
|
|
110
|
+
throw MetadataError.fromMissingOption(meta, prop, 'mappedBy');
|
|
119
111
|
}
|
|
120
112
|
}
|
|
121
|
-
validateOwningSide(meta, prop
|
|
113
|
+
validateOwningSide(meta, prop) {
|
|
114
|
+
const inverse = prop.targetMeta.properties[prop.inversedBy];
|
|
122
115
|
// has correct `inversedBy` on owning side
|
|
123
116
|
if (!inverse) {
|
|
124
117
|
throw MetadataError.fromWrongReference(meta, prop, 'inversedBy');
|
|
125
118
|
}
|
|
126
|
-
const
|
|
119
|
+
const targetClass = inverse.targetMeta?.root.class;
|
|
127
120
|
// has correct `inversedBy` reference type
|
|
128
|
-
if (inverse.type !== meta.className &&
|
|
121
|
+
if (inverse.type !== meta.className && targetClass !== meta.root.class) {
|
|
129
122
|
throw MetadataError.fromWrongReference(meta, prop, 'inversedBy', inverse);
|
|
130
123
|
}
|
|
131
124
|
// inverse side is not defined as owner
|
|
@@ -133,13 +126,14 @@ export class MetadataValidator {
|
|
|
133
126
|
throw MetadataError.fromWrongOwnership(meta, prop, 'inversedBy');
|
|
134
127
|
}
|
|
135
128
|
}
|
|
136
|
-
validateInverseSide(meta, prop
|
|
129
|
+
validateInverseSide(meta, prop) {
|
|
130
|
+
const owner = prop.targetMeta.properties[prop.mappedBy];
|
|
137
131
|
// has correct `mappedBy` on inverse side
|
|
138
132
|
if (prop.mappedBy && !owner) {
|
|
139
133
|
throw MetadataError.fromWrongReference(meta, prop, 'mappedBy');
|
|
140
134
|
}
|
|
141
135
|
// has correct `mappedBy` reference type
|
|
142
|
-
if (owner.type !== meta.className &&
|
|
136
|
+
if (owner.type !== meta.className && owner.targetMeta?.root.class !== meta.root.class) {
|
|
143
137
|
throw MetadataError.fromWrongReference(meta, prop, 'mappedBy', owner);
|
|
144
138
|
}
|
|
145
139
|
// owning side is not defined as inverse
|
|
@@ -182,7 +176,7 @@ export class MetadataValidator {
|
|
|
182
176
|
return [prop.embedded ? prop.embedded.join('.') : prop.name, prop.fieldNames[0]];
|
|
183
177
|
});
|
|
184
178
|
});
|
|
185
|
-
throw MetadataError.duplicateFieldName(meta.
|
|
179
|
+
throw MetadataError.duplicateFieldName(meta.class, pairs);
|
|
186
180
|
}
|
|
187
181
|
}
|
|
188
182
|
validateVersionField(meta) {
|
package/metadata/types.d.ts
CHANGED
|
@@ -308,7 +308,7 @@ export interface PropertyOptions<Owner> {
|
|
|
308
308
|
}
|
|
309
309
|
export interface ReferenceOptions<Owner, Target> extends PropertyOptions<Owner> {
|
|
310
310
|
/** Set target entity type. */
|
|
311
|
-
entity?:
|
|
311
|
+
entity?: () => EntityName<Target>;
|
|
312
312
|
/** Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see {@doclink cascading}). */
|
|
313
313
|
cascade?: Cascade[];
|
|
314
314
|
/** Always load the relationship. Discouraged for use with to-many relations for performance reasons. */
|
|
@@ -417,7 +417,7 @@ export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner
|
|
|
417
417
|
/** Override default name for pivot table (see {@doclink naming-strategy | Naming Strategy}). */
|
|
418
418
|
pivotTable?: string;
|
|
419
419
|
/** Set pivot entity for this relation (see {@doclink collections#custom-pivot-table-entity | Custom pivot table entity}). */
|
|
420
|
-
pivotEntity?:
|
|
420
|
+
pivotEntity?: () => EntityName;
|
|
421
421
|
/** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
|
|
422
422
|
joinColumn?: string;
|
|
423
423
|
/** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is suitable for composite keys, where one property is represented by multiple columns. */
|
|
@@ -438,7 +438,7 @@ export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner
|
|
|
438
438
|
createForeignKeyConstraint?: boolean;
|
|
439
439
|
}
|
|
440
440
|
export interface EmbeddedOptions<Owner, Target> extends PropertyOptions<Owner> {
|
|
441
|
-
entity?:
|
|
441
|
+
entity?: () => EntityName<Target> | EntityName<Target>[];
|
|
442
442
|
prefix?: string | boolean;
|
|
443
443
|
prefixMode?: EmbeddedPrefixMode;
|
|
444
444
|
object?: boolean;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.115",
|
|
5
5
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -69,13 +69,13 @@ export class EntitySerializer {
|
|
|
69
69
|
if (!isVisible(meta, prop, options)) {
|
|
70
70
|
continue;
|
|
71
71
|
}
|
|
72
|
-
const cycle = root.visit(meta.
|
|
72
|
+
const cycle = root.visit(meta.class, prop);
|
|
73
73
|
if (cycle && visited) {
|
|
74
74
|
continue;
|
|
75
75
|
}
|
|
76
76
|
const val = this.processProperty(prop, entity, options);
|
|
77
77
|
if (!cycle) {
|
|
78
|
-
root.leave(meta.
|
|
78
|
+
root.leave(meta.class, prop);
|
|
79
79
|
}
|
|
80
80
|
if (options.skipNull && Utils.isPlainObject(val)) {
|
|
81
81
|
Utils.dropUndefinedProperties(val, null);
|
|
@@ -57,19 +57,19 @@ export class EntityTransformer {
|
|
|
57
57
|
if (!visible) {
|
|
58
58
|
continue;
|
|
59
59
|
}
|
|
60
|
-
const populated = root.isMarkedAsPopulated(meta.
|
|
61
|
-
const partiallyLoaded = root.isPartiallyLoaded(meta.
|
|
60
|
+
const populated = root.isMarkedAsPopulated(meta.class, prop);
|
|
61
|
+
const partiallyLoaded = root.isPartiallyLoaded(meta.class, prop);
|
|
62
62
|
const isPrimary = includePrimaryKeys && meta.properties[prop].primary;
|
|
63
63
|
if (!partiallyLoaded && !populated && !isPrimary) {
|
|
64
64
|
continue;
|
|
65
65
|
}
|
|
66
|
-
const cycle = root.visit(meta.
|
|
66
|
+
const cycle = root.visit(meta.class, prop);
|
|
67
67
|
if (cycle && visited) {
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
70
70
|
const val = EntityTransformer.processProperty(prop, entity, raw, populated);
|
|
71
71
|
if (!cycle) {
|
|
72
|
-
root.leave(meta.
|
|
72
|
+
root.leave(meta.class, prop);
|
|
73
73
|
}
|
|
74
74
|
if (isRaw(val)) {
|
|
75
75
|
throw new Error(`Trying to serialize raw SQL fragment: '${val.sql}'`);
|
|
@@ -86,7 +86,7 @@ export class EntityTransformer {
|
|
|
86
86
|
// decorated get methods
|
|
87
87
|
if (prop.getterName != null) {
|
|
88
88
|
const visible = !prop.hidden && entity[prop.getterName] instanceof Function;
|
|
89
|
-
const populated = root.isMarkedAsPopulated(meta.
|
|
89
|
+
const populated = root.isMarkedAsPopulated(meta.class, prop.name);
|
|
90
90
|
if (visible) {
|
|
91
91
|
ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.getterName, entity, raw, populated);
|
|
92
92
|
}
|
|
@@ -94,7 +94,7 @@ export class EntityTransformer {
|
|
|
94
94
|
else {
|
|
95
95
|
// decorated getters
|
|
96
96
|
const visible = !prop.hidden && typeof entity[prop.name] !== 'undefined';
|
|
97
|
-
const populated = root.isMarkedAsPopulated(meta.
|
|
97
|
+
const populated = root.isMarkedAsPopulated(meta.class, prop.name);
|
|
98
98
|
if (visible) {
|
|
99
99
|
ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.name, entity, raw, populated);
|
|
100
100
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyEntity, EntityMetadata, PopulateOptions } from '../typings.js';
|
|
1
|
+
import type { AnyEntity, EntityMetadata, EntityName, PopulateOptions } from '../typings.js';
|
|
2
2
|
import type { Configuration } from '../utils/Configuration.js';
|
|
3
3
|
/**
|
|
4
4
|
* Helper that allows to keep track of where we are currently at when serializing complex entity graph with cycles.
|
|
@@ -10,21 +10,21 @@ export declare class SerializationContext<T extends object> {
|
|
|
10
10
|
private readonly populate;
|
|
11
11
|
private readonly fields?;
|
|
12
12
|
private readonly exclude?;
|
|
13
|
-
readonly path: [
|
|
13
|
+
readonly path: [EntityName, string][];
|
|
14
14
|
readonly visited: Set<Partial<any>>;
|
|
15
15
|
private entities;
|
|
16
16
|
constructor(config: Configuration, populate?: PopulateOptions<T>[], fields?: Set<string> | undefined, exclude?: string[] | undefined);
|
|
17
17
|
/**
|
|
18
18
|
* Returns true when there is a cycle detected.
|
|
19
19
|
*/
|
|
20
|
-
visit(entityName:
|
|
21
|
-
leave
|
|
20
|
+
visit(entityName: EntityName, prop: string): boolean;
|
|
21
|
+
leave(entityName: EntityName, prop: string): void;
|
|
22
22
|
close(): void;
|
|
23
23
|
/**
|
|
24
24
|
* When initializing new context, we need to propagate it to the whole entity graph recursively.
|
|
25
25
|
*/
|
|
26
26
|
static propagate(root: SerializationContext<any>, entity: AnyEntity, isVisible: (meta: EntityMetadata, prop: string) => boolean): void;
|
|
27
|
-
isMarkedAsPopulated(entityName:
|
|
28
|
-
isPartiallyLoaded(entityName:
|
|
27
|
+
isMarkedAsPopulated(entityName: EntityName, prop: string): boolean;
|
|
28
|
+
isPartiallyLoaded(entityName: EntityName, prop: string): boolean;
|
|
29
29
|
private register;
|
|
30
30
|
}
|
package/typings.d.ts
CHANGED
|
@@ -206,10 +206,10 @@ export interface IWrappedEntityInternal<Entity extends object> extends IWrappedE
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
export type AnyEntity<T = any> = Partial<T>;
|
|
209
|
-
export type EntityClass<T> = Function & {
|
|
209
|
+
export type EntityClass<T = any> = Function & {
|
|
210
210
|
prototype: T;
|
|
211
211
|
};
|
|
212
|
-
export type EntityName<T
|
|
212
|
+
export type EntityName<T = any> = EntityClass<T> | EntitySchema<T, any> | {
|
|
213
213
|
name: string;
|
|
214
214
|
};
|
|
215
215
|
export type GetRepository<Entity extends {
|
|
@@ -326,6 +326,7 @@ export type AnyString = string & {};
|
|
|
326
326
|
export interface EntityProperty<Owner = any, Target = any> {
|
|
327
327
|
name: EntityKey<Owner>;
|
|
328
328
|
entity: () => EntityName<Owner>;
|
|
329
|
+
target: EntityClass<Target>;
|
|
329
330
|
type: keyof typeof types | AnyString;
|
|
330
331
|
runtimeType: 'number' | 'string' | 'boolean' | 'bigint' | 'Buffer' | 'Date' | 'object' | 'any' | AnyString;
|
|
331
332
|
targetMeta?: EntityMetadata<Target>;
|
|
@@ -396,7 +397,7 @@ export interface EntityProperty<Owner = any, Target = any> {
|
|
|
396
397
|
fixedOrder?: boolean;
|
|
397
398
|
fixedOrderColumn?: string;
|
|
398
399
|
pivotTable: string;
|
|
399
|
-
pivotEntity:
|
|
400
|
+
pivotEntity: EntityClass<Target>;
|
|
400
401
|
joinColumns: string[];
|
|
401
402
|
ownColumns: string[];
|
|
402
403
|
inverseJoinColumns: string[];
|
|
@@ -420,13 +421,14 @@ export declare class EntityMetadata<T = any> {
|
|
|
420
421
|
readonly _id: number;
|
|
421
422
|
readonly propertyOrder: Map<string, number>;
|
|
422
423
|
constructor(meta?: Partial<EntityMetadata>);
|
|
423
|
-
addProperty(prop: Partial<EntityProperty<T
|
|
424
|
+
addProperty(prop: Partial<EntityProperty<T>>): void;
|
|
424
425
|
removeProperty(name: string, sync?: boolean): void;
|
|
425
426
|
getPrimaryProps(flatten?: boolean): EntityProperty<T>[];
|
|
426
427
|
getPrimaryProp(): EntityProperty<T>;
|
|
427
428
|
createColumnMappingObject(): Dictionary<any>;
|
|
428
429
|
get tableName(): string;
|
|
429
430
|
set tableName(name: string);
|
|
431
|
+
get uniqueName(): string;
|
|
430
432
|
sync(initIndexes?: boolean, config?: Configuration): void;
|
|
431
433
|
private initIndexes;
|
|
432
434
|
/** @internal */
|
|
@@ -446,11 +448,11 @@ export interface EntityMetadata<T = any> {
|
|
|
446
448
|
expression?: string | ((em: any, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>, stream?: boolean) => MaybePromise<Raw | object | string>);
|
|
447
449
|
discriminatorColumn?: EntityKey<T> | AnyString;
|
|
448
450
|
discriminatorValue?: number | string;
|
|
449
|
-
discriminatorMap?: Dictionary<
|
|
451
|
+
discriminatorMap?: Dictionary<EntityClass>;
|
|
450
452
|
embeddable: boolean;
|
|
451
453
|
constructorParams?: (keyof T)[];
|
|
452
454
|
forceConstructor: boolean;
|
|
453
|
-
extends
|
|
455
|
+
extends?: EntityName<T>;
|
|
454
456
|
collection: string;
|
|
455
457
|
path: string;
|
|
456
458
|
primaryKeys: EntityKey<T>[];
|
|
@@ -714,13 +716,13 @@ export interface MigrationObject {
|
|
|
714
716
|
type EntityFromInput<T> = T extends readonly EntityName<infer U>[] ? U : T extends EntityName<infer U> ? U : never;
|
|
715
717
|
type FilterDefResolved<T extends object = any> = {
|
|
716
718
|
name: string;
|
|
717
|
-
cond: FilterQuery<T> | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, entityName?:
|
|
719
|
+
cond: FilterQuery<T> | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, entityName?: string) => MaybePromise<FilterQuery<T>>);
|
|
718
720
|
default?: boolean;
|
|
719
721
|
entity?: EntityName<T> | EntityName<T>[];
|
|
720
722
|
args?: boolean;
|
|
721
723
|
strict?: boolean;
|
|
722
724
|
};
|
|
723
|
-
export type FilterDef<T extends EntityName
|
|
725
|
+
export type FilterDef<T extends EntityName | readonly EntityName[] = any> = FilterDefResolved<EntityFromInput<T>> & {
|
|
724
726
|
entity?: T;
|
|
725
727
|
};
|
|
726
728
|
export type Populate<T, P extends string = never> = readonly AutoPath<T, P, `${PopulatePath}`>[] | false;
|
|
@@ -813,12 +815,12 @@ export interface Highlighter {
|
|
|
813
815
|
highlight(text: string): string;
|
|
814
816
|
}
|
|
815
817
|
export interface IMetadataStorage {
|
|
816
|
-
getAll():
|
|
817
|
-
get<T = any>(entity:
|
|
818
|
-
find<T = any>(entity:
|
|
819
|
-
has(entity:
|
|
820
|
-
set(entity:
|
|
821
|
-
reset(entity:
|
|
818
|
+
getAll(): Map<EntityName, EntityMetadata>;
|
|
819
|
+
get<T = any>(entity: EntityName<T>, init?: boolean, validate?: boolean): EntityMetadata<T>;
|
|
820
|
+
find<T = any>(entity: EntityName<T>): EntityMetadata<T> | undefined;
|
|
821
|
+
has<T>(entity: EntityName<T>): boolean;
|
|
822
|
+
set<T>(entity: EntityName<T>, meta: EntityMetadata): EntityMetadata;
|
|
823
|
+
reset<T>(entity: EntityName<T>): void;
|
|
822
824
|
}
|
|
823
825
|
export interface IHydrator {
|
|
824
826
|
/**
|
package/typings.js
CHANGED
|
@@ -25,22 +25,20 @@ 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 */
|
|
44
42
|
if (sync) {
|
|
45
43
|
this.sync();
|
|
46
44
|
}
|
|
@@ -74,6 +72,9 @@ export class EntityMetadata {
|
|
|
74
72
|
set tableName(name) {
|
|
75
73
|
this.collection = name;
|
|
76
74
|
}
|
|
75
|
+
get uniqueName() {
|
|
76
|
+
return this.tableName + '_' + this._id;
|
|
77
|
+
}
|
|
77
78
|
sync(initIndexes = false, config) {
|
|
78
79
|
this.root ??= this;
|
|
79
80
|
const props = Object.values(this.properties).sort((a, b) => this.propertyOrder.get(a.name) - this.propertyOrder.get(b.name));
|
|
@@ -100,7 +101,7 @@ export class EntityMetadata {
|
|
|
100
101
|
return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
|
|
101
102
|
});
|
|
102
103
|
this.selfReferencing = this.relations.some(prop => {
|
|
103
|
-
return
|
|
104
|
+
return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
|
|
104
105
|
});
|
|
105
106
|
this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
|
|
106
107
|
this.virtual = !!this.expression;
|
|
@@ -191,4 +192,8 @@ export class EntityMetadata {
|
|
|
191
192
|
clone() {
|
|
192
193
|
return this;
|
|
193
194
|
}
|
|
195
|
+
/** @ignore */
|
|
196
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
197
|
+
return `[${this.constructor.name}<${this.className}>]`;
|
|
198
|
+
}
|
|
194
199
|
}
|
|
@@ -11,9 +11,8 @@ export declare class ChangeSet<T extends object> {
|
|
|
11
11
|
getSerializedPrimaryKey(): string | null;
|
|
12
12
|
}
|
|
13
13
|
export interface ChangeSet<T> {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
collection: string;
|
|
14
|
+
meta: EntityMetadata<T>;
|
|
15
|
+
rootMeta: EntityMetadata<T>;
|
|
17
16
|
schema?: string;
|
|
18
17
|
type: ChangeSetType;
|
|
19
18
|
entity: T;
|
|
@@ -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) {
|
|
@@ -19,7 +19,7 @@ export class ChangeSetComputer {
|
|
|
19
19
|
this.comparator = this.config.getComparator(this.metadata);
|
|
20
20
|
}
|
|
21
21
|
computeChangeSet(entity) {
|
|
22
|
-
const meta = this.metadata.get(entity.constructor
|
|
22
|
+
const meta = this.metadata.get(entity.constructor);
|
|
23
23
|
if (meta.readonly) {
|
|
24
24
|
return null;
|
|
25
25
|
}
|
|
@@ -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
|
}
|