@mikro-orm/sql 7.0.8 → 7.0.9-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/AbstractSqlConnection.d.ts +58 -94
  2. package/AbstractSqlConnection.js +238 -235
  3. package/AbstractSqlDriver.d.ts +155 -410
  4. package/AbstractSqlDriver.js +1953 -2072
  5. package/AbstractSqlPlatform.d.ts +75 -85
  6. package/AbstractSqlPlatform.js +162 -166
  7. package/PivotCollectionPersister.d.ts +15 -33
  8. package/PivotCollectionPersister.js +160 -158
  9. package/README.md +1 -1
  10. package/SqlEntityManager.d.ts +22 -67
  11. package/SqlEntityManager.js +38 -54
  12. package/SqlEntityRepository.d.ts +14 -14
  13. package/SqlEntityRepository.js +23 -23
  14. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -12
  15. package/dialects/mssql/MsSqlNativeQueryBuilder.js +201 -199
  16. package/dialects/mysql/BaseMySqlPlatform.d.ts +46 -65
  17. package/dialects/mysql/BaseMySqlPlatform.js +134 -137
  18. package/dialects/mysql/MySqlExceptionConverter.d.ts +6 -6
  19. package/dialects/mysql/MySqlExceptionConverter.js +77 -91
  20. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +3 -3
  21. package/dialects/mysql/MySqlNativeQueryBuilder.js +69 -66
  22. package/dialects/mysql/MySqlSchemaHelper.d.ts +39 -58
  23. package/dialects/mysql/MySqlSchemaHelper.js +319 -327
  24. package/dialects/oracledb/OracleDialect.d.ts +52 -81
  25. package/dialects/oracledb/OracleDialect.js +149 -155
  26. package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +12 -12
  27. package/dialects/oracledb/OracleNativeQueryBuilder.js +243 -239
  28. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +106 -109
  29. package/dialects/postgresql/BasePostgreSqlPlatform.js +353 -354
  30. package/dialects/postgresql/FullTextType.d.ts +6 -10
  31. package/dialects/postgresql/FullTextType.js +51 -51
  32. package/dialects/postgresql/PostgreSqlExceptionConverter.d.ts +5 -5
  33. package/dialects/postgresql/PostgreSqlExceptionConverter.js +43 -55
  34. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
  35. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +4 -4
  36. package/dialects/postgresql/PostgreSqlSchemaHelper.d.ts +82 -117
  37. package/dialects/postgresql/PostgreSqlSchemaHelper.js +711 -747
  38. package/dialects/sqlite/BaseSqliteConnection.d.ts +5 -3
  39. package/dialects/sqlite/BaseSqliteConnection.js +19 -21
  40. package/dialects/sqlite/NodeSqliteDialect.d.ts +1 -1
  41. package/dialects/sqlite/NodeSqliteDialect.js +23 -23
  42. package/dialects/sqlite/SqliteDriver.d.ts +1 -1
  43. package/dialects/sqlite/SqliteDriver.js +3 -3
  44. package/dialects/sqlite/SqliteExceptionConverter.d.ts +6 -6
  45. package/dialects/sqlite/SqliteExceptionConverter.js +51 -67
  46. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +2 -2
  47. package/dialects/sqlite/SqliteNativeQueryBuilder.js +7 -7
  48. package/dialects/sqlite/SqlitePlatform.d.ts +72 -63
  49. package/dialects/sqlite/SqlitePlatform.js +139 -139
  50. package/dialects/sqlite/SqliteSchemaHelper.d.ts +60 -77
  51. package/dialects/sqlite/SqliteSchemaHelper.js +522 -541
  52. package/package.json +2 -2
  53. package/plugin/index.d.ts +35 -42
  54. package/plugin/index.js +36 -43
  55. package/plugin/transformer.d.ts +94 -117
  56. package/plugin/transformer.js +881 -890
  57. package/query/ArrayCriteriaNode.d.ts +4 -4
  58. package/query/ArrayCriteriaNode.js +18 -18
  59. package/query/CriteriaNode.d.ts +25 -35
  60. package/query/CriteriaNode.js +123 -133
  61. package/query/CriteriaNodeFactory.d.ts +6 -49
  62. package/query/CriteriaNodeFactory.js +94 -97
  63. package/query/NativeQueryBuilder.d.ts +120 -120
  64. package/query/NativeQueryBuilder.js +501 -507
  65. package/query/ObjectCriteriaNode.d.ts +12 -12
  66. package/query/ObjectCriteriaNode.js +282 -298
  67. package/query/QueryBuilder.d.ts +905 -1557
  68. package/query/QueryBuilder.js +2192 -2322
  69. package/query/QueryBuilderHelper.d.ts +72 -153
  70. package/query/QueryBuilderHelper.js +1028 -1079
  71. package/query/ScalarCriteriaNode.d.ts +3 -3
  72. package/query/ScalarCriteriaNode.js +46 -53
  73. package/query/enums.d.ts +14 -14
  74. package/query/enums.js +14 -14
  75. package/query/raw.d.ts +6 -16
  76. package/query/raw.js +10 -10
  77. package/schema/DatabaseSchema.d.ts +50 -74
  78. package/schema/DatabaseSchema.js +327 -355
  79. package/schema/DatabaseTable.d.ts +73 -96
  80. package/schema/DatabaseTable.js +927 -1012
  81. package/schema/SchemaComparator.d.ts +66 -70
  82. package/schema/SchemaComparator.js +764 -790
  83. package/schema/SchemaHelper.d.ts +96 -121
  84. package/schema/SchemaHelper.js +668 -683
  85. package/schema/SqlSchemaGenerator.d.ts +59 -79
  86. package/schema/SqlSchemaGenerator.js +495 -525
  87. package/typings.d.ts +275 -405
