The eight typed search-index tables (SP3)

Featurekamo-shared-library
Shipped
August 25, 2026 at 2:12 PM UTC
Author
Kamo
Commit
cac0d13

Search runs over explicit typed tables, not JSONB with GIN. That is forced by the database, not chosen: Yugabyte's own docs state a GIN index cannot use more than one required scan entry, multi-column GIN is unsupported, only IndexScan is available, and UPDATE is DELETE + INSERT. The single query US Core mandates most — Observation by patient AND category — is two required scan entries, so a JSONB-primary server would be slowest at exactly what certification tests. Each table exists because its type has a failure mode the others do not: - SpidxDate stores an INTERVAL, because a FHIR date IS one. 2026, 2026-08 and 2026-08-24 are different values and eq2026 means the whole year. A single instant collapses them and then silently fails to match, so a birthdate recorded as a year is not found by a search for that year. A null high means STILL RUNNING, not missing. - SpidxQuantity indexes ONLY the UCUM-canonical value, and deliberately has no column for the entered pair. Comparing entered units lets a query for 7500 ug miss a stored 7.5 mg, and the miss is silent — an empty result reads exactly like the patient having no such observation. A quantity that cannot be canonicalised is not indexed at all, which is the honest outcome. - SpidxComposite holds both halves on ONE row. Joining a token table to a quantity table on the resource cannot express "same element": a blood pressure has systolic and diastolic components, and that join would match the systolic code against the diastolic value and report a hypertensive reading that was never taken. - SpidxString keeps normalized and raw separately, because matching must not change what is displayed. :contains needs trigram matching Yugabyte does not do well; the CapabilityStatement must decoder it rather than offer a modifier that degrades to a scan. - SpidxReference is separate from fhir_reference_link on purpose. The link table is the GRAPH that _include and chaining walk; this is the INDEX a plain search filters on. Merging them makes every ordinary search pay for the graph's wider rows and double indexing. hashIdentity is a 64-bit hash of (resourceType, paramName) so the leading key stays narrow and fixed-width. Collisions are harmless because both strings are also stored — treating the hash as authoritative would be the bug. FhirSearchIndexShapeTest pins the invariants whose violation is silent, and is mutation-proven: re-adding the entered value to SpidxQuantity and dropping the reindex index from SpidxToken each failed with their own explanation before the revert. ClinicalEntityDisciplineTest's field scan now walks the class hierarchy too, so a violation parked in a @MappedSuperclass — which is exactly where shared columns live — can no longer hide from it. 1630 tests green.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing