knex 2.4.2 → 2.5.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 (190) hide show
  1. package/CHANGELOG.md +54 -18
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +147 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +473 -473
  7. package/bin/utils/cli-config-utils.js +210 -210
  8. package/bin/utils/constants.js +7 -7
  9. package/bin/utils/migrationsLister.js +37 -37
  10. package/knex.js +23 -23
  11. package/knex.mjs +11 -0
  12. package/lib/builder-interface-augmenter.js +120 -120
  13. package/lib/client.js +495 -475
  14. package/lib/constants.js +61 -61
  15. package/lib/dialects/better-sqlite3/index.js +77 -72
  16. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  17. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  18. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  19. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  20. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  21. package/lib/dialects/cockroachdb/index.js +86 -86
  22. package/lib/dialects/index.js +33 -33
  23. package/lib/dialects/mssql/index.js +500 -495
  24. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  25. package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -600
  26. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  27. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  28. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -378
  29. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  30. package/lib/dialects/mssql/transaction.js +176 -176
  31. package/lib/dialects/mysql/index.js +201 -201
  32. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -274
  33. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  34. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  35. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  36. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  37. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  38. package/lib/dialects/mysql/transaction.js +46 -46
  39. package/lib/dialects/mysql2/index.js +53 -33
  40. package/lib/dialects/mysql2/transaction.js +44 -44
  41. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  42. package/lib/dialects/oracle/index.js +92 -92
  43. package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -342
  44. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  45. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  46. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  47. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  48. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  49. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  50. package/lib/dialects/oracle/utils.js +87 -87
  51. package/lib/dialects/oracledb/index.js +327 -327
  52. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  53. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -55
  54. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  55. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  56. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  57. package/lib/dialects/oracledb/transaction.js +98 -98
  58. package/lib/dialects/oracledb/utils.js +208 -208
  59. package/lib/dialects/pgnative/index.js +60 -60
  60. package/lib/dialects/postgres/execution/pg-transaction.js +19 -12
  61. package/lib/dialects/postgres/index.js +358 -358
  62. package/lib/dialects/postgres/query/pg-querybuilder.js +43 -38
  63. package/lib/dialects/postgres/query/pg-querycompiler.js +400 -395
  64. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  65. package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
  66. package/lib/dialects/postgres/schema/pg-tablecompiler.js +304 -299
  67. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  68. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  69. package/lib/dialects/redshift/index.js +86 -86
  70. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  71. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  72. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  73. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  74. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  75. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  76. package/lib/dialects/redshift/transaction.js +32 -25
  77. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +25 -18
  78. package/lib/dialects/sqlite3/index.js +250 -250
  79. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  80. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  81. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  82. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  83. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  84. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  85. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  86. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  87. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  88. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  89. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  90. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -347
  91. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  92. package/lib/execution/batch-insert.js +51 -51
  93. package/lib/execution/internal/delay.js +6 -6
  94. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  95. package/lib/execution/internal/query-executioner.js +62 -62
  96. package/lib/execution/runner.js +325 -307
  97. package/lib/execution/transaction.js +409 -401
  98. package/lib/formatter/formatterUtils.js +42 -42
  99. package/lib/formatter/rawFormatter.js +84 -84
  100. package/lib/formatter/wrappingFormatter.js +250 -250
  101. package/lib/formatter.js +25 -25
  102. package/lib/index.js +3 -3
  103. package/lib/knex-builder/FunctionHelper.js +80 -54
  104. package/lib/knex-builder/Knex.js +59 -59
  105. package/lib/knex-builder/internal/config-resolver.js +57 -57
  106. package/lib/knex-builder/internal/parse-connection.js +87 -87
  107. package/lib/knex-builder/make-knex.js +345 -340
  108. package/lib/logger.js +76 -76
  109. package/lib/migrations/common/MigrationsLoader.js +36 -36
  110. package/lib/migrations/migrate/MigrationGenerator.js +84 -84
  111. package/lib/migrations/migrate/Migrator.js +598 -598
  112. package/lib/migrations/migrate/migrate-stub.js +17 -17
  113. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  114. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  115. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  116. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  117. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  118. package/lib/migrations/migrate/stub/eg.stub +14 -14
  119. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  120. package/lib/migrations/migrate/stub/js.stub +22 -22
  121. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  122. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  123. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  124. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  125. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  126. package/lib/migrations/migrate/stub/ls.stub +14 -14
  127. package/lib/migrations/migrate/stub/mjs.stub +23 -23
  128. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  129. package/lib/migrations/migrate/stub/ts.stub +21 -21
  130. package/lib/migrations/migrate/table-creator.js +77 -77
  131. package/lib/migrations/migrate/table-resolver.js +27 -27
  132. package/lib/migrations/seed/Seeder.js +137 -137
  133. package/lib/migrations/seed/seed-stub.js +13 -13
  134. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  135. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  136. package/lib/migrations/seed/stub/coffee.stub +9 -9
  137. package/lib/migrations/seed/stub/eg.stub +11 -11
  138. package/lib/migrations/seed/stub/js.stub +13 -13
  139. package/lib/migrations/seed/stub/ls.stub +11 -11
  140. package/lib/migrations/seed/stub/mjs.stub +12 -12
  141. package/lib/migrations/seed/stub/ts.stub +13 -13
  142. package/lib/migrations/util/fs.js +86 -86
  143. package/lib/migrations/util/import-file.js +12 -12
  144. package/lib/migrations/util/is-module-type.js +9 -9
  145. package/lib/migrations/util/template.js +52 -52
  146. package/lib/migrations/util/timestamp.js +14 -14
  147. package/lib/query/analytic.js +52 -52
  148. package/lib/query/constants.js +15 -15
  149. package/lib/query/joinclause.js +270 -270
  150. package/lib/query/method-constants.js +136 -135
  151. package/lib/query/querybuilder.js +1793 -1794
  152. package/lib/query/querycompiler.js +1591 -1580
  153. package/lib/raw.js +139 -139
  154. package/lib/ref.js +39 -39
  155. package/lib/schema/builder.js +115 -115
  156. package/lib/schema/columnbuilder.js +146 -146
  157. package/lib/schema/columncompiler.js +307 -307
  158. package/lib/schema/compiler.js +187 -187
  159. package/lib/schema/internal/helpers.js +55 -55
  160. package/lib/schema/tablebuilder.js +376 -376
  161. package/lib/schema/tablecompiler.js +433 -433
  162. package/lib/schema/viewbuilder.js +92 -92
  163. package/lib/schema/viewcompiler.js +138 -138
  164. package/lib/util/finally-mixin.js +13 -13
  165. package/lib/util/helpers.js +95 -95
  166. package/lib/util/is.js +32 -32
  167. package/lib/util/nanoid.js +40 -40
  168. package/lib/util/noop.js +1 -1
  169. package/lib/util/save-async-stack.js +14 -14
  170. package/lib/util/security.js +26 -0
  171. package/lib/util/string.js +190 -190
  172. package/lib/util/timeout.js +29 -29
  173. package/package.json +12 -10
  174. package/scripts/build.js +125 -125
  175. package/scripts/clean.js +31 -31
  176. package/scripts/docker-compose.yml +152 -152
  177. package/scripts/next-release-howto.md +24 -24
  178. package/scripts/oracledb-install-driver-libs.sh +82 -82
  179. package/scripts/release.sh +34 -34
  180. package/scripts/runkit-example.js +34 -34
  181. package/scripts/stress-test/README.txt +18 -18
  182. package/scripts/stress-test/docker-compose.yml +57 -57
  183. package/scripts/stress-test/knex-stress-test.js +208 -208
  184. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  185. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  186. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  187. package/scripts/update_gitignore_for_tsc_output.js +90 -90
  188. package/types/index.d.ts +3273 -3233
  189. package/types/result.d.ts +27 -27
  190. package/types/tables.d.ts +4 -4
