Skip to content

feat(persistence): honor _sort and add :missing/:not on PostgreSQL; reconcile search matrix#118

Open
smunini wants to merge 1 commit into
mainfrom
feat/pg-search-sort-modifiers
Open

feat(persistence): honor _sort and add :missing/:not on PostgreSQL; reconcile search matrix#118
smunini wants to merge 1 commit into
mainfrom
feat/pg-search-sort-modifiers

Conversation

@smunini
Copy link
Copy Markdown
Contributor

@smunini smunini commented Jun 3, 2026

Context

Audited HFS FHIR Search against the spec. The Backend Capability Matrix in crates/persistence/README.md was stale in both directions, and one discrepancy was a real functional bug: PostgreSQL claimed full _sort support but ignored query.sort and hardcoded ORDER BY last_updated DESC, id DESC.

Changes

Code

  • PostgreSQL _sort — added PostgresQueryBuilder::build_order_by and wired it into the first-page and offset search paths. SQLite had the same latent bug (its build_order_by was only exercised by unit tests), so it's wired in there too for parity. The no-_sort default ordering is byte-identical to before — no pagination regression; cursor/keyset pages keep the default ordering (a pre-existing constraint, now documented).
  • PostgreSQL :missing / :not:missing resolves from presence/absence of a search_index entry; :not (token) negates the match and correctly includes resources with no value. Mirrors SQLite.

Docs

  • Reconciled the capability matrix with code evidence — downgraded overstated cells (ES composite ◐, ES/SQLite/PG :above/:below ◐ for URI-only, Mongo multi-field sort ◐) and upgraded understated ones (PG chained/_has/_text/_content ✓, Mongo :exact/:contains ✓, PG :not/:missing ✓). Added clarifying notes and fixed contradicting prose.
  • New crates/persistence/docs/search-spec-assessment.md: capability-by-capability assessment vs. the spec, the REST/backend boundary, and a roadmap of remaining gaps.

Tests

New PostgreSQL integration tests: _sort (asc/desc), :missing (true/false), :not (incl. resources with no value). Full PG search suite + SQLite suite pass; clippy -D warnings clean.

Remaining gaps (documented, not in this PR)

Sort by arbitrary search parameter (all backends), PG composite + :of-type/:text-advanced, ES real composite components + chaining, MongoDB native search gaps, and minor REST result params (_maxresults, _score, first/last links).

…econcile search matrix

Audited FHIR Search against build.fhir.org/search.html and found the Backend
Capability Matrix stale in both directions, plus one functional bug.

- PostgreSQL search now honors `query.sort` on the first-page and offset paths
  (`_id`/`_lastUpdated`) instead of hardcoding `ORDER BY last_updated DESC`.
  SQLite had the same latent bug (its `build_order_by` helper was only used in
  unit tests); wired into both backends. Cursor/keyset pages keep the default
  ordering, and the no-`_sort` default ordering is unchanged (no paging
  regression).
- PostgreSQL now supports the `:missing` (type-agnostic) and `:not` (token)
  search modifiers, mirroring SQLite.
- Reconciled the capability matrix and contradicting prose: downgraded
  overstated cells (ES composite, ES/SQLite/PG :above/:below URI-only, Mongo
  multi-field sort) and upgraded understated ones (PG chained/_has/_text/
  _content, Mongo :exact/:contains).
- Added docs/search-spec-assessment.md: a capability-by-capability assessment
  vs. the spec with the REST/backend boundary and a roadmap of known gaps.

Tests: new PostgreSQL integration tests for `_sort`, `:missing`, and `:not`.
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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