knex 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/CONTRIBUTING.md +194 -194
  3. package/LICENSE +22 -22
  4. package/README.md +148 -148
  5. package/UPGRADING.md +233 -233
  6. package/bin/cli.js +472 -472
  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/lib/builder-interface-augmenter.js +120 -120
  12. package/lib/client.js +475 -470
  13. package/lib/constants.js +61 -61
  14. package/lib/dialects/better-sqlite3/index.js +72 -72
  15. package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
  16. package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
  17. package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
  18. package/lib/dialects/cockroachdb/crdb-tablecompiler.js +37 -37
  19. package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
  20. package/lib/dialects/cockroachdb/index.js +86 -86
  21. package/lib/dialects/mssql/index.js +495 -495
  22. package/lib/dialects/mssql/mssql-formatter.js +34 -34
  23. package/lib/dialects/mssql/query/mssql-querycompiler.js +600 -600
  24. package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
  25. package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
  26. package/lib/dialects/mssql/schema/mssql-tablecompiler.js +378 -372
  27. package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
  28. package/lib/dialects/mssql/transaction.js +176 -176
  29. package/lib/dialects/mysql/index.js +201 -201
  30. package/lib/dialects/mysql/query/mysql-querycompiler.js +274 -248
  31. package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
  32. package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
  33. package/lib/dialects/mysql/schema/mysql-tablecompiler.js +381 -381
  34. package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
  35. package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
  36. package/lib/dialects/mysql/transaction.js +46 -46
  37. package/lib/dialects/mysql2/index.js +33 -33
  38. package/lib/dialects/mysql2/transaction.js +44 -44
  39. package/lib/dialects/oracle/DEAD_CODE.md +5 -5
  40. package/lib/dialects/oracle/index.js +92 -92
  41. package/lib/dialects/oracle/query/oracle-querycompiler.js +342 -342
  42. package/lib/dialects/oracle/schema/internal/incrementUtils.js +20 -20
  43. package/lib/dialects/oracle/schema/internal/trigger.js +135 -135
  44. package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
  45. package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
  46. package/lib/dialects/oracle/schema/oracle-compiler.js +122 -122
  47. package/lib/dialects/oracle/schema/oracle-tablecompiler.js +190 -190
  48. package/lib/dialects/oracle/utils.js +87 -87
  49. package/lib/dialects/oracledb/index.js +327 -327
  50. package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
  51. package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +55 -55
  52. package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
  53. package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
  54. package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
  55. package/lib/dialects/oracledb/transaction.js +98 -98
  56. package/lib/dialects/oracledb/utils.js +208 -208
  57. package/lib/dialects/pgnative/index.js +60 -60
  58. package/lib/dialects/postgres/execution/pg-transaction.js +12 -12
  59. package/lib/dialects/postgres/index.js +358 -358
  60. package/lib/dialects/postgres/query/pg-querybuilder.js +38 -38
  61. package/lib/dialects/postgres/query/pg-querycompiler.js +395 -395
  62. package/lib/dialects/postgres/schema/pg-columncompiler.js +156 -156
  63. package/lib/dialects/postgres/schema/pg-compiler.js +136 -136
  64. package/lib/dialects/postgres/schema/pg-tablecompiler.js +299 -275
  65. package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
  66. package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
  67. package/lib/dialects/redshift/index.js +86 -86
  68. package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
  69. package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
  70. package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
  71. package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
  72. package/lib/dialects/redshift/schema/redshift-tablecompiler.js +122 -122
  73. package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
  74. package/lib/dialects/redshift/transaction.js +25 -25
  75. package/lib/dialects/sqlite3/execution/sqlite-transaction.js +18 -18
  76. package/lib/dialects/sqlite3/index.js +250 -250
  77. package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
  78. package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +334 -334
  79. package/lib/dialects/sqlite3/schema/ddl.js +400 -400
  80. package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
  81. package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
  82. package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
  83. package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
  84. package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
  85. package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
  86. package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
  87. package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
  88. package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +347 -341
  89. package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
  90. package/lib/execution/batch-insert.js +51 -51
  91. package/lib/execution/internal/delay.js +6 -6
  92. package/lib/execution/internal/ensure-connection-callback.js +41 -41
  93. package/lib/execution/internal/query-executioner.js +62 -58
  94. package/lib/execution/runner.js +307 -307
  95. package/lib/execution/transaction.js +401 -401
  96. package/lib/formatter/formatterUtils.js +42 -42
  97. package/lib/formatter/rawFormatter.js +84 -84
  98. package/lib/formatter/wrappingFormatter.js +250 -250
  99. package/lib/formatter.js +25 -25
  100. package/lib/index.js +3 -3
  101. package/lib/knex-builder/FunctionHelper.js +54 -54
  102. package/lib/knex-builder/Knex.js +59 -59
  103. package/lib/knex-builder/internal/config-resolver.js +57 -57
  104. package/lib/knex-builder/internal/parse-connection.js +87 -87
  105. package/lib/knex-builder/make-knex.js +340 -340
  106. package/lib/logger.js +76 -76
  107. package/lib/migrations/common/MigrationsLoader.js +36 -36
  108. package/lib/migrations/migrate/MigrationGenerator.js +82 -82
  109. package/lib/migrations/migrate/Migrator.js +598 -598
  110. package/lib/migrations/migrate/migrate-stub.js +17 -17
  111. package/lib/migrations/migrate/migration-list-resolver.js +33 -33
  112. package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
  113. package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
  114. package/lib/migrations/migrate/stub/cjs.stub +15 -15
  115. package/lib/migrations/migrate/stub/coffee.stub +13 -13
  116. package/lib/migrations/migrate/stub/eg.stub +14 -14
  117. package/lib/migrations/migrate/stub/js-schema.stub +22 -22
  118. package/lib/migrations/migrate/stub/js.stub +22 -22
  119. package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
  120. package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
  121. package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
  122. package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
  123. package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
  124. package/lib/migrations/migrate/stub/ls.stub +14 -14
  125. package/lib/migrations/migrate/stub/mjs.stub +23 -15
  126. package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
  127. package/lib/migrations/migrate/stub/ts.stub +21 -21
  128. package/lib/migrations/migrate/table-creator.js +77 -77
  129. package/lib/migrations/migrate/table-resolver.js +27 -27
  130. package/lib/migrations/seed/Seeder.js +137 -137
  131. package/lib/migrations/seed/seed-stub.js +13 -13
  132. package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
  133. package/lib/migrations/seed/sources/fs-seeds.js +65 -65
  134. package/lib/migrations/seed/stub/coffee.stub +9 -9
  135. package/lib/migrations/seed/stub/eg.stub +11 -11
  136. package/lib/migrations/seed/stub/js.stub +13 -13
  137. package/lib/migrations/seed/stub/ls.stub +11 -11
  138. package/lib/migrations/seed/stub/mjs.stub +12 -12
  139. package/lib/migrations/seed/stub/ts.stub +13 -13
  140. package/lib/migrations/util/fs.js +86 -86
  141. package/lib/migrations/util/import-file.js +12 -12
  142. package/lib/migrations/util/is-module-type.js +9 -9
  143. package/lib/migrations/util/template.js +52 -52
  144. package/lib/migrations/util/timestamp.js +14 -14
  145. package/lib/query/analytic.js +52 -52
  146. package/lib/query/constants.js +15 -15
  147. package/lib/query/joinclause.js +270 -270
  148. package/lib/query/method-constants.js +135 -135
  149. package/lib/query/querybuilder.js +1794 -1800
  150. package/lib/query/querycompiler.js +1580 -1580
  151. package/lib/raw.js +139 -139
  152. package/lib/ref.js +39 -39
  153. package/lib/schema/builder.js +114 -114
  154. package/lib/schema/columnbuilder.js +145 -145
  155. package/lib/schema/columncompiler.js +307 -307
  156. package/lib/schema/compiler.js +187 -187
  157. package/lib/schema/internal/helpers.js +55 -55
  158. package/lib/schema/tablebuilder.js +375 -375
  159. package/lib/schema/tablecompiler.js +433 -433
  160. package/lib/schema/viewbuilder.js +93 -93
  161. package/lib/schema/viewcompiler.js +138 -138
  162. package/lib/util/finally-mixin.js +13 -13
  163. package/lib/util/helpers.js +95 -95
  164. package/lib/util/is.js +32 -32
  165. package/lib/util/nanoid.js +40 -40
  166. package/lib/util/noop.js +1 -1
  167. package/lib/util/save-async-stack.js +14 -14
  168. package/lib/util/string.js +190 -190
  169. package/lib/util/timeout.js +29 -29
  170. package/package.json +4 -4
  171. package/scripts/build.js +125 -125
  172. package/scripts/clean.js +29 -29
  173. package/scripts/docker-compose.yml +152 -152
  174. package/scripts/next-release-howto.md +24 -24
  175. package/scripts/oracledb-install-driver-libs.sh +82 -82
  176. package/scripts/release.sh +34 -34
  177. package/scripts/runkit-example.js +34 -34
  178. package/scripts/stress-test/README.txt +18 -18
  179. package/scripts/stress-test/docker-compose.yml +57 -57
  180. package/scripts/stress-test/knex-stress-test.js +208 -208
  181. package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +145 -145
  182. package/scripts/stress-test/mysql2-sudden-exit-without-error.js +100 -100
  183. package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +184 -184
  184. package/scripts/update_gitignore_for_tsc_output.js +86 -85
  185. package/types/index.d.ts +3233 -3230
  186. package/types/result.d.ts +27 -27
  187. package/types/tables.d.ts +4 -4
@@ -1,372 +1,378 @@
1
- /* eslint max-len:0 */
2
-
3
- // MSSQL Table Builder & Compiler
4
- // -------
5
- const TableCompiler = require('../../../schema/tablecompiler');
6
- const helpers = require('../../../util/helpers');
7
- const { isObject } = require('../../../util/is');
8
-
9
- // Table Compiler
10
- // ------
11
-
12
- class TableCompiler_MSSQL extends TableCompiler {
13
- constructor(client, tableBuilder) {
14
- super(client, tableBuilder);
15
- }
16
-
17
- createQuery(columns, ifNot, like) {
18
- let createStatement = ifNot
19
- ? `if object_id('${this.tableName()}', 'U') is null `
20
- : '';
21
-
22
- if (like) {
23
- // This query copy only columns and not all indexes and keys like other databases.
24
- createStatement += `SELECT * INTO ${this.tableName()} FROM ${this.tableNameLike()} WHERE 0=1`;
25
- } else {
26
- createStatement +=
27
- 'CREATE TABLE ' +
28
- this.tableName() +
29
- (this._formatting ? ' (\n ' : ' (') +
30
- columns.sql.join(this._formatting ? ',\n ' : ', ') +
31
- this._addChecks() +
32
- ')';
33
- }
34
-
35
- this.pushQuery(createStatement);
36
-
37
- if (this.single.comment) {
38
- this.comment(this.single.comment);
39
- }
40
- if (like) {
41
- this.addColumns(columns, this.addColumnsPrefix);
42
- }
43
- }
44
-
45
- comment(/** @type {string} */ comment) {
46
- if (!comment) {
47
- return;
48
- }
49
-
50
- // XXX: This is a byte limit, not character, so we cannot definitively say they'll exceed the limit without server collation info.
51
- // When I checked in SQL Server 2019, the ctext column in sys.syscomments is defined as a varbinary(8000), so it doesn't even have its own defined collation.
52
- if (comment.length > 7500 / 2) {
53
- this.client.logger.warn(
54
- 'Your comment might be longer than the max comment length for MSSQL of 7,500 bytes.'
55
- );
56
- }
57
-
58
- // See: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addextendedproperty-transact-sql?view=sql-server-ver15#f-adding-an-extended-property-to-a-table
59
- const value = this.formatter.escapingStringDelimiters(comment);
60
- const level0name = this.formatter.escapingStringDelimiters(
61
- this.schemaNameRaw || 'dbo'
62
- );
63
- const level1name = this.formatter.escapingStringDelimiters(
64
- this.tableNameRaw
65
- );
66
- const args = `N'MS_Description', N'${value}', N'Schema', N'${level0name}', N'Table', N'${level1name}'`;
67
- const isAlreadyDefined = `EXISTS(SELECT * FROM sys.fn_listextendedproperty(N'MS_Description', N'Schema', N'${level0name}', N'Table', N'${level1name}', NULL, NULL))`;
68
- this.pushQuery(
69
- `IF ${isAlreadyDefined}\n EXEC sys.sp_updateextendedproperty ${args}\nELSE\n EXEC sys.sp_addextendedproperty ${args}`
70
- );
71
- }
72
-
73
- // Compiles column add. Multiple columns need only one ADD clause (not one ADD per column) so core addColumns doesn't work. #1348
74
- addColumns(columns, prefix) {
75
- prefix = prefix || this.addColumnsPrefix;
76
-
77
- if (columns.sql.length > 0) {
78
- this.pushQuery({
79
- sql:
80
- (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
81
- this.tableName() +
82
- ' ' +
83
- prefix +
84
- columns.sql.join(', '),
85
- bindings: columns.bindings,
86
- });
87
- }
88
- }
89
-
90
- alterColumns(columns, colBuilder) {
91
- for (let i = 0, l = colBuilder.length; i < l; i++) {
92
- const builder = colBuilder[i];
93
- if (builder.modified.defaultTo) {
94
- const schema = this.schemaNameRaw || 'dbo';
95
- const baseQuery = `
96
- DECLARE @constraint varchar(100) = (SELECT default_constraints.name
97
- FROM sys.all_columns
98
- INNER JOIN sys.tables
99
- ON all_columns.object_id = tables.object_id
100
- INNER JOIN sys.schemas
101
- ON tables.schema_id = schemas.schema_id
102
- INNER JOIN sys.default_constraints
103
- ON all_columns.default_object_id = default_constraints.object_id
104
- WHERE schemas.name = '${schema}'
105
- AND tables.name = '${
106
- this.tableNameRaw
107
- }'
108
- AND all_columns.name = '${builder.getColumnName()}')
109
-
110
- IF @constraint IS NOT NULL EXEC('ALTER TABLE ${
111
- this.tableNameRaw
112
- } DROP CONSTRAINT ' + @constraint)`;
113
- this.pushQuery(baseQuery);
114
- }
115
- }
116
- // in SQL server only one column can be altered at a time
117
- columns.sql.forEach((sql) => {
118
- this.pushQuery({
119
- sql:
120
- (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
121
- this.tableName() +
122
- ' ' +
123
- (this.lowerCase
124
- ? this.alterColumnPrefix.toLowerCase()
125
- : this.alterColumnPrefix) +
126
- sql,
127
- bindings: columns.bindings,
128
- });
129
- });
130
- }
131
-
132
- // Compiles column drop. Multiple columns need only one DROP clause (not one DROP per column) so core dropColumn doesn't work. #1348
133
- dropColumn() {
134
- const _this2 = this;
135
- const columns = helpers.normalizeArr.apply(null, arguments);
136
- const columnsArray = Array.isArray(columns) ? columns : [columns];
137
- const drops = columnsArray.map((column) => _this2.formatter.wrap(column));
138
- const schema = this.schemaNameRaw || 'dbo';
139
-
140
- for (const column of columns) {
141
- const baseQuery = `
142
- DECLARE @constraint varchar(100) = (SELECT default_constraints.name
143
- FROM sys.all_columns
144
- INNER JOIN sys.tables
145
- ON all_columns.object_id = tables.object_id
146
- INNER JOIN sys.schemas
147
- ON tables.schema_id = schemas.schema_id
148
- INNER JOIN sys.default_constraints
149
- ON all_columns.default_object_id = default_constraints.object_id
150
- WHERE schemas.name = '${schema}'
151
- AND tables.name = '${this.tableNameRaw}'
152
- AND all_columns.name = '${column}')
153
-
154
- IF @constraint IS NOT NULL EXEC('ALTER TABLE ${this.tableNameRaw} DROP CONSTRAINT ' + @constraint)`;
155
- this.pushQuery(baseQuery);
156
- }
157
- this.pushQuery(
158
- (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
159
- this.tableName() +
160
- ' ' +
161
- this.dropColumnPrefix +
162
- drops.join(', ')
163
- );
164
- }
165
-
166
- changeType() {}
167
-
168
- // Renames a column on the table.
169
- renameColumn(from, to) {
170
- this.pushQuery(
171
- `exec sp_rename ${this.client.parameter(
172
- this.tableName() + '.' + from,
173
- this.tableBuilder,
174
- this.bindingsHolder
175
- )}, ${this.client.parameter(
176
- to,
177
- this.tableBuilder,
178
- this.bindingsHolder
179
- )}, 'COLUMN'`
180
- );
181
- }
182
-
183
- dropFKRefs(runner, refs) {
184
- const formatter = this.client.formatter(this.tableBuilder);
185
- return Promise.all(
186
- refs.map(function (ref) {
187
- const constraintName = formatter.wrap(ref.CONSTRAINT_NAME);
188
- const tableName = formatter.wrap(ref.TABLE_NAME);
189
- return runner.query({
190
- sql: `ALTER TABLE ${tableName} DROP CONSTRAINT ${constraintName}`,
191
- });
192
- })
193
- );
194
- }
195
-
196
- createFKRefs(runner, refs) {
197
- const formatter = this.client.formatter(this.tableBuilder);
198
-
199
- return Promise.all(
200
- refs.map(function (ref) {
201
- const tableName = formatter.wrap(ref.TABLE_NAME);
202
- const keyName = formatter.wrap(ref.CONSTRAINT_NAME);
203
- const column = formatter.columnize(ref.COLUMN_NAME);
204
- const references = formatter.columnize(ref.REFERENCED_COLUMN_NAME);
205
- const inTable = formatter.wrap(ref.REFERENCED_TABLE_NAME);
206
- const onUpdate = ` ON UPDATE ${ref.UPDATE_RULE}`;
207
- const onDelete = ` ON DELETE ${ref.DELETE_RULE}`;
208
-
209
- return runner.query({
210
- sql:
211
- `ALTER TABLE ${tableName} ADD CONSTRAINT ${keyName}` +
212
- ' FOREIGN KEY (' +
213
- column +
214
- ') REFERENCES ' +
215
- inTable +
216
- ' (' +
217
- references +
218
- ')' +
219
- onUpdate +
220
- onDelete,
221
- });
222
- })
223
- );
224
- }
225
-
226
- index(columns, indexName, options) {
227
- indexName = indexName
228
- ? this.formatter.wrap(indexName)
229
- : this._indexCommand('index', this.tableNameRaw, columns);
230
-
231
- let predicate;
232
- if (isObject(options)) {
233
- ({ predicate } = options);
234
- }
235
- const predicateQuery = predicate
236
- ? ' ' + this.client.queryCompiler(predicate).where()
237
- : '';
238
- this.pushQuery(
239
- `CREATE INDEX ${indexName} ON ${this.tableName()} (${this.formatter.columnize(
240
- columns
241
- )})${predicateQuery}`
242
- );
243
- }
244
-
245
- /**
246
- * Create a primary key.
247
- *
248
- * @param {undefined | string | string[]} columns
249
- * @param {string | {constraintName: string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} constraintName
250
- */
251
- primary(columns, constraintName) {
252
- let deferrable;
253
- if (isObject(constraintName)) {
254
- ({ constraintName, deferrable } = constraintName);
255
- }
256
- if (deferrable && deferrable !== 'not deferrable') {
257
- this.client.logger.warn(
258
- `mssql: primary key constraint [${constraintName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
259
- );
260
- }
261
- constraintName = constraintName
262
- ? this.formatter.wrap(constraintName)
263
- : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
264
- if (!this.forCreate) {
265
- this.pushQuery(
266
- `ALTER TABLE ${this.tableName()} ADD CONSTRAINT ${constraintName} PRIMARY KEY (${this.formatter.columnize(
267
- columns
268
- )})`
269
- );
270
- } else {
271
- this.pushQuery(
272
- `CONSTRAINT ${constraintName} PRIMARY KEY (${this.formatter.columnize(
273
- columns
274
- )})`
275
- );
276
- }
277
- }
278
-
279
- /**
280
- * Create a unique index.
281
- *
282
- * @param {string | string[]} columns
283
- * @param {string | {indexName: undefined | string, deferrable?: 'not deferrable'|'deferred'|'immediate', useConstraint?: true|false }} indexName
284
- */
285
- unique(columns, indexName) {
286
- /** @type {string | undefined} */
287
- let deferrable;
288
- let useConstraint = false;
289
- if (isObject(indexName)) {
290
- ({ indexName, deferrable, useConstraint } = indexName);
291
- }
292
- if (deferrable && deferrable !== 'not deferrable') {
293
- this.client.logger.warn(
294
- `mssql: unique index [${indexName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
295
- );
296
- }
297
- indexName = indexName
298
- ? this.formatter.wrap(indexName)
299
- : this._indexCommand('unique', this.tableNameRaw, columns);
300
-
301
- if (!Array.isArray(columns)) {
302
- columns = [columns];
303
- }
304
-
305
- const whereAllTheColumnsAreNotNull = columns
306
- .map((column) => this.formatter.columnize(column) + ' IS NOT NULL')
307
- .join(' AND ');
308
-
309
- if (useConstraint) {
310
- // mssql supports unique indexes and unique constraints.
311
- // unique indexes cannot be used with foreign key relationships hence unique constraints are used instead.
312
- this.pushQuery(
313
- `ALTER TABLE ${this.tableName()} ADD CONSTRAINT ${indexName} UNIQUE (${this.formatter.columnize(
314
- columns
315
- )})`
316
- );
317
- } else {
318
- // make unique constraint that allows null https://stackoverflow.com/a/767702/360060
319
- // to be more or less compatible with other DBs (if any of the columns is NULL then "duplicates" are allowed)
320
- this.pushQuery(
321
- `CREATE UNIQUE INDEX ${indexName} ON ${this.tableName()} (${this.formatter.columnize(
322
- columns
323
- )}) WHERE ${whereAllTheColumnsAreNotNull}`
324
- );
325
- }
326
- }
327
-
328
- // Compile a drop index command.
329
- dropIndex(columns, indexName) {
330
- indexName = indexName
331
- ? this.formatter.wrap(indexName)
332
- : this._indexCommand('index', this.tableNameRaw, columns);
333
- this.pushQuery(`DROP INDEX ${indexName} ON ${this.tableName()}`);
334
- }
335
-
336
- // Compile a drop foreign key command.
337
- dropForeign(columns, indexName) {
338
- indexName = indexName
339
- ? this.formatter.wrap(indexName)
340
- : this._indexCommand('foreign', this.tableNameRaw, columns);
341
- this.pushQuery(
342
- `ALTER TABLE ${this.tableName()} DROP CONSTRAINT ${indexName}`
343
- );
344
- }
345
-
346
- // Compile a drop primary key command.
347
- dropPrimary(constraintName) {
348
- constraintName = constraintName
349
- ? this.formatter.wrap(constraintName)
350
- : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
351
- this.pushQuery(
352
- `ALTER TABLE ${this.tableName()} DROP CONSTRAINT ${constraintName}`
353
- );
354
- }
355
-
356
- // Compile a drop unique key command.
357
- dropUnique(column, indexName) {
358
- indexName = indexName
359
- ? this.formatter.wrap(indexName)
360
- : this._indexCommand('unique', this.tableNameRaw, column);
361
- this.pushQuery(`DROP INDEX ${indexName} ON ${this.tableName()}`);
362
- }
363
- }
364
-
365
- TableCompiler_MSSQL.prototype.createAlterTableMethods = ['foreign', 'primary'];
366
- TableCompiler_MSSQL.prototype.lowerCase = false;
367
-
368
- TableCompiler_MSSQL.prototype.addColumnsPrefix = 'ADD ';
369
- TableCompiler_MSSQL.prototype.dropColumnPrefix = 'DROP COLUMN ';
370
- TableCompiler_MSSQL.prototype.alterColumnPrefix = 'ALTER COLUMN ';
371
-
372
- module.exports = TableCompiler_MSSQL;
1
+ /* eslint max-len:0 */
2
+
3
+ // MSSQL Table Builder & Compiler
4
+ // -------
5
+ const TableCompiler = require('../../../schema/tablecompiler');
6
+ const helpers = require('../../../util/helpers');
7
+ const { isObject } = require('../../../util/is');
8
+
9
+ // Table Compiler
10
+ // ------
11
+
12
+ class TableCompiler_MSSQL extends TableCompiler {
13
+ constructor(client, tableBuilder) {
14
+ super(client, tableBuilder);
15
+ }
16
+
17
+ createQuery(columns, ifNot, like) {
18
+ let createStatement = ifNot
19
+ ? `if object_id('${this.tableName()}', 'U') is null `
20
+ : '';
21
+
22
+ if (like) {
23
+ // This query copy only columns and not all indexes and keys like other databases.
24
+ createStatement += `SELECT * INTO ${this.tableName()} FROM ${this.tableNameLike()} WHERE 0=1`;
25
+ } else {
26
+ createStatement +=
27
+ 'CREATE TABLE ' +
28
+ this.tableName() +
29
+ (this._formatting ? ' (\n ' : ' (') +
30
+ columns.sql.join(this._formatting ? ',\n ' : ', ') +
31
+ this._addChecks() +
32
+ ')';
33
+ }
34
+
35
+ this.pushQuery(createStatement);
36
+
37
+ if (this.single.comment) {
38
+ this.comment(this.single.comment);
39
+ }
40
+ if (like) {
41
+ this.addColumns(columns, this.addColumnsPrefix);
42
+ }
43
+ }
44
+
45
+ comment(/** @type {string} */ comment) {
46
+ if (!comment) {
47
+ return;
48
+ }
49
+
50
+ // XXX: This is a byte limit, not character, so we cannot definitively say they'll exceed the limit without server collation info.
51
+ // When I checked in SQL Server 2019, the ctext column in sys.syscomments is defined as a varbinary(8000), so it doesn't even have its own defined collation.
52
+ if (comment.length > 7500 / 2) {
53
+ this.client.logger.warn(
54
+ 'Your comment might be longer than the max comment length for MSSQL of 7,500 bytes.'
55
+ );
56
+ }
57
+
58
+ // See: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addextendedproperty-transact-sql?view=sql-server-ver15#f-adding-an-extended-property-to-a-table
59
+ const value = this.formatter.escapingStringDelimiters(comment);
60
+ const level0name = this.formatter.escapingStringDelimiters(
61
+ this.schemaNameRaw || 'dbo'
62
+ );
63
+ const level1name = this.formatter.escapingStringDelimiters(
64
+ this.tableNameRaw
65
+ );
66
+ const args = `N'MS_Description', N'${value}', N'Schema', N'${level0name}', N'Table', N'${level1name}'`;
67
+ const isAlreadyDefined = `EXISTS(SELECT * FROM sys.fn_listextendedproperty(N'MS_Description', N'Schema', N'${level0name}', N'Table', N'${level1name}', NULL, NULL))`;
68
+ this.pushQuery(
69
+ `IF ${isAlreadyDefined}\n EXEC sys.sp_updateextendedproperty ${args}\nELSE\n EXEC sys.sp_addextendedproperty ${args}`
70
+ );
71
+ }
72
+
73
+ // Compiles column add. Multiple columns need only one ADD clause (not one ADD per column) so core addColumns doesn't work. #1348
74
+ addColumns(columns, prefix) {
75
+ prefix = prefix || this.addColumnsPrefix;
76
+
77
+ if (columns.sql.length > 0) {
78
+ this.pushQuery({
79
+ sql:
80
+ (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
81
+ this.tableName() +
82
+ ' ' +
83
+ prefix +
84
+ columns.sql.join(', '),
85
+ bindings: columns.bindings,
86
+ });
87
+ }
88
+ }
89
+
90
+ alterColumns(columns, colBuilder) {
91
+ for (let i = 0, l = colBuilder.length; i < l; i++) {
92
+ const builder = colBuilder[i];
93
+ if (builder.modified.defaultTo) {
94
+ const schema = this.schemaNameRaw || 'dbo';
95
+ const baseQuery = `
96
+ DECLARE @constraint varchar(100) = (SELECT default_constraints.name
97
+ FROM sys.all_columns
98
+ INNER JOIN sys.tables
99
+ ON all_columns.object_id = tables.object_id
100
+ INNER JOIN sys.schemas
101
+ ON tables.schema_id = schemas.schema_id
102
+ INNER JOIN sys.default_constraints
103
+ ON all_columns.default_object_id = default_constraints.object_id
104
+ WHERE schemas.name = '${schema}'
105
+ AND tables.name = '${
106
+ this.tableNameRaw
107
+ }'
108
+ AND all_columns.name = '${builder.getColumnName()}')
109
+
110
+ IF @constraint IS NOT NULL EXEC('ALTER TABLE ${
111
+ this.tableNameRaw
112
+ } DROP CONSTRAINT ' + @constraint)`;
113
+ this.pushQuery(baseQuery);
114
+ }
115
+ }
116
+ // in SQL server only one column can be altered at a time
117
+ columns.sql.forEach((sql) => {
118
+ this.pushQuery({
119
+ sql:
120
+ (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
121
+ this.tableName() +
122
+ ' ' +
123
+ (this.lowerCase
124
+ ? this.alterColumnPrefix.toLowerCase()
125
+ : this.alterColumnPrefix) +
126
+ sql,
127
+ bindings: columns.bindings,
128
+ });
129
+ });
130
+ }
131
+
132
+ // Compiles column drop. Multiple columns need only one DROP clause (not one DROP per column) so core dropColumn doesn't work. #1348
133
+ dropColumn() {
134
+ const _this2 = this;
135
+ const columns = helpers.normalizeArr.apply(null, arguments);
136
+ const columnsArray = Array.isArray(columns) ? columns : [columns];
137
+ const drops = columnsArray.map((column) => _this2.formatter.wrap(column));
138
+ const schema = this.schemaNameRaw || 'dbo';
139
+
140
+ for (const column of columns) {
141
+ const baseQuery = `
142
+ DECLARE @constraint varchar(100) = (SELECT default_constraints.name
143
+ FROM sys.all_columns
144
+ INNER JOIN sys.tables
145
+ ON all_columns.object_id = tables.object_id
146
+ INNER JOIN sys.schemas
147
+ ON tables.schema_id = schemas.schema_id
148
+ INNER JOIN sys.default_constraints
149
+ ON all_columns.default_object_id = default_constraints.object_id
150
+ WHERE schemas.name = '${schema}'
151
+ AND tables.name = '${this.tableNameRaw}'
152
+ AND all_columns.name = '${column}')
153
+
154
+ IF @constraint IS NOT NULL EXEC('ALTER TABLE ${this.tableNameRaw} DROP CONSTRAINT ' + @constraint)`;
155
+ this.pushQuery(baseQuery);
156
+ }
157
+ this.pushQuery(
158
+ (this.lowerCase ? 'alter table ' : 'ALTER TABLE ') +
159
+ this.tableName() +
160
+ ' ' +
161
+ this.dropColumnPrefix +
162
+ drops.join(', ')
163
+ );
164
+ }
165
+
166
+ changeType() {}
167
+
168
+ // Renames a column on the table.
169
+ renameColumn(from, to) {
170
+ this.pushQuery(
171
+ `exec sp_rename ${this.client.parameter(
172
+ this.tableName() + '.' + from,
173
+ this.tableBuilder,
174
+ this.bindingsHolder
175
+ )}, ${this.client.parameter(
176
+ to,
177
+ this.tableBuilder,
178
+ this.bindingsHolder
179
+ )}, 'COLUMN'`
180
+ );
181
+ }
182
+
183
+ dropFKRefs(runner, refs) {
184
+ const formatter = this.client.formatter(this.tableBuilder);
185
+ return Promise.all(
186
+ refs.map(function (ref) {
187
+ const constraintName = formatter.wrap(ref.CONSTRAINT_NAME);
188
+ const tableName = formatter.wrap(ref.TABLE_NAME);
189
+ return runner.query({
190
+ sql: `ALTER TABLE ${tableName} DROP CONSTRAINT ${constraintName}`,
191
+ });
192
+ })
193
+ );
194
+ }
195
+
196
+ createFKRefs(runner, refs) {
197
+ const formatter = this.client.formatter(this.tableBuilder);
198
+
199
+ return Promise.all(
200
+ refs.map(function (ref) {
201
+ const tableName = formatter.wrap(ref.TABLE_NAME);
202
+ const keyName = formatter.wrap(ref.CONSTRAINT_NAME);
203
+ const column = formatter.columnize(ref.COLUMN_NAME);
204
+ const references = formatter.columnize(ref.REFERENCED_COLUMN_NAME);
205
+ const inTable = formatter.wrap(ref.REFERENCED_TABLE_NAME);
206
+ const onUpdate = ` ON UPDATE ${ref.UPDATE_RULE}`;
207
+ const onDelete = ` ON DELETE ${ref.DELETE_RULE}`;
208
+
209
+ return runner.query({
210
+ sql:
211
+ `ALTER TABLE ${tableName} ADD CONSTRAINT ${keyName}` +
212
+ ' FOREIGN KEY (' +
213
+ column +
214
+ ') REFERENCES ' +
215
+ inTable +
216
+ ' (' +
217
+ references +
218
+ ')' +
219
+ onUpdate +
220
+ onDelete,
221
+ });
222
+ })
223
+ );
224
+ }
225
+
226
+ index(columns, indexName, options) {
227
+ indexName = indexName
228
+ ? this.formatter.wrap(indexName)
229
+ : this._indexCommand('index', this.tableNameRaw, columns);
230
+
231
+ let predicate;
232
+ if (isObject(options)) {
233
+ ({ predicate } = options);
234
+ }
235
+ const predicateQuery = predicate
236
+ ? ' ' + this.client.queryCompiler(predicate).where()
237
+ : '';
238
+ this.pushQuery(
239
+ `CREATE INDEX ${indexName} ON ${this.tableName()} (${this.formatter.columnize(
240
+ columns
241
+ )})${predicateQuery}`
242
+ );
243
+ }
244
+
245
+ /**
246
+ * Create a primary key.
247
+ *
248
+ * @param {undefined | string | string[]} columns
249
+ * @param {string | {constraintName: string, deferrable?: 'not deferrable'|'deferred'|'immediate' }} constraintName
250
+ */
251
+ primary(columns, constraintName) {
252
+ let deferrable;
253
+ if (isObject(constraintName)) {
254
+ ({ constraintName, deferrable } = constraintName);
255
+ }
256
+ if (deferrable && deferrable !== 'not deferrable') {
257
+ this.client.logger.warn(
258
+ `mssql: primary key constraint [${constraintName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
259
+ );
260
+ }
261
+ constraintName = constraintName
262
+ ? this.formatter.wrap(constraintName)
263
+ : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
264
+ if (!this.forCreate) {
265
+ this.pushQuery(
266
+ `ALTER TABLE ${this.tableName()} ADD CONSTRAINT ${constraintName} PRIMARY KEY (${this.formatter.columnize(
267
+ columns
268
+ )})`
269
+ );
270
+ } else {
271
+ this.pushQuery(
272
+ `CONSTRAINT ${constraintName} PRIMARY KEY (${this.formatter.columnize(
273
+ columns
274
+ )})`
275
+ );
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Create a unique index.
281
+ *
282
+ * @param {string | string[]} columns
283
+ * @param {string | {indexName: undefined | string, deferrable?: 'not deferrable'|'deferred'|'immediate', useConstraint?: true|false, predicate?: QueryBuilder }} indexName
284
+ */
285
+ unique(columns, indexName) {
286
+ /** @type {string | undefined} */
287
+ let deferrable;
288
+ let useConstraint = false;
289
+ let predicate;
290
+ if (isObject(indexName)) {
291
+ ({ indexName, deferrable, useConstraint, predicate } = indexName);
292
+ }
293
+ if (deferrable && deferrable !== 'not deferrable') {
294
+ this.client.logger.warn(
295
+ `mssql: unique index [${indexName}] will not be deferrable ${deferrable} because mssql does not support deferred constraints.`
296
+ );
297
+ }
298
+ if (useConstraint && predicate) {
299
+ throw new Error('mssql cannot create constraint with predicate');
300
+ }
301
+ indexName = indexName
302
+ ? this.formatter.wrap(indexName)
303
+ : this._indexCommand('unique', this.tableNameRaw, columns);
304
+
305
+ if (!Array.isArray(columns)) {
306
+ columns = [columns];
307
+ }
308
+
309
+ if (useConstraint) {
310
+ // mssql supports unique indexes and unique constraints.
311
+ // unique indexes cannot be used with foreign key relationships hence unique constraints are used instead.
312
+ this.pushQuery(
313
+ `ALTER TABLE ${this.tableName()} ADD CONSTRAINT ${indexName} UNIQUE (${this.formatter.columnize(
314
+ columns
315
+ )})`
316
+ );
317
+ } else {
318
+ // default to making unique index that allows null https://stackoverflow.com/a/767702/360060
319
+ // to be more or less compatible with other DBs (if any of the columns is NULL then "duplicates" are allowed)
320
+ const predicateQuery = predicate
321
+ ? ' ' + this.client.queryCompiler(predicate).where()
322
+ : ' WHERE ' +
323
+ columns
324
+ .map((column) => this.formatter.columnize(column) + ' IS NOT NULL')
325
+ .join(' AND ');
326
+ this.pushQuery(
327
+ `CREATE UNIQUE INDEX ${indexName} ON ${this.tableName()} (${this.formatter.columnize(
328
+ columns
329
+ )})${predicateQuery}`
330
+ );
331
+ }
332
+ }
333
+
334
+ // Compile a drop index command.
335
+ dropIndex(columns, indexName) {
336
+ indexName = indexName
337
+ ? this.formatter.wrap(indexName)
338
+ : this._indexCommand('index', this.tableNameRaw, columns);
339
+ this.pushQuery(`DROP INDEX ${indexName} ON ${this.tableName()}`);
340
+ }
341
+
342
+ // Compile a drop foreign key command.
343
+ dropForeign(columns, indexName) {
344
+ indexName = indexName
345
+ ? this.formatter.wrap(indexName)
346
+ : this._indexCommand('foreign', this.tableNameRaw, columns);
347
+ this.pushQuery(
348
+ `ALTER TABLE ${this.tableName()} DROP CONSTRAINT ${indexName}`
349
+ );
350
+ }
351
+
352
+ // Compile a drop primary key command.
353
+ dropPrimary(constraintName) {
354
+ constraintName = constraintName
355
+ ? this.formatter.wrap(constraintName)
356
+ : this.formatter.wrap(`${this.tableNameRaw}_pkey`);
357
+ this.pushQuery(
358
+ `ALTER TABLE ${this.tableName()} DROP CONSTRAINT ${constraintName}`
359
+ );
360
+ }
361
+
362
+ // Compile a drop unique key command.
363
+ dropUnique(column, indexName) {
364
+ indexName = indexName
365
+ ? this.formatter.wrap(indexName)
366
+ : this._indexCommand('unique', this.tableNameRaw, column);
367
+ this.pushQuery(`DROP INDEX ${indexName} ON ${this.tableName()}`);
368
+ }
369
+ }
370
+
371
+ TableCompiler_MSSQL.prototype.createAlterTableMethods = ['foreign', 'primary'];
372
+ TableCompiler_MSSQL.prototype.lowerCase = false;
373
+
374
+ TableCompiler_MSSQL.prototype.addColumnsPrefix = 'ADD ';
375
+ TableCompiler_MSSQL.prototype.dropColumnPrefix = 'DROP COLUMN ';
376
+ TableCompiler_MSSQL.prototype.alterColumnPrefix = 'ALTER COLUMN ';
377
+
378
+ module.exports = TableCompiler_MSSQL;