knex 0.95.14 → 1.0.2

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 (78) hide show
  1. package/CHANGELOG.md +90 -1
  2. package/README.md +1 -1
  3. package/UPGRADING.md +7 -0
  4. package/lib/client.js +14 -1
  5. package/lib/constants.js +2 -0
  6. package/lib/dialects/better-sqlite3/index.js +72 -0
  7. package/lib/dialects/cockroachdb/crdb-querycompiler.js +92 -33
  8. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +19 -0
  9. package/lib/dialects/cockroachdb/index.js +13 -0
  10. package/lib/dialects/mssql/index.js +0 -11
  11. package/lib/dialects/mssql/query/mssql-querycompiler.js +122 -64
  12. package/lib/dialects/mssql/schema/mssql-columncompiler.js +41 -6
  13. package/lib/dialects/mssql/schema/mssql-compiler.js +3 -4
  14. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +24 -9
  15. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +15 -1
  16. package/lib/dialects/mysql/query/mysql-querycompiler.js +93 -5
  17. package/lib/dialects/mysql/schema/mysql-columncompiler.js +32 -5
  18. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +33 -6
  19. package/lib/dialects/oracle/query/oracle-querycompiler.js +7 -6
  20. package/lib/dialects/oracle/schema/internal/trigger.js +1 -1
  21. package/lib/dialects/oracle/schema/oracle-columncompiler.js +10 -4
  22. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +17 -6
  23. package/lib/dialects/oracledb/index.js +0 -4
  24. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +89 -0
  25. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +23 -0
  26. package/lib/dialects/postgres/index.js +21 -6
  27. package/lib/dialects/postgres/query/pg-querybuilder.js +38 -0
  28. package/lib/dialects/postgres/query/pg-querycompiler.js +172 -9
  29. package/lib/dialects/postgres/schema/pg-columncompiler.js +24 -4
  30. package/lib/dialects/postgres/schema/pg-tablecompiler.js +63 -46
  31. package/lib/dialects/redshift/index.js +12 -0
  32. package/lib/dialects/redshift/query/redshift-querycompiler.js +62 -26
  33. package/lib/dialects/redshift/schema/redshift-columncompiler.js +2 -1
  34. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +4 -1
  35. package/lib/dialects/sqlite3/index.js +23 -4
  36. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -0
  37. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +87 -22
  38. package/lib/dialects/sqlite3/schema/ddl.js +274 -282
  39. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +18 -8
  40. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +20 -0
  41. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +16 -12
  42. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +15 -5
  43. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +31 -2
  44. package/lib/execution/runner.js +37 -2
  45. package/lib/knex-builder/FunctionHelper.js +36 -0
  46. package/lib/migrations/common/MigrationsLoader.js +36 -0
  47. package/lib/migrations/migrate/MigrationGenerator.js +1 -1
  48. package/lib/migrations/migrate/Migrator.js +22 -24
  49. package/lib/migrations/migrate/migration-list-resolver.js +2 -5
  50. package/lib/migrations/migrate/{configuration-merger.js → migrator-configuration-merger.js} +2 -4
  51. package/lib/migrations/migrate/sources/fs-migrations.js +4 -29
  52. package/lib/migrations/migrate/stub/js.stub +8 -1
  53. package/lib/migrations/migrate/stub/knexfile-js.stub +3 -0
  54. package/lib/migrations/migrate/stub/knexfile-ts.stub +5 -2
  55. package/lib/migrations/migrate/table-creator.js +6 -5
  56. package/lib/migrations/seed/Seeder.js +25 -92
  57. package/lib/migrations/seed/seeder-configuration-merger.js +60 -0
  58. package/lib/migrations/seed/sources/fs-seeds.js +65 -0
  59. package/lib/migrations/seed/stub/js.stub +4 -1
  60. package/lib/migrations/util/import-file.js +0 -1
  61. package/lib/query/joinclause.js +24 -5
  62. package/lib/query/method-constants.js +37 -0
  63. package/lib/query/querybuilder.js +292 -53
  64. package/lib/query/querycompiler.js +309 -85
  65. package/lib/schema/columnbuilder.js +14 -1
  66. package/lib/schema/columncompiler.js +132 -5
  67. package/lib/schema/compiler.js +1 -0
  68. package/lib/schema/tablebuilder.js +41 -8
  69. package/lib/schema/tablecompiler.js +61 -4
  70. package/lib/schema/viewcompiler.js +13 -10
  71. package/package.json +37 -27
  72. package/scripts/docker-compose.yml +7 -7
  73. package/scripts/oracledb-install-driver-libs.sh +82 -0
  74. package/scripts/runkit-example.js +1 -1
  75. package/scripts/stress-test/docker-compose.yml +3 -3
  76. package/scripts/stress-test/knex-stress-test.js +1 -1
  77. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +1 -1
  78. package/types/index.d.ts +133 -21
