fix(mongodb): serve :of-type, reference :identifier, :[type] and :above/:below - #1419
Merged
Merged
Conversation
…:below MongoDB refused three standard search modifiers that SQLite, PostgreSQL and Elasticsearch serve, so the same request succeeded or failed with HFS_STORAGE_BACKEND: token `:of-type`, reference `:identifier` and the reference `:[type]` qualifier all fell into the `UnsupportedModifier` catch-all of their filter builder. Reference `:above`/`:below` were refused one step earlier, by `validate_query_support`. Root cause: the builders were never written. Nothing was missing from the index - the writer has always stored `value_identifier_type_system` / `value_identifier_type_code` on identifier rows (and the partial index `idx_search_identifier_type_v2` exists for them), so no reindex is needed. - `:of-type` compares type system, type code and value; an empty part is not compared (as SQLite/PostgreSQL); anything but three parts matches nothing rather than dropping the condition. - `:[type]` is the qualified reference: `subject:Patient=1` builds the very filter `subject=Patient/1` builds, so it cannot match `Group/1`. A value naming another type matches nothing. Qualified reference values are now version-agnostic (`strip_reference_version`), like every other backend. - `:identifier` has the SQLite/PostgreSQL meaning (the reference's target carries the identifier). A filter document cannot join, so `matching_resource_ids` resolves the targets first - tenant-scoped, and bounded to the parameter's declared target types so the token index serves it - and turns the parameter into one index-bounded `$in` of `Type/id` plus an anchored `_history` regex each. More than 10 000 targets is refused (`TooManyResults`), never truncated. - reference `:above`/`:below` reuse the uri shapes. `modifiers_for_type` advertises what is now served, and the new cross-backend `modifier_parity_suite` walks every modifier `SearchModifier::is_valid_for` allows on every parameter type on all four backends, with each backend's known differences stated explicitly so no backend can silently fall behind again. Fixes #1408
… tenants The suite's `:identifier` lookup is a second query; a cell now proves it is tenant-scoped, three cells AND a modified parameter with a plain one so it is also exercised as the non-driving filter, and every cell checks that `search_count` counts what `search` returns. Refs #1408
smunini
added a commit
that referenced
this pull request
Sep 21, 2026
…omic-versioned-writes #1419 and this PR each add a backend-agnostic suite (modifier_parity_suite there, versioned_write_race_suite here) and wire it into the same spots of tests/mongodb_tests.rs and tests/postgres_tests.rs, so whichever merges second conflicts. Resolved here, making the order #1419 then this PR; every test kept unchanged. The resulting tree is byte-identical to the corresponding step of a scratch merge of main with all four open PRs (#1419, #1421, #1422, #1423), which compiled under `cargo test --workspace --all-features --no-run` and passed the full SQLite, PostgreSQL, MongoDB, Elasticsearch and REST suites.
smunini
added a commit
that referenced
this pull request
Sep 21, 2026
…nto feat/1406-shared-conditional-patch #1419, #1421 and this PR each add a backend-agnostic suite and wire it into the same spots of tests/mongodb_tests.rs, tests/postgres_tests.rs and tests/sqlite_tests.rs, so whichever merges later conflicts. Resolved here, making the order #1419, #1421, then this PR; every test kept unchanged. The resulting tree is byte-identical to the corresponding step of a scratch merge of main with all four open PRs (#1419, #1421, #1422, #1423), which compiled under `cargo test --workspace --all-features --no-run` and passed the full SQLite, PostgreSQL, MongoDB, Elasticsearch and REST suites.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MongoDB refused search modifiers that SQLite, PostgreSQL and Elasticsearch all serve, so the same request succeeded or failed depending on
HFS_STORAGE_BACKEND.:of-type, reference:identifierand the reference:[type]qualifier.:above/:below, was found while fixing them.These were reachable over plain HTTP
These results come from a real
hfson MongoDB, withmain's MongoDB code before the fix and this branch after.Observation?subject:Patient=p1400unsupported modifierPatient200, the Observation whose subject isPatient/p1Observation?subject:Group=p1400200, the Observation whose subject isGroup/p1Observation?subject:identifier=http://example.org/mrn|12345400200, correct matchPatient?identifier:of-type=…v2-0203|MR|12345400unsupported modifierofType200, correct matchObservation?subject:below=Patient400200, correct matchsubject:Patient.identifier=…) and_has:[type]to the backend as a modifier, not as a type-qualified value, so the refusal was reachable over HTTP.Why the Inferno MongoDB legs stayed green: the US Core test kit never sends these forms.
patient=Patient/<id>).:identifieror:of-type.subject:Patient=…was refused on MongoDB.Root cause
The builders were never written, so the modifiers fell into the
UnsupportedModifiercatch-all. Reference:above/:belowwere refused one step earlier, invalidate_query_support.Nothing was missing from the index. The writer has always stored the identifier type system and code on identifier rows, and a partial index for them already exists. No reindex is needed.
Fix
:of-type:[type]subject:Patient=1builds the same filter assubject=Patient/1, so it cannot matchGroup/1.strip_reference_version), as on every other backend.:identifier$in. The lookup is tenant-scoped and bounded to the parameter's declared target types.TooManyResults. The result is never truncated.:above/:belowreuse the uri shapes.modifiers_for_typenow advertises what is actually served.New test suite
New cross-backend suite:
crates/persistence/tests/search/modifier_parity_suite.rs.SearchModifier::is_valid_forallows, on every parameter type, on all four backends.search_countand tenant isolation.Verification
Run after merging current
main, on real containers:cargo test -p helios-persistence --lib --features sqlite,postgres,mongodb,elasticsearch: 1782 passedmongodb_tests(full): 206 passedpostgres_tests(full): 268 passedelasticsearch_tests(full): 141 passedsqlite_tests+search_suite: 219 passedcargo +1.98.1 clippy -p helios-persistence --features R4,R4B,R5,R6,sqlite,postgres,mongodb,elasticsearch,s3 --all-targetswith the CI flags: clean. This compiles code gated on several FHIR versions.cargo fmt --check: cleanNot run on this branch alone:
helios-resttests. No REST code is touched.--workspace --all-featurescompile. That runs on the combined tree of the open PRs.Fixes #1408