fhirkit 0.1.0

FHIR R4 for Rust: typed models for every resource and datatype generated from the official specification, lossless JSON with path-precise validation, typed search queries, FHIRPath
Documentation
# fhirkit roadmap

fhirkit is the FHIR sibling of hl7kit and mwlkit: general-purpose FHIR R4
for Rust (and Python), not tied to radiology. It uses the same rules as its
siblings: no runtime dependencies in the core crate, no `unsafe`, no panics
on input, and it compiles for `wasm32-unknown-unknown`.

Everything is generated from the official `hl7.fhir.r4.core` 4.0.1 package
by `crates/fhirkit-gen`, and the generated code is committed.

## Phase 1: models and JSON (done: core)

- [x] Generator: 146 resources, 39 datatypes, 658 structs, 186 choice enums,
      cycle-aware boxing, `contentReference` reuse.
- [x] Dependency-free JSON reader and writer. Decimals keep their exact text,
      key order is kept, duplicate keys are reported, errors carry
      line and column.
- [x] Lenient decoding that reports every problem with its path
      (`Observation.component[1].valueQuantity`):
  - primitive formats (per the R4 regexes, hand-written), required elements,
    choice conflicts, unknown elements, empty arrays and strings,
    misaligned `_element` arrays;
  - `from_json` returns the value together with the issues;
    `from_json_strict` fails on any error.
- [x] Cargo features per specification category (`foundation`, `base`,
      `clinical`, `financial`, `specialized`).
- [x] Conformance: all 5,309 official R4 examples read and write back
      byte-for-byte equivalent JSON. The 15 examples that are invalid in the
      package itself are pinned to exactly their known problems.
- [ ] Required bindings: code lists from the package's CodeSystems for
      every `required` binding, checked on read (`Observation.status`).
- [ ] Builders or constructors for ergonomic creation, and
      `Reference::to::<Patient>("123")` helpers.
- [ ] XML reading and writing (optional feature).
- [ ] Measure and cap WebAssembly size per feature group.

## Phase 2: typed search

Generated from the package's 1,400 `SearchParameter`s. Each one has a
name, a type (token, reference, date, string, quantity, uri, number,
composite, special), a list of resource types it applies to, reference
targets and a FHIRPath expression.

- [ ] `Observation::search().code(token).date(ge("2024"))`: only the
      parameters that exist for the resource, with typed values and the
      modifiers each type allows (`:exact`, `:contains`, `:missing`, `:not`,
      `:above`, `:below`, `:in`, `:of-type`, …).
- [ ] Chaining (`subject:Patient.identifier=…`), checked against the
      reference targets; reverse chaining (`_has`); `_include` and
      `_revinclude` with their `:iterate` forms. All of these are valid by
      construction.
- [ ] Result parameters (`_sort`, `_count`, `_elements`, `_summary`,
      `_total`, `_contained`).
- [ ] Rendering to URL form, and parsing a URL back into the typed form, so
      incoming queries can be checked and explained.
- [ ] Composite parameters (`component-code-value-quantity`).
- [ ] Tests: every SearchParameter's expression and targets round-trip, plus
      the examples from the FHIR search page.

## Phase 3: FHIRPath

- [ ] Parser for the FHIRPath 2.0 grammar (normative in R4), with
      positioned errors.
- [ ] Evaluator over the typed models, through a generated reflection
      layer (child elements by name, type names, choice resolution for
      `ofType`/`is`/`as`). It keeps decimal precision and gives
      date/time partial-precision comparison semantics.
- [ ] Function library, in this order: the SQL-on-FHIR shareable subset
      first (`where`, `exists`, `empty`, `first`, `ofType`, `extension`,
      `join`, indexers, arithmetic, comparison), then the rest of the
      specification.
- [ ] Custom function registry that accepts type-specifier arguments
      (`getReferenceKey(Patient)`), and environment variables (`%resource`,
      `%context`, `%rowIndex`, typed `%constant`s).
- [ ] Run the generated invariants (`obs-6`, `ele-1`, …) as part of
      validation.
- [ ] Gate: HL7's official FHIRPath test suite (R4 `tests-fhir-r4.xml`).
- [ ] Reference to check against: helios-fhirpath (MIT).

## Phase 4: mappings