@@ -7,11 +7,13 @@
7
7
  const identity = require('lodash/identity');
8
8
  const { nanonum } = require('../../../util/nanoid');
9
9
  const {
10
- createNewTable,
11
10
  copyData,
12
11
  dropOriginal,
13
12
  renameTable,
14
13
  getTableSql,
14
+ isForeignCheckEnabled,
15
+ setForeignCheck,
16
+ executeForeignCheck,
15
17
  } = require('./internal/sqlite-ddl-operations');
16
18
  const { parseCreateTable, parseCreateIndex } = require('./internal/parser');
17
19
  const {
@@ -43,365 +45,355 @@ class SQLite3_DDL {
43
45
  getTableSql() {
44
46
  const tableName = this.tableName();
45
47
 
46
- this.trx.disableProcessing();
47
- return this.trx.raw(getTableSql(tableName)).then((result) => {
48
- this.trx.enableProcessing();
49
- return {
50
- createTable: result.filter((create) => create.type === 'table')[0].sql,
51
- createIndices: result
52
- .filter((create) => create.type === 'index')
53
- .map((create) => create.sql),
54
- };
55
- });
48
+ return this.client.transaction(
49
+ async (trx) => {
50
+ trx.disableProcessing();
51
+ const result = await trx.raw(getTableSql(tableName));
52
+ trx.enableProcessing();
53
+
54
+ return {
55
+ createTable: result.filter((create) => create.type === 'table')[0]
56
+ .sql,
57
+ createIndices: result
58
+ .filter((create) => create.type === 'index')
59
+ .map((create) => create.sql),
60
+ };
61
+ },
62
+ { connection: this.connection }
63
+ );
56
64
  }
57
65
 
58
- renameTable() {
59
- return this.trx.raw(renameTable(this.alteredName, this.tableName()));
66
+ async isForeignCheckEnabled() {
67
+ const result = await this.client
68
+ .raw(isForeignCheckEnabled())
69
+ .connection(this.connection);
70
+
71
+ return result[0].foreign_keys === 1;
60
72
  }
61
73
 
62
- dropOriginal() {
63
- return this.trx.raw(dropOriginal(this.tableName()));
74
+ async setForeignCheck(enable) {
75
+ await this.client.raw(setForeignCheck(enable)).connection(this.connection);
64
76
  }
65
77
 
66
- copyData(columns) {
67
- return this.trx.raw(copyData(this.tableName(), this.alteredName, columns));
78
+ renameTable(trx) {
79
+ return trx.raw(renameTable(this.alteredName, this.tableName()));
68
80
  }
69
81
 
70
- createNewTable(sql) {
71
- return this.trx.raw(
72
- createNewTable(sql, this.tableName(), this.alteredName)
73
- );
82
+ dropOriginal(trx) {
83
+ return trx.raw(dropOriginal(this.tableName()));
74
84
  }
75
85
 
76
- alterColumn(columns) {
77
- return this.client.transaction(
78
- async (trx) => {
79
- this.trx = trx;
86
+ copyData(trx, columns) {
87
+ return trx.raw(copyData(this.tableName(), this.alteredName, columns));
88
+ }
80
89
 
81
- const { createTable, createIndices } = await this.getTableSql();
90
+ async alterColumn(columns) {
91
+ const { createTable, createIndices } = await this.getTableSql();
82
92
 
83
- const parsedTable = parseCreateTable(createTable);
93
+ const parsedTable = parseCreateTable(createTable);
94
+ parsedTable.table = this.alteredName;
84
95
 
85
- parsedTable.columns = parsedTable.columns.map((column) => {
86
- const newColumnInfo = columns.find((c) =>
87
- isEqualId(c.name, column.name)
88
- );
96
+ parsedTable.columns = parsedTable.columns.map((column) => {
97
+ const newColumnInfo = columns.find((c) => isEqualId(c.name, column.name));
89
98
 
90
- if (newColumnInfo) {
91
- column.type = newColumnInfo.type;
92
-
93
- column.constraints.default =
94
- newColumnInfo.defaultTo !== null
95
- ? {
96
- name: null,
97
- value: newColumnInfo.defaultTo,
98
- expression: false,
99
- }
100
- : null;
101
-
102
- column.constraints.notnull = newColumnInfo.notNull
103
- ? { name: null, conflict: null }
104
- : null;
105
-
106
- column.constraints.null = newColumnInfo.notNull
107
- ? null
108
- : column.constraints.null;
109
- }
99
+ if (newColumnInfo) {
100
+ column.type = newColumnInfo.type;
110
101
 
111
- return column;
112
- });
102
+ column.constraints.default =
103
+ newColumnInfo.defaultTo !== null
104
+ ? {
105
+ name: null,
106
+ value: newColumnInfo.defaultTo,
107
+ expression: false,
108
+ }
109
+ : null;
113
110
 
114
- const newTable = compileCreateTable(parsedTable, this.wrap);
111
+ column.constraints.notnull = newColumnInfo.notNull
112
+ ? { name: null, conflict: null }
113
+ : null;
115
114
 
116
- return this.alter(newTable, createIndices);
117
- },
118
- { connection: this.connection }
119
- );
120
- }
115
+ column.constraints.null = newColumnInfo.notNull
116
+ ? null
117
+ : column.constraints.null;
118
+ }
121
119
 
122
- dropColumn(columns) {
123
- return this.client.transaction(
124
- async (trx) => {
125
- this.trx = trx;
120
+ return column;
121
+ });
126
122
 
127
- const { createTable, createIndices } = await this.getTableSql();
123
+ const newTable = compileCreateTable(parsedTable, this.wrap);
128
124
 
129
- const parsedTable = parseCreateTable(createTable);
125
+ return this.generateAlterCommands(newTable, createIndices);
126
+ }
130
127
 
131
- parsedTable.columns = parsedTable.columns.filter(
132
- (parsedColumn) =>
133
- parsedColumn.expression || !includesId(columns, parsedColumn.name)
134
- );
128
+ async dropColumn(columns) {
129
+ const { createTable, createIndices } = await this.getTableSql();
135
130
 
136
- if (parsedTable.columns.length === 0) {
137
- throw new Error('Unable to drop last column from table');
138
- }
131
+ const parsedTable = parseCreateTable(createTable);
132
+ parsedTable.table = this.alteredName;
139
133
 
140
- parsedTable.constraints = parsedTable.constraints.filter(
141
- (constraint) => {
142
- if (
143
- constraint.type === 'PRIMARY KEY' ||
144
- constraint.type === 'UNIQUE'
145
- ) {
146
- return constraint.columns.every(
147
- (constraintColumn) =>
148
- constraintColumn.expression ||
149
- !includesId(columns, constraintColumn.name)
150
- );
151
- } else if (constraint.type === 'FOREIGN KEY') {
152
- return (
153
- constraint.columns.every(
154
- (constraintColumnName) =>
155
- !includesId(columns, constraintColumnName)
156
- ) &&
157
- (constraint.references.table !== parsedTable.table ||
158
- constraint.references.columns.every(
159
- (referenceColumnName) =>
160
- !includesId(columns, referenceColumnName)
161
- ))
162
- );
163
- } else {
164
- return true;
165
- }
166
- }
134
+ parsedTable.columns = parsedTable.columns.filter(
135
+ (parsedColumn) =>
136
+ parsedColumn.expression || !includesId(columns, parsedColumn.name)
137
+ );
138
+
139
+ if (parsedTable.columns.length === 0) {
140
+ throw new Error('Unable to drop last column from table');
141
+ }
142
+
143
+ parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
144
+ if (constraint.type === 'PRIMARY KEY' || constraint.type === 'UNIQUE') {
145
+ return constraint.columns.every(
146
+ (constraintColumn) =>
147
+ constraintColumn.expression ||
148
+ !includesId(columns, constraintColumn.name)
167
149
  );
150
+ } else if (constraint.type === 'FOREIGN KEY') {
151
+ return (
152
+ constraint.columns.every(
153
+ (constraintColumnName) => !includesId(columns, constraintColumnName)
154
+ ) &&
155
+ (constraint.references.table !== parsedTable.table ||
156
+ constraint.references.columns.every(
157
+ (referenceColumnName) => !includesId(columns, referenceColumnName)
158
+ ))
159
+ );
160
+ } else {
161
+ return true;
162
+ }
163
+ });
168
164
 
169
- const newColumns = parsedTable.columns.map((column) => column.name);
165
+ const newColumns = parsedTable.columns.map((column) => column.name);
170
166
 
171
- const newTable = compileCreateTable(parsedTable, this.wrap);
167
+ const newTable = compileCreateTable(parsedTable, this.wrap);
172
168
 
173
- const newIndices = [];
174
- for (const createIndex of createIndices) {
175
- const parsedIndex = parseCreateIndex(createIndex);
169
+ const newIndices = [];
170
+ for (const createIndex of createIndices) {
171
+ const parsedIndex = parseCreateIndex(createIndex);
176
172
 
177
- parsedIndex.columns = parsedIndex.columns.filter(
178
- (parsedColumn) =>
179
- parsedColumn.expression || !includesId(columns, parsedColumn.name)
180
- );
173
+ parsedIndex.columns = parsedIndex.columns.filter(
174
+ (parsedColumn) =>
175
+ parsedColumn.expression || !includesId(columns, parsedColumn.name)
176
+ );
181
177
 
182
- if (parsedIndex.columns.length > 0) {
183
- newIndices.push(compileCreateIndex(parsedIndex, this.wrap));
184
- }
185
- }
178
+ if (parsedIndex.columns.length > 0) {
179
+ newIndices.push(compileCreateIndex(parsedIndex, this.wrap));
180
+ }
181
+ }
186
182
 
187
- return this.alter(newTable, newIndices, newColumns);
188
- },
189
- { connection: this.connection }
190
- );
183
+ return this.alter(newTable, newIndices, newColumns);
191
184
  }
192
185
 
193
- dropForeign(columns, foreignKeyName) {
194
- return this.client.transaction(
195
- async (trx) => {
196
- this.trx = trx;
186
+ async dropForeign(columns, foreignKeyName) {
187
+ const { createTable, createIndices } = await this.getTableSql();
197
188
 
198
- const { createTable, createIndices } = await this.getTableSql();
189
+ const parsedTable = parseCreateTable(createTable);
190
+ parsedTable.table = this.alteredName;
199
191
 
200
- const parsedTable = parseCreateTable(createTable);
192
+ if (!foreignKeyName) {
193
+ parsedTable.columns = parsedTable.columns.map((column) => ({
194
+ ...column,
195
+ references: includesId(columns, column.name) ? null : column.references,
196
+ }));
197
+ }
201
198
 
202
- if (!foreignKeyName) {
203
- parsedTable.columns = parsedTable.columns.map((column) => ({
204
- ...column,
205
- references: includesId(columns, column.name)
206
- ? null
207
- : column.references,
208
- }));
199
+ parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
200
+ if (constraint.type === 'FOREIGN KEY') {
201
+ if (foreignKeyName) {
202
+ return (
203
+ !constraint.name || !isEqualId(constraint.name, foreignKeyName)
204
+ );
209
205
  }
210
206
 
211
- parsedTable.constraints = parsedTable.constraints.filter(
212
- (constraint) => {
213
- if (constraint.type === 'FOREIGN KEY') {
214
- if (foreignKeyName) {
215
- return (
216
- !constraint.name ||
217
- !isEqualId(constraint.name, foreignKeyName)
218
- );
219
- }
220
-
221
- return constraint.columns.every(
222
- (constraintColumnName) =>
223
- !includesId(columns, constraintColumnName)
224
- );
225
- } else {
226
- return true;
227
- }
228
- }
207
+ return constraint.columns.every(
208
+ (constraintColumnName) => !includesId(columns, constraintColumnName)
229
209
  );
210
+ } else {
211
+ return true;
212
+ }
213
+ });
230
214
 
231
- const newTable = compileCreateTable(parsedTable, this.wrap);
215
+ const newTable = compileCreateTable(parsedTable, this.wrap);
232
216
 
233
- return this.alter(newTable, createIndices);
234
- },
235
- { connection: this.connection }
236
- );
217
+ return this.alter(newTable, createIndices);
237
218
  }
238
219
 
239
- dropPrimary(constraintName) {
240
- return this.client.transaction(
241
- async (trx) => {
242
- this.trx = trx;
243
-
244
- const { createTable, createIndices } = await this.getTableSql();
245
-
246
- const parsedTable = parseCreateTable(createTable);
247
-
248
- parsedTable.columns = parsedTable.columns.map((column) => ({
249
- ...column,
250
- primary: null,
251
- }));
252
-
253
- parsedTable.constraints = parsedTable.constraints.filter(
254
- (constraint) => {
255
- if (constraint.type === 'PRIMARY KEY') {
256
- if (constraintName) {
257
- return (
258
- !constraint.name ||
259
- !isEqualId(constraint.name, constraintName)
260
- );
261
- } else {
262
- return false;
263
- }
264
- } else {
265
- return true;
266
- }
267
- }
268
- );
220
+ async dropPrimary(constraintName) {
221
+ const { createTable, createIndices } = await this.getTableSql();
269
222
 
270
- const newTable = compileCreateTable(parsedTable, this.wrap);
223
+ const parsedTable = parseCreateTable(createTable);
224
+ parsedTable.table = this.alteredName;
271
225
 
272
- return this.alter(newTable, createIndices);
273
- },
274
- { connection: this.connection }
275
- );
276
- }
226
+ parsedTable.columns = parsedTable.columns.map((column) => ({
227
+ ...column,
228
+ primary: null,
229
+ }));
277
230
 
278
- primary(columns, constraintName) {
279
- return this.client.transaction(
280
- async (trx) => {
281
- this.trx = trx;
231
+ parsedTable.constraints = parsedTable.constraints.filter((constraint) => {
232
+ if (constraint.type === 'PRIMARY KEY') {
233
+ if (constraintName) {
234
+ return (
235
+ !constraint.name || !isEqualId(constraint.name, constraintName)
236
+ );
237
+ } else {
238
+ return false;
239
+ }
240
+ } else {
241
+ return true;
242
+ }
243
+ });
282
244
 
283
- const { createTable, createIndices } = await this.getTableSql();
245
+ const newTable = compileCreateTable(parsedTable, this.wrap);
284
246
 
285
- const parsedTable = parseCreateTable(createTable);
247
+ return this.alter(newTable, createIndices);
248
+ }
286
249
 
287
- parsedTable.columns = parsedTable.columns.map((column) => ({
288
- ...column,
289
- primary: null,
290
- }));
250
+ async primary(columns, constraintName) {
251
+ const { createTable, createIndices } = await this.getTableSql();
291
252
 
292
- parsedTable.constraints = parsedTable.constraints.filter(
293
- (constraint) => constraint.type !== 'PRIMARY KEY'
294
- );
253
+ const parsedTable = parseCreateTable(createTable);
254
+ parsedTable.table = this.alteredName;
295
255
 
296
- parsedTable.constraints.push({
297
- type: 'PRIMARY KEY',
298
- name: constraintName || null,
299
- columns: columns.map((column) => ({
300
- name: column,
301
- expression: false,
302
- collation: null,
303
- order: null,
304
- })),
305
- conflict: null,
306
- });
307
-
308
- const newTable = compileCreateTable(parsedTable, this.wrap);
309
-
310
- return this.alter(newTable, createIndices);
311
- },
312
- { connection: this.connection }
256
+ parsedTable.columns = parsedTable.columns.map((column) => ({
257
+ ...column,
258
+ primary: null,
259
+ }));
260
+
261
+ parsedTable.constraints = parsedTable.constraints.filter(
262
+ (constraint) => constraint.type !== 'PRIMARY KEY'
313
263
  );
314
- }
315
264
 
316
- foreign(foreignInfo) {
317
- return this.client.transaction(
318
- async (trx) => {
319
- this.trx = trx;
265
+ parsedTable.constraints.push({
266
+ type: 'PRIMARY KEY',
267
+ name: constraintName || null,
268
+ columns: columns.map((column) => ({
269
+ name: column,
270
+ expression: false,
271
+ collation: null,
272
+ order: null,
273
+ })),
274
+ conflict: null,
275
+ });
320
276
 
321
- const { createTable, createIndices } = await this.getTableSql();
277
+ const newTable = compileCreateTable(parsedTable, this.wrap);
322
278
 
323
- const parsedTable = parseCreateTable(createTable);
279
+ return this.alter(newTable, createIndices);
280
+ }
324
281
 
325
- parsedTable.constraints.push({
326
- type: 'FOREIGN KEY',
327
- name: foreignInfo.keyName || null,
328
- columns: foreignInfo.column,
329
- references: {
330
- table: foreignInfo.inTable,
331
- columns: foreignInfo.references,
332
- delete: foreignInfo.onDelete || null,
333
- update: foreignInfo.onUpdate || null,
334
- match: null,
335
- deferrable: null,
336
- },
337
- });
282
+ async foreign(foreignInfo) {
283
+ const { createTable, createIndices } = await this.getTableSql();
284
+
285
+ const parsedTable = parseCreateTable(createTable);
286
+ parsedTable.table = this.alteredName;
287
+
288
+ parsedTable.constraints.push({
289
+ type: 'FOREIGN KEY',
290
+ name: foreignInfo.keyName || null,
291
+ columns: foreignInfo.column,
292
+ references: {
293
+ table: foreignInfo.inTable,
294
+ columns: foreignInfo.references,
295
+ delete: foreignInfo.onDelete || null,
296
+ update: foreignInfo.onUpdate || null,
297
+ match: null,
298
+ deferrable: null,
299
+ },
300
+ });
338
301
 
339
- const newTable = compileCreateTable(parsedTable, this.wrap);
302
+ const newTable = compileCreateTable(parsedTable, this.wrap);
340
303
 
341
- return this.generateAlterCommands(newTable, createIndices);
342
- },
343
- { connection: this.connection }
344
- );
304
+ return this.generateAlterCommands(newTable, createIndices);
345
305
  }
346
306
 
347
- setNullable(column, isNullable) {
348
- return this.client.transaction(
349
- async (trx) => {
350
- this.trx = trx;
307
+ async setNullable(column, isNullable) {
308
+ const { createTable, createIndices } = await this.getTableSql();
351
309
 
352
- const { createTable, createIndices } = await this.getTableSql();
310
+ const parsedTable = parseCreateTable(createTable);
311
+ parsedTable.table = this.alteredName;
353
312
 
354
- const parsedTable = parseCreateTable(createTable);
355
- const parsedColumn = parsedTable.columns.find((c) =>
356
- isEqualId(column, c.name)
357
- );
313
+ const parsedColumn = parsedTable.columns.find((c) =>
314
+ isEqualId(column, c.name)
315
+ );
358
316
 
359
- if (!parsedColumn) {
360
- throw new Error(
361
- `.setNullable: Column ${column} does not exist in table ${this.tableName()}.`
362
- );
363
- }
317
+ if (!parsedColumn) {
318
+ throw new Error(
319
+ `.setNullable: Column ${column} does not exist in table ${this.tableName()}.`
320
+ );
321
+ }
364
322
 
365
- parsedColumn.constraints.notnull = isNullable
366
- ? null
367
- : { name: null, conflict: null };
323
+ parsedColumn.constraints.notnull = isNullable
324
+ ? null
325
+ : { name: null, conflict: null };
368
326
 
369
- parsedColumn.constraints.null = isNullable
370
- ? parsedColumn.constraints.null
371
- : null;
327
+ parsedColumn.constraints.null = isNullable
328
+ ? parsedColumn.constraints.null
329
+ : null;
372
330
 
373
- const newTable = compileCreateTable(parsedTable, this.wrap);
331
+ const newTable = compileCreateTable(parsedTable, this.wrap);
374
332
 
375
- return this.generateAlterCommands(newTable, createIndices);
376
- },
377
- { connection: this.connection }
378
- );
333
+ return this.generateAlterCommands(newTable, createIndices);
379
334
  }
380
335
 
381
336
  async alter(newSql, createIndices, columns) {
382
- await this.createNewTable(newSql);
383
- await this.copyData(columns);
384
- await this.dropOriginal();
385
- await this.renameTable();
337
+ const wasForeignCheckEnabled = await this.isForeignCheckEnabled();
386
338
 
387
- for (const createIndex of createIndices) {
388
- await this.trx.raw(createIndex);
339
+ if (wasForeignCheckEnabled) {
340
+ await this.setForeignCheck(false);
341
+ }
342
+
343
+ try {
344
+ await this.client.transaction(
345
+ async (trx) => {
346
+ await trx.raw(newSql);
347
+ await this.copyData(trx, columns);
348
+ await this.dropOriginal(trx);
349
+ await this.renameTable(trx);
350
+
351
+ for (const createIndex of createIndices) {
352
+ await trx.raw(createIndex);
353
+ }
354
+
355
+ if (wasForeignCheckEnabled) {
356
+ const foreignViolations = await trx.raw(executeForeignCheck());
357
+
358
+ if (foreignViolations.length > 0) {
359
+ throw new Error('FOREIGN KEY constraint failed');
360
+ }
361
+ }
362
+ },
363
+ { connection: this.connection }
364
+ );
365
+ } finally {
366
+ if (wasForeignCheckEnabled) {
367
+ await this.setForeignCheck(true);
368
+ }
389
369
  }
390
370
  }
391
371
 
392
- generateAlterCommands(newSql, createIndices, columns) {
393
- const result = [];
372
+ async generateAlterCommands(newSql, createIndices, columns) {
373
+ const sql = [];
374
+ const pre = [];
375
+ const post = [];
376
+ let check = null;
394
377
 
395
- result.push(createNewTable(newSql, this.tableName(), this.alteredName));
396
- result.push(copyData(this.tableName(), this.alteredName, columns));
397
- result.push(dropOriginal(this.tableName()));
398
- result.push(renameTable(this.alteredName, this.tableName()));
378
+ sql.push(newSql);
379
+ sql.push(copyData(this.tableName(), this.alteredName, columns));
380
+ sql.push(dropOriginal(this.tableName()));
381
+ sql.push(renameTable(this.alteredName, this.tableName()));
399
382
 
400
383
  for (const createIndex of createIndices) {
401
- result.push(createIndex);
384
+ sql.push(createIndex);
385
+ }
386
+
387
+ const isForeignCheckEnabled = await this.isForeignCheckEnabled();
388
+
389
+ if (isForeignCheckEnabled) {
390
+ pre.push(setForeignCheck(false));
391
+ post.push(setForeignCheck(true));
392
+
393
+ check = executeForeignCheck();
402
394
  }
403
395
 
404
- return result;
396
+ return { pre, sql, check, post };
405
397
  }
406
398
  }
407
399