Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fhir: tooling to auto-generate an adaptor #801

Closed
wants to merge 28 commits into from
Closed

Conversation

josephjclark
Copy link
Collaborator

@josephjclark josephjclark commented Oct 25, 2024

Summary

This PR adds tooling to auto-generate a FHIR adaptor from a FHIR spec.

Closes #798

Usage guide

First time (to generate packages/fhir-jembi):

pnpm generate-fhir jembi --spec https://build.fhir.org/ig/jembi/ethiopia-hiv/branches/master/definitions.json.zip

To rebuild from the same spec:

pnpm generate-fhir jembi

To update/redownload the spec:
To rebuild from the same spec:

pnpm generate-fhir jembi --respec

Steps

  • Moved the gen code into a single central command pnpm generate-fhir
  • Re-generated fhir-ndr-et with no diffs in builders.js
  • Generated PASSING (but basic) unit tests for each builder function
  • Add valuesets to type definitions
  • Add an intialiser function in the mappings, which is useful for meta and text stuff
  • Handle FHIR extensions (complex types) better
  • Generate a FHIR v4 adaptor and hand-write datatype helpers into it
  • Re-base fhir-ndr-et on the fhir 4 adaptor
  • Set a better default icon

Later

  • Generate skipped tests for each example in the spec
  • [ ]

AI Usage

Please disclose how you've used AI in this work (it's cool, we just want to know!):

  • Code generation (copilot but not intellisense)
  • Learning or fact checking
  • Strategy / design
  • Optimisation / refactoring
  • Translation / spellchecking / doc gen
  • Other
  • I have not used AI

You can read more details in our Responsible AI Policy

@josephjclark josephjclark marked this pull request as draft October 28, 2024 11:08
@josephjclark
Copy link
Collaborator Author

Refer to #812 for guidance on how to handle types.

I don't think it's a copy and paste solution but it at least shows where we were going wrong.

@josephjclark
Copy link
Collaborator Author

Here's the a no-diff diff from builders.js in a02d9c0

> pnpm generate-fhir jembi --spec https://build.fhir.org/ig/jembi/ethiopia-hiv/branches/master/definitions.json.zip

> diff --color packages/fhir-jembi/src/builders.js packages/fhir-ndr-et/src/builders.js 
31239c31239
< }
---
> }
\ No newline at end of file

This depends on mappings file (because of course it does!), which I've temporarily checked in. It uses ordered generation too.

Pretty pleased with this: I've externalised the tooling into a pretty elegant command.

The commits from this point will start to diverge the code

@josephjclark
Copy link
Collaborator Author

Auto-generated unit tests 😎

