@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EntityManager.d.ts +85 -56
- package/EntityManager.js +332 -293
- package/MikroORM.d.ts +41 -32
- package/MikroORM.js +100 -140
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +8 -7
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +16 -7
- package/connections/Connection.js +23 -14
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +35 -19
- package/drivers/IDatabaseDriver.d.ts +38 -17
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -30
- package/entity/Collection.js +439 -99
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +72 -53
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +30 -15
- package/entity/EntityLoader.d.ts +7 -6
- package/entity/EntityLoader.js +84 -72
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityRepository.js +2 -2
- package/entity/Reference.d.ts +6 -5
- package/entity/Reference.js +34 -9
- package/entity/WrappedEntity.d.ts +2 -7
- package/entity/WrappedEntity.js +3 -8
- package/entity/defineEntity.d.ts +568 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +21 -6
- package/enums.js +14 -1
- package/errors.d.ts +17 -9
- package/errors.js +41 -21
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +50 -33
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +13 -17
- package/metadata/EntitySchema.js +67 -51
- package/metadata/MetadataDiscovery.d.ts +6 -10
- package/metadata/MetadataDiscovery.js +289 -298
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +46 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +70 -37
- package/metadata/MetadataValidator.d.ts +2 -9
- package/metadata/MetadataValidator.js +22 -38
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +480 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +8 -4
- package/naming-strategy/AbstractNamingStrategy.js +8 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +14 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +6 -13
- package/platforms/Platform.js +17 -43
- package/serialization/EntitySerializer.d.ts +5 -0
- package/serialization/EntitySerializer.js +47 -27
- package/serialization/EntityTransformer.js +28 -18
- package/serialization/SerializationContext.d.ts +6 -6
- package/serialization/SerializationContext.js +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +8 -6
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +124 -86
- package/typings.js +50 -42
- package/unit-of-work/ChangeSet.d.ts +2 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +14 -12
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +65 -33
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/UnitOfWork.d.ts +10 -3
- package/unit-of-work/UnitOfWork.js +139 -96
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +18 -16
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +753 -207
- package/utils/Configuration.js +145 -190
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +0 -3
- package/utils/Cursor.js +9 -6
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +65 -17
- package/utils/EntityComparator.d.ts +13 -9
- package/utils/EntityComparator.js +85 -43
- package/utils/QueryHelper.d.ts +14 -6
- package/utils/QueryHelper.js +87 -25
- package/utils/RawQueryFragment.d.ts +48 -25
- package/utils/RawQueryFragment.js +66 -70
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +12 -119
- package/utils/Utils.js +97 -373
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +32 -0
- package/utils/fs-utils.js +178 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -402
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { basename, extname } from 'node:path';
|
|
2
|
-
import globby from 'globby';
|
|
3
1
|
import { EntityMetadata, } from '../typings.js';
|
|
4
2
|
import { Utils } from '../utils/Utils.js';
|
|
5
3
|
import { MetadataValidator } from './MetadataValidator.js';
|
|
@@ -7,16 +5,16 @@ import { MetadataStorage } from './MetadataStorage.js';
|
|
|
7
5
|
import { EntitySchema } from './EntitySchema.js';
|
|
8
6
|
import { Cascade, ReferenceKind } from '../enums.js';
|
|
9
7
|
import { MetadataError } from '../errors.js';
|
|
10
|
-
import {
|
|
8
|
+
import { t, Type } from '../types/index.js';
|
|
11
9
|
import { colors } from '../logging/colors.js';
|
|
12
|
-
import { raw,
|
|
10
|
+
import { raw, Raw } from '../utils/RawQueryFragment.js';
|
|
11
|
+
import { BaseEntity } from '../entity/BaseEntity.js';
|
|
13
12
|
export class MetadataDiscovery {
|
|
14
13
|
metadata;
|
|
15
14
|
platform;
|
|
16
15
|
config;
|
|
17
16
|
namingStrategy;
|
|
18
17
|
metadataProvider;
|
|
19
|
-
cache;
|
|
20
18
|
logger;
|
|
21
19
|
schemaHelper;
|
|
22
20
|
validator = new MetadataValidator();
|
|
@@ -27,11 +25,11 @@ export class MetadataDiscovery {
|
|
|
27
25
|
this.config = config;
|
|
28
26
|
this.namingStrategy = this.config.getNamingStrategy();
|
|
29
27
|
this.metadataProvider = this.config.getMetadataProvider();
|
|
30
|
-
this.cache = this.config.getMetadataCacheAdapter();
|
|
31
28
|
this.logger = this.config.getLogger();
|
|
32
29
|
this.schemaHelper = this.platform.getSchemaHelper();
|
|
33
30
|
}
|
|
34
31
|
async discover(preferTs = true) {
|
|
32
|
+
this.discovered.length = 0;
|
|
35
33
|
const startTime = Date.now();
|
|
36
34
|
this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)}`);
|
|
37
35
|
await this.findEntities(preferTs);
|
|
@@ -47,10 +45,12 @@ export class MetadataDiscovery {
|
|
|
47
45
|
await this.config.get('discovery').afterDiscovered?.(storage, this.platform);
|
|
48
46
|
return storage;
|
|
49
47
|
}
|
|
50
|
-
discoverSync(
|
|
48
|
+
discoverSync() {
|
|
49
|
+
this.discovered.length = 0;
|
|
51
50
|
const startTime = Date.now();
|
|
52
51
|
this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)} in sync mode`);
|
|
53
|
-
this.
|
|
52
|
+
const refs = this.config.get('entities');
|
|
53
|
+
this.discoverReferences(refs);
|
|
54
54
|
for (const meta of this.discovered) {
|
|
55
55
|
/* v8 ignore next */
|
|
56
56
|
void this.config.get('discovery').onMetadata?.(meta, this.platform);
|
|
@@ -70,15 +70,48 @@ export class MetadataDiscovery {
|
|
|
70
70
|
.sort((a, b) => b.root.name.localeCompare(a.root.name))
|
|
71
71
|
.forEach(meta => {
|
|
72
72
|
this.platform.validateMetadata(meta);
|
|
73
|
-
discovered.set(meta.
|
|
73
|
+
discovered.set(meta.class, meta);
|
|
74
74
|
});
|
|
75
|
+
for (const meta of discovered) {
|
|
76
|
+
meta.root = discovered.get(meta.root.class);
|
|
77
|
+
}
|
|
75
78
|
return discovered;
|
|
76
79
|
}
|
|
80
|
+
initAccessors(meta) {
|
|
81
|
+
for (const prop of Object.values(meta.properties)) {
|
|
82
|
+
if (!prop.accessor || meta.properties[prop.accessor]) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
|
|
86
|
+
if (desc?.get || desc?.set) {
|
|
87
|
+
this.initFieldName(prop);
|
|
88
|
+
const accessor = prop.name;
|
|
89
|
+
prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
|
|
90
|
+
if (prop.accessor === true) {
|
|
91
|
+
prop.getter = prop.setter = true;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
prop.getter = prop.setter = false;
|
|
95
|
+
}
|
|
96
|
+
prop.accessor = accessor;
|
|
97
|
+
prop.serializedName ??= accessor;
|
|
98
|
+
Utils.renameKey(meta.properties, accessor, prop.name);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
const name = prop.name;
|
|
102
|
+
prop.name = prop.accessor;
|
|
103
|
+
this.initFieldName(prop);
|
|
104
|
+
prop.serializedName ??= prop.accessor;
|
|
105
|
+
prop.name = name;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
77
109
|
processDiscoveredEntities(discovered) {
|
|
78
110
|
for (const meta of discovered) {
|
|
79
111
|
let i = 1;
|
|
80
112
|
Object.values(meta.properties).forEach(prop => meta.propertyOrder.set(prop.name, i++));
|
|
81
113
|
Object.values(meta.properties).forEach(prop => this.initPolyEmbeddables(prop, discovered));
|
|
114
|
+
this.initAccessors(meta);
|
|
82
115
|
}
|
|
83
116
|
// ignore base entities (not annotated with @Entity)
|
|
84
117
|
const filtered = discovered.filter(meta => meta.root.name);
|
|
@@ -86,66 +119,61 @@ export class MetadataDiscovery {
|
|
|
86
119
|
filtered.sort((a, b) => !a.embeddable === !b.embeddable ? 0 : (a.embeddable ? 1 : -1));
|
|
87
120
|
filtered.forEach(meta => this.initSingleTableInheritance(meta, filtered));
|
|
88
121
|
filtered.forEach(meta => this.defineBaseEntityProperties(meta));
|
|
89
|
-
filtered.forEach(meta =>
|
|
122
|
+
filtered.forEach(meta => {
|
|
123
|
+
const newMeta = EntitySchema.fromMetadata(meta).init().meta;
|
|
124
|
+
return this.metadata.set(newMeta.class, newMeta);
|
|
125
|
+
});
|
|
90
126
|
filtered.forEach(meta => this.initAutoincrement(meta));
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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));
|
|
97
137
|
filtered.forEach(meta => this.initAutoincrement(meta)); // once again after we init custom types
|
|
98
138
|
filtered.forEach(meta => this.initCheckConstraints(meta));
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
prop.trackChanges = false;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
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));
|
|
111
146
|
filtered.forEach(meta => this.autoWireBidirectionalProperties(meta));
|
|
112
|
-
filtered.forEach(meta => this.findReferencingProperties(meta, filtered));
|
|
113
147
|
for (const meta of filtered) {
|
|
114
148
|
discovered.push(...this.processEntity(meta));
|
|
115
149
|
}
|
|
116
150
|
discovered.forEach(meta => meta.sync(true));
|
|
117
|
-
|
|
118
|
-
// override the path in the options, so we can log it from the CLI in `cache:generate` command
|
|
119
|
-
if (combinedCachePath) {
|
|
120
|
-
this.config.get('metadataCache').combined = combinedCachePath;
|
|
121
|
-
}
|
|
151
|
+
this.metadataProvider.combineCache();
|
|
122
152
|
return discovered.map(meta => {
|
|
123
|
-
meta = this.metadata.get(meta.
|
|
153
|
+
meta = this.metadata.get(meta.class);
|
|
124
154
|
meta.sync(true);
|
|
155
|
+
this.findReferencingProperties(meta, filtered);
|
|
125
156
|
return meta;
|
|
126
157
|
});
|
|
127
158
|
}
|
|
128
|
-
findEntities(preferTs
|
|
129
|
-
this.
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const paths =
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
159
|
+
async findEntities(preferTs) {
|
|
160
|
+
const { entities, entitiesTs, baseDir } = this.config.getAll();
|
|
161
|
+
const targets = (preferTs && entitiesTs.length > 0) ? entitiesTs : entities;
|
|
162
|
+
const processed = [];
|
|
163
|
+
const paths = [];
|
|
164
|
+
for (const entity of targets) {
|
|
165
|
+
if (typeof entity === 'string') {
|
|
166
|
+
paths.push(entity);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
processed.push(entity);
|
|
137
170
|
}
|
|
138
|
-
return this.discoverDirectories(paths).then(() => {
|
|
139
|
-
this.discoverReferences(refs);
|
|
140
|
-
this.discoverMissingTargets();
|
|
141
|
-
this.validator.validateDiscovered(this.discovered, options);
|
|
142
|
-
return this.discovered;
|
|
143
|
-
});
|
|
144
171
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
172
|
+
if (paths.length > 0) {
|
|
173
|
+
const { discoverEntities } = await import('@mikro-orm/core/file-discovery');
|
|
174
|
+
processed.push(...await discoverEntities(paths, { baseDir }));
|
|
175
|
+
}
|
|
176
|
+
return this.discoverReferences(processed);
|
|
149
177
|
}
|
|
150
178
|
discoverMissingTargets() {
|
|
151
179
|
const unwrap = (type) => type
|
|
@@ -154,17 +182,22 @@ export class MetadataDiscovery {
|
|
|
154
182
|
.replace(/\((.*)\)/, '$1'); // unwrap union types
|
|
155
183
|
const missing = [];
|
|
156
184
|
this.discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
|
|
157
|
-
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
+
}
|
|
162
193
|
}
|
|
163
|
-
if (prop.kind !== ReferenceKind.SCALAR
|
|
164
|
-
const target = typeof prop.entity === 'function'
|
|
194
|
+
if (prop.kind !== ReferenceKind.SCALAR) {
|
|
195
|
+
const target = typeof prop.entity === 'function' && !prop.entity.prototype
|
|
165
196
|
? prop.entity()
|
|
166
197
|
: prop.type;
|
|
167
|
-
|
|
198
|
+
if (!unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
|
|
199
|
+
missing.push(...Utils.asArray(target));
|
|
200
|
+
}
|
|
168
201
|
}
|
|
169
202
|
}));
|
|
170
203
|
if (missing.length > 0) {
|
|
@@ -173,122 +206,99 @@ export class MetadataDiscovery {
|
|
|
173
206
|
}
|
|
174
207
|
tryDiscoverTargets(targets) {
|
|
175
208
|
for (const target of targets) {
|
|
176
|
-
|
|
177
|
-
|
|
209
|
+
const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
|
|
210
|
+
if (isDiscoverable && target.name && !this.metadata.has(target)) {
|
|
211
|
+
this.discoverReferences([target], false);
|
|
178
212
|
this.discoverMissingTargets();
|
|
179
213
|
}
|
|
180
214
|
}
|
|
181
215
|
}
|
|
182
|
-
|
|
183
|
-
paths = paths.map(path => Utils.normalizePath(path));
|
|
184
|
-
const files = await globby(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
|
|
185
|
-
this.logger.log('discovery', `- processing ${colors.cyan('' + files.length)} files`);
|
|
186
|
-
const found = [];
|
|
187
|
-
for (const filepath of files) {
|
|
188
|
-
const filename = basename(filepath);
|
|
189
|
-
if (!filename.match(/\.[cm]?[jt]s$/) ||
|
|
190
|
-
filename.endsWith('.js.map') ||
|
|
191
|
-
filename.match(/\.d\.[cm]?ts/) ||
|
|
192
|
-
filename.startsWith('.') ||
|
|
193
|
-
filename.match(/index\.[cm]?[jt]s$/)) {
|
|
194
|
-
this.logger.log('discovery', `- ignoring file ${filename}`);
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
const name = this.namingStrategy.getClassName(filename);
|
|
198
|
-
const path = Utils.normalizePath(this.config.get('baseDir'), filepath);
|
|
199
|
-
const targets = await this.getEntityClassOrSchema(path, name);
|
|
200
|
-
for (const target of targets) {
|
|
201
|
-
if (!(target instanceof Function) && !(target instanceof EntitySchema)) {
|
|
202
|
-
this.logger.log('discovery', `- ignoring file ${filename}`);
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
const entity = this.prepare(target);
|
|
206
|
-
const schema = this.getSchema(entity, path);
|
|
207
|
-
const meta = schema.init().meta;
|
|
208
|
-
this.metadata.set(meta.className, meta);
|
|
209
|
-
found.push([schema, path]);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
for (const [schema, path] of found) {
|
|
213
|
-
this.discoverEntity(schema, path);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
discoverReferences(refs) {
|
|
216
|
+
discoverReferences(refs, validate = true) {
|
|
217
217
|
const found = [];
|
|
218
218
|
for (const entity of refs) {
|
|
219
|
-
|
|
219
|
+
if (typeof entity === 'string') {
|
|
220
|
+
throw new Error('Folder based discovery requires the async `MikroORM.init()` method.');
|
|
221
|
+
}
|
|
222
|
+
const schema = this.getSchema(entity);
|
|
220
223
|
const meta = schema.init().meta;
|
|
221
|
-
this.metadata.set(meta.
|
|
224
|
+
this.metadata.set(meta.class, meta);
|
|
222
225
|
found.push(schema);
|
|
223
226
|
}
|
|
224
227
|
// discover parents (base entities) automatically
|
|
225
228
|
for (const meta of this.metadata) {
|
|
226
229
|
let parent = meta.extends;
|
|
227
|
-
if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.
|
|
228
|
-
this.discoverReferences([parent]);
|
|
230
|
+
if (parent instanceof EntitySchema && !this.metadata.has(parent.init().meta.class)) {
|
|
231
|
+
this.discoverReferences([parent], false);
|
|
229
232
|
}
|
|
230
|
-
|
|
233
|
+
if (typeof parent === 'function' && parent.name && !this.metadata.has(parent)) {
|
|
234
|
+
this.discoverReferences([parent], false);
|
|
235
|
+
}
|
|
236
|
+
/* v8 ignore next */
|
|
231
237
|
if (!meta.class) {
|
|
232
238
|
continue;
|
|
233
239
|
}
|
|
234
240
|
parent = Object.getPrototypeOf(meta.class);
|
|
235
|
-
if (parent.name !== '' && !this.metadata.has(parent
|
|
236
|
-
this.discoverReferences([parent]);
|
|
241
|
+
if (parent.name !== '' && !this.metadata.has(parent) && parent !== BaseEntity) {
|
|
242
|
+
this.discoverReferences([parent], false);
|
|
237
243
|
}
|
|
238
244
|
}
|
|
239
245
|
for (const schema of found) {
|
|
240
246
|
this.discoverEntity(schema);
|
|
241
247
|
}
|
|
248
|
+
this.discoverMissingTargets();
|
|
249
|
+
if (validate) {
|
|
250
|
+
this.validator.validateDiscovered(this.discovered, this.config.get('discovery'));
|
|
251
|
+
}
|
|
242
252
|
return this.discovered.filter(meta => found.find(m => m.name === meta.className));
|
|
243
253
|
}
|
|
244
|
-
reset(
|
|
245
|
-
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));
|
|
246
256
|
if (exists !== -1) {
|
|
247
|
-
this.metadata.reset(this.discovered[exists].
|
|
257
|
+
this.metadata.reset(this.discovered[exists].class);
|
|
248
258
|
this.discovered.splice(exists, 1);
|
|
249
259
|
}
|
|
250
260
|
}
|
|
251
|
-
|
|
252
|
-
/* v8 ignore next 3 */
|
|
253
|
-
if ('schema' in entity && entity.schema instanceof EntitySchema) {
|
|
254
|
-
return entity.schema;
|
|
255
|
-
}
|
|
261
|
+
getSchema(entity) {
|
|
256
262
|
if (EntitySchema.REGISTRY.has(entity)) {
|
|
257
|
-
|
|
263
|
+
entity = EntitySchema.REGISTRY.get(entity);
|
|
258
264
|
}
|
|
259
|
-
return entity;
|
|
260
|
-
}
|
|
261
|
-
getSchema(entity, filepath) {
|
|
262
265
|
if (entity instanceof EntitySchema) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
MetadataStorage.getMetadata(entity.meta.className, filepath);
|
|
266
|
-
}
|
|
267
|
-
return entity;
|
|
266
|
+
const meta = Utils.copy(entity.meta, false);
|
|
267
|
+
return EntitySchema.fromMetadata(meta);
|
|
268
268
|
}
|
|
269
269
|
const path = entity[MetadataStorage.PATH_SYMBOL];
|
|
270
270
|
if (path) {
|
|
271
271
|
const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
|
|
272
|
-
meta.path =
|
|
273
|
-
this.metadata.set(entity
|
|
272
|
+
meta.path = path;
|
|
273
|
+
this.metadata.set(entity, meta);
|
|
274
274
|
}
|
|
275
|
-
const exists = this.metadata.has(entity
|
|
276
|
-
const meta = this.metadata.get(entity
|
|
275
|
+
const exists = this.metadata.has(entity);
|
|
276
|
+
const meta = this.metadata.get(entity, true);
|
|
277
277
|
meta.abstract ??= !(exists && meta.name);
|
|
278
278
|
const schema = EntitySchema.fromMetadata(meta);
|
|
279
279
|
schema.setClass(entity);
|
|
280
280
|
return schema;
|
|
281
281
|
}
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
getRootEntity(meta) {
|
|
283
|
+
const base = meta.extends && this.metadata.find(meta.extends);
|
|
284
|
+
if (!base || base === meta) { // make sure we do not fall into infinite loop
|
|
285
|
+
return meta;
|
|
286
|
+
}
|
|
287
|
+
const root = this.getRootEntity(base);
|
|
288
|
+
if (root.discriminatorColumn) {
|
|
289
|
+
return root;
|
|
290
|
+
}
|
|
291
|
+
return meta;
|
|
292
|
+
}
|
|
293
|
+
discoverEntity(schema) {
|
|
284
294
|
const meta = schema.meta;
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
const
|
|
295
|
+
const path = meta.path;
|
|
296
|
+
this.logger.log('discovery', `- processing entity ${colors.cyan(meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
|
|
297
|
+
const root = this.getRootEntity(meta);
|
|
298
|
+
schema.meta.path = meta.path;
|
|
299
|
+
const cache = this.metadataProvider.getCachedMetadata(meta, root);
|
|
288
300
|
if (cache) {
|
|
289
301
|
this.logger.log('discovery', `- using cached metadata for entity ${colors.cyan(meta.className)}`);
|
|
290
|
-
this.metadataProvider.loadFromCache(meta, cache);
|
|
291
|
-
meta.root = root;
|
|
292
302
|
this.discovered.push(meta);
|
|
293
303
|
return;
|
|
294
304
|
}
|
|
@@ -297,50 +307,18 @@ export class MetadataDiscovery {
|
|
|
297
307
|
this.inferDefaultValue(meta, prop);
|
|
298
308
|
}
|
|
299
309
|
// if the definition is using EntitySchema we still want it to go through the metadata provider to validate no types are missing
|
|
300
|
-
this.metadataProvider.loadEntityMetadata(meta
|
|
301
|
-
if (!meta.
|
|
310
|
+
this.metadataProvider.loadEntityMetadata(meta);
|
|
311
|
+
if (!meta.tableName && meta.name) {
|
|
302
312
|
const entityName = root.discriminatorColumn ? root.name : meta.name;
|
|
303
|
-
meta.
|
|
313
|
+
meta.tableName = this.namingStrategy.classToTableName(entityName);
|
|
304
314
|
}
|
|
305
|
-
|
|
306
|
-
this.saveToCache(meta);
|
|
315
|
+
this.metadataProvider.saveToCache(meta);
|
|
307
316
|
meta.root = root;
|
|
308
317
|
this.discovered.push(meta);
|
|
309
318
|
}
|
|
310
|
-
saveToCache(meta) {
|
|
311
|
-
if (!this.metadataProvider.useCache()) {
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
const copy = Utils.copy(meta, false);
|
|
315
|
-
for (const prop of copy.props) {
|
|
316
|
-
if (Type.isMappedType(prop.type)) {
|
|
317
|
-
Reflect.deleteProperty(prop, 'type');
|
|
318
|
-
Reflect.deleteProperty(prop, 'customType');
|
|
319
|
-
}
|
|
320
|
-
if (prop.default) {
|
|
321
|
-
const raw = RawQueryFragment.getKnownFragment(prop.default);
|
|
322
|
-
if (raw) {
|
|
323
|
-
prop.defaultRaw ??= this.platform.formatQuery(raw.sql, raw.params);
|
|
324
|
-
Reflect.deleteProperty(prop, 'default');
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
Reflect.deleteProperty(prop, 'targetMeta');
|
|
328
|
-
}
|
|
329
|
-
[
|
|
330
|
-
'prototype', 'props', 'referencingProperties', 'propertyOrder', 'relations',
|
|
331
|
-
'concurrencyCheckKeys', 'checks',
|
|
332
|
-
].forEach(key => delete copy[key]);
|
|
333
|
-
// base entity without properties might not have path, but nothing to cache there
|
|
334
|
-
if (meta.path) {
|
|
335
|
-
this.cache.set(meta.className + extname(meta.path), copy, meta.path);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
319
|
initNullability(prop) {
|
|
339
|
-
if (prop.kind === ReferenceKind.MANY_TO_ONE) {
|
|
340
|
-
return Utils.defaultValue(prop, 'nullable', prop.optional || prop.cascade.includes(Cascade.REMOVE) || prop.cascade.includes(Cascade.ALL));
|
|
341
|
-
}
|
|
342
320
|
if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
|
343
|
-
return Utils.defaultValue(prop, 'nullable', prop.optional || !prop.owner
|
|
321
|
+
return Utils.defaultValue(prop, 'nullable', prop.optional || !prop.owner);
|
|
344
322
|
}
|
|
345
323
|
return Utils.defaultValue(prop, 'nullable', prop.optional);
|
|
346
324
|
}
|
|
@@ -375,7 +353,7 @@ export class MetadataDiscovery {
|
|
|
375
353
|
if (prop.joinColumns.length !== prop.columnTypes.length) {
|
|
376
354
|
prop.columnTypes = prop.joinColumns.flatMap(field => {
|
|
377
355
|
const matched = meta.props.find(p => p.fieldNames?.includes(field));
|
|
378
|
-
/* v8 ignore next
|
|
356
|
+
/* v8 ignore next */
|
|
379
357
|
if (!matched) {
|
|
380
358
|
throw MetadataError.fromWrongForeignKey(meta, prop, 'columnTypes');
|
|
381
359
|
}
|
|
@@ -402,7 +380,7 @@ export class MetadataDiscovery {
|
|
|
402
380
|
}
|
|
403
381
|
}
|
|
404
382
|
initManyToOneFieldName(prop, name) {
|
|
405
|
-
const meta2 =
|
|
383
|
+
const meta2 = prop.targetMeta;
|
|
406
384
|
const ret = [];
|
|
407
385
|
for (const primaryKey of meta2.primaryKeys) {
|
|
408
386
|
this.initFieldName(meta2.properties[primaryKey]);
|
|
@@ -413,11 +391,11 @@ export class MetadataDiscovery {
|
|
|
413
391
|
return ret;
|
|
414
392
|
}
|
|
415
393
|
initManyToManyFieldName(prop, name) {
|
|
416
|
-
const meta2 =
|
|
394
|
+
const meta2 = prop.targetMeta;
|
|
417
395
|
return meta2.primaryKeys.map(() => this.namingStrategy.propertyToColumnName(name));
|
|
418
396
|
}
|
|
419
397
|
initManyToManyFields(meta, prop) {
|
|
420
|
-
const meta2 =
|
|
398
|
+
const meta2 = prop.targetMeta;
|
|
421
399
|
Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
|
|
422
400
|
const pivotMeta = this.metadata.find(prop.pivotEntity);
|
|
423
401
|
const props = Object.values(pivotMeta?.properties ?? {});
|
|
@@ -438,26 +416,26 @@ export class MetadataDiscovery {
|
|
|
438
416
|
prop.inverseJoinColumns ??= second.fieldNames;
|
|
439
417
|
}
|
|
440
418
|
if (!prop.pivotTable && prop.owner && this.platform.usesPivotTable()) {
|
|
441
|
-
prop.pivotTable = this.namingStrategy.joinTableName(meta.
|
|
419
|
+
prop.pivotTable = this.namingStrategy.joinTableName(meta.className, meta2.tableName, prop.name, meta.tableName);
|
|
442
420
|
}
|
|
443
421
|
if (prop.mappedBy) {
|
|
444
422
|
const prop2 = meta2.properties[prop.mappedBy];
|
|
445
423
|
this.initManyToManyFields(meta2, prop2);
|
|
446
424
|
prop.pivotTable = prop2.pivotTable;
|
|
447
|
-
prop.pivotEntity = prop2.pivotEntity
|
|
425
|
+
prop.pivotEntity = prop2.pivotEntity;
|
|
448
426
|
prop.fixedOrder = prop2.fixedOrder;
|
|
449
427
|
prop.fixedOrderColumn = prop2.fixedOrderColumn;
|
|
450
428
|
prop.joinColumns = prop2.inverseJoinColumns;
|
|
451
429
|
prop.inverseJoinColumns = prop2.joinColumns;
|
|
452
430
|
}
|
|
453
431
|
prop.referencedColumnNames ??= Utils.flatten(meta.primaryKeys.map(primaryKey => meta.properties[primaryKey].fieldNames));
|
|
454
|
-
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.namingStrategy.joinKeyColumnName(meta.root.className, referencedColumnName, meta.compositePK));
|
|
432
|
+
prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.namingStrategy.joinKeyColumnName(meta.root.className, referencedColumnName, meta.compositePK, meta.root.tableName));
|
|
455
433
|
prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className);
|
|
456
434
|
}
|
|
457
435
|
initManyToOneFields(prop) {
|
|
458
|
-
const meta2 =
|
|
436
|
+
const meta2 = prop.targetMeta;
|
|
459
437
|
const fieldNames = Utils.flatten(meta2.primaryKeys.map(primaryKey => meta2.properties[primaryKey].fieldNames));
|
|
460
|
-
Utils.defaultValue(prop, 'referencedTableName', meta2.
|
|
438
|
+
Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
|
|
461
439
|
if (!prop.joinColumns) {
|
|
462
440
|
prop.joinColumns = fieldNames.map(fieldName => this.namingStrategy.joinKeyColumnName(prop.name, fieldName, fieldNames.length > 1));
|
|
463
441
|
}
|
|
@@ -466,7 +444,7 @@ export class MetadataDiscovery {
|
|
|
466
444
|
}
|
|
467
445
|
}
|
|
468
446
|
initOneToManyFields(prop) {
|
|
469
|
-
const meta2 =
|
|
447
|
+
const meta2 = prop.targetMeta;
|
|
470
448
|
if (!prop.joinColumns) {
|
|
471
449
|
prop.joinColumns = [this.namingStrategy.joinColumnName(prop.name)];
|
|
472
450
|
}
|
|
@@ -484,7 +462,7 @@ export class MetadataDiscovery {
|
|
|
484
462
|
pks[0].deleteRule ??= 'cascade';
|
|
485
463
|
}
|
|
486
464
|
meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
|
|
487
|
-
this.validator.validateEntityDefinition(this.metadata, meta.
|
|
465
|
+
this.validator.validateEntityDefinition(this.metadata, meta.class, this.config.get('discovery'));
|
|
488
466
|
for (const prop of Object.values(meta.properties)) {
|
|
489
467
|
this.initNullability(prop);
|
|
490
468
|
this.applyNamingStrategy(meta, prop);
|
|
@@ -497,15 +475,21 @@ export class MetadataDiscovery {
|
|
|
497
475
|
}
|
|
498
476
|
this.initOwnColumns(meta);
|
|
499
477
|
meta.simplePK = pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
|
|
500
|
-
meta.serializedPrimaryKey
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
serializedPKProp.persist = false;
|
|
478
|
+
meta.serializedPrimaryKey ??= meta.props.find(prop => prop.serializedPrimaryKey)?.name;
|
|
479
|
+
if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
|
|
480
|
+
meta.properties[meta.serializedPrimaryKey].persist ??= false;
|
|
504
481
|
}
|
|
505
482
|
if (this.platform.usesPivotTable()) {
|
|
506
483
|
return Object.values(meta.properties)
|
|
507
484
|
.filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
|
|
508
|
-
.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
|
+
});
|
|
509
493
|
}
|
|
510
494
|
return [];
|
|
511
495
|
}
|
|
@@ -522,8 +506,11 @@ export class MetadataDiscovery {
|
|
|
522
506
|
['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
|
|
523
507
|
const value = prop[type];
|
|
524
508
|
if (value instanceof Function) {
|
|
525
|
-
const meta2 = this.metadata.get(prop.
|
|
509
|
+
const meta2 = prop.targetMeta ?? this.metadata.get(prop.target);
|
|
526
510
|
prop[type] = value(meta2.properties)?.name;
|
|
511
|
+
if (type === 'pivotEntity' && value) {
|
|
512
|
+
prop[type] = value(meta2.properties);
|
|
513
|
+
}
|
|
527
514
|
if (prop[type] == null) {
|
|
528
515
|
throw MetadataError.fromWrongReference(meta, prop, type);
|
|
529
516
|
}
|
|
@@ -539,9 +526,9 @@ export class MetadataDiscovery {
|
|
|
539
526
|
}
|
|
540
527
|
else if (fks.length >= 2) {
|
|
541
528
|
[first, second] = fks;
|
|
542
|
-
/* v8 ignore next 3 */
|
|
543
529
|
}
|
|
544
530
|
else {
|
|
531
|
+
/* v8 ignore next */
|
|
545
532
|
return [];
|
|
546
533
|
}
|
|
547
534
|
// wrong FK order, first FK needs to point to the owning side
|
|
@@ -555,7 +542,9 @@ export class MetadataDiscovery {
|
|
|
555
542
|
return [first, second];
|
|
556
543
|
}
|
|
557
544
|
definePivotTableEntity(meta, prop) {
|
|
558
|
-
const pivotMeta =
|
|
545
|
+
const pivotMeta = prop.pivotEntity
|
|
546
|
+
? this.metadata.find(prop.pivotEntity)
|
|
547
|
+
: this.metadata.getByClassName(prop.pivotTable, false);
|
|
559
548
|
// ensure inverse side exists so we can join it when populating via pivot tables
|
|
560
549
|
if (!prop.inversedBy && prop.targetMeta) {
|
|
561
550
|
const inverseName = `${meta.className}_${prop.name}__inverse`;
|
|
@@ -564,6 +553,8 @@ export class MetadataDiscovery {
|
|
|
564
553
|
name: inverseName,
|
|
565
554
|
kind: ReferenceKind.MANY_TO_MANY,
|
|
566
555
|
type: meta.className,
|
|
556
|
+
target: meta.class,
|
|
557
|
+
targetMeta: meta,
|
|
567
558
|
mappedBy: prop.name,
|
|
568
559
|
pivotEntity: prop.pivotEntity,
|
|
569
560
|
pivotTable: prop.pivotTable,
|
|
@@ -572,55 +563,51 @@ export class MetadataDiscovery {
|
|
|
572
563
|
};
|
|
573
564
|
this.applyNamingStrategy(prop.targetMeta, inverseProp);
|
|
574
565
|
this.initCustomType(prop.targetMeta, inverseProp);
|
|
575
|
-
this.initRelation(inverseProp);
|
|
576
566
|
prop.targetMeta.properties[inverseName] = inverseProp;
|
|
577
567
|
}
|
|
578
568
|
if (pivotMeta) {
|
|
569
|
+
prop.pivotEntity = pivotMeta.class;
|
|
579
570
|
this.ensureCorrectFKOrderInPivotEntity(pivotMeta, prop);
|
|
580
571
|
return pivotMeta;
|
|
581
572
|
}
|
|
582
|
-
const exists = this.metadata.find(prop.pivotTable);
|
|
583
|
-
if (exists) {
|
|
584
|
-
prop.pivotEntity = exists.className;
|
|
585
|
-
return exists;
|
|
586
|
-
}
|
|
587
573
|
let tableName = prop.pivotTable;
|
|
588
574
|
let schemaName;
|
|
589
575
|
if (prop.pivotTable.includes('.')) {
|
|
590
576
|
[schemaName, tableName] = prop.pivotTable.split('.');
|
|
591
577
|
}
|
|
592
578
|
schemaName ??= meta.schema;
|
|
593
|
-
const
|
|
594
|
-
const
|
|
579
|
+
const targetMeta = prop.targetMeta;
|
|
580
|
+
const targetType = targetMeta.className;
|
|
581
|
+
const pivotMeta2 = new EntityMetadata({
|
|
595
582
|
name: prop.pivotTable,
|
|
596
583
|
className: prop.pivotTable,
|
|
597
584
|
collection: tableName,
|
|
598
585
|
schema: schemaName,
|
|
599
586
|
pivotTable: true,
|
|
600
587
|
});
|
|
601
|
-
prop.pivotEntity =
|
|
588
|
+
prop.pivotEntity = pivotMeta2.class;
|
|
602
589
|
if (prop.fixedOrder) {
|
|
603
|
-
const primaryProp = this.defineFixedOrderProperty(prop,
|
|
604
|
-
|
|
590
|
+
const primaryProp = this.defineFixedOrderProperty(prop, targetMeta);
|
|
591
|
+
pivotMeta2.properties[primaryProp.name] = primaryProp;
|
|
605
592
|
}
|
|
606
593
|
else {
|
|
607
|
-
|
|
594
|
+
pivotMeta2.compositePK = true;
|
|
608
595
|
}
|
|
609
596
|
// handle self-referenced m:n with same default field names
|
|
610
597
|
if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
|
|
611
|
-
prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.
|
|
612
|
-
prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.
|
|
598
|
+
prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_1', name, meta.compositePK));
|
|
599
|
+
prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_2', name, meta.compositePK));
|
|
613
600
|
if (prop.inversedBy) {
|
|
614
|
-
const prop2 =
|
|
601
|
+
const prop2 = targetMeta.properties[prop.inversedBy];
|
|
615
602
|
prop2.inverseJoinColumns = prop.joinColumns;
|
|
616
603
|
prop2.joinColumns = prop.inverseJoinColumns;
|
|
617
604
|
}
|
|
618
605
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
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);
|
|
622
609
|
}
|
|
623
|
-
defineFixedOrderProperty(prop,
|
|
610
|
+
defineFixedOrderProperty(prop, targetMeta) {
|
|
624
611
|
const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
|
|
625
612
|
const primaryProp = {
|
|
626
613
|
name: pk,
|
|
@@ -634,7 +621,7 @@ export class MetadataDiscovery {
|
|
|
634
621
|
this.initColumnType(primaryProp);
|
|
635
622
|
prop.fixedOrderColumn = pk;
|
|
636
623
|
if (prop.inversedBy) {
|
|
637
|
-
const prop2 =
|
|
624
|
+
const prop2 = targetMeta.properties[prop.inversedBy];
|
|
638
625
|
prop2.fixedOrder = true;
|
|
639
626
|
prop2.fixedOrderColumn = pk;
|
|
640
627
|
}
|
|
@@ -643,7 +630,8 @@ export class MetadataDiscovery {
|
|
|
643
630
|
definePivotProperty(prop, name, type, inverse, owner, selfReferencing) {
|
|
644
631
|
const ret = {
|
|
645
632
|
name,
|
|
646
|
-
type,
|
|
633
|
+
type: Utils.className(type),
|
|
634
|
+
target: type,
|
|
647
635
|
kind: ReferenceKind.MANY_TO_ONE,
|
|
648
636
|
cascade: [Cascade.ALL],
|
|
649
637
|
fixedOrder: prop.fixedOrder,
|
|
@@ -653,6 +641,7 @@ export class MetadataDiscovery {
|
|
|
653
641
|
autoincrement: false,
|
|
654
642
|
updateRule: prop.updateRule,
|
|
655
643
|
deleteRule: prop.deleteRule,
|
|
644
|
+
createForeignKeyConstraint: prop.createForeignKeyConstraint,
|
|
656
645
|
};
|
|
657
646
|
if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
|
|
658
647
|
ret.updateRule ??= 'no action';
|
|
@@ -700,7 +689,7 @@ export class MetadataDiscovery {
|
|
|
700
689
|
Object.values(meta.properties)
|
|
701
690
|
.filter(prop => prop.kind !== ReferenceKind.SCALAR && !prop.owner && prop.mappedBy)
|
|
702
691
|
.forEach(prop => {
|
|
703
|
-
const meta2 =
|
|
692
|
+
const meta2 = prop.targetMeta;
|
|
704
693
|
const prop2 = meta2.properties[prop.mappedBy];
|
|
705
694
|
if (prop2 && !prop2.inversedBy) {
|
|
706
695
|
prop2.inversedBy = prop.name;
|
|
@@ -708,7 +697,7 @@ export class MetadataDiscovery {
|
|
|
708
697
|
});
|
|
709
698
|
}
|
|
710
699
|
defineBaseEntityProperties(meta) {
|
|
711
|
-
const base = meta.extends && this.metadata.get(
|
|
700
|
+
const base = meta.extends && this.metadata.get(meta.extends);
|
|
712
701
|
if (!base || base === meta) { // make sure we do not fall into infinite loop
|
|
713
702
|
return 0;
|
|
714
703
|
}
|
|
@@ -739,12 +728,9 @@ export class MetadataDiscovery {
|
|
|
739
728
|
Utils.keys(base.hooks).forEach(type => {
|
|
740
729
|
meta.hooks[type] = Utils.unique([...base.hooks[type], ...(meta.hooks[type] || [])]);
|
|
741
730
|
});
|
|
742
|
-
if (meta.constructorParams
|
|
731
|
+
if ((meta.constructorParams?.length ?? 0) === 0 && (base.constructorParams?.length ?? 0) > 0) {
|
|
743
732
|
meta.constructorParams = [...base.constructorParams];
|
|
744
733
|
}
|
|
745
|
-
if (meta.toJsonParams.length === 0 && base.toJsonParams.length > 0) {
|
|
746
|
-
meta.toJsonParams = [...base.toJsonParams];
|
|
747
|
-
}
|
|
748
734
|
return order;
|
|
749
735
|
}
|
|
750
736
|
initPolyEmbeddables(embeddedProp, discovered, visited = new Set()) {
|
|
@@ -820,22 +806,30 @@ export class MetadataDiscovery {
|
|
|
820
806
|
}
|
|
821
807
|
return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
|
|
822
808
|
};
|
|
809
|
+
const isParentArray = (prop) => {
|
|
810
|
+
if (prop.array) {
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
|
|
814
|
+
};
|
|
823
815
|
const rootProperty = getRootProperty(embeddedProp);
|
|
824
816
|
const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
|
|
825
817
|
const object = isParentObject(embeddedProp);
|
|
818
|
+
const array = isParentArray(embeddedProp);
|
|
826
819
|
this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
|
|
827
820
|
// the prefix of the parent cannot be a boolean; it already passed here
|
|
828
821
|
const prefix = this.getPrefix(embeddedProp, parentProperty);
|
|
829
822
|
const glue = object ? '~' : '_';
|
|
830
823
|
for (const prop of Object.values(embeddable.properties)) {
|
|
831
824
|
const name = (embeddedProp.embeddedPath?.join(glue) ?? embeddedProp.fieldNames[0] + glue) + prop.name;
|
|
832
|
-
meta.properties[name] = Utils.copy(prop
|
|
825
|
+
meta.properties[name] = Utils.copy(prop);
|
|
833
826
|
meta.properties[name].name = name;
|
|
834
827
|
meta.properties[name].embedded = [embeddedProp.name, prop.name];
|
|
835
828
|
meta.propertyOrder.set(name, (order += 0.01));
|
|
836
829
|
embeddedProp.embeddedProps[prop.name] = meta.properties[name];
|
|
837
830
|
meta.properties[name].persist ??= embeddedProp.persist;
|
|
838
|
-
|
|
831
|
+
const refInArray = array && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
|
|
832
|
+
if (embeddedProp.nullable || refInArray) {
|
|
839
833
|
meta.properties[name].nullable = true;
|
|
840
834
|
}
|
|
841
835
|
if (meta.properties[name].fieldNames) {
|
|
@@ -873,6 +867,7 @@ export class MetadataDiscovery {
|
|
|
873
867
|
meta.properties[name].persist = false; // only virtual as we store the whole object
|
|
874
868
|
meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
|
|
875
869
|
meta.properties[name].object = true;
|
|
870
|
+
this.initCustomType(meta, meta.properties[name], false, true);
|
|
876
871
|
}
|
|
877
872
|
this.initEmbeddables(meta, meta.properties[name], visited);
|
|
878
873
|
}
|
|
@@ -895,7 +890,7 @@ export class MetadataDiscovery {
|
|
|
895
890
|
}
|
|
896
891
|
initSingleTableInheritance(meta, metadata) {
|
|
897
892
|
if (meta.root !== meta && !meta.__processed) {
|
|
898
|
-
meta.root = metadata.find(m => m.
|
|
893
|
+
meta.root = metadata.find(m => m.class === meta.root.class);
|
|
899
894
|
meta.root.__processed = true;
|
|
900
895
|
}
|
|
901
896
|
else {
|
|
@@ -904,17 +899,23 @@ export class MetadataDiscovery {
|
|
|
904
899
|
if (!meta.root.discriminatorColumn) {
|
|
905
900
|
return;
|
|
906
901
|
}
|
|
907
|
-
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 {
|
|
908
909
|
meta.root.discriminatorMap = {};
|
|
909
910
|
const children = metadata
|
|
910
|
-
.filter(m => m.root.
|
|
911
|
+
.filter(m => m.root.class === meta.root.class && !m.abstract)
|
|
911
912
|
.sort((a, b) => a.className.localeCompare(b.className));
|
|
912
913
|
for (const m of children) {
|
|
913
914
|
const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
|
|
914
|
-
meta.root.discriminatorMap[name] = m.
|
|
915
|
+
meta.root.discriminatorMap[name] = m.class;
|
|
915
916
|
}
|
|
916
917
|
}
|
|
917
|
-
meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([,
|
|
918
|
+
meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, cls]) => cls === meta.class)?.[0];
|
|
918
919
|
if (!meta.root.properties[meta.root.discriminatorColumn]) {
|
|
919
920
|
this.createDiscriminatorProperty(meta.root);
|
|
920
921
|
}
|
|
@@ -941,10 +942,10 @@ export class MetadataDiscovery {
|
|
|
941
942
|
newProp.items = Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
|
|
942
943
|
}
|
|
943
944
|
newProp.nullable = true;
|
|
944
|
-
newProp.inherited =
|
|
945
|
+
newProp.inherited = !meta.root.properties[prop.name];
|
|
945
946
|
meta.root.addProperty(newProp);
|
|
946
947
|
});
|
|
947
|
-
meta.
|
|
948
|
+
meta.tableName = meta.root.tableName;
|
|
948
949
|
meta.root.indexes = Utils.unique([...meta.root.indexes, ...meta.indexes]);
|
|
949
950
|
meta.root.uniques = Utils.unique([...meta.root.uniques, ...meta.uniques]);
|
|
950
951
|
meta.root.checks = Utils.unique([...meta.root.checks, ...meta.checks]);
|
|
@@ -966,7 +967,7 @@ export class MetadataDiscovery {
|
|
|
966
967
|
}
|
|
967
968
|
}
|
|
968
969
|
initCheckConstraints(meta) {
|
|
969
|
-
const map =
|
|
970
|
+
const map = meta.createColumnMappingObject();
|
|
970
971
|
for (const check of meta.checks) {
|
|
971
972
|
const columns = check.property ? meta.properties[check.property].fieldNames : [];
|
|
972
973
|
check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
|
|
@@ -976,7 +977,7 @@ export class MetadataDiscovery {
|
|
|
976
977
|
}
|
|
977
978
|
if (this.platform.usesEnumCheckConstraints() && !meta.embeddable) {
|
|
978
979
|
for (const prop of meta.props) {
|
|
979
|
-
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item =>
|
|
980
|
+
if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
|
|
980
981
|
this.initFieldName(prop);
|
|
981
982
|
meta.checks.push({
|
|
982
983
|
name: this.namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
|
|
@@ -1001,38 +1002,28 @@ export class MetadataDiscovery {
|
|
|
1001
1002
|
}
|
|
1002
1003
|
return;
|
|
1003
1004
|
}
|
|
1004
|
-
const map =
|
|
1005
|
+
const map = meta.createColumnMappingObject();
|
|
1005
1006
|
if (prop.generated instanceof Function) {
|
|
1006
1007
|
prop.generated = prop.generated(map);
|
|
1007
1008
|
}
|
|
1008
1009
|
}
|
|
1009
|
-
|
|
1010
|
-
return Object.values(meta.properties).reduce((o, prop) => {
|
|
1011
|
-
if (prop.fieldNames) {
|
|
1012
|
-
o[prop.name] = prop.fieldNames[0];
|
|
1013
|
-
}
|
|
1014
|
-
return o;
|
|
1015
|
-
}, {});
|
|
1016
|
-
}
|
|
1017
|
-
getDefaultVersionValue(prop) {
|
|
1010
|
+
getDefaultVersionValue(meta, prop) {
|
|
1018
1011
|
if (typeof prop.defaultRaw !== 'undefined') {
|
|
1019
1012
|
return prop.defaultRaw;
|
|
1020
1013
|
}
|
|
1021
|
-
/* v8 ignore next
|
|
1014
|
+
/* v8 ignore next */
|
|
1022
1015
|
if (prop.default != null) {
|
|
1023
1016
|
return '' + this.platform.quoteVersionValue(prop.default, prop);
|
|
1024
1017
|
}
|
|
1025
|
-
|
|
1018
|
+
this.initCustomType(meta, prop, true);
|
|
1019
|
+
const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
|
|
1020
|
+
if (type === 'Date') {
|
|
1026
1021
|
prop.length ??= this.platform.getDefaultVersionLength();
|
|
1027
1022
|
return this.platform.getCurrentTimestampSQL(prop.length);
|
|
1028
1023
|
}
|
|
1029
1024
|
return '1';
|
|
1030
1025
|
}
|
|
1031
1026
|
inferDefaultValue(meta, prop) {
|
|
1032
|
-
/* v8 ignore next 3 */
|
|
1033
|
-
if (!meta.class) {
|
|
1034
|
-
return;
|
|
1035
|
-
}
|
|
1036
1027
|
try {
|
|
1037
1028
|
// try to create two entity instances to detect the value is stable
|
|
1038
1029
|
const now = Date.now();
|
|
@@ -1060,12 +1051,12 @@ export class MetadataDiscovery {
|
|
|
1060
1051
|
return;
|
|
1061
1052
|
}
|
|
1062
1053
|
let val = prop.default;
|
|
1063
|
-
const raw =
|
|
1054
|
+
const raw = Raw.getKnownFragment(val);
|
|
1064
1055
|
if (raw) {
|
|
1065
1056
|
prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
|
|
1066
1057
|
return;
|
|
1067
1058
|
}
|
|
1068
|
-
if (
|
|
1059
|
+
if (Array.isArray(prop.default) && prop.customType) {
|
|
1069
1060
|
val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
|
|
1070
1061
|
}
|
|
1071
1062
|
prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
|
|
@@ -1093,13 +1084,13 @@ export class MetadataDiscovery {
|
|
|
1093
1084
|
if (prop.version) {
|
|
1094
1085
|
this.initDefaultValue(prop);
|
|
1095
1086
|
meta.versionProperty = prop.name;
|
|
1096
|
-
prop.defaultRaw = this.getDefaultVersionValue(prop);
|
|
1087
|
+
prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
|
|
1097
1088
|
}
|
|
1098
1089
|
if (prop.concurrencyCheck && !prop.primary) {
|
|
1099
1090
|
meta.concurrencyCheckKeys.add(prop.name);
|
|
1100
1091
|
}
|
|
1101
1092
|
}
|
|
1102
|
-
initCustomType(meta, prop) {
|
|
1093
|
+
initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
|
|
1103
1094
|
// `prop.type` might be actually instance of custom type class
|
|
1104
1095
|
if (Type.isMappedType(prop.type) && !prop.customType) {
|
|
1105
1096
|
prop.customType = prop.type;
|
|
@@ -1107,47 +1098,70 @@ export class MetadataDiscovery {
|
|
|
1107
1098
|
}
|
|
1108
1099
|
// `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
|
|
1109
1100
|
if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
|
|
1110
|
-
|
|
1111
|
-
|
|
1101
|
+
// if the type is an ORM defined mapped type without `ensureComparable: true`,
|
|
1102
|
+
// we use just the type name, to have more performant hydration code
|
|
1103
|
+
const type = Utils.keys(t).find(type => {
|
|
1104
|
+
return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
|
|
1105
|
+
});
|
|
1106
|
+
if (type) {
|
|
1107
|
+
prop.type = type === 'datetime' ? 'Date' : type;
|
|
1108
|
+
}
|
|
1109
|
+
else {
|
|
1110
|
+
prop.customType = new prop.type();
|
|
1111
|
+
prop.type = prop.customType.constructor.name;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (simple) {
|
|
1115
|
+
return;
|
|
1112
1116
|
}
|
|
1113
1117
|
if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
|
|
1114
|
-
prop.customType = new
|
|
1118
|
+
prop.customType = new t.json();
|
|
1115
1119
|
}
|
|
1116
1120
|
if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
|
|
1117
|
-
prop.customType = new
|
|
1121
|
+
prop.customType = new t.json();
|
|
1122
|
+
}
|
|
1123
|
+
if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
|
|
1124
|
+
prop.customType = new t.json();
|
|
1118
1125
|
}
|
|
1119
1126
|
if (!prop.customType && prop.array && prop.items) {
|
|
1120
|
-
prop.customType = new
|
|
1127
|
+
prop.customType = new t.enumArray(`${meta.className}.${prop.name}`, prop.items);
|
|
1128
|
+
}
|
|
1129
|
+
const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
|
|
1130
|
+
if (objectEmbeddable && !prop.customType && isArray) {
|
|
1131
|
+
prop.customType = new t.json();
|
|
1121
1132
|
}
|
|
1122
1133
|
// for number arrays we make sure to convert the items to numbers
|
|
1123
1134
|
if (!prop.customType && prop.type === 'number[]') {
|
|
1124
|
-
prop.customType = new
|
|
1135
|
+
prop.customType = new t.array(i => +i);
|
|
1125
1136
|
}
|
|
1126
1137
|
// `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
|
|
1127
|
-
if (!prop.customType &&
|
|
1128
|
-
prop.customType = new
|
|
1138
|
+
if (!prop.customType && isArray) {
|
|
1139
|
+
prop.customType = new t.array();
|
|
1129
1140
|
}
|
|
1130
1141
|
if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
|
|
1131
|
-
prop.customType = new
|
|
1142
|
+
prop.customType = new t.blob();
|
|
1132
1143
|
}
|
|
1133
1144
|
if (!prop.customType && prop.type?.toLowerCase() === 'uint8array') {
|
|
1134
|
-
prop.customType = new
|
|
1145
|
+
prop.customType = new t.uint8array();
|
|
1135
1146
|
}
|
|
1136
1147
|
const mappedType = this.getMappedType(prop);
|
|
1137
1148
|
if (prop.fieldNames?.length === 1 && !prop.customType) {
|
|
1138
|
-
[
|
|
1149
|
+
[t.bigint, t.double, t.decimal, t.interval, t.date]
|
|
1139
1150
|
.filter(type => mappedType instanceof type)
|
|
1140
|
-
.forEach(type => prop.customType = new type());
|
|
1151
|
+
.forEach((type) => prop.customType = new type());
|
|
1141
1152
|
}
|
|
1142
1153
|
if (prop.customType && !prop.columnTypes) {
|
|
1143
1154
|
const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
|
|
1144
|
-
if (prop.customType.compareAsType() === 'any' && ![
|
|
1155
|
+
if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
|
|
1145
1156
|
prop.runtimeType ??= mappedType.runtimeType;
|
|
1146
1157
|
}
|
|
1147
1158
|
else {
|
|
1148
1159
|
prop.runtimeType ??= prop.customType.runtimeType;
|
|
1149
1160
|
}
|
|
1150
1161
|
}
|
|
1162
|
+
else if (prop.runtimeType === 'object') {
|
|
1163
|
+
prop.runtimeType = mappedType.runtimeType;
|
|
1164
|
+
}
|
|
1151
1165
|
else {
|
|
1152
1166
|
prop.runtimeType ??= mappedType.runtimeType;
|
|
1153
1167
|
}
|
|
@@ -1158,16 +1172,16 @@ export class MetadataDiscovery {
|
|
|
1158
1172
|
prop.columnTypes ??= [prop.customType.getColumnType(prop, this.platform)];
|
|
1159
1173
|
prop.hasConvertToJSValueSQL = !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
|
|
1160
1174
|
prop.hasConvertToDatabaseValueSQL = !!prop.customType.convertToDatabaseValueSQL && prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
|
|
1161
|
-
if (prop.customType instanceof
|
|
1175
|
+
if (prop.customType instanceof t.bigint && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
|
|
1162
1176
|
prop.customType.mode = prop.runtimeType.toLowerCase();
|
|
1163
1177
|
}
|
|
1164
1178
|
}
|
|
1165
|
-
if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !
|
|
1179
|
+
if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
|
|
1166
1180
|
prop.type = prop.customType.name;
|
|
1167
1181
|
}
|
|
1168
|
-
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) {
|
|
1169
1183
|
prop.customTypes = [];
|
|
1170
|
-
for (const pk of
|
|
1184
|
+
for (const pk of prop.targetMeta.getPrimaryProps()) {
|
|
1171
1185
|
if (pk.customType) {
|
|
1172
1186
|
prop.customTypes.push(pk.customType);
|
|
1173
1187
|
prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
|
|
@@ -1179,7 +1193,7 @@ export class MetadataDiscovery {
|
|
|
1179
1193
|
}
|
|
1180
1194
|
}
|
|
1181
1195
|
}
|
|
1182
|
-
if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof
|
|
1196
|
+
if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
|
|
1183
1197
|
if (!prop.columnTypes && prop.nativeEnumName && meta.schema !== this.platform.getDefaultSchemaName() && meta.schema && !prop.nativeEnumName.includes('.')) {
|
|
1184
1198
|
prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
|
|
1185
1199
|
}
|
|
@@ -1197,7 +1211,8 @@ export class MetadataDiscovery {
|
|
|
1197
1211
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
1198
1212
|
return;
|
|
1199
1213
|
}
|
|
1200
|
-
|
|
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);
|
|
1201
1216
|
prop.referencedPKs = meta2.primaryKeys;
|
|
1202
1217
|
prop.targetMeta = meta2;
|
|
1203
1218
|
if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
|
|
@@ -1206,7 +1221,7 @@ export class MetadataDiscovery {
|
|
|
1206
1221
|
}
|
|
1207
1222
|
initColumnType(prop) {
|
|
1208
1223
|
this.initUnsigned(prop);
|
|
1209
|
-
|
|
1224
|
+
prop.targetMeta?.getPrimaryProps().map(pk => {
|
|
1210
1225
|
prop.length ??= pk.length;
|
|
1211
1226
|
prop.precision ??= pk.precision;
|
|
1212
1227
|
prop.scale ??= pk.scale;
|
|
@@ -1222,8 +1237,7 @@ export class MetadataDiscovery {
|
|
|
1222
1237
|
if (prop.kind === ReferenceKind.SCALAR) {
|
|
1223
1238
|
const mappedType = this.getMappedType(prop);
|
|
1224
1239
|
const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
|
|
1225
|
-
if (mappedType instanceof
|
|
1226
|
-
&& !prop.columnTypes
|
|
1240
|
+
if (mappedType instanceof t.unknown
|
|
1227
1241
|
// it could be a runtime type from reflect-metadata
|
|
1228
1242
|
&& !SCALAR_TYPES.includes(prop.type)
|
|
1229
1243
|
// or it might be inferred via ts-morph to some generic type alias
|
|
@@ -1236,11 +1250,12 @@ export class MetadataDiscovery {
|
|
|
1236
1250
|
}
|
|
1237
1251
|
return;
|
|
1238
1252
|
}
|
|
1239
|
-
|
|
1253
|
+
/* v8 ignore next */
|
|
1254
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
1240
1255
|
prop.columnTypes = [this.platform.getJsonDeclarationSQL()];
|
|
1241
1256
|
return;
|
|
1242
1257
|
}
|
|
1243
|
-
const targetMeta =
|
|
1258
|
+
const targetMeta = prop.targetMeta;
|
|
1244
1259
|
prop.columnTypes = [];
|
|
1245
1260
|
for (const pk of targetMeta.getPrimaryProps()) {
|
|
1246
1261
|
this.initCustomType(targetMeta, pk);
|
|
@@ -1266,7 +1281,7 @@ export class MetadataDiscovery {
|
|
|
1266
1281
|
t = 'enum';
|
|
1267
1282
|
}
|
|
1268
1283
|
else if (prop.enum) {
|
|
1269
|
-
t = prop.items?.every(item =>
|
|
1284
|
+
t = prop.items?.every(item => typeof item === 'string') ? 'enum' : 'tinyint';
|
|
1270
1285
|
}
|
|
1271
1286
|
if (t === 'Date') {
|
|
1272
1287
|
t = 'datetime';
|
|
@@ -1290,7 +1305,7 @@ export class MetadataDiscovery {
|
|
|
1290
1305
|
return;
|
|
1291
1306
|
}
|
|
1292
1307
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
1293
|
-
const meta2 =
|
|
1308
|
+
const meta2 = prop.targetMeta;
|
|
1294
1309
|
prop.unsigned = meta2.getPrimaryProps().some(pk => {
|
|
1295
1310
|
this.initUnsigned(pk);
|
|
1296
1311
|
return pk.unsigned;
|
|
@@ -1305,30 +1320,6 @@ export class MetadataDiscovery {
|
|
|
1305
1320
|
prop.index ??= true;
|
|
1306
1321
|
}
|
|
1307
1322
|
}
|
|
1308
|
-
async getEntityClassOrSchema(path, name) {
|
|
1309
|
-
const exports = await Utils.dynamicImport(path);
|
|
1310
|
-
const targets = Object.values(exports)
|
|
1311
|
-
.filter(item => item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name)));
|
|
1312
|
-
// ignore class implementations that are linked from an EntitySchema
|
|
1313
|
-
for (const item of targets) {
|
|
1314
|
-
if (item instanceof EntitySchema) {
|
|
1315
|
-
targets.forEach((item2, idx) => {
|
|
1316
|
-
if (item.meta.class === item2) {
|
|
1317
|
-
targets.splice(idx, 1);
|
|
1318
|
-
}
|
|
1319
|
-
});
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
if (targets.length > 0) {
|
|
1323
|
-
return targets;
|
|
1324
|
-
}
|
|
1325
|
-
const target = exports.default ?? exports[name];
|
|
1326
|
-
/* v8 ignore next 3 */
|
|
1327
|
-
if (!target) {
|
|
1328
|
-
throw MetadataError.entityNotFound(name, path.replace(this.config.get('baseDir'), '.'));
|
|
1329
|
-
}
|
|
1330
|
-
return [target];
|
|
1331
|
-
}
|
|
1332
1323
|
shouldForceConstructorUsage(meta) {
|
|
1333
1324
|
const forceConstructor = this.config.get('forceEntityConstructor');
|
|
1334
1325
|
if (Array.isArray(forceConstructor)) {
|