pgsql-deparser 17.7.2 → 17.8.1
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 +44 -2
- package/deparser.d.ts +2 -0
- package/deparser.js +363 -86
- package/esm/deparser.js +363 -86
- package/esm/utils/sql-formatter.js +11 -2
- package/package.json +2 -2
- package/utils/sql-formatter.d.ts +3 -1
- package/utils/sql-formatter.js +11 -2
package/deparser.js
CHANGED
|
@@ -51,7 +51,7 @@ class Deparser {
|
|
|
51
51
|
tree;
|
|
52
52
|
options;
|
|
53
53
|
constructor(tree, opts = {}) {
|
|
54
|
-
this.formatter = new sql_formatter_1.SqlFormatter(opts.newline, opts.tab);
|
|
54
|
+
this.formatter = new sql_formatter_1.SqlFormatter(opts.newline, opts.tab, opts.pretty);
|
|
55
55
|
// Set default options
|
|
56
56
|
this.options = {
|
|
57
57
|
functionDelimiter: '$$',
|
|
@@ -184,7 +184,9 @@ class Deparser {
|
|
|
184
184
|
}
|
|
185
185
|
if (!node.op || node.op === 'SETOP_NONE') {
|
|
186
186
|
if (node.valuesLists == null) {
|
|
187
|
-
|
|
187
|
+
if (!this.formatter.isPretty() || !node.targetList) {
|
|
188
|
+
output.push('SELECT');
|
|
189
|
+
}
|
|
188
190
|
}
|
|
189
191
|
}
|
|
190
192
|
else {
|
|
@@ -230,41 +232,82 @@ class Deparser {
|
|
|
230
232
|
output.push(rightStmt);
|
|
231
233
|
}
|
|
232
234
|
}
|
|
235
|
+
// Handle DISTINCT clause - in pretty mode, we'll include it in the SELECT clause
|
|
236
|
+
let distinctPart = '';
|
|
233
237
|
if (node.distinctClause) {
|
|
234
238
|
const distinctClause = list_utils_1.ListUtils.unwrapList(node.distinctClause);
|
|
235
239
|
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
236
|
-
output.push('DISTINCT ON');
|
|
237
240
|
const clause = distinctClause
|
|
238
241
|
.map(e => this.visit(e, { ...context, select: true }))
|
|
239
242
|
.join(', ');
|
|
240
|
-
|
|
243
|
+
distinctPart = ' DISTINCT ON ' + this.formatter.parens(clause);
|
|
241
244
|
}
|
|
242
245
|
else {
|
|
243
|
-
|
|
246
|
+
distinctPart = ' DISTINCT';
|
|
247
|
+
}
|
|
248
|
+
if (!this.formatter.isPretty()) {
|
|
249
|
+
if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
|
|
250
|
+
output.push('DISTINCT ON');
|
|
251
|
+
const clause = distinctClause
|
|
252
|
+
.map(e => this.visit(e, { ...context, select: true }))
|
|
253
|
+
.join(', ');
|
|
254
|
+
output.push(this.formatter.parens(clause));
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
output.push('DISTINCT');
|
|
258
|
+
}
|
|
244
259
|
}
|
|
245
260
|
}
|
|
246
261
|
if (node.targetList) {
|
|
247
262
|
const targetList = list_utils_1.ListUtils.unwrapList(node.targetList);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
263
|
+
if (this.formatter.isPretty()) {
|
|
264
|
+
const targetStrings = targetList
|
|
265
|
+
.map(e => {
|
|
266
|
+
const targetStr = this.visit(e, { ...context, select: true });
|
|
267
|
+
if (this.containsMultilineStringLiteral(targetStr)) {
|
|
268
|
+
return targetStr;
|
|
269
|
+
}
|
|
270
|
+
return this.formatter.indent(targetStr);
|
|
271
|
+
});
|
|
272
|
+
const formattedTargets = targetStrings.join(',' + this.formatter.newline());
|
|
273
|
+
output.push('SELECT' + distinctPart);
|
|
274
|
+
output.push(formattedTargets);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const targets = targetList
|
|
278
|
+
.map(e => this.visit(e, { ...context, select: true }))
|
|
279
|
+
.join(', ');
|
|
280
|
+
output.push(targets);
|
|
281
|
+
}
|
|
252
282
|
}
|
|
253
283
|
if (node.intoClause) {
|
|
254
284
|
output.push('INTO');
|
|
255
285
|
output.push(this.IntoClause(node.intoClause, context));
|
|
256
286
|
}
|
|
257
287
|
if (node.fromClause) {
|
|
258
|
-
output.push('FROM');
|
|
259
288
|
const fromList = list_utils_1.ListUtils.unwrapList(node.fromClause);
|
|
260
289
|
const fromItems = fromList
|
|
261
290
|
.map(e => this.deparse(e, { ...context, from: true }))
|
|
262
291
|
.join(', ');
|
|
263
|
-
output.push(fromItems);
|
|
292
|
+
output.push('FROM ' + fromItems.trim());
|
|
264
293
|
}
|
|
265
294
|
if (node.whereClause) {
|
|
266
|
-
|
|
267
|
-
|
|
295
|
+
if (this.formatter.isPretty()) {
|
|
296
|
+
output.push('WHERE');
|
|
297
|
+
const whereExpr = this.visit(node.whereClause, context);
|
|
298
|
+
const lines = whereExpr.split(this.formatter.newline());
|
|
299
|
+
const indentedLines = lines.map((line, index) => {
|
|
300
|
+
if (index === 0) {
|
|
301
|
+
return this.formatter.indent(line);
|
|
302
|
+
}
|
|
303
|
+
return line;
|
|
304
|
+
});
|
|
305
|
+
output.push(indentedLines.join(this.formatter.newline()));
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
output.push('WHERE');
|
|
309
|
+
output.push(this.visit(node.whereClause, context));
|
|
310
|
+
}
|
|
268
311
|
}
|
|
269
312
|
if (node.valuesLists) {
|
|
270
313
|
output.push('VALUES');
|
|
@@ -275,16 +318,43 @@ class Deparser {
|
|
|
275
318
|
output.push(lists.join(', '));
|
|
276
319
|
}
|
|
277
320
|
if (node.groupClause) {
|
|
278
|
-
output.push('GROUP BY');
|
|
279
321
|
const groupList = list_utils_1.ListUtils.unwrapList(node.groupClause);
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
322
|
+
if (this.formatter.isPretty()) {
|
|
323
|
+
const groupItems = groupList
|
|
324
|
+
.map(e => {
|
|
325
|
+
const groupStr = this.visit(e, { ...context, group: true });
|
|
326
|
+
if (this.containsMultilineStringLiteral(groupStr)) {
|
|
327
|
+
return groupStr;
|
|
328
|
+
}
|
|
329
|
+
return this.formatter.indent(groupStr);
|
|
330
|
+
})
|
|
331
|
+
.join(',' + this.formatter.newline());
|
|
332
|
+
output.push('GROUP BY');
|
|
333
|
+
output.push(groupItems);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
output.push('GROUP BY');
|
|
337
|
+
const groupItems = groupList
|
|
338
|
+
.map(e => this.visit(e, { ...context, group: true }))
|
|
339
|
+
.join(', ');
|
|
340
|
+
output.push(groupItems);
|
|
341
|
+
}
|
|
284
342
|
}
|
|
285
343
|
if (node.havingClause) {
|
|
286
|
-
|
|
287
|
-
|
|
344
|
+
if (this.formatter.isPretty()) {
|
|
345
|
+
output.push('HAVING');
|
|
346
|
+
const havingStr = this.visit(node.havingClause, context);
|
|
347
|
+
if (this.containsMultilineStringLiteral(havingStr)) {
|
|
348
|
+
output.push(havingStr);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
output.push(this.formatter.indent(havingStr));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
output.push('HAVING');
|
|
356
|
+
output.push(this.visit(node.havingClause, context));
|
|
357
|
+
}
|
|
288
358
|
}
|
|
289
359
|
if (node.windowClause) {
|
|
290
360
|
output.push('WINDOW');
|
|
@@ -295,20 +365,33 @@ class Deparser {
|
|
|
295
365
|
output.push(windowClauses);
|
|
296
366
|
}
|
|
297
367
|
if (node.sortClause) {
|
|
298
|
-
output.push('ORDER BY');
|
|
299
368
|
const sortList = list_utils_1.ListUtils.unwrapList(node.sortClause);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
369
|
+
if (this.formatter.isPretty()) {
|
|
370
|
+
const sortItems = sortList
|
|
371
|
+
.map(e => {
|
|
372
|
+
const sortStr = this.visit(e, { ...context, sort: true });
|
|
373
|
+
if (this.containsMultilineStringLiteral(sortStr)) {
|
|
374
|
+
return sortStr;
|
|
375
|
+
}
|
|
376
|
+
return this.formatter.indent(sortStr);
|
|
377
|
+
})
|
|
378
|
+
.join(',' + this.formatter.newline());
|
|
379
|
+
output.push('ORDER BY');
|
|
380
|
+
output.push(sortItems);
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
output.push('ORDER BY');
|
|
384
|
+
const sortItems = sortList
|
|
385
|
+
.map(e => this.visit(e, { ...context, sort: true }))
|
|
386
|
+
.join(', ');
|
|
387
|
+
output.push(sortItems);
|
|
388
|
+
}
|
|
304
389
|
}
|
|
305
390
|
if (node.limitCount) {
|
|
306
|
-
output.push('LIMIT');
|
|
307
|
-
output.push(this.visit(node.limitCount, context));
|
|
391
|
+
output.push('LIMIT ' + this.visit(node.limitCount, context));
|
|
308
392
|
}
|
|
309
393
|
if (node.limitOffset) {
|
|
310
|
-
output.push('OFFSET');
|
|
311
|
-
output.push(this.visit(node.limitOffset, context));
|
|
394
|
+
output.push('OFFSET ' + this.visit(node.limitOffset, context));
|
|
312
395
|
}
|
|
313
396
|
if (node.lockingClause) {
|
|
314
397
|
const lockingList = list_utils_1.ListUtils.unwrapList(node.lockingClause);
|
|
@@ -317,6 +400,10 @@ class Deparser {
|
|
|
317
400
|
.join(' ');
|
|
318
401
|
output.push(lockingClauses);
|
|
319
402
|
}
|
|
403
|
+
if (this.formatter.isPretty()) {
|
|
404
|
+
const filteredOutput = output.filter(item => item.trim() !== '');
|
|
405
|
+
return filteredOutput.join(this.formatter.newline());
|
|
406
|
+
}
|
|
320
407
|
return output.join(' ');
|
|
321
408
|
}
|
|
322
409
|
A_Expr(node, context) {
|
|
@@ -806,9 +893,24 @@ class Deparser {
|
|
|
806
893
|
if (node.recursive) {
|
|
807
894
|
output.push('RECURSIVE');
|
|
808
895
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
896
|
+
if (node.ctes && node.ctes.length > 0) {
|
|
897
|
+
const ctes = list_utils_1.ListUtils.unwrapList(node.ctes);
|
|
898
|
+
if (this.formatter.isPretty()) {
|
|
899
|
+
const cteStrings = ctes.map((cte, index) => {
|
|
900
|
+
const cteStr = this.visit(cte, context);
|
|
901
|
+
const prefix = index === 0 ? this.formatter.newline() : ',' + this.formatter.newline();
|
|
902
|
+
if (this.containsMultilineStringLiteral(cteStr)) {
|
|
903
|
+
return prefix + cteStr;
|
|
904
|
+
}
|
|
905
|
+
return prefix + this.formatter.indent(cteStr);
|
|
906
|
+
});
|
|
907
|
+
output.push(cteStrings.join(''));
|
|
908
|
+
}
|
|
909
|
+
else {
|
|
910
|
+
const cteStrings = ctes.map(cte => this.visit(cte, context));
|
|
911
|
+
output.push(cteStrings.join(', '));
|
|
912
|
+
}
|
|
913
|
+
}
|
|
812
914
|
return output.join(' ');
|
|
813
915
|
}
|
|
814
916
|
ResTarget(node, context) {
|
|
@@ -892,11 +994,23 @@ class Deparser {
|
|
|
892
994
|
// return formatStr.replace('%s', () => andArgs); // ✅ Function callback prevents interpretation
|
|
893
995
|
switch (boolop) {
|
|
894
996
|
case 'AND_EXPR':
|
|
895
|
-
|
|
896
|
-
|
|
997
|
+
if (this.formatter.isPretty() && args.length > 1) {
|
|
998
|
+
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(this.formatter.newline() + ' AND ');
|
|
999
|
+
return formatStr.replace('%s', () => andArgs);
|
|
1000
|
+
}
|
|
1001
|
+
else {
|
|
1002
|
+
const andArgs = args.map(arg => this.visit(arg, boolContext)).join(' AND ');
|
|
1003
|
+
return formatStr.replace('%s', () => andArgs);
|
|
1004
|
+
}
|
|
897
1005
|
case 'OR_EXPR':
|
|
898
|
-
|
|
899
|
-
|
|
1006
|
+
if (this.formatter.isPretty() && args.length > 1) {
|
|
1007
|
+
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(this.formatter.newline() + ' OR ');
|
|
1008
|
+
return formatStr.replace('%s', () => orArgs);
|
|
1009
|
+
}
|
|
1010
|
+
else {
|
|
1011
|
+
const orArgs = args.map(arg => this.visit(arg, boolContext)).join(' OR ');
|
|
1012
|
+
return formatStr.replace('%s', () => orArgs);
|
|
1013
|
+
}
|
|
900
1014
|
case 'NOT_EXPR':
|
|
901
1015
|
return `NOT (${this.visit(args[0], context)})`;
|
|
902
1016
|
default:
|
|
@@ -1098,7 +1212,13 @@ class Deparser {
|
|
|
1098
1212
|
windowParts.push(frameClause);
|
|
1099
1213
|
}
|
|
1100
1214
|
if (windowParts.length > 0) {
|
|
1101
|
-
|
|
1215
|
+
if (this.formatter.isPretty() && windowParts.length > 1) {
|
|
1216
|
+
const formattedParts = windowParts.map(part => this.formatter.indent(part));
|
|
1217
|
+
result += ` OVER (${this.formatter.newline()}${formattedParts.join(this.formatter.newline())}${this.formatter.newline()})`;
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
result += ` OVER (${windowParts.join(' ')})`;
|
|
1221
|
+
}
|
|
1102
1222
|
}
|
|
1103
1223
|
else {
|
|
1104
1224
|
result += ` OVER ()`;
|
|
@@ -1722,15 +1842,39 @@ class Deparser {
|
|
|
1722
1842
|
output.push(this.visit(node.arg, context));
|
|
1723
1843
|
}
|
|
1724
1844
|
const args = list_utils_1.ListUtils.unwrapList(node.args);
|
|
1725
|
-
|
|
1726
|
-
|
|
1845
|
+
if (this.formatter.isPretty() && args.length > 0) {
|
|
1846
|
+
for (const arg of args) {
|
|
1847
|
+
const whenClause = this.visit(arg, context);
|
|
1848
|
+
if (this.containsMultilineStringLiteral(whenClause)) {
|
|
1849
|
+
output.push(this.formatter.newline() + whenClause);
|
|
1850
|
+
}
|
|
1851
|
+
else {
|
|
1852
|
+
output.push(this.formatter.newline() + this.formatter.indent(whenClause));
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
if (node.defresult) {
|
|
1856
|
+
const elseResult = this.visit(node.defresult, context);
|
|
1857
|
+
if (this.containsMultilineStringLiteral(elseResult)) {
|
|
1858
|
+
output.push(this.formatter.newline() + 'ELSE ' + elseResult);
|
|
1859
|
+
}
|
|
1860
|
+
else {
|
|
1861
|
+
output.push(this.formatter.newline() + this.formatter.indent('ELSE ' + elseResult));
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
output.push(this.formatter.newline() + 'END');
|
|
1865
|
+
return output.join(' ');
|
|
1727
1866
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1867
|
+
else {
|
|
1868
|
+
for (const arg of args) {
|
|
1869
|
+
output.push(this.visit(arg, context));
|
|
1870
|
+
}
|
|
1871
|
+
if (node.defresult) {
|
|
1872
|
+
output.push('ELSE');
|
|
1873
|
+
output.push(this.visit(node.defresult, context));
|
|
1874
|
+
}
|
|
1875
|
+
output.push('END');
|
|
1876
|
+
return output.join(' ');
|
|
1731
1877
|
}
|
|
1732
|
-
output.push('END');
|
|
1733
|
-
return output.join(' ');
|
|
1734
1878
|
}
|
|
1735
1879
|
CoalesceExpr(node, context) {
|
|
1736
1880
|
const args = list_utils_1.ListUtils.unwrapList(node.args);
|
|
@@ -1943,7 +2087,13 @@ class Deparser {
|
|
|
1943
2087
|
const elementStrs = elements.map(el => {
|
|
1944
2088
|
return this.deparse(el, context);
|
|
1945
2089
|
});
|
|
1946
|
-
|
|
2090
|
+
if (this.formatter.isPretty()) {
|
|
2091
|
+
const formattedElements = elementStrs.map(el => this.formatter.indent(el)).join(',' + this.formatter.newline());
|
|
2092
|
+
output.push('(' + this.formatter.newline() + formattedElements + this.formatter.newline() + ')');
|
|
2093
|
+
}
|
|
2094
|
+
else {
|
|
2095
|
+
output.push(this.formatter.parens(elementStrs.join(', ')));
|
|
2096
|
+
}
|
|
1947
2097
|
}
|
|
1948
2098
|
else if (!node.partbound) {
|
|
1949
2099
|
output.push(this.formatter.parens(''));
|
|
@@ -2228,38 +2378,52 @@ class Deparser {
|
|
|
2228
2378
|
}
|
|
2229
2379
|
}
|
|
2230
2380
|
if (node.fk_upd_action && node.fk_upd_action !== 'a') {
|
|
2231
|
-
|
|
2381
|
+
let updateClause = 'ON UPDATE ';
|
|
2232
2382
|
switch (node.fk_upd_action) {
|
|
2233
2383
|
case 'r':
|
|
2234
|
-
|
|
2384
|
+
updateClause += 'RESTRICT';
|
|
2235
2385
|
break;
|
|
2236
2386
|
case 'c':
|
|
2237
|
-
|
|
2387
|
+
updateClause += 'CASCADE';
|
|
2238
2388
|
break;
|
|
2239
2389
|
case 'n':
|
|
2240
|
-
|
|
2390
|
+
updateClause += 'SET NULL';
|
|
2241
2391
|
break;
|
|
2242
2392
|
case 'd':
|
|
2243
|
-
|
|
2393
|
+
updateClause += 'SET DEFAULT';
|
|
2244
2394
|
break;
|
|
2245
2395
|
}
|
|
2396
|
+
if (this.formatter.isPretty()) {
|
|
2397
|
+
output.push('\n' + this.formatter.indent(updateClause));
|
|
2398
|
+
}
|
|
2399
|
+
else {
|
|
2400
|
+
output.push('ON UPDATE');
|
|
2401
|
+
output.push(updateClause.replace('ON UPDATE ', ''));
|
|
2402
|
+
}
|
|
2246
2403
|
}
|
|
2247
2404
|
if (node.fk_del_action && node.fk_del_action !== 'a') {
|
|
2248
|
-
|
|
2405
|
+
let deleteClause = 'ON DELETE ';
|
|
2249
2406
|
switch (node.fk_del_action) {
|
|
2250
2407
|
case 'r':
|
|
2251
|
-
|
|
2408
|
+
deleteClause += 'RESTRICT';
|
|
2252
2409
|
break;
|
|
2253
2410
|
case 'c':
|
|
2254
|
-
|
|
2411
|
+
deleteClause += 'CASCADE';
|
|
2255
2412
|
break;
|
|
2256
2413
|
case 'n':
|
|
2257
|
-
|
|
2414
|
+
deleteClause += 'SET NULL';
|
|
2258
2415
|
break;
|
|
2259
2416
|
case 'd':
|
|
2260
|
-
|
|
2417
|
+
deleteClause += 'SET DEFAULT';
|
|
2261
2418
|
break;
|
|
2262
2419
|
}
|
|
2420
|
+
if (this.formatter.isPretty()) {
|
|
2421
|
+
output.push('\n' + this.formatter.indent(deleteClause));
|
|
2422
|
+
}
|
|
2423
|
+
else {
|
|
2424
|
+
output.push('ON DELETE');
|
|
2425
|
+
output.push(deleteClause.replace('ON DELETE ', ''));
|
|
2426
|
+
}
|
|
2263
2427
|
}
|
|
2264
2428
|
// Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
|
|
2265
2429
|
if (node.skip_validation && !context.isDomainConstraint) {
|
|
@@ -2317,17 +2481,48 @@ class Deparser {
|
|
|
2317
2481
|
// Handle deferrable constraints for all constraint types that support it
|
|
2318
2482
|
if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
|
|
2319
2483
|
if (node.deferrable) {
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2484
|
+
if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2485
|
+
output.push('\n' + this.formatter.indent('DEFERRABLE'));
|
|
2486
|
+
if (node.initdeferred === true) {
|
|
2487
|
+
output.push('\n' + this.formatter.indent('INITIALLY DEFERRED'));
|
|
2488
|
+
}
|
|
2489
|
+
else if (node.initdeferred === false) {
|
|
2490
|
+
output.push('\n' + this.formatter.indent('INITIALLY IMMEDIATE'));
|
|
2491
|
+
}
|
|
2323
2492
|
}
|
|
2324
|
-
else
|
|
2325
|
-
output.push('
|
|
2493
|
+
else {
|
|
2494
|
+
output.push('DEFERRABLE');
|
|
2495
|
+
if (node.initdeferred === true) {
|
|
2496
|
+
output.push('INITIALLY DEFERRED');
|
|
2497
|
+
}
|
|
2498
|
+
else if (node.initdeferred === false) {
|
|
2499
|
+
output.push('INITIALLY IMMEDIATE');
|
|
2500
|
+
}
|
|
2326
2501
|
}
|
|
2327
2502
|
}
|
|
2328
2503
|
else if (node.deferrable === false) {
|
|
2329
|
-
|
|
2504
|
+
if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2505
|
+
output.push('\n' + this.formatter.indent('NOT DEFERRABLE'));
|
|
2506
|
+
}
|
|
2507
|
+
else {
|
|
2508
|
+
output.push('NOT DEFERRABLE');
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
|
|
2513
|
+
let result = '';
|
|
2514
|
+
for (let i = 0; i < output.length; i++) {
|
|
2515
|
+
if (output[i].startsWith('\n')) {
|
|
2516
|
+
result += output[i];
|
|
2517
|
+
}
|
|
2518
|
+
else {
|
|
2519
|
+
if (i > 0 && !output[i - 1].startsWith('\n')) {
|
|
2520
|
+
result += ' ';
|
|
2521
|
+
}
|
|
2522
|
+
result += output[i];
|
|
2523
|
+
}
|
|
2330
2524
|
}
|
|
2525
|
+
return result;
|
|
2331
2526
|
}
|
|
2332
2527
|
return output.join(' ');
|
|
2333
2528
|
}
|
|
@@ -3051,11 +3246,9 @@ class Deparser {
|
|
|
3051
3246
|
}
|
|
3052
3247
|
switch (node.jointype) {
|
|
3053
3248
|
case 'JOIN_INNER':
|
|
3054
|
-
// Handle NATURAL JOIN first - it has isNatural=true (NATURAL already added above)
|
|
3055
3249
|
if (node.isNatural) {
|
|
3056
3250
|
joinStr += 'JOIN';
|
|
3057
3251
|
}
|
|
3058
|
-
// Handle CROSS JOIN case - when there's no quals, no usingClause, and not natural
|
|
3059
3252
|
else if (!node.quals && (!node.usingClause || node.usingClause.length === 0)) {
|
|
3060
3253
|
joinStr += 'CROSS JOIN';
|
|
3061
3254
|
}
|
|
@@ -3075,26 +3268,63 @@ class Deparser {
|
|
|
3075
3268
|
default:
|
|
3076
3269
|
joinStr += 'JOIN';
|
|
3077
3270
|
}
|
|
3078
|
-
output.push(joinStr);
|
|
3079
3271
|
if (node.rarg) {
|
|
3080
3272
|
let rargStr = this.visit(node.rarg, context);
|
|
3081
3273
|
if (node.rarg && 'JoinExpr' in node.rarg && !node.rarg.JoinExpr.alias) {
|
|
3082
3274
|
rargStr = `(${rargStr})`;
|
|
3083
3275
|
}
|
|
3084
|
-
|
|
3276
|
+
if (this.formatter.isPretty()) {
|
|
3277
|
+
output.push(this.formatter.newline() + joinStr + ' ' + rargStr);
|
|
3278
|
+
}
|
|
3279
|
+
else {
|
|
3280
|
+
output.push(joinStr + ' ' + rargStr);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
else {
|
|
3284
|
+
if (this.formatter.isPretty()) {
|
|
3285
|
+
output.push(this.formatter.newline() + joinStr);
|
|
3286
|
+
}
|
|
3287
|
+
else {
|
|
3288
|
+
output.push(joinStr);
|
|
3289
|
+
}
|
|
3085
3290
|
}
|
|
3086
3291
|
if (node.usingClause && node.usingClause.length > 0) {
|
|
3087
|
-
output.push('USING');
|
|
3088
3292
|
const usingList = list_utils_1.ListUtils.unwrapList(node.usingClause);
|
|
3089
3293
|
const columnNames = usingList.map(col => this.visit(col, context));
|
|
3090
|
-
|
|
3294
|
+
if (this.formatter.isPretty()) {
|
|
3295
|
+
output.push(` USING (${columnNames.join(', ')})`);
|
|
3296
|
+
}
|
|
3297
|
+
else {
|
|
3298
|
+
output.push(`USING (${columnNames.join(', ')})`);
|
|
3299
|
+
}
|
|
3091
3300
|
}
|
|
3092
3301
|
else if (node.quals) {
|
|
3093
|
-
|
|
3094
|
-
|
|
3302
|
+
const qualsStr = this.visit(node.quals, context);
|
|
3303
|
+
if (this.formatter.isPretty()) {
|
|
3304
|
+
// For complex JOIN conditions, format with proper indentation
|
|
3305
|
+
if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
|
|
3306
|
+
if (this.containsMultilineStringLiteral(qualsStr)) {
|
|
3307
|
+
output.push(` ON ${qualsStr}`);
|
|
3308
|
+
}
|
|
3309
|
+
else {
|
|
3310
|
+
output.push(` ON${this.formatter.newline()}${this.formatter.indent(qualsStr)}`);
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
else {
|
|
3314
|
+
output.push(` ON ${qualsStr}`);
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
else {
|
|
3318
|
+
output.push(`ON ${qualsStr}`);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
let result;
|
|
3322
|
+
if (this.formatter.isPretty()) {
|
|
3323
|
+
result = output.join('');
|
|
3324
|
+
}
|
|
3325
|
+
else {
|
|
3326
|
+
result = output.join(' ');
|
|
3095
3327
|
}
|
|
3096
|
-
let result = output.join(' ');
|
|
3097
|
-
// Handle join_using_alias first (for USING clause aliases like "AS x")
|
|
3098
3328
|
if (node.join_using_alias && node.join_using_alias.aliasname) {
|
|
3099
3329
|
let aliasStr = node.join_using_alias.aliasname;
|
|
3100
3330
|
if (node.join_using_alias.colnames && node.join_using_alias.colnames.length > 0) {
|
|
@@ -3104,7 +3334,6 @@ class Deparser {
|
|
|
3104
3334
|
}
|
|
3105
3335
|
result += ` AS ${aliasStr}`;
|
|
3106
3336
|
}
|
|
3107
|
-
// Handle regular alias (for outer table aliases like "y")
|
|
3108
3337
|
if (node.alias && node.alias.aliasname) {
|
|
3109
3338
|
let aliasStr = node.alias.aliasname;
|
|
3110
3339
|
if (node.alias.colnames && node.alias.colnames.length > 0) {
|
|
@@ -5823,38 +6052,82 @@ class Deparser {
|
|
|
5823
6052
|
return output.join(' ');
|
|
5824
6053
|
}
|
|
5825
6054
|
CreatePolicyStmt(node, context) {
|
|
5826
|
-
const output = [
|
|
6055
|
+
const output = [];
|
|
6056
|
+
const initialParts = ['CREATE', 'POLICY'];
|
|
5827
6057
|
if (node.policy_name) {
|
|
5828
|
-
|
|
6058
|
+
initialParts.push(`"${node.policy_name}"`);
|
|
5829
6059
|
}
|
|
5830
|
-
output.push('
|
|
6060
|
+
output.push(initialParts.join(' '));
|
|
6061
|
+
// Add ON clause on new line in pretty mode
|
|
5831
6062
|
if (node.table) {
|
|
5832
|
-
|
|
6063
|
+
if (this.formatter.isPretty()) {
|
|
6064
|
+
output.push(this.formatter.newline() + this.formatter.indent(`ON ${this.RangeVar(node.table, context)}`));
|
|
6065
|
+
}
|
|
6066
|
+
else {
|
|
6067
|
+
output.push('ON');
|
|
6068
|
+
output.push(this.RangeVar(node.table, context));
|
|
6069
|
+
}
|
|
5833
6070
|
}
|
|
5834
6071
|
// Handle AS RESTRICTIVE/PERMISSIVE clause
|
|
5835
6072
|
if (node.permissive === undefined) {
|
|
5836
|
-
|
|
6073
|
+
if (this.formatter.isPretty()) {
|
|
6074
|
+
output.push(this.formatter.newline() + this.formatter.indent('AS RESTRICTIVE'));
|
|
6075
|
+
}
|
|
6076
|
+
else {
|
|
6077
|
+
output.push('AS', 'RESTRICTIVE');
|
|
6078
|
+
}
|
|
5837
6079
|
}
|
|
5838
6080
|
else if (node.permissive === true) {
|
|
5839
|
-
|
|
6081
|
+
if (this.formatter.isPretty()) {
|
|
6082
|
+
output.push(this.formatter.newline() + this.formatter.indent('AS PERMISSIVE'));
|
|
6083
|
+
}
|
|
6084
|
+
else {
|
|
6085
|
+
output.push('AS', 'PERMISSIVE');
|
|
6086
|
+
}
|
|
5840
6087
|
}
|
|
5841
6088
|
if (node.cmd_name) {
|
|
5842
|
-
|
|
6089
|
+
if (this.formatter.isPretty()) {
|
|
6090
|
+
output.push(this.formatter.newline() + this.formatter.indent(`FOR ${node.cmd_name.toUpperCase()}`));
|
|
6091
|
+
}
|
|
6092
|
+
else {
|
|
6093
|
+
output.push('FOR', node.cmd_name.toUpperCase());
|
|
6094
|
+
}
|
|
5843
6095
|
}
|
|
5844
6096
|
if (node.roles && node.roles.length > 0) {
|
|
5845
|
-
output.push('TO');
|
|
5846
6097
|
const roles = list_utils_1.ListUtils.unwrapList(node.roles).map(role => this.visit(role, context));
|
|
5847
|
-
|
|
6098
|
+
if (this.formatter.isPretty()) {
|
|
6099
|
+
output.push(this.formatter.newline() + this.formatter.indent(`TO ${roles.join(', ')}`));
|
|
6100
|
+
}
|
|
6101
|
+
else {
|
|
6102
|
+
output.push('TO');
|
|
6103
|
+
output.push(roles.join(', '));
|
|
6104
|
+
}
|
|
5848
6105
|
}
|
|
5849
6106
|
if (node.qual) {
|
|
5850
|
-
|
|
5851
|
-
|
|
6107
|
+
if (this.formatter.isPretty()) {
|
|
6108
|
+
const qualExpr = this.visit(node.qual, context);
|
|
6109
|
+
output.push(this.formatter.newline() + this.formatter.indent('USING ('));
|
|
6110
|
+
output.push(this.formatter.newline() + this.formatter.indent(this.formatter.indent(qualExpr)));
|
|
6111
|
+
output.push(this.formatter.newline() + this.formatter.indent(')'));
|
|
6112
|
+
}
|
|
6113
|
+
else {
|
|
6114
|
+
output.push('USING');
|
|
6115
|
+
output.push(`(${this.visit(node.qual, context)})`);
|
|
6116
|
+
}
|
|
5852
6117
|
}
|
|
5853
6118
|
if (node.with_check) {
|
|
5854
|
-
|
|
5855
|
-
|
|
6119
|
+
if (this.formatter.isPretty()) {
|
|
6120
|
+
const checkExpr = this.visit(node.with_check, context);
|
|
6121
|
+
output.push(this.formatter.newline() + this.formatter.indent('WITH CHECK ('));
|
|
6122
|
+
output.push(this.formatter.newline() + this.formatter.indent(this.formatter.indent(checkExpr)));
|
|
6123
|
+
output.push(this.formatter.newline() + this.formatter.indent(')'));
|
|
6124
|
+
}
|
|
6125
|
+
else {
|
|
6126
|
+
output.push('WITH CHECK');
|
|
6127
|
+
output.push(`(${this.visit(node.with_check, context)})`);
|
|
6128
|
+
}
|
|
5856
6129
|
}
|
|
5857
|
-
return output.join(' ');
|
|
6130
|
+
return this.formatter.isPretty() ? output.join('') : output.join(' ');
|
|
5858
6131
|
}
|
|
5859
6132
|
AlterPolicyStmt(node, context) {
|
|
5860
6133
|
const output = ['ALTER', 'POLICY'];
|
|
@@ -9720,5 +9993,9 @@ class Deparser {
|
|
|
9720
9993
|
}
|
|
9721
9994
|
return output.join(' ');
|
|
9722
9995
|
}
|
|
9996
|
+
containsMultilineStringLiteral(content) {
|
|
9997
|
+
const stringLiteralRegex = /'[^']*\n[^']*'/g;
|
|
9998
|
+
return stringLiteralRegex.test(content);
|
|
9999
|
+
}
|
|
9723
10000
|
}
|
|
9724
10001
|
exports.Deparser = Deparser;
|