@mikro-orm/knex 6.4.6-dev.9 → 7.0.0-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 (101) hide show
  1. package/AbstractSqlConnection.d.ts +15 -25
  2. package/AbstractSqlConnection.js +98 -126
  3. package/AbstractSqlDriver.d.ts +20 -13
  4. package/AbstractSqlDriver.js +73 -54
  5. package/AbstractSqlPlatform.d.ts +15 -3
  6. package/AbstractSqlPlatform.js +32 -11
  7. package/README.md +0 -2
  8. package/SqlEntityManager.d.ts +5 -6
  9. package/SqlEntityManager.js +5 -5
  10. package/SqlEntityRepository.d.ts +1 -6
  11. package/SqlEntityRepository.js +0 -6
  12. package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +12 -0
  13. package/dialects/mssql/MsSqlNativeQueryBuilder.js +161 -0
  14. package/dialects/mssql/index.d.ts +1 -1
  15. package/dialects/mssql/index.js +1 -1
  16. package/dialects/mysql/MySqlExceptionConverter.js +1 -0
  17. package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +7 -0
  18. package/dialects/mysql/MySqlNativeQueryBuilder.js +81 -0
  19. package/dialects/mysql/MySqlPlatform.d.ts +5 -1
  20. package/dialects/mysql/MySqlPlatform.js +9 -1
  21. package/dialects/mysql/MySqlSchemaHelper.d.ts +6 -12
  22. package/dialects/mysql/MySqlSchemaHelper.js +42 -75
  23. package/dialects/mysql/index.d.ts +1 -3
  24. package/dialects/mysql/index.js +1 -3
  25. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +5 -0
  26. package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +12 -0
  27. package/dialects/postgresql/index.d.ts +1 -1
  28. package/dialects/postgresql/index.js +1 -1
  29. package/dialects/sqlite/BaseSqliteConnection.d.ts +0 -5
  30. package/dialects/sqlite/BaseSqliteConnection.js +4 -42
  31. package/dialects/sqlite/BaseSqlitePlatform.d.ts +15 -3
  32. package/dialects/sqlite/BaseSqlitePlatform.js +20 -4
  33. package/dialects/sqlite/SqliteExceptionConverter.d.ts +9 -0
  34. package/dialects/sqlite/SqliteExceptionConverter.js +55 -0
  35. package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +6 -0
  36. package/dialects/sqlite/SqliteNativeQueryBuilder.js +15 -0
  37. package/dialects/sqlite/SqliteSchemaHelper.d.ts +38 -0
  38. package/dialects/sqlite/SqliteSchemaHelper.js +384 -0
  39. package/dialects/sqlite/index.d.ts +3 -5
  40. package/dialects/sqlite/index.js +3 -5
  41. package/index.d.ts +1 -2
  42. package/index.js +3 -5
  43. package/index.mjs +10 -13
  44. package/package.json +4 -18
  45. package/query/CriteriaNodeFactory.js +5 -5
  46. package/query/NativeQueryBuilder.d.ts +108 -0
  47. package/query/NativeQueryBuilder.js +429 -0
  48. package/query/ObjectCriteriaNode.js +3 -3
  49. package/query/QueryBuilder.d.ts +30 -34
  50. package/query/QueryBuilder.js +112 -123
  51. package/query/QueryBuilderHelper.d.ts +27 -23
  52. package/query/QueryBuilderHelper.js +174 -168
  53. package/query/ScalarCriteriaNode.js +4 -0
  54. package/query/index.d.ts +1 -0
  55. package/query/index.js +1 -0
  56. package/schema/DatabaseSchema.js +9 -6
  57. package/schema/DatabaseTable.d.ts +2 -1
  58. package/schema/DatabaseTable.js +9 -5
  59. package/schema/SchemaComparator.d.ts +1 -2
  60. package/schema/SchemaComparator.js +31 -18
  61. package/schema/SchemaHelper.d.ts +27 -33
  62. package/schema/SchemaHelper.js +294 -184
  63. package/schema/SqlSchemaGenerator.d.ts +3 -9
  64. package/schema/SqlSchemaGenerator.js +105 -229
  65. package/typings.d.ts +7 -17
  66. package/MonkeyPatchable.d.ts +0 -18
  67. package/MonkeyPatchable.js +0 -60
  68. package/dialects/mssql/MsSqlColumnCompiler.d.ts +0 -4
  69. package/dialects/mssql/MsSqlColumnCompiler.js +0 -10
  70. package/dialects/mssql/MsSqlKnexDialect.d.ts +0 -6
  71. package/dialects/mssql/MsSqlKnexDialect.js +0 -22
  72. package/dialects/mssql/MsSqlQueryCompiler.d.ts +0 -12
  73. package/dialects/mssql/MsSqlQueryCompiler.js +0 -94
  74. package/dialects/mssql/MsSqlTableCompiler.d.ts +0 -9
  75. package/dialects/mssql/MsSqlTableCompiler.js +0 -40
  76. package/dialects/mysql/MariaDbKnexDialect.d.ts +0 -6
  77. package/dialects/mysql/MariaDbKnexDialect.js +0 -16
  78. package/dialects/mysql/MySqlColumnCompiler.d.ts +0 -7
  79. package/dialects/mysql/MySqlColumnCompiler.js +0 -26
  80. package/dialects/mysql/MySqlConnection.d.ts +0 -8
  81. package/dialects/mysql/MySqlConnection.js +0 -43
  82. package/dialects/mysql/MySqlKnexDialect.d.ts +0 -5
  83. package/dialects/mysql/MySqlKnexDialect.js +0 -17
  84. package/dialects/mysql/MySqlQueryCompiler.d.ts +0 -5
  85. package/dialects/mysql/MySqlQueryCompiler.js +0 -23
  86. package/dialects/postgresql/PostgreSqlKnexDialect.d.ts +0 -7
  87. package/dialects/postgresql/PostgreSqlKnexDialect.js +0 -20
  88. package/dialects/postgresql/PostgreSqlQueryCompiler.d.ts +0 -4
  89. package/dialects/postgresql/PostgreSqlQueryCompiler.js +0 -13
  90. package/dialects/postgresql/PostgreSqlTableCompiler.d.ts +0 -11
  91. package/dialects/postgresql/PostgreSqlTableCompiler.js +0 -89
  92. package/dialects/sqlite/BaseSqliteSchemaHelper.d.ts +0 -28
  93. package/dialects/sqlite/BaseSqliteSchemaHelper.js +0 -200
  94. package/dialects/sqlite/BetterSqliteKnexDialect.d.ts +0 -5
  95. package/dialects/sqlite/BetterSqliteKnexDialect.js +0 -15
  96. package/dialects/sqlite/LibSqlKnexDialect.d.ts +0 -11
  97. package/dialects/sqlite/LibSqlKnexDialect.js +0 -85
  98. package/dialects/sqlite/SqliteKnexDialect.d.ts +0 -8
  99. package/dialects/sqlite/SqliteKnexDialect.js +0 -67
  100. package/dialects/sqlite/SqliteTableCompiler.d.ts +0 -6
  101. package/dialects/sqlite/SqliteTableCompiler.js +0 -71
