Skip to content

feat: the SQL dialect a filter is written in - #28

Merged
christiangda merged 2 commits into
mainfrom
feat/the-sql-dialect
Oct 24, 2026
Merged

christiangda merged 2 commits into
mainfrom
feat/the-sql-dialect

Conversation

@christiangda

@christiangda christiangda commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What was wrong

The parser checks an expression and does not translate one: a caller hands the filter's text to its database. So "accepted" has to mean "this database runs it". The grammar was always PostgreSQL's, every rule checked against PostgreSQL 18, but the package said so nowhere except in its tests.

What changes

  • Dialect, chosen with WithDialect. It is a small struct with two exported values, so a dialect that does not exist cannot be named. The zero value is DialectPostgreSQL, and nothing changes for a caller that passes no option.

    Dialect Reference Accepts
    DialectPostgreSQL (default) PostgreSQL 18 and its manual's SQL Syntax chapter every operator, as before
    DialectSQLStandard ISO/IEC 9075:2023 (SQL:2023), Part 2, with the feature IDs from PostgreSQL's SQL Conformance appendix PostgreSQL's grammar without what PostgreSQL's manual calls its own
  • The standard dialect refuses PostgreSQL's own spellings. Each refusal names the standard's spelling, and each quotes PostgreSQL's manual:

    • !=: write <>;
    • ILIKE;
    • the ~~ operators: write LIKE;
    • ~: the standard's regular expressions are LIKE_REGEX, which this package does not parse;
    • ISNULL and NOTNULL: write IS [NOT] NULL;
    • an empty ESCAPE.

    What it keeps, with the standard's feature IDs:

    • E061-01 comparison, E061-02 BETWEEN, T461 its SYMMETRIC form, E061-03 IN;
    • E061-04 LIKE, E061-05 its ESCAPE clause;
    • E061-06 the NULL predicate, T141 SIMILAR TO, T151 and T152 IS [NOT] DISTINCT FROM;
    • F571 the truth value tests.
  • The dialect is checked before the allow-list. An operator the dialect does not have is refused whether WithAllowedOperators allows it or not.

  • Dialect.Operators() says which operators a dialect has.

  • One difference cannot be checked, and the docs say so: without ESCAPE, the standard has no escape character, where PostgreSQL's is the backslash.

Together with #27 (ESCAPE), this is v1.1.0. The migration guide's v1.0.5 → v1.1.0 section covers both.

How it was checked

  • TestTheSQLStandardDialect:
    • every predicate the parser knows, in its standard spelling, is accepted (31 inputs);
    • every PostgreSQL extension is refused, with its message (14 inputs, one inside a group).
  • TestTheDefaultDialectIsPostgreSQL: the zero value is PostgreSQL, and those 14 inputs are accepted with and without the option.
  • TestTheDialectNarrowsTheAllowedOperators: allowing ILIKE does not put it in the standard.
  • Mutants: 9 of 9 caught, each compiling.
    • The standard having every operator.
    • No spelling refused.
    • != not checked.
    • ~~ not checked.
    • ISNULL not checked.
    • An empty ESCAPE accepted in the standard.
    • The dialect checked only without an allow-list.
    • The option ignored.
    • The standard treated as PostgreSQL.
  • go test -race passes, coverage is 98.2%, and golangci-lint reports 0 issues.

Docs, every page that describes the filter parser, and each changed diagram rendered:

  • configuration.md: a section on the dialect, with its tables, and the gating diagram;
  • docs/README.md: the parsers diagram shows the dialect, and the guide table names it;
  • filtering.md: its opening and its pipeline diagram;
  • getting-started.md, error-handling.md, README.md, migration.md;
  • the package doc in docs.go, which is what pkg.go.dev shows;
  • a runnable ExampleWithDialect.

🤖 Generated with Claude Code

The parser checks an expression and does not translate one: a caller
hands the filter's text to its database, so what the parser accepts has
to be what that database runs. It always read PostgreSQL's grammar and
said so nowhere but in its tests. WithDialect names it: DialectPostgreSQL,
the default and the zero value, every operator as before; or
DialectSQLStandard, ISO/IEC 9075:2023, which refuses what PostgreSQL's
manual calls its own (!=, ILIKE, the ~~ and ~ operators, ISNULL and
NOTNULL, an empty ESCAPE), each refusal naming the standard's spelling.
What it keeps is listed with the standard's feature ids, from
PostgreSQL's SQL Conformance appendix. The dialect is checked before the
allow-list: an operator it does not have is refused however allowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@christiangda christiangda self-assigned this Oct 24, 2026
The package doc (what pkg.go.dev shows) was two lines; it says the
filter grammar is PostgreSQL's by default, or the standard's with
WithDialect. The documentation index's diagram shows the dialect gating
the filter parser, and its guide table names it; Getting Started,
Error Handling and Filtering (its opening and its pipeline diagram) say
it; ExampleWithDialect is runnable on pkg.go.dev. Every diagram was
rendered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@christiangda
christiangda merged commit d558b63 into main Oct 24, 2026
1 check passed
@christiangda
christiangda deleted the feat/the-sql-dialect branch October 24, 2026 17:25
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