medizininformatik-initiative / torch

Apache License 2.0
2 stars 0 forks source link

Create Resource Transformer #3

Closed juliangruendner closed 3 months ago

juliangruendner commented 4 months ago

This issue depends on this issue: https://github.com/medizininformatik-initiative/torch/issues/7

Background

The CRTDL (https://github.com/medizininformatik-initiative/clinical-resource-transfer-definition-language) defines groups of data to be extracted which reference specific fhir profiles.

Click to expand JSON Examplegroup which references an extraction of all laboratory values and for these the code and value ```json { "attributeGroups": [ { "groupReference": "https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab", "attributes": [ { "attributeRef": "Observation.code", "mustHave": false }, { "attributeRef": "Observation.value", "mustHave": true } ], "filter": [] } ] } ```

The CRTDL then further defines which attributes to copy from the original resource (attributeRef) and whether the attributes are mustHave attributes or not.

Task

A transformer should be created which based on the information of an attributeGroup, creates new resources based on the referenced profile, the fields to be copied and a original resource.

The transformer should proceed as follows:

  1. Given a groupReference the transformer should use the blueprint creator as implemented here https://github.com/medizininformatik-initiative/torch/issues/7 to create a new resource.

  2. It should then copy over all the attributes as defined by the attributeRef of the CRTDL and for each: 2.1. check if the attribute contains FHIR extensions, which is not specified in the profile referenced by the CRTDL and remove the extensions 2.2. check if the attribute is must have and if it then cannot be copied as it does not exist in the original resource, in which case the copying of the whole resource can be stopped and the resource has to be removed from the extraction

See also this Generator for an example use of the hapi lib for resource creation:

Example

Given this CRTDL:

Click to expand JSON Example ```json { "attributeGroups": [ { "groupReference": "https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab", "attributes": [ { "attributeRef": "Observation.code", "mustHave": false }, { "attributeRef": "Observation.value", "mustHave": true } ], "filter": [] } ] } ```

and this original resource:

Click to expand JSON Example ```json { "category": [ { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "laboratory", "display": "Laboratory" }, { "system": "http://loinc.org", "code": "26436-6", "display": "Laboratory studies (set)" } ] } ], "meta": { "versionId": "12002", "lastUpdated": "2024-04-11T11:02:01.630Z", "profile": [ "https://www.medizininformatik-initiative.de/fhir/core/modul-labor/StructureDefinition/ObservationLab" ] }, "encounter": { "reference": "Encounter/VHF-MIXED-TEST-CASE-0001-a-E-1" }, "valueQuantity": { "value": -666.66, "_unit": { "extension": [ { "url": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "valueCode": "unknown" } ] }, "system": "http://unitsofmeasure.org", "_code": { "extension": [ { "url": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "valueCode": "unknown" } ] } }, "resourceType": "Observation", "effectiveDateTime": "2021-01-01T06:06:00+01:00", "status": "final", "id": "VHF-MIXED-TEST-CASE-0001-a-E-1-OL-15", "code": { "coding": [ { "system": "http://loinc.org", "code": "33762-6" } ], "text": "NT-proBNP SerPl-mCnc" }, "identifier": [ { "type": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "OBI" } ] }, "system": "https://VHFMIXEDTESTCASEA.de/befund", "value": "VHF-MIXED-TEST-CASE-0001-a-E-1-OL-15", "assigner": { "identifier": { "system": "https://www.medizininformatik-initiative.de/fhir/core/NamingSystem/org-identifier", "value": "VHFMIXEDTESTCASEA" } } } ], "subject": { "reference": "Patient/VHF-MIXED-TEST-CASE-0001-a" } } ```

should result in the following extracted resource

TODO @Lucas0T - please check the resulting resource and fix the example - specifically how the data absent reasons have to be added

Click to expand JSON Example ```json { "resourceType": "Observation", "identifier": [ { "dataAbsentReason": { "coding": [ { "code": "not-permitted", "system": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "display": "Not Permitted" } ] } } ], "status": {"dataAbsentReason": { "coding": [ { "code": "not-permitted", "system": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "display": "Not Permitted" } ] }}, "code": { "coding": [ { "system": "http://loinc.org", "code": "33762-6" } ], "text": "NT-proBNP SerPl-mCnc" }, "valueQuantity": { "value": -666.66, "_unit": { "extension": [ { "url": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "valueCode": "unknown" } ] }, "system": "http://unitsofmeasure.org", "_code": { "extension": [ { "url": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "valueCode": "unknown" } ] } }, "effectiveDateTime": {"dataAbsentReason": { "coding": [ { "code": "not-permitted", "system": "http://terminology.hl7.org/CodeSystem/data-absent-reason", "display": "Not Permitted" } ] }} } ```
juliangruendner commented 3 months ago

Potential pseudocode implementation - to still be discussed:

failedPatientList = []

// the found resources are a direct result of the fhir search for each group

For each group:
  1. for each resource in found resource for each attribute in attributes:

    1.1 copy from original ressource (OrigRes)
    1.1.2 if attribut = mustHave and not in OrigRes => skip and move on to next resource
    1.2. resolve elementId in structureDefinition of profile referenced by _groupReference_  and:
    1.2.1. resolve cardinality for itself and its children and add data absent reasons for all cardinalities where 1
    1.2.2. check for itself and children if extensions valid if extensions - remove as necessary  (remove by creating new object if necessary)

    add(getDelta PatientList - patientsFound) to failedPatientList

For all resources where patientRef in failPatientList - delete

after all attributes
check cardinality 1... on first level - if one is missing from the final extracted resource add data absend reason accordingly