pgsql-deparser 16.0.0 → 17.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 (35) hide show
  1. package/README.md +45 -88
  2. package/deparser.d.ts +253 -0
  3. package/{deparser/deparser.js → deparser.js} +180 -579
  4. package/esm/{deparser/deparser.js → deparser.js} +180 -579
  5. package/esm/index.js +3 -15
  6. package/esm/utils/index.js +90 -0
  7. package/esm/{deparser/utils → utils}/list-utils.js +0 -4
  8. package/esm/{deparser/utils → utils}/quote-utils.js +0 -34
  9. package/esm/utils/sql-formatter.js +23 -0
  10. package/esm/{deparser/visitors → visitors}/base.js +0 -4
  11. package/index.d.ts +3 -9
  12. package/index.js +4 -16
  13. package/package.json +27 -14
  14. package/utils/index.d.ts +4 -0
  15. package/utils/index.js +97 -0
  16. package/{deparser/utils → utils}/list-utils.d.ts +0 -4
  17. package/{deparser/utils → utils}/list-utils.js +0 -4
  18. package/utils/quote-utils.d.ts +5 -0
  19. package/{deparser/utils → utils}/quote-utils.js +0 -34
  20. package/{deparser/utils → utils}/sql-formatter.d.ts +1 -7
  21. package/{deparser/utils → utils}/sql-formatter.js +2 -15
  22. package/{deparser/visitors → visitors}/base.d.ts +5 -8
  23. package/{deparser/visitors → visitors}/base.js +0 -4
  24. package/deparser/deparser.d.ts +0 -301
  25. package/deparser/index.d.ts +0 -9
  26. package/deparser/index.js +0 -17
  27. package/deparser/utils/quote-utils.d.ts +0 -24
  28. package/esm/deparser/index.js +0 -13
  29. package/esm/deparser/utils/sql-formatter.js +0 -36
  30. package/esm/v16-to-v17-direct.js +0 -44
  31. package/esm/v16-to-v17.js +0 -1488
  32. package/v16-to-v17-direct.d.ts +0 -21
  33. package/v16-to-v17-direct.js +0 -48
  34. package/v16-to-v17.d.ts +0 -638
  35. package/v16-to-v17.js +0 -1492
@@ -1,116 +1,27 @@
1
- /**
2
- * Auto-generated file with types stripped for better tree-shaking
3
- * DO NOT EDIT - Generated by strip-deparser-types.ts
4
- */
5
1
  import { SqlFormatter } from './utils/sql-formatter';
6
2
  import { QuoteUtils } from './utils/quote-utils';
7
3
  import { ListUtils } from './utils/list-utils';
8
- // Type guards for better type safety
9
- function isParseResult(obj) {
10
- // A ParseResult is an object that could have stmts (but not required)
11
- // and is not already wrapped as a Node
12
- // IMPORTANT: ParseResult.stmts is "repeated RawStmt" in protobuf, meaning
13
- // the array contains RawStmt objects inline (not wrapped as { RawStmt: ... })
14
- // Example: { version: 170004, stmts: [{ stmt: {...}, stmt_len: 32 }] }
15
- return obj && typeof obj === 'object' &&
16
- !Array.isArray(obj) &&
17
- !('ParseResult' in obj) &&
18
- !('RawStmt' in obj) &&
19
- // Check if it looks like a ParseResult (has stmts or version)
20
- ('stmts' in obj || 'version' in obj);
21
- }
22
- function isWrappedParseResult(obj) {
23
- return obj && typeof obj === 'object' && 'ParseResult' in obj;
24
- }
25
- /**
26
- * Deparser - Converts PostgreSQL AST nodes back to SQL strings
27
- *
28
- * Entry Points:
29
- * 1. ParseResult (from libpg-query) - The complete parse result
30
- * Structure: { version: number, stmts: RawStmt[] }
31
- * Note: stmts is "repeated RawStmt" in protobuf, so array contains RawStmt
32
- * objects inline (not wrapped as { RawStmt: ... } nodes)
33
- * Example: { version: 170004, stmts: [{ stmt: {...}, stmt_len: 32 }] }
34
- *
35
- * 2. Wrapped ParseResult - When explicitly wrapped as a Node
36
- * Structure: { ParseResult: { version: number, stmts: RawStmt[] } }
37
- *
38
- * 3. Wrapped RawStmt - When explicitly wrapped as a Node
39
- * Structure: { RawStmt: { stmt: Node, stmt_len?: number } }
40
- *
41
- * 4. Array of Nodes - Multiple statements to deparse
42
- * Can be: Node[] (e.g., SelectStmt, InsertStmt, etc.)
43
- *
44
- * 5. Single Node - Individual statement node
45
- * Example: { SelectStmt: {...} }, { InsertStmt: {...} }, etc.
46
- *
47
- * The deparser automatically detects bare ParseResult objects for backward
48
- * compatibility and wraps them internally for consistent processing.
49
- */
50
4
  export class Deparser {
51
5
  formatter;
52
6
  tree;
53
- options;
54
7
  constructor(tree, opts = {}) {
55
- this.formatter = new SqlFormatter(opts.newline, opts.tab, opts.pretty);
56
- // Set default options
57
- this.options = {
58
- functionDelimiter: '$$',
59
- functionDelimiterFallback: '$EOFCODE$',
60
- ...opts
61
- };
62
- // Handle different input types
63
- if (isParseResult(tree)) {
64
- // Duck-typed ParseResult (backward compatibility)
65
- // Wrap it as a proper Node for consistent handling
66
- this.tree = [{ ParseResult: tree }];
67
- }
68
- else if (Array.isArray(tree)) {
69
- // Array of Nodes
70
- this.tree = tree;
8
+ this.formatter = new SqlFormatter(opts.newline, opts.tab);
9
+ // Handle parsed query objects that contain both version and stmts
10
+ if (tree && typeof tree === 'object' && !Array.isArray(tree) && 'stmts' in tree) {
11
+ this.tree = tree.stmts;
71
12
  }
72
13
  else {
73
- // Single Node (including wrapped ParseResult)
74
- this.tree = [tree];
75
- }
76
- }
77
- /**
78
- * Static method to deparse PostgreSQL AST nodes to SQL
79
- * @param query - Can be:
80
- * - ParseResult from libpg-query (e.g., { version: 170004, stmts: [...] })
81
- * - Wrapped ParseResult node (e.g., { ParseResult: {...} })
82
- * - Wrapped RawStmt node (e.g., { RawStmt: {...} })
83
- * - Array of Nodes
84
- * - Single Node (e.g., { SelectStmt: {...} })
85
- * @param opts - Deparser options for formatting
86
- * @returns The deparsed SQL string
87
- */
14
+ this.tree = Array.isArray(tree) ? tree : [tree];
15
+ }
16
+ }
88
17
  static deparse(query, opts = {}) {
89
18
  return new Deparser(query, opts).deparseQuery();
90
19
  }
