prettier-plugin-postgresql 0.1.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 +197 -0
- package/bin/dotnet/Google.Protobuf.dll +0 -0
- package/bin/dotnet/PgScriptDom.deps.json +95 -0
- package/bin/dotnet/PgScriptDom.dll +0 -0
- package/bin/dotnet/PrettierSql.Core.dll +0 -0
- package/bin/dotnet/libpg_query.dylib +0 -0
- package/bin/dotnet/pgsqlparser.dll +0 -0
- package/bin/dotnet/runtimes/linux-x64/native/libpg_query.so +0 -0
- package/bin/dotnet/runtimes/osx-arm64/native/libpg_query.dylib +0 -0
- package/bin/dotnet/runtimes/osx-x64/native/libpg_query.dylib +0 -0
- package/bin/dotnet/runtimes/win-x64/native/libpg_query.dll +0 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/language.d.ts +3 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +9 -0
- package/dist/language.js.map +1 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +58 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/printer/expressions.d.ts +8 -0
- package/dist/printer/expressions.d.ts.map +1 -0
- package/dist/printer/expressions.js +623 -0
- package/dist/printer/expressions.js.map +1 -0
- package/dist/printer/helpers.d.ts +6 -0
- package/dist/printer/helpers.d.ts.map +1 -0
- package/dist/printer/helpers.js +18 -0
- package/dist/printer/helpers.js.map +1 -0
- package/dist/printer/index.d.ts +4 -0
- package/dist/printer/index.d.ts.map +1 -0
- package/dist/printer/index.js +23 -0
- package/dist/printer/index.js.map +1 -0
- package/dist/printer/statements.d.ts +11 -0
- package/dist/printer/statements.d.ts.map +1 -0
- package/dist/printer/statements.js +1533 -0
- package/dist/printer/statements.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
import { keyword, join, indent, hardline, aliasDoc } from '@prettier-sql/core/printer/utils';
|
|
2
|
+
import { printStatement, printQueryExpr } from './statements.js';
|
|
3
|
+
import { prop, propArr, propStr, propBool, rangeVarName } from './helpers.js';
|
|
4
|
+
export function printExpression(node, opts, printNode) {
|
|
5
|
+
switch (node.type) {
|
|
6
|
+
case 'SelectStatement': return printQueryExpr(node, opts);
|
|
7
|
+
case 'SetOpStatement': return printQueryExpr(node, opts);
|
|
8
|
+
case 'ValuesStatement': return printStatement(node, opts);
|
|
9
|
+
case 'Literal': return node.text ?? '';
|
|
10
|
+
case 'ColumnRef': return propStr(node, 'name') ?? '';
|
|
11
|
+
case 'BinaryExpr': return printBinaryExpr(node, opts, printNode);
|
|
12
|
+
case 'BoolExpr': return printBoolExpr(node, opts, printNode);
|
|
13
|
+
case 'FunctionCall': return printFunctionCall(node, opts, printNode);
|
|
14
|
+
case 'Cast': return printCast(node, opts, printNode);
|
|
15
|
+
case 'SubLink': return printSubLink(node, opts, printNode);
|
|
16
|
+
case 'CaseExpr': return printCaseExpr(node, opts, printNode);
|
|
17
|
+
case 'NullTest': return printNullTest(node, opts, printNode);
|
|
18
|
+
case 'BooleanTest': return printBooleanTest(node, opts, printNode);
|
|
19
|
+
case 'ResTarget': return printResTarget(node, opts, printNode);
|
|
20
|
+
case 'RangeVar': return printRangeVar(node, opts);
|
|
21
|
+
case 'JoinExpr': return printJoinExpr(node, opts, printNode);
|
|
22
|
+
case 'Subquery': return printSubquery(node, opts, printNode);
|
|
23
|
+
case 'RangeFunction': return printRangeFunction(node, opts, printNode);
|
|
24
|
+
case 'SortItem': return printSortItem(node, opts, printNode);
|
|
25
|
+
case 'ColumnDef': return printColumnDef(node, opts, printNode);
|
|
26
|
+
case 'Constraint': return printConstraint(node, opts, printNode);
|
|
27
|
+
case 'AlterCmd': return printAlterCmd(node, opts, printNode);
|
|
28
|
+
case 'FunctionParam': return printFunctionParam(node, opts);
|
|
29
|
+
case 'IndexElem': {
|
|
30
|
+
const expr = prop(node, 'expr');
|
|
31
|
+
const direction = propStr(node, 'direction');
|
|
32
|
+
const name = propStr(node, 'name');
|
|
33
|
+
const base = expr ? printNode(expr) : (name ?? '');
|
|
34
|
+
return direction ? [base, ' ', keyword(direction, opts)] : base;
|
|
35
|
+
}
|
|
36
|
+
case 'ExprList': return join(', ', propArr(node, 'items').map(printNode));
|
|
37
|
+
case 'ArrayExpr': return printArrayExpr(node, opts, printNode);
|
|
38
|
+
case 'Coalesce': return printCoalesce(node, opts, printNode);
|
|
39
|
+
case 'RowExpr': return ['(', join(', ', propArr(node, 'args').map(printNode)), ')'];
|
|
40
|
+
case 'ParamRef': return node.text ?? '$?';
|
|
41
|
+
case 'SqlvalueFunction': return keyword(node.text ?? '', opts);
|
|
42
|
+
case 'CTE': return printCteInline(node, opts, printNode);
|
|
43
|
+
case 'WithClause': return '';
|
|
44
|
+
case 'InExpr': return printInExpr(node, opts, printNode);
|
|
45
|
+
case 'BetweenExpr': return printBetweenExpr(node, opts, printNode);
|
|
46
|
+
case 'QuantifiedExpr': return printQuantifiedExpr(node, opts, printNode);
|
|
47
|
+
case 'Subscript': return printSubscript(node, opts, printNode);
|
|
48
|
+
case 'NamedArg': return printNamedArg(node, opts, printNode);
|
|
49
|
+
case 'GroupingSet': return printGroupingSet(node, opts, printNode);
|
|
50
|
+
case 'GroupingFunc': return printGroupingFunc(node, opts, printNode);
|
|
51
|
+
case 'IntervalLiteral': return printIntervalLiteral(node, opts, printNode);
|
|
52
|
+
case 'RangeTableSample': return printRangeTableSample(node, opts, printNode);
|
|
53
|
+
case 'TableLikeClause': return printTableLikeClause(node, opts);
|
|
54
|
+
case 'XmlExpr': return printXmlExpr(node, opts, printNode);
|
|
55
|
+
case 'JsonFuncExpr': return printJsonFuncExpr(node, opts, printNode);
|
|
56
|
+
default: return node.text ?? `/* unknown: ${node.type} */`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Expressions
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
function printBinaryExpr(node, opts, printNode) {
|
|
63
|
+
const left = prop(node, 'left');
|
|
64
|
+
const right = prop(node, 'right');
|
|
65
|
+
const op = propStr(node, 'op') ?? '?';
|
|
66
|
+
const opDoc = /^[A-Z]/.test(op) ? keyword(op, opts) : op;
|
|
67
|
+
return [left ? printNode(left) : '', ' ', opDoc, ' ', right ? printNode(right) : ''];
|
|
68
|
+
}
|
|
69
|
+
function printBoolExpr(node, opts, printNode) {
|
|
70
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
71
|
+
const op = propStr(node, 'op') ?? 'AND';
|
|
72
|
+
const args = propArr(node, 'args');
|
|
73
|
+
if (op === 'NOT') {
|
|
74
|
+
const arg = args[0];
|
|
75
|
+
return [makeKeyword('NOT'), ' ', arg ? printNode(arg) : ''];
|
|
76
|
+
}
|
|
77
|
+
return join([hardline, makeKeyword(op), ' '], args.map(printNode));
|
|
78
|
+
}
|
|
79
|
+
function printFunctionCall(node, opts, printNode) {
|
|
80
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
81
|
+
const rawName = propStr(node, 'name') ?? '';
|
|
82
|
+
const args = propArr(node, 'args');
|
|
83
|
+
const star = propBool(node, 'star');
|
|
84
|
+
const distinct = propBool(node, 'distinct');
|
|
85
|
+
const aggOrder = propArr(node, 'aggOrder');
|
|
86
|
+
const filter = prop(node, 'filter');
|
|
87
|
+
const over = prop(node, 'over');
|
|
88
|
+
// SQL standard keyword-form functions — reconstruct readable syntax
|
|
89
|
+
if (rawName.startsWith('pg_catalog.')) {
|
|
90
|
+
const local = rawName.slice('pg_catalog.'.length);
|
|
91
|
+
switch (local) {
|
|
92
|
+
case 'substring': return printSubstringForm(args, opts, printNode);
|
|
93
|
+
case 'extract': return printExtractForm(args, opts, printNode);
|
|
94
|
+
case 'ltrim': return printTrimForm(args, 'LEADING', opts, printNode);
|
|
95
|
+
case 'rtrim': return printTrimForm(args, 'TRAILING', opts, printNode);
|
|
96
|
+
case 'btrim': return printTrimForm(args, 'BOTH', opts, printNode);
|
|
97
|
+
case 'position': return printPositionForm(args, opts, printNode);
|
|
98
|
+
case 'timezone': return printAtTimeZoneForm(args, opts, printNode);
|
|
99
|
+
case 'overlay': return printOverlayForm(args, opts, printNode);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Strip pg_catalog. schema prefix — it's an implementation detail, not user-facing
|
|
103
|
+
const name = rawName.startsWith('pg_catalog.') ? rawName.slice('pg_catalog.'.length) : rawName;
|
|
104
|
+
const argDocs = star ? [makeKeyword('*')] : args.map(printNode);
|
|
105
|
+
const distinctPrefix = distinct ? [makeKeyword('DISTINCT'), ' '] : '';
|
|
106
|
+
// ORDER BY inside the aggregate call: array_agg(x ORDER BY x)
|
|
107
|
+
let innerDoc = [distinctPrefix, join(', ', argDocs)];
|
|
108
|
+
if (aggOrder.length > 0) {
|
|
109
|
+
innerDoc = [innerDoc, ' ', makeKeyword('ORDER BY'), ' ', join(', ', aggOrder.map(printNode))];
|
|
110
|
+
}
|
|
111
|
+
let callDoc = [makeKeyword(name), '(', innerDoc, ')'];
|
|
112
|
+
// FILTER (WHERE ...) after the call, before OVER
|
|
113
|
+
if (filter) {
|
|
114
|
+
callDoc = [callDoc, ' ', makeKeyword('FILTER'), ' (', makeKeyword('WHERE'), ' ', printNode(filter), ')'];
|
|
115
|
+
}
|
|
116
|
+
if (!over)
|
|
117
|
+
return callDoc;
|
|
118
|
+
// Named window reference: OVER w (no inline spec)
|
|
119
|
+
if (over.type === 'WindowRef')
|
|
120
|
+
return [callDoc, ' ', makeKeyword('OVER'), ' ', over.text ?? ''];
|
|
121
|
+
return [callDoc, ' ', makeKeyword('OVER'), ' (', printWindowDef(over, opts, printNode), ')'];
|
|
122
|
+
}
|
|
123
|
+
// SUBSTRING(str FROM pattern) — 2 args: regex form
|
|
124
|
+
// SUBSTRING(str FROM pos FOR len) — 3 args: positional form
|
|
125
|
+
function printSubstringForm(args, opts, printNode) {
|
|
126
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
127
|
+
const [str, fromExpr, forExpr] = args;
|
|
128
|
+
if (!str)
|
|
129
|
+
return makeKeyword('SUBSTRING') + '()';
|
|
130
|
+
if (forExpr) {
|
|
131
|
+
return [makeKeyword('SUBSTRING'), '(', printNode(str), ' ', makeKeyword('FROM'), ' ', printNode(fromExpr), ' ', makeKeyword('FOR'), ' ', printNode(forExpr), ')'];
|
|
132
|
+
}
|
|
133
|
+
return [makeKeyword('SUBSTRING'), '(', printNode(str), ' ', makeKeyword('FROM'), ' ', printNode(fromExpr ?? args[1]), ')'];
|
|
134
|
+
}
|
|
135
|
+
// EXTRACT(YEAR FROM expr)
|
|
136
|
+
function printExtractForm(args, opts, printNode) {
|
|
137
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
138
|
+
const [fieldArg, sourceArg] = args;
|
|
139
|
+
// fieldArg is a Literal whose text is "'year'" — strip quotes and apply keyword casing
|
|
140
|
+
const raw = fieldArg?.text ?? '';
|
|
141
|
+
const field = raw.replace(/^'|'$/g, '').toUpperCase();
|
|
142
|
+
return [makeKeyword('EXTRACT'), '(', makeKeyword(field), ' ', makeKeyword('FROM'), ' ', sourceArg ? printNode(sourceArg) : '', ')'];
|
|
143
|
+
}
|
|
144
|
+
// TRIM(LEADING chars FROM str) / TRIM(TRAILING ...) / TRIM(BOTH ...)
|
|
145
|
+
function printTrimForm(args, direction, opts, printNode) {
|
|
146
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
147
|
+
const [str, chars] = args;
|
|
148
|
+
if (!chars) {
|
|
149
|
+
// 1-arg: trim spaces — use directional shorthand
|
|
150
|
+
const fnName = direction === 'LEADING' ? 'LTRIM' : direction === 'TRAILING' ? 'RTRIM' : 'TRIM';
|
|
151
|
+
return [makeKeyword(fnName), '(', str ? printNode(str) : '', ')'];
|
|
152
|
+
}
|
|
153
|
+
return [makeKeyword('TRIM'), '(', makeKeyword(direction), ' ', printNode(chars), ' ', makeKeyword('FROM'), ' ', printNode(str), ')'];
|
|
154
|
+
}
|
|
155
|
+
// POSITION(substr IN str) — note: pg_catalog.position(str, substr) has reversed args
|
|
156
|
+
function printPositionForm(args, opts, printNode) {
|
|
157
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
158
|
+
const [str, substr] = args; // pg_catalog.position(haystack, needle)
|
|
159
|
+
return [makeKeyword('POSITION'), '(', substr ? printNode(substr) : '', ' ', makeKeyword('IN'), ' ', str ? printNode(str) : '', ')'];
|
|
160
|
+
}
|
|
161
|
+
// ts AT TIME ZONE tz — pg_catalog.timezone(tz, ts) has reversed args
|
|
162
|
+
function printAtTimeZoneForm(args, opts, printNode) {
|
|
163
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
164
|
+
const [tz, ts] = args; // pg_catalog.timezone(zone, timestamp)
|
|
165
|
+
return [ts ? printNode(ts) : '', ' ', makeKeyword('AT TIME ZONE'), ' ', tz ? printNode(tz) : ''];
|
|
166
|
+
}
|
|
167
|
+
// OVERLAY(str PLACING sub FROM pos FOR len)
|
|
168
|
+
function printOverlayForm(args, opts, printNode) {
|
|
169
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
170
|
+
const [str, placing, fromExpr, forExpr] = args;
|
|
171
|
+
const doc = [
|
|
172
|
+
makeKeyword('OVERLAY'), '(',
|
|
173
|
+
str ? printNode(str) : '', ' ', makeKeyword('PLACING'), ' ',
|
|
174
|
+
placing ? printNode(placing) : '', ' ', makeKeyword('FROM'), ' ',
|
|
175
|
+
fromExpr ? printNode(fromExpr) : '',
|
|
176
|
+
];
|
|
177
|
+
if (forExpr)
|
|
178
|
+
doc.push(' ', makeKeyword('FOR'), ' ', printNode(forExpr));
|
|
179
|
+
doc.push(')');
|
|
180
|
+
return doc;
|
|
181
|
+
}
|
|
182
|
+
export function printWindowDef(node, opts, printNode) {
|
|
183
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
184
|
+
const partitionBy = propArr(node, 'partitionBy');
|
|
185
|
+
const orderBy = propArr(node, 'orderBy');
|
|
186
|
+
const frameMode = propStr(node, 'frameMode');
|
|
187
|
+
const frameStart = propStr(node, 'frameStart');
|
|
188
|
+
const frameEnd = propStr(node, 'frameEnd');
|
|
189
|
+
const startOffset = prop(node, 'startOffset');
|
|
190
|
+
const endOffset = prop(node, 'endOffset');
|
|
191
|
+
const parts = [];
|
|
192
|
+
if (partitionBy.length > 0) {
|
|
193
|
+
parts.push([makeKeyword('PARTITION BY'), ' ', join(', ', partitionBy.map(printNode))]);
|
|
194
|
+
}
|
|
195
|
+
if (orderBy.length > 0) {
|
|
196
|
+
parts.push([makeKeyword('ORDER BY'), ' ', join(', ', orderBy.map(printNode))]);
|
|
197
|
+
}
|
|
198
|
+
if (frameMode) {
|
|
199
|
+
const startDoc = startOffset
|
|
200
|
+
? [printNode(startOffset), ' ', makeKeyword(frameStart ?? '')]
|
|
201
|
+
: makeKeyword(frameStart ?? '');
|
|
202
|
+
if (frameEnd) {
|
|
203
|
+
const endDoc = endOffset
|
|
204
|
+
? [printNode(endOffset), ' ', makeKeyword(frameEnd)]
|
|
205
|
+
: makeKeyword(frameEnd);
|
|
206
|
+
parts.push([makeKeyword(frameMode), ' ', makeKeyword('BETWEEN'), ' ', startDoc, ' ', makeKeyword('AND'), ' ', endDoc]);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
parts.push([makeKeyword(frameMode), ' ', startDoc]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return join(' ', parts);
|
|
213
|
+
}
|
|
214
|
+
function printCast(node, opts, printNode) {
|
|
215
|
+
const arg = prop(node, 'arg');
|
|
216
|
+
const typeName = propStr(node, 'typeName') ?? '';
|
|
217
|
+
return [arg ? printNode(arg) : '', '::', keyword(typeName, opts)];
|
|
218
|
+
}
|
|
219
|
+
function printSubLink(node, opts, printNode) {
|
|
220
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
221
|
+
const type = propStr(node, 'type') ?? 'SCALAR';
|
|
222
|
+
const subquery = prop(node, 'subquery');
|
|
223
|
+
const testexpr = prop(node, 'testexpr');
|
|
224
|
+
const op = propStr(node, 'op') ?? '=';
|
|
225
|
+
const inner = subquery ? printNode(subquery) : '';
|
|
226
|
+
const subDoc = ['(', indent([hardline, inner]), hardline, ')'];
|
|
227
|
+
if (type === 'EXISTS')
|
|
228
|
+
return [makeKeyword('EXISTS'), ' ', subDoc];
|
|
229
|
+
const lhs = testexpr ? [printNode(testexpr), ' '] : '';
|
|
230
|
+
if (type === 'ANY') {
|
|
231
|
+
// = ANY is SQL's IN
|
|
232
|
+
return op === '=' ? [lhs, makeKeyword('IN'), ' ', subDoc]
|
|
233
|
+
: [lhs, op, ' ', makeKeyword('ANY'), ' ', subDoc];
|
|
234
|
+
}
|
|
235
|
+
if (type === 'ALL')
|
|
236
|
+
return [lhs, op, ' ', makeKeyword('ALL'), ' ', subDoc];
|
|
237
|
+
return subDoc;
|
|
238
|
+
}
|
|
239
|
+
function printCaseExpr(node, opts, printNode) {
|
|
240
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
241
|
+
const arg = prop(node, 'arg');
|
|
242
|
+
const whens = propArr(node, 'whens');
|
|
243
|
+
const else_ = prop(node, 'else');
|
|
244
|
+
const whenDocs = whens.map((w) => {
|
|
245
|
+
const cond = prop(w, 'condition');
|
|
246
|
+
const result = prop(w, 'result');
|
|
247
|
+
return [makeKeyword('WHEN'), ' ', cond ? printNode(cond) : '', ' ', makeKeyword('THEN'), ' ', result ? printNode(result) : ''];
|
|
248
|
+
});
|
|
249
|
+
return [
|
|
250
|
+
makeKeyword('CASE'), arg ? [' ', printNode(arg)] : '',
|
|
251
|
+
indent([hardline, join(hardline, whenDocs)]),
|
|
252
|
+
else_ ? [hardline, makeKeyword('ELSE'), ' ', printNode(else_)] : '',
|
|
253
|
+
hardline, makeKeyword('END'),
|
|
254
|
+
];
|
|
255
|
+
}
|
|
256
|
+
function printNullTest(node, opts, printNode) {
|
|
257
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
258
|
+
const arg = prop(node, 'arg');
|
|
259
|
+
const isNull = propBool(node, 'isNull');
|
|
260
|
+
return [arg ? printNode(arg) : '', ' ', isNull ? makeKeyword('IS NULL') : makeKeyword('IS NOT NULL')];
|
|
261
|
+
}
|
|
262
|
+
function printBooleanTest(node, opts, printNode) {
|
|
263
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
264
|
+
const arg = prop(node, 'arg');
|
|
265
|
+
const test = propStr(node, 'test') ?? '';
|
|
266
|
+
return [arg ? printNode(arg) : '', ' ', makeKeyword('IS'), ' ', makeKeyword(test.replace(/_/g, ' '))];
|
|
267
|
+
}
|
|
268
|
+
function printResTarget(node, opts, printNode) {
|
|
269
|
+
const name = propStr(node, 'name');
|
|
270
|
+
const val = prop(node, 'val');
|
|
271
|
+
const expr = val ? printNode(val) : '';
|
|
272
|
+
return [expr, aliasDoc(name, opts)];
|
|
273
|
+
}
|
|
274
|
+
// ---------------------------------------------------------------------------
|
|
275
|
+
// FROM items
|
|
276
|
+
// ---------------------------------------------------------------------------
|
|
277
|
+
function printRangeVar(node, opts) {
|
|
278
|
+
return [rangeVarName(node), aliasDoc(propStr(node, 'alias'), opts)];
|
|
279
|
+
}
|
|
280
|
+
function printJoinExpr(node, opts, printNode) {
|
|
281
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
282
|
+
const joinType = propStr(node, 'joinType') ?? 'INNER';
|
|
283
|
+
const lhs = prop(node, 'lhs');
|
|
284
|
+
const rhs = prop(node, 'rhs');
|
|
285
|
+
const on = prop(node, 'on');
|
|
286
|
+
const using = node.props?.['using'] ?? [];
|
|
287
|
+
const joinKw = joinType === 'CROSS' ? makeKeyword('CROSS JOIN')
|
|
288
|
+
: joinType === 'INNER' ? makeKeyword('JOIN')
|
|
289
|
+
: joinType === 'NATURAL' ? makeKeyword('NATURAL JOIN')
|
|
290
|
+
: [makeKeyword(joinType), ' ', makeKeyword('JOIN')];
|
|
291
|
+
const condition = joinType === 'CROSS' ? ''
|
|
292
|
+
: on ? [' ', makeKeyword('ON'), ' ', printNode(on)]
|
|
293
|
+
: using.length > 0 ? [' ', makeKeyword('USING'), ' (', join(', ', using), ')']
|
|
294
|
+
: '';
|
|
295
|
+
return [lhs ? printNode(lhs) : '', hardline, joinKw, ' ', rhs ? printNode(rhs) : '', condition];
|
|
296
|
+
}
|
|
297
|
+
function printSubquery(node, opts, printNode) {
|
|
298
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
299
|
+
const subquery = prop(node, 'subquery');
|
|
300
|
+
const lateral = propBool(node, 'lateral');
|
|
301
|
+
const prefix = lateral ? [makeKeyword('LATERAL'), ' '] : '';
|
|
302
|
+
return [prefix, '(', indent([hardline, subquery ? printNode(subquery) : '']), hardline, ')', aliasDoc(propStr(node, 'alias'), opts)];
|
|
303
|
+
}
|
|
304
|
+
function printRangeFunction(node, opts, printNode) {
|
|
305
|
+
return [join(', ', propArr(node, 'functions').map(printNode)), aliasDoc(propStr(node, 'alias'), opts)];
|
|
306
|
+
}
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// Sort / ORDER BY
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
function printSortItem(node, opts, printNode) {
|
|
311
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
312
|
+
const expr = prop(node, 'expr');
|
|
313
|
+
const direction = propStr(node, 'direction');
|
|
314
|
+
return [expr ? printNode(expr) : '', direction ? [' ', makeKeyword(direction)] : ''];
|
|
315
|
+
}
|
|
316
|
+
// ---------------------------------------------------------------------------
|
|
317
|
+
// DDL pieces
|
|
318
|
+
// ---------------------------------------------------------------------------
|
|
319
|
+
function printColumnDef(node, opts, printNode) {
|
|
320
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
321
|
+
const name = propStr(node, 'name') ?? '';
|
|
322
|
+
const typeName = propStr(node, 'typeName') ?? '';
|
|
323
|
+
const constraints = propArr(node, 'constraints');
|
|
324
|
+
const parts = [name, ' ', makeKeyword(typeName)];
|
|
325
|
+
for (const c of constraints) {
|
|
326
|
+
parts.push(' ', printConstraint(c, opts, printNode));
|
|
327
|
+
}
|
|
328
|
+
return parts;
|
|
329
|
+
}
|
|
330
|
+
function printConstraint(node, opts, printNode) {
|
|
331
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
332
|
+
const contype = propStr(node, 'contype') ?? '';
|
|
333
|
+
const name = propStr(node, 'name');
|
|
334
|
+
const expr = prop(node, 'expr');
|
|
335
|
+
const pktable = prop(node, 'pktable');
|
|
336
|
+
const fkAttrs = node.props?.['fkAttrs'] ?? [];
|
|
337
|
+
const pkAttrs = node.props?.['pkAttrs'] ?? [];
|
|
338
|
+
const keys = node.props?.['keys'] ?? [];
|
|
339
|
+
const fkUpdAction = propStr(node, 'fkUpdAction');
|
|
340
|
+
const fkDelAction = propStr(node, 'fkDelAction');
|
|
341
|
+
const generatedWhen = propStr(node, 'generatedWhen');
|
|
342
|
+
const nullsNotDistinct = propBool(node, 'nullsNotDistinct');
|
|
343
|
+
const deferrable = propBool(node, 'deferrable');
|
|
344
|
+
const initDeferred = propBool(node, 'initDeferred');
|
|
345
|
+
const namePrefix = name ? [makeKeyword('CONSTRAINT'), ' ', name, ' '] : '';
|
|
346
|
+
switch (contype) {
|
|
347
|
+
case 'NULL': return [namePrefix, makeKeyword('NULL')];
|
|
348
|
+
case 'NOT NULL': return [namePrefix, makeKeyword('NOT NULL')];
|
|
349
|
+
case 'DEFAULT':
|
|
350
|
+
return [namePrefix, makeKeyword('DEFAULT'), expr ? [' ', printNode(expr)] : ''];
|
|
351
|
+
case 'CHECK':
|
|
352
|
+
return [namePrefix, makeKeyword('CHECK'), ' (', expr ? printNode(expr) : '', ')'];
|
|
353
|
+
case 'PRIMARY KEY': {
|
|
354
|
+
const colList = keys.length > 0 ? [' (', keys.join(', '), ')'] : '';
|
|
355
|
+
return [namePrefix, makeKeyword('PRIMARY KEY'), colList];
|
|
356
|
+
}
|
|
357
|
+
case 'UNIQUE': {
|
|
358
|
+
const colList = keys.length > 0 ? [' (', keys.join(', '), ')'] : '';
|
|
359
|
+
const nnd = nullsNotDistinct ? [' ', makeKeyword('NULLS NOT DISTINCT')] : '';
|
|
360
|
+
return [namePrefix, makeKeyword('UNIQUE'), nnd, colList];
|
|
361
|
+
}
|
|
362
|
+
case 'FOREIGN KEY': {
|
|
363
|
+
// Column-level: REFERENCES table [(col, ...)] [ON UPDATE x] [ON DELETE y]
|
|
364
|
+
// Table-level: FOREIGN KEY (fkAttrs) REFERENCES table [(pkAttrs)]
|
|
365
|
+
const fkColList = fkAttrs.length > 0 ? [' (', fkAttrs.join(', '), ')'] : '';
|
|
366
|
+
const pkColList = pkAttrs.length > 0 ? [' (', pkAttrs.join(', '), ')'] : '';
|
|
367
|
+
const pktableDoc = pktable ? printRangeVar(pktable, opts) : '';
|
|
368
|
+
const onUpdate = fkUpdAction ? [' ', makeKeyword('ON UPDATE'), ' ', makeKeyword(fkUpdAction)] : '';
|
|
369
|
+
const onDelete = fkDelAction ? [' ', makeKeyword('ON DELETE'), ' ', makeKeyword(fkDelAction)] : '';
|
|
370
|
+
const deferrableDoc = deferrable
|
|
371
|
+
? [' ', makeKeyword('DEFERRABLE'), initDeferred ? [' ', makeKeyword('INITIALLY DEFERRED')] : [' ', makeKeyword('INITIALLY IMMEDIATE')]]
|
|
372
|
+
: '';
|
|
373
|
+
if (fkAttrs.length > 0) {
|
|
374
|
+
// table-level
|
|
375
|
+
return [namePrefix, makeKeyword('FOREIGN KEY'), fkColList, ' ', makeKeyword('REFERENCES'), ' ', pktableDoc, pkColList, onUpdate, onDelete, deferrableDoc];
|
|
376
|
+
}
|
|
377
|
+
// column-level
|
|
378
|
+
return [namePrefix, makeKeyword('REFERENCES'), ' ', pktableDoc, pkColList, onUpdate, onDelete, deferrableDoc];
|
|
379
|
+
}
|
|
380
|
+
case 'IDENTITY': {
|
|
381
|
+
const when = generatedWhen ? makeKeyword(generatedWhen) : makeKeyword('BY DEFAULT');
|
|
382
|
+
return [namePrefix, makeKeyword('GENERATED'), ' ', when, ' ', makeKeyword('AS IDENTITY')];
|
|
383
|
+
}
|
|
384
|
+
case 'GENERATED': {
|
|
385
|
+
return [namePrefix, makeKeyword('GENERATED ALWAYS AS'), ' (', expr ? printNode(expr) : '', ') ', makeKeyword('STORED')];
|
|
386
|
+
}
|
|
387
|
+
default:
|
|
388
|
+
return [namePrefix, makeKeyword(contype)];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function printAlterCmd(node, opts, printNode) {
|
|
392
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
393
|
+
const subtype = propStr(node, 'subtype') ?? '';
|
|
394
|
+
const name = propStr(node, 'name') ?? '';
|
|
395
|
+
const newType = propStr(node, 'newType');
|
|
396
|
+
const expr = prop(node, 'expr');
|
|
397
|
+
const def = prop(node, 'def');
|
|
398
|
+
const ifExists = propBool(node, 'ifExists') ? [makeKeyword('IF EXISTS'), ' '] : '';
|
|
399
|
+
switch (subtype) {
|
|
400
|
+
case 'ADD COLUMN':
|
|
401
|
+
return [makeKeyword('ADD COLUMN'), ' ', ifExists, def ? printNode(def) : name];
|
|
402
|
+
case 'DROP COLUMN':
|
|
403
|
+
return [makeKeyword('DROP COLUMN'), ' ', ifExists, name];
|
|
404
|
+
case 'ADD CONSTRAINT':
|
|
405
|
+
return [makeKeyword('ADD'), ' ', def ? printNode(def) : name];
|
|
406
|
+
case 'ALTER COLUMN TYPE':
|
|
407
|
+
return [makeKeyword('ALTER COLUMN'), ' ', name, ' ', makeKeyword('TYPE'), ' ', newType ? makeKeyword(newType) : ''];
|
|
408
|
+
case 'SET DEFAULT':
|
|
409
|
+
return [makeKeyword('ALTER COLUMN'), ' ', name, ' ', makeKeyword('SET DEFAULT'), ' ', expr ? printNode(expr) : ''];
|
|
410
|
+
case 'DROP DEFAULT':
|
|
411
|
+
return [makeKeyword('ALTER COLUMN'), ' ', name, ' ', makeKeyword('DROP DEFAULT')];
|
|
412
|
+
case 'SET NOT NULL':
|
|
413
|
+
return [makeKeyword('ALTER COLUMN'), ' ', name, ' ', makeKeyword('SET NOT NULL')];
|
|
414
|
+
case 'DROP NOT NULL':
|
|
415
|
+
return [makeKeyword('ALTER COLUMN'), ' ', name, ' ', makeKeyword('DROP NOT NULL')];
|
|
416
|
+
default:
|
|
417
|
+
return [makeKeyword(subtype), name ? [' ', name] : ''];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function printFunctionParam(node, opts) {
|
|
421
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
422
|
+
const name = propStr(node, 'name') ?? '';
|
|
423
|
+
const typeName = propStr(node, 'typeName') ?? '';
|
|
424
|
+
const mode = propStr(node, 'mode');
|
|
425
|
+
const modePrefix = mode ? [makeKeyword(mode), ' '] : '';
|
|
426
|
+
return [modePrefix, name ? [name, ' '] : '', makeKeyword(typeName)];
|
|
427
|
+
}
|
|
428
|
+
// ---------------------------------------------------------------------------
|
|
429
|
+
// Arrays / misc
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
function printArrayExpr(node, opts, printNode) {
|
|
432
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
433
|
+
const elements = propArr(node, 'elements');
|
|
434
|
+
return [makeKeyword('ARRAY'), '[', join(', ', elements.map(printNode)), ']'];
|
|
435
|
+
}
|
|
436
|
+
function printCoalesce(node, opts, printNode) {
|
|
437
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
438
|
+
const args = propArr(node, 'args');
|
|
439
|
+
return [makeKeyword('COALESCE'), '(', join(', ', args.map(printNode)), ')'];
|
|
440
|
+
}
|
|
441
|
+
function printCteInline(node, opts, printNode) {
|
|
442
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
443
|
+
const name = propStr(node, 'name') ?? '';
|
|
444
|
+
const query = prop(node, 'query');
|
|
445
|
+
return [name, ' ', makeKeyword('AS'), ' (', indent([hardline, query ? printNode(query) : '']), hardline, ')'];
|
|
446
|
+
}
|
|
447
|
+
// ---------------------------------------------------------------------------
|
|
448
|
+
// IN / BETWEEN / Quantified (ANY, ALL)
|
|
449
|
+
// ---------------------------------------------------------------------------
|
|
450
|
+
function printInExpr(node, opts, printNode) {
|
|
451
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
452
|
+
const left = prop(node, 'left');
|
|
453
|
+
const not = propBool(node, 'not');
|
|
454
|
+
const values = prop(node, 'values');
|
|
455
|
+
const keywordDoc = not ? makeKeyword('NOT IN') : makeKeyword('IN');
|
|
456
|
+
// values is an ExprList node; its items are the IN list
|
|
457
|
+
const items = values ? propArr(values, 'items').map(printNode) : [];
|
|
458
|
+
return [left ? printNode(left) : '', ' ', keywordDoc, ' (', join(', ', items), ')'];
|
|
459
|
+
}
|
|
460
|
+
function printBetweenExpr(node, opts, printNode) {
|
|
461
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
462
|
+
const arg = prop(node, 'arg');
|
|
463
|
+
const not = propBool(node, 'not');
|
|
464
|
+
const symmetric = propBool(node, 'symmetric');
|
|
465
|
+
const low = prop(node, 'low');
|
|
466
|
+
const high = prop(node, 'high');
|
|
467
|
+
const keywordDoc = not
|
|
468
|
+
? (symmetric ? makeKeyword('NOT BETWEEN SYMMETRIC') : makeKeyword('NOT BETWEEN'))
|
|
469
|
+
: (symmetric ? makeKeyword('BETWEEN SYMMETRIC') : makeKeyword('BETWEEN'));
|
|
470
|
+
return [
|
|
471
|
+
arg ? printNode(arg) : '',
|
|
472
|
+
' ', keywordDoc, ' ',
|
|
473
|
+
low ? printNode(low) : '',
|
|
474
|
+
' ', makeKeyword('AND'), ' ',
|
|
475
|
+
high ? printNode(high) : '',
|
|
476
|
+
];
|
|
477
|
+
}
|
|
478
|
+
function printQuantifiedExpr(node, opts, printNode) {
|
|
479
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
480
|
+
const left = prop(node, 'left');
|
|
481
|
+
const right = prop(node, 'right');
|
|
482
|
+
const op = propStr(node, 'op') ?? '=';
|
|
483
|
+
const quantifier = propStr(node, 'quantifier') ?? 'ANY';
|
|
484
|
+
// right is typically an array literal or subquery
|
|
485
|
+
return [left ? printNode(left) : '', ' ', op, ' ', makeKeyword(quantifier), '(', right ? printNode(right) : '', ')'];
|
|
486
|
+
}
|
|
487
|
+
function printIntervalLiteral(node, opts, printNode) {
|
|
488
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
489
|
+
const value = prop(node, 'value');
|
|
490
|
+
const field = propStr(node, 'field');
|
|
491
|
+
return [makeKeyword('INTERVAL'), ' ', value ? printNode(value) : '', field ? [' ', makeKeyword(field)] : ''];
|
|
492
|
+
}
|
|
493
|
+
function printRangeTableSample(node, opts, printNode) {
|
|
494
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
495
|
+
const relation = prop(node, 'relation');
|
|
496
|
+
const method = propStr(node, 'method') ?? 'bernoulli';
|
|
497
|
+
const args = propArr(node, 'args');
|
|
498
|
+
const repeatable = prop(node, 'repeatable');
|
|
499
|
+
return [
|
|
500
|
+
relation ? printNode(relation) : '',
|
|
501
|
+
' ', makeKeyword('TABLESAMPLE'), ' ', makeKeyword(method.toUpperCase()),
|
|
502
|
+
'(', join(', ', args.map(printNode)), ')',
|
|
503
|
+
repeatable ? [' ', makeKeyword('REPEATABLE'), ' (', printNode(repeatable), ')'] : '',
|
|
504
|
+
];
|
|
505
|
+
}
|
|
506
|
+
function printTableLikeClause(node, opts) {
|
|
507
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
508
|
+
const relation = prop(node, 'relation');
|
|
509
|
+
const including = node.props?.['including'] ?? [];
|
|
510
|
+
return [
|
|
511
|
+
makeKeyword('LIKE'), ' ', rangeVarName(relation),
|
|
512
|
+
...including.map((opt) => [' ', makeKeyword('INCLUDING'), ' ', makeKeyword(opt)]),
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
function printSubscript(node, _opts, printNode) {
|
|
516
|
+
const arg = prop(node, 'arg');
|
|
517
|
+
const subscripts = propArr(node, 'subscripts');
|
|
518
|
+
const base = arg ? printNode(arg) : '';
|
|
519
|
+
const parts = subscripts.map((s) => {
|
|
520
|
+
if (s.type === 'SubscriptIndex') {
|
|
521
|
+
const index = prop(s, 'index');
|
|
522
|
+
return ['[', index ? printNode(index) : '', ']'];
|
|
523
|
+
}
|
|
524
|
+
if (s.type === 'SubscriptSlice') {
|
|
525
|
+
const lower = prop(s, 'lower');
|
|
526
|
+
const upper = prop(s, 'upper');
|
|
527
|
+
return ['[', lower ? printNode(lower) : '', ':', upper ? printNode(upper) : '', ']'];
|
|
528
|
+
}
|
|
529
|
+
if (s.type === 'FieldAccess')
|
|
530
|
+
return ['.', s.text ?? ''];
|
|
531
|
+
return '';
|
|
532
|
+
});
|
|
533
|
+
return [base, ...parts];
|
|
534
|
+
}
|
|
535
|
+
function printNamedArg(node, _opts, printNode) {
|
|
536
|
+
const name = propStr(node, 'name') ?? '';
|
|
537
|
+
const arg = prop(node, 'arg');
|
|
538
|
+
return [name, ' => ', arg ? printNode(arg) : ''];
|
|
539
|
+
}
|
|
540
|
+
function printGroupingSet(node, opts, printNode) {
|
|
541
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
542
|
+
const kind = propStr(node, 'kind') ?? '';
|
|
543
|
+
const content = propArr(node, 'content');
|
|
544
|
+
if (kind === 'EMPTY')
|
|
545
|
+
return '()';
|
|
546
|
+
if (kind === 'SIMPLE')
|
|
547
|
+
return ['(', join(', ', content.map(printNode)), ')'];
|
|
548
|
+
const printItem = (item) => item.type === 'GroupingSet' ? printGroupingSet(item, opts, printNode) : printNode(item);
|
|
549
|
+
// Inside GROUPING SETS: GroupingSet and RowExpr already carry their own parens;
|
|
550
|
+
// bare column refs need them added: (col) not col
|
|
551
|
+
const printSetItem = (item) => item.type === 'GroupingSet' ? printGroupingSet(item, opts, printNode)
|
|
552
|
+
: item.type === 'RowExpr' ? printNode(item)
|
|
553
|
+
: ['(', printNode(item), ')'];
|
|
554
|
+
if (kind === 'ROLLUP')
|
|
555
|
+
return [makeKeyword('ROLLUP'), '(', join(', ', content.map(printItem)), ')'];
|
|
556
|
+
if (kind === 'CUBE')
|
|
557
|
+
return [makeKeyword('CUBE'), '(', join(', ', content.map(printItem)), ')'];
|
|
558
|
+
if (kind === 'SETS')
|
|
559
|
+
return [makeKeyword('GROUPING SETS'), '(', join(', ', content.map(printSetItem)), ')'];
|
|
560
|
+
return [makeKeyword(kind), '(', join(', ', content.map(printItem)), ')'];
|
|
561
|
+
}
|
|
562
|
+
function printGroupingFunc(node, opts, printNode) {
|
|
563
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
564
|
+
const args = propArr(node, 'args');
|
|
565
|
+
return [makeKeyword('GROUPING'), '(', join(', ', args.map(printNode)), ')'];
|
|
566
|
+
}
|
|
567
|
+
function printXmlExpr(node, opts, printNode) {
|
|
568
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
569
|
+
const op = propStr(node, 'op') ?? 'XMLEXPR';
|
|
570
|
+
const name = propStr(node, 'name');
|
|
571
|
+
const args = propArr(node, 'args');
|
|
572
|
+
const namedArgs = propArr(node, 'namedArgs');
|
|
573
|
+
if (op === 'XMLELEMENT') {
|
|
574
|
+
const parts = [makeKeyword('NAME'), ' ', name ?? ''];
|
|
575
|
+
if (namedArgs.length > 0) {
|
|
576
|
+
// namedArgs correspond to xmlattributes() arguments
|
|
577
|
+
const attrItems = namedArgs.map((a) => {
|
|
578
|
+
const alias = propStr(a, 'name');
|
|
579
|
+
const val = prop(a, 'val');
|
|
580
|
+
const valDoc = val ? printNode(val) : '';
|
|
581
|
+
return alias ? [valDoc, ' ', makeKeyword('AS'), ' ', alias] : valDoc;
|
|
582
|
+
});
|
|
583
|
+
parts.push(', ', makeKeyword('XMLATTRIBUTES'), '(', join(', ', attrItems), ')');
|
|
584
|
+
}
|
|
585
|
+
for (const a of args)
|
|
586
|
+
parts.push(', ', printNode(a));
|
|
587
|
+
return [makeKeyword('XMLELEMENT'), '(', ...parts, ')'];
|
|
588
|
+
}
|
|
589
|
+
if (op === 'XMLFOREST') {
|
|
590
|
+
const items = namedArgs.map((a) => {
|
|
591
|
+
const alias = propStr(a, 'name');
|
|
592
|
+
const val = prop(a, 'val');
|
|
593
|
+
const valDoc = val ? printNode(val) : '';
|
|
594
|
+
return alias ? [valDoc, ' ', makeKeyword('AS'), ' ', alias] : valDoc;
|
|
595
|
+
});
|
|
596
|
+
return [makeKeyword('XMLFOREST'), '(', join(', ', items), ')'];
|
|
597
|
+
}
|
|
598
|
+
if (op === 'XMLPI') {
|
|
599
|
+
const items = [makeKeyword('NAME'), ' ', name ?? ''];
|
|
600
|
+
if (args.length > 0)
|
|
601
|
+
items.push(', ', printNode(args[0]));
|
|
602
|
+
return [makeKeyword('XMLPI'), '(', ...items, ')'];
|
|
603
|
+
}
|
|
604
|
+
// XMLCONCAT, XMLPARSE, XMLROOT, XMLSERIALIZE — simple arg list
|
|
605
|
+
const allArgs = [...namedArgs, ...args].map(printNode);
|
|
606
|
+
return [makeKeyword(op), '(', join(', ', allArgs), ')'];
|
|
607
|
+
}
|
|
608
|
+
function printJsonFuncExpr(node, opts, printNode) {
|
|
609
|
+
const makeKeyword = (kw) => keyword(kw, opts);
|
|
610
|
+
const op = propStr(node, 'op') ?? 'JSON_QUERY';
|
|
611
|
+
const context = prop(node, 'context');
|
|
612
|
+
const path = prop(node, 'path');
|
|
613
|
+
const returning = propStr(node, 'returning');
|
|
614
|
+
const parts = [
|
|
615
|
+
context ? printNode(context) : '',
|
|
616
|
+
', ',
|
|
617
|
+
path ? printNode(path) : '',
|
|
618
|
+
];
|
|
619
|
+
if (returning)
|
|
620
|
+
parts.push(' ', makeKeyword('RETURNING'), ' ', returning);
|
|
621
|
+
return [makeKeyword(op), '(', ...parts, ')'];
|
|
622
|
+
}
|
|
623
|
+
//# sourceMappingURL=expressions.js.map
|