@@ -1,384 +1,356 @@
1
- import { ReferenceKind, isRaw } from '@mikro-orm/core';
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
- 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);
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;
25
16
  }
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);
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);
25
+ }
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);
51
41
  }
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
- }
42
+ hasTable(name) {
43
+ return !!this.getTable(name);
73
44
  }
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);
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);
51
+ }
52
+ return view;
53
+ }
54
+ getViews() {
55
+ return this.#views;
56
+ }
57
+ /** @internal */
58
+ setViews(views) {
59
+ this.#views = views;
109
60
  }
110
- // Filter out skipped views
111
- if (skipViews && skipViews.length > 0) {
112
- schema.#views = schema.#views.filter(v => this.isNameAllowed(v.name, skipViews));
61
+ getView(name) {
62
+ return this.#views.find(v => v.name === name || `${v.schema}.${v.name}` === name);
113
63
  }
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
- };
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
+ }
144
73
  }
145
- }
146
74
  }
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
- }
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(t => this.isTableNameAllowed(t.table_name, takeTables, skipTables) &&
97
+ (t.table_name !== migrationsTableName || (t.schema_name && t.schema_name !== migrationsSchemaName)));
98
+ await platform
99
+ .getSchemaHelper()
100
+ .loadInformationSchema(schema, connection, tables, schemas && schemas.length > 0 ? schemas : undefined, ctx);
101
+ // Load views from database
102
+ await platform.getSchemaHelper().loadViews(schema, connection, schemaName, ctx);
103
+ // Load materialized views (PostgreSQL only)
104
+ if (platform.supportsMaterializedViews()) {
105
+ await platform.getSchemaHelper().loadMaterializedViews(schema, connection, schemaName, ctx);
184
106
  }
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;
107
+ // Filter out skipped views
108
+ if (skipViews && skipViews.length > 0) {
109
+ schema.#views = schema.#views.filter(v => this.isNameAllowed(v.name, skipViews));
196
110
  }
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;
111
+ return schema;
112
+ }
113
+ static fromMetadata(metadata, platform, config, schemaName, em) {
114
+ const schema = new DatabaseSchema(platform, schemaName ?? config.get('schema'));
115
+ const nativeEnums = {};
116
+ const skipColumns = config.get('schemaGenerator').skipColumns || {};
117
+ for (const meta of metadata) {
118
+ // Skip view entities when collecting native enums
119
+ if (meta.view) {
120
+ continue;
121
+ }
122
+ for (const prop of meta.props) {
123
+ if (prop.nativeEnumName) {
124
+ let key = prop.nativeEnumName;
125
+ let enumName = prop.nativeEnumName;
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
+ }
212
142
  }
213
- }
214
143
  }
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
- }
238
- }
239
- return schema;
240
- }
241
- static getViewDefinition(meta, em, platform) {
242
- if (typeof meta.expression === 'string') {
243
- return meta.expression;
144
+ schema.setNativeEnums(nativeEnums);
145
+ for (const meta of metadata) {
146
+ // Handle view entities separately
147
+ if (meta.view) {
148
+ const viewDefinition = this.getViewDefinition(meta, em, platform);
149
+ if (viewDefinition) {
150
+ const view = schema.addView(meta.collection, this.getSchemaName(meta, config, schemaName), viewDefinition, meta.materialized, meta.withData);
151
+ if (meta.materialized) {
152
+ // Use a DatabaseTable to resolve property names → field names for indexes.
153
+ // addIndex only needs meta + table name, not actual columns.
154
+ const indexTable = new DatabaseTable(platform, meta.collection, this.getSchemaName(meta, config, schemaName));
155
+ meta.indexes.forEach(index => indexTable.addIndex(meta, index, 'index'));
156
+ meta.uniques.forEach(index => indexTable.addIndex(meta, index, 'unique'));
157
+ const pkProps = meta.props.filter(prop => prop.primary);
158
+ indexTable.addIndex(meta, { properties: pkProps.map(prop => prop.name) }, 'primary');
159
+ // Materialized views don't have primary keys or constraints in the DB,
160
+ // convert to match what PostgreSQL stores.
161
+ view.indexes = indexTable.getIndexes().map(idx => {
162
+ if (idx.primary) {
163
+ return { ...idx, primary: false, unique: true, constraint: false };
164
+ }
165
+ if (idx.constraint) {
166
+ return { ...idx, constraint: false };
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;
244
225
  }
245
- // Expression is a function, need to evaluate it
246
- /* v8 ignore next */
247
- if (!em) {
248
- return undefined;
226
+ static getViewDefinition(meta, em, platform) {
227
+ if (typeof meta.expression === 'string') {
228
+ return meta.expression;
229
+ }
230
+ // Expression is a function, need to evaluate it
231
+ /* v8 ignore next */
232
+ if (!em) {
233
+ return undefined;
234
+ }
235
+ const result = meta.expression(em, {}, {});
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;
249
254
  }
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
- );
255
+ static getSchemaName(meta, config, schema) {
256
+ return (meta.schema === '*' ? schema : meta.schema) ?? config.get('schema');
256
257
  }
257
- /* v8 ignore next */
258
- if (typeof result === 'string') {
259
- return result;
258
+ /**
259
+ * Add a foreign key from a TPT child entity's PK to its parent entity's PK.
260
+ * This FK uses ON DELETE CASCADE to ensure child rows are deleted when parent is deleted.
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
+ };
260
282
  }
261
- /* v8 ignore next */
262
- if (isRaw(result)) {
263
- return platform.formatQuery(result.sql, result.params);
283
+ static matchName(name, nameToMatch) {
284
+ return typeof nameToMatch === 'string'
285
+ ? name.toLocaleLowerCase() === nameToMatch.toLocaleLowerCase()
286
+ : nameToMatch.test(name);
264
287
  }
265
- // Check if it's a QueryBuilder (has getFormattedQuery method)
266
- if (result && typeof result.getFormattedQuery === 'function') {
267
- return result.getFormattedQuery();
288
+ static isNameAllowed(name, skipNames) {
289
+ return !(skipNames?.some(pattern => this.matchName(name, pattern)) ?? false);
268
290
  }
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;
291
+ static isTableNameAllowed(tableName, takeTables, skipTables) {
292
+ return ((takeTables?.some(tableNameToMatch => this.matchName(tableName, tableNameToMatch)) ?? true) &&
293
+ this.isNameAllowed(tableName, skipTables));
318
294
  }
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))) {
295
+ static shouldHaveColumn(meta, prop, skipColumns) {
296
+ if (prop.persist === false || (prop.columnTypes?.length ?? 0) === 0) {
329
297
  return false;
330
- }
331
298
  }
332
- }
333
- }
334
- if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
335
- return true;
299
+ // Check if column should be skipped
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));
336
324
  }
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;
325
+ toJSON() {
326
+ return {
327
+ name: this.name,
328
+ namespaces: [...this.#namespaces],
329
+ tables: this.#tables,
330
+ views: this.#views,
331
+ nativeEnums: this.#nativeEnums,
332
+ };
341
333
  }
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
- }
334
+ prune(schema, wildcardSchemaTables) {
335
+ const hasWildcardSchema = wildcardSchemaTables.length > 0;
336
+ this.#tables = this.#tables.filter(table => {
337
+ return ((!schema && !hasWildcardSchema) || // no schema specified and we don't have any multi-schema entity
338
+ table.schema === schema || // specified schema matches the table's one
339
+ (!schema && !wildcardSchemaTables.includes(table.name))); // no schema specified and the table has fixed one provided
340
+ });
341
+ this.#views = this.#views.filter(view => {
342
+ /* v8 ignore next */
343
+ return ((!schema && !hasWildcardSchema) ||
344
+ view.schema === schema ||
345
+ (!schema && !wildcardSchemaTables.includes(view.name)));
346
+ });
347
+ // remove namespaces of ignored tables and views
348
+ for (const ns of this.#namespaces) {
349
+ if (!this.#tables.some(t => t.schema === ns) &&
350
+ !this.#views.some(v => v.schema === ns) &&
351
+ !Object.values(this.#nativeEnums).some(e => e.schema === ns)) {
352
+ this.#namespaces.delete(ns);
353
+ }
354
+ }
382
355
  }
383
- }
384
356
  }