Skip to content

Add PostgREST query parsing as an opt-in dialect - #88

Open
kriszyp wants to merge 11 commits into
kris/rql-v2from
feat/parse-postgrest-dialect
Open

Add PostgREST query parsing as an opt-in dialect#88
kriszyp wants to merge 11 commits into
kris/rql-v2from
feat/parse-postgrest-dialect

Conversation

@kriszyp

@kriszyp kriszyp commented Sep 2, 2026

Copy link
Copy Markdown
Member

Summary

Add parsePostgREST() as a zero-dependency rql/postgrest package subpath that maps PostgREST query parameters into the same canonical ParseResult model as Core. The root rql export remains Core-only.

The operator mapping implements the Appendix E.2 rows for scalar eq/gt/gte/lt/lte/neq/in/not, recursive and/or/not logic, any/all, array cs/cd/ov, is.null/is.true/is.false, extension comparators including configured FTS, JSON-arrow paths, select, order, limit, and offset.

Unsupported-feature vectors fail loudly with UnsupportedFeature by default. Aliases, casts, null placement, aggregates, embedding and hints, related-resource ordering, structured or multidimensional containment, and empty-list operations without a canonical representation are intentionally unsupported. onUnsupported: "drop" is limited to projection aliases/casts and null-placement decoration where the remaining query retains its filtering and pagination meaning.

Builds on #86.

For the human reviewer

  • Framing-Verdict: chosen-approach-sound. The separate subpath preserves the explicit dialect choice and leaves the normative Core surface unchanged.
  • Addressing dawsontoth's review, src/dialects/postgrest.ts now reads trunk-first — parsePostgREST, syntaxViolation, parseInto, then the per-parameter parsers and finally the operand and lexical helpers — under the same // ── section ── banners src/parser.ts already uses. Function hoisting makes the forward calls valid; every moved block is byte-identical, which the independent reviewer verified block-by-block. src/parser.ts itself is still bottom-up, so the two files now disagree on direction — worth settling as a repo convention, but out of scope here.
  • Taking the suggested spelling, the exports are parsePostgREST and PostgRESTOptions, matching PostgREST's own capitalization and the casing the file's prose and Appendix E already use. The rql/postgrest subpath is unchanged. Nothing outside this unreleased alpha consumes either name, so reverting the rename costs one sed.
  • Logic leaves use PostgREST's field-first, leftmost viable operator boundary. Thus meta.like=eq.5 is a dotted top-level path, while or=(meta.like.eq.5,b.eq.1) means field meta, comparator like, operand eq.5; quoting permits operator-named path segments. This is the main spec ambiguity and is deliberately pinned for review before the dialect becomes stable.
  • Semantic deltas remain visible rather than compensated: neq has RQL set-complement behavior around absent values; is.null cannot distinguish SQL null from absence; schema-free dotted embedded filters inherit RQL's join behavior; -> and ->> collapse to canonical paths; FTS configuration is folded into the opaque comparator name; non-finite spellings remain strings.
  • Valid PostgREST operations whose truth value cannot be represented fail closed, including cs.{} and non-collapsible empty any/all expansions. JSON/range containment, multidimensional arrays, aggregates, embeddings, and related ordering also fail closed instead of silently changing results.
  • Tests verify the parser boundary, canonical AST mappings, Core equivalence where representable, hostile inputs, and the built package surface. There is no canonical model executor in this repository, so they do not execute the AST against rows.
  • Adjacent Core finding, intentionally left out of this scoped dialect change: parseQuery('not(tags[=not_in=(red,blue)])') rejects Appendix E.2's stated canonical spelling, preventing a direct cd equivalence assertion.

Verification

  • npm test — 251 passing tests across 38 suites, including the unchanged 111-test Core suite
  • npm run typecheck
  • npm pack --dry-run --json — includes built JavaScript and declarations for dist/dialects/postgrest
  • rg -n "postgrest|parsePostgREST" src/index.ts test/v2 — no matches
  • Independent review: full Claude, Cursor/Grok, and Harper-domain coverage found hardening issues that were fixed. The reorganization round was reviewed by Codex (opposite family to its author) at medium effort: LGTM, no findings, with the move verified as byte-identical across all 26 functions. Gemini coverage was unavailable because its local CLI is not authenticated. Two later attempts to re-review the assembled 1,253-line diff in a single pass both exhausted their run budget (Codex at xhigh and again at medium, with Cursor/Grok timing out alongside it), so independent coverage on this branch is per-commit — each commit reviewed as the delta that introduced it — rather than one pass over the finished file.

Complexity: complicated

Generated by GPT-5 Codex; review-feedback round by Claude Opus.

Review-Coverage: authored=claude; ran=codex; declined=gemini,cursor-grok,cursor-composer,domain; rounds=1 @ ab9462f

Human-Review-Need: 2 @ ab9462f

kriszyp and others added 10 commits September 1, 2026 16:10
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Co-Authored-By: GPT-5 Codex <noreply@openai.com>
Comment thread src/dialects/postgrest.ts Outdated
@kriszyp
kriszyp marked this pull request as ready for review September 2, 2026 14:32
Read the file from its entry point down: parsePostgREST, then the
query-parameter dispatch, then the per-parameter parsers, then operand
and lexical helpers, under the section banners parser.ts already uses.
No behavior change — the moved blocks are byte-identical.

Rename the exported parser and options interface to match PostgREST's
own capitalization, which the file's prose and the spec already use.

Co-Authored-By: Claude Opus <noreply@anthropic.com>
@kriszyp kriszyp closed this Sep 2, 2026
@kriszyp kriszyp reopened this Sep 2, 2026
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.

2 participants