Skip to content

Don't add a space before a parenthesis or bracket that continues an expression (quantile(0.9)(x), splitByChar(',', s)[1], col[1]) - #992

Closed
MunMunMiao wants to merge 1 commit into
sql-formatter-org:masterfrom
MunMunMiao:format-subscript-and-chained-call-without-space
Closed

MunMunMiao wants to merge 1 commit into
sql-formatter-org:masterfrom
MunMunMiao:format-subscript-and-chained-call-without-space

Conversation

@MunMunMiao

Copy link
Copy Markdown

Problem

A parenthesis or bracket that directly continues the previous expression gets a space in front of it when that expression is a function call, a parenthesis, a quoted identifier, a property access or a subscript. Only an unquoted identifier is handled (c[1], through the ARRAY_IDENTIFIER token).

SELECT quantile(0.9)(x), splitByChar(',', s)[1], (arr)[1], `signals`[1], t.`signals`[2], c[1][2] FROM t

Before (15.9.0, language: 'clickhouse'):

SELECT
  quantile(0.9) (x),
  splitByChar(',', s) [1],
  (arr) [1],
  `signals` [1],
  t.`signals` [2],
  c[1] [2]
FROM
  t

After:

SELECT
  quantile(0.9)(x),
  splitByChar(',', s)[1],
  (arr)[1],
  `signals`[1],
  t.`signals`[2],
  c[1][2]
FROM
  t

It is not limited to ClickHouse: BigQuery gives SPLIT(s, ',') [OFFSET(1)] and `col` [0], and PostgreSQL gives "col" [1] and string_to_array(s, ',') [1].

Change

ExpressionFormatter.formatParenthesis now removes the space in front of the node when it directly follows another node of the same list and

  • it opens with ( and the previous node is a function call (quantile(0.9)(x)), or
  • it opens with [ and the previous node is a function call, a parenthesis, a quoted identifier, a property access or a subscript.

A parenthesis or bracket after a keyword is not affected, so x IN [1, 2], IN (1, 2) and OVER (...) look as before. The parenthesis that belongs to a function call is handled as before, because it is not a node of the list.

I tried a grammar change first, but the parser rejects ambiguous grammars and f(a) (b) is already valid as two expressions. Looking at the previous node in the formatter avoids that.

Tests

  • ClickHouse: parametric aggregate functions, subscripts after calls, parentheses, quoted identifiers, property access and subscripts, and that x IN [1, 2] keeps its space.
  • BigQuery and PostgreSQL: a subscript after a function call, a quoted identifier and a parenthesis.

pnpm exec jest passes for all dialects (5890 passed, 1 skipped). No existing expectation changed. tsc --noEmit, prettier --check and eslint are clean.

Fixes #991.


This change was prepared with Claude Code (an AI coding assistant) and checked by running the full test suite locally.

…xpression

A parenthesis directly after a function call (the arguments of a ClickHouse
parametric aggregate function, `quantile(0.9)(x)`) and brackets directly
after a function call, a parenthesis, a quoted identifier, a property access
or another subscript (`splitByChar(',', s)[1]`, `"col"[1]`) were separated
from the previous expression by a space. Only `col[1]` with an unquoted
identifier was handled, through the ARRAY_IDENTIFIER token.
Copilot AI balanced review requested due to automatic review settings October 14, 2026 04:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The formatter cannot distinguish adjacent syntax from whitespace-separated expressions and may alter query semantics.

1 open finding
What changed in this PR

Updates expression formatting so chained calls and subscripts render without an intervening space.

Changes:

  • Detects parentheses and brackets that follow compatible expression nodes.
  • Adds ClickHouse, BigQuery, and PostgreSQL regression tests.
File Description
src/​formatter/​ExpressionFormatter.ts Adds continuation-spacing logic.
test/​clickhouse.test.ts Tests chained calls and subscripts.
test/​bigquery.test.ts Tests function and identifier subscripts.
test/​postgresql.test.ts Tests several subscript forms.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +213 to +217
const prev = this.nodes[this.index - 1];
// Only for a node of this list, not for the parenthesis that belongs to a function call
if (!prev || this.nodes[this.index] !== node) {
return false;
}
@MunMunMiao

Copy link
Copy Markdown
Author

Closing for now: I'm going to handle the formatting on my side instead. Thanks for the library.

@MunMunMiao MunMunMiao closed this Oct 14, 2026
@MunMunMiao
MunMunMiao deleted the format-subscript-and-chained-call-without-space branch October 14, 2026 04:17
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.

[FORMATTING] A space is added before the parenthesis of a chained call and before the brackets of a subscript after a call or quoted identifier

2 participants