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.
Files changed (40) hide show
  1. package/README.md +197 -0
  2. package/bin/dotnet/Google.Protobuf.dll +0 -0
  3. package/bin/dotnet/PgScriptDom.deps.json +95 -0
  4. package/bin/dotnet/PgScriptDom.dll +0 -0
  5. package/bin/dotnet/PrettierSql.Core.dll +0 -0
  6. package/bin/dotnet/libpg_query.dylib +0 -0
  7. package/bin/dotnet/pgsqlparser.dll +0 -0
  8. package/bin/dotnet/runtimes/linux-x64/native/libpg_query.so +0 -0
  9. package/bin/dotnet/runtimes/osx-arm64/native/libpg_query.dylib +0 -0
  10. package/bin/dotnet/runtimes/osx-x64/native/libpg_query.dylib +0 -0
  11. package/bin/dotnet/runtimes/win-x64/native/libpg_query.dll +0 -0
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +21 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/language.d.ts +3 -0
  17. package/dist/language.d.ts.map +1 -0
  18. package/dist/language.js +9 -0
  19. package/dist/language.js.map +1 -0
  20. package/dist/parser/index.d.ts +5 -0
  21. package/dist/parser/index.d.ts.map +1 -0
  22. package/dist/parser/index.js +58 -0
  23. package/dist/parser/index.js.map +1 -0
  24. package/dist/printer/expressions.d.ts +8 -0
  25. package/dist/printer/expressions.d.ts.map +1 -0
  26. package/dist/printer/expressions.js +623 -0
  27. package/dist/printer/expressions.js.map +1 -0
  28. package/dist/printer/helpers.d.ts +6 -0
  29. package/dist/printer/helpers.d.ts.map +1 -0
  30. package/dist/printer/helpers.js +18 -0
  31. package/dist/printer/helpers.js.map +1 -0
  32. package/dist/printer/index.d.ts +4 -0
  33. package/dist/printer/index.d.ts.map +1 -0
  34. package/dist/printer/index.js +23 -0
  35. package/dist/printer/index.js.map +1 -0
  36. package/dist/printer/statements.d.ts +11 -0
  37. package/dist/printer/statements.d.ts.map +1 -0
  38. package/dist/printer/statements.js +1533 -0
  39. package/dist/printer/statements.js.map +1 -0
  40. 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