@mikro-orm/core 7.0.0-dev.113 → 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 +47 -69
- package/MikroORM.d.ts +1 -1
- package/MikroORM.js +2 -3
- package/drivers/DatabaseDriver.d.ts +11 -11
- package/drivers/DatabaseDriver.js +8 -9
- package/drivers/IDatabaseDriver.d.ts +12 -12
- package/entity/Collection.js +7 -6
- 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 +22 -35
- package/entity/WrappedEntity.js +1 -1
- package/entity/defineEntity.d.ts +11 -11
- package/entity/validators.js +2 -2
- package/errors.d.ts +8 -8
- package/errors.js +14 -13
- package/hydration/ObjectHydrator.js +25 -18
- package/metadata/EntitySchema.d.ts +5 -5
- package/metadata/EntitySchema.js +23 -21
- package/metadata/MetadataDiscovery.d.ts +2 -3
- package/metadata/MetadataDiscovery.js +119 -92
- 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/platforms/Platform.js +2 -2
- package/serialization/EntitySerializer.js +2 -2
- package/serialization/EntityTransformer.js +6 -6
- package/serialization/SerializationContext.d.ts +6 -6
- package/typings.d.ts +19 -17
- 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/Cursor.js +3 -3
- package/utils/DataloaderUtils.js +13 -11
- package/utils/EntityComparator.d.ts +6 -6
- package/utils/EntityComparator.js +30 -27
- package/utils/QueryHelper.d.ts +6 -6
- package/utils/QueryHelper.js +18 -17
- package/utils/RawQueryFragment.d.ts +11 -12
- package/utils/RawQueryFragment.js +28 -55
- package/utils/TransactionManager.js +1 -1
- package/utils/Utils.d.ts +3 -1
- package/utils/Utils.js +10 -2
- package/utils/clone.js +7 -21
- package/utils/env-vars.js +0 -1
- package/utils/upsert-utils.d.ts +4 -4
|
@@ -7,7 +7,8 @@ import { Cascade, ReferenceKind } from '../enums.js';
|
|
|
7
7
|
import { MetadataError } from '../errors.js';
|
|
8
8
|
import { t, Type } from '../types/index.js';
|
|
9
9
|
import { colors } from '../logging/colors.js';
|
|
10
|
-
import { raw,
|
|
10
|
+
import { raw, Raw } from '../utils/RawQueryFragment.js';
|
|
11
|
+
import { BaseEntity } from '../entity/BaseEntity.js';
|
|
11
12
|
export class MetadataDiscovery {
|
|
12
13
|
metadata;
|
|
13
14
|
platform;
|
|
@@ -62,9 +63,6 @@ export class MetadataDiscovery {
|
|
|
62
63
|
void this.config.get('discovery').afterDiscovered?.(storage, this.platform);
|
|
63
64
|
return storage;
|
|
64
65
|
}
|
|
65
|
-
validateDiscovered(metadata) {
|
|
66
|
-
return this.validator.validateDiscovered(metadata, this.config.get('discovery'));
|
|
67
|
-
}
|
|
68
66
|
mapDiscoveredEntities() {
|
|
69
67
|
const discovered = new MetadataStorage();
|
|
70
68
|
this.discovered
|
|
@@ -72,8 +70,11 @@ export class MetadataDiscovery {
|
|
|
72
70
|
.sort((a, b) => b.root.name.localeCompare(a.root.name))
|
|
73
71
|
.forEach(meta => {
|
|
74
72
|
this.platform.validateMetadata(meta);
|
|
75
|
-
discovered.set(meta.
|
|
73
|
+
discovered.set(meta.class, meta);
|
|
76
74
|
});
|
|
75
|
+
for (const meta of discovered) {
|
|
76
|
+
meta.root = discovered.get(meta.root.class);
|
|
77
|
+
}
|
|
77
78
|
return discovered;
|
|
78
79
|
}
|
|
79
80
|
initAccessors(meta) {
|
|
@@ -118,34 +119,40 @@ export class MetadataDiscovery {
|
|
|
118
119
|
filtered.sort((a, b) => !a.embeddable === !b.embeddable ? 0 : (a.embeddable ? 1 : -1));
|
|
119
120
|
filtered.forEach(meta => this.initSingleTableInheritance(meta, filtered));
|
|
120
121
|
filtered.forEach(meta => this.defineBaseEntityProperties(meta));
|
|
121
|
-
filtered.forEach(meta =>
|
|
122
|
+
filtered.forEach(meta => {
|
|
123
|
+
const newMeta = EntitySchema.fromMetadata(meta).init().meta;
|
|
124
|
+
return this.metadata.set(newMeta.class, newMeta);
|
|
125
|
+
});
|
|
122
126
|
filtered.forEach(meta => this.initAutoincrement(meta));
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
const forEachProp = (cb) => {
|
|
128
|
+
filtered.forEach(meta => Object.values(meta.properties).forEach(prop => cb(meta, prop)));
|
|
129
|
+
};
|
|
130
|
+
forEachProp((m, p) => this.initFactoryField(m, p));
|
|
131
|
+
forEachProp((_m, p) => this.initRelation(p));
|
|
132
|
+
forEachProp((m, p) => this.initEmbeddables(m, p));
|
|
133
|
+
forEachProp((_m, p) => this.initFieldName(p));
|
|
134
|
+
forEachProp((m, p) => this.initVersionProperty(m, p));
|
|
135
|
+
forEachProp((m, p) => this.initCustomType(m, p));
|
|
136
|
+
forEachProp((m, p) => this.initGeneratedColumn(m, p));
|
|
129
137
|
filtered.forEach(meta => this.initAutoincrement(meta)); // once again after we init custom types
|
|
130
138
|
filtered.forEach(meta => this.initCheckConstraints(meta));
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initIndexes(meta, prop)));
|
|
139
|
+
forEachProp((_m, p) => {
|
|
140
|
+
this.initDefaultValue(p);
|
|
141
|
+
this.inferTypeFromDefault(p);
|
|
142
|
+
this.initRelation(p);
|
|
143
|
+
this.initColumnType(p);
|
|
144
|
+
});
|
|
145
|
+
forEachProp((m, p) => this.initIndexes(m, p));
|
|
139
146
|
filtered.forEach(meta => this.autoWireBidirectionalProperties(meta));
|
|
140
|
-
filtered.forEach(meta => this.findReferencingProperties(meta, filtered));
|
|
141
147
|
for (const meta of filtered) {
|
|
142
148
|
discovered.push(...this.processEntity(meta));
|
|
143
149
|
}
|
|
144
150
|
discovered.forEach(meta => meta.sync(true));
|
|
145
151
|
this.metadataProvider.combineCache();
|
|
146
152
|
return discovered.map(meta => {
|
|
147
|
-
meta = this.metadata.get(meta.
|
|
153
|
+
meta = this.metadata.get(meta.class);
|
|
148
154
|
meta.sync(true);
|
|
155
|
+
this.findReferencingProperties(meta, filtered);
|
|
149
156
|
return meta;
|
|
150
157
|
});
|
|
151
158
|
}
|
|
@@ -175,17 +182,22 @@ export class MetadataDiscovery {
|
|
|
175
182
|
.replace(/\((.*)\)/, '$1'); // unwrap union types
|
|
176
183
|
const missing = [];
|
|
177
184
|
this.discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
|
|
178
|
-
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
185
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity) {
|
|
186
|
+
const pivotEntity = prop.pivotEntity;
|
|
187
|
+
const target = typeof pivotEntity === 'function' && !pivotEntity.prototype
|
|
188
|
+
? pivotEntity()
|
|
189
|
+
: pivotEntity;
|
|
190
|
+
if (!this.discovered.find(m => m.className === Utils.className(target))) {
|
|
191
|
+
missing.push(target);
|
|
192
|
+
}
|
|
183
193
|
}
|
|
184
|
-
if (prop.kind !== ReferenceKind.SCALAR
|
|
185
|
-
const target = typeof prop.entity === 'function'
|
|
194
|
+
if (prop.kind !== ReferenceKind.SCALAR) {
|
|
195
|
+
const target = typeof prop.entity === 'function' && !prop.entity.prototype
|
|
186
196
|
? prop.entity()
|
|
187
197
|
: prop.type;
|
|
188
|
-
|
|
198
|
+
if (!unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
|
|
199
|
+
missing.push(...Utils.asArray(target));
|
|
200
|
+
}
|
|
189
201
|
}
|
|
190
202
|
}));
|
|
191
203
|
if (missing.length > 0) {
|
|
@@ -195,7 +207,7 @@ export class MetadataDiscovery {
|
|
|
195
207
|
tryDiscoverTargets(targets) {
|
|
196
208
|
for (const target of targets) {
|
|
197
209
|
const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
|
|
198
|
-
if (isDiscoverable && target.name && !this.metadata.has(target
|
|
210
|
+
if (isDiscoverable && target.name && !this.metadata.has(target)) {
|
|
199
211
|
this.discoverReferences([target], false);
|
|
200
212
|
this.discoverMissingTargets();
|
|
201
213
|
}
|
|
@@ -209,16 +221,16 @@ export class MetadataDiscovery {
|
|
|
209
221
|
}
|
|
210
222
|
const schema = this.getSchema(entity);
|
|
211
223
|
const meta = schema.init().meta;
|
|
212
|
-
this.metadata.set(meta.
|
|
224
|
+
this.metadata.set(meta.class, meta);
|
|
213
225
|
found.push(schema);
|
|
214
226
|
}
|
|
215
227
|
// discover parents (base entities) automatically
|
|
216
228
|
for (const meta of this.metadata) {
|
|
217
229
|
let parent = meta.extends;
|
|
218
|
-
if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.
|
|
230
|
+
if (parent instanceof EntitySchema && !this.metadata.has(parent.init().meta.class)) {
|
|
219
231
|
this.discoverReferences([parent], false);
|
|
220
232
|
}
|
|
221
|
-
if (typeof parent === 'function' && parent.name && !this.metadata.has(parent
|
|
233
|
+
if (typeof parent === 'function' && parent.name && !this.metadata.has(parent)) {
|
|
222
234
|
this.discoverReferences([parent], false);
|
|
223
235
|
}
|
|
224
236
|
/* v8 ignore next */
|
|
@@ -226,7 +238,7 @@ export class MetadataDiscovery {
|
|
|
226
238
|
continue;
|
|
227
239
|
}
|
|
228
240
|
parent = Object.getPrototypeOf(meta.class);
|
|
229
|
-
if (parent.name !== '' && !this.metadata.has(parent
|
|
241
|
+
if (parent.name !== '' && !this.metadata.has(parent) && parent !== BaseEntity) {
|
|
230
242
|
this.discoverReferences([parent], false);
|
|
231
243
|
}
|
|
232
244
|
}
|
|
@@ -235,14 +247,14 @@ export class MetadataDiscovery {
|
|
|
235
247
|
}
|
|
236
248
|
this.discoverMissingTargets();
|
|
237
249
|
if (validate) {
|
|
238
|
-
this.validateDiscovered(this.discovered);
|
|
250
|
+
this.validator.validateDiscovered(this.discovered, this.config.get('discovery'));
|
|
239
251
|
}
|
|
240
252
|
return this.discovered.filter(meta => found.find(m => m.name === meta.className));
|
|
241
253
|
}
|
|
242
|
-
reset(
|
|
243
|
-
const exists = this.discovered.findIndex(m => m.className === className);
|
|
254
|
+
reset(entityName) {
|
|
255
|
+
const exists = this.discovered.findIndex(m => m.class === entityName || m.className === Utils.className(entityName));
|
|
244
256
|
if (exists !== -1) {
|
|
245
|
-
this.metadata.reset(this.discovered[exists].
|
|
257
|
+
this.metadata.reset(this.discovered[exists].class);
|
|
246
258
|
this.discovered.splice(exists, 1);
|
|
247
259
|
}
|
|
248
260
|
}
|
|
@@ -258,17 +270,17 @@ export class MetadataDiscovery {
|
|
|
258
270
|
if (path) {
|
|
259
271
|
const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
|
|
260
272
|
meta.path = path;
|
|
261
|
-
this.metadata.set(entity
|
|
273
|
+
this.metadata.set(entity, meta);
|
|
262
274
|
}
|
|
263
|
-
const exists = this.metadata.has(entity
|
|
264
|
-
const meta = this.metadata.get(entity
|
|
275
|
+
const exists = this.metadata.has(entity);
|
|
276
|
+
const meta = this.metadata.get(entity, true);
|
|
265
277
|
meta.abstract ??= !(exists && meta.name);
|
|
266
278
|
const schema = EntitySchema.fromMetadata(meta);
|
|
267
279
|
schema.setClass(entity);
|
|
268
280
|
return schema;
|
|
269
281
|
}
|
|
270
282
|
getRootEntity(meta) {
|
|
271
|
-
const base = meta.extends && this.metadata.find(
|
|
283
|
+
const base = meta.extends && this.metadata.find(meta.extends);
|
|
272
284
|
if (!base || base === meta) { // make sure we do not fall into infinite loop
|
|
273
285
|
return meta;
|
|
274
286
|
}
|
|
@@ -368,7 +380,7 @@ export class MetadataDiscovery {
|
|
|
368
380
|
}
|
|
369
381
|
}
|
|
370
382
|
initManyToOneFieldName(prop, name) {
|
|
371
|
-
const meta2 =
|
|
383
|
+
const meta2 = prop.targetMeta;
|
|
372
384
|
const ret = [];
|
|
373
385
|
for (const primaryKey of meta2.primaryKeys) {
|
|
374
386
|
this.initFieldName(meta2.properties[primaryKey]);
|
|
@@ -379,11 +391,11 @@ export class MetadataDiscovery {
|
|
|
379
391
|
return ret;
|
|
380
392
|
}
|
|
381
393
|
initManyToManyFieldName(prop, name) {
|
|
382
|
-
const meta2 =
|
|
394
|
+
const meta2 = prop.targetMeta;
|
|
383
395
|
return meta2.primaryKeys.map(() => this.namingStrategy.propertyToColumnName(name));
|
|
384
396
|
}
|
|
385
397
|
initManyToManyFields(meta, prop) {
|
|
386
|
-
const meta2 =
|
|
398
|
+
const meta2 = prop.targetMeta;
|
|
387
399
|
Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
|
|
388
400
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
389
401
|
const props = Object.values(pivotMeta?.properties ?? {});
|
|
@@ -410,7 +422,7 @@ export class MetadataDiscovery {
|
|
|
410
422
|
const prop2 = meta2.properties[prop.mappedBy];
|
|
411
423
|
this.initManyToManyFields(meta2, prop2);
|
|
412
424
|
prop.pivotTable = prop2.pivotTable;
|
|
413
|
-
prop.pivotEntity = prop2.pivotEntity
|
|
425
|
+
prop.pivotEntity = prop2.pivotEntity;
|
|
414
426
|
prop.fixedOrder = prop2.fixedOrder;
|
|
415
427
|
prop.fixedOrderColumn = prop2.fixedOrderColumn;
|
|
416
428
|
prop.joinColumns = prop2.inverseJoinColumns;
|
|
@@ -421,7 +433,7 @@ export class MetadataDiscovery {
|
|
|
421
433
|
prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className);
|
|
422
434
|
}
|
|
423
435
|
initManyToOneFields(prop) {
|
|
424
|
-
const meta2 =
|
|
436
|
+
const meta2 = prop.targetMeta;
|
|
425
437
|
const fieldNames = Utils.flatten(meta2.primaryKeys.map(primaryKey => meta2.properties[primaryKey].fieldNames));
|
|
426
438
|
Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
|
|
427
439
|
if (!prop.joinColumns) {
|
|
@@ -432,7 +444,7 @@ export class MetadataDiscovery {
|
|
|
432
444
|
}
|
|
433
445
|
}
|
|
434
446
|
initOneToManyFields(prop) {
|
|
435
|
-
const meta2 =
|
|
447
|
+
const meta2 = prop.targetMeta;
|
|
436
448
|
if (!prop.joinColumns) {
|
|
437
449
|
prop.joinColumns = [this.namingStrategy.joinColumnName(prop.name)];
|
|
438
450
|
}
|
|
@@ -450,7 +462,7 @@ export class MetadataDiscovery {
|
|
|
450
462
|
pks[0].deleteRule ??= 'cascade';
|
|
451
463
|
}
|
|
452
464
|
meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
|
|
453
|
-
this.validator.validateEntityDefinition(this.metadata, meta.
|
|
465
|
+
this.validator.validateEntityDefinition(this.metadata, meta.class, this.config.get('discovery'));
|
|
454
466
|
for (const prop of Object.values(meta.properties)) {
|
|
455
467
|
this.initNullability(prop);
|
|
456
468
|
this.applyNamingStrategy(meta, prop);
|
|
@@ -470,7 +482,14 @@ export class MetadataDiscovery {
|
|
|
470
482
|
if (this.platform.usesPivotTable()) {
|
|
471
483
|
return Object.values(meta.properties)
|
|
472
484
|
.filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
|
|
473
|
-
.map(prop =>
|
|
485
|
+
.map(prop => {
|
|
486
|
+
const pivotMeta = this.definePivotTableEntity(meta, prop);
|
|
487
|
+
prop.pivotEntity = pivotMeta.class;
|
|
488
|
+
if (prop.inversedBy) {
|
|
489
|
+
prop.targetMeta.properties[prop.inversedBy].pivotEntity = pivotMeta.class;
|
|
490
|
+
}
|
|
491
|
+
return pivotMeta;
|
|
492
|
+
});
|
|
474
493
|
}
|
|
475
494
|
return [];
|
|
476
495
|
}
|
|
@@ -487,8 +506,11 @@ export class MetadataDiscovery {
|
|
|
487
506
|
['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
|
|
488
507
|
const value = prop[type];
|
|
489
508
|
if (value instanceof Function) {
|
|
490
|
-
const meta2 = this.metadata.get(prop.
|
|
509
|
+
const meta2 = prop.targetMeta ?? this.metadata.get(prop.target);
|
|
491
510
|
prop[type] = value(meta2.properties)?.name;
|
|
511
|
+
if (type === 'pivotEntity' && value) {
|
|
512
|
+
prop[type] = value(meta2.properties);
|
|
513
|
+
}
|
|
492
514
|
if (prop[type] == null) {
|
|
493
515
|
throw MetadataError.fromWrongReference(meta, prop, type);
|
|
494
516
|
}
|
|
@@ -504,9 +526,9 @@ export class MetadataDiscovery {
|
|
|
504
526
|
}
|
|
505
527
|
else if (fks.length >= 2) {
|
|
506
528
|
[first, second] = fks;
|
|
507
|
-
/* v8 ignore next */
|
|
508
529
|
}
|
|
509
530
|
else {
|
|
531
|
+
/* v8 ignore next */
|
|
510
532
|
return [];
|
|
511
533
|
}
|
|
512
534
|
// wrong FK order, first FK needs to point to the owning side
|
|
@@ -520,7 +542,9 @@ export class MetadataDiscovery {
|
|
|
520
542
|
return [first, second];
|
|
521
543
|
}
|
|
522
544
|
definePivotTableEntity(meta, prop) {
|
|
523
|
-
const pivotMeta =
|
|
545
|
+
const pivotMeta = prop.pivotEntity
|
|
546
|
+
? this.metadata.find(prop.pivotEntity)
|
|
547
|
+
: this.metadata.getByClassName(prop.pivotTable, false);
|
|
524
548
|
// ensure inverse side exists so we can join it when populating via pivot tables
|
|
525
549
|
if (!prop.inversedBy && prop.targetMeta) {
|
|
526
550
|
const inverseName = `${meta.className}_${prop.name}__inverse`;
|
|
@@ -529,6 +553,8 @@ export class MetadataDiscovery {
|
|
|
529
553
|
name: inverseName,
|
|
530
554
|
kind: ReferenceKind.MANY_TO_MANY,
|
|
531
555
|
type: meta.className,
|
|
556
|
+
target: meta.class,
|
|
557
|
+
targetMeta: meta,
|
|
532
558
|
mappedBy: prop.name,
|
|
533
559
|
pivotEntity: prop.pivotEntity,
|
|
534
560
|
pivotTable: prop.pivotTable,
|
|
@@ -537,55 +563,51 @@ export class MetadataDiscovery {
|
|
|
537
563
|
};
|
|
538
564
|
this.applyNamingStrategy(prop.targetMeta, inverseProp);
|
|
539
565
|
this.initCustomType(prop.targetMeta, inverseProp);
|
|
540
|
-
this.initRelation(inverseProp);
|
|
541
566
|
prop.targetMeta.properties[inverseName] = inverseProp;
|
|
542
567
|
}
|
|
543
568
|
if (pivotMeta) {
|
|
569
|
+
prop.pivotEntity = pivotMeta.class;
|
|
544
570
|
this.ensureCorrectFKOrderInPivotEntity(pivotMeta, prop);
|
|
545
571
|
return pivotMeta;
|
|
546
572
|
}
|
|
547
|
-
const exists = this.metadata.find(prop.pivotTable);
|
|
548
|
-
if (exists) {
|
|
549
|
-
prop.pivotEntity = exists.className;
|
|
550
|
-
return exists;
|
|
551
|
-
}
|
|
552
573
|
let tableName = prop.pivotTable;
|
|
553
574
|
let schemaName;
|
|
554
575
|
if (prop.pivotTable.includes('.')) {
|
|
555
576
|
[schemaName, tableName] = prop.pivotTable.split('.');
|
|
556
577
|
}
|
|
557
578
|
schemaName ??= meta.schema;
|
|
558
|
-
const
|
|
559
|
-
const
|
|
579
|
+
const targetMeta = prop.targetMeta;
|
|
580
|
+
const targetType = targetMeta.className;
|
|
581
|
+
const pivotMeta2 = new EntityMetadata({
|
|
560
582
|
name: prop.pivotTable,
|
|
561
583
|
className: prop.pivotTable,
|
|
562
584
|
collection: tableName,
|
|
563
585
|
schema: schemaName,
|
|
564
586
|
pivotTable: true,
|
|
565
587
|
});
|
|
566
|
-
prop.pivotEntity =
|
|
588
|
+
prop.pivotEntity = pivotMeta2.class;
|
|
567
589
|
if (prop.fixedOrder) {
|
|
568
|
-
const primaryProp = this.defineFixedOrderProperty(prop,
|
|
569
|
-
|
|
590
|
+
const primaryProp = this.defineFixedOrderProperty(prop, targetMeta);
|
|
591
|
+
pivotMeta2.properties[primaryProp.name] = primaryProp;
|
|
570
592
|
}
|
|
571
593
|
else {
|
|
572
|
-
|
|
594
|
+
pivotMeta2.compositePK = true;
|
|
573
595
|
}
|
|
574
596
|
// handle self-referenced m:n with same default field names
|
|
575
597
|
if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
|
|
576
598
|
prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_1', name, meta.compositePK));
|
|
577
599
|
prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_2', name, meta.compositePK));
|
|
578
600
|
if (prop.inversedBy) {
|
|
579
|
-
const prop2 =
|
|
601
|
+
const prop2 = targetMeta.properties[prop.inversedBy];
|
|
580
602
|
prop2.inverseJoinColumns = prop.joinColumns;
|
|
581
603
|
prop2.joinColumns = prop.inverseJoinColumns;
|
|
582
604
|
}
|
|
583
605
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
return this.metadata.set(
|
|
606
|
+
pivotMeta2.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.class, targetType + '_inverse', true, meta.className === targetType);
|
|
607
|
+
pivotMeta2.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetMeta.class, meta.name + '_owner', false, meta.className === targetType);
|
|
608
|
+
return this.metadata.set(pivotMeta2.class, EntitySchema.fromMetadata(pivotMeta2).init().meta);
|
|
587
609
|
}
|
|
588
|
-
defineFixedOrderProperty(prop,
|
|
610
|
+
defineFixedOrderProperty(prop, targetMeta) {
|
|
589
611
|
const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
|
|
590
612
|
const primaryProp = {
|
|
591
613
|
name: pk,
|
|
@@ -599,7 +621,7 @@ export class MetadataDiscovery {
|
|
|
599
621
|
this.initColumnType(primaryProp);
|
|
600
622
|
prop.fixedOrderColumn = pk;
|
|
601
623
|
if (prop.inversedBy) {
|
|
602
|
-
const prop2 =
|
|
624
|
+
const prop2 = targetMeta.properties[prop.inversedBy];
|
|
603
625
|
prop2.fixedOrder = true;
|
|
604
626
|
prop2.fixedOrderColumn = pk;
|
|
605
627
|
}
|
|
@@ -608,7 +630,8 @@ export class MetadataDiscovery {
|
|
|
608
630
|
definePivotProperty(prop, name, type, inverse, owner, selfReferencing) {
|
|
609
631
|
const ret = {
|
|
610
632
|
name,
|
|
611
|
-
type,
|
|
633
|
+
type: Utils.className(type),
|
|
634
|
+
target: type,
|
|
612
635
|
kind: ReferenceKind.MANY_TO_ONE,
|
|
613
636
|
cascade: [Cascade.ALL],
|
|
614
637
|
fixedOrder: prop.fixedOrder,
|
|
@@ -666,7 +689,7 @@ export class MetadataDiscovery {
|
|
|
666
689
|
Object.values(meta.properties)
|
|
667
690
|
.filter(prop => prop.kind !== ReferenceKind.SCALAR && !prop.owner && prop.mappedBy)
|
|
668
691
|
.forEach(prop => {
|
|
669
|
-
const meta2 =
|
|
692
|
+
const meta2 = prop.targetMeta;
|
|
670
693
|
const prop2 = meta2.properties[prop.mappedBy];
|
|
671
694
|
if (prop2 && !prop2.inversedBy) {
|
|
672
695
|
prop2.inversedBy = prop.name;
|
|
@@ -674,7 +697,7 @@ export class MetadataDiscovery {
|
|
|
674
697
|
});
|
|
675
698
|
}
|
|
676
699
|
defineBaseEntityProperties(meta) {
|
|
677
|
-
const base = meta.extends && this.metadata.get(
|
|
700
|
+
const base = meta.extends && this.metadata.get(meta.extends);
|
|
678
701
|
if (!base || base === meta) { // make sure we do not fall into infinite loop
|
|
679
702
|
return 0;
|
|
680
703
|
}
|
|
@@ -867,7 +890,7 @@ export class MetadataDiscovery {
|
|
|
867
890
|
}
|
|
868
891
|
initSingleTableInheritance(meta, metadata) {
|
|
869
892
|
if (meta.root !== meta && !meta.__processed) {
|
|
870
|
-
meta.root = metadata.find(m => m.
|
|
893
|
+
meta.root = metadata.find(m => m.class === meta.root.class);
|
|
871
894
|
meta.root.__processed = true;
|
|
872
895
|
}
|
|
873
896
|
else {
|
|
@@ -876,17 +899,23 @@ export class MetadataDiscovery {
|
|
|
876
899
|
if (!meta.root.discriminatorColumn) {
|
|
877
900
|
return;
|
|
878
901
|
}
|
|
879
|
-
if (
|
|
902
|
+
if (meta.root.discriminatorMap) {
|
|
903
|
+
const map = meta.root.discriminatorMap;
|
|
904
|
+
Object.keys(map)
|
|
905
|
+
.filter(key => typeof map[key] === 'string')
|
|
906
|
+
.forEach(key => map[key] = this.metadata.getByClassName(map[key]).class);
|
|
907
|
+
}
|
|
908
|
+
else {
|
|
880
909
|
meta.root.discriminatorMap = {};
|
|
881
910
|
const children = metadata
|
|
882
|
-
.filter(m => m.root.
|
|
911
|
+
.filter(m => m.root.class === meta.root.class && !m.abstract)
|
|
883
912
|
.sort((a, b) => a.className.localeCompare(b.className));
|
|
884
913
|
for (const m of children) {
|
|
885
914
|
const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
|
|
886
|
-
meta.root.discriminatorMap[name] = m.
|
|
915
|
+
meta.root.discriminatorMap[name] = m.class;
|
|
887
916
|
}
|
|
888
917
|
}
|
|
889
|
-
meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([,
|
|
918
|
+
meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, cls]) => cls === meta.class)?.[0];
|
|
890
919
|
if (!meta.root.properties[meta.root.discriminatorColumn]) {
|
|
891
920
|
this.createDiscriminatorProperty(meta.root);
|
|
892
921
|
}
|
|
@@ -995,9 +1024,6 @@ export class MetadataDiscovery {
|
|
|
995
1024
|
return '1';
|
|
996
1025
|
}
|
|
997
1026
|
inferDefaultValue(meta, prop) {
|
|
998
|
-
if (!meta.class) {
|
|
999
|
-
return;
|
|
1000
|
-
}
|
|
1001
1027
|
try {
|
|
1002
1028
|
// try to create two entity instances to detect the value is stable
|
|
1003
1029
|
const now = Date.now();
|
|
@@ -1025,7 +1051,7 @@ export class MetadataDiscovery {
|
|
|
1025
1051
|
return;
|
|
1026
1052
|
}
|
|
1027
1053
|
let val = prop.default;
|
|
1028
|
-
const raw =
|
|
1054
|
+
const raw = Raw.getKnownFragment(val);
|
|
1029
1055
|
if (raw) {
|
|
1030
1056
|
prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
|
|
1031
1057
|
return;
|
|
@@ -1153,9 +1179,9 @@ export class MetadataDiscovery {
|
|
|
1153
1179
|
if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
|
|
1154
1180
|
prop.type = prop.customType.name;
|
|
1155
1181
|
}
|
|
1156
|
-
if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) &&
|
|
1182
|
+
if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && prop.targetMeta.compositePK) {
|
|
1157
1183
|
prop.customTypes = [];
|
|
1158
|
-
for (const pk of
|
|
1184
|
+
for (const pk of prop.targetMeta.getPrimaryProps()) {
|
|
1159
1185
|
if (pk.customType) {
|
|
1160
1186
|
prop.customTypes.push(pk.customType);
|
|
1161
1187
|
prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
|
|
@@ -1185,7 +1211,8 @@ export class MetadataDiscovery {
|
|
|
1185
1211
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
1186
1212
|
return;
|
|
1187
1213
|
}
|
|
1188
|
-
|
|
1214
|
+
// when the target is a polymorphic embedded entity, `prop.target` is an array of classes, we need to get the metadata by the type name instead
|
|
1215
|
+
const meta2 = this.metadata.find(prop.target) ?? this.metadata.getByClassName(prop.type);
|
|
1189
1216
|
prop.referencedPKs = meta2.primaryKeys;
|
|
1190
1217
|
prop.targetMeta = meta2;
|
|
1191
1218
|
if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
|
|
@@ -1194,7 +1221,7 @@ export class MetadataDiscovery {
|
|
|
1194
1221
|
}
|
|
1195
1222
|
initColumnType(prop) {
|
|
1196
1223
|
this.initUnsigned(prop);
|
|
1197
|
-
|
|
1224
|
+
prop.targetMeta?.getPrimaryProps().map(pk => {
|
|
1198
1225
|
prop.length ??= pk.length;
|
|
1199
1226
|
prop.precision ??= pk.precision;
|
|
1200
1227
|
prop.scale ??= pk.scale;
|
|
@@ -1211,7 +1238,6 @@ export class MetadataDiscovery {
|
|
|
1211
1238
|
const mappedType = this.getMappedType(prop);
|
|
1212
1239
|
const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
|
|
1213
1240
|
if (mappedType instanceof t.unknown
|
|
1214
|
-
&& !prop.columnTypes
|
|
1215
1241
|
// it could be a runtime type from reflect-metadata
|
|
1216
1242
|
&& !SCALAR_TYPES.includes(prop.type)
|
|
1217
1243
|
// or it might be inferred via ts-morph to some generic type alias
|
|
@@ -1224,11 +1250,12 @@ export class MetadataDiscovery {
|
|
|
1224
1250
|
}
|
|
1225
1251
|
return;
|
|
1226
1252
|
}
|
|
1227
|
-
|
|
1253
|
+
/* v8 ignore next */
|
|
1254
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
1228
1255
|
prop.columnTypes = [this.platform.getJsonDeclarationSQL()];
|
|
1229
1256
|
return;
|
|
1230
1257
|
}
|
|
1231
|
-
const targetMeta =
|
|
1258
|
+
const targetMeta = prop.targetMeta;
|
|
1232
1259
|
prop.columnTypes = [];
|
|
1233
1260
|
for (const pk of targetMeta.getPrimaryProps()) {
|
|
1234
1261
|
this.initCustomType(targetMeta, pk);
|
|
@@ -1278,7 +1305,7 @@ export class MetadataDiscovery {
|
|
|
1278
1305
|
return;
|
|
1279
1306
|
}
|
|
1280
1307
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
1281
|
-
const meta2 =
|
|
1308
|
+
const meta2 = prop.targetMeta;
|
|
1282
1309
|
prop.unsigned = meta2.getPrimaryProps().some(pk => {
|
|
1283
1310
|
this.initUnsigned(pk);
|
|
1284
1311
|
return pk.unsigned;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Utils } from '../utils/Utils.js';
|
|
2
|
+
import { EntitySchema } from './EntitySchema.js';
|
|
2
3
|
export class MetadataProvider {
|
|
3
4
|
config;
|
|
4
5
|
constructor(config) {
|
|
@@ -13,6 +14,7 @@ export class MetadataProvider {
|
|
|
13
14
|
else if (prop.entity) {
|
|
14
15
|
const tmp = prop.entity();
|
|
15
16
|
prop.type = Array.isArray(tmp) ? tmp.map(t => Utils.className(t)).sort().join(' | ') : Utils.className(tmp);
|
|
17
|
+
prop.target = tmp instanceof EntitySchema ? tmp.meta.class : tmp;
|
|
16
18
|
}
|
|
17
19
|
else if (!prop.type && !(prop.enum && (prop.items?.length ?? 0) > 0)) {
|
|
18
20
|
throw new Error(`Please provide either 'type' or 'entity' attribute in ${meta.className}.${prop.name}.`);
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type Dictionary, EntityMetadata, type EntityName } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
export declare class MetadataStorage {
|
|
4
4
|
static readonly PATH_SYMBOL: unique symbol;
|
|
5
5
|
private static readonly metadata;
|
|
6
6
|
private readonly metadata;
|
|
7
|
+
private readonly idMap;
|
|
8
|
+
private readonly classNameMap;
|
|
9
|
+
private readonly uniqueNameMap;
|
|
7
10
|
constructor(metadata?: Dictionary<EntityMetadata>);
|
|
8
11
|
static getMetadata(): Dictionary<EntityMetadata>;
|
|
9
12
|
static getMetadata<T = any>(entity: string, path: string): EntityMetadata<T>;
|
|
10
13
|
static isKnownEntity(name: string): boolean;
|
|
11
14
|
static clear(): void;
|
|
12
|
-
getAll():
|
|
13
|
-
get<T = any>(entityName: EntityName<T>, init?: boolean
|
|
15
|
+
getAll(): Map<EntityName, EntityMetadata>;
|
|
16
|
+
get<T = any>(entityName: EntityName<T>, init?: boolean): EntityMetadata<T>;
|
|
14
17
|
find<T = any>(entityName: EntityName<T>): EntityMetadata<T> | undefined;
|
|
15
|
-
has(
|
|
16
|
-
set(
|
|
17
|
-
reset(
|
|
18
|
+
has<T>(entityName: EntityName<T>): boolean;
|
|
19
|
+
set<T>(entityName: EntityName<T>, meta: EntityMetadata): EntityMetadata;
|
|
20
|
+
reset<T>(entityName: EntityName<T>): void;
|
|
18
21
|
decorate(em: EntityManager): void;
|
|
19
22
|
[Symbol.iterator](): IterableIterator<EntityMetadata>;
|
|
23
|
+
getById<T>(id: number): EntityMetadata<T>;
|
|
24
|
+
getByClassName<T = any, V extends boolean = true>(className: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
|
|
25
|
+
getByUniqueName<T = any, V extends boolean = true>(uniqueName: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
|
|
26
|
+
private validate;
|
|
20
27
|
}
|