@@ -1,433 +1,433 @@
1
- /* eslint max-len:0 */
2
-
3
- // Table Compiler
4
- // -------
5
- const {
6
- pushAdditional,
7
- pushQuery,
8
- unshiftQuery,
9
- } = require('./internal/helpers');
10
- const helpers = require('../util/helpers');
11
- const groupBy = require('lodash/groupBy');
12
- const indexOf = require('lodash/indexOf');
13
- const isEmpty = require('lodash/isEmpty');
14
- const tail = require('lodash/tail');
15
- const { normalizeArr } = require('../util/helpers');
16
-
17
- class TableCompiler {
18
- constructor(client, tableBuilder) {
19
- this.client = client;
20
- this.tableBuilder = tableBuilder;
21
- this._commonBuilder = this.tableBuilder;
22
- this.method = tableBuilder._method;
23
- this.schemaNameRaw = tableBuilder._schemaName;
24
- this.tableNameRaw = tableBuilder._tableName;
25
- this.tableNameLikeRaw = tableBuilder._tableNameLike;
26
- this.single = tableBuilder._single;
27
- this.grouped = groupBy(tableBuilder._statements, 'grouping');
28
-
29
- this.formatter = client.formatter(tableBuilder);
30
- this.bindings = [];
31
- this.formatter.bindings = this.bindings;
32
- this.bindingsHolder = this;
33
-
34
- this.sequence = [];
35
- this._formatting = client.config && client.config.formatting;
36
-
37
- this.checksCount = 0;
38
- }
39
-
40
- // Convert the tableCompiler toSQL
41
- toSQL() {
42
- this[this.method]();
43
- return this.sequence;
44
- }
45
-
46
- // Column Compilation
47
- // -------
48
-
49
- // If this is a table "creation", we need to first run through all
50
- // of the columns to build them into a single string,
51
- // and then run through anything else and push it to the query sequence.
52
- create(ifNot, like) {
53
- const columnBuilders = this.getColumns();
54
- const columns = columnBuilders.map((col) => col.toSQL());
55
- const columnTypes = this.getColumnTypes(columns);
56
- if (this.createAlterTableMethods) {
57
- this.alterTableForCreate(columnTypes);
58
- }
59
- this.createQuery(columnTypes, ifNot, like);
60
- this.columnQueries(columns);
61
- delete this.single.comment;
62
- this.alterTable();
63
- }
64
-
65
- // Only create the table if it doesn't exist.
66
- createIfNot() {
67
- this.create(true);
68
- }
69
-
70
- createLike() {
71
- this.create(false, true);
72
- }
73
-
74
- createLikeIfNot() {
75
- this.create(true, true);
76
- }
77
-
78
- // If we're altering the table, we need to one-by-one
79
- // go through and handle each of the queries associated
80
- // with altering the table's schema.
81
- alter() {
82
- const addColBuilders = this.getColumns();
83
- const addColumns = addColBuilders.map((col) => col.toSQL());
84
- const alterColBuilders = this.getColumns('alter');
85
- const alterColumns = alterColBuilders.map((col) => col.toSQL());
86
- const addColumnTypes = this.getColumnTypes(addColumns);
87
- const alterColumnTypes = this.getColumnTypes(alterColumns);
88
-
89
- this.addColumns(addColumnTypes);
90
- this.alterColumns(alterColumnTypes, alterColBuilders);
91
- this.columnQueries(addColumns);
92
- this.columnQueries(alterColumns);
93
- this.alterTable();
94
- }
95
-
96
- foreign(foreignData) {
97
- if (foreignData.inTable && foreignData.references) {
98
- const keyName = foreignData.keyName
99
- ? this.formatter.wrap(foreignData.keyName)
100
- : this._indexCommand('foreign', this.tableNameRaw, foreignData.column);
101
- const column = this.formatter.columnize(foreignData.column);
102
- const references = this.formatter.columnize(foreignData.references);
103
- const inTable = this.formatter.wrap(foreignData.inTable);
104
- const onUpdate = foreignData.onUpdate
105
- ? (this.lowerCase ? ' on update ' : ' ON UPDATE ') +
106
- foreignData.onUpdate
107
- : '';
108
- const onDelete = foreignData.onDelete
109
- ? (this.lowerCase ? ' on delete ' : ' ON DELETE ') +
110
- foreignData.onDelete
111
- : '';
112
- const deferrable = foreignData.deferrable
113
- ? this.lowerCase
114
- ? ` deferrable initially ${foreignData.deferrable.toLowerCase()} `
115
- : ` DEFERRABLE INITIALLY ${foreignData.deferrable.toUpperCase()} `
116
- : '';
117
- if (this.lowerCase) {
118
- this.pushQuery(
119
- (!this.forCreate ? `alter table ${this.tableName()} add ` : '') +
120
- 'constraint ' +
121
- keyName +
122
- ' ' +
123
- 'foreign key (' +
124
- column +
125
- ') references ' +
126
- inTable +
127
- ' (' +
128
- references +
129
- ')' +
130
- onUpdate +
131
- onDelete +
132
- deferrable
133
- );
134
- } else {
135
- this.pushQuery(
136
- (!this.forCreate ? `ALTER TABLE ${this.tableName()} ADD ` : '') +
137
- 'CONSTRAINT ' +
138
- keyName +
139
- ' ' +
140
- 'FOREIGN KEY (' +
141
- column +
142
- ') REFERENCES ' +
143
- inTable +
144
- ' (' +
145
- references +
146
- ')' +
147
- onUpdate +
148
- onDelete +
149
- deferrable
150
- );
151
- }
152
- }
153
- }
154
-
155
- // Get all of the column sql & bindings individually for building the table queries.
156
- getColumnTypes(columns) {
157
- return columns.reduce(
158
- function (memo, columnSQL) {
159
- const column = columnSQL[0];
160
- memo.sql.push(column.sql);
161
- memo.bindings.concat(column.bindings);
162
- return memo;
163
- },
164
- { sql: [], bindings: [] }
165
- );
166
- }
167
-
168
- // Adds all of the additional queries from the "column"
169
- columnQueries(columns) {
170
- const queries = columns.reduce(function (memo, columnSQL) {
171
- const column = tail(columnSQL);
172
- if (!isEmpty(column)) return memo.concat(column);
173
- return memo;
174
- }, []);
175
- for (const q of queries) {
176
- this.pushQuery(q);
177
- }
178
- }
179
-
180
- // All of the columns to "add" for the query
181
- addColumns(columns, prefix) {
182
- prefix = prefix || this.addColumnsPrefix;
183
-
184
- if (columns.sql.length > 0) {
185
- const columnSql = columns.sql.map((column) => {
186
- return prefix + column;
187
- });
188
- this.pushQuery({
189
- sql:
190
- (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
191
- this.tableName() +
192
- ' ' +
193
- columnSql.join(', '),
194
- bindings: columns.bindings,
195
- });
196
- }
197
- }
198
-
199
- alterColumns(columns, colBuilders) {
200
- if (columns.sql.length > 0) {
201
- this.addColumns(columns, this.alterColumnsPrefix, colBuilders);
202
- }
203
- }
204
-
205
- // Compile the columns as needed for the current create or alter table
206
- getColumns(method) {
207
- const columns = this.grouped.columns || [];
208
- method = method || 'add';
209
-
210
- const queryContext = this.tableBuilder.queryContext();
211
-
212
- return columns
213
- .filter((column) => column.builder._method === method)
214
- .map((column) => {
215
- // pass queryContext down to columnBuilder but do not overwrite it if already set
216
- if (
217
- queryContext !== undefined &&
218
- column.builder.queryContext() === undefined
219
- ) {
220
- column.builder.queryContext(queryContext);
221
- }
222
- return this.client.columnCompiler(this, column.builder);
223
- });
224
- }
225
-
226
- tableName() {
227
- const name = this.schemaNameRaw
228
- ? `${this.schemaNameRaw}.${this.tableNameRaw}`
229
- : this.tableNameRaw;
230
-
231
- return this.formatter.wrap(name);
232
- }
233
-
234
- tableNameLike() {
235
- const name = this.schemaNameRaw
236
- ? `${this.schemaNameRaw}.${this.tableNameLikeRaw}`
237
- : this.tableNameLikeRaw;
238
-
239
- return this.formatter.wrap(name);
240
- }
241
-
242
- // Generate all of the alter column statements necessary for the query.
243
- alterTable() {
244
- const alterTable = this.grouped.alterTable || [];
245
- for (let i = 0, l = alterTable.length; i < l; i++) {
246
- const statement = alterTable[i];
247
- if (this[statement.method]) {
248
- this[statement.method].apply(this, statement.args);
249
- } else {
250
- this.client.logger.error(`Debug: ${statement.method} does not exist`);
251
- }
252
- }
253
- for (const item in this.single) {
254
- if (typeof this[item] === 'function') this[item](this.single[item]);
255
- }
256
- }
257
-
258
- alterTableForCreate(columnTypes) {
259
- this.forCreate = true;
260
- const savedSequence = this.sequence;
261
- const alterTable = this.grouped.alterTable || [];
262
- this.grouped.alterTable = [];
263
- for (let i = 0, l = alterTable.length; i < l; i++) {
264
- const statement = alterTable[i];
265
- if (indexOf(this.createAlterTableMethods, statement.method) < 0) {
266
- this.grouped.alterTable.push(statement);
267
- continue;
268
- }
269
- if (this[statement.method]) {
270
- this.sequence = [];
271
- this[statement.method].apply(this, statement.args);
272
- columnTypes.sql.push(this.sequence[0].sql);
273
- } else {
274
- this.client.logger.error(`Debug: ${statement.method} does not exist`);
275
- }
276
- }
277
- this.sequence = savedSequence;
278
- this.forCreate = false;
279
- }
280
-
281
- // Drop the index on the current table.
282
- dropIndex(value) {
283
- this.pushQuery(`drop index${value}`);
284
- }
285
-
286
- dropUnique() {
287
- throw new Error('Method implemented in the dialect driver');
288
- }
289
-
290
- dropForeign() {
291
- throw new Error('Method implemented in the dialect driver');
292
- }
293
-
294
- dropColumn() {
295
- const columns = helpers.normalizeArr.apply(null, arguments);
296
- const drops = (Array.isArray(columns) ? columns : [columns]).map(
297
- (column) => {
298
- return this.dropColumnPrefix + this.formatter.wrap(column);
299
- }
300
- );
301
- this.pushQuery(
302
- (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
303
- this.tableName() +
304
- ' ' +
305
- drops.join(', ')
306
- );
307
- }
308
-
309
- //Default implementation of setNullable. Overwrite on dialect-specific tablecompiler when needed
310
- //(See postgres/mssql for reference)
311
- _setNullableState(column, nullable) {
312
- const tableName = this.tableName();
313
- const columnName = this.formatter.columnize(column);
314
- const alterColumnPrefix = this.alterColumnsPrefix;
315
- return this.pushQuery({
316
- sql: 'SELECT 1',
317
- output: () => {
318
- return this.client
319
- .queryBuilder()
320
- .from(this.tableNameRaw)
321
- .columnInfo(column)
322
- .then((columnInfo) => {
323
- if (isEmpty(columnInfo)) {
324
- throw new Error(
325
- `.setNullable: Column ${columnName} does not exist in table ${tableName}.`
326
- );
327
- }
328
- const nullableType = nullable ? 'null' : 'not null';
329
- const columnType =
330
- columnInfo.type +
331
- (columnInfo.maxLength ? `(${columnInfo.maxLength})` : '');
332
- const defaultValue =
333
- columnInfo.defaultValue !== null &&
334
- columnInfo.defaultValue !== void 0
335
- ? `default '${columnInfo.defaultValue}'`
336
- : '';
337
- const sql = `alter table ${tableName} ${alterColumnPrefix} ${columnName} ${columnType} ${nullableType} ${defaultValue}`;
338
- return this.client.raw(sql);
339
- });
340
- },
341
- });
342
- }
343
-
344
- setNullable(column) {
345
- return this._setNullableState(column, true);
346
- }
347
-
348
- dropNullable(column) {
349
- return this._setNullableState(column, false);
350
- }
351
-
352
- dropChecks(checkConstraintNames) {
353
- if (checkConstraintNames === undefined) return '';
354
- checkConstraintNames = normalizeArr(checkConstraintNames);
355
- const tableName = this.tableName();
356
- const sql = `alter table ${tableName} ${checkConstraintNames
357
- .map((constraint) => `drop constraint ${constraint}`)
358
- .join(', ')}`;
359
- this.pushQuery(sql);
360
- }
361
-
362
- check(checkPredicate, bindings, constraintName) {
363
- const tableName = this.tableName();
364
- let checkConstraint = constraintName;
365
- if (!checkConstraint) {
366
- this.checksCount++;
367
- checkConstraint = tableName + '_' + this.checksCount;
368
- }
369
- const sql = `alter table ${tableName} add constraint ${checkConstraint} check(${checkPredicate})`;
370
- this.pushQuery(sql);
371
- }
372
-
373
- _addChecks() {
374
- if (this.grouped.checks) {
375
- return (
376
- ', ' +
377
- this.grouped.checks
378
- .map((c) => {
379
- return `${
380
- c.args[2] ? 'constraint ' + c.args[2] + ' ' : ''
381
- }check (${this.client.raw(c.args[0], c.args[1])})`;
382
- })
383
- .join(', ')
384
- );
385
- }
386
- return '';
387
- }
388
-
389
- // If no name was specified for this index, we will create one using a basic
390
- // convention of the table name, followed by the columns, followed by an
391
- // index type, such as primary or index, which makes the index unique.
392
- _indexCommand(type, tableName, columns) {
393
- if (!Array.isArray(columns)) columns = columns ? [columns] : [];
394
- const table = tableName.replace(/\.|-/g, '_');
395
- const indexName = (
396
- table +
397
- '_' +
398
- columns.join('_') +
399
- '_' +
400
- type
401
- ).toLowerCase();
402
- return this.formatter.wrap(indexName);
403
- }
404
-
405
- _getPrimaryKeys() {
406
- return (this.grouped.alterTable || [])
407
- .filter((a) => a.method === 'primary')
408
- .flatMap((a) => a.args)
409
- .flat();
410
- }
411
-
412
- _canBeAddPrimaryKey(options) {
413
- return options.primaryKey && this._getPrimaryKeys().length === 0;
414
- }
415
-
416
- _getIncrementsColumnNames() {
417
- return this.grouped.columns
418
- .filter((c) => c.builder._type === 'increments')
419
- .map((c) => c.builder._args[0]);
420
- }
421
- }
422
-
423
- TableCompiler.prototype.pushQuery = pushQuery;
424
- TableCompiler.prototype.pushAdditional = pushAdditional;
425
- TableCompiler.prototype.unshiftQuery = unshiftQuery;
426
- TableCompiler.prototype.lowerCase = true;
427
- TableCompiler.prototype.createAlterTableMethods = null;
428
- TableCompiler.prototype.addColumnsPrefix = 'add column ';
429
- TableCompiler.prototype.alterColumnsPrefix = 'alter column ';
430
- TableCompiler.prototype.modifyColumnPrefix = 'modify column ';
431
- TableCompiler.prototype.dropColumnPrefix = 'drop column ';
432
-
433
- module.exports = TableCompiler;
1
+ /* eslint max-len:0 */
2
+
3
+ // Table Compiler
4
+ // -------
5
+ const {
6
+ pushAdditional,
7
+ pushQuery,
8
+ unshiftQuery,
9
+ } = require('./internal/helpers');
10
+ const helpers = require('../util/helpers');
11
+ const groupBy = require('lodash/groupBy');
12
+ const indexOf = require('lodash/indexOf');
13
+ const isEmpty = require('lodash/isEmpty');
14
+ const tail = require('lodash/tail');
15
+ const { normalizeArr } = require('../util/helpers');
16
+
17
+ class TableCompiler {
18
+ constructor(client, tableBuilder) {
19
+ this.client = client;
20
+ this.tableBuilder = tableBuilder;
21
+ this._commonBuilder = this.tableBuilder;
22
+ this.method = tableBuilder._method;
23
+ this.schemaNameRaw = tableBuilder._schemaName;
24
+ this.tableNameRaw = tableBuilder._tableName;
25
+ this.tableNameLikeRaw = tableBuilder._tableNameLike;
26
+ this.single = tableBuilder._single;
27
+ this.grouped = groupBy(tableBuilder._statements, 'grouping');
28
+
29
+ this.formatter = client.formatter(tableBuilder);
30
+ this.bindings = [];
31
+ this.formatter.bindings = this.bindings;
32
+ this.bindingsHolder = this;
33
+
34
+ this.sequence = [];
35
+ this._formatting = client.config && client.config.formatting;
36
+
37
+ this.checksCount = 0;
38
+ }
39
+
40
+ // Convert the tableCompiler toSQL
41
+ toSQL() {
42
+ this[this.method]();
43
+ return this.sequence;
44
+ }
45
+
46
+ // Column Compilation
47
+ // -------
48
+
49
+ // If this is a table "creation", we need to first run through all
50
+ // of the columns to build them into a single string,
51
+ // and then run through anything else and push it to the query sequence.
52
+ create(ifNot, like) {
53
+ const columnBuilders = this.getColumns();
54
+ const columns = columnBuilders.map((col) => col.toSQL());
55
+ const columnTypes = this.getColumnTypes(columns);
56
+ if (this.createAlterTableMethods) {
57
+ this.alterTableForCreate(columnTypes);
58
+ }
59
+ this.createQuery(columnTypes, ifNot, like);
60
+ this.columnQueries(columns);
61
+ delete this.single.comment;
62
+ this.alterTable();
63
+ }
64
+
65
+ // Only create the table if it doesn't exist.
66
+ createIfNot() {
67
+ this.create(true);
68
+ }
69
+
70
+ createLike() {
71
+ this.create(false, true);
72
+ }
73
+
74
+ createLikeIfNot() {
75
+ this.create(true, true);
76
+ }
77
+
78
+ // If we're altering the table, we need to one-by-one
79
+ // go through and handle each of the queries associated
80
+ // with altering the table's schema.
81
+ alter() {
82
+ const addColBuilders = this.getColumns();
83
+ const addColumns = addColBuilders.map((col) => col.toSQL());
84
+ const alterColBuilders = this.getColumns('alter');
85
+ const alterColumns = alterColBuilders.map((col) => col.toSQL());
86
+ const addColumnTypes = this.getColumnTypes(addColumns);
87
+ const alterColumnTypes = this.getColumnTypes(alterColumns);
88
+
89
+ this.addColumns(addColumnTypes);
90
+ this.alterColumns(alterColumnTypes, alterColBuilders);
91
+ this.columnQueries(addColumns);
92
+ this.columnQueries(alterColumns);
93
+ this.alterTable();
94
+ }
95
+
96
+ foreign(foreignData) {
97
+ if (foreignData.inTable && foreignData.references) {
98
+ const keyName = foreignData.keyName
99
+ ? this.formatter.wrap(foreignData.keyName)
100
+ : this._indexCommand('foreign', this.tableNameRaw, foreignData.column);
101
+ const column = this.formatter.columnize(foreignData.column);
102
+ const references = this.formatter.columnize(foreignData.references);
103
+ const inTable = this.formatter.wrap(foreignData.inTable);
104
+ const onUpdate = foreignData.onUpdate
105
+ ? (this.lowerCase ? ' on update ' : ' ON UPDATE ') +
106
+ foreignData.onUpdate
107
+ : '';
108
+ const onDelete = foreignData.onDelete
109
+ ? (this.lowerCase ? ' on delete ' : ' ON DELETE ') +
110
+ foreignData.onDelete
111
+ : '';
112
+ const deferrable = foreignData.deferrable
113
+ ? this.lowerCase
114
+ ? ` deferrable initially ${foreignData.deferrable.toLowerCase()} `
115
+ : ` DEFERRABLE INITIALLY ${foreignData.deferrable.toUpperCase()} `
116
+ : '';
117
+ if (this.lowerCase) {
118
+ this.pushQuery(
119
+ (!this.forCreate ? `alter table ${this.tableName()} add ` : '') +
120
+ 'constraint ' +
121
+ keyName +
122
+ ' ' +
123
+ 'foreign key (' +
124
+ column +
125
+ ') references ' +
126
+ inTable +
127
+ ' (' +
128
+ references +
129
+ ')' +
130
+ onUpdate +
131
+ onDelete +
132
+ deferrable
133
+ );
134
+ } else {
135
+ this.pushQuery(
136
+ (!this.forCreate ? `ALTER TABLE ${this.tableName()} ADD ` : '') +
137
+ 'CONSTRAINT ' +
138
+ keyName +
139
+ ' ' +
140
+ 'FOREIGN KEY (' +
141
+ column +
142
+ ') REFERENCES ' +
143
+ inTable +
144
+ ' (' +
145
+ references +
146
+ ')' +
147
+ onUpdate +
148
+ onDelete +
149
+ deferrable
150
+ );
151
+ }
152
+ }
153
+ }
154
+
155
+ // Get all of the column sql & bindings individually for building the table queries.
156
+ getColumnTypes(columns) {
157
+ return columns.reduce(
158
+ function (memo, columnSQL) {
159
+ const column = columnSQL[0];
160
+ memo.sql.push(column.sql);
161
+ memo.bindings.concat(column.bindings);
162
+ return memo;
163
+ },
164
+ { sql: [], bindings: [] }
165
+ );
166
+ }
167
+
168
+ // Adds all of the additional queries from the "column"
169
+ columnQueries(columns) {
170
+ const queries = columns.reduce(function (memo, columnSQL) {
171
+ const column = tail(columnSQL);
172
+ if (!isEmpty(column)) return memo.concat(column);
173
+ return memo;
174
+ }, []);
175
+ for (const q of queries) {
176
+ this.pushQuery(q);
177
+ }
178
+ }
179
+
180
+ // All of the columns to "add" for the query
181
+ addColumns(columns, prefix) {
182
+ prefix = prefix || this.addColumnsPrefix;
183
+
184
+ if (columns.sql.length > 0) {
185
+ const columnSql = columns.sql.map((column) => {
186
+ return prefix + column;
187
+ });
188
+ this.pushQuery({
189
+ sql:
190
+ (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
191
+ this.tableName() +
192
+ ' ' +
193
+ columnSql.join(', '),
194
+ bindings: columns.bindings,
195
+ });
196
+ }
197
+ }
198
+
199
+ alterColumns(columns, colBuilders) {
200
+ if (columns.sql.length > 0) {
201
+ this.addColumns(columns, this.alterColumnsPrefix, colBuilders);
202
+ }
203
+ }
204
+
205
+ // Compile the columns as needed for the current create or alter table
206
+ getColumns(method) {
207
+ const columns = this.grouped.columns || [];
208
+ method = method || 'add';
209
+
210
+ const queryContext = this.tableBuilder.queryContext();
211
+
212
+ return columns
213
+ .filter((column) => column.builder._method === method)
214
+ .map((column) => {
215
+ // pass queryContext down to columnBuilder but do not overwrite it if already set
216
+ if (
217
+ queryContext !== undefined &&
218
+ column.builder.queryContext() === undefined
219
+ ) {
220
+ column.builder.queryContext(queryContext);
221
+ }
222
+ return this.client.columnCompiler(this, column.builder);
223
+ });
224
+ }
225
+
226
+ tableName() {
227
+ const name = this.schemaNameRaw
228
+ ? `${this.schemaNameRaw}.${this.tableNameRaw}`
229
+ : this.tableNameRaw;
230
+
231
+ return this.formatter.wrap(name);
232
+ }
233
+
234
+ tableNameLike() {
235
+ const name = this.schemaNameRaw
236
+ ? `${this.schemaNameRaw}.${this.tableNameLikeRaw}`
237
+ : this.tableNameLikeRaw;
238
+
239
+ return this.formatter.wrap(name);
240
+ }
241
+
242
+ // Generate all of the alter column statements necessary for the query.
243
+ alterTable() {
244
+ const alterTable = this.grouped.alterTable || [];
245
+ for (let i = 0, l = alterTable.length; i < l; i++) {
246
+ const statement = alterTable[i];
247
+ if (this[statement.method]) {
248
+ this[statement.method].apply(this, statement.args);
249
+ } else {
250
+ this.client.logger.error(`Debug: ${statement.method} does not exist`);
251
+ }
252
+ }
253
+ for (const item in this.single) {
254
+ if (typeof this[item] === 'function') this[item](this.single[item]);
255
+ }
256
+ }
257
+
258
+ alterTableForCreate(columnTypes) {
259
+ this.forCreate = true;
260
+ const savedSequence = this.sequence;
261
+ const alterTable = this.grouped.alterTable || [];
262
+ this.grouped.alterTable = [];
263
+ for (let i = 0, l = alterTable.length; i < l; i++) {
264
+ const statement = alterTable[i];
265
+ if (indexOf(this.createAlterTableMethods, statement.method) < 0) {
266
+ this.grouped.alterTable.push(statement);
267
+ continue;
268
+ }
269
+ if (this[statement.method]) {
270
+ this.sequence = [];
271
+ this[statement.method].apply(this, statement.args);
272
+ columnTypes.sql.push(this.sequence[0].sql);
273
+ } else {
274
+ this.client.logger.error(`Debug: ${statement.method} does not exist`);
275
+ }
276
+ }
277
+ this.sequence = savedSequence;
278
+ this.forCreate = false;
279
+ }
280
+
281
+ // Drop the index on the current table.
282
+ dropIndex(value) {
283
+ this.pushQuery(`drop index${value}`);
284
+ }
285
+
286
+ dropUnique() {
287
+ throw new Error('Method implemented in the dialect driver');
288
+ }
289
+
290
+ dropForeign() {
291
+ throw new Error('Method implemented in the dialect driver');
292
+ }
293
+
294
+ dropColumn() {
295
+ const columns = helpers.normalizeArr.apply(null, arguments);
296
+ const drops = (Array.isArray(columns) ? columns : [columns]).map(
297
+ (column) => {
298
+ return this.dropColumnPrefix + this.formatter.wrap(column);
299
+ }
300
+ );
301
+ this.pushQuery(
302
+ (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
303
+ this.tableName() +
304
+ ' ' +
305
+ drops.join(', ')
306
+ );
307
+ }
308
+
309
+ //Default implementation of setNullable. Overwrite on dialect-specific tablecompiler when needed
310
+ //(See postgres/mssql for reference)
311
+ _setNullableState(column, nullable) {
312
+ const tableName = this.tableName();
313
+ const columnName = this.formatter.columnize(column);
314
+ const alterColumnPrefix = this.alterColumnsPrefix;
315
+ return this.pushQuery({
316
+ sql: 'SELECT 1',
317
+ output: () => {
318
+ return this.client
319
+ .queryBuilder()
320
+ .from(this.tableNameRaw)
321
+ .columnInfo(column)
322
+ .then((columnInfo) => {
323
+ if (isEmpty(columnInfo)) {
324
+ throw new Error(
325
+ `.setNullable: Column ${columnName} does not exist in table ${tableName}.`
326
+ );
327
+ }
328
+ const nullableType = nullable ? 'null' : 'not null';
329
+ const columnType =
330
+ columnInfo.type +
331
+ (columnInfo.maxLength ? `(${columnInfo.maxLength})` : '');
332
+ const defaultValue =
333
+ columnInfo.defaultValue !== null &&
334
+ columnInfo.defaultValue !== void 0
335
+ ? `default '${columnInfo.defaultValue}'`
336
+ : '';
337
+ const sql = `alter table ${tableName} ${alterColumnPrefix} ${columnName} ${columnType} ${nullableType} ${defaultValue}`;
338
+ return this.client.raw(sql);
339
+ });
340
+ },
341
+ });
342
+ }
343
+
344
+ setNullable(column) {
345
+ return this._setNullableState(column, true);
346
+ }
347
+
348
+ dropNullable(column) {
349
+ return this._setNullableState(column, false);
350
+ }
351
+
352
+ dropChecks(checkConstraintNames) {
353
+ if (checkConstraintNames === undefined) return '';
354
+ checkConstraintNames = normalizeArr(checkConstraintNames);
355
+ const tableName = this.tableName();
356
+ const sql = `alter table ${tableName} ${checkConstraintNames
357
+ .map((constraint) => `drop constraint ${constraint}`)
358
+ .join(', ')}`;
359
+ this.pushQuery(sql);
360
+ }
361
+
362
+ check(checkPredicate, bindings, constraintName) {
363
+ const tableName = this.tableName();
364
+ let checkConstraint = constraintName;
365
+ if (!checkConstraint) {
366
+ this.checksCount++;
367
+ checkConstraint = tableName + '_' + this.checksCount;
368
+ }
369
+ const sql = `alter table ${tableName} add constraint ${checkConstraint} check(${checkPredicate})`;
370
+ this.pushQuery(sql);
371
+ }
372
+
373
+ _addChecks() {
374
+ if (this.grouped.checks) {
375
+ return (
376
+ ', ' +
377
+ this.grouped.checks
378
+ .map((c) => {
379
+ return `${
380
+ c.args[2] ? 'constraint ' + c.args[2] + ' ' : ''
381
+ }check (${this.client.raw(c.args[0], c.args[1])})`;
382
+ })
383
+ .join(', ')
384
+ );
385
+ }
386
+ return '';
387
+ }
388
+
389
+ // If no name was specified for this index, we will create one using a basic
390
+ // convention of the table name, followed by the columns, followed by an
391
+ // index type, such as primary or index, which makes the index unique.
392
+ _indexCommand(type, tableName, columns) {
393
+ if (!Array.isArray(columns)) columns = columns ? [columns] : [];
394
+ const table = tableName.replace(/\.|-/g, '_');
395
+ const indexName = (
396
+ table +
397
+ '_' +
398
+ columns.join('_') +
399
+ '_' +
400
+ type
401
+ ).toLowerCase();
402
+ return this.formatter.wrap(indexName);
403
+ }
404
+
405
+ _getPrimaryKeys() {
406
+ return (this.grouped.alterTable || [])
407
+ .filter((a) => a.method === 'primary')
408
+ .flatMap((a) => a.args)
409
+ .flat();
410
+ }
411
+
412
+ _canBeAddPrimaryKey(options) {
413
+ return options.primaryKey && this._getPrimaryKeys().length === 0;
414
+ }
415
+
416
+ _getIncrementsColumnNames() {
417
+ return this.grouped.columns
418
+ .filter((c) => c.builder._type === 'increments')
419
+ .map((c) => c.builder._args[0]);
420
+ }
421
+ }
422
+
423
+ TableCompiler.prototype.pushQuery = pushQuery;
424
+ TableCompiler.prototype.pushAdditional = pushAdditional;
425
+ TableCompiler.prototype.unshiftQuery = unshiftQuery;
426
+ TableCompiler.prototype.lowerCase = true;
427
+ TableCompiler.prototype.createAlterTableMethods = null;
428
+ TableCompiler.prototype.addColumnsPrefix = 'add column ';
429
+ TableCompiler.prototype.alterColumnsPrefix = 'alter column ';
430
+ TableCompiler.prototype.modifyColumnPrefix = 'modify column ';
431
+ TableCompiler.prototype.dropColumnPrefix = 'drop column ';
432
+
433
+ module.exports = TableCompiler;