pgsql-deparser 17.18.0 → 17.18.2

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/deparser.js CHANGED
@@ -508,9 +508,7 @@ class Deparser {
508
508
  output.push('VALUES');
509
509
  const lists = list_utils_1.ListUtils.unwrapList(node.valuesLists).map(list => {
510
510
  const values = list_utils_1.ListUtils.unwrapList(list).map(val => this.visit(val, context));
511
- // Put each value on its own line for pretty printing
512
- const indentedValues = values.map(val => context.indent(val));
513
- return '(\n' + indentedValues.join(',\n') + '\n)';
511
+ return context.parens(values.join(', '));
514
512
  });
515
513
  const indentedTuples = lists.map(tuple => {
516
514
  if (this.containsMultilineStringLiteral(tuple)) {
@@ -660,10 +658,15 @@ class Deparser {
660
658
  return context.format([leftExpr, operator, rightExpr]);
661
659
  }
662
660
  else if (rexpr) {
663
- return context.format([
664
- this.deparseOperatorName(name, context),
665
- this.visit(rexpr, context)
666
- ]);
661
+ // Unary operator (e.g., unary minus: - expr)
662
+ const operator = this.deparseOperatorName(name, context);
663
+ let rightExpr = this.visit(rexpr, context);
664
+ // Wrap in parentheses if rexpr is a binary A_Expr to preserve semantics
665
+ // e.g., -(a - b) must stay -(a - b), not become -a - b
666
+ if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP' && rexpr.A_Expr?.lexpr) {
667
+ rightExpr = context.parens(rightExpr);
668
+ }
669
+ return context.format([operator, rightExpr]);
667
670
  }
668
671
  break;
669
672
  case 'AEXPR_OP_ANY':
@@ -1764,7 +1767,7 @@ class Deparser {
1764
1767
  }
1765
1768
  return output.join(' ');
1766
1769
  }
1767
- let result = mods(typeName, args);
1770
+ let result = mods(quotes_1.QuoteUtils.quoteIdentifierTypeName(typeName), args);
1768
1771
  if (node.arrayBounds && node.arrayBounds.length > 0) {
1769
1772
  result += formatArrayBounds(node.arrayBounds);
1770
1773
  }
@@ -2876,6 +2879,10 @@ class Deparser {
2876
2879
  });
2877
2880
  output.push(`(${exclusionElements.join(', ')})`);
2878
2881
  }
2882
+ if (node.where_clause) {
2883
+ output.push('WHERE');
2884
+ output.push(context.parens(this.visit(node.where_clause, context)));
2885
+ }
2879
2886
  break;
2880
2887
  }
2881
2888
  // Handle deferrable constraints for all constraint types that support it
