@mikro-orm/core 7.0.0-rc.3 → 7.0.1-dev.0
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 +2 -15
- package/EntityManager.js +155 -152
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +20 -20
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -22
- package/cache/GeneratedCacheAdapter.d.ts +1 -1
- package/cache/GeneratedCacheAdapter.js +6 -6
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +1 -0
- package/connections/Connection.js +27 -11
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +2 -4
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +95 -105
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +48 -48
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +36 -39
- package/entity/Reference.d.ts +1 -2
- package/entity/Reference.js +11 -11
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/defineEntity.d.ts +18 -73
- package/enums.d.ts +2 -1
- package/enums.js +1 -0
- package/errors.d.ts +11 -11
- package/errors.js +3 -13
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +25 -22
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +8 -6
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +16 -16
- package/logging/DefaultLogger.js +3 -2
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +1 -1
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +162 -149
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +36 -36
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/naming-strategy/AbstractNamingStrategy.js +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/package.json +1 -1
- package/platforms/Platform.d.ts +23 -1
- package/platforms/Platform.js +57 -4
- package/serialization/EntitySerializer.js +1 -1
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +20 -15
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +12 -1
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +21 -21
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +52 -52
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +5 -19
- package/unit-of-work/UnitOfWork.js +182 -174
- package/utils/AbstractMigrator.d.ts +1 -1
- package/utils/AbstractMigrator.js +7 -7
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +94 -78
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -4
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +49 -49
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +70 -24
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/TransactionManager.js +1 -2
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +5 -4
- package/utils/clone.js +5 -0
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +1 -1
- package/utils/upsert-utils.js +1 -1
|
@@ -12,72 +12,72 @@ import { colors } from '../logging/colors.js';
|
|
|
12
12
|
import { raw, Raw } from '../utils/RawQueryFragment.js';
|
|
13
13
|
import { BaseEntity } from '../entity/BaseEntity.js';
|
|
14
14
|
export class MetadataDiscovery {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
#namingStrategy;
|
|
16
|
+
#metadataProvider;
|
|
17
|
+
#logger;
|
|
18
|
+
#schemaHelper;
|
|
19
|
+
#validator = new MetadataValidator();
|
|
20
|
+
#discovered = [];
|
|
21
|
+
#metadata;
|
|
22
|
+
#platform;
|
|
23
|
+
#config;
|
|
24
24
|
constructor(metadata, platform, config) {
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
28
|
-
this
|
|
29
|
-
this
|
|
30
|
-
this
|
|
31
|
-
this
|
|
25
|
+
this.#metadata = metadata;
|
|
26
|
+
this.#platform = platform;
|
|
27
|
+
this.#config = config;
|
|
28
|
+
this.#namingStrategy = this.#config.getNamingStrategy();
|
|
29
|
+
this.#metadataProvider = this.#config.getMetadataProvider();
|
|
30
|
+
this.#logger = this.#config.getLogger();
|
|
31
|
+
this.#schemaHelper = this.#platform.getSchemaHelper();
|
|
32
32
|
}
|
|
33
33
|
async discover(preferTs = true) {
|
|
34
|
-
this
|
|
34
|
+
this.#discovered.length = 0;
|
|
35
35
|
const startTime = Date.now();
|
|
36
|
-
const suffix = this
|
|
36
|
+
const suffix = this.#metadataProvider.constructor === MetadataProvider
|
|
37
37
|
? ''
|
|
38
|
-
: `, using ${colors.cyan(this
|
|
39
|
-
this
|
|
38
|
+
: `, using ${colors.cyan(this.#metadataProvider.constructor.name)}`;
|
|
39
|
+
this.#logger.log('discovery', `ORM entity discovery started${suffix}`);
|
|
40
40
|
await this.findEntities(preferTs);
|
|
41
|
-
for (const meta of this
|
|
41
|
+
for (const meta of this.#discovered) {
|
|
42
42
|
/* v8 ignore next */
|
|
43
|
-
await this
|
|
43
|
+
await this.#config.get('discovery').onMetadata?.(meta, this.#platform);
|
|
44
44
|
}
|
|
45
|
-
this.processDiscoveredEntities(this
|
|
45
|
+
this.processDiscoveredEntities(this.#discovered);
|
|
46
46
|
const diff = Date.now() - startTime;
|
|
47
|
-
this
|
|
47
|
+
this.#logger.log('discovery', `- entity discovery finished, found ${colors.green('' + this.#discovered.length)} entities, took ${colors.green(`${diff} ms`)}`);
|
|
48
48
|
const storage = this.mapDiscoveredEntities();
|
|
49
49
|
/* v8 ignore next */
|
|
50
|
-
await this
|
|
50
|
+
await this.#config.get('discovery').afterDiscovered?.(storage, this.#platform);
|
|
51
51
|
return storage;
|
|
52
52
|
}
|
|
53
53
|
discoverSync() {
|
|
54
|
-
this
|
|
54
|
+
this.#discovered.length = 0;
|
|
55
55
|
const startTime = Date.now();
|
|
56
|
-
const suffix = this
|
|
56
|
+
const suffix = this.#metadataProvider.constructor === MetadataProvider
|
|
57
57
|
? ''
|
|
58
|
-
: `, using ${colors.cyan(this
|
|
59
|
-
this
|
|
60
|
-
const refs = this
|
|
58
|
+
: `, using ${colors.cyan(this.#metadataProvider.constructor.name)}`;
|
|
59
|
+
this.#logger.log('discovery', `ORM entity discovery started${suffix} in sync mode`);
|
|
60
|
+
const refs = this.#config.get('entities');
|
|
61
61
|
this.discoverReferences(refs);
|
|
62
|
-
for (const meta of this
|
|
62
|
+
for (const meta of this.#discovered) {
|
|
63
63
|
/* v8 ignore next */
|
|
64
|
-
void this
|
|
64
|
+
void this.#config.get('discovery').onMetadata?.(meta, this.#platform);
|
|
65
65
|
}
|
|
66
|
-
this.processDiscoveredEntities(this
|
|
66
|
+
this.processDiscoveredEntities(this.#discovered);
|
|
67
67
|
const diff = Date.now() - startTime;
|
|
68
|
-
this
|
|
68
|
+
this.#logger.log('discovery', `- entity discovery finished, found ${colors.green('' + this.#discovered.length)} entities, took ${colors.green(`${diff} ms`)}`);
|
|
69
69
|
const storage = this.mapDiscoveredEntities();
|
|
70
70
|
/* v8 ignore next */
|
|
71
|
-
void this
|
|
71
|
+
void this.#config.get('discovery').afterDiscovered?.(storage, this.#platform);
|
|
72
72
|
return storage;
|
|
73
73
|
}
|
|
74
74
|
mapDiscoveredEntities() {
|
|
75
75
|
const discovered = new MetadataStorage();
|
|
76
|
-
this
|
|
76
|
+
this.#discovered
|
|
77
77
|
.filter(meta => meta.root.name)
|
|
78
78
|
.sort((a, b) => b.root.name.localeCompare(a.root.name))
|
|
79
79
|
.forEach(meta => {
|
|
80
|
-
this
|
|
80
|
+
this.#platform.validateMetadata(meta);
|
|
81
81
|
discovered.set(meta.class, meta);
|
|
82
82
|
});
|
|
83
83
|
for (const meta of discovered) {
|
|
@@ -137,7 +137,7 @@ export class MetadataDiscovery {
|
|
|
137
137
|
filtered.forEach(meta => this.defineBaseEntityProperties(meta));
|
|
138
138
|
filtered.forEach(meta => {
|
|
139
139
|
const newMeta = EntitySchema.fromMetadata(meta).init().meta;
|
|
140
|
-
return this
|
|
140
|
+
return this.#metadata.set(newMeta.class, newMeta);
|
|
141
141
|
});
|
|
142
142
|
filtered.forEach(meta => this.initAutoincrement(meta));
|
|
143
143
|
const forEachProp = (cb) => {
|
|
@@ -167,9 +167,9 @@ export class MetadataDiscovery {
|
|
|
167
167
|
discovered.push(...this.processEntity(meta));
|
|
168
168
|
}
|
|
169
169
|
discovered.forEach(meta => meta.sync(true));
|
|
170
|
-
this
|
|
170
|
+
this.#metadataProvider.combineCache();
|
|
171
171
|
return discovered.map(meta => {
|
|
172
|
-
meta = this
|
|
172
|
+
meta = this.#metadata.get(meta.class);
|
|
173
173
|
meta.sync(true);
|
|
174
174
|
this.findReferencingProperties(meta, filtered);
|
|
175
175
|
if (meta.inheritanceType === 'tpt') {
|
|
@@ -179,7 +179,7 @@ export class MetadataDiscovery {
|
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
181
|
async findEntities(preferTs) {
|
|
182
|
-
const { entities, entitiesTs, baseDir } = this
|
|
182
|
+
const { entities, entitiesTs, baseDir } = this.#config.getAll();
|
|
183
183
|
const targets = preferTs && entitiesTs.length > 0 ? entitiesTs : entities;
|
|
184
184
|
const processed = [];
|
|
185
185
|
const paths = [];
|
|
@@ -203,13 +203,13 @@ export class MetadataDiscovery {
|
|
|
203
203
|
.replace(/\[]$/, '') // remove array suffix
|
|
204
204
|
.replace(/\((.*)\)/, '$1'); // unwrap union types
|
|
205
205
|
const missing = [];
|
|
206
|
-
this
|
|
206
|
+
this.#discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
|
|
207
207
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity) {
|
|
208
208
|
const pivotEntity = prop.pivotEntity;
|
|
209
209
|
const target = typeof pivotEntity === 'function' && !pivotEntity.prototype
|
|
210
210
|
? pivotEntity()
|
|
211
211
|
: pivotEntity;
|
|
212
|
-
if (!this
|
|
212
|
+
if (!this.#discovered.find(m => m.className === Utils.className(target))) {
|
|
213
213
|
missing.push(target);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
@@ -217,7 +217,7 @@ export class MetadataDiscovery {
|
|
|
217
217
|
const target = typeof prop.entity === 'function' && !prop.entity.prototype ? prop.entity() : prop.type;
|
|
218
218
|
if (!unwrap(prop.type)
|
|
219
219
|
.split(/ ?\| ?/)
|
|
220
|
-
.every(type => this
|
|
220
|
+
.every(type => this.#discovered.find(m => m.className === type))) {
|
|
221
221
|
missing.push(...Utils.asArray(target));
|
|
222
222
|
}
|
|
223
223
|
}
|
|
@@ -233,7 +233,7 @@ export class MetadataDiscovery {
|
|
|
233
233
|
if (isDiscoverable && target.name) {
|
|
234
234
|
// Get the actual class for EntitySchema, or use target directly for classes
|
|
235
235
|
const targetClass = schema ? schema.meta.class : target;
|
|
236
|
-
if (!this
|
|
236
|
+
if (!this.#metadata.has(targetClass)) {
|
|
237
237
|
this.discoverReferences([target], false);
|
|
238
238
|
this.discoverMissingTargets();
|
|
239
239
|
}
|
|
@@ -248,16 +248,16 @@ export class MetadataDiscovery {
|
|
|
248
248
|
}
|
|
249
249
|
const schema = this.getSchema(entity);
|
|
250
250
|
const meta = schema.init().meta;
|
|
251
|
-
this
|
|
251
|
+
this.#metadata.set(meta.class, meta);
|
|
252
252
|
found.push(schema);
|
|
253
253
|
}
|
|
254
254
|
// discover parents (base entities) automatically
|
|
255
|
-
for (const meta of this
|
|
255
|
+
for (const meta of this.#metadata) {
|
|
256
256
|
let parent = meta.extends;
|
|
257
|
-
if (parent instanceof EntitySchema && !this
|
|
257
|
+
if (parent instanceof EntitySchema && !this.#metadata.has(parent.init().meta.class)) {
|
|
258
258
|
this.discoverReferences([parent], false);
|
|
259
259
|
}
|
|
260
|
-
if (typeof parent === 'function' && parent.name && !this
|
|
260
|
+
if (typeof parent === 'function' && parent.name && !this.#metadata.has(parent)) {
|
|
261
261
|
this.discoverReferences([parent], false);
|
|
262
262
|
}
|
|
263
263
|
/* v8 ignore next */
|
|
@@ -266,7 +266,10 @@ export class MetadataDiscovery {
|
|
|
266
266
|
}
|
|
267
267
|
parent = Object.getPrototypeOf(meta.class);
|
|
268
268
|
// Skip if parent is the auto-generated base class for the same entity (from setClass usage)
|
|
269
|
-
if (parent.name !== '' &&
|
|
269
|
+
if (parent.name !== '' &&
|
|
270
|
+
parent.name !== meta.className &&
|
|
271
|
+
!this.#metadata.has(parent) &&
|
|
272
|
+
parent !== BaseEntity) {
|
|
270
273
|
this.discoverReferences([parent], false);
|
|
271
274
|
}
|
|
272
275
|
}
|
|
@@ -275,15 +278,15 @@ export class MetadataDiscovery {
|
|
|
275
278
|
}
|
|
276
279
|
this.discoverMissingTargets();
|
|
277
280
|
if (validate) {
|
|
278
|
-
this
|
|
281
|
+
this.#validator.validateDiscovered(this.#discovered, this.#config.get('discovery'));
|
|
279
282
|
}
|
|
280
|
-
return this
|
|
283
|
+
return this.#discovered.filter(meta => found.find(m => m.name === meta.className));
|
|
281
284
|
}
|
|
282
285
|
reset(entityName) {
|
|
283
|
-
const exists = this
|
|
286
|
+
const exists = this.#discovered.findIndex(m => m.class === entityName || m.className === Utils.className(entityName));
|
|
284
287
|
if (exists !== -1) {
|
|
285
|
-
this
|
|
286
|
-
this
|
|
288
|
+
this.#metadata.reset(this.#discovered[exists].class);
|
|
289
|
+
this.#discovered.splice(exists, 1);
|
|
287
290
|
}
|
|
288
291
|
}
|
|
289
292
|
getSchema(entity) {
|
|
@@ -298,17 +301,17 @@ export class MetadataDiscovery {
|
|
|
298
301
|
if (path) {
|
|
299
302
|
const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
|
|
300
303
|
meta.path = path;
|
|
301
|
-
this
|
|
304
|
+
this.#metadata.set(entity, meta);
|
|
302
305
|
}
|
|
303
|
-
const exists = this
|
|
304
|
-
const meta = this
|
|
306
|
+
const exists = this.#metadata.has(entity);
|
|
307
|
+
const meta = this.#metadata.get(entity, true);
|
|
305
308
|
meta.abstract ??= !(exists && meta.name);
|
|
306
309
|
const schema = EntitySchema.fromMetadata(meta);
|
|
307
310
|
schema.setClass(entity);
|
|
308
311
|
return schema;
|
|
309
312
|
}
|
|
310
313
|
getRootEntity(meta) {
|
|
311
|
-
const base = meta.extends && this
|
|
314
|
+
const base = meta.extends && this.#metadata.find(meta.extends);
|
|
312
315
|
if (!base || base === meta) {
|
|
313
316
|
// make sure we do not fall into infinite loop
|
|
314
317
|
return meta;
|
|
@@ -324,13 +327,13 @@ export class MetadataDiscovery {
|
|
|
324
327
|
discoverEntity(schema) {
|
|
325
328
|
const meta = schema.meta;
|
|
326
329
|
const path = meta.path;
|
|
327
|
-
this
|
|
330
|
+
this.#logger.log('discovery', `- processing entity ${colors.cyan(meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
|
|
328
331
|
const root = this.getRootEntity(meta);
|
|
329
332
|
schema.meta.path = meta.path;
|
|
330
|
-
const cache = this
|
|
333
|
+
const cache = this.#metadataProvider.getCachedMetadata(meta, root);
|
|
331
334
|
if (cache) {
|
|
332
|
-
this
|
|
333
|
-
this
|
|
335
|
+
this.#logger.log('discovery', `- using cached metadata for entity ${colors.cyan(meta.className)}`);
|
|
336
|
+
this.#discovered.push(meta);
|
|
334
337
|
return;
|
|
335
338
|
}
|
|
336
339
|
// infer default value from property initializer early, as the metadata provider might use some defaults, e.g. string for reflect-metadata
|
|
@@ -338,14 +341,14 @@ export class MetadataDiscovery {
|
|
|
338
341
|
this.inferDefaultValue(meta, prop);
|
|
339
342
|
}
|
|
340
343
|
// if the definition is using EntitySchema we still want it to go through the metadata provider to validate no types are missing
|
|
341
|
-
this
|
|
344
|
+
this.#metadataProvider.loadEntityMetadata(meta);
|
|
342
345
|
if (!meta.tableName && meta.name) {
|
|
343
346
|
const entityName = root.discriminatorColumn ? root.name : meta.name;
|
|
344
|
-
meta.tableName = this
|
|
347
|
+
meta.tableName = this.#namingStrategy.classToTableName(entityName);
|
|
345
348
|
}
|
|
346
|
-
this
|
|
349
|
+
this.#metadataProvider.saveToCache(meta);
|
|
347
350
|
meta.root = root;
|
|
348
|
-
this
|
|
351
|
+
this.#discovered.push(meta);
|
|
349
352
|
}
|
|
350
353
|
initNullability(prop) {
|
|
351
354
|
if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
|
@@ -410,7 +413,7 @@ export class MetadataDiscovery {
|
|
|
410
413
|
return;
|
|
411
414
|
}
|
|
412
415
|
if (prop.kind === ReferenceKind.SCALAR || prop.kind === ReferenceKind.EMBEDDED) {
|
|
413
|
-
prop.fieldNames = [this
|
|
416
|
+
prop.fieldNames = [this.#namingStrategy.propertyToColumnName(prop.name, object)];
|
|
414
417
|
}
|
|
415
418
|
else if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.polymorphic) {
|
|
416
419
|
prop.fieldNames = this.initManyToOneFieldName(prop, prop.name);
|
|
@@ -425,19 +428,19 @@ export class MetadataDiscovery {
|
|
|
425
428
|
for (const primaryKey of meta2.primaryKeys) {
|
|
426
429
|
this.initFieldName(meta2.properties[primaryKey]);
|
|
427
430
|
for (const fieldName of meta2.properties[primaryKey].fieldNames) {
|
|
428
|
-
ret.push(this
|
|
431
|
+
ret.push(this.#namingStrategy.joinKeyColumnName(name, fieldName, meta2.compositePK, tableName));
|
|
429
432
|
}
|
|
430
433
|
}
|
|
431
434
|
return ret;
|
|
432
435
|
}
|
|
433
436
|
initManyToManyFieldName(prop, name) {
|
|
434
437
|
const meta2 = prop.targetMeta;
|
|
435
|
-
return meta2.primaryKeys.map(() => this
|
|
438
|
+
return meta2.primaryKeys.map(() => this.#namingStrategy.propertyToColumnName(name));
|
|
436
439
|
}
|
|
437
440
|
initManyToManyFields(meta, prop) {
|
|
438
441
|
const meta2 = prop.targetMeta;
|
|
439
442
|
Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
|
|
440
|
-
const pivotMeta = this
|
|
443
|
+
const pivotMeta = this.#metadata.find(prop.pivotEntity);
|
|
441
444
|
const props = Object.values(pivotMeta?.properties ?? {});
|
|
442
445
|
const pks = props.filter(p => p.primary);
|
|
443
446
|
const fks = props.filter(p => p.kind === ReferenceKind.MANY_TO_ONE);
|
|
@@ -455,8 +458,8 @@ export class MetadataDiscovery {
|
|
|
455
458
|
prop.joinColumns ??= first.fieldNames;
|
|
456
459
|
prop.inverseJoinColumns ??= second.fieldNames;
|
|
457
460
|
}
|
|
458
|
-
if (!prop.pivotTable && prop.owner && this
|
|
459
|
-
prop.pivotTable = this
|
|
461
|
+
if (!prop.pivotTable && prop.owner && this.#platform.usesPivotTable()) {
|
|
462
|
+
prop.pivotTable = this.#namingStrategy.joinTableName(meta.className, meta2.tableName, prop.name, meta.tableName);
|
|
460
463
|
}
|
|
461
464
|
if (prop.mappedBy) {
|
|
462
465
|
const prop2 = meta2.properties[prop.mappedBy];
|
|
@@ -475,22 +478,22 @@ export class MetadataDiscovery {
|
|
|
475
478
|
prop.referencedColumnNames ??= Utils.flatten(meta.primaryKeys.map(primaryKey => meta.properties[primaryKey].fieldNames));
|
|
476
479
|
// For polymorphic M:N, use discriminator base name for FK column (e.g., taggable_id instead of post_id)
|
|
477
480
|
if (prop.polymorphic && prop.discriminator) {
|
|
478
|
-
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this
|
|
481
|
+
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.#namingStrategy.joinKeyColumnName(prop.discriminator, referencedColumnName, prop.referencedColumnNames.length > 1));
|
|
479
482
|
}
|
|
480
483
|
else {
|
|
481
484
|
const ownerTableName = this.isExplicitTableName(meta.root) ? meta.root.tableName : undefined;
|
|
482
|
-
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this
|
|
485
|
+
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.#namingStrategy.joinKeyColumnName(meta.root.className, referencedColumnName, meta.compositePK, ownerTableName));
|
|
483
486
|
}
|
|
484
487
|
const inverseTableName = this.isExplicitTableName(meta2.root) ? meta2.root.tableName : undefined;
|
|
485
488
|
prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className, inverseTableName);
|
|
486
489
|
}
|
|
487
490
|
isExplicitTableName(meta) {
|
|
488
|
-
return meta.tableName !== this
|
|
491
|
+
return meta.tableName !== this.#namingStrategy.classToTableName(meta.className);
|
|
489
492
|
}
|
|
490
493
|
initManyToOneFields(prop) {
|
|
491
494
|
if (prop.polymorphic && prop.polymorphTargets) {
|
|
492
495
|
const fieldNames1 = prop.targetMeta.getPrimaryProps().flatMap(pk => pk.fieldNames);
|
|
493
|
-
const idColumns = fieldNames1.map(fieldName => this
|
|
496
|
+
const idColumns = fieldNames1.map(fieldName => this.#namingStrategy.joinKeyColumnName(prop.discriminator, fieldName, fieldNames1.length > 1));
|
|
494
497
|
prop.fieldNames ??= [prop.discriminatorColumn, ...idColumns];
|
|
495
498
|
prop.joinColumns ??= idColumns;
|
|
496
499
|
prop.referencedColumnNames ??= fieldNames1;
|
|
@@ -509,7 +512,7 @@ export class MetadataDiscovery {
|
|
|
509
512
|
}
|
|
510
513
|
Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
|
|
511
514
|
if (!prop.joinColumns) {
|
|
512
|
-
prop.joinColumns = fieldNames.map(fieldName => this
|
|
515
|
+
prop.joinColumns = fieldNames.map(fieldName => this.#namingStrategy.joinKeyColumnName(prop.name, fieldName, fieldNames.length > 1));
|
|
513
516
|
}
|
|
514
517
|
if (!prop.referencedColumnNames) {
|
|
515
518
|
prop.referencedColumnNames = fieldNames;
|
|
@@ -528,7 +531,7 @@ export class MetadataDiscovery {
|
|
|
528
531
|
initOneToManyFields(prop) {
|
|
529
532
|
const meta2 = prop.targetMeta;
|
|
530
533
|
if (!prop.joinColumns) {
|
|
531
|
-
prop.joinColumns = [this
|
|
534
|
+
prop.joinColumns = [this.#namingStrategy.joinColumnName(prop.name)];
|
|
532
535
|
}
|
|
533
536
|
if (!prop.referencedColumnNames) {
|
|
534
537
|
meta2.getPrimaryProps().forEach(pk => this.applyNamingStrategy(meta2, pk));
|
|
@@ -549,7 +552,7 @@ export class MetadataDiscovery {
|
|
|
549
552
|
}
|
|
550
553
|
}
|
|
551
554
|
meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
|
|
552
|
-
this
|
|
555
|
+
this.#validator.validateEntityDefinition(this.#metadata, meta.class, this.#config.get('discovery'));
|
|
553
556
|
for (const prop of Object.values(meta.properties)) {
|
|
554
557
|
this.initNullability(prop);
|
|
555
558
|
this.applyNamingStrategy(meta, prop);
|
|
@@ -567,7 +570,7 @@ export class MetadataDiscovery {
|
|
|
567
570
|
if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
|
|
568
571
|
meta.properties[meta.serializedPrimaryKey].persist ??= false;
|
|
569
572
|
}
|
|
570
|
-
if (this
|
|
573
|
+
if (this.#platform.usesPivotTable()) {
|
|
571
574
|
return Object.values(meta.properties)
|
|
572
575
|
.filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
|
|
573
576
|
.map(prop => {
|
|
@@ -594,7 +597,7 @@ export class MetadataDiscovery {
|
|
|
594
597
|
['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
|
|
595
598
|
const value = prop[type];
|
|
596
599
|
if (value instanceof Function) {
|
|
597
|
-
const meta2 = prop.targetMeta ?? this
|
|
600
|
+
const meta2 = prop.targetMeta ?? this.#metadata.get(prop.target);
|
|
598
601
|
prop[type] = value(meta2.properties)?.name;
|
|
599
602
|
if (type === 'pivotEntity' && value) {
|
|
600
603
|
prop[type] = value(meta2.properties);
|
|
@@ -631,8 +634,8 @@ export class MetadataDiscovery {
|
|
|
631
634
|
}
|
|
632
635
|
definePivotTableEntity(meta, prop) {
|
|
633
636
|
const pivotMeta = prop.pivotEntity
|
|
634
|
-
? this
|
|
635
|
-
: this
|
|
637
|
+
? this.#metadata.find(prop.pivotEntity)
|
|
638
|
+
: this.#metadata.getByClassName(prop.pivotTable, false);
|
|
636
639
|
// ensure inverse side exists so we can join it when populating via pivot tables
|
|
637
640
|
if (!prop.inversedBy && prop.targetMeta) {
|
|
638
641
|
const inverseName = `${meta.className}_${prop.name}__inverse`;
|
|
@@ -698,15 +701,15 @@ export class MetadataDiscovery {
|
|
|
698
701
|
prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
|
|
699
702
|
// use tableName only when explicitly provided by user, otherwise use className for backwards compatibility
|
|
700
703
|
const baseName = this.isExplicitTableName(meta) ? meta.tableName : meta.className;
|
|
701
|
-
prop.joinColumns = prop.referencedColumnNames.map(name => this
|
|
702
|
-
prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this
|
|
704
|
+
prop.joinColumns = prop.referencedColumnNames.map(name => this.#namingStrategy.joinKeyColumnName(baseName + '_1', name, meta.compositePK));
|
|
705
|
+
prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.#namingStrategy.joinKeyColumnName(baseName + '_2', name, meta.compositePK));
|
|
703
706
|
if (prop.inversedBy) {
|
|
704
707
|
const prop2 = targetMeta.properties[prop.inversedBy];
|
|
705
708
|
prop2.inverseJoinColumns = prop.joinColumns;
|
|
706
709
|
prop2.joinColumns = prop.inverseJoinColumns;
|
|
707
710
|
}
|
|
708
711
|
// propagate updated joinColumns to all child entities that inherit this property (STI)
|
|
709
|
-
for (const childMeta of this
|
|
712
|
+
for (const childMeta of this.#discovered.filter(m => m.root === meta && m !== meta)) {
|
|
710
713
|
const childProp = childMeta.properties[prop.name];
|
|
711
714
|
if (childProp) {
|
|
712
715
|
childProp.joinColumns = prop.joinColumns;
|
|
@@ -722,7 +725,7 @@ export class MetadataDiscovery {
|
|
|
722
725
|
pivotMeta2.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.class, targetType + '_inverse', true, meta.className === targetType);
|
|
723
726
|
pivotMeta2.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetMeta.class, meta.name + '_owner', false, meta.className === targetType);
|
|
724
727
|
}
|
|
725
|
-
return this
|
|
728
|
+
return this.#metadata.set(pivotMeta2.class, EntitySchema.fromMetadata(pivotMeta2).init().meta);
|
|
726
729
|
}
|
|
727
730
|
/**
|
|
728
731
|
* Create a scalar property for a pivot table column.
|
|
@@ -778,7 +781,7 @@ export class MetadataDiscovery {
|
|
|
778
781
|
pivotMeta.properties[primaryProp.name] = primaryProp;
|
|
779
782
|
pivotMeta.compositePK = false;
|
|
780
783
|
}
|
|
781
|
-
const discriminatorProp = this.createPivotScalarProperty(discriminatorColumn, [this
|
|
784
|
+
const discriminatorProp = this.createPivotScalarProperty(discriminatorColumn, [this.#platform.getVarcharTypeDeclarationSQL(prop)], [discriminatorColumn], { type: 'string', primary: !isCompositePK, nullable: false });
|
|
782
785
|
this.initFieldName(discriminatorProp);
|
|
783
786
|
pivotMeta.properties[discriminatorColumn] = discriminatorProp;
|
|
784
787
|
const columnTypes = this.getPrimaryKeyColumnTypes(meta);
|
|
@@ -831,21 +834,22 @@ export class MetadataDiscovery {
|
|
|
831
834
|
ret.precision = pkProp.precision;
|
|
832
835
|
ret.scale = pkProp.scale;
|
|
833
836
|
}
|
|
834
|
-
const schema = targetMeta.schema ?? this
|
|
837
|
+
const schema = targetMeta.schema ?? this.#config.get('schema') ?? this.#platform.getDefaultSchemaName();
|
|
835
838
|
ret.referencedTableName = schema && schema !== '*' ? schema + '.' + targetMeta.tableName : targetMeta.tableName;
|
|
836
839
|
this.initColumnType(ret);
|
|
837
840
|
this.initRelation(ret);
|
|
838
841
|
return ret;
|
|
839
842
|
}
|
|
840
843
|
defineFixedOrderProperty(prop, targetMeta) {
|
|
841
|
-
const pk = prop.fixedOrderColumn || this
|
|
844
|
+
const pk = prop.fixedOrderColumn || this.#namingStrategy.referenceColumnName();
|
|
842
845
|
const primaryProp = {
|
|
843
846
|
name: pk,
|
|
844
847
|
type: 'number',
|
|
848
|
+
runtimeType: 'number',
|
|
845
849
|
kind: ReferenceKind.SCALAR,
|
|
846
850
|
primary: true,
|
|
847
851
|
autoincrement: true,
|
|
848
|
-
unsigned: this
|
|
852
|
+
unsigned: this.#platform.supportsUnsigned(),
|
|
849
853
|
};
|
|
850
854
|
this.initFieldName(primaryProp);
|
|
851
855
|
this.initColumnType(primaryProp);
|
|
@@ -866,21 +870,21 @@ export class MetadataDiscovery {
|
|
|
866
870
|
cascade: [Cascade.ALL],
|
|
867
871
|
fixedOrder: prop.fixedOrder,
|
|
868
872
|
fixedOrderColumn: prop.fixedOrderColumn,
|
|
869
|
-
index: this
|
|
873
|
+
index: this.#platform.indexForeignKeys(),
|
|
870
874
|
primary: !prop.fixedOrder,
|
|
871
875
|
autoincrement: false,
|
|
872
876
|
updateRule: prop.updateRule,
|
|
873
877
|
deleteRule: prop.deleteRule,
|
|
874
878
|
createForeignKeyConstraint: prop.createForeignKeyConstraint,
|
|
875
879
|
};
|
|
876
|
-
const defaultRule = selfReferencing && !this
|
|
880
|
+
const defaultRule = selfReferencing && !this.#platform.supportsMultipleCascadePaths() ? 'no action' : 'cascade';
|
|
877
881
|
ret.updateRule ??= defaultRule;
|
|
878
882
|
ret.deleteRule ??= defaultRule;
|
|
879
|
-
const meta = this
|
|
883
|
+
const meta = this.#metadata.get(type);
|
|
880
884
|
ret.targetMeta = meta;
|
|
881
885
|
ret.joinColumns = [];
|
|
882
886
|
ret.inverseJoinColumns = [];
|
|
883
|
-
const schema = meta.schema ?? this
|
|
887
|
+
const schema = meta.schema ?? this.#config.get('schema') ?? this.#platform.getDefaultSchemaName();
|
|
884
888
|
ret.referencedTableName = schema && schema !== '*' ? schema + '.' + meta.tableName : meta.tableName;
|
|
885
889
|
if (owner) {
|
|
886
890
|
ret.owner = true;
|
|
@@ -926,7 +930,7 @@ export class MetadataDiscovery {
|
|
|
926
930
|
});
|
|
927
931
|
}
|
|
928
932
|
defineBaseEntityProperties(meta) {
|
|
929
|
-
const base = meta.extends && this
|
|
933
|
+
const base = meta.extends && this.#metadata.get(meta.extends);
|
|
930
934
|
if (!base || base === meta) {
|
|
931
935
|
// make sure we do not fall into infinite loop
|
|
932
936
|
return 0;
|
|
@@ -973,8 +977,8 @@ export class MetadataDiscovery {
|
|
|
973
977
|
}
|
|
974
978
|
visited.add(embeddedProp);
|
|
975
979
|
const types = embeddedProp.type.split(/ ?\| ?/);
|
|
976
|
-
let embeddable = this
|
|
977
|
-
const polymorphs = this
|
|
980
|
+
let embeddable = this.#discovered.find(m => m.name === embeddedProp.type);
|
|
981
|
+
const polymorphs = this.#discovered.filter(m => types.includes(m.name));
|
|
978
982
|
// create virtual polymorphic entity
|
|
979
983
|
if (!embeddable && polymorphs.length > 0) {
|
|
980
984
|
const properties = {};
|
|
@@ -986,13 +990,17 @@ export class MetadataDiscovery {
|
|
|
986
990
|
if (properties[prop.name] && properties[prop.name].type !== prop.type) {
|
|
987
991
|
properties[prop.name].type = `${properties[prop.name].type} | ${prop.type}`;
|
|
988
992
|
properties[prop.name].runtimeType = 'any';
|
|
993
|
+
properties[prop.name].stiMerged = true;
|
|
989
994
|
return properties[prop.name];
|
|
990
995
|
}
|
|
991
|
-
|
|
996
|
+
// Deep copy to prevent mutating the original entity's property —
|
|
997
|
+
// both from the merge path above (GH #6522/#6523) and from
|
|
998
|
+
// downstream code that mutates nested arrays like fieldNames.
|
|
999
|
+
return (properties[prop.name] = Utils.copy(prop));
|
|
992
1000
|
});
|
|
993
1001
|
};
|
|
994
1002
|
const processExtensions = (meta) => {
|
|
995
|
-
const parent = this
|
|
1003
|
+
const parent = this.#discovered.find(m => {
|
|
996
1004
|
return meta.extends && Utils.className(meta.extends) === m.className;
|
|
997
1005
|
});
|
|
998
1006
|
if (!parent) {
|
|
@@ -1030,7 +1038,7 @@ export class MetadataDiscovery {
|
|
|
1030
1038
|
}
|
|
1031
1039
|
prop.polymorphic = true;
|
|
1032
1040
|
prop.discriminator ??= prop.name;
|
|
1033
|
-
prop.discriminatorColumn ??= this
|
|
1041
|
+
prop.discriminatorColumn ??= this.#namingStrategy.discriminatorColumnName(prop.discriminator);
|
|
1034
1042
|
prop.createForeignKeyConstraint = false;
|
|
1035
1043
|
const isToOne = [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
|
|
1036
1044
|
if (isToOne) {
|
|
@@ -1042,7 +1050,7 @@ export class MetadataDiscovery {
|
|
|
1042
1050
|
if (prop.discriminatorMap) {
|
|
1043
1051
|
const normalizedMap = {};
|
|
1044
1052
|
for (const [key, value] of Object.entries(prop.discriminatorMap)) {
|
|
1045
|
-
const targetMeta = this
|
|
1053
|
+
const targetMeta = this.#metadata.getByClassName(value, false);
|
|
1046
1054
|
if (!targetMeta) {
|
|
1047
1055
|
throw MetadataError.fromUnknownEntity(value, `${meta.className}.${prop.name} discriminatorMap`);
|
|
1048
1056
|
}
|
|
@@ -1077,7 +1085,7 @@ export class MetadataDiscovery {
|
|
|
1077
1085
|
return;
|
|
1078
1086
|
}
|
|
1079
1087
|
visited.add(embeddedProp);
|
|
1080
|
-
const embeddable = this
|
|
1088
|
+
const embeddable = this.#discovered.find(m => m.name === embeddedProp.type);
|
|
1081
1089
|
if (!embeddable) {
|
|
1082
1090
|
throw MetadataError.fromUnknownEntity(embeddedProp.type, `${meta.className}.${embeddedProp.name}`);
|
|
1083
1091
|
}
|
|
@@ -1149,7 +1157,7 @@ export class MetadataDiscovery {
|
|
|
1149
1157
|
meta.properties[name].fieldNames = prop.fieldNames;
|
|
1150
1158
|
meta.properties[name].embeddedPath = path;
|
|
1151
1159
|
const targetProp = prop.targetMeta?.getPrimaryProp() ?? prop;
|
|
1152
|
-
const fieldName = raw(this
|
|
1160
|
+
const fieldName = raw(this.#platform.getSearchJsonPropertySQL(path.join('->'), targetProp.runtimeType ?? targetProp.type, true));
|
|
1153
1161
|
meta.properties[name].fieldNameRaw = fieldName.sql; // for querying in SQL drivers
|
|
1154
1162
|
meta.properties[name].persist = false; // only virtual as we store the whole object
|
|
1155
1163
|
meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
|
|
@@ -1191,7 +1199,7 @@ export class MetadataDiscovery {
|
|
|
1191
1199
|
const map = meta.root.discriminatorMap;
|
|
1192
1200
|
Object.keys(map)
|
|
1193
1201
|
.filter(key => typeof map[key] === 'string')
|
|
1194
|
-
.forEach(key => (map[key] = this
|
|
1202
|
+
.forEach(key => (map[key] = this.#metadata.getByClassName(map[key]).class));
|
|
1195
1203
|
}
|
|
1196
1204
|
else {
|
|
1197
1205
|
meta.root.discriminatorMap = {};
|
|
@@ -1199,7 +1207,7 @@ export class MetadataDiscovery {
|
|
|
1199
1207
|
.filter(m => m.root.class === meta.root.class && !m.abstract)
|
|
1200
1208
|
.sort((a, b) => a.className.localeCompare(b.className));
|
|
1201
1209
|
for (const m of children) {
|
|
1202
|
-
const name = m.discriminatorValue ?? this
|
|
1210
|
+
const name = m.discriminatorValue ?? this.#namingStrategy.classToTableName(m.className);
|
|
1203
1211
|
meta.root.discriminatorMap[name] = m.class;
|
|
1204
1212
|
}
|
|
1205
1213
|
}
|
|
@@ -1215,8 +1223,13 @@ export class MetadataDiscovery {
|
|
|
1215
1223
|
Object.values(meta.properties).forEach(prop => {
|
|
1216
1224
|
const newProp = { ...prop };
|
|
1217
1225
|
const rootProp = meta.root.properties[prop.name];
|
|
1226
|
+
// stiMerged is set during inlineProperties when a property was merged
|
|
1227
|
+
// from multiple polymorphic variants with different types. The flag is
|
|
1228
|
+
// cleared implicitly when the first child claims the root property via
|
|
1229
|
+
// addProperty below, so subsequent children correctly trigger renaming.
|
|
1230
|
+
const typesMatch = rootProp?.type === prop.type || rootProp?.stiMerged === true;
|
|
1218
1231
|
if (rootProp &&
|
|
1219
|
-
(
|
|
1232
|
+
(!typesMatch ||
|
|
1220
1233
|
(rootProp.fieldNames && prop.fieldNames && !compareArrays(rootProp.fieldNames, prop.fieldNames)))) {
|
|
1221
1234
|
const name = newProp.name;
|
|
1222
1235
|
this.initFieldName(newProp, newProp.object);
|
|
@@ -1231,7 +1244,7 @@ export class MetadataDiscovery {
|
|
|
1231
1244
|
rootProp.stiFieldNameMap = {};
|
|
1232
1245
|
// Find which discriminator owns the original fieldNames
|
|
1233
1246
|
for (const [discValue, childClass] of Object.entries(meta.root.discriminatorMap)) {
|
|
1234
|
-
const childMeta = this
|
|
1247
|
+
const childMeta = this.#metadata.find(childClass);
|
|
1235
1248
|
if (childMeta?.properties[prop.name]?.fieldNames &&
|
|
1236
1249
|
compareArrays(childMeta.properties[prop.name].fieldNames, rootProp.fieldNames)) {
|
|
1237
1250
|
rootProp.stiFieldNameMap[discValue] = rootProp.fieldNames[0];
|
|
@@ -1299,11 +1312,11 @@ export class MetadataDiscovery {
|
|
|
1299
1312
|
if (meta.tptChildren) {
|
|
1300
1313
|
meta.tptChildren = meta.tptChildren.map(child => metadata.find(m => m.class === child.class) ?? child);
|
|
1301
1314
|
}
|
|
1302
|
-
const registryMeta = this
|
|
1315
|
+
const registryMeta = this.#metadata.get(meta.class);
|
|
1303
1316
|
if (registryMeta && registryMeta !== meta) {
|
|
1304
1317
|
registryMeta.inheritanceType = meta.inheritanceType;
|
|
1305
|
-
registryMeta.tptParent = meta.tptParent ? this
|
|
1306
|
-
registryMeta.tptChildren = meta.tptChildren?.map(child => this
|
|
1318
|
+
registryMeta.tptParent = meta.tptParent ? this.#metadata.get(meta.tptParent.class) : undefined;
|
|
1319
|
+
registryMeta.tptChildren = meta.tptChildren?.map(child => this.#metadata.get(child.class));
|
|
1307
1320
|
}
|
|
1308
1321
|
this.initTPTDiscriminator(meta, metadata);
|
|
1309
1322
|
}
|
|
@@ -1321,12 +1334,12 @@ export class MetadataDiscovery {
|
|
|
1321
1334
|
}
|
|
1322
1335
|
meta.root.discriminatorMap = {};
|
|
1323
1336
|
for (const m of allDescendants) {
|
|
1324
|
-
const name = this
|
|
1337
|
+
const name = this.#namingStrategy.classToTableName(m.className);
|
|
1325
1338
|
meta.root.discriminatorMap[name] = m.class;
|
|
1326
1339
|
m.discriminatorValue = name;
|
|
1327
1340
|
}
|
|
1328
1341
|
if (!meta.abstract) {
|
|
1329
|
-
const name = this
|
|
1342
|
+
const name = this.#namingStrategy.classToTableName(meta.className);
|
|
1330
1343
|
meta.root.discriminatorMap[name] = meta.class;
|
|
1331
1344
|
meta.discriminatorValue = name;
|
|
1332
1345
|
}
|
|
@@ -1439,7 +1452,7 @@ export class MetadataDiscovery {
|
|
|
1439
1452
|
}
|
|
1440
1453
|
initAutoincrement(meta) {
|
|
1441
1454
|
const pks = meta.getPrimaryProps();
|
|
1442
|
-
if (pks.length === 1 && this
|
|
1455
|
+
if (pks.length === 1 && this.#platform.isNumericProperty(pks[0])) {
|
|
1443
1456
|
/* v8 ignore next */
|
|
1444
1457
|
pks[0].autoincrement ??= true;
|
|
1445
1458
|
}
|
|
@@ -1458,12 +1471,12 @@ export class MetadataDiscovery {
|
|
|
1458
1471
|
const table = this.createSchemaTable(meta);
|
|
1459
1472
|
for (const check of meta.checks) {
|
|
1460
1473
|
const fieldNames = check.property ? meta.properties[check.property].fieldNames : [];
|
|
1461
|
-
check.name ??= this
|
|
1474
|
+
check.name ??= this.#namingStrategy.indexName(meta.tableName, fieldNames, 'check');
|
|
1462
1475
|
if (check.expression instanceof Function) {
|
|
1463
1476
|
check.expression = check.expression(columns, table);
|
|
1464
1477
|
}
|
|
1465
1478
|
}
|
|
1466
|
-
if (this
|
|
1479
|
+
if (this.#platform.usesEnumCheckConstraints() && !meta.embeddable) {
|
|
1467
1480
|
for (const prop of meta.props) {
|
|
1468
1481
|
if (prop.enum &&
|
|
1469
1482
|
prop.persist !== false &&
|
|
@@ -1471,9 +1484,9 @@ export class MetadataDiscovery {
|
|
|
1471
1484
|
prop.items?.every(item => typeof item === 'string')) {
|
|
1472
1485
|
this.initFieldName(prop);
|
|
1473
1486
|
meta.checks.push({
|
|
1474
|
-
name: this
|
|
1487
|
+
name: this.#namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
|
|
1475
1488
|
property: prop.name,
|
|
1476
|
-
expression: `${this
|
|
1489
|
+
expression: `${this.#platform.quoteIdentifier(prop.fieldNames[0])} in ('${prop.items.join("', '")}')`,
|
|
1477
1490
|
});
|
|
1478
1491
|
}
|
|
1479
1492
|
}
|
|
@@ -1481,13 +1494,13 @@ export class MetadataDiscovery {
|
|
|
1481
1494
|
}
|
|
1482
1495
|
initGeneratedColumn(meta, prop) {
|
|
1483
1496
|
if (!prop.generated && prop.columnTypes) {
|
|
1484
|
-
const match =
|
|
1497
|
+
const match = /(.*) generated always as (.*)/i.exec(prop.columnTypes[0]);
|
|
1485
1498
|
if (match) {
|
|
1486
1499
|
prop.columnTypes[0] = match[1];
|
|
1487
1500
|
prop.generated = match[2];
|
|
1488
1501
|
return;
|
|
1489
1502
|
}
|
|
1490
|
-
const match2 = prop.columnTypes[0]?.trim()
|
|
1503
|
+
const match2 = /^as (.*)/i.exec(prop.columnTypes[0]?.trim());
|
|
1491
1504
|
if (match2) {
|
|
1492
1505
|
prop.generated = match2[1];
|
|
1493
1506
|
}
|
|
@@ -1504,13 +1517,13 @@ export class MetadataDiscovery {
|
|
|
1504
1517
|
}
|
|
1505
1518
|
/* v8 ignore next */
|
|
1506
1519
|
if (prop.default != null) {
|
|
1507
|
-
return '' + this
|
|
1520
|
+
return '' + this.#platform.convertVersionValue(prop.default, prop);
|
|
1508
1521
|
}
|
|
1509
1522
|
this.initCustomType(meta, prop, true);
|
|
1510
1523
|
const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
|
|
1511
1524
|
if (type === 'Date') {
|
|
1512
|
-
prop.length ??= this
|
|
1513
|
-
return this
|
|
1525
|
+
prop.length ??= this.#platform.getDefaultVersionLength();
|
|
1526
|
+
return this.#platform.getCurrentTimestampSQL(prop.length);
|
|
1514
1527
|
}
|
|
1515
1528
|
return '1';
|
|
1516
1529
|
}
|
|
@@ -1521,7 +1534,7 @@ export class MetadataDiscovery {
|
|
|
1521
1534
|
const entity1 = new meta.class();
|
|
1522
1535
|
const entity2 = new meta.class();
|
|
1523
1536
|
// we compare the two values by reference, this will discard things like `new Date()` or `Date.now()`
|
|
1524
|
-
if (this
|
|
1537
|
+
if (this.#config.get('discovery').inferDefaultValues &&
|
|
1525
1538
|
prop.default === undefined &&
|
|
1526
1539
|
entity1[prop.name] != null &&
|
|
1527
1540
|
entity1[prop.name] === entity2[prop.name] &&
|
|
@@ -1548,11 +1561,11 @@ export class MetadataDiscovery {
|
|
|
1548
1561
|
let val = prop.default;
|
|
1549
1562
|
const raw = Raw.getKnownFragment(val);
|
|
1550
1563
|
if (raw) {
|
|
1551
|
-
prop.defaultRaw = this
|
|
1564
|
+
prop.defaultRaw = this.#platform.formatQuery(raw.sql, raw.params);
|
|
1552
1565
|
return;
|
|
1553
1566
|
}
|
|
1554
1567
|
if (Array.isArray(prop.default) && prop.customType) {
|
|
1555
|
-
val = prop.customType.convertToDatabaseValue(prop.default, this
|
|
1568
|
+
val = prop.customType.convertToDatabaseValue(prop.default, this.#platform);
|
|
1556
1569
|
}
|
|
1557
1570
|
prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
|
|
1558
1571
|
}
|
|
@@ -1652,7 +1665,7 @@ export class MetadataDiscovery {
|
|
|
1652
1665
|
}
|
|
1653
1666
|
if (prop.customType && !prop.columnTypes) {
|
|
1654
1667
|
const mappedType = this.getMappedType({
|
|
1655
|
-
columnTypes: [prop.customType.getColumnType(prop, this
|
|
1668
|
+
columnTypes: [prop.customType.getColumnType(prop, this.#platform)],
|
|
1656
1669
|
});
|
|
1657
1670
|
if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
|
|
1658
1671
|
prop.runtimeType ??= mappedType.runtimeType;
|
|
@@ -1668,15 +1681,15 @@ export class MetadataDiscovery {
|
|
|
1668
1681
|
prop.runtimeType ??= mappedType.runtimeType;
|
|
1669
1682
|
}
|
|
1670
1683
|
if (prop.customType) {
|
|
1671
|
-
prop.customType.platform = this
|
|
1684
|
+
prop.customType.platform = this.#platform;
|
|
1672
1685
|
prop.customType.meta = meta;
|
|
1673
1686
|
prop.customType.prop = prop;
|
|
1674
|
-
prop.columnTypes ??= [prop.customType.getColumnType(prop, this
|
|
1687
|
+
prop.columnTypes ??= [prop.customType.getColumnType(prop, this.#platform)];
|
|
1675
1688
|
prop.hasConvertToJSValueSQL =
|
|
1676
|
-
!!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this
|
|
1689
|
+
!!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.#platform) !== '';
|
|
1677
1690
|
prop.hasConvertToDatabaseValueSQL =
|
|
1678
1691
|
!!prop.customType.convertToDatabaseValueSQL &&
|
|
1679
|
-
prop.customType.convertToDatabaseValueSQL('', this
|
|
1692
|
+
prop.customType.convertToDatabaseValueSQL('', this.#platform) !== '';
|
|
1680
1693
|
if (prop.customType instanceof t.bigint &&
|
|
1681
1694
|
['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
|
|
1682
1695
|
prop.customType.mode = prop.runtimeType.toLowerCase();
|
|
@@ -1694,11 +1707,11 @@ export class MetadataDiscovery {
|
|
|
1694
1707
|
if (pk.customType) {
|
|
1695
1708
|
prop.customTypes.push(pk.customType);
|
|
1696
1709
|
prop.hasConvertToJSValueSQL ||=
|
|
1697
|
-
!!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this
|
|
1710
|
+
!!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.#platform) !== '';
|
|
1698
1711
|
/* v8 ignore next */
|
|
1699
1712
|
prop.hasConvertToDatabaseValueSQL ||=
|
|
1700
1713
|
!!pk.customType.convertToDatabaseValueSQL &&
|
|
1701
|
-
pk.customType.convertToDatabaseValueSQL('', this
|
|
1714
|
+
pk.customType.convertToDatabaseValueSQL('', this.#platform) !== '';
|
|
1702
1715
|
}
|
|
1703
1716
|
else {
|
|
1704
1717
|
prop.customTypes.push(undefined);
|
|
@@ -1708,13 +1721,13 @@ export class MetadataDiscovery {
|
|
|
1708
1721
|
if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
|
|
1709
1722
|
if (!prop.columnTypes &&
|
|
1710
1723
|
prop.nativeEnumName &&
|
|
1711
|
-
meta.schema !== this
|
|
1724
|
+
meta.schema !== this.#platform.getDefaultSchemaName() &&
|
|
1712
1725
|
meta.schema &&
|
|
1713
1726
|
!prop.nativeEnumName.includes('.')) {
|
|
1714
1727
|
prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
|
|
1715
1728
|
}
|
|
1716
1729
|
else {
|
|
1717
|
-
prop.columnTypes ??= [mappedType.getColumnType(prop, this
|
|
1730
|
+
prop.columnTypes ??= [mappedType.getColumnType(prop, this.#platform)];
|
|
1718
1731
|
}
|
|
1719
1732
|
// use only custom types provided by user, we don't need to use the ones provided by ORM,
|
|
1720
1733
|
// with exception for ArrayType and JsonType, those two are handled in
|
|
@@ -1728,7 +1741,7 @@ export class MetadataDiscovery {
|
|
|
1728
1741
|
return;
|
|
1729
1742
|
}
|
|
1730
1743
|
// 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
|
|
1731
|
-
const meta2 = this
|
|
1744
|
+
const meta2 = this.#metadata.find(prop.target) ?? this.#metadata.getByClassName(prop.type);
|
|
1732
1745
|
// If targetKey is specified, use that property instead of PKs for referencedPKs
|
|
1733
1746
|
prop.referencedPKs = prop.targetKey ? [prop.targetKey] : meta2.primaryKeys;
|
|
1734
1747
|
prop.targetMeta = meta2;
|
|
@@ -1743,7 +1756,7 @@ export class MetadataDiscovery {
|
|
|
1743
1756
|
!prop.embedded) {
|
|
1744
1757
|
this.initFieldName(prop);
|
|
1745
1758
|
if (prop.fieldNames?.length === 1) {
|
|
1746
|
-
prop.formula = table => `${table}.${this
|
|
1759
|
+
prop.formula = table => `${table}.${this.#platform.quoteIdentifier(prop.fieldNames[0])}`;
|
|
1747
1760
|
}
|
|
1748
1761
|
}
|
|
1749
1762
|
}
|
|
@@ -1765,7 +1778,7 @@ export class MetadataDiscovery {
|
|
|
1765
1778
|
const mappedType = this.getMappedType(prop);
|
|
1766
1779
|
prop.type = mappedType.compareAsType();
|
|
1767
1780
|
}
|
|
1768
|
-
if (prop.columnTypes || !this
|
|
1781
|
+
if (prop.columnTypes || !this.#schemaHelper) {
|
|
1769
1782
|
return;
|
|
1770
1783
|
}
|
|
1771
1784
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
@@ -1775,18 +1788,18 @@ export class MetadataDiscovery {
|
|
|
1775
1788
|
// it could be a runtime type from reflect-metadata
|
|
1776
1789
|
!SCALAR_TYPES.includes(prop.type) &&
|
|
1777
1790
|
// or it might be inferred via ts-morph to some generic type alias
|
|
1778
|
-
|
|
1791
|
+
!/[<>:"';{}]/.exec(prop.type)) {
|
|
1779
1792
|
const type = prop.length != null && !prop.type.endsWith(`(${prop.length})`) ? `${prop.type}(${prop.length})` : prop.type;
|
|
1780
1793
|
prop.columnTypes = [type];
|
|
1781
1794
|
}
|
|
1782
1795
|
else {
|
|
1783
|
-
prop.columnTypes = [mappedType.getColumnType(prop, this
|
|
1796
|
+
prop.columnTypes = [mappedType.getColumnType(prop, this.#platform)];
|
|
1784
1797
|
}
|
|
1785
1798
|
return;
|
|
1786
1799
|
}
|
|
1787
1800
|
/* v8 ignore next */
|
|
1788
1801
|
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
1789
|
-
prop.columnTypes = [this
|
|
1802
|
+
prop.columnTypes = [this.#platform.getJsonDeclarationSQL()];
|
|
1790
1803
|
return;
|
|
1791
1804
|
}
|
|
1792
1805
|
const targetMeta = prop.targetMeta;
|
|
@@ -1794,7 +1807,7 @@ export class MetadataDiscovery {
|
|
|
1794
1807
|
// Use targetKey property if specified, otherwise use primary key properties
|
|
1795
1808
|
const referencedProps = prop.targetKey ? [targetMeta.properties[prop.targetKey]] : targetMeta.getPrimaryProps();
|
|
1796
1809
|
if (prop.polymorphic && prop.polymorphTargets) {
|
|
1797
|
-
prop.columnTypes.push(this
|
|
1810
|
+
prop.columnTypes.push(this.#platform.getVarcharTypeDeclarationSQL(prop));
|
|
1798
1811
|
}
|
|
1799
1812
|
for (const referencedProp of referencedProps) {
|
|
1800
1813
|
this.initCustomType(targetMeta, referencedProp);
|
|
@@ -1802,7 +1815,7 @@ export class MetadataDiscovery {
|
|
|
1802
1815
|
const mappedType = this.getMappedType(referencedProp);
|
|
1803
1816
|
let columnTypes = referencedProp.columnTypes;
|
|
1804
1817
|
if (referencedProp.autoincrement) {
|
|
1805
|
-
columnTypes = [mappedType.getColumnType({ ...referencedProp, autoincrement: false }, this
|
|
1818
|
+
columnTypes = [mappedType.getColumnType({ ...referencedProp, autoincrement: false }, this.#platform)];
|
|
1806
1819
|
}
|
|
1807
1820
|
prop.columnTypes.push(...columnTypes);
|
|
1808
1821
|
if (!targetMeta.compositePK || prop.targetKey) {
|
|
@@ -1825,7 +1838,7 @@ export class MetadataDiscovery {
|
|
|
1825
1838
|
if (t === 'Date') {
|
|
1826
1839
|
t = 'datetime';
|
|
1827
1840
|
}
|
|
1828
|
-
return this
|
|
1841
|
+
return this.#platform.getMappedType(t);
|
|
1829
1842
|
}
|
|
1830
1843
|
getPrefix(prop, parent) {
|
|
1831
1844
|
const { embeddedPath = [], fieldNames, prefix = true, prefixMode } = prop;
|
|
@@ -1836,7 +1849,7 @@ export class MetadataDiscovery {
|
|
|
1836
1849
|
if (prefix === false) {
|
|
1837
1850
|
return prefixParent;
|
|
1838
1851
|
}
|
|
1839
|
-
const mode = prefixMode ?? this
|
|
1852
|
+
const mode = prefixMode ?? this.#config.get('embeddables').prefixMode;
|
|
1840
1853
|
return mode === 'absolute' ? prefix : prefixParent + prefix;
|
|
1841
1854
|
}
|
|
1842
1855
|
initUnsigned(prop) {
|
|
@@ -1851,16 +1864,16 @@ export class MetadataDiscovery {
|
|
|
1851
1864
|
return;
|
|
1852
1865
|
}
|
|
1853
1866
|
prop.unsigned ??=
|
|
1854
|
-
(prop.primary || prop.unsigned) && this
|
|
1867
|
+
(prop.primary || prop.unsigned) && this.#platform.isNumericProperty(prop) && this.#platform.supportsUnsigned();
|
|
1855
1868
|
}
|
|
1856
1869
|
initIndexes(meta, prop) {
|
|
1857
1870
|
const hasIndex = meta.indexes.some(idx => idx.properties?.length === 1 && idx.properties[0] === prop.name);
|
|
1858
|
-
if (prop.kind === ReferenceKind.MANY_TO_ONE && this
|
|
1871
|
+
if (prop.kind === ReferenceKind.MANY_TO_ONE && this.#platform.indexForeignKeys() && !hasIndex) {
|
|
1859
1872
|
prop.index ??= true;
|
|
1860
1873
|
}
|
|
1861
1874
|
}
|
|
1862
1875
|
shouldForceConstructorUsage(meta) {
|
|
1863
|
-
const forceConstructor = this
|
|
1876
|
+
const forceConstructor = this.#config.get('forceEntityConstructor');
|
|
1864
1877
|
if (Array.isArray(forceConstructor)) {
|
|
1865
1878
|
return forceConstructor.some(cls => Utils.className(cls) === meta.className);
|
|
1866
1879
|
}
|