Skip to content

Allow backtick-quoted names in expressions - #155

Open
hadley wants to merge 1 commit into
mainfrom
backtick-quoted-names
Open

Allow backtick-quoted names in expressions#155
hadley wants to merge 1 commit into
mainfrom
backtick-quoted-names

Conversation

@hadley

@hadley hadley commented Jul 31, 2026

Copy link
Copy Markdown
Member

A table or column could be declared with any non-empty name, but only a plain identifier ([A-Za-z_][A-Za-z0-9_]*) could be referenced from an assertion or a join — so a column called creation date was declarable and then unreachable, with no quoting syntax to bridge the gap.

Names of any other shape — containing a space or punctuation, starting with a digit, or colliding with a reserved word — now go in backticks:

constraints:
  - assert: '`creation date` <= `end`'
relationships:
  - join: '`other studies`.`study id` = study.id'

A quoted name may hold any character, doubling a backtick to embed one. Each side of a join's . is quoted on its own, so a . between backticks is part of the name. Quoting changes only how a name is read, never how it's matched, so backticks are optional on a name that doesn't need them. Malformed quoting (unterminated, empty) lands on the existing S19/S04 rather than a new check code, so validation.md and schema.yaml are unchanged.

Backticks rather than SQL's " because '…' is already a string literal (and COLUMNS('regex') a regex), and because it matches the analytics mini-languages users come from — pandas query(), dplyr, Spark. One wrinkle documented in the spec: a backtick can't open a plain YAML scalar, so an expression starting with one needs YAML quotes; one merely containing a backtick doesn't.

Spec first: site/expressions.md gains a Column references section, plus grammar and COLUMNS([...]) updates.

Tests: quoted names, reserved-word names, embedded backtick/dot/non-ASCII, spans, and the unterminated/empty rejections in both parsers; tests/fixtures/spec/quoted-names-ok.yaml exercises the whole path through the CLI.

Fixes #148, #137

🤖 Generated with Claude Code

A table or column could be declared with any non-empty name, but only a
plain identifier could be referenced from an assertion or a `join`, so a
column called `creation date` was declarable and then unreachable. Names
of any other shape — a space or punctuation, a leading digit, or a clash
with a reserved word — now go in backticks:

    - assert: '`creation date` <= `end`'
    - join: '`other studies`.`study id` = study.id'

A quoted name may hold any character, doubling a backtick to embed one,
and each side of a join's `.` is quoted on its own, so a `.` between
backticks is part of the name. Quoting changes only how a name is read,
never how it is matched, so backticks are optional on a name that doesn't
need them. Malformed quoting lands on the existing S19/S04 rather than a
new code.

A backtick can't open a plain YAML scalar, so an expression that starts
with one needs YAML quotes; site/expressions.md says so alongside the new
`Column references` section.

Fixes #148, #137
@hadley
hadley requested a review from gaborcsardi July 31, 2026 13:21
@gaborcsardi

Copy link
Copy Markdown
Member

now go in backticks:

There are no backticks in this example. :)

@gaborcsardi gaborcsardi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we should de-duplicate the two parsers? E.g. this PR adds parse_quoted_name() to both, and the two implementations are exactly identical. Which makes sense, they are supposed to be identical. But then we should probably merge the two.

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.

Define quoting in expression syntax

2 participants