@@ -7,7 +7,7 @@ class SchemaHelper {
7
7
  constructor(platform) {
8
8
  this.platform = platform;
9
9
  }
10
- getSchemaBeginning(charset, disableForeignKeys) {
10
+ getSchemaBeginning(_charset, disableForeignKeys) {
11
11
  if (disableForeignKeys) {
12
12
  return `${this.disableForeignKeysSQL()}\n`;
13
13
  }
@@ -26,7 +26,10 @@ class SchemaHelper {
26
26
  return '';
27
27
  }
28
28
  finalizeTable(table, charset, collate) {
29
- //
29
+ return '';
30
+ }
31
+ appendComments(table) {
32
+ return [];
30
33
  }
31
34
  supportsSchemaConstraints() {
32
35
  return true;
@@ -42,10 +45,6 @@ class SchemaHelper {
42
45
  }
43
46
  return +match[1];
44
47
  }
45
- async getForeignKeys(connection, tableName, schemaName) {
46
- const fks = await connection.execute(this.getForeignKeysSQL(tableName, schemaName));
47
- return this.mapForeignKeys(fks, tableName, schemaName);
48
- }
49
48
  getTableKey(t) {
50
49
  const unquote = (str) => str.replace(/['"`]/g, '');
51
50
  const parts = t.table_name.split('.');
@@ -57,9 +56,6 @@ class SchemaHelper {
57
56
  }
58
57
  return unquote(t.table_name);
59
58
  }
60
- async getEnumDefinitions(connection, checks, tableName, schemaName) {
61
- return {};
62
- }
63
59
  getCreateNativeEnumSQL(name, values, schema) {
64
60
  throw new Error('Not supported by given driver');
65
61
  }
@@ -69,51 +65,159 @@ class SchemaHelper {
69
65
  getAlterNativeEnumSQL(name, schema, value, items, oldItems) {
70
66
  throw new Error('Not supported by given driver');
71
67
  }
72
- async loadInformationSchema(schema, connection, tables, schemas) {
73
- for (const t of tables) {
74
- const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
75
- const cols = await this.getColumns(connection, table.name, table.schema);
76
- const indexes = await this.getIndexes(connection, table.name, table.schema);
77
- const checks = await this.getChecks(connection, table.name, table.schema, cols);
78
- const pks = await this.getPrimaryKeys(connection, indexes, table.name, table.schema);
79
- const fks = await this.getForeignKeys(connection, table.name, table.schema);
80
- const enums = await this.getEnumDefinitions(connection, checks, table.name, table.schema);
81
- table.init(cols, indexes, checks, pks, fks, enums);
82
- }
83
- }
84
68
  getListTablesSQL(schemaName) {
85
69
  throw new Error('Not supported by given driver');
86
70
  }
87
71
  getRenameColumnSQL(tableName, oldColumnName, to, schemaName) {
88
- tableName = this.platform.quoteIdentifier(tableName);
89
- oldColumnName = this.platform.quoteIdentifier(oldColumnName);
90
- const columnName = this.platform.quoteIdentifier(to.name);
72
+ tableName = this.quote(tableName);
73
+ oldColumnName = this.quote(oldColumnName);
74
+ const columnName = this.quote(to.name);
91
75
  const schemaReference = (schemaName !== undefined && schemaName !== 'public') ? ('"' + schemaName + '".') : '';
92
76
  const tableReference = schemaReference + tableName;
93
77
  return `alter table ${tableReference} rename column ${oldColumnName} to ${columnName}`;
94
78
  }
95
- getCreateIndexSQL(tableName, index, partialExpression = false) {
79
+ getCreateIndexSQL(tableName, index) {
96
80
  /* istanbul ignore next */
97
- if (index.expression && !partialExpression) {
81
+ if (index.expression) {
98
82
  return index.expression;
99
83
  }
100
- tableName = this.platform.quoteIdentifier(tableName);
101
- const keyName = this.platform.quoteIdentifier(index.keyName);
102
- const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
103
- if (index.expression && partialExpression) {
104
- return `${sql}(${index.expression})`;
84
+ tableName = this.quote(tableName);
85
+ const keyName = this.quote(index.keyName);
86
+ const defer = index.deferMode ? ` deferrable initially ${index.deferMode}` : '';
87
+ let sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
88
+ if (index.unique && index.constraint) {
89
+ sql = `alter table ${tableName} add constraint ${keyName} unique `;
90
+ }
91
+ if (index.columnNames.some(column => column.includes('.'))) {
92
+ // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
93
+ const sql = `create ${index.unique ? 'unique ' : ''}index ${keyName} on ${tableName} `;
94
+ const columns = this.platform.getJsonIndexDefinition(index);
95
+ return `${sql}(${columns.join(', ')})${defer}`;
105
96
  }
106
- return `${sql}(${index.columnNames.map(c => this.platform.quoteIdentifier(c)).join(', ')})`;
97
+ return `${sql}(${index.columnNames.map(c => this.quote(c)).join(', ')})${defer}`;
107
98
  }
108
99
  getDropIndexSQL(tableName, index) {
109
- return `drop index ${this.platform.quoteIdentifier(index.keyName)}`;
100
+ return `drop index ${this.quote(index.keyName)}`;
110
101
  }
111
102
  getRenameIndexSQL(tableName, index, oldIndexName) {
112
- return [this.getDropIndexSQL(tableName, { ...index, keyName: oldIndexName }), this.getCreateIndexSQL(tableName, index)].join(';\n');
103
+ return [
104
+ this.getDropIndexSQL(tableName, { ...index, keyName: oldIndexName }),
105
+ this.getCreateIndexSQL(tableName, index),
106
+ ];
107
+ }
108
+ alterTable(diff, safe) {
109
+ const ret = [];
110
+ const [schemaName, tableName] = this.splitTableName(diff.name);
111
+ if (this.platform.supportsNativeEnums()) {
112
+ const changedNativeEnums = [];
113
+ for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
114
+ if (!column.nativeEnumName) {
115
+ continue;
116
+ }
117
+ const key = schemaName && schemaName !== this.platform.getDefaultSchemaName() && !column.nativeEnumName.includes('.')
118
+ ? schemaName + '.' + column.nativeEnumName
119
+ : column.nativeEnumName;
120
+ if (changedProperties.has('enumItems') && key in diff.fromTable.nativeEnums) {
121
+ changedNativeEnums.push([column.nativeEnumName, column.enumItems, diff.fromTable.nativeEnums[key].items]);
122
+ }
123
+ }
124
+ core_1.Utils.removeDuplicates(changedNativeEnums).forEach(([enumName, itemsNew, itemsOld]) => {
125
+ // postgres allows only adding new items, the values are case insensitive
126
+ itemsOld = itemsOld.map(v => v.toLowerCase());
127
+ const newItems = itemsNew.filter(val => !itemsOld.includes(val.toLowerCase()));
128
+ if (enumName.includes('.')) {
129
+ const [enumSchemaName, rawEnumName] = enumName.split('.');
130
+ ret.push(...newItems.map(val => this.getAlterNativeEnumSQL(rawEnumName, enumSchemaName, val, itemsNew, itemsOld)));
131
+ return;
132
+ }
133
+ ret.push(...newItems.map(val => this.getAlterNativeEnumSQL(enumName, schemaName, val, itemsNew, itemsOld)));
134
+ });
135
+ }
136
+ for (const index of Object.values(diff.removedIndexes)) {
137
+ ret.push(this.dropIndex(diff.name, index));
138
+ }
139
+ for (const index of Object.values(diff.changedIndexes)) {
140
+ ret.push(this.dropIndex(diff.name, index));
141
+ }
142
+ for (const check of Object.values(diff.removedChecks)) {
143
+ ret.push(this.dropConstraint(diff.name, check.name));
144
+ }
145
+ for (const check of Object.values(diff.changedChecks)) {
146
+ ret.push(this.dropConstraint(diff.name, check.name));
147
+ }
148
+ /* istanbul ignore else */
149
+ if (!safe && Object.values(diff.removedColumns).length > 0) {
150
+ ret.push(this.getDropColumnsSQL(tableName, Object.values(diff.removedColumns), schemaName));
151
+ }
152
+ if (Object.values(diff.addedColumns).length > 0) {
153
+ this.append(ret, this.getAddColumnsSQL(diff.toTable, Object.values(diff.addedColumns)));
154
+ }
155
+ for (const column of Object.values(diff.addedColumns)) {
156
+ const foreignKey = Object.values(diff.addedForeignKeys).find(fk => fk.columnNames.length === 1 && fk.columnNames[0] === column.name);
157
+ if (foreignKey && this.options.createForeignKeyConstraints) {
158
+ delete diff.addedForeignKeys[foreignKey.constraintName];
159
+ ret.push(this.createForeignKey(diff.toTable, foreignKey));
160
+ }
161
+ }
162
+ for (const { column, changedProperties } of Object.values(diff.changedColumns)) {
163
+ if (changedProperties.size === 1 && changedProperties.has('comment')) {
164
+ continue;
165
+ }
166
+ if (changedProperties.size === 1 && changedProperties.has('enumItems') && column.nativeEnumName) {
167
+ continue;
168
+ }
169
+ this.append(ret, this.alterTableColumn(column, diff.fromTable, changedProperties));
170
+ }
171
+ for (const { column, changedProperties } of Object.values(diff.changedColumns).filter(diff => diff.changedProperties.has('comment'))) {
172
+ if (['type', 'nullable', 'autoincrement', 'unsigned', 'default', 'enumItems'].some(t => changedProperties.has(t))) {
173
+ continue; // will be handled via column update
174
+ }
175
+ ret.push(this.getChangeColumnCommentSQL(tableName, column, schemaName));
176
+ }
177
+ for (const [oldColumnName, column] of Object.entries(diff.renamedColumns)) {
178
+ ret.push(this.getRenameColumnSQL(tableName, oldColumnName, column, schemaName));
179
+ }
180
+ for (const foreignKey of Object.values(diff.addedForeignKeys)) {
181
+ ret.push(this.createForeignKey(diff.toTable, foreignKey));
182
+ }
183
+ for (const foreignKey of Object.values(diff.changedForeignKeys)) {
184
+ ret.push(this.createForeignKey(diff.toTable, foreignKey));
185
+ }
186
+ for (const index of Object.values(diff.addedIndexes)) {
187
+ ret.push(this.createIndex(index, diff.toTable));
188
+ }
189
+ for (const index of Object.values(diff.changedIndexes)) {
190
+ ret.push(this.createIndex(index, diff.toTable, true));
191
+ }
192
+ for (const [oldIndexName, index] of Object.entries(diff.renamedIndexes)) {
193
+ if (index.unique) {
194
+ ret.push(this.dropIndex(diff.name, index, oldIndexName));
195
+ ret.push(this.createIndex(index, diff.toTable));
196
+ }
197
+ else {
198
+ ret.push(...this.getRenameIndexSQL(diff.name, index, oldIndexName));
199
+ }
200
+ }
201
+ for (const check of Object.values(diff.addedChecks)) {
202
+ ret.push(this.createCheck(diff.toTable, check));
203
+ }
204
+ for (const check of Object.values(diff.changedChecks)) {
205
+ ret.push(this.createCheck(diff.toTable, check));
206
+ }
207
+ if ('changedComment' in diff) {
208
+ ret.push(this.alterTableComment(diff.toTable, diff.changedComment));
209
+ }
210
+ return ret;
211
+ }
212
+ getAddColumnsSQL(table, columns) {
213
+ const adds = columns.map(column => {
214
+ return `add ${this.createTableColumn(column, table)}`;
215
+ }).join(', ');
216
+ return [`alter table ${table.getQuotedName()} ${adds}`];
113
217
  }
114
218
  getDropColumnsSQL(tableName, columns, schemaName) {
115
- const name = this.platform.quoteIdentifier((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
116
- const drops = columns.map(column => `drop column ${this.platform.quoteIdentifier(column.name)}`).join(', ');
219
+ const name = this.quote(this.getTableName(tableName, schemaName));
220
+ const drops = columns.map(column => `drop column ${this.quote(column.name)}`).join(', ');
117
221
  return `alter table ${name} ${drops}`;
118
222
  }
119
223
  hasNonDefaultPrimaryKeyName(table) {
@@ -124,51 +228,55 @@ class SchemaHelper {
124
228
  const defaultName = this.platform.getDefaultPrimaryName(table.name, pkIndex.columnNames);
125
229
  return pkIndex?.keyName !== defaultName;
126
230
  }
127
- createTableColumn(table, column, fromTable, changedProperties, alter) {
128
- const compositePK = fromTable.getPrimaryKey()?.composite;
129
- if (column.autoincrement && !column.generated && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
130
- const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(fromTable);
131
- if (column.mappedType instanceof core_1.BigIntType) {
132
- return table.bigIncrements(column.name, { primaryKey });
133
- }
134
- return table.increments(column.name, { primaryKey });
135
- }
136
- if (column.mappedType instanceof core_1.EnumType && column.enumItems?.every(item => core_1.Utils.isString(item))) {
137
- return table.enum(column.name, column.enumItems);
138
- }
139
- let columnType = column.type;
140
- if (column.generated) {
141
- columnType += ` generated always as ${column.generated}`;
142
- }
143
- return table.specificType(column.name, columnType);
144
- }
145
- configureColumn(column, col, knex, changedProperties) {
146
- const guard = (key) => !changedProperties || changedProperties.has(key);
147
- core_1.Utils.runIfNotEmpty(() => col.nullable(), column.nullable && guard('nullable'));
148
- core_1.Utils.runIfNotEmpty(() => col.notNullable(), !column.nullable && !column.generated);
149
- core_1.Utils.runIfNotEmpty(() => col.unsigned(), column.unsigned);
150
- core_1.Utils.runIfNotEmpty(() => col.comment(this.processComment(column.comment)), column.comment);
151
- this.configureColumnDefault(column, col, knex, changedProperties);
152
- return col;
231
+ /* istanbul ignore next */
232
+ castColumn(name, type) {
233
+ return '';
153
234
  }
154
- configureColumnDefault(column, col, knex, changedProperties) {
155
- const guard = (key) => !changedProperties || changedProperties.has(key);
156
- if (changedProperties) {
157
- core_1.Utils.runIfNotEmpty(() => col.defaultTo(column.default == null ? null : knex.raw(column.default)), guard('default'));
235
+ alterTableColumn(column, table, changedProperties) {
236
+ const sql = [];
237
+ if (changedProperties.has('default') && column.default == null) {
238
+ sql.push(`alter table ${table.getQuotedName()} alter column ${this.quote(column.name)} drop default`);
158
239
  }
159
- else {
160
- core_1.Utils.runIfNotEmpty(() => col.defaultTo(knex.raw(column.default)), column.default != null && column.default !== 'null');
240
+ if (changedProperties.has('type')) {
241
+ let type = column.type + (column.generated ? ` generated always as ${column.generated}` : '');
242
+ if (column.nativeEnumName) {
243
+ type = this.quote(this.getTableName(type, table.schema));
244
+ }
245
+ sql.push(`alter table ${table.getQuotedName()} alter column ${this.quote(column.name)} type ${type + this.castColumn(column.name, type)}`);
246
+ }
247
+ if (changedProperties.has('default') && column.default != null) {
248
+ sql.push(`alter table ${table.getQuotedName()} alter column ${this.quote(column.name)} set default ${column.default}`);
249
+ }
250
+ if (changedProperties.has('nullable')) {
251
+ const action = column.nullable ? 'drop' : 'set';
252
+ sql.push(`alter table ${table.getQuotedName()} alter column ${this.quote(column.name)} ${action} not null`);
253
+ }
254
+ return sql;
255
+ }
256
+ createTableColumn(column, table, changedProperties) {
257
+ const compositePK = table.getPrimaryKey()?.composite;
258
+ const primaryKey = !changedProperties && !this.hasNonDefaultPrimaryKeyName(table);
259
+ const columnType = column.type + (column.generated ? ` generated always as ${column.generated}` : '');
260
+ const useDefault = column.default != null && column.default !== 'null' && !column.autoincrement;
261
+ const col = [this.quote(column.name), columnType];
262
+ core_1.Utils.runIfNotEmpty(() => col.push('unsigned'), column.unsigned && this.platform.supportsUnsigned());
263
+ core_1.Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
264
+ core_1.Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable && !column.generated);
265
+ core_1.Utils.runIfNotEmpty(() => col.push('auto_increment'), column.autoincrement);
266
+ core_1.Utils.runIfNotEmpty(() => col.push('unique'), column.autoincrement && !column.primary);
267
+ if (column.autoincrement && !column.generated && !compositePK && (!changedProperties || changedProperties.has('autoincrement') || changedProperties.has('type'))) {
268
+ core_1.Utils.runIfNotEmpty(() => col.push('primary key'), primaryKey && column.primary);
161
269
  }
162
- return col;
270
+ core_1.Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
271
+ core_1.Utils.runIfNotEmpty(() => col.push(column.extra), column.extra);
272
+ core_1.Utils.runIfNotEmpty(() => col.push(`comment ${this.platform.quoteValue(column.comment)}`), column.comment);
273
+ return col.join(' ');
163
274
  }
164
275
  getPreAlterTable(tableDiff, safe) {
165
- return '';
276
+ return [];
166
277
  }
167
278
  getPostAlterTable(tableDiff, safe) {
168
- return '';
169
- }
170
- getAlterColumnAutoincrement(tableName, column, schemaName) {
171
- return '';
279
+ return [];
172
280
  }
173
281
  getChangeColumnCommentSQL(tableName, to, schemaName) {
174
282
  return '';
@@ -176,15 +284,6 @@ class SchemaHelper {
176
284
  async getNamespaces(connection) {
177
285
  return [];
178
286
  }
179
- async getColumns(connection, tableName, schemaName) {
180
- throw new Error('Not supported by given driver');
181
- }
182
- async getIndexes(connection, tableName, schemaName) {
183
- throw new Error('Not supported by given driver');
184
- }
185
- async getChecks(connection, tableName, schemaName, columns) {
186
- throw new Error('Not supported by given driver');
187
- }
188
287
  async mapIndexes(indexes) {
189
288
  const map = {};
190
289
  indexes.forEach(index => {
@@ -198,9 +297,6 @@ class SchemaHelper {
198
297
  });
199
298
  return Object.values(map);
200
299
  }
201
- getForeignKeysSQL(tableName, schemaName) {
202
- throw new Error('Not supported by given driver');
203
- }
204
300
  mapForeignKeys(fks, tableName, schemaName) {
205
301
  return fks.reduce((ret, fk) => {
206
302
  if (ret[fk.constraint_name]) {
@@ -242,15 +338,15 @@ class SchemaHelper {
242
338
  return `create database ${name};\n\nuse ${name}`;
243
339
  }
244
340
  getDropDatabaseSQL(name) {
245
- return `drop database if exists ${this.platform.quoteIdentifier(name)}`;
341
+ return `drop database if exists ${this.quote(name)}`;
246
342
  }
247
343
  /* istanbul ignore next */
248
344
  getCreateNamespaceSQL(name) {
249
- return `create schema if not exists ${this.platform.quoteIdentifier(name)}`;
345
+ return `create schema if not exists ${this.quote(name)}`;
250
346
  }
251
347
  /* istanbul ignore next */
252
348
  getDropNamespaceSQL(name) {
253
- return `drop schema if exists ${this.platform.quoteIdentifier(name)}`;
349
+ return `drop schema if exists ${this.quote(name)}`;
254
350
  }
255
351
  getDatabaseExistsSQL(name) {
256
352
  return `select 1 from information_schema.schemata where schema_name = '${name}'`;
@@ -273,78 +369,98 @@ class SchemaHelper {
273
369
  if (e instanceof Error && e.message.includes(this.getDatabaseNotExistsError(name))) {
274
370
  return false;
275
371
  }
372
+ /* istanbul ignore next */
276
373
  throw e;
277
374
  }
278
375
  }
279
- /**
280
- * Uses `raw` method injected in `AbstractSqlConnection` to allow adding custom queries inside alter statements.
281
- */
282
- pushTableQuery(table, expression, grouping = 'alterTable') {
283
- table._statements.push({ grouping, method: 'raw', args: [expression] });
284
- }
285
- async dump(builder, append) {
286
- if (typeof builder === 'string') {
287
- return builder ? builder + (builder.endsWith(';') ? '' : ';') + append : '';
376
+ append(array, sql, pad = false) {
377
+ const length = array.length;
378
+ for (const row of core_1.Utils.asArray(sql)) {
379
+ if (!row) {
380
+ continue;
381
+ }
382
+ let tmp = row.trim();
383
+ if (!tmp.endsWith(';')) {
384
+ tmp += ';';
385
+ }
386
+ array.push(tmp);
288
387
  }
289
- const sql = await builder.generateDdlCommands();
290
- const queries = [...sql.pre, ...sql.sql, ...sql.post];
291
- if (queries.length === 0) {
292
- return '';
388
+ if (pad && array.length > length) {
389
+ array.push('');
293
390
  }
294
- const dump = `${queries.map(q => typeof q === 'object' ? q.sql : q).join(';\n')};${append}`;
295
- const tmp = dump.replace(/pragma table_.+/ig, '').replace(/\n\n+/g, '\n').trim();
296
- return tmp ? tmp + append : '';
297
391
  }
298
- createTable(tableDef, alter) {
299
- return this.createSchemaBuilder(tableDef.schema).createTable(tableDef.name, table => {
300
- tableDef.getColumns().forEach(column => {
301
- const col = this.createTableColumn(table, column, tableDef, undefined, alter);
302
- this.configureColumn(column, col, this.knex);
303
- });
304
- for (const index of tableDef.getIndexes()) {
305
- const createPrimary = !tableDef.getColumns().some(c => c.autoincrement && c.primary) || this.hasNonDefaultPrimaryKeyName(tableDef);
306
- this.createIndex(table, index, tableDef, createPrimary);
307
- }
308
- for (const check of tableDef.getChecks()) {
309
- this.createCheck(table, check);
392
+ createTable(table, alter) {
393
+ let sql = `create table ${table.getQuotedName()} (`;
394
+ const columns = table.getColumns();
395
+ const lastColumn = columns[columns.length - 1].name;
396
+ for (const column of columns) {
397
+ const col = this.createTableColumn(column, table);
398
+ if (col) {
399
+ const comma = column.name === lastColumn ? '' : ', ';
400
+ sql += col + comma;
310
401
  }
311
- if (tableDef.comment) {
312
- const comment = this.platform.quoteValue(tableDef.comment).replace(/^'|'$/g, '');
313
- table.comment(comment);
314
- }
315
- if (!this.supportsSchemaConstraints()) {
316
- for (const fk of Object.values(tableDef.getForeignKeys())) {
317
- this.createForeignKey(table, fk);
318
- }
402
+ }
403
+ const primaryKey = table.getPrimaryKey();
404
+ const createPrimary = !table.getColumns().some(c => c.autoincrement && c.primary) || this.hasNonDefaultPrimaryKeyName(table);
405
+ if (createPrimary && primaryKey) {
406
+ const name = this.hasNonDefaultPrimaryKeyName(table) ? `constraint ${this.quote(primaryKey.keyName)} ` : '';
407
+ sql += `, ${name}primary key (${primaryKey.columnNames.map(c => this.quote(c)).join(', ')})`;
408
+ }
409
+ sql += ')';
410
+ sql += this.finalizeTable(table, this.platform.getConfig().get('charset'), this.platform.getConfig().get('collate'));
411
+ const ret = [];
412
+ this.append(ret, sql);
413
+ this.append(ret, this.appendComments(table));
414
+ for (const index of table.getIndexes()) {
415
+ this.append(ret, this.createIndex(index, table));
416
+ }
417
+ if (!alter) {
418
+ for (const check of table.getChecks()) {
419
+ this.append(ret, this.createCheck(table, check));
319
420
  }
320
- this.finalizeTable(table, this.platform.getConfig().get('charset'), this.platform.getConfig().get('collate'));
321
- });
421
+ }
422
+ return ret;
423
+ }
424
+ alterTableComment(table, comment) {
425
+ return `alter table ${table.getQuotedName()} comment = ${this.platform.quoteValue(comment ?? '')}`;
322
426
  }
323
- createForeignKey(table, foreignKey, schema) {
427
+ createForeignKey(table, foreignKey, alterTable = true, inline = false) {
324
428
  if (!this.options.createForeignKeyConstraints) {
325
- return;
429
+ return '';
430
+ }
431
+ const constraintName = this.quote(foreignKey.constraintName);
432
+ const columnNames = foreignKey.columnNames.map(c => this.quote(c)).join(', ');
433
+ const referencedColumnNames = foreignKey.referencedColumnNames.map(c => this.quote(c)).join(', ');
434
+ const referencedTableName = this.quote(this.getReferencedTableName(foreignKey.referencedTableName, table.schema));
435
+ const sql = [];
436
+ if (alterTable) {
437
+ sql.push(`alter table ${table.getQuotedName()} add`);
438
+ }
439
+ sql.push(`constraint ${constraintName}`);
440
+ if (!inline) {
441
+ sql.push(`foreign key (${columnNames})`);
326
442
  }
327
- const builder = table
328
- .foreign(foreignKey.columnNames, foreignKey.constraintName)
329
- .references(foreignKey.referencedColumnNames)
330
- .inTable(this.getReferencedTableName(foreignKey.referencedTableName, schema))
331
- .withKeyName(foreignKey.constraintName);
443
+ sql.push(`references ${referencedTableName} (${referencedColumnNames})`);
332
444
  if (foreignKey.localTableName !== foreignKey.referencedTableName || this.platform.supportsMultipleCascadePaths()) {
333
445
  if (foreignKey.updateRule) {
334
- builder.onUpdate(foreignKey.updateRule);
446
+ sql.push(`on update ${foreignKey.updateRule}`);
335
447
  }
336
448
  if (foreignKey.deleteRule) {
337
- builder.onDelete(foreignKey.deleteRule);
449
+ sql.push(`on delete ${foreignKey.deleteRule}`);
338
450
  }
339
451
  }
340
452
  if (foreignKey.deferMode) {
341
- builder.deferrable(foreignKey.deferMode);
453
+ sql.push(`deferrable initially ${foreignKey.deferMode}`);
342
454
  }
455
+ return sql.join(' ');
343
456
  }
344
- splitTableName(name) {
457
+ splitTableName(name, skipDefaultSchema = false) {
345
458
  const parts = name.split('.');
346
459
  const tableName = parts.pop();
347
- const schemaName = parts.pop();
460
+ let schemaName = parts.pop();
461
+ if (skipDefaultSchema && schemaName === this.platform.getDefaultSchemaName()) {
462
+ schemaName = undefined;
463
+ }
348
464
  return [schemaName, tableName];
349
465
  }
350
466
  getReferencedTableName(referencedTableName, schema) {
@@ -354,58 +470,37 @@ class SchemaHelper {
354
470
  if (schema && schemaName === '*') {
355
471
  return `${schema}.${referencedTableName.replace(/^\*\./, '')}`;
356
472
  }
357
- if (!schemaName || schemaName === this.platform.getDefaultSchemaName()) {
358
- return tableName;
359
- }
360
- return `${schemaName}.${tableName}`;
473
+ return this.getTableName(tableName, schema);
361
474
  }
362
- createIndex(table, index, tableDef, createPrimary = false) {
475
+ createIndex(index, table, createPrimary = false) {
363
476
  if (index.primary && !createPrimary) {
364
- return;
477
+ return '';
365
478
  }
366
479
  if (index.expression) {
367
- this.pushTableQuery(table, index.expression);
368
- }
369
- else if (index.primary) {
370
- const keyName = this.hasNonDefaultPrimaryKeyName(tableDef) ? index.keyName : undefined;
371
- table.primary(index.columnNames, keyName);
480
+ return index.expression;
372
481
  }
373
- else if (index.unique) {
374
- // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
375
- if (index.columnNames.some(column => column.includes('.'))) {
376
- const columns = this.platform.getJsonIndexDefinition(index);
377
- table.index(columns.map(column => this.knex.raw(column)), index.keyName, { indexType: 'unique' });
378
- }
379
- else {
380
- table.unique(index.columnNames, { indexName: index.keyName, deferrable: index.deferMode });
381
- }
482
+ const columns = index.columnNames.map(c => this.quote(c)).join(', ');
483
+ const defer = index.deferMode ? ` deferrable initially ${index.deferMode}` : '';
484
+ if (index.primary) {
485
+ const keyName = this.hasNonDefaultPrimaryKeyName(table) ? `constraint ${index.keyName} ` : '';
486
+ return `alter table ${table.getQuotedName()} add ${keyName}primary key (${columns})${defer}`;
382
487
  }
383
- else if (index.type === 'fulltext') {
384
- const columns = index.columnNames.map(name => ({ name, type: tableDef.getColumn(name).type }));
488
+ if (index.type === 'fulltext') {
489
+ const columns = index.columnNames.map(name => ({ name, type: table.getColumn(name).type }));
385
490
  if (this.platform.supportsCreatingFullTextIndex()) {
386
- this.pushTableQuery(table, this.platform.getFullTextIndexExpression(index.keyName, tableDef.schema, tableDef.name, columns));
387
- }
388
- }
389
- else {
390
- // JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
391
- if (index.columnNames.some(column => column.includes('.'))) {
392
- const columns = this.platform.getJsonIndexDefinition(index);
393
- table.index(columns.map(column => this.knex.raw(column)), index.keyName, index.type);
394
- }
395
- else {
396
- table.index(index.columnNames, index.keyName, index.type);
491
+ return this.platform.getFullTextIndexExpression(index.keyName, table.schema, table.name, columns);
397
492
  }
398
493
  }
494
+ return this.getCreateIndexSQL(table.getShortestName(), index);
399
495
  }
400
496
  createCheck(table, check) {
401
- table.check(check.expression, {}, check.name);
497
+ return `alter table ${table.getQuotedName()} add constraint ${this.quote(check.name)} check (${check.expression})`;
402
498
  }
403
- createSchemaBuilder(schema) {
404
- const builder = this.knex.schema;
499
+ getTableName(table, schema) {
405
500
  if (schema && schema !== this.platform.getDefaultSchemaName()) {
406
- builder.withSchema(schema);
501
+ return `${schema}.${table}`;
407
502
  }
408
- return builder;
503
+ return table;
409
504
  }
410
505
  getTablesGroupedBySchemas(tables) {
411
506
  return tables.reduce((acc, table) => {
@@ -418,18 +513,33 @@ class SchemaHelper {
418
513
  return acc;
419
514
  }, new Map());
420
515
  }
421
- get knex() {
422
- const connection = this.platform.getConfig().getDriver().getConnection();
423
- return connection.getKnex();
424
- }
425
516
  get options() {
426
517
  return this.platform.getConfig().get('schemaGenerator');
427
518
  }
428
519
  processComment(comment) {
429
- return this.platform.getSchemaHelper().handleMultilineComment(comment);
520
+ return comment;
430
521
  }
431
- handleMultilineComment(comment) {
432
- return comment.replaceAll('\n', '\\n');
522
+ quote(...keys) {
523
+ return this.platform.quoteIdentifier(keys.filter(Boolean).join('.'));
524
+ }
525
+ dropForeignKey(tableName, constraintName) {
526
+ return `alter table ${this.quote(tableName)} drop foreign key ${this.quote(constraintName)}`;
527
+ }
528
+ dropIndex(table, index, oldIndexName = index.keyName) {
529
+ if (index.primary) {
530
+ return `alter table ${this.quote(table)} drop primary key`;
531
+ }
532
+ return `alter table ${this.quote(table)} drop index ${this.quote(oldIndexName)}`;
533
+ }
534
+ dropConstraint(table, name) {
535
+ return `alter table ${this.quote(table)} drop constraint ${this.quote(name)}`;
536
+ }
537
+ dropTableIfExists(name, schema) {
538
+ let sql = `drop table if exists ${this.quote(this.getTableName(name, schema))}`;
539
+ if (this.platform.usesCascadeStatement()) {
540
+ sql += ' cascade';
541
+ }
542
+ return sql;
433
543
  }
434
544
  }
435
545
  exports.SchemaHelper = SchemaHelper;
@@ -37,13 +37,11 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
37
37
  safe?: boolean;
38
38
  dropTables?: boolean;
39
39
  schema?: string;
40
- }): Promise<string>;
40
+ }): string;
41
41
  /**
42
42
  * We need to drop foreign keys first for all tables to allow dropping PK constraints.
43
43
  */
44
44
  private preAlterTable;
45
- private postAlterTable;
46
- private alterTable;
47
45
  /**
48
46
  * creates new database and connects to it
49
47
  */
@@ -53,12 +51,8 @@ export declare class SqlSchemaGenerator extends AbstractSchemaGenerator<Abstract
53
51
  wrap?: boolean;
54
52
  ctx?: Transaction;
55
53
  }): Promise<void>;
54
+ dropTableIfExists(name: string, schema?: string): Promise<void>;
56
55
  private wrapSchema;
57
- private dropIndex;
58
- private dropCheck;
59
- private dropTable;
60
- private createForeignKeys;
61
- private dump;
62
- private get knex();
56
+ private append;
63
57
  }
64
58
  export { SqlSchemaGenerator as SchemaGenerator };