pgsql-deparser 17.18.1 → 17.18.3

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
@@ -658,10 +658,15 @@ class Deparser {
658
658
  return context.format([leftExpr, operator, rightExpr]);
659
659
  }
660
660
  else if (rexpr) {
661
- return context.format([
662
- this.deparseOperatorName(name, context),
663
- this.visit(rexpr, context)
664
- ]);
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]);
665
670
  }
666
671
  break;
667
672
  case 'AEXPR_OP_ANY':
@@ -1312,8 +1317,13 @@ class Deparser {
1312
1317
  }
1313
1318
  // Handle EXTRACT function with SQL syntax
1314
1319
  if (node.funcformat === 'COERCE_SQL_SYNTAX' && name === 'pg_catalog.extract' && args.length >= 2) {
1315
- const field = this.visit(args[0], context);
1320
+ let field = this.visit(args[0], context);
1316
1321
  const source = this.visit(args[1], context);
1322
+ // EXTRACT requires an unquoted uppercase keyword (EPOCH, YEAR, etc.)
1323
+ // but A_Const sval deparsing wraps it in single quotes — strip and uppercase
1324
+ if (field.startsWith("'") && field.endsWith("'")) {
1325
+ field = field.slice(1, -1).toUpperCase();
1326
+ }
1317
1327
  return `EXTRACT(${field} FROM ${source})`;
1318
1328
  }
1319
1329
  // Handle TRIM function with SQL syntax (TRIM TRAILING/LEADING/BOTH)
package/esm/deparser.js CHANGED
@@ -655,10 +655,15 @@ export class Deparser {
655
655
  return context.format([leftExpr, operator, rightExpr]);
656
656
  }
657
657
  else if (rexpr) {
658
- return context.format([
659
- this.deparseOperatorName(name, context),
660
- this.visit(rexpr, context)
661
- ]);
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]);
662
667
  }
663
668
  break;
664
669
  case 'AEXPR_OP_ANY':
@@ -1309,8 +1314,13 @@ export class Deparser {
1309
1314
  }
1310
1315
  // Handle EXTRACT function with SQL syntax
1311
1316
  if (node.funcformat === 'COERCE_SQL_SYNTAX' && name === 'pg_catalog.extract' && args.length >= 2) {
1312
- const field = this.visit(args[0], context);
1317
+ let field = this.visit(args[0], context);
1313
1318
  const source = this.visit(args[1], context);
1319
+ // EXTRACT requires an unquoted uppercase keyword (EPOCH, YEAR, etc.)
1320
+ // but A_Const sval deparsing wraps it in single quotes — strip and uppercase
1321
+ if (field.startsWith("'") && field.endsWith("'")) {
1322
+ field = field.slice(1, -1).toUpperCase();
1323
+ }
1314
1324
  return `EXTRACT(${field} FROM ${source})`;
1315
1325
  }
1316
1326
  // Handle TRIM function with SQL syntax (TRIM TRAILING/LEADING/BOTH)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgsql-deparser",
3
- "version": "17.18.1",
3
+ "version": "17.18.3",
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": "58ddefe11a5d002db6645fa7bc2f284123d48470"
63
+ "gitHead": "16d4dced1144372f2debc270ea07e9d842cc50c9"
64
64
  }