Skip to content

Commit

Permalink
Merge pull request #99 from samply/develop
Browse files Browse the repository at this point in the history
exporter bugs fixed, pulchrification of CQL replacements
  • Loading branch information
enola-dkfz authored Jan 9, 2024
2 parents 6f73c39 + 1a8c222 commit b60223f
Show file tree
Hide file tree
Showing 34 changed files with 333 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "focus"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
license = "Apache-2.0"

Expand Down
28 changes: 28 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::{path::Path, env, io::{BufWriter, Write}, fs::File};

use build_data::get_git_dirty;

/// Outputs a readable version number such as
Expand All @@ -15,11 +17,37 @@ fn version() -> String {
}
}

fn build_cqlmap() {
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("replace_map.rs");
let mut file = BufWriter::new(File::create(path).unwrap());

write!(&mut file, r#"
static REPLACE_MAP: once_cell::sync::Lazy<HashMap<&'static str, &'static str>> = once_cell::sync::Lazy::new(|| {{
let mut map = HashMap::new();
"#).unwrap();

for cqlfile in std::fs::read_dir(Path::new("resources/cql")).unwrap() {
let cqlfile = cqlfile.unwrap();
let cqlfilename = cqlfile.file_name().to_str().unwrap().to_owned();
let cqlcontent = std::fs::read_to_string(cqlfile.path()).unwrap();
write!(&mut file, r####"
map.insert(r###"{cqlfilename}"###, r###"{cqlcontent}"###);
"####).unwrap();
}

writeln!(&mut file, "
map
}});"
).unwrap();
}

fn main() {
build_data::set_GIT_COMMIT_SHORT();
build_data::set_GIT_DIRTY();
build_data::set_BUILD_DATE();
build_data::set_BUILD_TIME();
build_data::no_debug_rebuilds();
println!("cargo:rustc-env=SAMPLY_USER_AGENT=Samply.Focus.{}/{}", env!("CARGO_PKG_NAME"), version());

build_cqlmap();
}
2 changes: 2 additions & 0 deletions resources/cql/BBMRI_STRAT_AGE_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define AgeClass:
(AgeInYears() div 10) * 10
4 changes: 4 additions & 0 deletions resources/cql/BBMRI_STRAT_CUSTODIAN_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
define Custodian:
First(from Specimen.extension E
where E.url = 'https://fhir.bbmri.de/StructureDefinition/Custodian'
return (E.value as Reference).identifier.value)
1 change: 1 addition & 0 deletions resources/cql/BBMRI_STRAT_DEF_IN_INITIAL_POPULATION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
define InInitialPopulation:
1 change: 1 addition & 0 deletions resources/cql/BBMRI_STRAT_DEF_SPECIMEN
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
define Specimen:
5 changes: 5 additions & 0 deletions resources/cql/BBMRI_STRAT_DIAGNOSIS_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Diagnosis:
if InInitialPopulation then [Condition] else {} as List<Condition>
define function DiagnosisCode(condition FHIR.Condition, specimen FHIR.Specimen):
Coalesce(condition.code.coding.where(system = 'http://hl7.org/fhir/sid/icd-10').code.first(), condition.code.coding.where(system = 'http://fhir.de/CodeSystem/dimdi/icd-10-gm').code.first(), specimen.extension.where(url='https://fhir.bbmri.de/StructureDefinition/SampleDiagnosis').value.coding.code.first(), condition.code.coding.where(system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm').code.first())

2 changes: 2 additions & 0 deletions resources/cql/BBMRI_STRAT_GENDER_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define Gender:
if (Patient.gender is null) then 'unknown' else Patient.gender
45 changes: 45 additions & 0 deletions resources/cql/BBMRI_STRAT_SAMPLE_TYPE_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
define function SampleType(specimen FHIR.Specimen):
case FHIRHelpers.ToCode(specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').first())
when Code 'plasma-edta' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-citrat' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-heparin' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-cell-free' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-other' from SampleMaterialType then 'blood-plasma'
when Code 'plasma' from SampleMaterialType then 'blood-plasma'
when Code 'tissue-formalin' from SampleMaterialType then 'tissue-ffpe'
when Code 'tumor-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'normal-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'other-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'tumor-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'normal-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'other-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'tissue-paxgene-or-else' from SampleMaterialType then 'tissue-other'
when Code 'derivative' from SampleMaterialType then 'derivative-other'
when Code 'liquid' from SampleMaterialType then 'liquid-other'
when Code 'tissue' from SampleMaterialType then 'tissue-other'
when Code 'serum' from SampleMaterialType then 'blood-serum'
when Code 'cf-dna' from SampleMaterialType then 'dna'
when Code 'g-dna' from SampleMaterialType then 'dna'
when Code 'blood-plasma' from SampleMaterialType then 'blood-plasma'
when Code 'tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'tissue-other' from SampleMaterialType then 'tissue-other'
when Code 'derivative-other' from SampleMaterialType then 'derivative-other'
when Code 'liquid-other' from SampleMaterialType then 'liquid-other'
when Code 'blood-serum' from SampleMaterialType then 'blood-serum'
when Code 'dna' from SampleMaterialType then 'dna'
when Code 'buffy-coat' from SampleMaterialType then 'buffy-coat'
when Code 'urine' from SampleMaterialType then 'urine'
when Code 'ascites' from SampleMaterialType then 'ascites'
when Code 'saliva' from SampleMaterialType then 'saliva'
when Code 'csf-liquor' from SampleMaterialType then 'csf-liquor'
when Code 'bone-marrow' from SampleMaterialType then 'bone-marrow'
when Code 'peripheral-blood-cells-vital' from SampleMaterialType then 'peripheral-blood-cells-vital'
when Code 'stool-faeces' from SampleMaterialType then 'stool-faeces'
when Code 'rna' from SampleMaterialType then 'rna'
when Code 'whole-blood' from SampleMaterialType then 'whole-blood'
when Code 'swab' from SampleMaterialType then 'swab'
when Code 'dried-whole-blood' from SampleMaterialType then 'dried-whole-blood'
when null then 'Unknown'
else 'Unknown'
end
2 changes: 2 additions & 0 deletions resources/cql/DKTK_STRAT_AGE_CLASS_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define AgeClass:
if (PrimaryDiagnosis.onset is null) then 'unknown' else ToString((AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) div 10) * 10)
8 changes: 8 additions & 0 deletions resources/cql/DKTK_STRAT_AGE_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
define PrimaryDiagnosis:
First(
from [Condition] C
where C.extension.where(url='http://hl7.org/fhir/StructureDefinition/condition-related').empty()
sort by date from onset asc)

define AgeClass:
if (PrimaryDiagnosis.onset is null) then 'unknown' else ToString((AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) div 10) * 10)
4 changes: 4 additions & 0 deletions resources/cql/DKTK_STRAT_DECEASED_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
define PatientDeceased:
First (from [Observation: Code '75186-7' from loinc] O return O.value.coding.where(system = 'http://dktk.dkfz.de/fhir/onco/core/CodeSystem/VitalstatusCS').code.first())
define Deceased:
if (PatientDeceased is null) then 'unbekannt' else PatientDeceased
1 change: 1 addition & 0 deletions resources/cql/DKTK_STRAT_DEF_IN_INITIAL_POPULATION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
define InInitialPopulation:
5 changes: 5 additions & 0 deletions resources/cql/DKTK_STRAT_DIAGNOSIS_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Diagnosis:
if InInitialPopulation then [Condition] else {} as List<Condition>

define function DiagnosisCode(condition FHIR.Condition):
condition.code.coding.where(system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm').code.first()
5 changes: 5 additions & 0 deletions resources/cql/DKTK_STRAT_ENCOUNTER_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Encounter:
if InInitialPopulation then [Encounter] else {} as List<Encounter>

define function Departments(encounter FHIR.Encounter):
encounter.identifier.where(system = 'http://dktk.dkfz.de/fhir/sid/hki-department').value.first()
2 changes: 2 additions & 0 deletions resources/cql/DKTK_STRAT_GENDER_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define Gender:
if (Patient.gender is null) then 'unknown' else Patient.gender
5 changes: 5 additions & 0 deletions resources/cql/DKTK_STRAT_HISTOLOGY_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Histo:
if InInitialPopulation then [Observation] else {} as List <Observation>

define function Histlogoy(histo FHIR.Observation):
if histo.code.coding.where(code = '59847-4').code.first() is null then 0 else 1
2 changes: 2 additions & 0 deletions resources/cql/DKTK_STRAT_MEDICATION_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define MedicationStatement:
if InInitialPopulation then [MedicationStatement] else {} as List <MedicationStatement>
6 changes: 6 additions & 0 deletions resources/cql/DKTK_STRAT_PRIMARY_DIAGNOSIS_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
define PrimaryDiagnosis:
First(
from [Condition] C
where C.extension.where(url='http://hl7.org/fhir/StructureDefinition/condition-related').empty()
sort by date from onset asc)

5 changes: 5 additions & 0 deletions resources/cql/DKTK_STRAT_PROCEDURE_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Procedure:
if InInitialPopulation then [Procedure] else {} as List <Procedure>

define function ProcedureType(procedure FHIR.Procedure):
procedure.category.coding.where(system = 'http://dktk.dkfz.de/fhir/onco/core/CodeSystem/SYSTTherapieartCS').code.first()
5 changes: 5 additions & 0 deletions resources/cql/DKTK_STRAT_SPECIMEN_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
define Specimen:
if InInitialPopulation then [Specimen] else {} as List<Specimen>

define function SampleType(specimen FHIR.Specimen):
specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').code.first()
3 changes: 3 additions & 0 deletions resources/cql/EXLIQUID_ALIQUOTS_CQL_DIAGNOSIS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
define retrieveCondition: First(from [Condition] C return C.code.coding.where(system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm').code.first())
define Diagnosis: if (retrieveCondition is null) then 'unknown' else retrieveCondition

6 changes: 6 additions & 0 deletions resources/cql/EXLIQUID_ALIQUOTS_CQL_SPECIMEN
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
define Specimen:
if InInitialPopulation then [Specimen] else {} as List<Specimen>
define Aliquot:
[Specimen] S
where exists S.collection.quantity.value and exists S.parent.reference and S.container.specimenQuantity.value > 0 define AliquotGroupReferences: flatten Aliquot S return S.parent.reference define AliquotGroupWithAliquot: [Specimen] S where not (S.identifier.system contains 'http://dktk.dkfz.de/fhir/sid/exliquid-specimen') and not exists S.collection.quantity.value and not exists S.container.specimenQuantity.value and AliquotGroupReferences contains 'Specimen/' + S.id define PrimarySampleReferences: flatten AliquotGroupWithAliquot S return S.parent.reference define ExliquidSpecimenWithAliquot: from [Specimen] PrimarySample where PrimarySample.identifier.system contains 'http://dktk.dkfz.de/fhir/sid/exliquid-specimen' and PrimarySampleReferences contains 'Specimen/' + PrimarySample.id
define function SampleType(specimen FHIR.Specimen): specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').code.first()
3 changes: 3 additions & 0 deletions resources/cql/EXLIQUID_CQL_DIAGNOSIS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
define retrieveCondition: First(from [Condition] C return C.code.coding.where(system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm').code.first())
define Diagnosis: if (retrieveCondition is null) then 'unknown' else retrieveCondition

7 changes: 7 additions & 0 deletions resources/cql/EXLIQUID_CQL_SPECIMEN
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
define Specimen:
if InInitialPopulation then [Specimen] else {} as List<Specimen>
define ExliquidSpecimen:
from [Specimen] S
where S.identifier.system contains 'http://dktk.dkfz.de/fhir/sid/exliquid-specimen'
define function SampleType(specimen FHIR.Specimen):
specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').code.first()
3 changes: 3 additions & 0 deletions resources/cql/EXLIQUID_STRAT_DEF_IN_INITIAL_POPULATION
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
define InInitialPopulation:
exists ExliquidSpecimen and

2 changes: 2 additions & 0 deletions resources/cql/EXLIQUID_STRAT_W_ALIQUOTS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define InInitialPopulation: exists ExliquidSpecimenWithAliquot and

2 changes: 2 additions & 0 deletions resources/cql/MTBA_STRAT_GENETIC_VARIANT
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
define GeneticVariantCode:
First (from [Observation: Code '69548-6' from loinc] O return O.component.where(code.coding contains Code '48018-6' from loinc).value.coding.code.first())
12 changes: 12 additions & 0 deletions resources/cql/UCT_STRAT_SPECIMEN_STRATIFIER
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
define Specimen:
if InInitialPopulation then [Specimen] else {} as List<Specimen>

define function SampleType(specimen FHIR.Specimen):
specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').code.first()

define function Lagerort(specimen FHIR.Specimen):
specimen.extension.where(url = 'http://uct-locator/specimen/storage').value.coding.code.first()

define function annotations(specimen FHIR.Specimen):
(if (specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').code.first() is null) then 1 else 0) +
(if (specimen.collection.collected is null) then 1 else 0)
87 changes: 87 additions & 0 deletions resources/test/query_bbmri.cql
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
library Retrieve
using FHIR version '4.0.0'
include FHIRHelpers version '4.0.0'

codesystem loinc: 'http://loinc.org'

codesystem icd10: 'http://hl7.org/fhir/sid/icd-10'

codesystem SampleMaterialType: 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType'

context Patient

define AgeClass:
(AgeInYears() div 10) * 10


define Gender:
if (Patient.gender is null) then 'unknown' else Patient.gender


define Custodian:
First(from Specimen.extension E
where E.url = 'https://fhir.bbmri.de/StructureDefinition/Custodian'
return (E.value as Reference).identifier.value)


define function SampleType(specimen FHIR.Specimen):
case FHIRHelpers.ToCode(specimen.type.coding.where(system = 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType').first())
when Code 'plasma-edta' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-citrat' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-heparin' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-cell-free' from SampleMaterialType then 'blood-plasma'
when Code 'plasma-other' from SampleMaterialType then 'blood-plasma'
when Code 'plasma' from SampleMaterialType then 'blood-plasma'
when Code 'tissue-formalin' from SampleMaterialType then 'tissue-ffpe'
when Code 'tumor-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'normal-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'other-tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'tumor-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'normal-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'other-tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'tissue-paxgene-or-else' from SampleMaterialType then 'tissue-other'
when Code 'derivative' from SampleMaterialType then 'derivative-other'
when Code 'liquid' from SampleMaterialType then 'liquid-other'
when Code 'tissue' from SampleMaterialType then 'tissue-other'
when Code 'serum' from SampleMaterialType then 'blood-serum'
when Code 'cf-dna' from SampleMaterialType then 'dna'
when Code 'g-dna' from SampleMaterialType then 'dna'
when Code 'blood-plasma' from SampleMaterialType then 'blood-plasma'
when Code 'tissue-ffpe' from SampleMaterialType then 'tissue-ffpe'
when Code 'tissue-frozen' from SampleMaterialType then 'tissue-frozen'
when Code 'tissue-other' from SampleMaterialType then 'tissue-other'
when Code 'derivative-other' from SampleMaterialType then 'derivative-other'
when Code 'liquid-other' from SampleMaterialType then 'liquid-other'
when Code 'blood-serum' from SampleMaterialType then 'blood-serum'
when Code 'dna' from SampleMaterialType then 'dna'
when Code 'buffy-coat' from SampleMaterialType then 'buffy-coat'
when Code 'urine' from SampleMaterialType then 'urine'
when Code 'ascites' from SampleMaterialType then 'ascites'
when Code 'saliva' from SampleMaterialType then 'saliva'
when Code 'csf-liquor' from SampleMaterialType then 'csf-liquor'
when Code 'bone-marrow' from SampleMaterialType then 'bone-marrow'
when Code 'peripheral-blood-cells-vital' from SampleMaterialType then 'peripheral-blood-cells-vital'
when Code 'stool-faeces' from SampleMaterialType then 'stool-faeces'
when Code 'rna' from SampleMaterialType then 'rna'
when Code 'whole-blood' from SampleMaterialType then 'whole-blood'
when Code 'swab' from SampleMaterialType then 'swab'
when Code 'dried-whole-blood' from SampleMaterialType then 'dried-whole-blood'
when null then 'Unknown'
else 'Unknown'
end


define Specimen:

if InInitialPopulation then [Specimen] else {} as List<Specimen>

define Diagnosis:
if InInitialPopulation then [Condition] else {} as List<Condition>
define function DiagnosisCode(condition FHIR.Condition, specimen FHIR.Specimen):
Coalesce(condition.code.coding.where(system = 'http://hl7.org/fhir/sid/icd-10').code.first(), condition.code.coding.where(system = 'http://fhir.de/CodeSystem/dimdi/icd-10-gm').code.first(), specimen.extension.where(url='https://fhir.bbmri.de/StructureDefinition/SampleDiagnosis').value.coding.code.first(), condition.code.coding.where(system = 'http://fhir.de/CodeSystem/bfarm/icd-10-gm').code.first())



define InInitialPopulation:

true
27 changes: 27 additions & 0 deletions resources/test/query_bbmri_placeholders.cql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
library Retrieve
using FHIR version '4.0.0'
include FHIRHelpers version '4.0.0'

codesystem loinc: 'http://loinc.org'

codesystem icd10: 'http://hl7.org/fhir/sid/icd-10'

codesystem SampleMaterialType: 'https://fhir.bbmri.de/CodeSystem/SampleMaterialType'

context Patient

BBMRI_STRAT_AGE_STRATIFIER

BBMRI_STRAT_GENDER_STRATIFIER

BBMRI_STRAT_CUSTODIAN_STRATIFIER

BBMRI_STRAT_SAMPLE_TYPE_STRATIFIER

BBMRI_STRAT_DEF_SPECIMEN
if InInitialPopulation then [Specimen] else {} as List<Specimen>

BBMRI_STRAT_DIAGNOSIS_STRATIFIER

BBMRI_STRAT_DEF_IN_INITIAL_POPULATION
true
6 changes: 3 additions & 3 deletions src/exporter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ pub async fn post_exporter_query(body: &String, execute: bool) -> Result<String,
let mut headers = HeaderMap::new();

headers.insert(
header::CONTENT_TYPE, //TODO discard the result, just return OK
HeaderValue::from_static("text/html; charset=UTF-8"),
header::CONTENT_TYPE,
HeaderValue::from_static("application/json"),
);

if let Some(auth_header_value) = CONFIG.auth_header.clone() {
headers.insert(
header::AUTHORIZATION,
"x-api-key",
HeaderValue::from_str(auth_header_value.as_str())
.map_err(FocusError::InvalidHeaderValue)?,
);
Expand Down
Loading

0 comments on commit b60223f

Please sign in to comment.