- [ ] hl7kit gets a general v2 → FHIR layer:
  - PID → Patient
  - PV1 → Encounter
  - ORC/OBR → ServiceRequest
  - OBX → Observation
  - AL1 → AllergyIntolerance
  - DG1 → Condition

  Follow the HL7 v2-to-FHIR ConceptMaps where they exist.
- [ ] The radiology mapping (DICOM → ImagingStudy, MII profiles) moves from
      `dicomscope-core` onto fhirkit types. dicomscope's bundle and its CI
      validation must come out unchanged.

## Phase 5: Python

- [ ] `fhirkit-py` (PyO3 in its own crate, as with hl7kit-py): typed resource
      classes or dict views, `parse` and `validate` with issue lists, the search
      builder, FHIRPath `evaluate`.
- [ ] Positioning: fast, R4 support (which fhir.resources dropped in v7),
      path-precise issues, v2 mapping. Benchmark against fhir.resources.

## SQL-on-FHIR (planned; starts after FHIRPath)

Target specification: view semantics as in the 3.0.0 ballot (Sept 2026,
FHIR 6.0.0 based). A 2.0.0 view (published 2024-10) gives the same rows,
and fhirkit will read both JSON shapes: `resourceType` as a URL or a
token, `identifier` as an object or an array.

Milestones:

1. **ViewDefinition model and static checks.** Unique and SQL-safe column
   names; `unionAll` branches with the same columns in the same order;
   at most one of `forEach`, `forEachOrNull` and `repeat` per select; every
   FHIRPath expression parses.
2. **FHIRPath prerequisites.** These come from phase 3:
   - `getResourceKey()`, `getReferenceKey(Type)` with a pluggable key
     strategy (default `Type/id`);
   - `%rowIndex` and typed constants of all 19 types;
   - `ofType` on choice elements;
   - `lowBoundary`/`highBoundary`;
   - errors instead of silent results for a non-boolean `where` and for a
     multi-valued column without `collection`.
3. **Runner.**
   - The specification's processing algorithm: Cartesian product of
     selects, `forEach` as an inner join, `forEachOrNull` as a left join,
     recursive `repeat`, `unionAll`, column order, `where` filters.
   - Contained resources are not emitted as rows.
   - Rows carry typed FHIR values.
   - Gate: the official suite from `FHIR/sql-on-fhir.js` `tests/*.json`
     (MIT; 144 tests, 133 shareable and 11 experimental), run by a Rust
     test that writes `test_report.json`. The suite changes often, so it
     is not vendored: `fetch-fixtures.sh` fetches it fresh from `main` in
     every CI run and every `local-ci.sh` run, into
     `tmp/fhir/sql-on-fhir/`, and records the commit. Target 133/133, then 144/144,
     then registration on sql-on-fhir.org's implementations page.
4. **Output.**
   - JSON, NDJSON and CSV without dependencies.
   - Behind an `arrow` feature: Arrow `RecordBatch`, with the schema taken
     from `column.type`, the specification's default SQL type map and
     `ansi/type` tags; Parquet from that.
   - `CREATE TABLE` generation.
5. **Scale.** Streaming NDJSON and Bulk Data export folders, fan-out per
   resource type, parallel with bounded memory.
6. **Python.**
   - `run_view(view, resources | path)` returning dict rows or a
     `pyarrow.Table` (zero-copy via `pyo3-arrow`, so pandas, polars and
     DuckDB work directly);
   - `validate_view`, `to_parquet`.
7. **Later, optional.**
   - SQLQuery/SQLView libraries executed through DuckDB or SQLite over the
     Arrow tables.
   - A FHIRPath-to-SQL backend (JSONB, DuckDB).
   - `$sql-run` / `$sql-export` endpoints in a separate server crate.

Prior art:
- helios-sof, with `pysof` on PyPI (MIT, Rust, 144/144, Parquet);
- octofhir-sof (MIT/Apache, in-memory and FHIRPath→SQL, 144/144);
- the reference implementation sof-js (MIT).

What fhirkit adds is R4 typed models underneath, the v2 → FHIR pipeline
in front, and Arrow-native Python.

Open questions:
- R4 only, or R5/R6 later? The ViewDefinition resource itself is R6.
- Is an HTTP operations layer in scope at all?