prettier-plugin-tsql 0.6.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/dotnet/PrettierSql.Core.dll +0 -0
- package/bin/dotnet/SqlScriptDom.dll +0 -0
- package/dist/_core/options.js +35 -0
- package/dist/_core/parser/loadDotnet.js +29 -0
- package/dist/_core/printer/helpers.js +17 -0
- package/dist/_core/printer/utils.js +83 -0
- package/dist/_core/types.js +2 -0
- package/dist/index.js +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/printer/admin.d.ts +1 -0
- package/dist/printer/admin.d.ts.map +1 -1
- package/dist/printer/admin.js +27 -5
- package/dist/printer/admin.js.map +1 -1
- package/dist/printer/ddl.d.ts.map +1 -1
- package/dist/printer/ddl.js +212 -27
- package/dist/printer/ddl.js.map +1 -1
- package/dist/printer/expressions.d.ts.map +1 -1
- package/dist/printer/expressions.js +23 -7
- package/dist/printer/expressions.js.map +1 -1
- package/dist/printer/helpers.d.ts.map +1 -1
- package/dist/printer/helpers.js +13 -8
- package/dist/printer/helpers.js.map +1 -1
- package/dist/printer/index.js +1 -1
- package/dist/printer/index.js.map +1 -1
- package/dist/printer/procedural.d.ts.map +1 -1
- package/dist/printer/procedural.js +47 -4
- package/dist/printer/procedural.js.map +1 -1
- package/dist/printer/security.js +1 -1
- package/dist/printer/statements.d.ts +6 -0
- package/dist/printer/statements.d.ts.map +1 -1
- package/dist/printer/statements.js +135 -30
- package/dist/printer/statements.js.map +1 -1
- package/package.json +5 -3
package/dist/printer/ddl.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
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 '../_core/printer/utils.js';
|
|
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)
|
|
5
|
-
import { printStatementWithComments, printNode, printBool, qexpr } from './statements.js';
|
|
5
|
+
import { printStatementWithComments, printNode, printBool, printBoolClause, qexpr } from './statements.js';
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
// Shared helpers
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
|
+
/**
|
|
10
|
+
* When ScriptDOM sees `AS BEGIN...END` it wraps the body in a single
|
|
11
|
+
* BeginEndBlockStatement. Unwrap that one outer block so that proc/function/
|
|
12
|
+
* trigger printers can emit their own BEGIN/END delimiters cleanly, while
|
|
13
|
+
* a *standalone* BEGIN...END statement still prints with its own delimiters.
|
|
14
|
+
*/
|
|
15
|
+
function unwrapBodyBlock(stmts) {
|
|
16
|
+
if (stmts.length === 1 && stmts[0]?.type === 'BeginEndBlock') {
|
|
17
|
+
return propArr(stmts[0], 'statements');
|
|
18
|
+
}
|
|
19
|
+
return stmts;
|
|
20
|
+
}
|
|
9
21
|
/** Render ` NULL` / ` NOT NULL` from a tristate `nullable` prop value. */
|
|
10
22
|
function nullablePart(nullable, opts) {
|
|
11
23
|
if (nullable === true)
|
|
@@ -40,7 +52,7 @@ function printInlineIndex(node, opts) {
|
|
|
40
52
|
const kind = propStr(node, 'kind'); // 'clustered', 'nonclustered', etc.
|
|
41
53
|
const columns = propArr(node, 'columns');
|
|
42
54
|
const includeColumns = node.props?.['includeColumns'];
|
|
43
|
-
const
|
|
55
|
+
const filterPredicateNode = prop(node, 'filterPredicate');
|
|
44
56
|
const indexOptions = node.props?.['indexOptions'];
|
|
45
57
|
const uniqueKw = isUnique ? [keyword('UNIQUE', opts), ' '] : '';
|
|
46
58
|
const kindKw = kind ? [keyword(kind.toUpperCase(), opts), ' '] : '';
|
|
@@ -52,7 +64,7 @@ function printInlineIndex(node, opts) {
|
|
|
52
64
|
const includePart = includeColumns?.length
|
|
53
65
|
? [' ', keyword('INCLUDE', opts), ' ', parenList(includeColumns)]
|
|
54
66
|
: '';
|
|
55
|
-
const filterPart =
|
|
67
|
+
const filterPart = filterPredicateNode ? [' ', printBoolClause('WHERE', filterPredicateNode, opts)] : '';
|
|
56
68
|
const withPart = indexOptions?.length ? [' ', keyword('WITH', opts), ' (', join(', ', indexOptions), ')'] : '';
|
|
57
69
|
return [
|
|
58
70
|
keyword('INDEX', opts),
|
|
@@ -92,8 +104,18 @@ export function printCreateTable(node, opts) {
|
|
|
92
104
|
const withPart = options && options.length > 0 ? [hardline, keyword('WITH', opts), ' ', parenList(options)] : '';
|
|
93
105
|
const onFileGroup = propStr(node, 'onFileGroup');
|
|
94
106
|
const textimageOn = propStr(node, 'textimageOn');
|
|
107
|
+
const fileStreamOn = propStr(node, 'fileStreamOn');
|
|
95
108
|
const onPart = onFileGroup ? [hardline, keyword('ON', opts), ' ', onFileGroup] : '';
|
|
96
109
|
const textimagePart = textimageOn ? [hardline, keyword('TEXTIMAGE_ON', opts), ' ', textimageOn] : '';
|
|
110
|
+
const fileStreamPart = fileStreamOn ? [hardline, keyword('FILESTREAM_ON', opts), ' ', fileStreamOn] : '';
|
|
111
|
+
// Graph table types (AS NODE / AS EDGE)
|
|
112
|
+
const asNode = node.props?.['asNode'];
|
|
113
|
+
const asEdge = node.props?.['asEdge'];
|
|
114
|
+
const graphPart = asNode
|
|
115
|
+
? [' ', keyword('AS NODE', opts)]
|
|
116
|
+
: asEdge
|
|
117
|
+
? [' ', keyword('AS EDGE', opts)]
|
|
118
|
+
: '';
|
|
97
119
|
return group([
|
|
98
120
|
keyword('CREATE TABLE', opts),
|
|
99
121
|
' ',
|
|
@@ -102,18 +124,27 @@ export function printCreateTable(node, opts) {
|
|
|
102
124
|
indent([hardline, join([',', hardline], allDefs)]),
|
|
103
125
|
hardline,
|
|
104
126
|
')',
|
|
127
|
+
graphPart,
|
|
105
128
|
onPart,
|
|
129
|
+
fileStreamPart,
|
|
106
130
|
textimagePart,
|
|
107
131
|
withPart,
|
|
108
132
|
';',
|
|
109
133
|
]);
|
|
110
134
|
}
|
|
111
135
|
export function printColumnDef(node, opts) {
|
|
136
|
+
// Raw leaf (e.g. ENCRYPTED WITH — property names vary across ScriptDOM versions).
|
|
137
|
+
// The C# AstBuilder emits `Leaf("ColumnDefinition", col, rawText)` which sets
|
|
138
|
+
// `node.text` to the original column fragment and leaves `node.props` undefined.
|
|
139
|
+
if (!node.props)
|
|
140
|
+
return node.text ?? '/* column */';
|
|
112
141
|
const name = propStr(node, 'name') ?? 'col';
|
|
113
|
-
// Computed column: Name AS expression [PERSISTED]
|
|
142
|
+
// Computed column: Name AS expression [PERSISTED] [NOT NULL|NULL]
|
|
114
143
|
const computedExpr = prop(node, 'computedExpression');
|
|
115
144
|
if (computedExpr) {
|
|
116
145
|
const isPersisted = node.props?.['isPersisted'];
|
|
146
|
+
// Computed PERSISTED columns may have an explicit nullability constraint
|
|
147
|
+
const computedNullPart = nullablePart(node.props?.['nullable'], opts);
|
|
117
148
|
return [
|
|
118
149
|
name,
|
|
119
150
|
' ',
|
|
@@ -121,10 +152,13 @@ export function printColumnDef(node, opts) {
|
|
|
121
152
|
' ',
|
|
122
153
|
printNode(computedExpr, opts),
|
|
123
154
|
isPersisted ? [' ', keyword('PERSISTED', opts)] : '',
|
|
155
|
+
computedNullPart,
|
|
124
156
|
];
|
|
125
157
|
}
|
|
126
158
|
const dataType = propStr(node, 'dataType') ?? 'INT';
|
|
127
159
|
const params = node.props?.['dataTypeParams'];
|
|
160
|
+
const xmlSchemaCollection = propStr(node, 'xmlSchemaCollection');
|
|
161
|
+
const xmlTypeOption = propStr(node, 'xmlTypeOption');
|
|
128
162
|
// Read nullable as a tristate (true/false/undefined) — propBool only returns true/false.
|
|
129
163
|
const isNullable = node.props?.['nullable'];
|
|
130
164
|
const isIdentity = propBool(node, 'identity');
|
|
@@ -133,9 +167,18 @@ export function printColumnDef(node, opts) {
|
|
|
133
167
|
const defaultValue = prop(node, 'defaultValue');
|
|
134
168
|
const checkConstraint = prop(node, 'checkConstraint');
|
|
135
169
|
const collation = propStr(node, 'collation');
|
|
136
|
-
const typeStr =
|
|
137
|
-
|
|
138
|
-
|
|
170
|
+
const typeStr = (() => {
|
|
171
|
+
const baseType = keyword(dataType, opts);
|
|
172
|
+
if (Array.isArray(params) && params.length > 0) {
|
|
173
|
+
return [baseType, `(${params.join(', ')})`];
|
|
174
|
+
}
|
|
175
|
+
if (xmlSchemaCollection) {
|
|
176
|
+
// xml(CONTENT|DOCUMENT schema_collection) — CONTENT/DOCUMENT are optional keywords
|
|
177
|
+
const prefix = xmlTypeOption ? `${keyword(xmlTypeOption, opts)} ` : '';
|
|
178
|
+
return [baseType, '(', prefix, xmlSchemaCollection, ')'];
|
|
179
|
+
}
|
|
180
|
+
return baseType;
|
|
181
|
+
})();
|
|
139
182
|
const parts = [name, ' ', typeStr];
|
|
140
183
|
// COLLATE clause comes right after the data type
|
|
141
184
|
if (collation)
|
|
@@ -144,6 +187,8 @@ export function printColumnDef(node, opts) {
|
|
|
144
187
|
const seed = identitySeed ?? '1';
|
|
145
188
|
const inc = identityIncrement ?? '1';
|
|
146
189
|
parts.push(' ', keyword('IDENTITY', opts), `(${seed}, ${inc})`);
|
|
190
|
+
if (node.props?.['identityNotForReplication'])
|
|
191
|
+
parts.push(' ', keyword('NOT FOR REPLICATION', opts));
|
|
147
192
|
}
|
|
148
193
|
if (node.props?.['isRowGuidCol'])
|
|
149
194
|
parts.push(' ', keyword('ROWGUIDCOL', opts));
|
|
@@ -179,8 +224,11 @@ export function printColumnDef(node, opts) {
|
|
|
179
224
|
const maskFn = propStr(node, 'maskingFunction') ?? 'default()';
|
|
180
225
|
parts.push(' ', keyword('MASKED WITH', opts), ' (', keyword('FUNCTION', opts), ` = '${maskFn}')`);
|
|
181
226
|
}
|
|
182
|
-
if (defaultValue)
|
|
183
|
-
|
|
227
|
+
if (defaultValue) {
|
|
228
|
+
const defaultName = propStr(node, 'defaultConstraintName');
|
|
229
|
+
const defaultNamePrefix = defaultName ? [keyword('CONSTRAINT', opts), ' ', defaultName, ' '] : '';
|
|
230
|
+
parts.push(' ', defaultNamePrefix, keyword('DEFAULT', opts), ' ', printNode(defaultValue, opts));
|
|
231
|
+
}
|
|
184
232
|
parts.push(nullablePart(isNullable, opts));
|
|
185
233
|
if (checkConstraint) {
|
|
186
234
|
const checkName = propStr(node, 'checkConstraintName');
|
|
@@ -201,9 +249,12 @@ export function printColumnDef(node, opts) {
|
|
|
201
249
|
: '';
|
|
202
250
|
parts.push(' ', constraintNamePrefix, uqKw, clusteredKw);
|
|
203
251
|
}
|
|
204
|
-
// Inline REFERENCES (column-level foreign key: col type REFERENCES Table(col))
|
|
252
|
+
// Inline REFERENCES (column-level foreign key: col type [CONSTRAINT name] REFERENCES Table(col))
|
|
205
253
|
const foreignKey = node.props?.['foreignKey'];
|
|
206
254
|
if (foreignKey) {
|
|
255
|
+
if (foreignKey.constraintName) {
|
|
256
|
+
parts.push(' ', keyword('CONSTRAINT', opts), ' ', foreignKey.constraintName);
|
|
257
|
+
}
|
|
207
258
|
const refColsPart = foreignKey.refColumns?.length ? [' (', join(', ', foreignKey.refColumns), ')'] : '';
|
|
208
259
|
parts.push(' ', keyword('REFERENCES', opts), ' ', schemaObjectName(foreignKey.refTable), refColsPart);
|
|
209
260
|
if (foreignKey.deleteAction) {
|
|
@@ -244,11 +295,23 @@ export function printConstraintDef(node, opts) {
|
|
|
244
295
|
return [c.name, dir];
|
|
245
296
|
});
|
|
246
297
|
const colsDoc = parenList(colDocs);
|
|
247
|
-
|
|
298
|
+
const indexOptions = node.props?.['indexOptions'];
|
|
299
|
+
const withPart = indexOptions?.length
|
|
300
|
+
? [' ', keyword('WITH', opts), ' (', join(', ', indexOptions), ')']
|
|
301
|
+
: '';
|
|
302
|
+
return group([namePrefix, indent([softline, kw, ' ', clusteredKw, colsDoc]), withPart]);
|
|
248
303
|
}
|
|
249
304
|
case 'CheckConstraint': {
|
|
250
305
|
const expr = prop(node, 'expression');
|
|
251
|
-
|
|
306
|
+
const nfr = propBool(node, 'notForReplication');
|
|
307
|
+
return [
|
|
308
|
+
namePrefix,
|
|
309
|
+
keyword('CHECK', opts),
|
|
310
|
+
nfr ? [' ', keyword('NOT FOR REPLICATION', opts)] : '',
|
|
311
|
+
' (',
|
|
312
|
+
expr ? printBool(expr, opts) : '',
|
|
313
|
+
')',
|
|
314
|
+
];
|
|
252
315
|
}
|
|
253
316
|
case 'ForeignKeyConstraint': {
|
|
254
317
|
const cols = Array.isArray(node.props?.['columns']) ? node.props?.['columns'] : [];
|
|
@@ -257,6 +320,7 @@ export function printConstraintDef(node, opts) {
|
|
|
257
320
|
const refName = refTable ? schemaObjectName(refTable) : '';
|
|
258
321
|
const deleteAction = propStr(node, 'deleteAction');
|
|
259
322
|
const updateAction = propStr(node, 'updateAction');
|
|
323
|
+
const nfr = propBool(node, 'notForReplication');
|
|
260
324
|
const refActionKw = (action) => keyword(action
|
|
261
325
|
.replace(/([A-Z])/g, ' $1')
|
|
262
326
|
.trim()
|
|
@@ -276,6 +340,7 @@ export function printConstraintDef(node, opts) {
|
|
|
276
340
|
]),
|
|
277
341
|
deleteAction ? [line, keyword('ON DELETE', opts), ' ', refActionKw(deleteAction)] : '',
|
|
278
342
|
updateAction ? [line, keyword('ON UPDATE', opts), ' ', refActionKw(updateAction)] : '',
|
|
343
|
+
nfr ? [line, keyword('NOT FOR REPLICATION', opts)] : '',
|
|
279
344
|
]),
|
|
280
345
|
]),
|
|
281
346
|
];
|
|
@@ -316,6 +381,11 @@ export function printAlterTable(node, opts) {
|
|
|
316
381
|
join([',', line], elements.map((e) => e.name)),
|
|
317
382
|
]),
|
|
318
383
|
]);
|
|
384
|
+
// WITH (ONLINE = ON, WAIT_AT_LOW_PRIORITY ...) on DROP CLUSTERED CONSTRAINT
|
|
385
|
+
const allDropOptions = elements.flatMap((e) => e.dropOptions ?? []);
|
|
386
|
+
const withPart = allDropOptions.length
|
|
387
|
+
? [' ', keyword('WITH', opts), ' (', join(', ', allDropOptions), ')']
|
|
388
|
+
: '';
|
|
319
389
|
return [
|
|
320
390
|
keyword('ALTER TABLE', opts),
|
|
321
391
|
' ',
|
|
@@ -325,6 +395,7 @@ export function printAlterTable(node, opts) {
|
|
|
325
395
|
ifExists ? [' ', keyword('IF EXISTS', opts)] : '',
|
|
326
396
|
' ',
|
|
327
397
|
nameList,
|
|
398
|
+
withPart,
|
|
328
399
|
';',
|
|
329
400
|
];
|
|
330
401
|
}
|
|
@@ -350,7 +421,49 @@ export function printAlterTable(node, opts) {
|
|
|
350
421
|
}
|
|
351
422
|
if (alterType === 'AlterTableAlterColumnStatement') {
|
|
352
423
|
const column = propStr(node, 'column') ?? '';
|
|
424
|
+
const alterColumnOption = propStr(node, 'alterColumnOption');
|
|
425
|
+
const maskingFunction = propStr(node, 'maskingFunction');
|
|
426
|
+
// ADD/DROP modifier variants (no data type change, just add/remove a column property)
|
|
427
|
+
if (alterColumnOption) {
|
|
428
|
+
let optDoc;
|
|
429
|
+
if (alterColumnOption === 'AddMaskingFunction') {
|
|
430
|
+
// ALTER COLUMN col ADD MASKED WITH (FUNCTION = 'fn()')
|
|
431
|
+
const fn = maskingFunction ?? 'default()';
|
|
432
|
+
optDoc = [keyword('ADD MASKED WITH', opts), ' (', keyword('FUNCTION', opts), ` = '${fn}')`];
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
const optMap = {
|
|
436
|
+
DropMaskingFunction: 'DROP MASKED',
|
|
437
|
+
AddSparse: 'ADD SPARSE',
|
|
438
|
+
DropSparse: 'DROP SPARSE',
|
|
439
|
+
AddRowGuidCol: 'ADD ROWGUIDCOL',
|
|
440
|
+
DropRowGuidCol: 'DROP ROWGUIDCOL',
|
|
441
|
+
AddHidden: 'ADD HIDDEN',
|
|
442
|
+
DropHidden: 'DROP HIDDEN',
|
|
443
|
+
AddPersisted: 'ADD PERSISTED',
|
|
444
|
+
DropPersisted: 'DROP PERSISTED',
|
|
445
|
+
};
|
|
446
|
+
optDoc = keyword(optMap[alterColumnOption] ?? alterColumnOption.toUpperCase(), opts);
|
|
447
|
+
}
|
|
448
|
+
return [
|
|
449
|
+
keyword('ALTER TABLE', opts),
|
|
450
|
+
' ',
|
|
451
|
+
name,
|
|
452
|
+
hardline,
|
|
453
|
+
keyword('ALTER COLUMN', opts),
|
|
454
|
+
' ',
|
|
455
|
+
column,
|
|
456
|
+
' ',
|
|
457
|
+
optDoc,
|
|
458
|
+
';',
|
|
459
|
+
];
|
|
460
|
+
}
|
|
461
|
+
// Normal type-change: ALTER COLUMN col newtype [COLLATE ...] [NULL|NOT NULL]
|
|
353
462
|
const dataType = propStr(node, 'dataType') ?? '';
|
|
463
|
+
const collationAC = propStr(node, 'collation');
|
|
464
|
+
const collatePart = collationAC
|
|
465
|
+
? [' ', keyword('COLLATE', opts), ' ', collationAC]
|
|
466
|
+
: '';
|
|
354
467
|
const nullPart = nullablePart(node.props?.['nullable'], opts);
|
|
355
468
|
return [
|
|
356
469
|
keyword('ALTER TABLE', opts),
|
|
@@ -362,6 +475,7 @@ export function printAlterTable(node, opts) {
|
|
|
362
475
|
column,
|
|
363
476
|
' ',
|
|
364
477
|
keyword(dataType, opts),
|
|
478
|
+
collatePart,
|
|
365
479
|
nullPart,
|
|
366
480
|
';',
|
|
367
481
|
];
|
|
@@ -407,9 +521,13 @@ export function printAlterTable(node, opts) {
|
|
|
407
521
|
const sourcePartition = propStr(node, 'sourcePartition');
|
|
408
522
|
const targetTable = prop(node, 'targetTable');
|
|
409
523
|
const targetPartition = propStr(node, 'targetPartition');
|
|
524
|
+
const switchOptions = node.props?.['switchOptions'];
|
|
410
525
|
const sourceDoc = sourcePartition ? [' ', keyword('PARTITION', opts), ' ', sourcePartition] : '';
|
|
411
526
|
const targetDoc = targetTable ? schemaObjectName(targetTable) : '';
|
|
412
527
|
const targetPartDoc = targetPartition ? [' ', keyword('PARTITION', opts), ' ', targetPartition] : '';
|
|
528
|
+
const switchOptDoc = switchOptions?.length
|
|
529
|
+
? [' ', keyword('WITH', opts), ' (', join(', ', switchOptions), ')']
|
|
530
|
+
: '';
|
|
413
531
|
return [
|
|
414
532
|
keyword('ALTER TABLE', opts),
|
|
415
533
|
' ',
|
|
@@ -422,6 +540,7 @@ export function printAlterTable(node, opts) {
|
|
|
422
540
|
' ',
|
|
423
541
|
targetDoc,
|
|
424
542
|
targetPartDoc,
|
|
543
|
+
switchOptDoc,
|
|
425
544
|
';',
|
|
426
545
|
];
|
|
427
546
|
}
|
|
@@ -444,7 +563,7 @@ export function printCreateIndex(node, opts) {
|
|
|
444
563
|
const table = prop(node, 'table');
|
|
445
564
|
const columns = propArr(node, 'columns');
|
|
446
565
|
const includeColumns = node.props?.['includeColumns'];
|
|
447
|
-
const
|
|
566
|
+
const filterPredicateNode = prop(node, 'filterPredicate');
|
|
448
567
|
const colDocs = columns.map((c) => {
|
|
449
568
|
const colName = propStr(c, 'name') ?? c.text ?? '';
|
|
450
569
|
const sort = propStr(c, 'sortOrder') ?? 'Ascending';
|
|
@@ -472,11 +591,15 @@ export function printCreateIndex(node, opts) {
|
|
|
472
591
|
const includePart = Array.isArray(includeColumns) && includeColumns.length > 0
|
|
473
592
|
? [hardline, keyword('INCLUDE', opts), ' ', parenList(includeColumns)]
|
|
474
593
|
: '';
|
|
475
|
-
const filterPart =
|
|
594
|
+
const filterPart = filterPredicateNode
|
|
595
|
+
? [hardline, printBoolClause('WHERE', filterPredicateNode, opts)]
|
|
596
|
+
: '';
|
|
476
597
|
const indexOptions = node.props?.['indexOptions'];
|
|
477
598
|
const withPart = indexOptions && indexOptions.length > 0
|
|
478
599
|
? [hardline, keyword('WITH', opts), ' (', join(', ', indexOptions), ')']
|
|
479
600
|
: '';
|
|
601
|
+
const onFileGroup = propStr(node, 'onFileGroup');
|
|
602
|
+
const fileGroupPart = onFileGroup ? [hardline, keyword('ON', opts), ' ', onFileGroup] : '';
|
|
480
603
|
return group([
|
|
481
604
|
keyword('CREATE', opts),
|
|
482
605
|
' ',
|
|
@@ -487,6 +610,7 @@ export function printCreateIndex(node, opts) {
|
|
|
487
610
|
indexName,
|
|
488
611
|
indent([hardline, onClause, includePart, filterPart]),
|
|
489
612
|
withPart,
|
|
613
|
+
fileGroupPart,
|
|
490
614
|
';',
|
|
491
615
|
]);
|
|
492
616
|
}
|
|
@@ -520,8 +644,8 @@ export function printAlterIndex(node, opts) {
|
|
|
520
644
|
schemaObjectName(table),
|
|
521
645
|
' ',
|
|
522
646
|
typeKw,
|
|
523
|
-
withPart,
|
|
524
647
|
partitionPart,
|
|
648
|
+
withPart,
|
|
525
649
|
';',
|
|
526
650
|
];
|
|
527
651
|
}
|
|
@@ -583,7 +707,11 @@ export function printCreateProcedure(node, opts) {
|
|
|
583
707
|
parts.push(' ', keyword('READONLY', opts));
|
|
584
708
|
return parts;
|
|
585
709
|
});
|
|
586
|
-
|
|
710
|
+
// Natively compiled procs have a single BEGIN ATOMIC WITH (...) body statement.
|
|
711
|
+
const atomicBlock = body.length === 1 && body[0].type === 'BeginEndAtomicBlock' ? body[0] : null;
|
|
712
|
+
const atomicOptions = atomicBlock?.props?.['atomicOptions'];
|
|
713
|
+
const innerBody = atomicBlock ? propArr(atomicBlock, 'statements') : unwrapBodyBlock(body);
|
|
714
|
+
const bodyDocs = innerBody.map((s) => printStatementWithComments(s, opts));
|
|
587
715
|
const preBody = commentsBlock(node.preBodyComments);
|
|
588
716
|
const postParam = commentsBlock(node.postParamComments);
|
|
589
717
|
const procKw = node.type === 'CreateOrAlterProcedureStatement'
|
|
@@ -591,6 +719,26 @@ export function printCreateProcedure(node, opts) {
|
|
|
591
719
|
: node.type === 'AlterProcedureStatement'
|
|
592
720
|
? keyword('ALTER PROCEDURE', opts)
|
|
593
721
|
: keyword('CREATE PROCEDURE', opts);
|
|
722
|
+
// CLR stored procedure: AS EXTERNAL NAME assembly.[class].method
|
|
723
|
+
const externalName = propStr(node, 'externalName');
|
|
724
|
+
if (externalName) {
|
|
725
|
+
return group([
|
|
726
|
+
procKw,
|
|
727
|
+
' ',
|
|
728
|
+
schemaObjectName(prop(node, 'name')),
|
|
729
|
+
preBody,
|
|
730
|
+
parameters.length > 0 ? indent([hardline, join([',', hardline], paramDocs)]) : '',
|
|
731
|
+
postParam,
|
|
732
|
+
printModuleOptions(node, opts),
|
|
733
|
+
hardline,
|
|
734
|
+
keyword('AS', opts),
|
|
735
|
+
' ',
|
|
736
|
+
keyword('EXTERNAL NAME', opts),
|
|
737
|
+
' ',
|
|
738
|
+
externalName,
|
|
739
|
+
';',
|
|
740
|
+
]);
|
|
741
|
+
}
|
|
594
742
|
return group([
|
|
595
743
|
procKw,
|
|
596
744
|
' ',
|
|
@@ -602,7 +750,19 @@ export function printCreateProcedure(node, opts) {
|
|
|
602
750
|
hardline,
|
|
603
751
|
keyword('AS', opts),
|
|
604
752
|
hardline,
|
|
605
|
-
|
|
753
|
+
...(atomicOptions?.length
|
|
754
|
+
? [
|
|
755
|
+
keyword('BEGIN', opts),
|
|
756
|
+
' ',
|
|
757
|
+
keyword('ATOMIC', opts),
|
|
758
|
+
' ',
|
|
759
|
+
keyword('WITH', opts),
|
|
760
|
+
' (',
|
|
761
|
+
indent([hardline, join([',', hardline], atomicOptions)]),
|
|
762
|
+
hardline,
|
|
763
|
+
')',
|
|
764
|
+
]
|
|
765
|
+
: [keyword('BEGIN', opts)]),
|
|
606
766
|
indent([hardline, join([hardline, hardline], bodyDocs)]),
|
|
607
767
|
hardline,
|
|
608
768
|
keyword('END', opts),
|
|
@@ -639,6 +799,25 @@ export function printCreateFunction(node, opts) {
|
|
|
639
799
|
group(['(', parameters.length > 0 ? [indent([softline, join([',', line], paramDocs)]), softline] : '', ')']),
|
|
640
800
|
postParam,
|
|
641
801
|
];
|
|
802
|
+
// CLR function: EXTERNAL NAME assembly.[class].method (no body)
|
|
803
|
+
const externalName = propStr(node, 'externalName');
|
|
804
|
+
if (externalName) {
|
|
805
|
+
return [
|
|
806
|
+
nameAndParamsNoOpts,
|
|
807
|
+
hardline,
|
|
808
|
+
keyword('RETURNS', opts),
|
|
809
|
+
' ',
|
|
810
|
+
keyword(returnType, opts),
|
|
811
|
+
printModuleOptions(node, opts),
|
|
812
|
+
hardline,
|
|
813
|
+
keyword('AS', opts),
|
|
814
|
+
' ',
|
|
815
|
+
keyword('EXTERNAL NAME', opts),
|
|
816
|
+
' ',
|
|
817
|
+
externalName,
|
|
818
|
+
';',
|
|
819
|
+
];
|
|
820
|
+
}
|
|
642
821
|
if (bodyType === 'table') {
|
|
643
822
|
// Inline TVF: RETURNS TABLE [WITH options] AS RETURN (query) — no BEGIN/END
|
|
644
823
|
const queryDoc = body && !Array.isArray(body) ? qexpr(body, opts) : '/* query */';
|
|
@@ -661,7 +840,7 @@ export function printCreateFunction(node, opts) {
|
|
|
661
840
|
];
|
|
662
841
|
}
|
|
663
842
|
// Scalar or multi-statement TVF — both use BEGIN...END
|
|
664
|
-
const stmts = Array.isArray(body) ? body.map((s) => printStatementWithComments(s, opts)) : [];
|
|
843
|
+
const stmts = Array.isArray(body) ? unwrapBodyBlock(body).map((s) => printStatementWithComments(s, opts)) : [];
|
|
665
844
|
const bodyDoc = join([hardline, hardline], stmts);
|
|
666
845
|
let retTypePart;
|
|
667
846
|
if (bodyType === 'inline-table') {
|
|
@@ -757,7 +936,13 @@ export function printCreateTrigger(node, opts) {
|
|
|
757
936
|
: '';
|
|
758
937
|
const notForReplication = propBool(node, 'notForReplication');
|
|
759
938
|
const notForReplicationDoc = notForReplication ? [hardline, keyword('NOT FOR REPLICATION', opts)] : '';
|
|
760
|
-
const bodyDocs = propArr(node, 'body').map((s) => printStatementWithComments(s, opts));
|
|
939
|
+
const bodyDocs = unwrapBodyBlock(propArr(node, 'body')).map((s) => printStatementWithComments(s, opts));
|
|
940
|
+
const triggerScope = propStr(node, 'triggerScope'); // 'Database' or 'Server' for DDL triggers
|
|
941
|
+
const onTarget = triggerScope === 'Database'
|
|
942
|
+
? keyword('DATABASE', opts)
|
|
943
|
+
: triggerScope === 'Server'
|
|
944
|
+
? keyword('ALL SERVER', opts)
|
|
945
|
+
: schemaObjectName(prop(node, 'onName'));
|
|
761
946
|
return [
|
|
762
947
|
kw,
|
|
763
948
|
' ',
|
|
@@ -765,7 +950,7 @@ export function printCreateTrigger(node, opts) {
|
|
|
765
950
|
hardline,
|
|
766
951
|
keyword('ON', opts),
|
|
767
952
|
' ',
|
|
768
|
-
|
|
953
|
+
onTarget,
|
|
769
954
|
hardline,
|
|
770
955
|
typeKw,
|
|
771
956
|
' ',
|
|
@@ -1058,7 +1243,7 @@ export function printCreateColumnStoreIndex(node, opts) {
|
|
|
1058
1243
|
const clustered = node.props?.['clustered'];
|
|
1059
1244
|
const onName = prop(node, 'onName');
|
|
1060
1245
|
const columns = node.props?.['columns'];
|
|
1061
|
-
const
|
|
1246
|
+
const filterPredicateNode = prop(node, 'filterPredicate');
|
|
1062
1247
|
const options = node.props?.['options'];
|
|
1063
1248
|
const clusterKw = clustered === true
|
|
1064
1249
|
? [keyword('CLUSTERED', opts), ' ']
|
|
@@ -1070,8 +1255,8 @@ export function printCreateColumnStoreIndex(node, opts) {
|
|
|
1070
1255
|
if (columns?.length) {
|
|
1071
1256
|
parts.push([' ', parenList(columns)]);
|
|
1072
1257
|
}
|
|
1073
|
-
if (
|
|
1074
|
-
parts.push([hardline,
|
|
1258
|
+
if (filterPredicateNode)
|
|
1259
|
+
parts.push([hardline, printBoolClause('WHERE', filterPredicateNode, opts)]);
|
|
1075
1260
|
if (options?.length) {
|
|
1076
1261
|
parts.push([
|
|
1077
1262
|
hardline,
|
|
@@ -1119,15 +1304,15 @@ export function printCreateStatistics(node, opts) {
|
|
|
1119
1304
|
const name = propStr(node, 'name') ?? '';
|
|
1120
1305
|
const onName = prop(node, 'onName');
|
|
1121
1306
|
const columns = node.props?.['columns'];
|
|
1122
|
-
const
|
|
1307
|
+
const filterPredicateNode = prop(node, 'filterPredicate');
|
|
1123
1308
|
const options = node.props?.['options'];
|
|
1124
1309
|
const parts = [keyword('CREATE STATISTICS', opts), ' ', name];
|
|
1125
1310
|
parts.push([hardline, keyword('ON', opts), ' ', onName ? schemaObjectName(onName) : '']);
|
|
1126
1311
|
if (columns?.length) {
|
|
1127
1312
|
parts.push([' ', parenList(columns)]);
|
|
1128
1313
|
}
|
|
1129
|
-
if (
|
|
1130
|
-
parts.push([hardline,
|
|
1314
|
+
if (filterPredicateNode)
|
|
1315
|
+
parts.push([hardline, printBoolClause('WHERE', filterPredicateNode, opts)]);
|
|
1131
1316
|
if (options?.length)
|
|
1132
1317
|
parts.push([hardline, withOptionsClause(options, opts)]);
|
|
1133
1318
|
parts.push(';');
|