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

Move phdi customizations into fork #3

Merged
merged 30 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c8d32d1
Merge branch 'main' of https://github.com/microsoft/FHIR-Converter
mcmcgrath13 Nov 1, 2024
2c3de46
fix: move over custom fhir files
mcmcgrath13 Nov 1, 2024
931a935
Add custom filter to process batch of resources in parallel (#576)
pallar-ms Nov 1, 2024
e4b2177
fix: make it build
mcmcgrath13 Nov 1, 2024
f71a68c
fix: add back microsoft health source
mcmcgrath13 Nov 1, 2024
f83b422
fix: try adding using
mcmcgrath13 Nov 1, 2024
52c2eea
Merge branch 'main' of https://github.com/microsoft/FHIR-Converter in…
mcmcgrath13 Nov 1, 2024
f480cf2
Merge branch 'main' of https://github.com/skylight-hq/FHIR-Converter …
mcmcgrath13 Nov 1, 2024
d25973f
fix: ignore output.json
mcmcgrath13 Nov 1, 2024
943177c
fix: point into output dir
mcmcgrath13 Nov 1, 2024
3b3591d
fix: debug logging
mcmcgrath13 Nov 1, 2024
200f870
fix: more debug logging
mcmcgrath13 Nov 1, 2024
294724d
fix: capture the exception
mcmcgrath13 Nov 1, 2024
baed751
fix: all the debugs
mcmcgrath13 Nov 1, 2024
d7a5bd7
fix: wat
mcmcgrath13 Nov 1, 2024
cab8b01
fix: am I crazy?
mcmcgrath13 Nov 1, 2024
c621144
fix: more debug logging
mcmcgrath13 Nov 1, 2024
ec15d26
ci: add testing workflow
mcmcgrath13 Nov 1, 2024
e9a7a16
ci: fix yaml
mcmcgrath13 Nov 1, 2024
da791b0
ci: remove working directory
mcmcgrath13 Nov 1, 2024
2e47a19
fix: case
mcmcgrath13 Nov 4, 2024
fb9cbf3
docs: add some context to the readme
mcmcgrath13 Nov 4, 2024
495f84b
fix: what is the test value on the github runner?
mcmcgrath13 Nov 4, 2024
e36b7e8
fix: case
mcmcgrath13 Nov 4, 2024
5d9105b
test: debugging gzip test
mcmcgrath13 Nov 4, 2024
d1d49a8
test: add linux value
mcmcgrath13 Nov 4, 2024
9319eac
fix: cleanup debug logs
mcmcgrath13 Nov 4, 2024
16cfe65
fix: linting
mcmcgrath13 Nov 4, 2024
1d3e36d
fix: licensing
mcmcgrath13 Nov 5, 2024
2174647
fix: update with latest templates
mcmcgrath13 Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Test fhir-converter

on:
pull_request:
push:
branches:
- main

jobs:
unit-test-dotnet-fhir-converter:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
- name: Run tests
run: dotnet test --filter FullyQualifiedName~Converter.UnitTests

functional-test-dotnet-fhir-converter:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: "6.0.x"
- name: Run tests
run: dotnet test --filter FullyQualifiedName~Converter.FunctionalTests
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ bld/

# Visual Studio 2015/2017 cache/options directory
.vs/
.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

Expand Down Expand Up @@ -363,4 +364,12 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# ASDF
.tool-versions

# Common test files
/input.txt
/output.json
output/
3 changes: 2 additions & 1 deletion CustomAnalysisRules.ruleset
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
<Rule Id="SA1623" Action="None" />
<Rule Id="SA1629" Action="None" />
<Rule Id="SA1652" Action="None" />
<Rule Id="SA1633" Action="None" />
</Rules>
</RuleSet>
</RuleSet>
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.
Copyright (c) 2024 Skylight. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# FHIR Converter
# Skylight fork of microsoft/FHIR Converter

FHIR converter is an open source project that enables conversion of health data from legacy formats to and from FHIR. The FHIR converter uses the [Liquid template language](https://shopify.github.io/liquid/) and the .NET runtime.

The FHIR converter supports the following conversions: **HL7v2 to FHIR**, **C-CDA to FHIR**, **JSON to FHIR**, **FHIR STU3 to R4**, and **FHIR to HL7v2** (*Preview*).
The Microsoft FHIR converter supports the following conversions: **HL7v2 to FHIR**, **C-CDA to FHIR**, **JSON to FHIR**, **FHIR STU3 to R4**, and **FHIR to HL7v2** (*Preview*).

The Skylight fork has added support for **eCR to FHIR** and **ELR to FHIR**. Some other changes to the code were needed to support these conversions in addition to the new functionality. These converters are still under active development and are not yet fully validated.

The converter uses templates that define mappings between these different data formats. The templates are written in [Liquid](https://shopify.github.io/liquid/) templating language and make use of custom [filters](docs/Filters-and-Tags.md).

Expand Down
1,861 changes: 1,861 additions & 0 deletions data/Templates/ELR/ELR.liquid

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions data/Templates/eCR/ConsultationNote.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{% evaluate patientId using 'Utils/GenerateId' obj: msg.ClinicalDocument.recordTarget.patientRole -%}
{% assign fullPatientId = patientId | prepend: 'Patient/' -%}
{% include 'Header' -%}
{% include 'Section/AllergiesAndAdverseReaction' -%}
{% include 'Section/Problem' -%}

{% include 'Section/FamilyHistory' -%}
{% include 'Section/Immunization' -%}
{% include 'Section/Medication' -%}
{% include 'Section/Procedure' -%}
{% include 'Section/Result' -%}
{% include 'Section/SocialHistory' -%}
{% include 'Section/VitalSign' -%}
{% include 'Section/FunctionalStatus' -%}
{% include 'Section/MedicalEquipment' -%}
{% include 'Section/AdvanceDirective' -%}
{% include 'Section/MentalStatus' -%}
{% include 'Section/Nutrition' -%}

{% assign documentId = msg | to_json_string | generate_uuid -%}
{% include 'Resource/DocumentReference' documentReference: msg ID: documentId -%}
]
}
16 changes: 16 additions & 0 deletions data/Templates/eCR/DataType/_Address.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% assign lines = Address.streetAddressLine | to_array -%}
{% if lines.first._ or Address.city._ or Address.state._ or Address.country._ or Address.postalCode._ or Address.county._ -%}
"use": "{{ Address.use | get_property: 'ValueSet/AddressUse' }}",

"line": [
{% assign lines = Address.streetAddressLine | to_array -%}
{% for l in lines -%}
"{{l._}}",
{% endfor -%}
],
"city": "{{Address.city._}}",
"state": "{{Address.state._}}",
"country": "{{Address.country._}}",
"postalCode": "{{Address.postalCode._}}",
"district": "{{Address.county._}}",
{% endif -%}
7 changes: 7 additions & 0 deletions data/Templates/eCR/DataType/_CodeableConcept.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"coding":
[
{% assign concepts = CodeableConcept | to_array -%}
{% for concept in concepts -%}
{ {% include 'DataType/Coding' Coding: concept -%} },
{% endfor -%}
],
16 changes: 16 additions & 0 deletions data/Templates/eCR/DataType/_Coding.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"code": "{{ Coding.code }}",
{%- capture codeSystemName -%}
{% include 'ValueSet/SystemReference' code: Coding.codeSystem %}
{%- endcapture -%}
"system": {{ codeSystemName }},
{% if Coding.displayName -%}
"display": "{{ Coding.displayName | strip }}",
{% elsif Coding.originalText._ -%}
"display": "{{ Coding.originalText._ | strip }}",
{% elsif Coding.originalText.reference._ -%}
"display": "{{ Coding.originalText.reference._ }}",
{% elsif codeSystemName contains "loinc" -%}
"display": "{{ Coding.code | get_loinc_name }}",
{% elsif codeSystemName contains "rxnorm" -%}
"display": "{{ Coding.code | get_rxnorm_name }}",
{% endif -%}
11 changes: 11 additions & 0 deletions data/Templates/eCR/DataType/_ContactPoint.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% if ContactPoint.value -%}
{% if ContactPoint.value contains 'tel:' -%}
"system":"phone",
"value": "{{ContactPoint.value | replace: 'tel:\s*', ''}}",
"use": "{{ ContactPoint.use | get_property: 'ValueSet/TelecomUse' }}",
{% elsif ContactPoint.value contains 'mailto:' or ContactPoint.value contains '@' -%}
"system":"email",
"value": "{{ContactPoint.value | replace: 'mailto:\s*', ''}}",
"use": "{{ ContactPoint.use | get_property: 'ValueSet/TelecomUse' }}",
{% endif -%}
{% endif -%}
16 changes: 16 additions & 0 deletions data/Templates/eCR/DataType/_HumanName.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use":"{{ HumanName.use | get_property: 'ValueSet/NameUse' }}",
"family":"{{HumanName.family._}}",
"given":[
{% assign givens = HumanName.given | to_array -%}
{% for g in givens -%}
"{{g._}}",
{% endfor -%}
],
"prefix":
[
"{{HumanName.prefix._}}",
],
"suffix":
[
"{{HumanName.suffix._}}",
]
13 changes: 13 additions & 0 deletions data/Templates/eCR/DataType/_Identifier.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% if Identifier.nullFlavor == null -%}
{% if Identifier.extension -%}
"system":{% include 'ValueSet/SystemReference' code: Identifier.root -%},
"value":"{{Identifier.extension}}",
"assigner":
{
"display":"{{Identifier.assigningAuthorityName}}"
}
{% else -%}
"system":"urn:ietf:rfc:3986",
"value":"urn:uuid:{{Identifier.root}}",
{% endif -%}
{% endif -%}
9 changes: 9 additions & 0 deletions data/Templates/eCR/DataType/_IdentifierRoot.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% if Identifier.nullFlavor == null -%}
"value":"{{Identifier.root}}",
{% if Identifier.assigningAuthorityName -%}
"assigner":
{
"display":"{{Identifier.assigningAuthorityName}}"
}
{% endif -%}
{% endif -%}
2 changes: 2 additions & 0 deletions data/Templates/eCR/DataType/_Period.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"start":"{{ Period.low.value | format_as_date_time }}",
"end":"{{ Period.high.value | format_as_date_time }}",
11 changes: 11 additions & 0 deletions data/Templates/eCR/DataType/_Reason.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% assign key = "2_16_840_1_113883_10_20_22_2_12" -%}
{% assign reas_n = Reason[key] -%}
{% if reason and reas_n.entry and reas_n.entry.observation and reas_n.entry.observation.value and reas_n.entry.observation.value.originalText and reas_n.entry.observation.value.originalText._ %}
"reason": [{
"value": [{
"concept": {
"text": "{{ reas_n.entry.observation.value.originalText._ }}",
}
}]
}],
{% endif -%}
24 changes: 24 additions & 0 deletions data/Templates/eCR/DischargeSummary.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"resourceType": "Bundle",
"type": "batch",
"entry": [
{% evaluate patientId using 'Utils/GenerateId' obj: msg.ClinicalDocument.recordTarget.patientRole -%}
{% assign fullPatientId = patientId | prepend: 'Patient/' -%}
{% include 'Header' -%}
{% include 'Section/AllergiesAndAdverseReaction' -%}
{% include 'Section/HospitalDischargeDiagnosis' -%}

{% include 'Section/FunctionalStatus' -%}
{% include 'Section/HospitalAdmissionDiagnosis' -%}
{% include 'Section/Problem' -%}
{% include 'Section/Procedure' -%}
{% include 'Section/VitalSign' -%}
{% include 'Section/SocialHistory' -%}
{% include 'Section/Immunization' -%}
{% include 'Section/FamilyHistory' -%}
{% include 'Section/HospitalDischargeMedication' -%}

{% assign documentId = msg | to_json_string | generate_uuid -%}
{% include 'Resource/DocumentReference' documentReference: msg ID: documentId -%}
]
}
26 changes: 26 additions & 0 deletions data/Templates/eCR/EICR.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"resourceType": "Bundle",
"type": "batch",
"entry": [{% evaluate patientId using 'Utils/GenerateId' obj: msg.ClinicalDocument.recordTarget.patientRole -%}
{% assign fullPatientId = patientId | prepend: 'Patient/' -%}

{% include 'Header' -%}
{% include 'Section/AllergiesAndAdverseReaction' -%}
{% include 'Section/Medication' -%}
{% include 'Section/Problem' -%}
{% include 'Section/Pregnancy' -%}
{% include 'Section/Result' -%}
{% include 'Section/SocialHistory' -%}
{% include 'Section/VitalSign' -%}

{% include 'Section/Procedure' -%}
{% include 'Section/Immunization' -%}
{% include 'Section/FunctionalStatus' -%}
{% include 'Section/FamilyHistory' -%}
{% include 'Section/AdvanceDirective' -%}
{% include 'Section/MedicalEquipment' -%}
{% include 'Section/MentalStatus' -%}
{% include 'Section/Nutrition' -%}
{% include 'Section/Payer' -%}
]
}
19 changes: 19 additions & 0 deletions data/Templates/eCR/Entry/AdvanceDirective/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{% if entry.organizer -%}
{% assign organizationId = entry.organizer | to_json_string | generate_uuid -%}
{% include 'Resource/Consent' consentScope: 'adr', consentEntry: entry.organizer, ID: organizationId -%}
{% include 'Reference/Consent/Patient' ID: organizationId, REF: fullPatientId -%}

