Commit 7092fd2c authored by Sebastian Mate's avatar Sebastian Mate
Browse files

basic support for bundles

fix/improve creation of PATIENT_DIMENSION entries
parent 51cddd78
......@@ -32,7 +32,7 @@ create table i2b2miracum.fhir_elt_log (ts timestamptz null, message text null);
create or replace function i2b2miracum.fhir_elt_log(message text) returns void language plpgsql as
$$
begin
--insert into i2b2miracum.fhir_elt_log (ts, message) values (current_timestamp, "message");
insert into i2b2miracum.fhir_elt_log (ts, message) values (current_timestamp, "message");
end;
$$;
......@@ -55,7 +55,6 @@ $$;
--CREATE INDEX observation_fact_observation_blob_idx ON i2b2miracum.observation_fact (observation_blob);
--CREATE INDEX observation_fact_fhir_reference_idx ON i2b2miracum.observation_fact (fhir_reference);
-- Create OBSERVATION_FACT_TEMP, which will be used to store temporary data:
drop table if exists i2b2miracum.observation_fact_temp;
create table i2b2miracum.observation_fact_temp as (select * from i2b2miracum.observation_fact);
......@@ -81,15 +80,47 @@ select setval('instance_num_seq', (select max(instance_num) from i2b2miracum.obs
create or replace function i2b2miracum.fhir_inserted() returns trigger language plpgsql as
$$
declare FHIR_id text := new.fhir->>'id';
declare FHIR_resourcetype text := json_extract_path_text(new.fhir::json, 'resourceType');
declare FHIR_sourcesystem text := new.fhir->'meta'->>'source';
declare FHIR_patient_identifier text;
declare
element text;
i record;
begin
--
perform i2b2miracum.fhir_elt_log('Incoming FHIR: ' || new.fhir::text);
--
if json_extract_path_text(new.fhir::json, 'resourceType') = 'Bundle' then
--for i in select * from jsonb_array_elements(new.fhir->'entry')
for i in (select jsonb_array_elements(new.fhir->'entry') element)
loop
perform i2b2miracum.process_fhir_resource(i.element->'resource');
end loop;
else
perform i2b2miracum.process_fhir_resource(new.fhir);
end if;
--
return null; -- Return nothing. This prevents that the FHIR data is actually written into the "FHIR" table.
exception
when others then
perform i2b2miracum.fhir_elt_log('Exception cought: ' || sqlerrm);
insert into i2b2miracum.fhir_failed(ts, message, fhir) values (now(), sqlerrm, new.fhir);
return null;
end;
$$;
create or replace function i2b2miracum.process_fhir_resource(fhir jsonb) returns void language plpgsql as
$$
declare FHIR_id text := fhir->>'id';
declare FHIR_resourcetype text := json_extract_path_text(fhir::json, 'resourceType');
declare FHIR_sourcesystem text := fhir->'meta'->>'source';
declare FHIR_patient_identifier text; -- Use the resource ID if patient identifier ist not specified otherwise.
declare FHIR_encounter_identifier text;
declare i2b2_patient_identifier int; declare i2b2_patient_found int;
declare i2b2_encounter_identifier int; declare i2b2_encounter_found int;
declare i json;
declare omgjson json := '[{ "type": false }, { "type": "photo" }, {"type": "comment" }]'::json;
begin
if FHIR_resourcetype != 'Patient' and
if FHIR_resourcetype != 'Bundle' and
FHIR_resourcetype != 'Patient' and
FHIR_resourcetype != 'Encounter' and
FHIR_resourcetype != 'Condition' and
FHIR_resourcetype != 'Observation' and
......@@ -107,25 +138,29 @@ begin
--
-- Extract FHIR_patient_identifier and FHIR_encounter_identifier from FHIR resource:
if FHIR_resourcetype = 'Patient' then
FHIR_patient_identifier := jsonb_array_elements(new.fhir->'identifier')->>'value';
if FHIR_patient_identifier is null then raise exception 'FHIR_patient_identifier is empty!'; end if;
FHIR_patient_identifier := jsonb_array_elements(fhir->'identifier')->>'value';
if FHIR_patient_identifier is null then
-- raise exception 'FHIR_patient_identifier is empty!'; end if;
FHIR_patient_identifier := 'Patient/' || FHIR_id;
end if;
else
FHIR_patient_identifier := new.fhir->'subject'->'identifier'->>'value';
FHIR_patient_identifier := fhir->'subject'->'identifier'->>'value';
end if;
--
if FHIR_resourcetype = 'Encounter' then
FHIR_encounter_identifier := jsonb_array_elements(new.fhir->'identifier')->>'value';
FHIR_encounter_identifier := jsonb_array_elements(fhir->'identifier')->>'value';
if FHIR_encounter_identifier is null then raise exception 'FHIR_encounter_identifier is empty!'; end if;
else
FHIR_encounter_identifier := new.fhir->'encounter'->'identifier'->>'value';
FHIR_encounter_identifier := fhir->'encounter'->'identifier'->>'value';
end if;
--
if FHIR_resourcetype = 'MedicationStatement' then
FHIR_encounter_identifier := new.fhir->'context'->'identifier'->>'value';
FHIR_encounter_identifier := fhir->'context'->'identifier'->>'value';
end if;
--
--if FHIR_patient_identifier is null then FHIR_patient_identifier := 'UNKNOWN'; end if;
--if FHIR_encounter_identifier is null then FHIR_encounter_identifier := 'UNKNOWN'; end if;
if FHIR_patient_identifier is null then FHIR_patient_identifier := 'UNKNOWN'; end if;
if FHIR_encounter_identifier is null then FHIR_encounter_identifier := 'UNKNOWN'; end if;
perform i2b2miracum.fhir_elt_log('FHIR_patient_identifier = ' || FHIR_patient_identifier);
perform i2b2miracum.fhir_elt_log('FHIR_encounter_identifier = ' || FHIR_encounter_identifier);
--
......@@ -172,22 +207,22 @@ begin
marital_status_cd,religion_cd,zip_cd,statecityzip_path,income_cd,patient_blob,update_date,
download_date,import_date,sourcesystem_cd,upload_id)
values (i2b2_patient_identifier, -- patient_num
case when (new.fhir->>'deceasedDateTime')::timestamp is not null then 'Y'
case when (fhir->>'deceasedDateTime')::timestamp is not null then 'Y'
else 'N' end, -- vital_status_cd
(new.fhir->>'birthDate')::timestamp, -- birth_date
(new.fhir->>'deceasedDateTime')::timestamp, -- death_date
case when new.fhir->>'gender' = 'male' then 'm'
when new.fhir->>'gender' = 'female' then 'f'
when new.fhir->>'gender' = 'other' then 'd'
when new.fhir->>'gender' = 'unknown' then 'x'
(fhir->>'birthDate')::timestamp, -- birth_date
(fhir->>'deceasedDateTime')::timestamp, -- death_date
case when fhir->>'gender' = 'male' then 'm'
when fhir->>'gender' = 'female' then 'f'
when fhir->>'gender' = 'other' then 'd'
when fhir->>'gender' = 'unknown' then 'x'
else null end, -- sex_cd
case when (new.fhir->>'deceasedDateTime')::timestamp is null then extract(year from age(now(), (new.fhir->>'birthDate')::timestamp))
else extract(year from age((new.fhir->>'deceasedDateTime')::timestamp, (new.fhir->>'birthDate')::timestamp)) end, -- age_in_years_num
case when (fhir->>'deceasedDateTime')::timestamp is null then extract(year from age(now(), (fhir->>'birthDate')::timestamp))
else extract(year from age((fhir->>'deceasedDateTime')::timestamp, (fhir->>'birthDate')::timestamp)) end, -- age_in_years_num
null, -- language_cd
null, -- race_cd
null, -- marital_status_cd
null, -- religion_cd
jsonb_array_elements(new.fhir->'address')->>'postalCode', -- zip_cd
jsonb_array_elements(fhir->'address')->>'postalCode', -- zip_cd
null, -- statecityzip_path
null, -- income_cd
null, -- patient_blob
......@@ -252,10 +287,12 @@ begin
select i2b2_encounter_identifier, -- encounter_num
i2b2_patient_identifier, -- patient_num
case when fhir_data.system = 'http://fhir.de/CodeSystem/dimdi/icd-10-gm' then 'ICD10'
else 'UNKNOWN'
end || ':' || fhir_data.code, -- concept_cd
else 'UNKNOWN'
end || ':' || fhir_data.code, -- concept_cd
'FHIR', -- provider_id
fhir_data.onsetDateTime, -- start_date
case when fhir_data.onsetDateTime is not null then fhir_data.onsetDateTime
else now()
end, -- start_date
'@', -- modifier_cd
nextval('instance_num_seq'), -- instance_num
'@', -- valtype_cd
......@@ -264,7 +301,9 @@ begin
null, -- valueflag_cd
null, -- quantity_num
null, -- units_cd
fhir_data.onsetDateTime, -- end_date
case when fhir_data.onsetDateTime is not null then fhir_data.onsetDateTime
else now()
end, -- end_date
'', -- location_cd
FHIR_id, -- observation_blob
0, -- confidence_num
......@@ -275,9 +314,9 @@ begin
1, -- upload_id
nextval('instance_num_seq') -- text_search_index
from (SELECT
jsonb_array_elements(new.fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(new.fhir->'code'->'coding')->>'system' as system,
(new.fhir->>'onsetDateTime')::timestamp as onsetDateTime
jsonb_array_elements(fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(fhir->'code'->'coding')->>'system' as system,
(fhir->>'onsetDateTime')::timestamp as onsetDateTime
) fhir_data;
end if;
--
......@@ -316,13 +355,13 @@ begin
1, -- upload_id
nextval('instance_num_seq') -- text_search_index
from (SELECT
jsonb_array_elements(new.fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(new.fhir->'code'->'coding')->>'system' as system,
(new.fhir->>'effectiveDateTime')::timestamp as effectiveDateTime,
(new.fhir->'valueQuantity'->>'value')::numeric(18,5) as valueQuantity_value,
new.fhir->'valueQuantity'->>'unit'::text as valueQuantity_unit,
new.fhir->'valueQuantity'->>'system'::text as valueQuantity_system,
new.fhir->'valueQuantity'->>'code'::text as valueQuantity_code
jsonb_array_elements(fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(fhir->'code'->'coding')->>'system' as system,
(fhir->>'effectiveDateTime')::timestamp as effectiveDateTime,
(fhir->'valueQuantity'->>'value')::numeric(18,5) as valueQuantity_value,
fhir->'valueQuantity'->>'unit'::text as valueQuantity_unit,
fhir->'valueQuantity'->>'system'::text as valueQuantity_system,
fhir->'valueQuantity'->>'code'::text as valueQuantity_code
) fhir_data;
end if;
--
......@@ -361,9 +400,9 @@ begin
1, -- upload_id
nextval('instance_num_seq') -- text_search_index
from (SELECT
jsonb_array_elements(new.fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(new.fhir->'code'->'coding')->>'system' as system,
(new.fhir->>'performedDateTime')::timestamp as performedDateTime
jsonb_array_elements(fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(fhir->'code'->'coding')->>'system' as system,
(fhir->>'performedDateTime')::timestamp as performedDateTime
) fhir_data;
end if;
--
......@@ -381,9 +420,9 @@ begin
fhir_data.system,
fhir_data.display
from (SELECT
jsonb_array_elements(new.fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(new.fhir->'code'->'coding')->>'system' as system,
jsonb_array_elements(new.fhir->'code'->'coding')->>'display' as display
jsonb_array_elements(fhir->'code'->'coding')->>'code' as code,
jsonb_array_elements(fhir->'code'->'coding')->>'system' as system,
jsonb_array_elements(fhir->'code'->'coding')->>'display' as display
) fhir_data;
-- Update old MedicationStatement data in OBSERVATION_FACT
-- Move the old OBSERVATION_FACT entry (MedicationStatement data) to OBSERVATION_FACT_TEMP:
......@@ -464,18 +503,18 @@ begin
fhir_medication.code as medication_code,
fhir_medication.system as medication_system,
new_as_table.fhir->'medicationReference'->>'reference' as medication_reference
from (select new.*) new_as_table
from (select *) new_as_table
left join i2b2miracum.fhir_medication
on new_as_table.fhir->'medicationReference'->>'reference' = 'Medication/' || fhir_medication.id
) fhir_data;
end if;
--
return null; -- Return nothing. This prevents that the FHIR data is actually written into the "FHIR" table.
--return null; -- Return nothing. This prevents that the FHIR data is actually written into the "FHIR" table.
exception
when others then
perform i2b2miracum.fhir_elt_log('Exception cought.');
insert into i2b2miracum.fhir_failed(ts, message, fhir) values (now(), sqlerrm, new.fhir);
return null;
perform i2b2miracum.fhir_elt_log('Exception cought: ' || sqlerrm || ' FHIR = ' || fhir);
insert into i2b2miracum.fhir_failed(ts, message, fhir) values (now(), sqlerrm, fhir);
--return null;
end;
$$;
......@@ -486,6 +525,7 @@ create trigger fhir_inserted before insert on i2b2miracum.fhir for each row exec
-- ============= Some Test Data =============
/*
INSERT INTO i2b2miracum.fhir (fhir) VALUES ('{ "resourceType": "Patient", "id": "Patient1", "meta": { "source": "Patient1.json", "profile": [ "https://fhir.miracum.org/core/StructureDefinition/PatientIn" ] }, "identifier": [ { "use": "official", "type": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MR" } ] }, "system": "https://fhir.diz.uk-erlangen.de/NamingSystem/patientId", "value": "Patient1" } ], "gender": "male", "birthDate": "1977-04-27", "deceasedDateTime": "2000-12-12T12:12:12+00:00", "address": [ { "type": "both", "city": "Entenhausen", "postalCode": "123456", "country": "DE" } ] }');
INSERT INTO i2b2miracum.fhir (fhir) VALUES ('{ "resourceType": "Patient", "id": "Patient2", "meta": { "source": "Patient2.json", "profile": [ "https://fhir.miracum.org/core/StructureDefinition/PatientIn" ] }, "identifier": [ { "use": "official", "type": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MR" } ] }, "system": "https://fhir.diz.uk-erlangen.de/NamingSystem/patientId", "value": "Patient2" } ], "gender": "female", "birthDate": "1978-04-27", "deceasedDateTime": "2001-12-12T12:12:12+00:00", "address": [ { "type": "both", "city": "Entenhausen", "postalCode": "123457", "country": "DE" } ] }');
INSERT INTO i2b2miracum.fhir (fhir) VALUES ('{ "resourceType": "Patient", "id": "Patient1", "meta": { "source": "Patient3.json", "profile": [ "https://fhir.miracum.org/core/StructureDefinition/PatientIn" ] }, "identifier": [ { "use": "official", "type": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MR" } ] }, "system": "https://fhir.diz.uk-erlangen.de/NamingSystem/patientId", "value": "Patient3" } ], "gender": "male", "birthDate": "1977-04-11", "address": [ { "type": "both", "city": "Entenhausen", "postalCode": "123456", "country": "DE" } ] }');
......@@ -520,5 +560,3 @@ INSERT INTO i2b2miracum.fhir (fhir) VALUES ('{"id": "Medication1", "code": {"cod
INSERT INTO i2b2miracum.fhir (fhir) VALUES ('{"id": "MedicationStatement1", "meta": {"profile": ["https://www.medizininformatik-initiative.de/fhir/core/StructureDefinition/MedicationStatement"], "security": [{"code": "PSEUDED", "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationValue", "display": "part of the resource is pseudonymized"}]}, "dosage": [{"text": "Cisplatin (50 mg/m²", "doseAndRate": [{"doseQuantity": {"unit": "mg/m²", "value": 50.0}}]}], "status": "unknown", "context": {"type": "Encounter", "reference": "Encounter/XXXXXXXXXXXXX", "identifier": {"type": {"text": "Visit number", "coding": [{"code": "VN", "system": "http://terminology.hl7.org/CodeSystem/v2-0203"}]}, "value": "Encounter4", "system": "https://fhir.diz.uk-erlangen.de/NamingSystem/encounterId"}}, "subject": {"type": "Patient", "reference": "Patient/XXXXXXXXXXXXXXX", "identifier": {"type": {"text": "Medical record number", "coding": [{"code": "MR", "system": "http://terminology.hl7.org/CodeSystem/v2-0203"}]}, "value": "Patient4", "system": "https://fhir.diz.uk-erlangen.de/NamingSystem/patientId"}}, "identifier": [{"value": "Cisplatin_50.0mg/m²_208004", "system": "https://averbis.com/de.averbis.types.health.Medication"}], "dateAsserted": "2008-07-29T17:44:00+00:00", "resourceType": "MedicationStatement", "effectiveDateTime": "2008-07-29T17:44:00+00:00", "medicationReference": {"type": "Medication", "reference": "Medication/Medication1", "identifier": {"value": "Cisplatin_50.0mg/m²", "system": "https://averbis.com/de.averbis.types.health.Medication"}}}');
*/
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment