@mikro-orm/sql 7.0.3 → 7.0.4-dev.1

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 +1941 -2064
  5. package/AbstractSqlPlatform.d.ts +73 -83
  6. package/AbstractSqlPlatform.js +158 -162
  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 +194 -192
  16. package/dialects/mysql/BaseMySqlPlatform.d.ts +45 -64
  17. package/dialects/mysql/BaseMySqlPlatform.js +131 -134
  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 -39
  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 +236 -232
  28. package/dialects/postgresql/BasePostgreSqlPlatform.d.ts +105 -108
  29. package/dialects/postgresql/BasePostgreSqlPlatform.js +350 -351
  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 -102
  37. package/dialects/postgresql/PostgreSqlSchemaHelper.js +705 -733
  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 -70
  51. package/dialects/sqlite/SqliteSchemaHelper.js +520 -533
  52. package/package.json +3 -3
  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 +118 -118
  64. package/query/NativeQueryBuilder.js +480 -484
  65. package/query/ObjectCriteriaNode.d.ts +12 -12
  66. package/query/ObjectCriteriaNode.js +282 -298
  67. package/query/QueryBuilder.d.ts +904 -1546
  68. package/query/QueryBuilder.js +2164 -2294
  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 -73
  78. package/schema/DatabaseSchema.js +307 -331
  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 +740 -766
  83. package/schema/SchemaHelper.d.ts +95 -109
  84. package/schema/SchemaHelper.js +659 -675
  85. package/schema/SqlSchemaGenerator.d.ts +58 -78
  86. package/schema/SqlSchemaGenerator.js +501 -535
  87. package/typings.d.ts +266 -380
@@ -1,197 +1,198 @@
1
1
  import { EnumType, StringType, TextType } from '@mikro-orm/core';
2
2
  import { SchemaHelper } from '../../schema/SchemaHelper.js';