{% if entry.organizer.component.observation.reference -%}
{% assign referenceId = entry.organizer.component.observation.reference | to_json_string | generate_uuid -%}
{% include 'Resource/DocumentReference2' docref: entry.organizer.component.observation.reference, ID: referenceId -%}
{% assign fullReferenceId = referenceId | prepend: 'DocumentReference/' -%}
{% include 'Reference/Consent/SourceReference' ID: organizationId, REF: fullReferenceId -%}
{% endif -%}

{% if entry.organizer.component.observation.author.assignedAuthor -%}
{% evaluate practitionerADId using 'Utils/GenerateId' obj: entry.organizer.component.observation.author.assignedAuthor -%}
{% include 'Resource/Practitioner' practitioner: entry.organizer.component.observation.author.assignedAuthor, ID: practitionerADId -%}
{% assign fullPractitionerADId = practitionerADId | prepend: 'Practitioner/' -%}
{% include 'Reference/Consent/Performer' ID: organizationId, REF: fullPractitionerADId -%}
{% endif -%}
{% endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% assign statusCode = entry.act.statusCode -%}
{{ entry.act.entryRelationship | to_array | batch_render: 'Entry/AllergiesAndAdverseReaction/entry_act_entryRelationship', 'relationship' }}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% assign templateIdString = relationship.observation.templateId | to_json_string -%}
{% if templateIdString contains '"2.16.840.1.113883.10.20.22.4.7"' -%}
{% assign allergyId = relationship.observation | to_json_string | generate_uuid -%}
{% include 'Resource/AllergyIntolerance' allergyStatus: statusCode, allergyEntry: relationship.observation, ID: allergyId -%}
{% include 'Reference/AllergyIntolerance/Patient' ID: allergyId, REF: fullPatientId -%}
{% endif -%}
3 changes: 3 additions & 0 deletions data/Templates/eCR/Entry/Complication/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% assign observationId = entry.observation | to_json_string | generate_uuid -%}
{% include 'Resource/Condition' conditionEntry: entry.observation, ID: observationId -%}
{% include 'Reference/Condition/Subject' ID: observationId, REF: fullPatientId -%}
14 changes: 14 additions & 0 deletions data/Templates/eCR/Entry/Encounter/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% assign encounterId = entry | to_json_string | generate_uuid -%}
{% include 'Resource/Encounter' encounter: entry.encounter, ID: encounterId -%}
{% include 'Reference/Encounter/Subject' ID: encounterId, REF: fullPatientId -%}