They don't do a lot, but they do verify that the generated code works and resources can be created

  art-follow-up-careplan
    ✔ should create a simple art-follow-up-careplan

  cervical-cancer-care-plan
    ✔ should create a simple cervical-cancer-care-plan

  cotrimoxazole-preventive-therapy-careplan
    ✔ should create a simple cotrimoxazole-preventive-therapy-careplan

  tb-treatment-careplan
    ✔ should create a simple tb-treatment-careplan

  tpt-careplan
    ✔ should create a simple tpt-careplan

  entry-from-outside-target-facility-encounter
    ✔ should create a simple entry-from-outside-target-facility-encounter

  target-facility-encounter
    ✔ should create a simple target-facility-encounter

  arv-regimen-medication
    ✔ should create a simple arv-regimen-medication

  oi-medication
    ✔ should create a simple oi-medication

  tpt-medication
    ✔ should create a simple tpt-medication

  arv-medication-administration
    ✔ should create a simple arv-medication-administration

  cotrimoxazole-preventive-therapy-medication-administration
    ✔ should create a simple cotrimoxazole-preventive-therapy-medication-administration

  fluconazole-preventive-therapy-medication-administration
    ✔ should create a simple fluconazole-preventive-therapy-medication-administration

  arv-medication-dispense
    ✔ should create a simple arv-medication-dispense

  cotrimoxazole-preventive-therapy-medication-dispense
    ✔ should create a simple cotrimoxazole-preventive-therapy-medication-dispense

  generic-medication-dispense
    ✔ should create a simple generic-medication-dispense

  arv-medication-request
    ✔ should create a simple arv-medication-request

  cotrimoxazole-preventive-therapy-medication-request
    ✔ should create a simple cotrimoxazole-preventive-therapy-medication-request

  generic-medication-request
    ✔ should create a simple generic-medication-request

  tpt-medication-request
    ✔ should create a simple tpt-medication-request

  active-tb-observation
    ✔ should create a simple active-tb-observation

  alt-ast-observation
    ✔ should create a simple alt-ast-observation

  alternate-tb-prophylaxis-type-observation
    ✔ should create a simple alternate-tb-prophylaxis-type-observation

  alternate-tpt-at-follow-up-observation
    ✔ should create a simple alternate-tpt-at-follow-up-observation

  art-eligibility-status-observation
    ✔ should create a simple art-eligibility-status-observation

  art-followup-status-observation
    ✔ should create a simple art-followup-status-observation

  art-followup-stopped-reasons-observation
    ✔ should create a simple art-followup-stopped-reasons-observation

  art-not-started-plan-next-step-observation
    ✔ should create a simple art-not-started-plan-next-step-observation

  arv-adherence-observation
    ✔ should create a simple arv-adherence-observation

  arv-change-category-type-observation
    ✔ should create a simple arv-change-category-type-observation

  arv-poor-adherence-reasons-observation
    ✔ should create a simple arv-poor-adherence-reasons-observation

  arv-regimen-change-reason-observation
    ✔ should create a simple arv-regimen-change-reason-observation

  arv-regimen-changed-observation
    ✔ should create a simple arv-regimen-changed-observation

  arv-regimen-side-effects-observation
    ✔ should create a simple arv-regimen-side-effects-observation

  assessed-for-pain-observation
    ✔ should create a simple assessed-for-pain-observation

  blood-pressure
    ✔ should create a simple blood-pressure

  bmi-observation
    ✔ should create a simple bmi-observation

  breastfeeding-status-observation
    ✔ should create a simple breastfeeding-status-observation

  cd4-absolute-observation
    ✔ should create a simple cd4-absolute-observation

  cd4-percentage-observation
    ✔ should create a simple cd4-percentage-observation

  cervical-cancer-screening-accepted-observation
    ✔ should create a simple cervical-cancer-screening-accepted-observation

  cervical-cancer-screening-counselling-status-observation
    ✔ should create a simple cervical-cancer-screening-counselling-status-observation

  cervical-cancer-screening-method-observation
    ✔ should create a simple cervical-cancer-screening-method-observation

  cervical-cancer-screening-observation
    ✔ should create a simple cervical-cancer-screening-observation

  cervical-cancer-screening-result-observation
    ✔ should create a simple cervical-cancer-screening-result-observation

  cervical-cancer-screening-type-observation
    ✔ should create a simple cervical-cancer-screening-type-observation

  cervical-cancer-treatment-received-observation
    ✔ should create a simple cervical-cancer-treatment-received-observation

  children-developmental-milestone-observation
    ✔ should create a simple children-developmental-milestone-observation

  confirmed-hiv-positive-observation
    ✔ should create a simple confirmed-hiv-positive-observation

  cotrimoxazole-preventive-therapy-adherence-observation
    ✔ should create a simple cotrimoxazole-preventive-therapy-adherence-observation

  cotrimoxazole-preventive-therapy-observation
    ✔ should create a simple cotrimoxazole-preventive-therapy-observation

  counseled-for-hiv-observation
    ✔ should create a simple counseled-for-hiv-observation

  creatine-observation
    ✔ should create a simple creatine-observation

  current-art-duration-observation
    ✔ should create a simple current-art-duration-observation

  delivery-mode-observation
    ✔ should create a simple delivery-mode-observation

  delivery-place-observation
    ✔ should create a simple delivery-place-observation

  differentiated-service-delivery-observation
    ✔ should create a simple differentiated-service-delivery-observation

  disclosure-status-observation
    ✔ should create a simple disclosure-status-observation

  edema-observation
    ✔ should create a simple edema-observation

  elicited-index-case-contacts-observation
    ✔ should create a simple elicited-index-case-contacts-observation

  enhanced-adherence-counselling-observation
    ✔ should create a simple enhanced-adherence-counselling-observation

  estimated-delivery-date-observation
    ✔ should create a simple estimated-delivery-date-observation

  family-member-hiv-status-observation
    ✔ should create a simple family-member-hiv-status-observation

  family-planning-method-observation
    ✔ should create a simple family-planning-method-observation

  fluconazole-preventive-therapy-observation
    ✔ should create a simple fluconazole-preventive-therapy-observation

  future-pregnancy-plans-observation
    ✔ should create a simple future-pregnancy-plans-observation

  generic-observation
    ✔ should create a simple generic-observation

  head-circumference-observation
    ✔ should create a simple head-circumference-observation

  health-status-observation
    ✔ should create a simple health-status-observation

  heart-rate-observation
    ✔ should create a simple heart-rate-observation

  height-observation
    ✔ should create a simple height-observation

  hgb-observation
    ✔ should create a simple hgb-observation

  highest-education-observation
    ✔ should create a simple highest-education-observation

  hiv-prevention-plan-observation
    ✔ should create a simple hiv-prevention-plan-observation

  hiv-program-final-outcome-known-observation
    ✔ should create a simple hiv-program-final-outcome-known-observation

  hiv-program-final-outcome-observation
    ✔ should create a simple hiv-program-final-outcome-observation

  hiv-program-reason-art-not-started-observation
    ✔ should create a simple hiv-program-reason-art-not-started-observation

  hiv-program-status-observation
    ✔ should create a simple hiv-program-status-observation

  hiv-status-disclosure-at-enrollment-observation
    ✔ should create a simple hiv-status-disclosure-at-enrollment-observation

  hiv-test-results-observation
    ✔ should create a simple hiv-test-results-observation

  hiv-treatment-prior-enrollment-observation
    ✔ should create a simple hiv-treatment-prior-enrollment-observation

  inh-at-follow-up-observation
    ✔ should create a simple inh-at-follow-up-observation

  last-menstrual-period-observation
    ✔ should create a simple last-menstrual-period-observation

  level-of-pain-observation
    ✔ should create a simple level-of-pain-observation

  maternal-hiv-status-observation
    ✔ should create a simple maternal-hiv-status-observation

  muac-observation
    ✔ should create a simple muac-observation

  nutritional-screening-result-observation
    ✔ should create a simple nutritional-screening-result-observation

  nutritional-status-observation
    ✔ should create a simple nutritional-status-observation

  nutritional-suppliments-provided-observation
    ✔ should create a simple nutritional-suppliments-provided-observation

  otz-observation
    ✔ should create a simple otz-observation

  patient-functional-status-observation
    ✔ should create a simple patient-functional-status-observation

  patient-occupation-observation
    ✔ should create a simple patient-occupation-observation

  patient-who-stage-observation
    ✔ should create a simple patient-who-stage-observation

  physical-examinations-observation
    ✔ should create a simple physical-examinations-observation

  pregnancy-status-observation
    ✔ should create a simple pregnancy-status-observation

  presenting-symptom-observation
    ✔ should create a simple presenting-symptom-observation

  reason-eligible-for-art-observation
    ✔ should create a simple reason-eligible-for-art-observation

  reason-not-eligbile-for-tpt-observation
    ✔ should create a simple reason-not-eligbile-for-tpt-observation

  resides-in-catchment-area-observation
    ✔ should create a simple resides-in-catchment-area-observation

  respiratory-rate-observation
    ✔ should create a simple respiratory-rate-observation

  screened-for-tb-observation
    ✔ should create a simple screened-for-tb-observation

  target-population-observation
    ✔ should create a simple target-population-observation

  tb-diagnostic-test-result-observation
    ✔ should create a simple tb-diagnostic-test-result-observation

  tb-prophylaxis-type-observation
    ✔ should create a simple tb-prophylaxis-type-observation

  tb-screening-result-observation
    ✔ should create a simple tb-screening-result-observation

  tb-treatment-started-observation
    ✔ should create a simple tb-treatment-started-observation

  tb-treatment-status-observation
    ✔ should create a simple tb-treatment-status-observation

  temperature-observation
    ✔ should create a simple temperature-observation

  tested-for-hiv-observation
    ✔ should create a simple tested-for-hiv-observation

  therapeutic-supplementary-food-observation
    ✔ should create a simple therapeutic-supplementary-food-observation

  tpt-eligbility-observation
    ✔ should create a simple tpt-eligbility-observation

  tpt-started-observation
    ✔ should create a simple tpt-started-observation

  treatment-completed-observation
    ✔ should create a simple treatment-completed-observation

  treatment-discontinued-observation
    ✔ should create a simple treatment-discontinued-observation

  viral-load-count-observation
    ✔ should create a simple viral-load-count-observation

  viral-load-indication-observation
    ✔ should create a simple viral-load-indication-observation

  viral-load-performed-observation
    ✔ should create a simple viral-load-performed-observation

  weight-observation
    ✔ should create a simple weight-observation

  patient
    ✔ should create a simple patient

  related-person
    ✔ should create a simple related-person