@@ -3009,6 +3016,8 @@ class Deparser {
3009
3016
  if (!node.frameOptions)
3010
3017
  return null;
3011
3018
  const frameOptions = node.frameOptions;
3019
+ const EXCLUDE_MASK = 0x8000 | 0x10000 | 0x20000;
3020
+ const baseFrameOptions = frameOptions & ~EXCLUDE_MASK;
3012
3021
  const frameParts = [];
3013
3022
  if (frameOptions & 0x01) { // FRAMEOPTION_NONDEFAULT
3014
3023
  if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
@@ -3025,31 +3034,31 @@ class Deparser {
3025
3034
  return null;
3026
3035
  const boundsParts = [];
3027
3036
  // Handle specific frameOptions values that have known mappings
3028
- if (frameOptions === 789) {
3037
+ if (baseFrameOptions === 789) {
3029
3038
  boundsParts.push('CURRENT ROW');
3030
3039
  boundsParts.push('AND UNBOUNDED FOLLOWING');
3031
3040
  }
3032
- else if (frameOptions === 1077) {
3041
+ else if (baseFrameOptions === 1077) {
3033
3042
  boundsParts.push('UNBOUNDED PRECEDING');
3034
3043
  boundsParts.push('AND CURRENT ROW');
3035
3044
  }
3036
- else if (frameOptions === 18453) {
3045
+ else if (baseFrameOptions === 18453) {
3037
3046
  if (node.startOffset && node.endOffset) {
3038
3047
  boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3039
3048
  boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3040
3049
  }
3041
3050
  }
3042
- else if (frameOptions === 1557) {
3051
+ else if (baseFrameOptions === 1557) {
3043
3052
  boundsParts.push('CURRENT ROW');
3044
3053
  boundsParts.push('AND CURRENT ROW');
3045
3054
  }
3046
- else if (frameOptions === 16917) {
3055
+ else if (baseFrameOptions === 16917) {
3047
3056
  boundsParts.push('CURRENT ROW');
3048
3057
  if (node.endOffset) {
3049
3058
  boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3050
3059
  }
3051
3060
  }
3052
- else if (frameOptions === 1058) {
3061
+ else if (baseFrameOptions === 1058) {
3053
3062
  return null;
3054
3063
  }
3055
3064
  else {
@@ -3103,6 +3112,16 @@ class Deparser {
3103
3112
  frameParts.push('BETWEEN');
3104
3113
  frameParts.push(boundsParts.join(' '));
3105
3114
  }
3115
+ // EXCLUDE clause
3116
+ if (frameOptions & 0x8000) { // FRAMEOPTION_EXCLUDE_CURRENT_ROW
3117
+ frameParts.push('EXCLUDE CURRENT ROW');
3118
+ }
3119
+ else if (frameOptions & 0x10000) { // FRAMEOPTION_EXCLUDE_GROUP
3120
+ frameParts.push('EXCLUDE GROUP');
3121
+ }
3122
+ else if (frameOptions & 0x20000) { // FRAMEOPTION_EXCLUDE_TIES
3123
+ frameParts.push('EXCLUDE TIES');
3124
+ }
3106
3125
  return frameParts.join(' ');
3107
3126
  }
3108
3127
  SortBy(node, context) {
package/esm/deparser.js CHANGED
@@ -505,9 +505,7 @@ export class Deparser {
505
505
  output.push('VALUES');
506
506
  const lists = ListUtils.unwrapList(node.valuesLists).map(list => {
507
507
  const values = ListUtils.unwrapList(list).map(val => this.visit(val, context));
508
- // Put each value on its own line for pretty printing
509
- const indentedValues = values.map(val => context.indent(val));
510
- return '(\n' + indentedValues.join(',\n') + '\n)';
508
+ return context.parens(values.join(', '));
511
509
  });
512
510
  const indentedTuples = lists.map(tuple => {
513
511
  if (this.containsMultilineStringLiteral(tuple)) {
@@ -657,10 +655,15 @@ export class Deparser {
657
655
  return context.format([leftExpr, operator, rightExpr]);
658
656
  }
659
657
  else if (rexpr) {
660
- return context.format([
661
- this.deparseOperatorName(name, context),
662
- this.visit(rexpr, context)
663
- ]);
658
+ // Unary operator (e.g., unary minus: - expr)
659
+ const operator = this.deparseOperatorName(name, context);
660
+ let rightExpr = this.visit(rexpr, context);
661
+ // Wrap in parentheses if rexpr is a binary A_Expr to preserve semantics
662
+ // e.g., -(a - b) must stay -(a - b), not become -a - b
663
+ if (rexpr && 'A_Expr' in rexpr && rexpr.A_Expr?.kind === 'AEXPR_OP' && rexpr.A_Expr?.lexpr) {
664
+ rightExpr = context.parens(rightExpr);
665
+ }
666
+ return context.format([operator, rightExpr]);
664
667
  }
665
668
  break;
666
669
  case 'AEXPR_OP_ANY':
@@ -1761,7 +1764,7 @@ export class Deparser {
1761
1764
  }
1762
1765
  return output.join(' ');
1763
1766
  }
1764
- let result = mods(typeName, args);
1767
+ let result = mods(QuoteUtils.quoteIdentifierTypeName(typeName), args);
1765
1768
  if (node.arrayBounds && node.arrayBounds.length > 0) {
1766
1769
  result += formatArrayBounds(node.arrayBounds);
1767
1770
  }
@@ -2873,6 +2876,10 @@ export class Deparser {
2873
2876
  });
2874
2877
  output.push(`(${exclusionElements.join(', ')})`);
2875
2878
  }
2879
+ if (node.where_clause) {
2880
+ output.push('WHERE');
2881
+ output.push(context.parens(this.visit(node.where_clause, context)));
2882
+ }
2876
2883
  break;
2877
2884
  }
2878
2885
  // Handle deferrable constraints for all constraint types that support it
@@ -3006,6 +3013,8 @@ export class Deparser {
3006
3013
  if (!node.frameOptions)
3007
3014
  return null;
3008
3015
  const frameOptions = node.frameOptions;
3016
+ const EXCLUDE_MASK = 0x8000 | 0x10000 | 0x20000;
3017
+ const baseFrameOptions = frameOptions & ~EXCLUDE_MASK;
3009
3018
  const frameParts = [];
3010
3019
  if (frameOptions & 0x01) { // FRAMEOPTION_NONDEFAULT
3011
3020
  if (frameOptions & 0x02) { // FRAMEOPTION_RANGE
@@ -3022,31 +3031,31 @@ export class Deparser {
3022
3031
  return null;
3023
3032
  const boundsParts = [];
3024
3033
  // Handle specific frameOptions values that have known mappings
3025
- if (frameOptions === 789) {
3034
+ if (baseFrameOptions === 789) {
3026
3035
  boundsParts.push('CURRENT ROW');
3027
3036
  boundsParts.push('AND UNBOUNDED FOLLOWING');
3028
3037
  }
3029
- else if (frameOptions === 1077) {
3038
+ else if (baseFrameOptions === 1077) {
3030
3039
  boundsParts.push('UNBOUNDED PRECEDING');
3031
3040
  boundsParts.push('AND CURRENT ROW');
3032
3041
  }
3033
- else if (frameOptions === 18453) {
3042
+ else if (baseFrameOptions === 18453) {
3034
3043
  if (node.startOffset && node.endOffset) {
3035
3044
  boundsParts.push(`${this.visit(node.startOffset, context)} PRECEDING`);
3036
3045
  boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3037
3046
  }
3038
3047
  }
3039
- else if (frameOptions === 1557) {
3048
+ else if (baseFrameOptions === 1557) {
3040
3049
  boundsParts.push('CURRENT ROW');
3041
3050
  boundsParts.push('AND CURRENT ROW');
3042
3051
  }
3043
- else if (frameOptions === 16917) {
3052
+ else if (baseFrameOptions === 16917) {
3044
3053
  boundsParts.push('CURRENT ROW');
3045
3054
  if (node.endOffset) {
3046
3055
  boundsParts.push(`AND ${this.visit(node.endOffset, context)} FOLLOWING`);
3047
3056
  }
3048
3057
  }
3049
- else if (frameOptions === 1058) {
3058
+ else if (baseFrameOptions === 1058) {
3050
3059
  return null;
3051
3060
  }
3052
3061
  else {
@@ -3100,6 +3109,16 @@ export class Deparser {
3100
3109
  frameParts.push('BETWEEN');
3101
3110
  frameParts.push(boundsParts.join(' '));
3102
3111
  }
3112
+ // EXCLUDE clause
3113
+ if (frameOptions & 0x8000) { // FRAMEOPTION_EXCLUDE_CURRENT_ROW
3114
+ frameParts.push('EXCLUDE CURRENT ROW');
3115
+ }
3116
+ else if (frameOptions & 0x10000) { // FRAMEOPTION_EXCLUDE_GROUP
3117
+ frameParts.push('EXCLUDE GROUP');
3118
+ }
3119
+ else if (frameOptions & 0x20000) { // FRAMEOPTION_EXCLUDE_TIES
3120
+ frameParts.push('EXCLUDE TIES');
3121
+ }
3103
3122
  return frameParts.join(' ');
3104
3123
  }
3105
3124
  SortBy(node, context) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgsql-deparser",
3
- "version": "17.18.0",
3
+ "version": "17.18.2",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PostgreSQL AST Deparser",
6
6
  "main": "index.js",
@@ -60,5 +60,5 @@
60
60
  "@pgsql/quotes": "17.1.0",
61
61
  "@pgsql/types": "^17.6.2"
62
62
  },
63
- "gitHead": "ab3eacdb20a9378b5d7aade0035e07b2edf85b90"
63
+ "gitHead": "cdd732b4694b84522895d2d1dd8d5db9944875d5"
64
64
  }