{% if entry.encounter.performer.assignedEntity -%}
{% assign practitionerEncPerfId = entry.encounter.performer.assignedEntity | to_json_string | generate_uuid -%}
{% include 'Resource/Practitioner' practitioner: entry.encounter.performer.assignedEntity, ID: practitionerEncPerfId -%}
{% assign fullPractitionerEncPerfId = practitionerEncPerfId | prepend: 'Practitioner/' -%}
{% include 'Reference/Encounter/Participant_Individual' ID: encounterId, REF: fullPractitionerEncPerfId -%}
{% endif -%}

{{ entry.encounter.participant | to_array | batch_render: 'Entry/Encounter/entry_encounter_participant', 'participant' }}
{{ entry.encounter.entryRelationship | to_array | batch_render: 'Entry/Encounter/entry_encounter_entryRelationship', 'relationship' }}

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ relationship.act.entryRelationship | to_array | batch_render: 'Entry/Encounter/entry_encounter_entryRelationship_act_entryRelationship', 'entryRelationship' }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{% if entryRelationship.observation -%}
{% assign observationId = entryRelationship.observation | to_json_string | generate_uuid -%}
{% include 'Resource/Condition' conditionEntry: entryRelationship.observation, ID: observationId -%}
{% include 'Reference/Condition/Subject' ID: observationId, REF: fullPatientId -%}
{% assign fullObservationId = observationId | prepend: 'Condition/' -%}
{% include 'Reference/Encounter/Diagnosis_Condition' ID: encounterId, -%}
{% endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{% if participant.typeCode == 'LOC' -%}
{% assign templateIdString = participant.participantRole.templateId | to_json_string -%}
{% if templateIdString contains '"2.16.840.1.113883.10.20.22.4.32"'-%}
{% assign locationId = participant.participantRole | to_json_string | generate_uuid -%}
{% include 'Resource/Location' location: participant.participantRole, ID: locationId -%}
{% assign fullLocationId = locationId | prepend: 'Location/' -%}
{% include 'Reference/Encounter/Location_Location' ID: encounterId, REF: fullLocationId -%}
{% endif -%}
{% endif -%}
3 changes: 3 additions & 0 deletions data/Templates/eCR/Entry/FamilyHistory/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% assign organizationId = entry.organizer | to_json_string | generate_uuid -%}
{% include 'Resource/FamilyMemberHistory' familyEntry: entry.organizer ID: organizationId -%}
{% include 'Reference/FamilyMemberHistory/Patient' ID: organizationId, REF:fullPatientId -%}
12 changes: 12 additions & 0 deletions data/Templates/eCR/Entry/FunctionalStatus/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% assign observationId = entry.observation | to_json_string | generate_uuid -%}
{{ entry.observation.templateId | to_array | batch_render: 'Entry/HospitalDischargeDiagnosis/entry_act_entryRelationship', 'relationship' }}
{% for templateId in entry.observation.templateId -%}
{% if templateId.root == "2.16.840.1.113883.10.20.22.4.4" -%}
{% include 'Resource/Condition' conditionEntry: entry.observation, ID: observationId -%}
{% include 'Reference/Condition/Subject' ID: observationId, REF: fullPatientId -%}
{% endif -%}
{% if templateId.root == "2.16.840.1.113883.10.20.22.4.2" -%}
{% include 'Resource/Observation' observationEntry: entry.observation, ID: observationId -%}
{% include 'Reference/Observation/Subject' ID: observationId, REF: fullPatientId -%}
{% endif -%}
{% endfor -%}
3 changes: 3 additions & 0 deletions data/Templates/eCR/Entry/Goal/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% assign observationId = entry.observation | to_json_string | generate_uuid -%}
{% include 'Resource/Goal' goalEntry: entry.observation, ID: observationId -%}
{$ include 'Reference/Goal/Subject' ID: observationId, REF: fullPatientId -$}
1 change: 1 addition & 0 deletions data/Templates/eCR/Entry/HealthConcern/_entry.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ entry.act.entryRelationship | to_array | batch_render: 'Entry/HealthConcern/entry_act_entryRelationship', 'relationship' }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% if relationship.observation -%}
{% assign observationId = relationship.observation | to_json_string | generate_uuid -%}
{% include 'Resource/Condition' conditionEntry: relationship.observation, ID: observationId -%}
{% include 'Reference/Condition/Subject' ID: observationId, REF: fullPatientId -%}
{% endif -%}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ entry.act.entryRelationship | to_array | batch_render: 'Entry/HospitalAdmissionDiagnosis/entry_act_entryRelationship', 'relationship' }}
Loading
Loading