prettier-plugin-tsql 0.5.0 → 0.6.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.
- package/README.md +2 -2
- package/bin/dotnet/PrettierSql.Core.dll +0 -0
- package/bin/dotnet/SqlScriptDom.deps.json +15 -1
- package/bin/dotnet/SqlScriptDom.dll +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +2 -24
- package/dist/parser/index.js.map +1 -1
- package/dist/printer/admin.d.ts +2 -2
- package/dist/printer/admin.d.ts.map +1 -1
- package/dist/printer/admin.js +5 -13
- package/dist/printer/admin.js.map +1 -1
- package/dist/printer/ddl.d.ts +2 -2
- package/dist/printer/ddl.d.ts.map +1 -1
- package/dist/printer/ddl.js +222 -45
- package/dist/printer/ddl.js.map +1 -1
- package/dist/printer/expressions.d.ts +2 -2
- package/dist/printer/expressions.d.ts.map +1 -1
- package/dist/printer/expressions.js +90 -13
- package/dist/printer/expressions.js.map +1 -1
- package/dist/printer/helpers.d.ts +3 -22
- package/dist/printer/helpers.d.ts.map +1 -1
- package/dist/printer/helpers.js +2 -33
- package/dist/printer/helpers.js.map +1 -1
- package/dist/printer/index.d.ts +1 -1
- package/dist/printer/index.d.ts.map +1 -1
- package/dist/printer/procedural.d.ts +3 -3
- package/dist/printer/procedural.d.ts.map +1 -1
- package/dist/printer/procedural.js +49 -12
- package/dist/printer/procedural.js.map +1 -1
- package/dist/printer/security.d.ts +2 -2
- package/dist/printer/security.d.ts.map +1 -1
- package/dist/printer/security.js +18 -16
- package/dist/printer/security.js.map +1 -1
- package/dist/printer/statements.d.ts +2 -2
- package/dist/printer/statements.d.ts.map +1 -1
- package/dist/printer/statements.js +20 -12
- package/dist/printer/statements.js.map +1 -1
- package/package.json +10 -15
- package/dist/options.d.ts +0 -3
- package/dist/options.d.ts.map +0 -1
- package/dist/options.js +0 -35
- package/dist/options.js.map +0 -1
- package/dist/parser/types.d.ts +0 -21
- package/dist/parser/types.d.ts.map +0 -1
- package/dist/parser/types.js +0 -2
- package/dist/parser/types.js.map +0 -1
- package/dist/printer/utils.d.ts +0 -48
- package/dist/printer/utils.d.ts.map +0 -1
- package/dist/printer/utils.js +0 -83
- package/dist/printer/utils.js.map +0 -1
package/dist/printer/ddl.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { keyword, hardline, join, indent, group, softline, line, ifExistsDoc, commentsBlock, parenList } from '
|
|
1
|
+
import { keyword, hardline, join, indent, group, softline, line, ifExistsDoc, commentsBlock, parenList, } from '@prettier-sql/core/printer/utils';
|
|
2
2
|
import { prop, propArr, propStr, propBool, schemaObjectName } from './helpers.js';
|
|
3
3
|
// printNode / printBool / qexpr / printStatementWithComments are imported from statements.ts
|
|
4
4
|
// — circular but safe in ESM (all imports are function references, never accessed during init)
|
|
@@ -33,22 +33,67 @@ function withOptionsClause(options, opts) {
|
|
|
33
33
|
// ---------------------------------------------------------------------------
|
|
34
34
|
// CREATE TABLE
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
|
+
/** Inline INDEX definition within CREATE TABLE body. */
|
|
37
|
+
function printInlineIndex(node, opts) {
|
|
38
|
+
const indexName = propStr(node, 'indexName') ?? '';
|
|
39
|
+
const isUnique = node.props?.['unique'];
|
|
40
|
+
const kind = propStr(node, 'kind'); // 'clustered', 'nonclustered', etc.
|
|
41
|
+
const columns = propArr(node, 'columns');
|
|
42
|
+
const includeColumns = node.props?.['includeColumns'];
|
|
43
|
+
const filterPredicate = propStr(node, 'filterPredicate');
|
|
44
|
+
const indexOptions = node.props?.['indexOptions'];
|
|
45
|
+
const uniqueKw = isUnique ? [keyword('UNIQUE', opts), ' '] : '';
|
|
46
|
+
const kindKw = kind ? [keyword(kind.toUpperCase(), opts), ' '] : '';
|
|
47
|
+
const colDocs = columns.map((c) => {
|
|
48
|
+
const colName = propStr(c, 'name') ?? '';
|
|
49
|
+
const sort = propStr(c, 'sortOrder') ?? 'Ascending';
|
|
50
|
+
return sort === 'Descending' ? [colName, ' ', keyword('DESC', opts)] : [colName, ' ', keyword('ASC', opts)];
|
|
51
|
+
});
|
|
52
|
+
const includePart = includeColumns?.length
|
|
53
|
+
? [' ', keyword('INCLUDE', opts), ' ', parenList(includeColumns)]
|
|
54
|
+
: '';
|
|
55
|
+
const filterPart = filterPredicate ? [' ', keyword('WHERE', opts), ' ', filterPredicate] : '';
|
|
56
|
+
const withPart = indexOptions?.length ? [' ', keyword('WITH', opts), ' (', join(', ', indexOptions), ')'] : '';
|
|
57
|
+
return [
|
|
58
|
+
keyword('INDEX', opts),
|
|
59
|
+
' ',
|
|
60
|
+
indexName,
|
|
61
|
+
' ',
|
|
62
|
+
uniqueKw,
|
|
63
|
+
kindKw,
|
|
64
|
+
parenList(colDocs),
|
|
65
|
+
includePart,
|
|
66
|
+
filterPart,
|
|
67
|
+
withPart,
|
|
68
|
+
];
|
|
69
|
+
}
|
|
36
70
|
export function printCreateTable(node, opts) {
|
|
37
71
|
const columns = propArr(node, 'columns');
|
|
38
72
|
const constraints = propArr(node, 'constraints');
|
|
39
73
|
const options = node.props?.['options'];
|
|
74
|
+
const systemTimePeriod = node.props?.['systemTimePeriod'];
|
|
75
|
+
const indexes = propArr(node, 'indexes');
|
|
40
76
|
const allDefs = [
|
|
41
77
|
...columns.map((col) => printColumnDef(col, opts)),
|
|
42
78
|
...constraints.map((c) => printConstraintDef(c, opts)),
|
|
79
|
+
...indexes.map((idx) => printInlineIndex(idx, opts)),
|
|
43
80
|
];
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
keyword('
|
|
48
|
-
' ',
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
81
|
+
// PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo) — always last in the table body
|
|
82
|
+
if (systemTimePeriod) {
|
|
83
|
+
allDefs.push([
|
|
84
|
+
keyword('PERIOD FOR SYSTEM_TIME', opts),
|
|
85
|
+
' (',
|
|
86
|
+
systemTimePeriod.startColumn,
|
|
87
|
+
', ',
|
|
88
|
+
systemTimePeriod.endColumn,
|
|
89
|
+
')',
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
const withPart = options && options.length > 0 ? [hardline, keyword('WITH', opts), ' ', parenList(options)] : '';
|
|
93
|
+
const onFileGroup = propStr(node, 'onFileGroup');
|
|
94
|
+
const textimageOn = propStr(node, 'textimageOn');
|
|
95
|
+
const onPart = onFileGroup ? [hardline, keyword('ON', opts), ' ', onFileGroup] : '';
|
|
96
|
+
const textimagePart = textimageOn ? [hardline, keyword('TEXTIMAGE_ON', opts), ' ', textimageOn] : '';
|
|
52
97
|
return group([
|
|
53
98
|
keyword('CREATE TABLE', opts),
|
|
54
99
|
' ',
|
|
@@ -57,6 +102,8 @@ export function printCreateTable(node, opts) {
|
|
|
57
102
|
indent([hardline, join([',', hardline], allDefs)]),
|
|
58
103
|
hardline,
|
|
59
104
|
')',
|
|
105
|
+
onPart,
|
|
106
|
+
textimagePart,
|
|
60
107
|
withPart,
|
|
61
108
|
';',
|
|
62
109
|
]);
|
|
@@ -84,18 +131,94 @@ export function printColumnDef(node, opts) {
|
|
|
84
131
|
const identitySeed = propStr(node, 'identitySeed');
|
|
85
132
|
const identityIncrement = propStr(node, 'identityIncrement');
|
|
86
133
|
const defaultValue = prop(node, 'defaultValue');
|
|
134
|
+
const checkConstraint = prop(node, 'checkConstraint');
|
|
135
|
+
const collation = propStr(node, 'collation');
|
|
87
136
|
const typeStr = Array.isArray(params) && params.length > 0
|
|
88
137
|
? [keyword(dataType, opts), `(${params.join(', ')})`]
|
|
89
138
|
: keyword(dataType, opts);
|
|
90
139
|
const parts = [name, ' ', typeStr];
|
|
140
|
+
// COLLATE clause comes right after the data type
|
|
141
|
+
if (collation)
|
|
142
|
+
parts.push(' ', keyword('COLLATE', opts), ' ', collation);
|
|
91
143
|
if (isIdentity) {
|
|
92
144
|
const seed = identitySeed ?? '1';
|
|
93
145
|
const inc = identityIncrement ?? '1';
|
|
94
146
|
parts.push(' ', keyword('IDENTITY', opts), `(${seed}, ${inc})`);
|
|
95
147
|
}
|
|
148
|
+
if (node.props?.['isRowGuidCol'])
|
|
149
|
+
parts.push(' ', keyword('ROWGUIDCOL', opts));
|
|
150
|
+
// SPARSE / FILESTREAM / COLUMN_SET
|
|
151
|
+
if (node.props?.['isSparse'])
|
|
152
|
+
parts.push(' ', keyword('SPARSE', opts));
|
|
153
|
+
if (node.props?.['isFileStream'])
|
|
154
|
+
parts.push(' ', keyword('FILESTREAM', opts));
|
|
155
|
+
if (node.props?.['isColumnSet'])
|
|
156
|
+
parts.push(' ', keyword('COLUMN_SET FOR ALL_SPARSE_COLUMNS', opts));
|
|
157
|
+
// Temporal table: GENERATED ALWAYS AS ROW START / ROW END [HIDDEN]
|
|
158
|
+
const generatedAlways = propStr(node, 'generatedAlways');
|
|
159
|
+
if (generatedAlways) {
|
|
160
|
+
const gaMap = {
|
|
161
|
+
RowStart: 'ROW START',
|
|
162
|
+
RowEnd: 'ROW END',
|
|
163
|
+
UserIdStart: 'USER ID START',
|
|
164
|
+
UserIdEnd: 'USER ID END',
|
|
165
|
+
UserNameStart: 'USER NAME START',
|
|
166
|
+
UserNameEnd: 'USER NAME END',
|
|
167
|
+
TransactionIdStart: 'TRANSACTION ID START',
|
|
168
|
+
TransactionIdEnd: 'TRANSACTION ID END',
|
|
169
|
+
SequenceNumberStart: 'SEQUENCE NUMBER START',
|
|
170
|
+
SequenceNumberEnd: 'SEQUENCE NUMBER END',
|
|
171
|
+
};
|
|
172
|
+
const gaKw = gaMap[generatedAlways] ?? generatedAlways.toUpperCase();
|
|
173
|
+
parts.push(' ', keyword('GENERATED ALWAYS AS', opts), ' ', keyword(gaKw, opts));
|
|
174
|
+
}
|
|
175
|
+
if (node.props?.['isHidden'])
|
|
176
|
+
parts.push(' ', keyword('HIDDEN', opts));
|
|
177
|
+
// Dynamic data masking
|
|
178
|
+
if (node.props?.['isMasked']) {
|
|
179
|
+
const maskFn = propStr(node, 'maskingFunction') ?? 'default()';
|
|
180
|
+
parts.push(' ', keyword('MASKED WITH', opts), ' (', keyword('FUNCTION', opts), ` = '${maskFn}')`);
|
|
181
|
+
}
|
|
96
182
|
if (defaultValue)
|
|
97
183
|
parts.push(' ', keyword('DEFAULT', opts), ' ', printNode(defaultValue, opts));
|
|
98
184
|
parts.push(nullablePart(isNullable, opts));
|
|
185
|
+
if (checkConstraint) {
|
|
186
|
+
const checkName = propStr(node, 'checkConstraintName');
|
|
187
|
+
const checkPrefix = checkName ? [keyword('CONSTRAINT', opts), ' ', checkName, ' '] : '';
|
|
188
|
+
parts.push(' ', checkPrefix, keyword('CHECK', opts), ' (', printBool(checkConstraint, opts), ')');
|
|
189
|
+
}
|
|
190
|
+
// Inline PRIMARY KEY / UNIQUE constraint (e.g. in table variable declarations)
|
|
191
|
+
const uniqueConstraint = node.props?.['uniqueConstraint'];
|
|
192
|
+
if (uniqueConstraint) {
|
|
193
|
+
const constraintNamePrefix = uniqueConstraint.constraintName
|
|
194
|
+
? [keyword('CONSTRAINT', opts), ' ', uniqueConstraint.constraintName, ' ']
|
|
195
|
+
: '';
|
|
196
|
+
const uqKw = uniqueConstraint.isPrimaryKey ? keyword('PRIMARY KEY', opts) : keyword('UNIQUE', opts);
|
|
197
|
+
const clusteredKw = uniqueConstraint.clustered === true
|
|
198
|
+
? [' ', keyword('CLUSTERED', opts)]
|
|
199
|
+
: uniqueConstraint.clustered === false
|
|
200
|
+
? [' ', keyword('NONCLUSTERED', opts)]
|
|
201
|
+
: '';
|
|
202
|
+
parts.push(' ', constraintNamePrefix, uqKw, clusteredKw);
|
|
203
|
+
}
|
|
204
|
+
// Inline REFERENCES (column-level foreign key: col type REFERENCES Table(col))
|
|
205
|
+
const foreignKey = node.props?.['foreignKey'];
|
|
206
|
+
if (foreignKey) {
|
|
207
|
+
const refColsPart = foreignKey.refColumns?.length ? [' (', join(', ', foreignKey.refColumns), ')'] : '';
|
|
208
|
+
parts.push(' ', keyword('REFERENCES', opts), ' ', schemaObjectName(foreignKey.refTable), refColsPart);
|
|
209
|
+
if (foreignKey.deleteAction) {
|
|
210
|
+
parts.push(' ', keyword('ON DELETE', opts), ' ', keyword(foreignKey.deleteAction
|
|
211
|
+
.replace(/([A-Z])/g, ' $1')
|
|
212
|
+
.trim()
|
|
213
|
+
.toUpperCase(), opts));
|
|
214
|
+
}
|
|
215
|
+
if (foreignKey.updateAction) {
|
|
216
|
+
parts.push(' ', keyword('ON UPDATE', opts), ' ', keyword(foreignKey.updateAction
|
|
217
|
+
.replace(/([A-Z])/g, ' $1')
|
|
218
|
+
.trim()
|
|
219
|
+
.toUpperCase(), opts));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
99
222
|
return parts;
|
|
100
223
|
}
|
|
101
224
|
export function printConstraintDef(node, opts) {
|
|
@@ -104,10 +227,24 @@ export function printConstraintDef(node, opts) {
|
|
|
104
227
|
switch (node.type) {
|
|
105
228
|
case 'UniqueConstraint': {
|
|
106
229
|
const isPK = propBool(node, 'isPrimaryKey');
|
|
107
|
-
const
|
|
230
|
+
const clustered = node.props?.['clustered'];
|
|
231
|
+
// Only emit CLUSTERED/NONCLUSTERED when explicitly specified in DDL
|
|
232
|
+
const clusteredKw = clustered === true
|
|
233
|
+
? [keyword('CLUSTERED', opts), ' ']
|
|
234
|
+
: clustered === false
|
|
235
|
+
? [keyword('NONCLUSTERED', opts), ' ']
|
|
236
|
+
: '';
|
|
108
237
|
const kw = isPK ? keyword('PRIMARY KEY', opts) : keyword('UNIQUE', opts);
|
|
109
|
-
|
|
110
|
-
|
|
238
|
+
// Columns are now {name, order} objects; fall back to plain strings for compat
|
|
239
|
+
const rawCols = Array.isArray(node.props?.['columns']) ? node.props['columns'] : [];
|
|
240
|
+
const colDocs = rawCols.map((c) => {
|
|
241
|
+
if (typeof c === 'string')
|
|
242
|
+
return c;
|
|
243
|
+
const dir = c.order === 'Descending' ? [' ', keyword('DESC', opts)] : '';
|
|
244
|
+
return [c.name, dir];
|
|
245
|
+
});
|
|
246
|
+
const colsDoc = parenList(colDocs);
|
|
247
|
+
return group([namePrefix, indent([softline, kw, ' ', clusteredKw, colsDoc])]);
|
|
111
248
|
}
|
|
112
249
|
case 'CheckConstraint': {
|
|
113
250
|
const expr = prop(node, 'expression');
|
|
@@ -230,13 +367,10 @@ export function printAlterTable(node, opts) {
|
|
|
230
367
|
];
|
|
231
368
|
}
|
|
232
369
|
if (alterType === 'AlterTableSetStatement') {
|
|
233
|
-
//
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
.replace(/^_/, '')
|
|
237
|
-
.toUpperCase();
|
|
370
|
+
// Options come pre-serialized from SerializeTableOption (e.g. "lock_escalation = table",
|
|
371
|
+
// "system_versioning = on (history_table = dbo.Tbl)"). Render them verbatim — applying
|
|
372
|
+
// keyword() casing would uppercase embedded schema/table names.
|
|
238
373
|
const options = (node.props?.['options'] ?? []);
|
|
239
|
-
const optDocs = options.map((o) => [keyword(toSqlKw(o.kind), opts), ' = ', keyword(toSqlKw(o.value), opts)]);
|
|
240
374
|
return [
|
|
241
375
|
keyword('ALTER TABLE', opts),
|
|
242
376
|
' ',
|
|
@@ -244,7 +378,7 @@ export function printAlterTable(node, opts) {
|
|
|
244
378
|
hardline,
|
|
245
379
|
keyword('SET', opts),
|
|
246
380
|
' (',
|
|
247
|
-
join(', ',
|
|
381
|
+
join(', ', options),
|
|
248
382
|
')',
|
|
249
383
|
';',
|
|
250
384
|
];
|
|
@@ -291,6 +425,14 @@ export function printAlterTable(node, opts) {
|
|
|
291
425
|
';',
|
|
292
426
|
];
|
|
293
427
|
}
|
|
428
|
+
if (alterType === 'AlterTableTriggerModificationStatement') {
|
|
429
|
+
const enable = propBool(node, 'enable');
|
|
430
|
+
const triggerAll = node.props?.['triggerAll'];
|
|
431
|
+
const triggerNames = node.props?.['triggerNames'];
|
|
432
|
+
const verb = enable ? keyword('ENABLE TRIGGER', opts) : keyword('DISABLE TRIGGER', opts);
|
|
433
|
+
const targets = triggerAll ? keyword('ALL', opts) : join(', ', triggerNames ?? []);
|
|
434
|
+
return [keyword('ALTER TABLE', opts), ' ', name, hardline, verb, ' ', targets, ';'];
|
|
435
|
+
}
|
|
294
436
|
return [keyword('ALTER TABLE', opts), ' ', name, ' /* ', alterType, ' */;'];
|
|
295
437
|
}
|
|
296
438
|
// ---------------------------------------------------------------------------
|
|
@@ -299,10 +441,10 @@ export function printAlterTable(node, opts) {
|
|
|
299
441
|
export function printCreateIndex(node, opts) {
|
|
300
442
|
const indexName = propStr(node, 'indexName') ?? 'idx';
|
|
301
443
|
const isUnique = propBool(node, 'unique');
|
|
302
|
-
const isClustered = propBool(node, 'clustered');
|
|
303
444
|
const table = prop(node, 'table');
|
|
304
445
|
const columns = propArr(node, 'columns');
|
|
305
446
|
const includeColumns = node.props?.['includeColumns'];
|
|
447
|
+
const filterPredicate = propStr(node, 'filterPredicate');
|
|
306
448
|
const colDocs = columns.map((c) => {
|
|
307
449
|
const colName = propStr(c, 'name') ?? c.text ?? '';
|
|
308
450
|
const sort = propStr(c, 'sortOrder') ?? 'Ascending';
|
|
@@ -310,8 +452,14 @@ export function printCreateIndex(node, opts) {
|
|
|
310
452
|
? [colName, ' ', keyword('DESC', opts)]
|
|
311
453
|
: [colName, ' ', keyword('ASC', opts)];
|
|
312
454
|
});
|
|
313
|
-
const uniqueKw = isUnique ? keyword('UNIQUE
|
|
314
|
-
|
|
455
|
+
const uniqueKw = isUnique ? [keyword('UNIQUE', opts), ' '] : '';
|
|
456
|
+
// Preserve CLUSTERED / NONCLUSTERED exactly as written; omit when not specified.
|
|
457
|
+
const clusteredProp = node.props?.['clustered'];
|
|
458
|
+
const clusteredKw = clusteredProp === true
|
|
459
|
+
? [keyword('CLUSTERED', opts), ' ']
|
|
460
|
+
: clusteredProp === false
|
|
461
|
+
? [keyword('NONCLUSTERED', opts), ' ']
|
|
462
|
+
: '';
|
|
315
463
|
const onClause = [
|
|
316
464
|
keyword('ON', opts),
|
|
317
465
|
' ',
|
|
@@ -322,21 +470,23 @@ export function printCreateIndex(node, opts) {
|
|
|
322
470
|
')',
|
|
323
471
|
];
|
|
324
472
|
const includePart = Array.isArray(includeColumns) && includeColumns.length > 0
|
|
325
|
-
? [
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
]
|
|
473
|
+
? [hardline, keyword('INCLUDE', opts), ' ', parenList(includeColumns)]
|
|
474
|
+
: '';
|
|
475
|
+
const filterPart = filterPredicate ? [hardline, keyword('WHERE', opts), ' ', filterPredicate] : '';
|
|
476
|
+
const indexOptions = node.props?.['indexOptions'];
|
|
477
|
+
const withPart = indexOptions && indexOptions.length > 0
|
|
478
|
+
? [hardline, keyword('WITH', opts), ' (', join(', ', indexOptions), ')']
|
|
331
479
|
: '';
|
|
332
480
|
return group([
|
|
333
|
-
keyword('CREATE
|
|
481
|
+
keyword('CREATE', opts),
|
|
482
|
+
' ',
|
|
334
483
|
uniqueKw,
|
|
335
484
|
clusteredKw,
|
|
336
485
|
keyword('INDEX', opts),
|
|
337
486
|
' ',
|
|
338
487
|
indexName,
|
|
339
|
-
indent([hardline, onClause, includePart]),
|
|
488
|
+
indent([hardline, onClause, includePart, filterPart]),
|
|
489
|
+
withPart,
|
|
340
490
|
';',
|
|
341
491
|
]);
|
|
342
492
|
}
|
|
@@ -354,6 +504,12 @@ export function printAlterIndex(node, opts) {
|
|
|
354
504
|
Set: 'SET',
|
|
355
505
|
};
|
|
356
506
|
const typeKw = keyword(typeKwMap[alterType] ?? alterType.toUpperCase(), opts);
|
|
507
|
+
const indexOptions = node.props?.['indexOptions'];
|
|
508
|
+
const partition = propStr(node, 'partition');
|
|
509
|
+
const withPart = indexOptions && indexOptions.length > 0
|
|
510
|
+
? [' ', keyword('WITH', opts), ' (', join(', ', indexOptions), ')']
|
|
511
|
+
: '';
|
|
512
|
+
const partitionPart = partition ? [' ', keyword('PARTITION', opts), ' = ', partition] : '';
|
|
357
513
|
return [
|
|
358
514
|
keyword('ALTER INDEX', opts),
|
|
359
515
|
' ',
|
|
@@ -364,6 +520,8 @@ export function printAlterIndex(node, opts) {
|
|
|
364
520
|
schemaObjectName(table),
|
|
365
521
|
' ',
|
|
366
522
|
typeKw,
|
|
523
|
+
withPart,
|
|
524
|
+
partitionPart,
|
|
367
525
|
';',
|
|
368
526
|
];
|
|
369
527
|
}
|
|
@@ -410,10 +568,13 @@ export function printCreateProcedure(node, opts) {
|
|
|
410
568
|
const paramDocs = parameters.map((p) => {
|
|
411
569
|
const pName = propStr(p, 'name') ?? '@p';
|
|
412
570
|
const dt = propStr(p, 'dataType') ?? 'INT';
|
|
571
|
+
const isUdt = propBool(p, 'isUdt');
|
|
413
572
|
const isOutput = propBool(p, 'output');
|
|
414
573
|
const isReadonly = propBool(p, 'readonly');
|
|
415
574
|
const defaultVal = prop(p, 'defaultValue');
|
|
416
|
-
|
|
575
|
+
// UDT names are identifiers, not SQL keywords — skip keyword-casing
|
|
576
|
+
const dtDoc = isUdt ? dt : keyword(dt, opts);
|
|
577
|
+
const parts = [pName, ' ', dtDoc];
|
|
417
578
|
if (defaultVal)
|
|
418
579
|
parts.push(' = ', printNode(defaultVal, opts));
|
|
419
580
|
if (isOutput)
|
|
@@ -459,7 +620,9 @@ export function printCreateFunction(node, opts) {
|
|
|
459
620
|
const paramDocs = parameters.map((p) => {
|
|
460
621
|
const pName = propStr(p, 'name') ?? '@p';
|
|
461
622
|
const dt = propStr(p, 'dataType') ?? 'INT';
|
|
462
|
-
|
|
623
|
+
const isUdt = propBool(p, 'isUdt');
|
|
624
|
+
// UDT names are identifiers — skip keyword-casing
|
|
625
|
+
return [pName, ' ', isUdt ? dt : keyword(dt, opts)];
|
|
463
626
|
});
|
|
464
627
|
const preBody = commentsBlock(node.preBodyComments);
|
|
465
628
|
const postParam = commentsBlock(node.postParamComments);
|
|
@@ -468,25 +631,24 @@ export function printCreateFunction(node, opts) {
|
|
|
468
631
|
: node.type === 'AlterFunctionStatement'
|
|
469
632
|
? keyword('ALTER FUNCTION', opts)
|
|
470
633
|
: keyword('CREATE FUNCTION', opts);
|
|
471
|
-
const
|
|
634
|
+
const nameAndParamsNoOpts = [
|
|
472
635
|
fnKw,
|
|
473
636
|
' ',
|
|
474
637
|
schemaObjectName(prop(node, 'name')),
|
|
475
638
|
preBody,
|
|
476
639
|
group(['(', parameters.length > 0 ? [indent([softline, join([',', line], paramDocs)]), softline] : '', ')']),
|
|
477
640
|
postParam,
|
|
478
|
-
printModuleOptions(node, opts),
|
|
479
641
|
];
|
|
480
642
|
if (bodyType === 'table') {
|
|
481
|
-
// Inline TVF: RETURNS TABLE AS RETURN (query) — no BEGIN/END
|
|
482
|
-
// returnType raw text contains the SELECT, not the word TABLE — hardcode TABLE
|
|
643
|
+
// Inline TVF: RETURNS TABLE [WITH options] AS RETURN (query) — no BEGIN/END
|
|
483
644
|
const queryDoc = body && !Array.isArray(body) ? qexpr(body, opts) : '/* query */';
|
|
484
645
|
return [
|
|
485
|
-
|
|
486
|
-
|
|
646
|
+
nameAndParamsNoOpts,
|
|
647
|
+
hardline,
|
|
487
648
|
keyword('RETURNS', opts),
|
|
488
649
|
' ',
|
|
489
650
|
keyword('TABLE', opts),
|
|
651
|
+
printModuleOptions(node, opts),
|
|
490
652
|
hardline,
|
|
491
653
|
keyword('AS', opts),
|
|
492
654
|
hardline,
|
|
@@ -519,12 +681,15 @@ export function printCreateFunction(node, opts) {
|
|
|
519
681
|
else {
|
|
520
682
|
retTypePart = keyword(returnType, opts);
|
|
521
683
|
}
|
|
684
|
+
// WITH options come AFTER RETURNS (per T-SQL syntax):
|
|
685
|
+
// CREATE FUNCTION ... (params) RETURNS type WITH options AS BEGIN ... END
|
|
522
686
|
return [
|
|
523
|
-
|
|
524
|
-
|
|
687
|
+
nameAndParamsNoOpts,
|
|
688
|
+
hardline,
|
|
525
689
|
keyword('RETURNS', opts),
|
|
526
690
|
' ',
|
|
527
691
|
retTypePart,
|
|
692
|
+
printModuleOptions(node, opts),
|
|
528
693
|
hardline,
|
|
529
694
|
keyword('AS', opts),
|
|
530
695
|
hardline,
|
|
@@ -547,9 +712,7 @@ export function printCreateView(node, opts) {
|
|
|
547
712
|
: node.type === 'AlterViewStatement'
|
|
548
713
|
? keyword('ALTER VIEW', opts)
|
|
549
714
|
: keyword('CREATE VIEW', opts);
|
|
550
|
-
const colsPart = columns?.length
|
|
551
|
-
? [' ', parenList(columns)]
|
|
552
|
-
: '';
|
|
715
|
+
const colsPart = columns?.length ? [' ', parenList(columns)] : '';
|
|
553
716
|
const withPart = withOptions?.length
|
|
554
717
|
? [
|
|
555
718
|
hardline,
|
|
@@ -559,6 +722,8 @@ export function printCreateView(node, opts) {
|
|
|
559
722
|
]
|
|
560
723
|
: '';
|
|
561
724
|
const preBodyPart = commentsBlock(node.preBodyComments);
|
|
725
|
+
const withCheckOption = node.props?.['withCheckOption'];
|
|
726
|
+
const checkOptionPart = withCheckOption ? [hardline, keyword('WITH CHECK OPTION', opts)] : '';
|
|
562
727
|
return group([
|
|
563
728
|
kw,
|
|
564
729
|
' ',
|
|
@@ -570,6 +735,7 @@ export function printCreateView(node, opts) {
|
|
|
570
735
|
keyword('AS', opts),
|
|
571
736
|
hardline,
|
|
572
737
|
body ? qexpr(body, opts) : '',
|
|
738
|
+
checkOptionPart,
|
|
573
739
|
';',
|
|
574
740
|
]);
|
|
575
741
|
}
|
|
@@ -589,6 +755,8 @@ export function printCreateTrigger(node, opts) {
|
|
|
589
755
|
const actionList = Array.isArray(actions)
|
|
590
756
|
? join(', ', actions.map((a) => keyword(a.toUpperCase(), opts)))
|
|
591
757
|
: '';
|
|
758
|
+
const notForReplication = propBool(node, 'notForReplication');
|
|
759
|
+
const notForReplicationDoc = notForReplication ? [hardline, keyword('NOT FOR REPLICATION', opts)] : '';
|
|
592
760
|
const bodyDocs = propArr(node, 'body').map((s) => printStatementWithComments(s, opts));
|
|
593
761
|
return [
|
|
594
762
|
kw,
|
|
@@ -602,6 +770,7 @@ export function printCreateTrigger(node, opts) {
|
|
|
602
770
|
typeKw,
|
|
603
771
|
' ',
|
|
604
772
|
actionList,
|
|
773
|
+
notForReplicationDoc,
|
|
605
774
|
hardline,
|
|
606
775
|
keyword('AS', opts),
|
|
607
776
|
hardline,
|
|
@@ -749,9 +918,14 @@ export function printDropObjects(objType, node, opts) {
|
|
|
749
918
|
];
|
|
750
919
|
}
|
|
751
920
|
export function printDropIndex(node, opts) {
|
|
921
|
+
const ifExists = propBool(node, 'ifExists');
|
|
752
922
|
const indices = propArr(node, 'indices');
|
|
753
923
|
const indexDocs = indices.map((idx) => [propStr(idx, 'name') ?? '', ' ', keyword('ON', opts), ' ', schemaObjectName(prop(idx, 'table'))]);
|
|
754
|
-
|
|
924
|
+
const ifExistsPart = ifExists ? [' ', keyword('IF EXISTS', opts)] : '';
|
|
925
|
+
if (indexDocs.length === 1) {
|
|
926
|
+
return [keyword('DROP INDEX', opts), ifExistsPart, ' ', indexDocs[0], ';'];
|
|
927
|
+
}
|
|
928
|
+
return [keyword('DROP INDEX', opts), ifExistsPart, indent([hardline, join([',', hardline], indexDocs)]), ';'];
|
|
755
929
|
}
|
|
756
930
|
// ---------------------------------------------------------------------------
|
|
757
931
|
// CREATE / DROP SYNONYM
|
|
@@ -964,7 +1138,10 @@ export function printUpdateStatistics(node, opts) {
|
|
|
964
1138
|
const subElements = node.props?.['subElements'];
|
|
965
1139
|
const options = node.props?.['options'];
|
|
966
1140
|
const parts = [keyword('UPDATE STATISTICS', opts), ' ', table ? schemaObjectName(table) : ''];
|
|
967
|
-
|
|
1141
|
+
// Single stat name: no parens needed. Multiple: wrap in parens.
|
|
1142
|
+
if (subElements?.length === 1)
|
|
1143
|
+
parts.push([' ', subElements[0]]);
|
|
1144
|
+
else if (subElements?.length)
|
|
968
1145
|
parts.push([' ', parenList(subElements)]);
|
|
969
1146
|
if (options?.length)
|
|
970
1147
|
parts.push([hardline, withOptionsClause(options, opts)]);
|