3
3
  export class MySqlSchemaHelper extends SchemaHelper {
4
- #cache = {};
5
- static DEFAULT_VALUES = {
6
- 'now()': ['now()', 'current_timestamp'],
7
- 'current_timestamp(?)': ['current_timestamp(?)'],
8
- 0: ['0', 'false'],
9
- };
10
- getSchemaBeginning(charset, disableForeignKeys) {
11
- if (disableForeignKeys) {
12
- return `set names ${charset};\n${this.disableForeignKeysSQL()}\n\n`;
4
+ #cache = {};
5
+ static DEFAULT_VALUES = {
6
+ 'now()': ['now()', 'current_timestamp'],
7
+ 'current_timestamp(?)': ['current_timestamp(?)'],
8
+ '0': ['0', 'false'],
9
+ };
10
+ getSchemaBeginning(charset, disableForeignKeys) {
11
+ if (disableForeignKeys) {
12
+ return `set names ${charset};\n${this.disableForeignKeysSQL()}\n\n`;
13
+ }
14
+ return `set names ${charset};\n\n`;
13
15
  }
14
- return `set names ${charset};\n\n`;
15
- }
16
- disableForeignKeysSQL() {
17
- return 'set foreign_key_checks = 0;';
18
- }
19
- enableForeignKeysSQL() {
20
- return 'set foreign_key_checks = 1;';
21
- }
22
- finalizeTable(table, charset, collate) {
23
- let sql = ` default character set ${charset}`;
24
- if (collate) {
25
- sql += ` collate ${collate}`;
16
+ disableForeignKeysSQL() {
17
+ return 'set foreign_key_checks = 0;';
26
18
  }
27
- sql += ' engine = InnoDB';
28
- if (table.comment) {
29
- sql += ` comment = ${this.platform.quoteValue(table.comment)}`;
19
+ enableForeignKeysSQL() {
20
+ return 'set foreign_key_checks = 1;';
30
21
  }
31
- return sql;
32
- }
33
- getListTablesSQL() {
34
- return `select table_name as table_name, nullif(table_schema, schema()) as schema_name, table_comment as table_comment from information_schema.tables where table_type = 'BASE TABLE' and table_schema = schema()`;
35
- }
36
- getListViewsSQL() {
37
- return `select table_name as view_name, nullif(table_schema, schema()) as schema_name, view_definition from information_schema.views where table_schema = schema()`;
38
- }
39
- async loadViews(schema, connection, schemaName) {
40
- const views = await connection.execute(this.getListViewsSQL());
41
- for (const view of views) {
42
- // MySQL information_schema.views.view_definition requires SHOW VIEW privilege
43
- // and may return NULL. Use SHOW CREATE VIEW as fallback.
44
- let definition = view.view_definition?.trim();
45
- if (!definition) {
46
- const createView = await connection.execute(`show create view \`${view.view_name}\``);
47
- if (createView[0]?.['Create View']) {
48
- // Extract SELECT statement from CREATE VIEW ... AS SELECT ...
49
- const match = /\bAS\s+(.+)$/is.exec(createView[0]['Create View']);
50
- definition = match?.[1]?.trim();
22
+ finalizeTable(table, charset, collate) {
23
+ let sql = ` default character set ${charset}`;
24
+ if (collate) {
25
+ sql += ` collate ${collate}`;
26
+ }
27
+ sql += ' engine = InnoDB';
28
+ if (table.comment) {
29
+ sql += ` comment = ${this.platform.quoteValue(table.comment)}`;
51
30
  }
52
- }
53
- if (definition) {
54
- schema.addView(view.view_name, view.schema_name ?? undefined, definition);
55
- }
31
+ return sql;
32
+ }
33
+ getListTablesSQL() {
34
+ return `select table_name as table_name, nullif(table_schema, schema()) as schema_name, table_comment as table_comment from information_schema.tables where table_type = 'BASE TABLE' and table_schema = schema()`;
56
35
  }
57
- }
58
- async loadInformationSchema(schema, connection, tables) {
59
- if (tables.length === 0) {
60
- return;
36
+ getListViewsSQL() {
37
+ return `select table_name as view_name, nullif(table_schema, schema()) as schema_name, view_definition from information_schema.views where table_schema = schema()`;
61
38
  }
62
- const columns = await this.getAllColumns(connection, tables);
63
- const indexes = await this.getAllIndexes(connection, tables);
64
- const checks = await this.getAllChecks(connection, tables);
65
- const fks = await this.getAllForeignKeys(connection, tables);
66
- const enums = await this.getAllEnumDefinitions(connection, tables);
67
- for (const t of tables) {
68
- const key = this.getTableKey(t);
69
- const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
70
- const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
71
- table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums[key]);
39
+ async loadViews(schema, connection, schemaName) {
40
+ const views = await connection.execute(this.getListViewsSQL());
41
+ for (const view of views) {
42
+ // MySQL information_schema.views.view_definition requires SHOW VIEW privilege
43
+ // and may return NULL. Use SHOW CREATE VIEW as fallback.
44
+ let definition = view.view_definition?.trim();
45
+ if (!definition) {
46
+ const createView = await connection.execute(`show create view \`${view.view_name}\``);
47
+ if (createView[0]?.['Create View']) {
48
+ // Extract SELECT statement from CREATE VIEW ... AS SELECT ...
49
+ const match = /\bAS\s+(.+)$/is.exec(createView[0]['Create View']);
50
+ definition = match?.[1]?.trim();
51
+ }
52
+ }
53
+ if (definition) {
54
+ schema.addView(view.view_name, view.schema_name ?? undefined, definition);
55
+ }
56
+ }
72
57
  }
73
- }
74
- async getAllIndexes(connection, tables) {
75
- const sql = `select table_name as table_name, nullif(table_schema, schema()) as schema_name, index_name as index_name, non_unique as non_unique, column_name as column_name, index_type as index_type, sub_part as sub_part, collation as sort_order /*!80013 , expression as expression, is_visible as is_visible */
58
+ async loadInformationSchema(schema, connection, tables) {
59
+ if (tables.length === 0) {
60
+ return;
61
+ }
62
+ const columns = await this.getAllColumns(connection, tables);
63
+ const indexes = await this.getAllIndexes(connection, tables);
64
+ const checks = await this.getAllChecks(connection, tables);
65
+ const fks = await this.getAllForeignKeys(connection, tables);
66
+ const enums = await this.getAllEnumDefinitions(connection, tables);
67
+ for (const t of tables) {
68
+ const key = this.getTableKey(t);
69
+ const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
70
+ const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
71
+ table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums[key]);
72
+ }
73
+ }
74
+ async getAllIndexes(connection, tables) {
75
+ const sql = `select table_name as table_name, nullif(table_schema, schema()) as schema_name, index_name as index_name, non_unique as non_unique, column_name as column_name, index_type as index_type, sub_part as sub_part, collation as sort_order /*!80013 , expression as expression, is_visible as is_visible */
76
76
  from information_schema.statistics where table_schema = database()
77
77
  and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')})
78
78
  order by schema_name, table_name, index_name, seq_in_index`;
79
- const allIndexes = await connection.execute(sql);
80
- const ret = {};
81
- for (const index of allIndexes) {
82
- const key = this.getTableKey(index);
83
- const indexDef = {
84
- columnNames: [index.column_name],
85
- keyName: index.index_name,
86
- unique: !index.non_unique,
87
- primary: index.index_name === 'PRIMARY',
88
- constraint: !index.non_unique,
89
- };
90
- // Capture column options (prefix length, sort order)
91
- if (index.sub_part != null || index.sort_order === 'D') {
92
- indexDef.columns = [
93
- {
94
- name: index.column_name,
95
- ...(index.sub_part != null && { length: index.sub_part }),
96
- ...(index.sort_order === 'D' && { sort: 'DESC' }),
97
- },
98
- ];
99
- }
100
- // Capture index type for fulltext and spatial indexes
101
- if (index.index_type === 'FULLTEXT') {
102
- indexDef.type = 'fulltext';
103
- } else if (index.index_type === 'SPATIAL') {
104
- /* v8 ignore next */
105
- indexDef.type = 'spatial';
106
- }
107
- // Capture invisible flag (MySQL 8.0.13+)
108
- if (index.is_visible === 'NO') {
109
- indexDef.invisible = true;
110
- }
111
- if (!index.column_name || index.expression?.match(/ where /i)) {
112
- indexDef.expression = index.expression; // required for the `getCreateIndexSQL()` call
113
- indexDef.expression = this.getCreateIndexSQL(index.table_name, indexDef, !!index.expression);
114
- }
115
- ret[key] ??= [];
116
- ret[key].push(indexDef);
117
- }
118
- for (const key of Object.keys(ret)) {
119
- ret[key] = await this.mapIndexes(ret[key]);
120
- }
121
- return ret;
122
- }
123
- getCreateIndexSQL(tableName, index, partialExpression = false) {
124
- /* v8 ignore next */
125
- if (index.expression && !partialExpression) {
126
- return index.expression;
127
- }
128
- tableName = this.quote(tableName);
129
- const keyName = this.quote(index.keyName);
130
- let sql = `alter table ${tableName} add ${index.unique ? 'unique' : 'index'} ${keyName} `;
131
- if (index.expression && partialExpression) {
132
- sql += `(${index.expression})`;
133
- return this.appendMySqlIndexSuffix(sql, index);
79
+ const allIndexes = await connection.execute(sql);
80
+ const ret = {};
81
+ for (const index of allIndexes) {
82
+ const key = this.getTableKey(index);
83
+ const indexDef = {
84
+ columnNames: [index.column_name],
85
+ keyName: index.index_name,
86
+ unique: !index.non_unique,
87
+ primary: index.index_name === 'PRIMARY',
88
+ constraint: !index.non_unique,
89
+ };
90
+ // Capture column options (prefix length, sort order)
91
+ if (index.sub_part != null || index.sort_order === 'D') {
92
+ indexDef.columns = [
93
+ {
94
+ name: index.column_name,
95
+ ...(index.sub_part != null && { length: index.sub_part }),
96
+ ...(index.sort_order === 'D' && { sort: 'DESC' }),
97
+ },
98
+ ];
99
+ }
100
+ // Capture index type for fulltext and spatial indexes
101
+ if (index.index_type === 'FULLTEXT') {
102
+ indexDef.type = 'fulltext';
103
+ }
104
+ else if (index.index_type === 'SPATIAL') {
105
+ /* v8 ignore next */
106
+ indexDef.type = 'spatial';
107
+ }
108
+ // Capture invisible flag (MySQL 8.0.13+)
109
+ if (index.is_visible === 'NO') {
110
+ indexDef.invisible = true;
111
+ }
112
+ if (!index.column_name || index.expression?.match(/ where /i)) {
113
+ indexDef.expression = index.expression; // required for the `getCreateIndexSQL()` call
114
+ indexDef.expression = this.getCreateIndexSQL(index.table_name, indexDef, !!index.expression);
115
+ }
116
+ ret[key] ??= [];
117
+ ret[key].push(indexDef);
118
+ }
119
+ for (const key of Object.keys(ret)) {
120
+ ret[key] = await this.mapIndexes(ret[key]);
121
+ }
122
+ return ret;
134
123
  }
135
- // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
136
- if (index.columnNames.some(column => column.includes('.'))) {
137
- const columns = this.platform.getJsonIndexDefinition(index);
138
- sql = `alter table ${tableName} add ${index.unique ? 'unique ' : ''}index ${keyName} `;
139
- sql += `(${columns.join(', ')})`;
140
- return this.appendMySqlIndexSuffix(sql, index);
124
+ getCreateIndexSQL(tableName, index, partialExpression = false) {
125
+ /* v8 ignore next */
126
+ if (index.expression && !partialExpression) {
127
+ return index.expression;
128
+ }
129
+ tableName = this.quote(tableName);
130
+ const keyName = this.quote(index.keyName);
131
+ let sql = `alter table ${tableName} add ${index.unique ? 'unique' : 'index'} ${keyName} `;
132
+ if (index.expression && partialExpression) {
133
+ sql += `(${index.expression})`;
134
+ return this.appendMySqlIndexSuffix(sql, index);
135
+ }
136
+ // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
137
+ if (index.columnNames.some(column => column.includes('.'))) {
138
+ const columns = this.platform.getJsonIndexDefinition(index);
139
+ sql = `alter table ${tableName} add ${index.unique ? 'unique ' : ''}index ${keyName} `;
140
+ sql += `(${columns.join(', ')})`;
141
+ return this.appendMySqlIndexSuffix(sql, index);
142
+ }
143
+ // Build column list with advanced options
144
+ const columns = this.getIndexColumns(index);
145
+ sql += `(${columns})`;
146
+ return this.appendMySqlIndexSuffix(sql, index);
141
147
  }
142
- // Build column list with advanced options
143
- const columns = this.getIndexColumns(index);
144
- sql += `(${columns})`;
145
- return this.appendMySqlIndexSuffix(sql, index);
146
- }
147
- /**
148
- * Build the column list for a MySQL index, with MySQL-specific handling for collation.
149
- * MySQL requires collation to be specified as an expression: (column_name COLLATE collation_name)
150
- */
151
- getIndexColumns(index) {
152
- if (index.columns?.length) {
153
- return index.columns
154
- .map(col => {
155
- const quotedName = this.quote(col.name);
156
- // MySQL supports collation via expression: (column_name COLLATE collation_name)
157
- // When collation is specified, wrap in parentheses as an expression
158
- if (col.collation) {
159
- let expr = col.length ? `${quotedName}(${col.length})` : quotedName;
160
- expr = `(${expr} collate ${col.collation})`;
161
- // Sort order comes after the expression
162
- if (col.sort) {
163
- expr += ` ${col.sort}`;
164
- }
165
- return expr;
166
- }
167
- // Standard column definition without collation
168
- let colDef = quotedName;
169
- // MySQL supports prefix length
170
- if (col.length) {
171
- colDef += `(${col.length})`;
172
- }
173
- // MySQL supports sort order
174
- if (col.sort) {
175
- colDef += ` ${col.sort}`;
176
- }
177
- return colDef;
178
- })
179
- .join(', ');
148
+ /**
149
+ * Build the column list for a MySQL index, with MySQL-specific handling for collation.
150
+ * MySQL requires collation to be specified as an expression: (column_name COLLATE collation_name)
151
+ */
152
+ getIndexColumns(index) {
153
+ if (index.columns?.length) {
154
+ return index.columns
155
+ .map(col => {
156
+ const quotedName = this.quote(col.name);
157
+ // MySQL supports collation via expression: (column_name COLLATE collation_name)
158
+ // When collation is specified, wrap in parentheses as an expression
159
+ if (col.collation) {
160
+ let expr = col.length ? `${quotedName}(${col.length})` : quotedName;
161
+ expr = `(${expr} collate ${col.collation})`;
162
+ // Sort order comes after the expression
163
+ if (col.sort) {
164
+ expr += ` ${col.sort}`;
165
+ }
166
+ return expr;
167
+ }
168
+ // Standard column definition without collation
169
+ let colDef = quotedName;
170
+ // MySQL supports prefix length
171
+ if (col.length) {
172
+ colDef += `(${col.length})`;
173
+ }
174
+ // MySQL supports sort order
175
+ if (col.sort) {
176
+ colDef += ` ${col.sort}`;
177
+ }
178
+ return colDef;
179
+ })
180
+ .join(', ');
181
+ }
182
+ return index.columnNames.map(c => this.quote(c)).join(', ');
180
183
  }
181
- return index.columnNames.map(c => this.quote(c)).join(', ');
182
- }
183
- /**
184
- * Append MySQL-specific index suffixes like INVISIBLE.
185
- */
186
- appendMySqlIndexSuffix(sql, index) {
187
- // MySQL 8.0+ supports INVISIBLE indexes
188
- if (index.invisible) {
189
- sql += ' invisible';
184
+ /**
185
+ * Append MySQL-specific index suffixes like INVISIBLE.
186
+ */
187
+ appendMySqlIndexSuffix(sql, index) {
188
+ // MySQL 8.0+ supports INVISIBLE indexes
189
+ if (index.invisible) {
190
+ sql += ' invisible';
191
+ }
192
+ return sql;
190
193
  }
191
- return sql;
192
- }
193
- async getAllColumns(connection, tables) {
194
- const sql = `select table_name as table_name,
194
+ async getAllColumns(connection, tables) {
195
+ const sql = `select table_name as table_name,
195
196
  nullif(table_schema, schema()) as schema_name,
196
197
  column_name as column_name,
197
198
  column_default as column_default,
@@ -207,160 +208,151 @@ export class MySqlSchemaHelper extends SchemaHelper {
207
208
  ifnull(datetime_precision, character_maximum_length) length
208
209
  from information_schema.columns where table_schema = database() and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name))})
209
210
  order by ordinal_position`;
210
- const allColumns = await connection.execute(sql);
211
- const str = val => (val != null ? '' + val : val);
212
- const extra = val =>
213
- val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim() || undefined;
214
- const ret = {};
215
- for (const col of allColumns) {
216
- const mappedType = this.platform.getMappedType(col.column_type);
217
- const defaultValue = str(
218
- this.normalizeDefaultValue(
219
- mappedType.compareAsType() === 'boolean' && ['0', '1'].includes(col.column_default)
220
- ? ['false', 'true'][+col.column_default]
221
- : col.column_default,
222
- col.length,
223
- ),
224
- );
225
- const key = this.getTableKey(col);
226
- const generated = col.generation_expression
227
- ? `(${col.generation_expression.replaceAll(`\\'`, `'`)}) ${col.extra.match(/stored generated/i) ? 'stored' : 'virtual'}`
228
- : undefined;
229
- ret[key] ??= [];
230
- ret[key].push({
231
- name: col.column_name,
232
- type: this.platform.isNumericColumn(mappedType)
233
- ? col.column_type.replace(/ unsigned$/, '').replace(/\(\d+\)$/, '')
234
- : col.column_type,
235
- mappedType,
236
- unsigned: col.column_type.endsWith(' unsigned'),
237
- length: col.length,
238
- default: this.wrap(defaultValue, mappedType),
239
- nullable: col.is_nullable === 'YES',
240
- primary: col.column_key === 'PRI',
241
- unique: col.column_key === 'UNI',
242
- autoincrement: col.extra === 'auto_increment',
243
- precision: col.numeric_precision,
244
- scale: col.numeric_scale,
245
- comment: col.column_comment,
246
- extra: extra(col.extra),
247
- generated,
248
- });
249
- }
250
- return ret;
251
- }
252
- async getAllChecks(connection, tables) {
253
- /* v8 ignore next */
254
- if (!(await this.supportsCheckConstraints(connection))) {
255
- return {};
211
+ const allColumns = await connection.execute(sql);
212
+ const str = (val) => (val != null ? '' + val : val);
213
+ const extra = (val) => val.replace(/auto_increment|default_generated|(stored|virtual) generated/i, '').trim() || undefined;
214
+ const ret = {};
215
+ for (const col of allColumns) {
216
+ const mappedType = this.platform.getMappedType(col.column_type);
217
+ const defaultValue = str(this.normalizeDefaultValue(mappedType.compareAsType() === 'boolean' && ['0', '1'].includes(col.column_default)
218
+ ? ['false', 'true'][+col.column_default]
219
+ : col.column_default, col.length));
220
+ const key = this.getTableKey(col);
221
+ const generated = col.generation_expression
222
+ ? `(${col.generation_expression.replaceAll(`\\'`, `'`)}) ${col.extra.match(/stored generated/i) ? 'stored' : 'virtual'}`
223
+ : undefined;
224
+ ret[key] ??= [];
225
+ ret[key].push({
226
+ name: col.column_name,
227
+ type: this.platform.isNumericColumn(mappedType)
228
+ ? col.column_type.replace(/ unsigned$/, '').replace(/\(\d+\)$/, '')
229
+ : col.column_type,
230
+ mappedType,
231
+ unsigned: col.column_type.endsWith(' unsigned'),
232
+ length: col.length,
233
+ default: this.wrap(defaultValue, mappedType),
234
+ nullable: col.is_nullable === 'YES',
235
+ primary: col.column_key === 'PRI',
236
+ unique: col.column_key === 'UNI',
237
+ autoincrement: col.extra === 'auto_increment',
238
+ precision: col.numeric_precision,
239
+ scale: col.numeric_scale,
240
+ comment: col.column_comment,
241
+ extra: extra(col.extra),
242
+ generated,
243
+ });
244
+ }
245
+ return ret;
256
246
  }
257
- const sql = this.getChecksSQL(tables);
258
- const allChecks = await connection.execute(sql);
259
- const ret = {};
260
- for (const check of allChecks) {
261
- const key = this.getTableKey(check);
262
- ret[key] ??= [];
263
- ret[key].push({
264
- name: check.name,
265
- columnName: check.column_name,
266
- definition: `check ${check.expression}`,
267
- expression: check.expression.replace(/^\((.*)\)$/, '$1'),
268
- });
247
+ async getAllChecks(connection, tables) {
248
+ /* v8 ignore next */
249
+ if (!(await this.supportsCheckConstraints(connection))) {
250
+ return {};
251
+ }
252
+ const sql = this.getChecksSQL(tables);
253
+ const allChecks = await connection.execute(sql);
254
+ const ret = {};
255
+ for (const check of allChecks) {
256
+ const key = this.getTableKey(check);
257
+ ret[key] ??= [];
258
+ ret[key].push({
259
+ name: check.name,
260
+ columnName: check.column_name,
261
+ definition: `check ${check.expression}`,
262
+ expression: check.expression.replace(/^\((.*)\)$/, '$1'),
263
+ });
264
+ }
265
+ return ret;
269
266
  }
270
- return ret;
271
- }
272
- async getAllForeignKeys(connection, tables) {
273
- const sql = `select k.constraint_name as constraint_name, nullif(k.table_schema, schema()) as schema_name, k.table_name as table_name, k.column_name as column_name, k.referenced_table_name as referenced_table_name, k.referenced_column_name as referenced_column_name, c.update_rule as update_rule, c.delete_rule as delete_rule
267
+ async getAllForeignKeys(connection, tables) {
268
+ const sql = `select k.constraint_name as constraint_name, nullif(k.table_schema, schema()) as schema_name, k.table_name as table_name, k.column_name as column_name, k.referenced_table_name as referenced_table_name, k.referenced_column_name as referenced_column_name, c.update_rule as update_rule, c.delete_rule as delete_rule
274
269
  from information_schema.key_column_usage k
275
270
  inner join information_schema.referential_constraints c on c.constraint_name = k.constraint_name and c.table_name = k.table_name
276
271
  where k.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')})
277
272
  and k.table_schema = database() and c.constraint_schema = database() and k.referenced_column_name is not null
278
273
  order by constraint_name, k.ordinal_position`;
279
- const allFks = await connection.execute(sql);
280
- const ret = {};
281
- for (const fk of allFks) {
282
- const key = this.getTableKey(fk);
283
- ret[key] ??= [];
284
- ret[key].push(fk);
274
+ const allFks = await connection.execute(sql);
275
+ const ret = {};
276
+ for (const fk of allFks) {
277
+ const key = this.getTableKey(fk);
278
+ ret[key] ??= [];
279
+ ret[key].push(fk);
280
+ }
281
+ Object.keys(ret).forEach(key => {
282
+ const parts = key.split('.');
283
+ /* v8 ignore next */
284
+ const schemaName = parts.length > 1 ? parts[0] : undefined;
285
+ ret[key] = this.mapForeignKeys(ret[key], key, schemaName);
286
+ });
287
+ return ret;
285
288
  }
286
- Object.keys(ret).forEach(key => {
287
- const parts = key.split('.');
288
- /* v8 ignore next */
289
- const schemaName = parts.length > 1 ? parts[0] : undefined;
290
- ret[key] = this.mapForeignKeys(ret[key], key, schemaName);
291
- });
292
- return ret;
293
- }
294
- getPreAlterTable(tableDiff, safe) {
295
- // Dropping primary keys requires to unset autoincrement attribute on the particular column first.
296
- const pk = Object.values(tableDiff.removedIndexes).find(idx => idx.primary);
297
- if (!pk || safe) {
298
- return [];
289
+ getPreAlterTable(tableDiff, safe) {
290
+ // Dropping primary keys requires to unset autoincrement attribute on the particular column first.
291
+ const pk = Object.values(tableDiff.removedIndexes).find(idx => idx.primary);
292
+ if (!pk || safe) {
293
+ return [];
294
+ }
295
+ return pk.columnNames
296
+ .filter(col => tableDiff.fromTable.hasColumn(col))
297
+ .map(col => tableDiff.fromTable.getColumn(col))
298
+ .filter(col => col.autoincrement)
299
+ .map(col => `alter table \`${tableDiff.name}\` modify \`${col.name}\` ${this.getColumnDeclarationSQL({ ...col, autoincrement: false })}`);
300
+ }
301
+ getRenameColumnSQL(tableName, oldColumnName, to) {
302
+ tableName = this.quote(tableName);
303
+ oldColumnName = this.quote(oldColumnName);
304
+ const columnName = this.quote(to.name);
305
+ return `alter table ${tableName} change ${oldColumnName} ${columnName} ${this.getColumnDeclarationSQL(to)}`;
306
+ }
307
+ getRenameIndexSQL(tableName, index, oldIndexName) {
308
+ tableName = this.quote(tableName);
309
+ oldIndexName = this.quote(oldIndexName);
310
+ const keyName = this.quote(index.keyName);
311
+ return [`alter table ${tableName} rename index ${oldIndexName} to ${keyName}`];
312
+ }
313
+ getChangeColumnCommentSQL(tableName, to, schemaName) {
314
+ tableName = this.quote(tableName);
315
+ const columnName = this.quote(to.name);
316
+ return `alter table ${tableName} modify ${columnName} ${this.getColumnDeclarationSQL(to)}`;
317
+ }
318
+ alterTableColumn(column, table, changedProperties) {
319
+ const col = this.createTableColumn(column, table, changedProperties);
320
+ return [`alter table ${table.getQuotedName()} modify ${col}`];
321
+ }
322
+ getColumnDeclarationSQL(col) {
323
+ let ret = col.type;
324
+ ret += col.unsigned ? ' unsigned' : '';
325
+ ret += col.autoincrement ? ' auto_increment' : '';
326
+ ret += ' ';
327
+ ret += col.nullable ? 'null' : 'not null';
328
+ ret += col.default ? ' default ' + col.default : '';
329
+ ret += col.comment ? ` comment ${this.platform.quoteValue(col.comment)}` : '';
330
+ return ret;
299
331
  }
300
- return pk.columnNames
301
- .filter(col => tableDiff.fromTable.hasColumn(col))
302
- .map(col => tableDiff.fromTable.getColumn(col))
303
- .filter(col => col.autoincrement)
304
- .map(
305
- col =>
306
- `alter table \`${tableDiff.name}\` modify \`${col.name}\` ${this.getColumnDeclarationSQL({ ...col, autoincrement: false })}`,
307
- );
308
- }
309
- getRenameColumnSQL(tableName, oldColumnName, to) {
310
- tableName = this.quote(tableName);
311
- oldColumnName = this.quote(oldColumnName);
312
- const columnName = this.quote(to.name);
313
- return `alter table ${tableName} change ${oldColumnName} ${columnName} ${this.getColumnDeclarationSQL(to)}`;
314
- }
315
- getRenameIndexSQL(tableName, index, oldIndexName) {
316
- tableName = this.quote(tableName);
317
- oldIndexName = this.quote(oldIndexName);
318
- const keyName = this.quote(index.keyName);
319
- return [`alter table ${tableName} rename index ${oldIndexName} to ${keyName}`];
320
- }
321
- getChangeColumnCommentSQL(tableName, to, schemaName) {
322
- tableName = this.quote(tableName);
323
- const columnName = this.quote(to.name);
324
- return `alter table ${tableName} modify ${columnName} ${this.getColumnDeclarationSQL(to)}`;
325
- }
326
- alterTableColumn(column, table, changedProperties) {
327
- const col = this.createTableColumn(column, table, changedProperties);
328
- return [`alter table ${table.getQuotedName()} modify ${col}`];
329
- }
330
- getColumnDeclarationSQL(col) {
331
- let ret = col.type;
332
- ret += col.unsigned ? ' unsigned' : '';
333
- ret += col.autoincrement ? ' auto_increment' : '';
334
- ret += ' ';
335
- ret += col.nullable ? 'null' : 'not null';
336
- ret += col.default ? ' default ' + col.default : '';
337
- ret += col.comment ? ` comment ${this.platform.quoteValue(col.comment)}` : '';
338
- return ret;
339
- }
340
- async getAllEnumDefinitions(connection, tables) {
341
- const sql = `select column_name as column_name, column_type as column_type, table_name as table_name
332
+ async getAllEnumDefinitions(connection, tables) {
333
+ const sql = `select column_name as column_name, column_type as column_type, table_name as table_name
342
334
  from information_schema.columns
343
335
  where data_type = 'enum' and table_name in (${tables.map(t => `'${t.table_name}'`).join(', ')}) and table_schema = database()`;
344
- const enums = await connection.execute(sql);
345
- return enums.reduce((o, item) => {
346
- o[item.table_name] ??= {};
347
- o[item.table_name][item.column_name] = item.column_type
348
- .match(/enum\((.*)\)/)[1]
349
- .split(',')
350
- .map(item => /'(.*)'/.exec(item)[1]);
351
- return o;
352
- }, {});
353
- }
354
- async supportsCheckConstraints(connection) {
355
- if (this.#cache.supportsCheckConstraints != null) {
356
- return this.#cache.supportsCheckConstraints;
336
+ const enums = await connection.execute(sql);
337
+ return enums.reduce((o, item) => {
338
+ o[item.table_name] ??= {};
339
+ o[item.table_name][item.column_name] = item.column_type
340
+ .match(/enum\((.*)\)/)[1]
341
+ .split(',')
342
+ .map((item) => /'(.*)'/.exec(item)[1]);
343
+ return o;
344
+ }, {});
357
345
  }
358
- const sql = `select 1 from information_schema.tables where table_name = 'CHECK_CONSTRAINTS' and table_schema = 'information_schema'`;
359
- const res = await connection.execute(sql);
360
- return (this.#cache.supportsCheckConstraints = res.length > 0);
361
- }
362
- getChecksSQL(tables) {
363
- return `select cc.constraint_schema as table_schema, tc.table_name as table_name, cc.constraint_name as name, cc.check_clause as expression
346
+ async supportsCheckConstraints(connection) {
347
+ if (this.#cache.supportsCheckConstraints != null) {
348
+ return this.#cache.supportsCheckConstraints;
349
+ }
350
+ const sql = `select 1 from information_schema.tables where table_name = 'CHECK_CONSTRAINTS' and table_schema = 'information_schema'`;
351
+ const res = await connection.execute(sql);
352
+ return (this.#cache.supportsCheckConstraints = res.length > 0);
353
+ }
354
+ getChecksSQL(tables) {
355
+ return `select cc.constraint_schema as table_schema, tc.table_name as table_name, cc.constraint_name as name, cc.check_clause as expression
364
356
  from information_schema.check_constraints cc
365
357
  join information_schema.table_constraints tc
366
358
  on tc.constraint_schema = cc.constraint_schema
@@ -368,12 +360,12 @@ export class MySqlSchemaHelper extends SchemaHelper {
368
360
  and constraint_type = 'CHECK'
369
361
  where tc.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name))}) and tc.constraint_schema = database()
370
362
  order by tc.constraint_name`;
371
- }
372
- normalizeDefaultValue(defaultValue, length) {
373
- return super.normalizeDefaultValue(defaultValue, length, MySqlSchemaHelper.DEFAULT_VALUES);
374
- }
375
- wrap(val, type) {
376
- const stringType = type instanceof StringType || type instanceof TextType || type instanceof EnumType;
377
- return typeof val === 'string' && val.length > 0 && stringType ? this.platform.quoteValue(val) : val;
378
- }
363
+ }
364
+ normalizeDefaultValue(defaultValue, length) {
365
+ return super.normalizeDefaultValue(defaultValue, length, MySqlSchemaHelper.DEFAULT_VALUES);
366
+ }
367
+ wrap(val, type) {
368
+ const stringType = type instanceof StringType || type instanceof TextType || type instanceof EnumType;
369
+ return typeof val === 'string' && val.length > 0 && stringType ? this.platform.quoteValue(val) : val;
370
+ }
379
371
  }