A PostgreSQL formatter that knows Postgres syntax
This PostgreSQL formatter puts each clause of a query on its own line, splits select lists and
SET assignments one per line, and indents every subquery, while reading the text the way
PostgreSQL does. The panel above opens with an UPDATE ... RETURNING query loaded; paste your own
over it to format a PostgreSQL query copied from a log, a migration or an ORM's debug output.
Nothing leaves your browser.
The reason for a dialect-aware Postgres SQL beautifier is that a handful of characters mean
something in PostgreSQL that they do not mean anywhere else. $$ opens a string. :: is a cast.
#> is a JSON operator, not a comment. A generic formatter that misreads any of them will break a
line inside a function body or detach a type from its value.
PostgreSQL dollar quoting
Dollar quoting is PostgreSQL's answer to escaping. Everything between $$ and the next $$ is one
string, with no special characters at all: single quotes, backslashes and semicolons are just text.
A tag between the dollars, as in $body$ ... $body$, lets one dollar-quoted string hold another, and
lets the body contain a bare $$.
It is how function and procedure bodies are written, and it is the part of a migration a formatter
is most likely to damage. This one reads a dollar-quoted string as one token from opening tag to
matching closing tag and copies it through unchanged. It also tells the difference between a tag
and a positional parameter: $1 is a parameter, $1$ would not be valid, and $fn$ opens a string.
Casts with ::
created_at::date is PostgreSQL's shorthand for CAST(created_at AS date). The formatter keeps the
double colon tight against both sides, so the type reads as part of the value, and applies your
keyword case to built-in type names such as INT. Custom types and names like timestamptz are left
as typed, because they are identifiers rather than reserved words.
RETURNING and ILIKE
RETURNING is what makes an INSERT, UPDATE or DELETE hand back the rows it changed, and here
it gets its own line like any other clause, with the returned columns beneath it. ILIKE is the
case-insensitive LIKE that PostgreSQL adds; it is treated as a keyword and follows your keyword
case, and a WHERE built from several ILIKE conditions breaks on each AND and OR.
ON CONFLICT ... DO UPDATE is laid out the same way, with the SET list below it.
Quoted identifiers
Double quotes in PostgreSQL always mean an identifier, never a string. They preserve case and allow
reserved words, which is how an ORM ends up creating a table called "Users" with a column called
"userId". Those names are copied byte for byte, and doubled quotes inside them are kept.
Block comments can also nest in PostgreSQL, so /* outer /* inner */ still a comment */ is a single
comment, and the formatter treats it as one.
For the rules shared by every dialect, see the SQL formatter. Queries headed for
MySQL or MariaDB belong in the MySQL formatter, which reads backticks and #
comments instead.