prettier-plugin-tsql 0.6.5 → 0.6.7
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/Microsoft.SqlServer.TransactSql.ScriptDom.dll +0 -0
- package/bin/dotnet/PrettierSql.Core.dll +0 -0
- package/bin/dotnet/SqlScriptDom.deps.json +7 -7
- package/bin/dotnet/SqlScriptDom.dll +0 -0
- package/dist/_core/printer/helpers.js +6 -0
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +7 -7
- package/dist/parser/index.js.map +1 -1
- package/dist/printer/admin.js.map +1 -1
- package/dist/printer/ddl.d.ts +1 -0
- package/dist/printer/ddl.d.ts.map +1 -1
- package/dist/printer/ddl.js +88 -60
- package/dist/printer/ddl.js.map +1 -1
- package/dist/printer/expressions.d.ts +8 -8
- package/dist/printer/expressions.d.ts.map +1 -1
- package/dist/printer/expressions.js +170 -149
- package/dist/printer/expressions.js.map +1 -1
- package/dist/printer/helpers.d.ts +2 -2
- package/dist/printer/helpers.d.ts.map +1 -1
- package/dist/printer/helpers.js +14 -14
- package/dist/printer/helpers.js.map +1 -1
- package/dist/printer/procedural.d.ts.map +1 -1
- package/dist/printer/procedural.js +7 -1
- package/dist/printer/procedural.js.map +1 -1
- package/dist/printer/statements.d.ts.map +1 -1
- package/dist/printer/statements.js +26 -3
- package/dist/printer/statements.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
import { keyword, getDensity, hardSep, softSep, hardline, join, group, indent, line, softline, fill, appendTrailingLines, parenList, aliasDoc, } from '../_core/printer/utils.js';
|
|
2
2
|
import { prop, propArr, propStr, propBool, schemaObjectName, assignmentOp } from './helpers.js';
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
+
// Module-level lookup tables (created once, not per call)
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
const BINARY_OP_MAP = {
|
|
7
|
+
Add: '+',
|
|
8
|
+
Subtract: '-',
|
|
9
|
+
Multiply: '*',
|
|
10
|
+
Divide: '/',
|
|
11
|
+
Modulo: '%',
|
|
12
|
+
BitwiseAnd: '&',
|
|
13
|
+
BitwiseOr: '|',
|
|
14
|
+
BitwiseXor: '^',
|
|
15
|
+
Concatenate: '+',
|
|
16
|
+
Concat: '||',
|
|
17
|
+
};
|
|
18
|
+
const CMP_OP_MAP = {
|
|
19
|
+
Equals: '=',
|
|
20
|
+
NotEqualToBrackets: '<>',
|
|
21
|
+
NotEqualToExclamation: '!=',
|
|
22
|
+
GreaterThan: '>',
|
|
23
|
+
LessThan: '<',
|
|
24
|
+
GreaterThanOrEqualTo: '>=',
|
|
25
|
+
LessThanOrEqualTo: '<=',
|
|
26
|
+
LeftOuterJoin: '*=',
|
|
27
|
+
RightOuterJoin: '=*',
|
|
28
|
+
NotLessThan: '!<',
|
|
29
|
+
NotGreaterThan: '!>',
|
|
30
|
+
};
|
|
31
|
+
const JOIN_TYPE_MAP = {
|
|
32
|
+
Inner: 'INNER JOIN',
|
|
33
|
+
LeftOuter: 'LEFT JOIN',
|
|
34
|
+
RightOuter: 'RIGHT JOIN',
|
|
35
|
+
FullOuter: 'FULL JOIN',
|
|
36
|
+
};
|
|
37
|
+
const JOIN_TYPE_WORD = {
|
|
38
|
+
Inner: 'INNER',
|
|
39
|
+
LeftOuter: 'LEFT',
|
|
40
|
+
RightOuter: 'RIGHT',
|
|
41
|
+
FullOuter: 'FULL',
|
|
42
|
+
};
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
4
44
|
// Scalar expressions
|
|
5
45
|
// ---------------------------------------------------------------------------
|
|
6
46
|
export function printExpression(node, opts, printFn) {
|
|
@@ -261,16 +301,25 @@ function printFunctionCall(node, opts, printFn) {
|
|
|
261
301
|
}
|
|
262
302
|
return argsDoc;
|
|
263
303
|
}
|
|
264
|
-
// Flatten a left-recursive
|
|
304
|
+
// Flatten a left-recursive chain of the given operators into leaf terms.
|
|
265
305
|
// Stops at any other operator so e.g. the `a * b` in `a * b + c` stays grouped.
|
|
266
|
-
|
|
306
|
+
// Keeping ops separate (Add/Concatenate vs Concat) prevents mixing + and || chains.
|
|
307
|
+
function collectBinaryChain(node, ...ops) {
|
|
267
308
|
const op = propStr(node, 'operator');
|
|
268
|
-
if (node.type !== 'BinaryExpression' || (op
|
|
309
|
+
if (node.type !== 'BinaryExpression' || !ops.includes(op ?? '')) {
|
|
269
310
|
return [node];
|
|
270
311
|
}
|
|
271
312
|
const left = prop(node, 'left');
|
|
272
313
|
const right = prop(node, 'right');
|
|
273
|
-
return [...(left ?
|
|
314
|
+
return [...(left ? collectBinaryChain(left, ...ops) : []), ...(right ? [right] : [])];
|
|
315
|
+
}
|
|
316
|
+
function buildFillChain(termDocs, sep) {
|
|
317
|
+
const parts = [termDocs[0]];
|
|
318
|
+
for (let i = 1; i < termDocs.length; i++) {
|
|
319
|
+
parts.push(indent([line, sep]));
|
|
320
|
+
parts.push(termDocs[i]);
|
|
321
|
+
}
|
|
322
|
+
return fill(parts);
|
|
274
323
|
}
|
|
275
324
|
function printBinaryExpr(node, opts, printFn) {
|
|
276
325
|
const op = propStr(node, 'operator') ?? '+';
|
|
@@ -279,14 +328,13 @@ function printBinaryExpr(node, opts, printFn) {
|
|
|
279
328
|
// term would overflow. Flat: "a + b + c". Filling: "a + b\n+ c + d".
|
|
280
329
|
// This prevents Prettier from descending into function args to break there.
|
|
281
330
|
if (op === 'Add' || op === 'Concatenate') {
|
|
282
|
-
const terms =
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return fill(parts);
|
|
331
|
+
const terms = collectBinaryChain(node, 'Add', 'Concatenate');
|
|
332
|
+
return buildFillChain(terms.map((t) => printExpression(t, opts, printFn)), '+ ');
|
|
333
|
+
}
|
|
334
|
+
// || chains work the same way but keep their own operator symbol.
|
|
335
|
+
if (op === 'Concat') {
|
|
336
|
+
const terms = collectBinaryChain(node, 'Concat');
|
|
337
|
+
return buildFillChain(terms.map((t) => printExpression(t, opts, printFn)), '|| ');
|
|
290
338
|
}
|
|
291
339
|
const left = prop(node, 'left');
|
|
292
340
|
const right = prop(node, 'right');
|
|
@@ -300,18 +348,7 @@ function printBinaryExpr(node, opts, printFn) {
|
|
|
300
348
|
]);
|
|
301
349
|
}
|
|
302
350
|
function mapBinaryOp(op) {
|
|
303
|
-
|
|
304
|
-
Add: '+',
|
|
305
|
-
Subtract: '-',
|
|
306
|
-
Multiply: '*',
|
|
307
|
-
Divide: '/',
|
|
308
|
-
Modulo: '%',
|
|
309
|
-
BitwiseAnd: '&',
|
|
310
|
-
BitwiseOr: '|',
|
|
311
|
-
BitwiseXor: '^',
|
|
312
|
-
Concatenate: '+',
|
|
313
|
-
};
|
|
314
|
-
return map[op] ?? op;
|
|
351
|
+
return BINARY_OP_MAP[op] ?? op;
|
|
315
352
|
}
|
|
316
353
|
function printUnaryExpr(node, opts, printFn) {
|
|
317
354
|
const expr = prop(node, 'expr');
|
|
@@ -511,6 +548,8 @@ export function printQueryExpression(node, opts, printFn) {
|
|
|
511
548
|
}
|
|
512
549
|
function printQuerySpec(node, opts, printFn) {
|
|
513
550
|
const density = getDensity(opts);
|
|
551
|
+
const compact = density === 'compact';
|
|
552
|
+
const sep = compact ? line : hardline;
|
|
514
553
|
const uniqueRowFilter = propStr(node, 'uniqueRowFilter');
|
|
515
554
|
const top = prop(node, 'top');
|
|
516
555
|
const selectElements = propArr(node, 'selectElements');
|
|
@@ -528,17 +567,16 @@ function printQuerySpec(node, opts, printFn) {
|
|
|
528
567
|
const selectKw = uniqueRowFilter === 'Distinct' ? keyword('SELECT DISTINCT', opts) : keyword('SELECT', opts);
|
|
529
568
|
const topDoc = top ? printTop(top, opts, printFn) : null;
|
|
530
569
|
const colDocs = selectElements.map((se) => printExpression(se, opts, printFn));
|
|
531
|
-
|
|
570
|
+
const parts = [selectKw, ...(topDoc ? [' ', topDoc] : [])];
|
|
571
|
+
if (compact) {
|
|
532
572
|
// Compact: fill-pack each list clause — as many items per line as fit, wrapping only when needed.
|
|
533
573
|
// indent() ensures wrapped lines are indented one level under the keyword.
|
|
534
574
|
const colList = indent(fill(colDocs.flatMap((d, i) => (i === 0 ? [d] : [[',', line], d]))));
|
|
535
|
-
|
|
536
|
-
if (intoTarget)
|
|
575
|
+
parts.push(' ', colList);
|
|
576
|
+
if (intoTarget)
|
|
537
577
|
parts.push(line, keyword('INTO', opts), ' ', schemaObjectName(intoTarget));
|
|
538
|
-
}
|
|
539
578
|
if (from) {
|
|
540
|
-
const
|
|
541
|
-
const fromDocs = tableRefs.map((tr) => printTableRef(tr, opts, printFn));
|
|
579
|
+
const fromDocs = propArr(from, 'tableReferences').map((tr) => printTableRef(tr, opts, printFn));
|
|
542
580
|
// Try to keep FROM on one line; if too long, each join on its own line
|
|
543
581
|
parts.push(line, keyword('FROM', opts), ' ', group(indent(join(softSep(opts), fromDocs))));
|
|
544
582
|
}
|
|
@@ -547,108 +585,89 @@ function printQuerySpec(node, opts, printFn) {
|
|
|
547
585
|
parts.push(line, keyword('WHERE', opts), group([indent([line, boolWithTrailing(where, fillBoolChain(where, opts, printFn))])]));
|
|
548
586
|
}
|
|
549
587
|
if (groupBy) {
|
|
550
|
-
const
|
|
551
|
-
const elemDocs = elems.map((e) => printExpression(e, opts, printFn));
|
|
588
|
+
const elemDocs = propArr(groupBy, 'elements').map((e) => printExpression(e, opts, printFn));
|
|
552
589
|
parts.push(line, keyword('GROUP BY', opts), ' ', indent(fill(elemDocs.flatMap((d, i) => (i === 0 ? [d] : [[',', line], d])))));
|
|
553
590
|
}
|
|
554
591
|
if (having) {
|
|
555
592
|
parts.push(line, keyword('HAVING', opts), group([indent([line, boolWithTrailing(having, fillBoolChain(having, opts, printFn))])]));
|
|
556
593
|
}
|
|
557
|
-
if (orderBy) {
|
|
558
|
-
parts.push(line, printOrderByClause(orderBy, opts, printFn));
|
|
559
|
-
}
|
|
560
|
-
if (offsetNode) {
|
|
561
|
-
parts.push(line, keyword('OFFSET', opts), ' ', printExpression(offsetNode, opts, printFn), ' ', keyword('ROWS', opts));
|
|
562
|
-
if (fetchNode) {
|
|
563
|
-
parts.push(line, keyword('FETCH NEXT', opts), ' ', printExpression(fetchNode, opts, printFn), ' ', keyword('ROWS ONLY', opts));
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
if (windowDefs.length > 0) {
|
|
567
|
-
parts.push(line, printWindowClause(windowDefs, opts, printFn));
|
|
568
|
-
}
|
|
569
|
-
if (forClause) {
|
|
570
|
-
parts.push(line, printForClause(forClause, opts));
|
|
571
|
-
}
|
|
572
|
-
return group(parts);
|
|
573
|
-
}
|
|
574
|
-
// Standard / Spacious: single column stays inline; multiple each on own line.
|
|
575
|
-
// A CASE expression always expands to multiple lines, so force it onto its own indented line.
|
|
576
|
-
const singleExprType = (prop(selectElements[0], 'expression') ?? selectElements[0])?.type;
|
|
577
|
-
const colList = density === 'standard' && colDocs.length === 1 && singleExprType !== 'CaseExpression'
|
|
578
|
-
? [' ', colDocs[0]]
|
|
579
|
-
: indent([hardline, join(hardSep(opts), colDocs)]);
|
|
580
|
-
const parts = [selectKw, ...(topDoc ? [' ', topDoc] : []), colList];
|
|
581
|
-
// SELECT INTO target appears after the column list and before the FROM clause
|
|
582
|
-
if (intoTarget) {
|
|
583
|
-
parts.push(hardline, keyword('INTO', opts), ' ', schemaObjectName(intoTarget));
|
|
584
|
-
}
|
|
585
|
-
if (from) {
|
|
586
|
-
const tableRefs = propArr(from, 'tableReferences');
|
|
587
|
-
const fromDocs = tableRefs.map((tr) => printTableRef(tr, opts, printFn));
|
|
588
|
-
// standard: single table (no joins) stays inline; multiple/joins each on own line
|
|
589
|
-
// InlineDerivedTable uses a softline so it stays inline when it fits but breaks
|
|
590
|
-
// FROM onto its own line (with the values block indented) when it doesn't
|
|
591
|
-
const singleTable = density === 'standard' &&
|
|
592
|
-
tableRefs.length === 1 &&
|
|
593
|
-
tableRefs[0].type !== 'QualifiedJoin' &&
|
|
594
|
-
tableRefs[0].type !== 'UnqualifiedJoin' &&
|
|
595
|
-
tableRefs[0].type !== 'InlineDerivedTable';
|
|
596
|
-
if (tableRefs.length === 1 && tableRefs[0].type === 'InlineDerivedTable') {
|
|
597
|
-
parts.push(hardline, group([keyword('FROM', opts), indent([line, fromDocs[0]])]));
|
|
598
|
-
}
|
|
599
|
-
else if (singleTable) {
|
|
600
|
-
parts.push(hardline, keyword('FROM', opts), ' ', fromDocs[0]);
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
parts.push(hardline, keyword('FROM', opts), indent([hardline, join(hardSep(opts), fromDocs)]));
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
if (where) {
|
|
607
|
-
// standard: single predicate inline; multiple each on own line
|
|
608
|
-
// spacious: always indented
|
|
609
|
-
const inline = density === 'standard' && where.type !== 'BooleanBinary';
|
|
610
|
-
if (inline) {
|
|
611
|
-
parts.push(hardline, keyword('WHERE', opts), ' ', boolWithTrailing(where, printBoolExpr(where, opts, printFn)));
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
parts.push(hardline, keyword('WHERE', opts), indent([hardline, boolWithTrailing(where, printBoolExpr(where, opts, printFn))]));
|
|
615
|
-
}
|
|
616
594
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
595
|
+
else {
|
|
596
|
+
// Standard / Spacious: single column stays inline; multiple each on own line.
|
|
597
|
+
// A CASE expression always expands to multiple lines, so force it onto its own indented line.
|
|
598
|
+
const singleExprType = (prop(selectElements[0], 'expression') ?? selectElements[0])?.type;
|
|
599
|
+
const colList = density === 'standard' && colDocs.length === 1 && singleExprType !== 'CaseExpression'
|
|
600
|
+
? [' ', colDocs[0]]
|
|
601
|
+
: indent([hardline, join(hardSep(opts), colDocs)]);
|
|
602
|
+
parts.push(colList);
|
|
603
|
+
// SELECT INTO target appears after the column list and before the FROM clause
|
|
604
|
+
if (intoTarget)
|
|
605
|
+
parts.push(hardline, keyword('INTO', opts), ' ', schemaObjectName(intoTarget));
|
|
606
|
+
if (from) {
|
|
607
|
+
const tableRefs = propArr(from, 'tableReferences');
|
|
608
|
+
const fromDocs = tableRefs.map((tr) => printTableRef(tr, opts, printFn));
|
|
609
|
+
// standard: single table (no joins) stays inline; multiple/joins each on own line
|
|
610
|
+
// InlineDerivedTable uses a softline so it stays inline when it fits but breaks
|
|
611
|
+
// FROM onto its own line (with the values block indented) when it doesn't
|
|
612
|
+
const singleTable = density === 'standard' &&
|
|
613
|
+
tableRefs.length === 1 &&
|
|
614
|
+
tableRefs[0].type !== 'QualifiedJoin' &&
|
|
615
|
+
tableRefs[0].type !== 'UnqualifiedJoin' &&
|
|
616
|
+
tableRefs[0].type !== 'InlineDerivedTable';
|
|
617
|
+
if (tableRefs.length === 1 && tableRefs[0].type === 'InlineDerivedTable') {
|
|
618
|
+
parts.push(hardline, group([keyword('FROM', opts), indent([line, fromDocs[0]])]));
|
|
619
|
+
}
|
|
620
|
+
else if (singleTable) {
|
|
621
|
+
parts.push(hardline, keyword('FROM', opts), ' ', fromDocs[0]);
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
parts.push(hardline, keyword('FROM', opts), indent([hardline, join(hardSep(opts), fromDocs)]));
|
|
625
|
+
}
|
|
623
626
|
}
|
|
624
|
-
|
|
625
|
-
|
|
627
|
+
if (where) {
|
|
628
|
+
// standard: single predicate inline; multiple each on own line
|
|
629
|
+
// spacious: always indented
|
|
630
|
+
const inline = density === 'standard' && where.type !== 'BooleanBinary';
|
|
631
|
+
if (inline) {
|
|
632
|
+
parts.push(hardline, keyword('WHERE', opts), ' ', boolWithTrailing(where, printBoolExpr(where, opts, printFn)));
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
parts.push(hardline, keyword('WHERE', opts), indent([hardline, boolWithTrailing(where, printBoolExpr(where, opts, printFn))]));
|
|
636
|
+
}
|
|
626
637
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
638
|
+
if (groupBy) {
|
|
639
|
+
const elems = propArr(groupBy, 'elements');
|
|
640
|
+
const elemDocs = elems.map((e) => printExpression(e, opts, printFn));
|
|
641
|
+
if (density === 'standard' && elems.length === 1) {
|
|
642
|
+
parts.push(hardline, keyword('GROUP BY', opts), ' ', elemDocs[0]);
|
|
643
|
+
}
|
|
644
|
+
else {
|
|
645
|
+
parts.push(hardline, keyword('GROUP BY', opts), indent([hardline, join(hardSep(opts), elemDocs)]));
|
|
646
|
+
}
|
|
632
647
|
}
|
|
633
|
-
|
|
634
|
-
|
|
648
|
+
if (having) {
|
|
649
|
+
const inline = density === 'standard' && having.type !== 'BooleanBinary';
|
|
650
|
+
if (inline) {
|
|
651
|
+
parts.push(hardline, keyword('HAVING', opts), ' ', boolWithTrailing(having, printBoolExpr(having, opts, printFn)));
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
parts.push(hardline, keyword('HAVING', opts), indent([hardline, boolWithTrailing(having, printBoolExpr(having, opts, printFn))]));
|
|
655
|
+
}
|
|
635
656
|
}
|
|
636
657
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
658
|
+
// Tail clauses — same layout intent for all densities, sep varies
|
|
659
|
+
if (orderBy)
|
|
660
|
+
parts.push(sep, printOrderByClause(orderBy, opts, printFn));
|
|
640
661
|
if (offsetNode) {
|
|
641
|
-
parts.push(
|
|
662
|
+
parts.push(sep, keyword('OFFSET', opts), ' ', printExpression(offsetNode, opts, printFn), ' ', keyword('ROWS', opts));
|
|
642
663
|
if (fetchNode) {
|
|
643
|
-
parts.push(
|
|
664
|
+
parts.push(sep, keyword('FETCH NEXT', opts), ' ', printExpression(fetchNode, opts, printFn), ' ', keyword('ROWS ONLY', opts));
|
|
644
665
|
}
|
|
645
666
|
}
|
|
646
|
-
if (windowDefs.length > 0)
|
|
647
|
-
parts.push(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
parts.push(hardline, printForClause(forClause, opts));
|
|
651
|
-
}
|
|
667
|
+
if (windowDefs.length > 0)
|
|
668
|
+
parts.push(sep, printWindowClause(windowDefs, opts, printFn));
|
|
669
|
+
if (forClause)
|
|
670
|
+
parts.push(sep, printForClause(forClause, opts));
|
|
652
671
|
return group(parts);
|
|
653
672
|
}
|
|
654
673
|
function printTop(node, opts, printFn) {
|
|
@@ -833,25 +852,14 @@ export function printBoolExpr(node, opts, printFn) {
|
|
|
833
852
|
return printDistinctPredicate(node, opts, printFn);
|
|
834
853
|
case 'SubqueryComparisonPredicate':
|
|
835
854
|
return printSubqueryComparison(node, opts, printFn);
|
|
855
|
+
case 'RegexpLikePredicate':
|
|
856
|
+
return printRegexpLikePredicate(node, opts, printFn);
|
|
836
857
|
default:
|
|
837
858
|
return node.text ?? `/* ${node.type} */`;
|
|
838
859
|
}
|
|
839
860
|
}
|
|
840
861
|
function cmpOp(op) {
|
|
841
|
-
|
|
842
|
-
Equals: '=',
|
|
843
|
-
NotEqualToBrackets: '<>',
|
|
844
|
-
NotEqualToExclamation: '!=',
|
|
845
|
-
GreaterThan: '>',
|
|
846
|
-
LessThan: '<',
|
|
847
|
-
GreaterThanOrEqualTo: '>=',
|
|
848
|
-
LessThanOrEqualTo: '<=',
|
|
849
|
-
LeftOuterJoin: '*=',
|
|
850
|
-
RightOuterJoin: '=*',
|
|
851
|
-
NotLessThan: '!<',
|
|
852
|
-
NotGreaterThan: '!>',
|
|
853
|
-
};
|
|
854
|
-
return map[op] ?? op;
|
|
862
|
+
return CMP_OP_MAP[op] ?? op;
|
|
855
863
|
}
|
|
856
864
|
function printBoolComparison(node, opts, printFn) {
|
|
857
865
|
const left = prop(node, 'left');
|
|
@@ -1006,6 +1014,16 @@ function printInPredicate(node, opts, printFn) {
|
|
|
1006
1014
|
const valueDocs = values.map((v) => printExpression(v, opts, printFn));
|
|
1007
1015
|
return [...lhs, group([' (', indent([softline, join([',', line], valueDocs)]), softline, ')'])];
|
|
1008
1016
|
}
|
|
1017
|
+
function printRegexpLikePredicate(node, opts, printFn) {
|
|
1018
|
+
const args = [
|
|
1019
|
+
prop(node, 'value') ? printExpression(prop(node, 'value'), opts, printFn) : '',
|
|
1020
|
+
prop(node, 'pattern') ? printExpression(prop(node, 'pattern'), opts, printFn) : '',
|
|
1021
|
+
];
|
|
1022
|
+
const flags = prop(node, 'flags');
|
|
1023
|
+
if (flags)
|
|
1024
|
+
args.push(printExpression(flags, opts, printFn));
|
|
1025
|
+
return [keyword('regexp_like', opts), parenList(args)];
|
|
1026
|
+
}
|
|
1009
1027
|
function printLikePredicate(node, opts, printFn) {
|
|
1010
1028
|
const expr = prop(node, 'expr');
|
|
1011
1029
|
const pattern = prop(node, 'pattern');
|
|
@@ -1028,12 +1046,26 @@ function printExistsPredicate(node, opts, printFn) {
|
|
|
1028
1046
|
const subquery = prop(node, 'subquery');
|
|
1029
1047
|
if (!subquery)
|
|
1030
1048
|
return keyword('EXISTS', opts) + '()';
|
|
1031
|
-
const
|
|
1049
|
+
const density = getDensity(opts);
|
|
1050
|
+
if (density === 'spacious') {
|
|
1051
|
+
// Spacious: always expand
|
|
1052
|
+
return group([
|
|
1053
|
+
keyword('EXISTS', opts),
|
|
1054
|
+
' (',
|
|
1055
|
+
indent([hardline, printQueryExpression(subquery, opts, printFn)]),
|
|
1056
|
+
hardline,
|
|
1057
|
+
')',
|
|
1058
|
+
]);
|
|
1059
|
+
}
|
|
1060
|
+
// compact + standard: render the inner query in compact mode so the group's
|
|
1061
|
+
// softline can keep simple subqueries inline. Complex ones still wrap because
|
|
1062
|
+
// their content exceeds printWidth and the group breaks.
|
|
1063
|
+
const compactOpts = { ...opts, sqlDensity: 'compact' };
|
|
1032
1064
|
return group([
|
|
1033
1065
|
keyword('EXISTS', opts),
|
|
1034
1066
|
' (',
|
|
1035
|
-
indent([
|
|
1036
|
-
|
|
1067
|
+
indent([softline, printQueryExpression(subquery, compactOpts, printFn)]),
|
|
1068
|
+
softline,
|
|
1037
1069
|
')',
|
|
1038
1070
|
]);
|
|
1039
1071
|
}
|
|
@@ -1130,22 +1162,11 @@ function printNamedTableRef(node, opts, printFn) {
|
|
|
1130
1162
|
return [nameDoc, temporalDoc, aliasPart, sampleDoc, hintsDoc];
|
|
1131
1163
|
}
|
|
1132
1164
|
function joinTypeKeyword(jt, opts, hint) {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
LeftOuter: 'LEFT',
|
|
1136
|
-
RightOuter: 'RIGHT',
|
|
1137
|
-
FullOuter: 'FULL',
|
|
1138
|
-
};
|
|
1139
|
-
const typeWord = typeMap[jt] ?? jt.toUpperCase();
|
|
1140
|
-
if (hint)
|
|
1165
|
+
if (hint) {
|
|
1166
|
+
const typeWord = JOIN_TYPE_WORD[jt] ?? jt.toUpperCase();
|
|
1141
1167
|
return keyword(`${typeWord} ${hint} JOIN`, opts);
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
LeftOuter: 'LEFT JOIN',
|
|
1145
|
-
RightOuter: 'RIGHT JOIN',
|
|
1146
|
-
FullOuter: 'FULL JOIN',
|
|
1147
|
-
};
|
|
1148
|
-
return keyword(noHintMap[jt] ?? `${typeWord} JOIN`, opts);
|
|
1168
|
+
}
|
|
1169
|
+
return keyword(JOIN_TYPE_MAP[jt] ?? `${(JOIN_TYPE_WORD[jt] ?? jt.toUpperCase())} JOIN`, opts);
|
|
1149
1170
|
}
|
|
1150
1171
|
/**
|
|
1151
1172
|
* Walk the rightmost path of an AST subtree (props in reverse insertion order)
|