@mikro-orm/sql 7.0.9-dev.8 → 7.0.9
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/AbstractSqlConnection.d.ts +94 -58
- package/AbstractSqlConnection.js +235 -238
- package/AbstractSqlDriver.d.ts +410 -155
- package/AbstractSqlDriver.js +2096 -1968
- package/AbstractSqlPlatform.d.ts +85 -75
- package/AbstractSqlPlatform.js +166 -162
- package/PivotCollectionPersister.d.ts +33 -15
- package/PivotCollectionPersister.js +158 -160
- package/README.md +1 -1
- package/SqlEntityManager.d.ts +67 -22
- package/SqlEntityManager.js +54 -38
- package/SqlEntityRepository.d.ts +14 -14
- package/SqlEntityRepository.js +23 -23
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -12
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +199 -201
- package/dialects/mysql/BaseMySqlPlatform.d.ts +65 -46
- package/dialects/mysql/BaseMySqlPlatform.js +137 -134
- package/dialects/mysql/MySqlExceptionConverter.d.ts +6 -6
- package/dialects/mysql/MySqlExceptionConverter.js +91 -77
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +3 -3
- package/dialects/mysql/MySqlNativeQueryBuilder.js +66 -69
- package/dialects/mysql/MySqlSchemaHelper.d.ts +58 -39
- package/dialects/mysql/MySqlSchemaHelper.js +327 -319
- package/dialects/oracledb/OracleDialect.d.ts +81 -52
- package/dialects/oracledb/OracleDialect.js +155 -149
- package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +12 -12
- package/dialects/oracledb/OracleNativeQueryBuilder.js +239 -243
- package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +109 -106
- package/dialects/postgresql/BasePostgreSqlPlatform.js +354 -353
- package/dialects/postgresql/FullTextType.d.ts +10 -6
- package/dialects/postgresql/FullTextType.js +51 -51
- package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +5 -5
- package/dialects/postgresql/PostgreSqlExceptionConverter.js +55 -43
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +4 -4
- package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +117 -82
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +747 -711
- package/dialects/sqlite/BaseSqliteConnection.d.ts +3 -5
- package/dialects/sqlite/BaseSqliteConnection.js +21 -19
- package/dialects/sqlite/NodeSqliteDialect.d.ts +1 -1
- package/dialects/sqlite/NodeSqliteDialect.js +23 -23
- package/dialects/sqlite/SqliteDriver.d.ts +1 -1
- package/dialects/sqlite/SqliteDriver.js +3 -3
- package/dialects/sqlite/SqliteExceptionConverter.d.ts +6 -6
- package/dialects/sqlite/SqliteExceptionConverter.js +67 -51
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +2 -2
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +7 -7
- package/dialects/sqlite/SqlitePlatform.d.ts +63 -72
- package/dialects/sqlite/SqlitePlatform.js +139 -139
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +77 -60
- package/dialects/sqlite/SqliteSchemaHelper.js +541 -522
- package/package.json +3 -3
- package/plugin/index.d.ts +42 -35
- package/plugin/index.js +43 -36
- package/plugin/transformer.d.ts +117 -94
- package/plugin/transformer.js +890 -881
- package/query/ArrayCriteriaNode.d.ts +4 -4
- package/query/ArrayCriteriaNode.js +18 -18
- package/query/CriteriaNode.d.ts +35 -25
- package/query/CriteriaNode.js +133 -123
- package/query/CriteriaNodeFactory.d.ts +49 -6
- package/query/CriteriaNodeFactory.js +97 -94
- package/query/NativeQueryBuilder.d.ts +120 -120
- package/query/NativeQueryBuilder.js +507 -501
- package/query/ObjectCriteriaNode.d.ts +12 -12
- package/query/ObjectCriteriaNode.js +298 -282
- package/query/QueryBuilder.d.ts +1557 -905
- package/query/QueryBuilder.js +2322 -2192
- package/query/QueryBuilderHelper.d.ts +153 -72
- package/query/QueryBuilderHelper.js +1080 -1028
- package/query/ScalarCriteriaNode.d.ts +3 -3
- package/query/ScalarCriteriaNode.js +53 -46
- package/query/enums.d.ts +14 -14
- package/query/enums.js +14 -14
- package/query/raw.d.ts +16 -6
- package/query/raw.js +10 -10
- package/schema/DatabaseSchema.d.ts +74 -50
- package/schema/DatabaseSchema.js +355 -327
- package/schema/DatabaseTable.d.ts +96 -73
- package/schema/DatabaseTable.js +1012 -927
- package/schema/SchemaComparator.d.ts +70 -66
- package/schema/SchemaComparator.js +790 -764
- package/schema/SchemaHelper.d.ts +121 -96
- package/schema/SchemaHelper.js +683 -668
- package/schema/SqlSchemaGenerator.d.ts +79 -59
- package/schema/SqlSchemaGenerator.js +525 -495
- package/typings.d.ts +405 -275
package/schema/DatabaseSchema.js
CHANGED
|
@@ -1,356 +1,384 @@
|
|
|
1
|
-
import { ReferenceKind, isRaw
|
|
1
|
+
import { ReferenceKind, isRaw } from '@mikro-orm/core';
|
|
2
2
|
import { DatabaseTable } from './DatabaseTable.js';
|
|
3
3
|
/**
|
|
4
4
|
* @internal
|
|
5
5
|
*/
|
|
6
6
|
export class DatabaseSchema {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
name;
|
|
8
|
+
#tables = [];
|
|
9
|
+
#views = [];
|
|
10
|
+
#namespaces = new Set();
|
|
11
|
+
#nativeEnums = {}; // for postgres
|
|
12
|
+
#platform;
|
|
13
|
+
constructor(platform, name) {
|
|
14
|
+
this.name = name;
|
|
15
|
+
this.#platform = platform;
|
|
16
|
+
}
|
|
17
|
+
addTable(name, schema, comment) {
|
|
18
|
+
const namespaceName = schema ?? this.name;
|
|
19
|
+
const table = new DatabaseTable(this.#platform, name, namespaceName);
|
|
20
|
+
table.nativeEnums = this.#nativeEnums;
|
|
21
|
+
table.comment = comment;
|
|
22
|
+
this.#tables.push(table);
|
|
23
|
+
if (namespaceName != null) {
|
|
24
|
+
this.#namespaces.add(namespaceName);
|
|
16
25
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
return table;
|
|
27
|
+
}
|
|
28
|
+
getTables() {
|
|
29
|
+
return this.#tables;
|
|
30
|
+
}
|
|
31
|
+
/** @internal */
|
|
32
|
+
setTables(tables) {
|
|
33
|
+
this.#tables = tables;
|
|
34
|
+
}
|
|
35
|
+
/** @internal */
|
|
36
|
+
setNamespaces(namespaces) {
|
|
37
|
+
this.#namespaces = namespaces;
|
|
38
|
+
}
|
|
39
|
+
getTable(name) {
|
|
40
|
+
return this.#tables.find(t => t.name === name || `${t.schema}.${t.name}` === name);
|
|
41
|
+
}
|
|
42
|
+
hasTable(name) {
|
|
43
|
+
return !!this.getTable(name);
|
|
44
|
+
}
|
|
45
|
+
addView(name, schema, definition, materialized, withData) {
|
|
46
|
+
const namespaceName = schema ?? this.name;
|
|
47
|
+
const view = { name, schema: namespaceName, definition, materialized, withData };
|
|
48
|
+
this.#views.push(view);
|
|
49
|
+
if (namespaceName != null) {
|
|
50
|
+
this.#namespaces.add(namespaceName);
|
|
41
51
|
}
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
return view;
|
|
53
|
+
}
|
|
54
|
+
getViews() {
|
|
55
|
+
return this.#views;
|
|
56
|
+
}
|
|
57
|
+
/** @internal */
|
|
58
|
+
setViews(views) {
|
|
59
|
+
this.#views = views;
|
|
60
|
+
}
|
|
61
|
+
getView(name) {
|
|
62
|
+
return this.#views.find(v => v.name === name || `${v.schema}.${v.name}` === name);
|
|
63
|
+
}
|
|
64
|
+
hasView(name) {
|
|
65
|
+
return !!this.getView(name);
|
|
66
|
+
}
|
|
67
|
+
setNativeEnums(nativeEnums) {
|
|
68
|
+
this.#nativeEnums = nativeEnums;
|
|
69
|
+
for (const nativeEnum of Object.values(nativeEnums)) {
|
|
70
|
+
if (nativeEnum.schema && nativeEnum.schema !== '*') {
|
|
71
|
+
this.#namespaces.add(nativeEnum.schema);
|
|
72
|
+
}
|
|
44
73
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
}
|
|
75
|
+
getNativeEnums() {
|
|
76
|
+
return this.#nativeEnums;
|
|
77
|
+
}
|
|
78
|
+
getNativeEnum(name) {
|
|
79
|
+
return this.#nativeEnums[name];
|
|
80
|
+
}
|
|
81
|
+
hasNamespace(namespace) {
|
|
82
|
+
return this.#namespaces.has(namespace);
|
|
83
|
+
}
|
|
84
|
+
hasNativeEnum(name) {
|
|
85
|
+
return name in this.#nativeEnums;
|
|
86
|
+
}
|
|
87
|
+
getNamespaces() {
|
|
88
|
+
return [...this.#namespaces];
|
|
89
|
+
}
|
|
90
|
+
static async create(connection, platform, config, schemaName, schemas, takeTables, skipTables, skipViews, ctx) {
|
|
91
|
+
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema') ?? platform.getDefaultSchemaName());
|
|
92
|
+
const allTables = await platform.getSchemaHelper().getAllTables(connection, schemas, ctx);
|
|
93
|
+
const parts = config.get('migrations').tableName.split('.');
|
|
94
|
+
const migrationsTableName = parts[1] ?? parts[0];
|
|
95
|
+
const migrationsSchemaName = parts.length > 1 ? parts[0] : config.get('schema', platform.getDefaultSchemaName());
|
|
96
|
+
const tables = allTables.filter(
|
|
97
|
+
t =>
|
|
98
|
+
this.isTableNameAllowed(t.table_name, takeTables, skipTables) &&
|
|
99
|
+
(t.table_name !== migrationsTableName || (t.schema_name && t.schema_name !== migrationsSchemaName)),
|
|
100
|
+
);
|
|
101
|
+
await platform
|
|
102
|
+
.getSchemaHelper()
|
|
103
|
+
.loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined, ctx);
|
|
104
|
+
// Load views from database
|
|
105
|
+
await platform.getSchemaHelper().loadViews(schema, connection, schemaName, ctx);
|
|
106
|
+
// Load materialized views (PostgreSQL only)
|
|
107
|
+
if (platform.supportsMaterializedViews()) {
|
|
108
|
+
await platform.getSchemaHelper().loadMaterializedViews(schema, connection, schemaName, ctx);
|
|
60
109
|
}
|
|
61
|
-
|
|
62
|
-
|
|
110
|
+
// Filter out skipped views
|
|
111
|
+
if (skipViews && skipViews.length > 0) {
|
|
112
|
+
schema.#views = schema.#views.filter(v => this.isNameAllowed(v.name, skipViews));
|
|
63
113
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
114
|
+
return schema;
|
|
115
|
+
}
|
|
116
|
+
static fromMetadata(metadata, platform, config, schemaName, em) {
|
|
117
|
+
const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
|
|
118
|
+
const nativeEnums = {};
|
|
119
|
+
const skipColumns = config.get('schemaGenerator').skipColumns || {};
|
|
120
|
+
for (const meta of metadata) {
|
|
121
|
+
// Skip view entities when collecting native enums
|
|
122
|
+
if (meta.view) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
for (const prop of meta.props) {
|
|
126
|
+
if (prop.nativeEnumName) {
|
|
127
|
+
let key = prop.nativeEnumName;
|
|
128
|
+
let enumName = prop.nativeEnumName;
|
|
129
|
+
let enumSchema = meta.schema ?? schema.name;
|
|
130
|
+
if (key.includes('.')) {
|
|
131
|
+
const [explicitSchema, ...parts] = prop.nativeEnumName.split('.');
|
|
132
|
+
enumName = parts.join('.');
|
|
133
|
+
key = enumName;
|
|
134
|
+
enumSchema = explicitSchema;
|
|
135
|
+
}
|
|
136
|
+
if (enumSchema && enumSchema !== '*' && enumSchema !== platform.getDefaultSchemaName()) {
|
|
137
|
+
key = enumSchema + '.' + key;
|
|
138
|
+
}
|
|
139
|
+
nativeEnums[key] = {
|
|
140
|
+
name: enumName,
|
|
141
|
+
schema: enumSchema,
|
|
142
|
+
items: prop.items?.map(val => '' + val) ?? [],
|
|
143
|
+
};
|
|
73
144
|
}
|
|
145
|
+
}
|
|
74
146
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
147
|
+
schema.setNativeEnums(nativeEnums);
|
|
148
|
+
for (const meta of metadata) {
|
|
149
|
+
// Handle view entities separately
|
|
150
|
+
if (meta.view) {
|
|
151
|
+
const viewDefinition = this.getViewDefinition(meta, em, platform);
|
|
152
|
+
if (viewDefinition) {
|
|
153
|
+
const view = schema.addView(
|
|
154
|
+
meta.collection,
|
|
155
|
+
this.getSchemaName(meta, config, schemaName),
|
|
156
|
+
viewDefinition,
|
|
157
|
+
meta.materialized,
|
|
158
|
+
meta.withData,
|
|
159
|
+
);
|
|
160
|
+
if (meta.materialized) {
|
|
161
|
+
// Use a DatabaseTable to resolve property names → field names for indexes.
|
|
162
|
+
// addIndex only needs meta + table name, not actual columns.
|
|
163
|
+
const indexTable = new DatabaseTable(
|
|
164
|
+
platform,
|
|
165
|
+
meta.collection,
|
|
166
|
+
this.getSchemaName(meta, config, schemaName),
|
|
167
|
+
);
|
|
168
|
+
meta.indexes.forEach(index => indexTable.addIndex(meta, index, 'index'));
|
|
169
|
+
meta.uniques.forEach(index => indexTable.addIndex(meta, index, 'unique'));
|
|
170
|
+
const pkProps = meta.props.filter(prop => prop.primary);
|
|
171
|
+
indexTable.addIndex(meta, { properties: pkProps.map(prop => prop.name) }, 'primary');
|
|
172
|
+
// Materialized views don't have primary keys or constraints in the DB,
|
|
173
|
+
// convert to match what PostgreSQL stores.
|
|
174
|
+
view.indexes = indexTable.getIndexes().map(idx => {
|
|
175
|
+
if (idx.primary) {
|
|
176
|
+
return { ...idx, primary: false, unique: true, constraint: false };
|
|
177
|
+
}
|
|
178
|
+
if (idx.constraint) {
|
|
179
|
+
return { ...idx, constraint: false };
|
|
180
|
+
}
|
|
181
|
+
return idx;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
106
184
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const table = schema.addTable(meta.collection, this.getSchemaName(meta, config, schemaName));
|
|
188
|
+
table.comment = meta.comment;
|
|
189
|
+
// For TPT child entities, only use ownProps (properties defined in this entity only)
|
|
190
|
+
// For all other entities (including TPT root), use all props
|
|
191
|
+
const propsToProcess =
|
|
192
|
+
meta.inheritanceType === 'tpt' && meta.tptParent && meta.ownProps ? meta.ownProps : meta.props;
|
|
193
|
+
for (const prop of propsToProcess) {
|
|
194
|
+
if (!this.shouldHaveColumn(meta, prop, skipColumns)) {
|
|
195
|
+
continue;
|
|
110
196
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
let enumSchema = meta.schema ?? schema.name;
|
|
127
|
-
if (key.includes('.')) {
|
|
128
|
-
const [explicitSchema, ...parts] = prop.nativeEnumName.split('.');
|
|
129
|
-
enumName = parts.join('.');
|
|
130
|
-
key = enumName;
|
|
131
|
-
enumSchema = explicitSchema;
|
|
132
|
-
}
|
|
133
|
-
if (enumSchema && enumSchema !== '*' && enumSchema !== platform.getDefaultSchemaName()) {
|
|
134
|
-
key = enumSchema + '.' + key;
|
|
135
|
-
}
|
|
136
|
-
nativeEnums[key] = {
|
|
137
|
-
name: enumName,
|
|
138
|
-
schema: enumSchema,
|
|
139
|
-
items: prop.items?.map(val => '' + val) ?? [],
|
|
140
|
-
};
|
|
141
|
-
}
|
|
197
|
+
table.addColumnFromProperty(prop, meta, config);
|
|
198
|
+
}
|
|
199
|
+
// For TPT child entities, always include the PK columns (they form the FK to parent)
|
|
200
|
+
if (meta.inheritanceType === 'tpt' && meta.tptParent) {
|
|
201
|
+
const pkProps = meta.primaryKeys.map(pk => meta.properties[pk]);
|
|
202
|
+
for (const pkProp of pkProps) {
|
|
203
|
+
// Only add if not already added (it might be in ownProps if defined in this entity)
|
|
204
|
+
if (!propsToProcess.includes(pkProp)) {
|
|
205
|
+
table.addColumnFromProperty(pkProp, meta, config);
|
|
206
|
+
}
|
|
207
|
+
// Child PK must not be autoincrement — it references the parent PK via FK
|
|
208
|
+
for (const field of pkProp.fieldNames) {
|
|
209
|
+
const col = table.getColumn(field);
|
|
210
|
+
if (col) {
|
|
211
|
+
col.autoincrement = false;
|
|
142
212
|
}
|
|
213
|
+
}
|
|
143
214
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
return idx;
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
continue;
|
|
173
|
-
}
|
|
174
|
-
const table = schema.addTable(meta.collection, this.getSchemaName(meta, config, schemaName));
|
|
175
|
-
table.comment = meta.comment;
|
|
176
|
-
// For TPT child entities, only use ownProps (properties defined in this entity only)
|
|
177
|
-
// For all other entities (including TPT root), use all props
|
|
178
|
-
const propsToProcess = meta.inheritanceType === 'tpt' && meta.tptParent && meta.ownProps ? meta.ownProps : meta.props;
|
|
179
|
-
for (const prop of propsToProcess) {
|
|
180
|
-
if (!this.shouldHaveColumn(meta, prop, skipColumns)) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
table.addColumnFromProperty(prop, meta, config);
|
|
184
|
-
}
|
|
185
|
-
// For TPT child entities, always include the PK columns (they form the FK to parent)
|
|
186
|
-
if (meta.inheritanceType === 'tpt' && meta.tptParent) {
|
|
187
|
-
const pkProps = meta.primaryKeys.map(pk => meta.properties[pk]);
|
|
188
|
-
for (const pkProp of pkProps) {
|
|
189
|
-
// Only add if not already added (it might be in ownProps if defined in this entity)
|
|
190
|
-
if (!propsToProcess.includes(pkProp)) {
|
|
191
|
-
table.addColumnFromProperty(pkProp, meta, config);
|
|
192
|
-
}
|
|
193
|
-
// Child PK must not be autoincrement — it references the parent PK via FK
|
|
194
|
-
for (const field of pkProp.fieldNames) {
|
|
195
|
-
const col = table.getColumn(field);
|
|
196
|
-
if (col) {
|
|
197
|
-
col.autoincrement = false;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
// Add FK from child PK to parent PK with ON DELETE CASCADE
|
|
202
|
-
this.addTPTForeignKey(table, meta, config, platform);
|
|
203
|
-
}
|
|
204
|
-
meta.indexes.forEach(index => table.addIndex(meta, index, 'index'));
|
|
205
|
-
meta.uniques.forEach(index => table.addIndex(meta, index, 'unique'));
|
|
206
|
-
// For TPT child entities, the PK is also defined here
|
|
207
|
-
const pkPropsForIndex = meta.inheritanceType === 'tpt' && meta.tptParent
|
|
208
|
-
? meta.primaryKeys.map(pk => meta.properties[pk])
|
|
209
|
-
: meta.props.filter(prop => prop.primary);
|
|
210
|
-
table.addIndex(meta, { properties: pkPropsForIndex.map(prop => prop.name) }, 'primary');
|
|
211
|
-
for (const check of meta.checks) {
|
|
212
|
-
const columnName = check.property ? meta.properties[check.property].fieldNames[0] : undefined;
|
|
213
|
-
const expression = isRaw(check.expression)
|
|
214
|
-
? platform.formatQuery(check.expression.sql, check.expression.params)
|
|
215
|
-
: check.expression;
|
|
216
|
-
table.addCheck({
|
|
217
|
-
name: check.name,
|
|
218
|
-
expression,
|
|
219
|
-
definition: `check (${expression})`,
|
|
220
|
-
columnName,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
return schema;
|
|
215
|
+
// Add FK from child PK to parent PK with ON DELETE CASCADE
|
|
216
|
+
this.addTPTForeignKey(table, meta, config, platform);
|
|
217
|
+
}
|
|
218
|
+
meta.indexes.forEach(index => table.addIndex(meta, index, 'index'));
|
|
219
|
+
meta.uniques.forEach(index => table.addIndex(meta, index, 'unique'));
|
|
220
|
+
// For TPT child entities, the PK is also defined here
|
|
221
|
+
const pkPropsForIndex =
|
|
222
|
+
meta.inheritanceType === 'tpt' && meta.tptParent
|
|
223
|
+
? meta.primaryKeys.map(pk => meta.properties[pk])
|
|
224
|
+
: meta.props.filter(prop => prop.primary);
|
|
225
|
+
table.addIndex(meta, { properties: pkPropsForIndex.map(prop => prop.name) }, 'primary');
|
|
226
|
+
for (const check of meta.checks) {
|
|
227
|
+
const columnName = check.property ? meta.properties[check.property].fieldNames[0] : undefined;
|
|
228
|
+
const expression = isRaw(check.expression)
|
|
229
|
+
? platform.formatQuery(check.expression.sql, check.expression.params)
|
|
230
|
+
: check.expression;
|
|
231
|
+
table.addCheck({
|
|
232
|
+
name: check.name,
|
|
233
|
+
expression,
|
|
234
|
+
definition: `check (${expression})`,
|
|
235
|
+
columnName,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
225
238
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// Async expressions are not supported for view entities
|
|
237
|
-
if (result && typeof result.then === 'function') {
|
|
238
|
-
throw new Error(`View entity ${meta.className} expression returned a Promise. Async expressions are not supported for view entities.`);
|
|
239
|
-
}
|
|
240
|
-
/* v8 ignore next */
|
|
241
|
-
if (typeof result === 'string') {
|
|
242
|
-
return result;
|
|
243
|
-
}
|
|
244
|
-
/* v8 ignore next */
|
|
245
|
-
if (isRaw(result)) {
|
|
246
|
-
return platform.formatQuery(result.sql, result.params);
|
|
247
|
-
}
|
|
248
|
-
// Check if it's a QueryBuilder (has getFormattedQuery method)
|
|
249
|
-
if (result && typeof result.getFormattedQuery === 'function') {
|
|
250
|
-
return result.getFormattedQuery();
|
|
251
|
-
}
|
|
252
|
-
/* v8 ignore next - fallback for unknown result types */
|
|
253
|
-
return undefined;
|
|
239
|
+
return schema;
|
|
240
|
+
}
|
|
241
|
+
static getViewDefinition(meta, em, platform) {
|
|
242
|
+
if (typeof meta.expression === 'string') {
|
|
243
|
+
return meta.expression;
|
|
244
|
+
}
|
|
245
|
+
// Expression is a function, need to evaluate it
|
|
246
|
+
/* v8 ignore next */
|
|
247
|
+
if (!em) {
|
|
248
|
+
return undefined;
|
|
254
249
|
}
|
|
255
|
-
|
|
256
|
-
|
|
250
|
+
const result = meta.expression(em, {}, {});
|
|
251
|
+
// Async expressions are not supported for view entities
|
|
252
|
+
if (result && typeof result.then === 'function') {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`View entity ${meta.className} expression returned a Promise. Async expressions are not supported for view entities.`,
|
|
255
|
+
);
|
|
257
256
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
*/
|
|
262
|
-
static addTPTForeignKey(table, meta, config, platform) {
|
|
263
|
-
const parent = meta.tptParent;
|
|
264
|
-
const pkColumnNames = meta.primaryKeys.flatMap(pk => meta.properties[pk].fieldNames);
|
|
265
|
-
const parentPkColumnNames = parent.primaryKeys.flatMap(pk => parent.properties[pk].fieldNames);
|
|
266
|
-
// Determine the parent table name with schema
|
|
267
|
-
const parentSchema = parent.schema === '*' ? undefined : (parent.schema ?? config.get('schema', platform.getDefaultSchemaName()));
|
|
268
|
-
const parentTableName = parentSchema ? `${parentSchema}.${parent.tableName}` : parent.tableName;
|
|
269
|
-
// Create FK constraint name
|
|
270
|
-
const constraintName = platform.getIndexName(table.name, pkColumnNames, 'foreign');
|
|
271
|
-
// Add the foreign key to the table
|
|
272
|
-
const fks = table.getForeignKeys();
|
|
273
|
-
fks[constraintName] = {
|
|
274
|
-
constraintName,
|
|
275
|
-
columnNames: pkColumnNames,
|
|
276
|
-
localTableName: table.getShortestName(false),
|
|
277
|
-
referencedColumnNames: parentPkColumnNames,
|
|
278
|
-
referencedTableName: parentTableName,
|
|
279
|
-
deleteRule: 'cascade', // TPT always uses cascade delete
|
|
280
|
-
updateRule: 'cascade', // TPT always uses cascade update
|
|
281
|
-
};
|
|
257
|
+
/* v8 ignore next */
|
|
258
|
+
if (typeof result === 'string') {
|
|
259
|
+
return result;
|
|
282
260
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
: nameToMatch.test(name);
|
|
261
|
+
/* v8 ignore next */
|
|
262
|
+
if (isRaw(result)) {
|
|
263
|
+
return platform.formatQuery(result.sql, result.params);
|
|
287
264
|
}
|
|
288
|
-
|
|
289
|
-
|
|
265
|
+
// Check if it's a QueryBuilder (has getFormattedQuery method)
|
|
266
|
+
if (result && typeof result.getFormattedQuery === 'function') {
|
|
267
|
+
return result.getFormattedQuery();
|
|
290
268
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
269
|
+
/* v8 ignore next - fallback for unknown result types */
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
static getSchemaName(meta, config, schema) {
|
|
273
|
+
return (meta.schema === '*' ? schema : meta.schema) ?? config.get('schema');
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Add a foreign key from a TPT child entity's PK to its parent entity's PK.
|
|
277
|
+
* This FK uses ON DELETE CASCADE to ensure child rows are deleted when parent is deleted.
|
|
278
|
+
*/
|
|
279
|
+
static addTPTForeignKey(table, meta, config, platform) {
|
|
280
|
+
const parent = meta.tptParent;
|
|
281
|
+
const pkColumnNames = meta.primaryKeys.flatMap(pk => meta.properties[pk].fieldNames);
|
|
282
|
+
const parentPkColumnNames = parent.primaryKeys.flatMap(pk => parent.properties[pk].fieldNames);
|
|
283
|
+
// Determine the parent table name with schema
|
|
284
|
+
const parentSchema =
|
|
285
|
+
parent.schema === '*' ? undefined : (parent.schema ?? config.get('schema', platform.getDefaultSchemaName()));
|
|
286
|
+
const parentTableName = parentSchema ? `${parentSchema}.${parent.tableName}` : parent.tableName;
|
|
287
|
+
// Create FK constraint name
|
|
288
|
+
const constraintName = platform.getIndexName(table.name, pkColumnNames, 'foreign');
|
|
289
|
+
// Add the foreign key to the table
|
|
290
|
+
const fks = table.getForeignKeys();
|
|
291
|
+
fks[constraintName] = {
|
|
292
|
+
constraintName,
|
|
293
|
+
columnNames: pkColumnNames,
|
|
294
|
+
localTableName: table.getShortestName(false),
|
|
295
|
+
referencedColumnNames: parentPkColumnNames,
|
|
296
|
+
referencedTableName: parentTableName,
|
|
297
|
+
deleteRule: 'cascade', // TPT always uses cascade delete
|
|
298
|
+
updateRule: 'cascade', // TPT always uses cascade update
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
static matchName(name, nameToMatch) {
|
|
302
|
+
return typeof nameToMatch === 'string'
|
|
303
|
+
? name.toLocaleLowerCase() === nameToMatch.toLocaleLowerCase()
|
|
304
|
+
: nameToMatch.test(name);
|
|
305
|
+
}
|
|
306
|
+
static isNameAllowed(name, skipNames) {
|
|
307
|
+
return !(skipNames?.some(pattern => this.matchName(name, pattern)) ?? false);
|
|
308
|
+
}
|
|
309
|
+
static isTableNameAllowed(tableName, takeTables, skipTables) {
|
|
310
|
+
return (
|
|
311
|
+
(takeTables?.some(tableNameToMatch => this.matchName(tableName, tableNameToMatch)) ?? true) &&
|
|
312
|
+
this.isNameAllowed(tableName, skipTables)
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
static shouldHaveColumn(meta, prop, skipColumns) {
|
|
316
|
+
if (prop.persist === false || (prop.columnTypes?.length ?? 0) === 0) {
|
|
317
|
+
return false;
|
|
294
318
|
}
|
|
295
|
-
|
|
296
|
-
|
|
319
|
+
// Check if column should be skipped
|
|
320
|
+
if (skipColumns) {
|
|
321
|
+
const tableName = meta.tableName;
|
|
322
|
+
const tableSchema = meta.schema;
|
|
323
|
+
const fullTableName = tableSchema ? `${tableSchema}.${tableName}` : tableName;
|
|
324
|
+
// Check for skipColumns by table name or fully qualified table name
|
|
325
|
+
const columnsToSkip = skipColumns[tableName] || skipColumns[fullTableName];
|
|
326
|
+
if (columnsToSkip) {
|
|
327
|
+
for (const fieldName of prop.fieldNames) {
|
|
328
|
+
if (columnsToSkip.some(pattern => this.matchName(fieldName, pattern))) {
|
|
297
329
|
return false;
|
|
330
|
+
}
|
|
298
331
|
}
|
|
299
|
-
|
|
300
|
-
if (skipColumns) {
|
|
301
|
-
const tableName = meta.tableName;
|
|
302
|
-
const tableSchema = meta.schema;
|
|
303
|
-
const fullTableName = tableSchema ? `${tableSchema}.${tableName}` : tableName;
|
|
304
|
-
// Check for skipColumns by table name or fully qualified table name
|
|
305
|
-
const columnsToSkip = skipColumns[tableName] || skipColumns[fullTableName];
|
|
306
|
-
if (columnsToSkip) {
|
|
307
|
-
for (const fieldName of prop.fieldNames) {
|
|
308
|
-
if (columnsToSkip.some(pattern => this.matchName(fieldName, pattern))) {
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
const getRootProperty = (prop) => prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop;
|
|
318
|
-
const rootProp = getRootProperty(prop);
|
|
319
|
-
if (rootProp.kind === ReferenceKind.EMBEDDED) {
|
|
320
|
-
return prop === rootProp || !rootProp.object;
|
|
321
|
-
}
|
|
322
|
-
return ([ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE].includes(prop.kind) ||
|
|
323
|
-
(prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner));
|
|
332
|
+
}
|
|
324
333
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
name: this.name,
|
|
328
|
-
namespaces: [...this.#namespaces],
|
|
329
|
-
tables: this.#tables,
|
|
330
|
-
views: this.#views,
|
|
331
|
-
nativeEnums: this.#nativeEnums,
|
|
332
|
-
};
|
|
334
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
|
|
335
|
+
return true;
|
|
333
336
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
337
|
+
const getRootProperty = prop => (prop.embedded ? getRootProperty(meta.properties[prop.embedded[0]]) : prop);
|
|
338
|
+
const rootProp = getRootProperty(prop);
|
|
339
|
+
if (rootProp.kind === ReferenceKind.EMBEDDED) {
|
|
340
|
+
return prop === rootProp || !rootProp.object;
|
|
341
|
+
}
|
|
342
|
+
return (
|
|
343
|
+
[ReferenceKind.SCALAR, ReferenceKind.MANY_TO_ONE].includes(prop.kind) ||
|
|
344
|
+
(prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner)
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
toJSON() {
|
|
348
|
+
return {
|
|
349
|
+
name: this.name,
|
|
350
|
+
namespaces: [...this.#namespaces],
|
|
351
|
+
tables: this.#tables,
|
|
352
|
+
views: this.#views,
|
|
353
|
+
nativeEnums: this.#nativeEnums,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
prune(schema, wildcardSchemaTables) {
|
|
357
|
+
const hasWildcardSchema = wildcardSchemaTables.length > 0;
|
|
358
|
+
this.#tables = this.#tables.filter(table => {
|
|
359
|
+
return (
|
|
360
|
+
(!schema && !hasWildcardSchema) || // no schema specified and we don't have any multi-schema entity
|
|
361
|
+
table.schema === schema || // specified schema matches the table's one
|
|
362
|
+
(!schema && !wildcardSchemaTables.includes(table.name))
|
|
363
|
+
); // no schema specified and the table has fixed one provided
|
|
364
|
+
});
|
|
365
|
+
this.#views = this.#views.filter(view => {
|
|
366
|
+
/* v8 ignore next */
|
|
367
|
+
return (
|
|
368
|
+
(!schema && !hasWildcardSchema) ||
|
|
369
|
+
view.schema === schema ||
|
|
370
|
+
(!schema && !wildcardSchemaTables.includes(view.name))
|
|
371
|
+
);
|
|
372
|
+
});
|
|
373
|
+
// remove namespaces of ignored tables and views
|
|
374
|
+
for (const ns of this.#namespaces) {
|
|
375
|
+
if (
|
|
376
|
+
!this.#tables.some(t => t.schema === ns) &&
|
|
377
|
+
!this.#views.some(v => v.schema === ns) &&
|
|
378
|
+
!Object.values(this.#nativeEnums).some(e => e.schema === ns)
|
|
379
|
+
) {
|
|
380
|
+
this.#namespaces.delete(ns);
|
|
381
|
+
}
|
|
355
382
|
}
|
|
383
|
+
}
|
|
356
384
|
}
|