@josephjclark
Copy link
Collaborator Author

I am going to merge this soon and start building other things on top.

I still want to do stuff like import fhir verbs from the base adaptor, generate base builders for v4, work out how to handle basic datatypes (how and where do we define and test those basic helpers? And how do we map across versions?)

I still also need to add a couple of big features in value-set mapping, fixing a bug with typings in lightning, and handling extensions even better.

But we can spin these out into issues and take them on later

@josephjclark

This comment was marked as resolved.

@josephjclark
Copy link
Collaborator Author

TODO: how do we handle meta and text in different implementations?

valuesets are now written to a file when the spec is downloaded and parsed
@josephjclark
Copy link
Collaborator Author

I'm gonna add a general initaliser function to the mapper. Maybe it goes in the overrides block, so you can set it on one resorce, profile, or all resources.

This is free code which needs to get baked into the builder function (we we need to serialise or parse the mapping function and embed it in the code). It gets called with the resource at the end of the build process, when most of the resource is built.

This is going to be useful for generating meta and text objects (both of which I think can maybe be complex). It's also a good catch all for free code and handling any wierd edge cases.

@josephjclark
Copy link
Collaborator Author

Ok, before I merge, I either want to:

a) generate a fhir-4 base adaptor which includes datatypes, and import those datatypes into the new adaptors
b) add datatype builders to the main fhir adaptor import the base into the new adaptors

This is a really important part of the strategy and does need thinking about

If we generate fhir adaptor per version, then obviously we get very good support across fhir versions (presumably good for fhir-to-fhir migration). The mappings file would include the base version, defaulting to 4.

Even within that, I don't know how much the datatypes change. Would the same set of builders map to all 5 fhir versions? Does each version hand-write its own, or is there some kind of common import with overrides/mutations to handle different versions?

Maybe we shouldn't worry too much. Let's just start with a generated version 4, hand-write (and test) the builders, and import those builders into our generated adaptor.

That gives me a good architecutral shape, which can be improved upon later.

@josephjclark
Copy link
Collaborator Author

Closing this PR down because I'm going to merge and release the fhir-fr adaptor now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Epic: Fhir Adaptor Generation
1 participant