Skip to content

feat(deparser): support JSON_QUERY, JSON_VALUE, JSON_EXISTS and JSON_TABLE - #369

Open
pyramation wants to merge 1 commit into
mainfrom
devin/1792901235-deparser-json-query-table
Open

pyramation wants to merge 1 commit into
mainfrom
devin/1792901235-deparser-json-query-table

Conversation

@pyramation

Copy link
Copy Markdown
Collaborator

Summary

JsonFuncExpr and JsonTable had no deparser visitor, so any statement using the SQL/JSON query functions threw Deparser does not handle node type: JsonFuncExpr / JsonTable.

Adds visitors for JsonFuncExpr, JsonTable, JsonTableColumn, JsonTablePathSpec, JsonBehavior and JsonArgument, covering:

  • JSON_EXISTS / JSON_VALUE / JSON_QUERY with FORMAT JSON [ENCODING ...] context items, PASSING ... AS name, RETURNING type [FORMAT JSON], WITH [CONDITIONAL|UNCONDITIONAL] WRAPPER / WITHOUT WRAPPER, KEEP|OMIT QUOTES, and every ... ON EMPTY / ... ON ERROR behavior (including DEFAULT expr).
  • JSON_TABLE with a named root path (AS name), PASSING, FOR ORDINALITY / regular / EXISTS / FORMAT JSON columns, NESTED [PATH] ... [AS name] COLUMNS (...) (recursively), table-level ON ERROR, LATERAL and aliases with column lists.

EXISTS columns never emit wrapper/quotes clauses: the parser fills in wrapper: JSW_NONE for them but the grammar rejects WITHOUT WRAPPER there.

cleanTree (used by the round-trip tests) now also strips name_location, the only location field not already ignored. Without it any JSON_TABLE ... AS name path whose name shifts position on deparse (e.g. jsonb '...' → '...'::jsonb) is reported as an AST mismatch.

Tests

New kitchen-sink fixtures misc/json-query-functions.sql and misc/json-table.sql (mostly from the PG18 sqljson_queryfuncs / sqljson_jsontable regression tests), regenerated with npm run kitchen-sink.

  • Before the visitors were added (with the old src/deparser.ts checked out), both generated tests failed with Deparser does not handle node type: JsonFuncExpr / JsonTable.
  • After: both pass, and so does the existing misc-pg18-sqljson suite.
  • Full suites: deparser 750/750, transform 250/250, plpgsql-deparser 115/115, transform-ast 1443/1443. tsc is clean and lint reports 0 errors.

This is independent of #368 (no shared hunks).

Link to Devin session: https://app.devin.ai/sessions/cb07c6509db64478af655f52611468f4
Open in Devin Desktop: https://app.devin.ai/desktop/session/cb07c6509db64478af655f52611468f4?variant=devin
Requested by: @pyramation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@tenki-reviewer

tenki-reviewer Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review complete. 🟡 1 medium

💬 Inline comments (1)

  • 🟡 ON SCALAR STRING silently dropped from JSON quote clauses — deparser.ts:11149

This PR extends the deparser with visitors for the JSON expression family: JsonBehavior, JsonArgument, passing/wrapper/quotes/behaviors formatters, JsonFuncExpr, JsonTablePathSpec, JsonTableColumn, and JsonTable, along with two new kitchen-sink fixture sets and generated tests.

Files Change
packages/deparser/src/deparser.ts New visitors and formatters covering JSON function behaviors, passing args, wrapper/quotes clauses, and JSON_TABLE columns/paths.
packages/deparser/scripts/clean-utils.ts Adds name_location to the noop positional-field cleanup list.
__fixtures__ + kitchen-sink tests New json-query-functions and json-table fixture SQL files with matching generated fixtures and round-trip test suites.

Reviewed commit: d30d6c2

@tenki-reviewer tenki-reviewer Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adds deparser support for SQL/JSON functions (JSON_QUERY/JSON_VALUE/JSON_EXISTS behaviors and JSON_TABLE columns) plus kitchen-sink fixtures and tests, with a name_location noop in the fixture cleaning script.

Key findings

  • 🟡 ON SCALAR STRING silently dropped from JSON quote clauses — deparser.ts:11149

Comment on lines +11149 to +11158
formatJsonQuotes(quotes: t.JsonQuotes | undefined): string | null {
switch (quotes) {
case 'JS_QUOTES_KEEP':
return 'KEEP QUOTES';
case 'JS_QUOTES_OMIT':
return 'OMIT QUOTES';
default:
return null;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 bug · medium

ON SCALAR STRING silently dropped from JSON quote clauses

The quotes field is a bare enum (JS_QUOTES_KEEP/JS_QUOTES_OMIT), so formatJsonQuotes can only emit KEEP QUOTES/OMIT QUOTES and silently drops the ON SCALAR STRING modifier (packages/deparser/src/deparser.ts:11149). Upstream PostgreSQL carries the ON SCALAR STRING flag as a separate boolean on the JSON quotes node and its ruleutils prints it back, but this repo's libpg-query protobuf (JsonQuotes enum in __fixtures__/proto/17-latest.proto:2900) has no such field, so the flag is already lost in the parse tree. JSON_QUERY(x, '$' OMIT QUOTES ON SCALAR STRING) therefore deparses as OMIT QUOTES, which omits quotes unconditionally instead of only for scalar strings — semantically different SQL with no error. The kitchen-sink fixture __fixtures__/kitchen-sink/misc/json-query-functions.sql:12 exercises exactly this clause, and round-trip tests pass only because reparse matches the already-lossy AST.

📋 Prompt for AI Agents

In packages/deparser/src/deparser.ts around lines 11149-11158 (formatJsonQuotes) and its callers JsonFuncExpr (line ~11196) and JsonTableColumn (line ~11245), handle the PostgreSQL ON SCALAR STRING modifier that upstream attaches to the JSON quotes node. First inspect the libpg-query version used at runtime to see whether it exposes a scalar_string/on_scalar field next to the JsonQuotes enum (the fixture protos in fixtures/proto/17-latest.proto lack it); if the runtime parse tree carries it, thread it through the types and emit ON SCALAR STRING when set. If the proto cannot represent the flag, add a test/comment documenting that OMIT QUOTES ON SCALAR STRING round-trips lossily (e.g. in fixtures/kitchen-sink/misc/json-query-functions.sql line 12) instead of silently emitting semantically different SQL.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Folded into #371

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant