Skip to content

feat(format): add the castStyle option for :: versus CAST(...) - #798

Open
edjubert wants to merge 4 commits into
supabase-community:mainfrom
edjubert:edjubert/cast-style
Open

edjubert wants to merge 4 commits into
supabase-community:mainfrom
edjubert:edjubert/cast-style

Conversation

@edjubert

@edjubert edjubert commented Sep 16, 2026

Copy link
Copy Markdown

What

Option Default Values
castStyle "cast" "cast", "operator"

cast keeps today's CAST(expr AS type). operator prints the PostgreSQL-specific expr::type form, adding parentheses only where the tighter binding of :: would otherwise change the meaning:

-- input
SELECT
  CAST(t.id AS bigint),
  CAST(t.id AS public.object_id),
  CAST(nullif(t.a, '') AS date),
  CAST(t.a + t.b AS int),
  CAST(CAST(t.a AS text) AS bigint),
  CAST((SELECT max(u.id) FROM s.u) AS bigint),
  CAST(CASE WHEN t.a THEN 1 ELSE 2 END AS text)
FROM s.t;

-- castStyle=operator
select
  t.id::bigint,
  t.id::public.object_id,
  nullif(t.a, '')::date,
  (t.a + t.b)::int,
  t.a::text::bigint,
  (select MAX(u.id) from s.u)::bigint,
  case when t.a then 1 else 2 end::text
from
  s.t;

Note the three groups: a column reference, a function call or an already-parenthesised sub-select needs nothing; an arithmetic or concatenation operand is parenthesised because :: binds tighter than +.
A chained cast collapses to t.a::text::bigint rather than nesting.

Why

expr::type is the form most PostgreSQL code is written in, and it is materially shorter in a long target list.
The choice is a house-style question, so it is an option and the default does not move.

Implementation

nodes/type_cast.rs decides on the spelling and on the parentheses from the argument node kind.
The decision happens at emission time, which is why the emitter needs access to the configuration (see the prerequisite PR).

Wiring: pgls_configuration (--cast-style), pgls_workspace settings, docs/features/formatting.md, docs/schema.json.

Tests

One fixture covering the nine argument shapes above, snapshotted at widths 80 and 100.

The two preparatory commits

The first two commits of this PR are shared, byte for byte, with the three other formatter-option PRs open alongside it:

The shared commits are:

  • test(pretty-print): allow per-fixture format configuration
  • refactor(pretty-print): thread the format config into the emitter

They are carried in each PR so every option remains independently reviewable and mergeable.
Whichever PR lands first, I will rebase the other three to remove the duplicate commits.

Merge them in whatever order suits you; nothing here depends on the others.

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