knex 3.1.0 → 3.2.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.
- package/CHANGELOG.md +2441 -2380
- package/CONTRIBUTING.md +190 -194
- package/LICENSE +22 -22
- package/README.md +156 -149
- package/UPGRADING.md +245 -245
- package/bin/cli.js +516 -475
- package/bin/knexfile-runtime-error.js +27 -0
- package/bin/utils/cli-config-utils.js +217 -212
- package/bin/utils/constants.js +7 -7
- package/bin/utils/migrationsLister.js +37 -37
- package/knex.js +23 -23
- package/knex.mjs +11 -11
- package/lib/builder-interface-augmenter.js +120 -120
- package/lib/client.js +585 -495
- package/lib/constants.js +61 -61
- package/lib/dialects/better-sqlite3/index.js +101 -77
- package/lib/dialects/cockroachdb/crdb-columncompiler.js +14 -14
- package/lib/dialects/cockroachdb/crdb-querybuilder.js +11 -11
- package/lib/dialects/cockroachdb/crdb-querycompiler.js +122 -122
- package/lib/dialects/cockroachdb/crdb-tablecompiler.js +46 -37
- package/lib/dialects/cockroachdb/crdb-viewcompiler.js +15 -15
- package/lib/dialects/cockroachdb/index.js +86 -86
- package/lib/dialects/index.js +34 -34
- package/lib/dialects/mssql/index.js +498 -500
- package/lib/dialects/mssql/mssql-formatter.js +34 -34
- package/lib/dialects/mssql/query/mssql-querycompiler.js +601 -601
- package/lib/dialects/mssql/schema/mssql-columncompiler.js +185 -185
- package/lib/dialects/mssql/schema/mssql-compiler.js +91 -91
- package/lib/dialects/mssql/schema/mssql-tablecompiler.js +393 -378
- package/lib/dialects/mssql/schema/mssql-viewcompiler.js +55 -55
- package/lib/dialects/mssql/transaction.js +176 -176
- package/lib/dialects/mysql/index.js +317 -206
- package/lib/dialects/mysql/query/mysql-querybuilder.js +14 -14
- package/lib/dialects/mysql/query/mysql-querycompiler.js +292 -292
- package/lib/dialects/mysql/schema/mysql-columncompiler.js +193 -193
- package/lib/dialects/mysql/schema/mysql-compiler.js +60 -60
- package/lib/dialects/mysql/schema/mysql-tablecompiler.js +426 -405
- package/lib/dialects/mysql/schema/mysql-viewbuilder.js +21 -21
- package/lib/dialects/mysql/schema/mysql-viewcompiler.js +15 -15
- package/lib/dialects/mysql/transaction.js +46 -46
- package/lib/dialects/mysql2/index.js +53 -53
- package/lib/dialects/mysql2/transaction.js +44 -44
- package/lib/dialects/oracle/DEAD_CODE.md +5 -5
- package/lib/dialects/oracle/index.js +92 -92
- package/lib/dialects/oracle/query/oracle-querycompiler.js +343 -343
- package/lib/dialects/oracle/schema/internal/incrementUtils.js +22 -22
- package/lib/dialects/oracle/schema/internal/trigger.js +155 -155
- package/lib/dialects/oracle/schema/oracle-columnbuilder.js +17 -17
- package/lib/dialects/oracle/schema/oracle-columncompiler.js +126 -126
- package/lib/dialects/oracle/schema/oracle-compiler.js +124 -124
- package/lib/dialects/oracle/schema/oracle-tablecompiler.js +210 -197
- package/lib/dialects/oracle/utils.js +107 -106
- package/lib/dialects/oracledb/index.js +381 -381
- package/lib/dialects/oracledb/query/oracledb-querycompiler.js +481 -481
- package/lib/dialects/oracledb/schema/oracledb-columncompiler.js +61 -61
- package/lib/dialects/oracledb/schema/oracledb-tablecompiler.js +19 -19
- package/lib/dialects/oracledb/schema/oracledb-viewbuilder.js +13 -13
- package/lib/dialects/oracledb/schema/oracledb-viewcompiler.js +19 -19
- package/lib/dialects/oracledb/transaction.js +98 -98
- package/lib/dialects/oracledb/utils.js +208 -208
- package/lib/dialects/pgnative/index.js +60 -60
- package/lib/dialects/postgres/execution/pg-transaction.js +19 -19
- package/lib/dialects/postgres/index.js +373 -361
- package/lib/dialects/postgres/query/pg-querybuilder.js +43 -43
- package/lib/dialects/postgres/query/pg-querycompiler.js +400 -400
- package/lib/dialects/postgres/schema/pg-columncompiler.js +162 -156
- package/lib/dialects/postgres/schema/pg-compiler.js +138 -138
- package/lib/dialects/postgres/schema/pg-tablecompiler.js +331 -304
- package/lib/dialects/postgres/schema/pg-viewbuilder.js +21 -21
- package/lib/dialects/postgres/schema/pg-viewcompiler.js +35 -35
- package/lib/dialects/redshift/index.js +86 -86
- package/lib/dialects/redshift/query/redshift-querycompiler.js +163 -163
- package/lib/dialects/redshift/schema/redshift-columnbuilder.js +22 -22
- package/lib/dialects/redshift/schema/redshift-columncompiler.js +67 -67
- package/lib/dialects/redshift/schema/redshift-compiler.js +14 -14
- package/lib/dialects/redshift/schema/redshift-tablecompiler.js +134 -122
- package/lib/dialects/redshift/schema/redshift-viewcompiler.js +11 -11
- package/lib/dialects/redshift/transaction.js +32 -32
- package/lib/dialects/sqlite3/execution/sqlite-transaction.js +172 -25
- package/lib/dialects/sqlite3/index.js +263 -250
- package/lib/dialects/sqlite3/query/sqlite-querybuilder.js +33 -33
- package/lib/dialects/sqlite3/query/sqlite-querycompiler.js +341 -334
- package/lib/dialects/sqlite3/schema/ddl.js +380 -400
- package/lib/dialects/sqlite3/schema/internal/compiler.js +327 -327
- package/lib/dialects/sqlite3/schema/internal/parser-combinator.js +161 -161
- package/lib/dialects/sqlite3/schema/internal/parser.js +638 -638
- package/lib/dialects/sqlite3/schema/internal/sqlite-ddl-operations.js +41 -41
- package/lib/dialects/sqlite3/schema/internal/tokenizer.js +38 -38
- package/lib/dialects/sqlite3/schema/internal/utils.js +12 -12
- package/lib/dialects/sqlite3/schema/sqlite-columncompiler.js +50 -50
- package/lib/dialects/sqlite3/schema/sqlite-compiler.js +80 -80
- package/lib/dialects/sqlite3/schema/sqlite-tablecompiler.js +364 -347
- package/lib/dialects/sqlite3/schema/sqlite-viewcompiler.js +40 -40
- package/lib/execution/batch-insert.js +51 -51
- package/lib/execution/internal/delay.js +6 -6
- package/lib/execution/internal/ensure-connection-callback.js +41 -41
- package/lib/execution/internal/query-executioner.js +62 -62
- package/lib/execution/runner.js +325 -325
- package/lib/execution/transaction.js +417 -413
- package/lib/formatter/formatterUtils.js +42 -42
- package/lib/formatter/rawFormatter.js +84 -84
- package/lib/formatter/wrappingFormatter.js +253 -250
- package/lib/formatter.js +25 -25
- package/lib/index.js +3 -3
- package/lib/knex-builder/FunctionHelper.js +80 -80
- package/lib/knex-builder/Knex.js +59 -59
- package/lib/knex-builder/internal/config-resolver.js +57 -57
- package/lib/knex-builder/internal/parse-connection.js +87 -87
- package/lib/knex-builder/make-knex.js +345 -345
- package/lib/logger.js +76 -76
- package/lib/migrations/common/MigrationsLoader.js +36 -36
- package/lib/migrations/migrate/MigrationGenerator.js +84 -84
- package/lib/migrations/migrate/Migrator.js +632 -599
- package/lib/migrations/migrate/migrate-stub.js +17 -17
- package/lib/migrations/migrate/migration-list-resolver.js +33 -33
- package/lib/migrations/migrate/migrator-configuration-merger.js +58 -58
- package/lib/migrations/migrate/sources/fs-migrations.js +74 -74
- package/lib/migrations/migrate/stub/cjs.stub +15 -15
- package/lib/migrations/migrate/stub/coffee.stub +13 -13
- package/lib/migrations/migrate/stub/eg.stub +14 -14
- package/lib/migrations/migrate/stub/js-schema.stub +22 -22
- package/lib/migrations/migrate/stub/js.stub +22 -22
- package/lib/migrations/migrate/stub/knexfile-coffee.stub +34 -34
- package/lib/migrations/migrate/stub/knexfile-eg.stub +43 -43
- package/lib/migrations/migrate/stub/knexfile-js.stub +47 -47
- package/lib/migrations/migrate/stub/knexfile-ls.stub +35 -35
- package/lib/migrations/migrate/stub/knexfile-ts.stub +47 -47
- package/lib/migrations/migrate/stub/ls.stub +14 -14
- package/lib/migrations/migrate/stub/mjs.stub +23 -23
- package/lib/migrations/migrate/stub/ts-schema.stub +21 -21
- package/lib/migrations/migrate/stub/ts.stub +21 -21
- package/lib/migrations/migrate/table-creator.js +77 -77
- package/lib/migrations/migrate/table-resolver.js +27 -27
- package/lib/migrations/seed/Seeder.js +137 -137
- package/lib/migrations/seed/seed-stub.js +13 -13
- package/lib/migrations/seed/seeder-configuration-merger.js +60 -60
- package/lib/migrations/seed/sources/fs-seeds.js +65 -65
- package/lib/migrations/seed/stub/coffee.stub +9 -9
- package/lib/migrations/seed/stub/eg.stub +11 -11
- package/lib/migrations/seed/stub/js.stub +13 -13
- package/lib/migrations/seed/stub/ls.stub +11 -11
- package/lib/migrations/seed/stub/mjs.stub +12 -12
- package/lib/migrations/seed/stub/ts.stub +13 -13
- package/lib/migrations/util/fs.js +86 -86
- package/lib/migrations/util/import-file.js +12 -12
- package/lib/migrations/util/is-module-type.js +9 -9
- package/lib/migrations/util/template.js +52 -52
- package/lib/migrations/util/timestamp.js +14 -14
- package/lib/query/analytic.js +52 -52
- package/lib/query/constants.js +15 -15
- package/lib/query/joinclause.js +270 -270
- package/lib/query/method-constants.js +136 -136
- package/lib/query/querybuilder.js +1793 -1793
- package/lib/query/querycompiler.js +1634 -1591
- package/lib/raw.js +139 -139
- package/lib/ref.js +39 -39
- package/lib/schema/builder.js +115 -115
- package/lib/schema/columnbuilder.js +146 -146
- package/lib/schema/columncompiler.js +307 -307
- package/lib/schema/compiler.js +187 -187
- package/lib/schema/internal/helpers.js +55 -55
- package/lib/schema/tablebuilder.js +379 -376
- package/lib/schema/tablecompiler.js +450 -439
- package/lib/schema/viewbuilder.js +92 -92
- package/lib/schema/viewcompiler.js +138 -138
- package/lib/util/finally-mixin.js +13 -13
- package/lib/util/helpers.js +95 -95
- package/lib/util/is.js +32 -32
- package/lib/util/nanoid.js +40 -40
- package/lib/util/noop.js +1 -1
- package/lib/util/save-async-stack.js +14 -14
- package/lib/util/security.js +32 -26
- package/lib/util/string.js +190 -190
- package/lib/util/timeout.js +29 -29
- package/package.json +291 -267
- package/scripts/act-testing/act.sh +19 -0
- package/scripts/act-testing/merged-no-label.json +11 -0
- package/scripts/act-testing/merged-patch-labeled.json +12 -0
- package/scripts/act-testing/merged-skip-labeled.json +12 -0
- package/scripts/act-testing/not-merged-patch-labeled.json +12 -0
- package/scripts/build-for-release.sh +122 -0
- package/scripts/build.js +125 -125
- package/scripts/clean.js +31 -31
- package/scripts/docker-compose.yml +150 -152
- package/scripts/format-changelog.js +55 -0
- package/scripts/next-release-howto.md +24 -24
- package/scripts/oracledb-install-driver-libs.sh +82 -82
- package/scripts/release.sh +36 -36
- package/scripts/runkit-example.js +35 -35
- package/scripts/stress-test/README.txt +18 -18
- package/scripts/stress-test/docker-compose.yml +55 -57
- package/scripts/stress-test/knex-stress-test.js +212 -212
- package/scripts/stress-test/mysql2-random-hanging-every-now-and-then.js +149 -149
- package/scripts/stress-test/mysql2-sudden-exit-without-error.js +101 -101
- package/scripts/stress-test/reconnect-test-mysql-based-drivers.js +188 -188
- package/types/index.d.ts +3321 -3275
- package/types/result.d.ts +27 -27
- package/types/tables.d.ts +4 -4
- package/scripts/update_gitignore_for_tsc_output.js +0 -90
|
@@ -1,378 +1,393 @@
|
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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, 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
|
+
dropForeignIfExists() {
|
|
353
|
+
throw new Error('.dropForeignIfExists is not supported for mssql.');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Compile a drop primary key command.
|
|
357
|
+
dropPrimary(constraintName) {
|
|
358
|
+
constraintName = constraintName
|
|
359
|
+
? this.formatter.wrap(constraintName)
|
|
360
|
+
: this.formatter.wrap(`${this.tableNameRaw}_pkey`);
|
|
361
|
+
this.pushQuery(
|
|
362
|
+
`ALTER TABLE ${this.tableName()} DROP CONSTRAINT ${constraintName}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
dropPrimaryIfExists() {
|
|
367
|
+
throw new Error('.dropPrimaryIfExists is not supported for mssql.');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Compile a drop unique key command.
|
|
371
|
+
dropUnique(column, indexName) {
|
|
372
|
+
indexName = indexName
|
|
373
|
+
? this.formatter.wrap(indexName)
|
|
374
|
+
: this._indexCommand('unique', this.tableNameRaw, column);
|
|
375
|
+
this.pushQuery(`DROP INDEX ${indexName} ON ${this.tableName()}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
dropUniqueIfExists(column, indexName) {
|
|
379
|
+
indexName = indexName
|
|
380
|
+
? this.formatter.wrap(indexName)
|
|
381
|
+
: this._indexCommand('unique', this.tableNameRaw, column);
|
|
382
|
+
this.pushQuery(`DROP INDEX IF EXISTS ${indexName} ON ${this.tableName()}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
TableCompiler_MSSQL.prototype.createAlterTableMethods = ['foreign', 'primary'];
|
|
387
|
+
TableCompiler_MSSQL.prototype.lowerCase = false;
|
|
388
|
+
|
|
389
|
+
TableCompiler_MSSQL.prototype.addColumnsPrefix = 'ADD ';
|
|
390
|
+
TableCompiler_MSSQL.prototype.dropColumnPrefix = 'DROP COLUMN ';
|
|
391
|
+
TableCompiler_MSSQL.prototype.alterColumnPrefix = 'ALTER COLUMN ';
|
|
392
|
+
|
|
393
|
+
module.exports = TableCompiler_MSSQL;
|