91
20
  deparseQuery() {
92
21
  return this.tree
93
- .map(node => {
94
- // All nodes should go through the standard deparse method
95
- // which will route to the appropriate handler
96
- const result = this.deparse(node);
97
- return result || '';
98
- })
99
- .filter(result => result !== '')
22
+ .map(node => this.deparse(node))
100
23
  .join(this.formatter.newline() + this.formatter.newline());
101
24
  }
102
- /**
103
- * Get the appropriate function delimiter based on the body content
104
- * @param body The function body to check
105
- * @returns The delimiter to use
106
- */
107
- getFunctionDelimiter(body) {
108
- const delimiter = this.options.functionDelimiter || '$$';
109
- if (body.includes(delimiter)) {
110
- return this.options.functionDelimiterFallback || '$EOFCODE$';
111
- }
112
- return delimiter;
113
- }
114
25
  deparse(node, context = { parentNodeTypes: [] }) {
115
26
  if (node == null) {
116
27
  return null;
@@ -128,10 +39,6 @@ export class Deparser {
128
39
  }
129
40
  visit(node, context = { parentNodeTypes: [] }) {
130
41
  const nodeType = this.getNodeType(node);
131
- // Handle empty objects
132
- if (!nodeType) {
133
- return '';
134
- }
135
42
  const nodeData = this.getNodeData(node);
136
43
  const methodName = nodeType;
137
44
  if (typeof this[methodName] === 'function') {
@@ -154,29 +61,24 @@ export class Deparser {
154
61
  }
155
62
  return node;
156
63
  }
157
- ParseResult(node, context) {
158
- if (!node.stmts || node.stmts.length === 0) {
159
- return '';
160
- }
161
- // Deparse each RawStmt in the ParseResult
162
- // Note: node.stmts is "repeated RawStmt" so contains RawStmt objects inline
163
- // Each element has structure: { stmt: Node, stmt_len?: number, stmt_location?: number }
164
- return node.stmts
165
- .filter((rawStmt) => rawStmt != null)
166
- .map((rawStmt) => this.RawStmt(rawStmt, context))
167
- .filter((result) => result !== '')
168
- .join(this.formatter.newline() + this.formatter.newline());
169
- }
170
64
  RawStmt(node, context) {
171
- if (!node.stmt) {
172
- return '';
173
- }
174
- const deparsedStmt = this.deparse(node.stmt, context);
175
- // Add semicolon if stmt_len is provided (indicates it had one in original)
176
65
  if (node.stmt_len) {
177
- return deparsedStmt + ';';
66
+ return this.deparse(node.stmt, context) + ';';
67
+ }
68
+ return this.deparse(node.stmt, context);
69
+ }
70
+ stmt(node, context = { parentNodeTypes: [] }) {
71
+ // Handle stmt wrapper nodes that contain the actual statement
72
+ const keys = Object.keys(node);
73
+ if (keys.length === 1) {
74
+ const statementType = keys[0];
75
+ const methodName = statementType;
76
+ if (typeof this[methodName] === 'function') {
77
+ return this[methodName](node[statementType], context);
78
+ }
79
+ throw new Error(`Deparser does not handle statement type: ${statementType}`);
178
80
  }
179
- return deparsedStmt;
81
+ return '';
180
82
  }
181
83
  SelectStmt(node, context) {
182
84
  const output = [];
@@ -185,25 +87,23 @@ export class Deparser {
185
87
  }
186
88
  if (!node.op || node.op === 'SETOP_NONE') {
187
89
  if (node.valuesLists == null) {
188
- if (!this.formatter.isPretty() || !node.targetList) {
189
- output.push('SELECT');
190
- }
90
+ output.push('SELECT');
191
91
  }
192
92
  }
193
93
  else {
194
94
  const leftStmt = this.SelectStmt(node.larg, context);
195
95
  const rightStmt = this.SelectStmt(node.rarg, context);
196
96
  // Add parentheses if the operand is a set operation OR has ORDER BY/LIMIT clauses OR has WITH clause
197
- const leftNeedsParens = node.larg && (((node.larg).op && (node.larg).op !== 'SETOP_NONE') ||
198
- (node.larg).sortClause ||
199
- (node.larg).limitCount ||
200
- (node.larg).limitOffset ||
201
- (node.larg).withClause);
202
- const rightNeedsParens = node.rarg && (((node.rarg).op && (node.rarg).op !== 'SETOP_NONE') ||
203
- (node.rarg).sortClause ||
204
- (node.rarg).limitCount ||
205
- (node.rarg).limitOffset ||
206
- (node.rarg).withClause);
97
+ const leftNeedsParens = node.larg && ((node.larg.op && node.larg.op !== 'SETOP_NONE') ||
98
+ node.larg.sortClause ||
99
+ node.larg.limitCount ||
100
+ node.larg.limitOffset ||
101
+ node.larg.withClause);
102
+ const rightNeedsParens = node.rarg && ((node.rarg.op && node.rarg.op !== 'SETOP_NONE') ||
103
+ node.rarg.sortClause ||
104
+ node.rarg.limitCount ||
105
+ node.rarg.limitOffset ||
106
+ node.rarg.withClause);
207
107
  if (leftNeedsParens) {
208
108
  output.push(this.formatter.parens(leftStmt));
209
109
  }
@@ -233,82 +133,41 @@ export class Deparser {
233
133
  output.push(rightStmt);
234
134
  }
235
135
  }
236
- // Handle DISTINCT clause - in pretty mode, we'll include it in the SELECT clause
237
- let distinctPart = '';
238
136
  if (node.distinctClause) {
239
137
  const distinctClause = ListUtils.unwrapList(node.distinctClause);
240
138
  if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
139
+ output.push('DISTINCT ON');
241
140
  const clause = distinctClause
242
141
  .map(e => this.visit(e, { ...context, select: true }))
243
142
  .join(', ');
244
- distinctPart = ' DISTINCT ON ' + this.formatter.parens(clause);
143
+ output.push(this.formatter.parens(clause));
245
144
  }
246
145
  else {
247
- distinctPart = ' DISTINCT';
248
- }
249
- if (!this.formatter.isPretty()) {
250
- if (distinctClause.length > 0 && Object.keys(distinctClause[0]).length > 0) {
251
- output.push('DISTINCT ON');
252
- const clause = distinctClause
253
- .map(e => this.visit(e, { ...context, select: true }))
254
- .join(', ');
255
- output.push(this.formatter.parens(clause));
256
- }
257
- else {
258
- output.push('DISTINCT');
259
- }
146
+ output.push('DISTINCT');
260
147
  }
261
148
  }
262
149
  if (node.targetList) {
263
150
  const targetList = ListUtils.unwrapList(node.targetList);
264
- if (this.formatter.isPretty()) {
265
- const targetStrings = targetList
266
- .map(e => {
267
- const targetStr = this.visit(e, { ...context, select: true });
268
- if (this.containsMultilineStringLiteral(targetStr)) {
269
- return targetStr;
270
- }
271
- return this.formatter.indent(targetStr);
272
- });
273
- const formattedTargets = targetStrings.join(',' + this.formatter.newline());
274
- output.push('SELECT' + distinctPart);
275
- output.push(formattedTargets);
276
- }
277
- else {
278
- const targets = targetList
279
- .map(e => this.visit(e, { ...context, select: true }))
280
- .join(', ');
281
- output.push(targets);
282
- }
151
+ const targets = targetList
152
+ .map(e => this.visit(e, { ...context, select: true }))
153
+ .join(', ');
154
+ output.push(targets);
283
155
  }
284
156
  if (node.intoClause) {
285
157
  output.push('INTO');
286
158
  output.push(this.IntoClause(node.intoClause, context));
287
159
  }
288
160
  if (node.fromClause) {
161
+ output.push('FROM');
289
162
  const fromList = ListUtils.unwrapList(node.fromClause);
290
163
  const fromItems = fromList
291
164
  .map(e => this.deparse(e, { ...context, from: true }))
292
165
  .join(', ');
293
- output.push('FROM ' + fromItems.trim());
166
+ output.push(fromItems);
294
167
  }
295
168
  if (node.whereClause) {
296
- if (this.formatter.isPretty()) {
297
- output.push('WHERE');
298
- const whereExpr = this.visit(node.whereClause, context);
299
- const lines = whereExpr.split(this.formatter.newline());
300
- const indentedLines = lines.map((line, index) => {
301
- if (index === 0) {
302
- return this.formatter.indent(line);
303
- }
304
- return line;
305
- });
306
- output.push(indentedLines.join(this.formatter.newline()));
307
- }
308
- else {
309
- output.push('WHERE');
310
- output.push(this.visit(node.whereClause, context));
311
- }
169
+ output.push('WHERE');
170
+ output.push(this.visit(node.whereClause, context));
312
171
  }
313
172
  if (node.valuesLists) {
314
173
  output.push('VALUES');
@@ -319,43 +178,16 @@ export class Deparser {
319
178
  output.push(lists.join(', '));
320
179
  }
321
180
  if (node.groupClause) {
181
+ output.push('GROUP BY');
322
182
  const groupList = ListUtils.unwrapList(node.groupClause);
323
- if (this.formatter.isPretty()) {
324
- const groupItems = groupList
325
- .map(e => {
326
- const groupStr = this.visit(e, { ...context, group: true });
327
- if (this.containsMultilineStringLiteral(groupStr)) {
328
- return groupStr;
329
- }
330
- return this.formatter.indent(groupStr);
331
- })
332
- .join(',' + this.formatter.newline());
333
- output.push('GROUP BY');
334
- output.push(groupItems);
335
- }
336
- else {
337
- output.push('GROUP BY');
338
- const groupItems = groupList
339
- .map(e => this.visit(e, { ...context, group: true }))
340
- .join(', ');
341
- output.push(groupItems);
342
- }
183
+ const groupItems = groupList
184
+ .map(e => this.visit(e, { ...context, group: true }))
185
+ .join(', ');
186
+ output.push(groupItems);
343
187
  }
344
188
  if (node.havingClause) {
345
- if (this.formatter.isPretty()) {
346
- output.push('HAVING');
347
- const havingStr = this.visit(node.havingClause, context);
348
- if (this.containsMultilineStringLiteral(havingStr)) {
349
- output.push(havingStr);
350
- }
351
- else {
352
- output.push(this.formatter.indent(havingStr));
353
- }
354
- }
355
- else {
356
- output.push('HAVING');
357
- output.push(this.visit(node.havingClause, context));
358
- }
189
+ output.push('HAVING');
190
+ output.push(this.visit(node.havingClause, context));
359
191
  }
360
192
  if (node.windowClause) {
361
193
  output.push('WINDOW');
@@ -366,33 +198,20 @@ export class Deparser {
366
198
  output.push(windowClauses);
367
199
  }
368
200
  if (node.sortClause) {
201
+ output.push('ORDER BY');
369
202
  const sortList = ListUtils.unwrapList(node.sortClause);
370
- if (this.formatter.isPretty()) {
371
- const sortItems = sortList
372
- .map(e => {
373
- const sortStr = this.visit(e, { ...context, sort: true });
374
- if (this.containsMultilineStringLiteral(sortStr)) {
375
- return sortStr;
376
- }
377
- return this.formatter.indent(sortStr);
378
- })
379
- .join(',' + this.formatter.newline());
380
- output.push('ORDER BY');
381
- output.push(sortItems);
382
- }
383
- else {
384
- output.push('ORDER BY');
385
- const sortItems = sortList
386
- .map(e => this.visit(e, { ...context, sort: true }))
387
- .join(', ');
388
- output.push(sortItems);
389
- }
203
+ const sortItems = sortList
204
+ .map(e => this.visit(e, { ...context, sort: true }))
205
+ .join(', ');
206
+ output.push(sortItems);
390
207
  }
391
208
  if (node.limitCount) {
392
- output.push('LIMIT ' + this.visit(node.limitCount, context));
209
+ output.push('LIMIT');
210
+ output.push(this.visit(node.limitCount, context));
393
211
  }
394
212
  if (node.limitOffset) {
395
- output.push('OFFSET ' + this.visit(node.limitOffset, context));
213
+ output.push('OFFSET');
214
+ output.push(this.visit(node.limitOffset, context));
396
215
  }
397
216
  if (node.lockingClause) {
398
217
  const lockingList = ListUtils.unwrapList(node.lockingClause);
@@ -401,10 +220,6 @@ export class Deparser {
401
220
  .join(' ');
402
221
  output.push(lockingClauses);
403
222
  }
404
- if (this.formatter.isPretty()) {
405
- const filteredOutput = output.filter(item => item.trim() !== '');
406
- return filteredOutput.join(this.formatter.newline());
407
- }
408
223
  return output.join(' ');
409
224
  }
410
225
  A_Expr(node, context) {
@@ -469,38 +284,18 @@ export class Deparser {
469
284
  'ALL',
470
285
  this.formatter.parens(this.visit(rexpr, context))
471
286
  ]);
472
- case 'AEXPR_DISTINCT': {
473
- let leftExpr = this.visit(lexpr, context);
474
- let rightExpr = this.visit(rexpr, context);
475
- // Add parentheses for complex expressions
476
- if (lexpr && this.isComplexExpression(lexpr)) {
477
- leftExpr = this.formatter.parens(leftExpr);
478
- }
479
- if (rexpr && this.isComplexExpression(rexpr)) {
480
- rightExpr = this.formatter.parens(rightExpr);
481
- }
287
+ case 'AEXPR_DISTINCT':
482
288
  return this.formatter.format([
483
- leftExpr,
289
+ this.visit(lexpr, context),
484
290
  'IS DISTINCT FROM',
485
- rightExpr
291
+ this.visit(rexpr, context)
486
292
  ]);
487
- }
488
- case 'AEXPR_NOT_DISTINCT': {
489
- let leftExpr = this.visit(lexpr, context);
490
- let rightExpr = this.visit(rexpr, context);
491
- // Add parentheses for complex expressions
492
- if (lexpr && this.isComplexExpression(lexpr)) {
493
- leftExpr = this.formatter.parens(leftExpr);
494
- }
495
- if (rexpr && this.isComplexExpression(rexpr)) {
496
- rightExpr = this.formatter.parens(rightExpr);
497
- }
293
+ case 'AEXPR_NOT_DISTINCT':
498
294
  return this.formatter.format([
499
- leftExpr,
295
+ this.visit(lexpr, context),
500
296
  'IS NOT DISTINCT FROM',
501
- rightExpr
297
+ this.visit(rexpr, context)
502
298
  ]);
503
- }
504
299
  case 'AEXPR_NULLIF':
505
300
  return this.formatter.format([
506
301
  'NULLIF',
@@ -894,24 +689,9 @@ export class Deparser {
894
689
  if (node.recursive) {
895
690
  output.push('RECURSIVE');
896
691
  }
897
- if (node.ctes && node.ctes.length > 0) {
898
- const ctes = ListUtils.unwrapList(node.ctes);
899
- if (this.formatter.isPretty()) {
900
- const cteStrings = ctes.map((cte, index) => {
901
- const cteStr = this.visit(cte, context);
902
- const prefix = index === 0 ? this.formatter.newline() : ',' + this.formatter.newline();
903
- if (this.containsMultilineStringLiteral(cteStr)) {
904
- return prefix + cteStr;
905
- }
906
- return prefix + this.formatter.indent(cteStr);
907
- });
908
- output.push(cteStrings.join(''));
909
- }
910
- else {
911
- const cteStrings = ctes.map(cte => this.visit(cte, context));
912
- output.push(cteStrings.join(', '));
913
- }
914
- }
692
+ const ctes = ListUtils.unwrapList(node.ctes);
693
+ const cteStrs = ctes.map(cte => this.visit(cte, context));
694
+ output.push(cteStrs.join(', '));
915
695
  return output.join(' ');
916
696
  }
917
697
  ResTarget(node, context) {
@@ -990,28 +770,13 @@ export class Deparser {
990
770
  formatStr = '(%s)';
991
771
  }
992
772
  const boolContext = { ...context, bool: true };
993
- // explanation of our syntax/fix below:
994
- // return formatStr.replace('%s', andArgs); // ❌ Interprets $ as special syntax
995
- // return formatStr.replace('%s', () => andArgs); // ✅ Function callback prevents interpretation
996
773
  switch (boolop) {
997
774
  case 'AND_EXPR':
998
- if (this.formatter.isPretty() && args.length > 1) {
999
- const andArgs = args.map(arg => this.visit(arg, boolContext)).join(this.formatter.newline() + ' AND ');
1000
- return formatStr.replace('%s', () => andArgs);
1001
- }
1002
- else {
1003
- const andArgs = args.map(arg => this.visit(arg, boolContext)).join(' AND ');
1004
- return formatStr.replace('%s', () => andArgs);
1005
- }
775
+ const andArgs = args.map(arg => this.visit(arg, boolContext)).join(' AND ');
776
+ return formatStr.replace('%s', andArgs);
1006
777
  case 'OR_EXPR':
1007
- if (this.formatter.isPretty() && args.length > 1) {
1008
- const orArgs = args.map(arg => this.visit(arg, boolContext)).join(this.formatter.newline() + ' OR ');
1009
- return formatStr.replace('%s', () => orArgs);
1010
- }
1011
- else {
1012
- const orArgs = args.map(arg => this.visit(arg, boolContext)).join(' OR ');
1013
- return formatStr.replace('%s', () => orArgs);
1014
- }
778
+ const orArgs = args.map(arg => this.visit(arg, boolContext)).join(' OR ');
779
+ return formatStr.replace('%s', orArgs);
1015
780
  case 'NOT_EXPR':
1016
781
  return `NOT (${this.visit(args[0], context)})`;
1017
782
  default:
@@ -1213,13 +978,7 @@ export class Deparser {
1213
978
  windowParts.push(frameClause);
1214
979
  }
1215
980
  if (windowParts.length > 0) {
1216
- if (this.formatter.isPretty() && windowParts.length > 1) {
1217
- const formattedParts = windowParts.map(part => this.formatter.indent(part));
1218
- result += ` OVER (${this.formatter.newline()}${formattedParts.join(this.formatter.newline())}${this.formatter.newline()})`;
1219
- }
1220
- else {
1221
- result += ` OVER (${windowParts.join(' ')})`;
1222
- }
981
+ result += ` OVER (${windowParts.join(' ')})`;
1223
982
  }
1224
983
  else {
1225
984
  result += ` OVER ()`;
@@ -1276,23 +1035,23 @@ export class Deparser {
1276
1035
  else if (nodeAny.sval !== undefined) {
1277
1036
  if (typeof nodeAny.sval === 'object' && nodeAny.sval !== null) {
1278
1037
  if (nodeAny.sval.sval !== undefined) {
1279
- return QuoteUtils.formatEString(nodeAny.sval.sval);
1038
+ return QuoteUtils.escape(nodeAny.sval.sval);
1280
1039
  }
1281
1040
  else if (nodeAny.sval.String && nodeAny.sval.String.sval !== undefined) {
1282
- return QuoteUtils.formatEString(nodeAny.sval.String.sval);
1041
+ return QuoteUtils.escape(nodeAny.sval.String.sval);
1283
1042
  }
1284
1043
  else if (Object.keys(nodeAny.sval).length === 0) {
1285
1044
  return "''";
1286
1045
  }
1287
1046
  else {
1288
- return QuoteUtils.formatEString(nodeAny.sval.toString());
1047
+ return QuoteUtils.escape(nodeAny.sval.toString());
1289
1048
  }
1290
1049
  }
1291
1050
  else if (nodeAny.sval === null) {
1292
1051
  return 'NULL';
1293
1052
  }
1294
1053
  else {
1295
- return QuoteUtils.formatEString(nodeAny.sval);
1054
+ return QuoteUtils.escape(nodeAny.sval);
1296
1055
  }
1297
1056
  }
1298
1057
  else if (nodeAny.boolval !== undefined) {
@@ -1431,7 +1190,7 @@ export class Deparser {
1431
1190
  }
1432
1191
  let args = null;
1433
1192
  if (node.typmods) {
1434
- const isInterval = names.some((name) => {
1193
+ const isInterval = names.some(name => {
1435
1194
  const nameStr = typeof name === 'string' ? name : (name.String?.sval || name.String?.str);
1436
1195
  return nameStr === 'interval';
1437
1196
  });
@@ -1600,14 +1359,7 @@ export class Deparser {
1600
1359
  output.push('ONLY');
1601
1360
  }
1602
1361
  let tableName = '';
1603
- if (node.catalogname) {
1604
- tableName = QuoteUtils.quote(node.catalogname);
1605
- if (node.schemaname) {
1606
- tableName += '.' + QuoteUtils.quote(node.schemaname);
1607
- }
1608
- tableName += '.' + QuoteUtils.quote(node.relname);
1609
- }
1610
- else if (node.schemaname) {
1362
+ if (node.schemaname) {
1611
1363
  tableName = QuoteUtils.quote(node.schemaname) + '.' + QuoteUtils.quote(node.relname);
1612
1364
  }
1613
1365
  else {
@@ -1843,39 +1595,15 @@ export class Deparser {
1843
1595
  output.push(this.visit(node.arg, context));
1844
1596
  }
1845
1597
  const args = ListUtils.unwrapList(node.args);
1846
- if (this.formatter.isPretty() && args.length > 0) {
1847
- for (const arg of args) {
1848
- const whenClause = this.visit(arg, context);
1849
- if (this.containsMultilineStringLiteral(whenClause)) {
1850
- output.push(this.formatter.newline() + whenClause);
1851
- }
1852
- else {
1853
- output.push(this.formatter.newline() + this.formatter.indent(whenClause));
1854
- }
1855
- }
1856
- if (node.defresult) {
1857
- const elseResult = this.visit(node.defresult, context);
1858
- if (this.containsMultilineStringLiteral(elseResult)) {
1859
- output.push(this.formatter.newline() + 'ELSE ' + elseResult);
1860
- }
1861
- else {
1862
- output.push(this.formatter.newline() + this.formatter.indent('ELSE ' + elseResult));
1863
- }
1864
- }
1865
- output.push(this.formatter.newline() + 'END');
1866
- return output.join(' ');
1598
+ for (const arg of args) {
1599
+ output.push(this.visit(arg, context));
1867
1600
  }
1868
- else {
1869
- for (const arg of args) {
1870
- output.push(this.visit(arg, context));
1871
- }
1872
- if (node.defresult) {
1873
- output.push('ELSE');
1874
- output.push(this.visit(node.defresult, context));
1875
- }
1876
- output.push('END');
1877
- return output.join(' ');
1601
+ if (node.defresult) {
1602
+ output.push('ELSE');
1603
+ output.push(this.visit(node.defresult, context));
1878
1604
  }
1605
+ output.push('END');
1606
+ return output.join(' ');
1879
1607
  }
1880
1608
  CoalesceExpr(node, context) {
1881
1609
  const args = ListUtils.unwrapList(node.args);
@@ -2010,7 +1738,7 @@ export class Deparser {
2010
1738
  }
2011
1739
  String(node, context) {
2012
1740
  if (context.isStringLiteral || context.isEnumValue) {
2013
- return QuoteUtils.formatEString(node.sval || '');
1741
+ return `'${node.sval || ''}'`;
2014
1742
  }
2015
1743
  const value = node.sval || '';
2016
1744
  if (context.parentNodeTypes.includes('DefElem') ||
@@ -2088,13 +1816,7 @@ export class Deparser {
2088
1816
  const elementStrs = elements.map(el => {
2089
1817
  return this.deparse(el, context);
2090
1818
  });
2091
- if (this.formatter.isPretty()) {
2092
- const formattedElements = elementStrs.map(el => this.formatter.indent(el)).join(',' + this.formatter.newline());
2093
- output.push('(' + this.formatter.newline() + formattedElements + this.formatter.newline() + ')');
2094
- }
2095
- else {
2096
- output.push(this.formatter.parens(elementStrs.join(', ')));
2097
- }
1819
+ output.push(this.formatter.parens(elementStrs.join(', ')));
2098
1820
  }
2099
1821
  else if (!node.partbound) {
2100
1822
  output.push(this.formatter.parens(''));
@@ -2333,9 +2055,6 @@ export class Deparser {
2333
2055
  break;
2334
2056
  case 'CONSTR_UNIQUE':
2335
2057
  output.push('UNIQUE');
2336
- if (node.nulls_not_distinct) {
2337
- output.push('NULLS NOT DISTINCT');
2338
- }
2339
2058
  if (node.keys && node.keys.length > 0) {
2340
2059
  const keyList = ListUtils.unwrapList(node.keys)
2341
2060
  .map(key => this.visit(key, context))
@@ -2379,52 +2098,38 @@ export class Deparser {
2379
2098
  }
2380
2099
  }
2381
2100
  if (node.fk_upd_action && node.fk_upd_action !== 'a') {
2382
- let updateClause = 'ON UPDATE ';
2101
+ output.push('ON UPDATE');
2383
2102
  switch (node.fk_upd_action) {
2384
2103
  case 'r':
2385
- updateClause += 'RESTRICT';
2104
+ output.push('RESTRICT');
2386
2105
  break;
2387
2106
  case 'c':
2388
- updateClause += 'CASCADE';
2107
+ output.push('CASCADE');
2389
2108
  break;
2390
2109
  case 'n':
2391
- updateClause += 'SET NULL';
2110
+ output.push('SET NULL');
2392
2111
  break;
2393
2112
  case 'd':
2394
- updateClause += 'SET DEFAULT';
2113
+ output.push('SET DEFAULT');
2395
2114
  break;
2396
2115
  }
2397
- if (this.formatter.isPretty()) {
2398
- output.push('\n' + this.formatter.indent(updateClause));
2399
- }
2400
- else {
2401
- output.push('ON UPDATE');
2402
- output.push(updateClause.replace('ON UPDATE ', ''));
2403
- }
2404
2116
  }
2405
2117
  if (node.fk_del_action && node.fk_del_action !== 'a') {
2406
- let deleteClause = 'ON DELETE ';
2118
+ output.push('ON DELETE');
2407
2119
  switch (node.fk_del_action) {
2408
2120
  case 'r':
2409
- deleteClause += 'RESTRICT';
2121
+ output.push('RESTRICT');
2410
2122
  break;
2411
2123
  case 'c':
2412
- deleteClause += 'CASCADE';
2124
+ output.push('CASCADE');
2413
2125
  break;
2414
2126
  case 'n':
2415
- deleteClause += 'SET NULL';
2127
+ output.push('SET NULL');
2416
2128
  break;
2417
2129
  case 'd':
2418
- deleteClause += 'SET DEFAULT';
2130
+ output.push('SET DEFAULT');
2419
2131
  break;
2420
2132
  }
2421
- if (this.formatter.isPretty()) {
2422
- output.push('\n' + this.formatter.indent(deleteClause));
2423
- }
2424
- else {
2425
- output.push('ON DELETE');
2426
- output.push(deleteClause.replace('ON DELETE ', ''));
2427
- }
2428
2133
  }
2429
2134
  // Handle NOT VALID for foreign key constraints - only for table constraints, not domain constraints
2430
2135
  if (node.skip_validation && !context.isDomainConstraint) {
@@ -2482,48 +2187,17 @@ export class Deparser {
2482
2187
  // Handle deferrable constraints for all constraint types that support it
2483
2188
  if (node.contype === 'CONSTR_PRIMARY' || node.contype === 'CONSTR_UNIQUE' || node.contype === 'CONSTR_FOREIGN') {
2484
2189
  if (node.deferrable) {
2485
- if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2486
- output.push('\n' + this.formatter.indent('DEFERRABLE'));
2487
- if (node.initdeferred === true) {
2488
- output.push('\n' + this.formatter.indent('INITIALLY DEFERRED'));
2489
- }
2490
- else if (node.initdeferred === false) {
2491
- output.push('\n' + this.formatter.indent('INITIALLY IMMEDIATE'));
2492
- }
2190
+ output.push('DEFERRABLE');
2191
+ if (node.initdeferred === true) {
2192
+ output.push('INITIALLY DEFERRED');
2493
2193
  }
2494
- else {
2495
- output.push('DEFERRABLE');
2496
- if (node.initdeferred === true) {
2497
- output.push('INITIALLY DEFERRED');
2498
- }
2499
- else if (node.initdeferred === false) {
2500
- output.push('INITIALLY IMMEDIATE');
2501
- }
2194
+ else if (node.initdeferred === false) {
2195
+ output.push('INITIALLY IMMEDIATE');
2502
2196
  }
2503
2197
  }
2504
2198
  else if (node.deferrable === false) {
2505
- if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2506
- output.push('\n' + this.formatter.indent('NOT DEFERRABLE'));
2507
- }
2508
- else {
2509
- output.push('NOT DEFERRABLE');
2510
- }
2511
- }
2512
- }
2513
- if (this.formatter.isPretty() && node.contype === 'CONSTR_FOREIGN') {
2514
- let result = '';
2515
- for (let i = 0; i < output.length; i++) {
2516
- if (output[i].startsWith('\n')) {
2517
- result += output[i];
2518
- }
2519
- else {
2520
- if (i > 0 && !output[i - 1].startsWith('\n')) {
2521
- result += ' ';
2522
- }
2523
- result += output[i];
2524
- }
2199
+ output.push('NOT DEFERRABLE');
2525
2200
  }
2526
- return result;
2527
2201
  }
2528
2202
  return output.join(' ');
2529
2203
  }
@@ -3247,9 +2921,11 @@ export class Deparser {
3247
2921
  }
3248
2922
  switch (node.jointype) {
3249
2923
  case 'JOIN_INNER':
2924
+ // Handle NATURAL JOIN first - it has isNatural=true (NATURAL already added above)
3250
2925
  if (node.isNatural) {
3251
2926
  joinStr += 'JOIN';
3252
2927
  }
2928
+ // Handle CROSS JOIN case - when there's no quals, no usingClause, and not natural
3253
2929
  else if (!node.quals && (!node.usingClause || node.usingClause.length === 0)) {
3254
2930
  joinStr += 'CROSS JOIN';
3255
2931
  }
@@ -3269,63 +2945,26 @@ export class Deparser {
3269
2945
  default:
3270
2946
  joinStr += 'JOIN';
3271
2947
  }
2948
+ output.push(joinStr);
3272
2949
  if (node.rarg) {
3273
2950
  let rargStr = this.visit(node.rarg, context);
3274
2951
  if (node.rarg && 'JoinExpr' in node.rarg && !node.rarg.JoinExpr.alias) {
3275
2952
  rargStr = `(${rargStr})`;
3276
2953
  }
3277
- if (this.formatter.isPretty()) {
3278
- output.push(this.formatter.newline() + joinStr + ' ' + rargStr);
3279
- }
3280
- else {
3281
- output.push(joinStr + ' ' + rargStr);
3282
- }
3283
- }
3284
- else {
3285
- if (this.formatter.isPretty()) {
3286
- output.push(this.formatter.newline() + joinStr);
3287
- }
3288
- else {
3289
- output.push(joinStr);
3290
- }
2954
+ output.push(rargStr);
3291
2955
  }
3292
2956
  if (node.usingClause && node.usingClause.length > 0) {
2957
+ output.push('USING');
3293
2958
  const usingList = ListUtils.unwrapList(node.usingClause);
3294
2959
  const columnNames = usingList.map(col => this.visit(col, context));
3295
- if (this.formatter.isPretty()) {
3296
- output.push(` USING (${columnNames.join(', ')})`);
3297
- }
3298
- else {
3299
- output.push(`USING (${columnNames.join(', ')})`);
3300
- }
2960
+ output.push(`(${columnNames.join(', ')})`);
3301
2961
  }
3302
2962
  else if (node.quals) {
3303
- const qualsStr = this.visit(node.quals, context);
3304
- if (this.formatter.isPretty()) {
3305
- // For complex JOIN conditions, format with proper indentation
3306
- if (qualsStr.includes('AND') || qualsStr.includes('OR') || qualsStr.length > 50) {
3307
- if (this.containsMultilineStringLiteral(qualsStr)) {
3308
- output.push(` ON ${qualsStr}`);
3309
- }
3310
- else {
3311
- output.push(` ON${this.formatter.newline()}${this.formatter.indent(qualsStr)}`);
3312
- }
3313
- }
3314
- else {
3315
- output.push(` ON ${qualsStr}`);
3316
- }
3317
- }
3318
- else {
3319
- output.push(`ON ${qualsStr}`);
3320
- }
3321
- }
3322
- let result;
3323
- if (this.formatter.isPretty()) {
3324
- result = output.join('');
3325
- }
3326
- else {
3327
- result = output.join(' ');
2963
+ output.push('ON');
2964
+ output.push(this.visit(node.quals, context));
3328
2965
  }
2966
+ let result = output.join(' ');
2967
+ // Handle join_using_alias first (for USING clause aliases like "AS x")
3329
2968
  if (node.join_using_alias && node.join_using_alias.aliasname) {
3330
2969
  let aliasStr = node.join_using_alias.aliasname;
3331
2970
  if (node.join_using_alias.colnames && node.join_using_alias.colnames.length > 0) {
@@ -3335,6 +2974,7 @@ export class Deparser {
3335
2974
  }
3336
2975
  result += ` AS ${aliasStr}`;
3337
2976
  }
2977
+ // Handle regular alias (for outer table aliases like "y")
3338
2978
  if (node.alias && node.alias.aliasname) {
3339
2979
  let aliasStr = node.alias.aliasname;
3340
2980
  if (node.alias.colnames && node.alias.colnames.length > 0) {
@@ -5146,17 +4786,17 @@ export class Deparser {
5146
4786
  }
5147
4787
  if (context.parentNodeTypes.includes('DoStmt')) {
5148
4788
  if (node.defname === 'as') {
5149
- const defElemContext = { ...context, parentNodeTypes: [...context.parentNodeTypes, 'DefElem'] };
5150
- const argValue = node.arg ? this.visit(node.arg, defElemContext) : '';
5151
4789
  if (Array.isArray(argValue)) {
5152
4790
  const bodyParts = argValue;
5153
- const body = bodyParts.join('');
5154
- const delimiter = this.getFunctionDelimiter(body);
5155
- return `${delimiter}${body}${delimiter}`;
4791
+ if (bodyParts.length === 1) {
4792
+ return `$$${bodyParts[0]}$$`;
4793
+ }
4794
+ else {
4795
+ return `$$${bodyParts.join('')}$$`;
4796
+ }
5156
4797
  }
5157
4798
  else {
5158
- const delimiter = this.getFunctionDelimiter(argValue);
5159
- return `${delimiter}${argValue}${delimiter}`;
4799
+ return `$$${argValue}$$`;
5160
4800
  }
5161
4801
  }
5162
4802
  return '';
@@ -5175,14 +4815,16 @@ export class Deparser {
5175
4815
  });
5176
4816
  if (bodyParts.length === 1) {
5177
4817
  const body = bodyParts[0];
5178
- const delimiter = this.getFunctionDelimiter(body);
5179
- return `AS ${delimiter}${body}${delimiter}`;
4818
+ // Check if body contains $$ to avoid conflicts
4819
+ if (body.includes('$$')) {
4820
+ return `AS '${body.replace(/'/g, "''")}'`;
4821
+ }
4822
+ else {
4823
+ return `AS $$${body}$$`;
4824
+ }
5180
4825
  }
5181
4826
  else {
5182
- return `AS ${bodyParts.map((part) => {
5183
- const delimiter = this.getFunctionDelimiter(part);
5184
- return `${delimiter}${part}${delimiter}`;
5185
- }).join(', ')}`;
4827
+ return `AS ${bodyParts.map((part) => `$$${part}$$`).join(', ')}`;
5186
4828
  }
5187
4829
  }
5188
4830
  // Handle Array type (legacy support)
@@ -5190,20 +4832,27 @@ export class Deparser {
5190
4832
  const bodyParts = argValue;
5191
4833
  if (bodyParts.length === 1) {
5192
4834
  const body = bodyParts[0];
5193
- const delimiter = this.getFunctionDelimiter(body);
5194
- return `AS ${delimiter}${body}${delimiter}`;
4835
+ // Check if body contains $$ to avoid conflicts
4836
+ if (body.includes('$$')) {
4837
+ return `AS '${body.replace(/'/g, "''")}'`;
4838
+ }
4839
+ else {
4840
+ return `AS $$${body}$$`;
4841
+ }
5195
4842
  }
5196
4843
  else {
5197
- return `AS ${bodyParts.map(part => {
5198
- const delimiter = this.getFunctionDelimiter(part);
5199
- return `${delimiter}${part}${delimiter}`;
5200
- }).join(', ')}`;
4844
+ return `AS ${bodyParts.map(part => `$$${part}$$`).join(', ')}`;
5201
4845
  }
5202
4846
  }
5203
4847
  // Handle String type (single function body)
5204
4848
  else {
5205
- const delimiter = this.getFunctionDelimiter(argValue);
5206
- return `AS ${delimiter}${argValue}${delimiter}`;
4849
+ // Check if argValue contains $$ to avoid conflicts
4850
+ if (argValue.includes('$$')) {
4851
+ return `AS '${argValue.replace(/'/g, "''")}'`;
4852
+ }
4853
+ else {
4854
+ return `AS $$${argValue}$$`;
4855
+ }
5207
4856
  }
5208
4857
  }
5209
4858
  if (node.defname === 'language') {
@@ -5317,18 +4966,6 @@ export class Deparser {
5317
4966
  : argValue;
5318
4967
  return `${node.defname} = ${quotedValue}`;
5319
4968
  }
5320
- // Handle CopyStmt WITH clause options - uppercase format without quotes
5321
- if (context.parentNodeTypes.includes('CopyStmt')) {
5322
- if (node.defname === 'format' && node.arg && this.getNodeType(node.arg) === 'String') {
5323
- const stringData = this.getNodeData(node.arg);
5324
- return `FORMAT ${stringData.sval.toUpperCase()}`;
5325
- }
5326
- // Handle other COPY options with uppercase defname
5327
- if (node.arg) {
5328
- return `${node.defname.toUpperCase()} ${argValue}`;
5329
- }
5330
- return node.defname.toUpperCase();
5331
- }
5332
4969
  // Handle CREATE OPERATOR and CREATE TYPE context
5333
4970
  if (context.parentNodeTypes.includes('DefineStmt')) {
5334
4971
  const preservedName = this.preserveOperatorDefElemCase(node.defname);
@@ -6019,7 +5656,8 @@ export class Deparser {
6019
5656
  output.push('NULL');
6020
5657
  }
6021
5658
  else if (node.comment) {
6022
- output.push(QuoteUtils.formatEString(node.comment));
5659
+ const escapedComment = node.comment.replace(/'/g, "''");
5660
+ output.push(`'${escapedComment}'`);
6023
5661
  }
6024
5662
  return output.join(' ');
6025
5663
  }
@@ -6053,82 +5691,38 @@ export class Deparser {
6053
5691
  return output.join(' ');
6054
5692
  }
6055
5693
  CreatePolicyStmt(node, context) {
6056
- const output = [];
6057
- const initialParts = ['CREATE', 'POLICY'];
5694
+ const output = ['CREATE', 'POLICY'];
6058
5695
  if (node.policy_name) {
6059
- initialParts.push(`"${node.policy_name}"`);
5696
+ output.push(`"${node.policy_name}"`);
6060
5697
  }
6061
- output.push(initialParts.join(' '));
6062
- // Add ON clause on new line in pretty mode
5698
+ output.push('ON');
6063
5699
  if (node.table) {
6064
- if (this.formatter.isPretty()) {
6065
- output.push(this.formatter.newline() + this.formatter.indent(`ON ${this.RangeVar(node.table, context)}`));
6066
- }
6067
- else {
6068
- output.push('ON');
6069
- output.push(this.RangeVar(node.table, context));
6070
- }
5700
+ output.push(this.RangeVar(node.table, context));
6071
5701
  }
6072
5702
  // Handle AS RESTRICTIVE/PERMISSIVE clause
6073
5703
  if (node.permissive === undefined) {
6074
- if (this.formatter.isPretty()) {
6075
- output.push(this.formatter.newline() + this.formatter.indent('AS RESTRICTIVE'));
6076
- }
6077
- else {
6078
- output.push('AS', 'RESTRICTIVE');
6079
- }
5704
+ output.push('AS', 'RESTRICTIVE');
6080
5705
  }
6081
5706
  else if (node.permissive === true) {
6082
- if (this.formatter.isPretty()) {
6083
- output.push(this.formatter.newline() + this.formatter.indent('AS PERMISSIVE'));
6084
- }
6085
- else {
6086
- output.push('AS', 'PERMISSIVE');
6087
- }
5707
+ output.push('AS', 'PERMISSIVE');
6088
5708
  }
6089
5709
  if (node.cmd_name) {
6090
- if (this.formatter.isPretty()) {
6091
- output.push(this.formatter.newline() + this.formatter.indent(`FOR ${node.cmd_name.toUpperCase()}`));
6092
- }
6093
- else {
6094
- output.push('FOR', node.cmd_name.toUpperCase());
6095
- }
5710
+ output.push('FOR', node.cmd_name.toUpperCase());
6096
5711
  }
6097
5712
  if (node.roles && node.roles.length > 0) {
5713
+ output.push('TO');
6098
5714
  const roles = ListUtils.unwrapList(node.roles).map(role => this.visit(role, context));
6099
- if (this.formatter.isPretty()) {
6100
- output.push(this.formatter.newline() + this.formatter.indent(`TO ${roles.join(', ')}`));
6101
- }
6102
- else {
6103
- output.push('TO');
6104
- output.push(roles.join(', '));
6105
- }
5715
+ output.push(roles.join(', '));
6106
5716
  }
6107
5717
  if (node.qual) {
6108
- if (this.formatter.isPretty()) {
6109
- const qualExpr = this.visit(node.qual, context);
6110
- output.push(this.formatter.newline() + this.formatter.indent('USING ('));
6111
- output.push(this.formatter.newline() + this.formatter.indent(this.formatter.indent(qualExpr)));
6112
- output.push(this.formatter.newline() + this.formatter.indent(')'));
6113
- }
6114
- else {
6115
- output.push('USING');
6116
- output.push(`(${this.visit(node.qual, context)})`);
6117
- }
5718
+ output.push('USING');
5719
+ output.push(`(${this.visit(node.qual, context)})`);
6118
5720
  }
6119
5721
  if (node.with_check) {
6120
- if (this.formatter.isPretty()) {
6121
- const checkExpr = this.visit(node.with_check, context);
6122
- output.push(this.formatter.newline() + this.formatter.indent('WITH CHECK ('));
6123
- output.push(this.formatter.newline() + this.formatter.indent(this.formatter.indent(checkExpr)));
6124
- output.push(this.formatter.newline() + this.formatter.indent(')'));
6125
- }
6126
- else {
6127
- output.push('WITH CHECK');
6128
- output.push(`(${this.visit(node.with_check, context)})`);
6129
- }
5722
+ output.push('WITH CHECK');
5723
+ output.push(`(${this.visit(node.with_check, context)})`);
6130
5724
  }
6131
- return this.formatter.isPretty() ? output.join('') : output.join(' ');
5725
+ return output.join(' ');
6132
5726
  }
6133
5727
  AlterPolicyStmt(node, context) {
6134
5728
  const output = ['ALTER', 'POLICY'];
@@ -6368,12 +5962,12 @@ export class Deparser {
6368
5962
  processedArgs.push(`LANGUAGE ${langValue}`);
6369
5963
  }
6370
5964
  else if (defElem.defname === 'as') {
6371
- // Handle code block with configurable delimiter
5965
+ // Handle code block with dollar quoting
6372
5966
  const argNodeType = this.getNodeType(defElem.arg);
6373
5967
  if (argNodeType === 'String') {
6374
5968
  const stringNode = this.getNodeData(defElem.arg);
6375
- const delimiter = this.getFunctionDelimiter(stringNode.sval);
6376
- processedArgs.push(`${delimiter}${stringNode.sval}${delimiter}`);
5969
+ const dollarTag = this.generateUniqueDollarTag(stringNode.sval);
5970
+ processedArgs.push(`${dollarTag}${stringNode.sval}${dollarTag}`);
6377
5971
  }
6378
5972
  else {
6379
5973
  processedArgs.push(this.visit(defElem.arg, doContext));
@@ -6407,11 +6001,9 @@ export class Deparser {
6407
6001
  }
6408
6002
  InlineCodeBlock(node, context) {
6409
6003
  if (node.source_text) {
6410
- const delimiter = this.getFunctionDelimiter(node.source_text);
6411
- return `${delimiter}${node.source_text}${delimiter}`;
6004
+ return `$$${node.source_text}$$`;
6412
6005
  }
6413
- const delimiter = this.options.functionDelimiter || '$$';
6414
- return `${delimiter}${delimiter}`;
6006
+ return '$$$$';
6415
6007
  }
6416
6008
  CallContext(node, context) {
6417
6009
  if (node.atomic !== undefined) {
@@ -9994,8 +9586,17 @@ export class Deparser {
9994
9586
  }
9995
9587
  return output.join(' ');
9996
9588
  }
9997
- containsMultilineStringLiteral(content) {
9998
- const stringLiteralRegex = /'[^']*\n[^']*'/g;
9999
- return stringLiteralRegex.test(content);
9589
+ version(node, context) {
9590
+ // Handle version node - typically just return the version number
9591
+ if (typeof node === 'number') {
9592
+ return node.toString();
9593
+ }
9594
+ if (typeof node === 'string') {
9595
+ return node;
9596
+ }
9597
+ if (node && typeof node === 'object' && node.version) {
9598
+ return node.version.toString();
9599
+ }
9600
+ return '';
10000
9601
  }
10001
9602
  }