From 5a8a93108326db7af5db6276a2abc30eb7e44efd Mon Sep 17 00:00:00 2001 From: Hector Cadavid Date: Tue, 17 Sep 2024 11:48:10 +0200 Subject: [PATCH] Removing one of the pairing rules assertions: Generating FHIR-Diabetes with an undefined onsetDate, when Diabetes was reported on a follow-up assessment, and the assessment date is not available. Address issue similar to #19 --- ...675432-hf-diab-followup-missing-date.json} | 8 +-- src/__tests__/diabetes.test.ts | 53 +++++++++++++---- src/lifelines/Diabetes.ts | 58 +++++++++++++------ src/lifelines/HeartFailure.ts | 1 + src/viewerserver/serversettings.ts | 2 +- 5 files changed, 86 insertions(+), 36 deletions(-) rename fhirvalidation/sampleinputs/{input-p675432-hf-followup-missing-date.json => input-p675432-hf-diab-followup-missing-date.json} (94%) diff --git a/fhirvalidation/sampleinputs/input-p675432-hf-followup-missing-date.json b/fhirvalidation/sampleinputs/input-p675432-hf-diab-followup-missing-date.json similarity index 94% rename from fhirvalidation/sampleinputs/input-p675432-hf-followup-missing-date.json rename to fhirvalidation/sampleinputs/input-p675432-hf-diab-followup-missing-date.json index f48cf7a..a2c04c1 100644 --- a/fhirvalidation/sampleinputs/input-p675432-hf-followup-missing-date.json +++ b/fhirvalidation/sampleinputs/input-p675432-hf-diab-followup-missing-date.json @@ -24,13 +24,13 @@ "stroke_followup_adu_q_1":{"2a":"2","3a":"2","3b":"2"}, - "diabetes_presence_adu_q_1": {"1a":"1"}, - "diabetes_startage_adu_q_1": {"1a":"28"}, - "diabetes_followup_adu_q_1": {"1b":"2","1c":"2","2a":"2","3a":"2","3b":"2"}, + "diabetes_presence_adu_q_1": {"1a":"2"}, + "diabetes_startage_adu_q_1": {"1a":""}, + "diabetes_followup_adu_q_1": {"1b":"2","1c":"2","2a":"2","3a":"1","3b":"2"}, "diabetes_type_adu_q_1": {"1a":"2"}, "diabetes_type_adu_q_1_a": {"1a":""}, "t1d_followup_adu_q_1": {"2a":"2","3a":"2","3b":"2"}, - "t2d_followup_adu_q_1": {"2a":"2","3a":"2","3b":"2"}, + "t2d_followup_adu_q_1": {"2a":"2","3a":"1","3b":"2"}, "bp_entrytype_all_m_1": {"1a":"2","2a":"2"}, "bp_bandsize_all_m_1": {"1a":"1","2a":"1","3a":"1"}, diff --git a/src/__tests__/diabetes.test.ts b/src/__tests__/diabetes.test.ts index 010b3bb..921768b 100644 --- a/src/__tests__/diabetes.test.ts +++ b/src/__tests__/diabetes.test.ts @@ -53,6 +53,38 @@ test('diabetes clinical status, when reported positive in a follow-up, diabetes +test('assertion test: diabetes clinical status, when reported positive in a follow-up, but no diabetes type is defined', () => { + + const input = { + "diabetes_presence_adu_q_1": { "1a": "2" }, + "diabetes_followup_adu_q_1": { "1b": "2", "1c": "2", "2a": "2", "3a": "1", "3b": "2" }, + "diabetes_startage_adu_q_1": { "1a": "" }, + "diabetes_type_adu_q_1": { "1a": "2" }, + "diabetes_type_adu_q_1_a": { "1a": "" }, + "t1d_followup_adu_q_1": { "2a": "2", "3a": "2", "3b": "2" }, + "t2d_followup_adu_q_1": { "2a": "2", "3a": "2", "3b": "2" }, + "date": {"1a":"1992-5","1b":"1995-5","1c":"1997-5",/*date1*/"2a":"2001-5",/*date2*/"3a":"2003-5","3b":"2005-5"}, + "age": { "1a": "22" }, + } + + try{ + InputSingleton.getInstance().setInput(input); + expect(diabetesmf.clinicalStatus()).toBe(clinicalStatusSNOMEDCodeList.active); + expect(diabetesmf.isPresent()).toBe(true); + expect(diabetesmf.code()).toBe(conditionsSNOMEDCodeList.diabetes_mellitus_type_1); + expect(diabetesmf.onsetDateTime()).toBe("2002-05"); + //execution shouldn't reach this point + throw new Error('Transformation should have failed with an UnexpectedInputException'); + } + catch(error){ + if (!(error instanceof UnexpectedInputException)) throw new Error('Transformation should have failed with an UnexpectedInputException'); + } + +}); + + + + test('diabetes clinical status, when reported positive in a follow-up after multiple skipped assessments, diabetes type 1', () => { const input = { @@ -75,11 +107,11 @@ test('diabetes clinical status, when reported positive in a follow-up after mult }); -test('diabetes clinical status, with inconsistencies, missing date on the assessment where diabetes is reported', () => { +test('diabetes clinical status (T1D) reported on a follow up, with missing date on the assessment where was reported', () => { const input = { "diabetes_presence_adu_q_1": { "1a": "2" }, - "diabetes_followup_adu_q_1": { "1b": "2", "1c": "2", "2a": "2", "3a": "", "3b": "1" }, + "diabetes_followup_adu_q_1": { "1b": "2", "1c": "2", "2a": "2", "3a": "1", "3b": "2" }, "diabetes_startage_adu_q_1": { "1a": "" }, "diabetes_type_adu_q_1": { "1a": "2" }, "diabetes_type_adu_q_1_a": { "1a": "" }, @@ -89,16 +121,13 @@ test('diabetes clinical status, with inconsistencies, missing date on the assess "age": { "1a": "22" }, } - try{ - InputSingleton.getInstance().setInput(input); - expect(diabetesmf.clinicalStatus()).toBe(clinicalStatusSNOMEDCodeList.active); - expect(diabetesmf.isPresent()).toBe(true); - expect(diabetesmf.code()).toBe(conditionsSNOMEDCodeList.diabetes_mellitus_type_1); - expect(diabetesmf.onsetDateTime()).toBe("2003-05"); - } - catch(error){ - if (!(error instanceof UnexpectedInputException)) fail('Expected exception') - } + + InputSingleton.getInstance().setInput(input); + expect(diabetesmf.clinicalStatus()).toBe(clinicalStatusSNOMEDCodeList.active); + expect(diabetesmf.isPresent()).toBe(true); + expect(diabetesmf.code()).toBe(conditionsSNOMEDCodeList.diabetes_mellitus_type_1); + expect(diabetesmf.onsetDateTime()).toBe(undefined); + }); diff --git a/src/lifelines/Diabetes.ts b/src/lifelines/Diabetes.ts index a65830e..e016019 100644 --- a/src/lifelines/Diabetes.ts +++ b/src/lifelines/Diabetes.ts @@ -90,18 +90,23 @@ const _clinicalStatus = moize((diab_presence:string|undefined,followup_assessmen * ------------------------------------------------------------------ * * @precondition - * - date is never a missing value (is a default variable) * - the problem is 'active' (see clinicalStatus function) * - if there is a diabetes report on a follow-up 'diabetes_followup_adu_q_1', there should be a 'yes' value * in either t2d_followup_adu_q_1 or t2d_followup_adu_q_1 (diabetes type) * * * @pairingrule - * if diabetes_presence_adu_q_1 = yes in 1A => approximate year on which the participant given the age reported by diabetes_startage_adu_q_1 - * (undefined if diabetes_startage_adu_q_1 has a missing value) + * if diabetes_presence_adu_q_1 = yes in 1A => + * if start_age was reported, approximate year of the event given start_age reported (diabetes_startage_adu_q_1) + * and the year of the year of the assessment. + * else + * undefined onset date * else - * if there is a 'yes' in any diabetes_followup_adu_q_1 => mean date between the date of the assessment - * where diabetes_followup_adu_q_1 = yes, and the date of the preceding one. + * if there is a 'yes' in any diabetes_followup_adu_q_1 => + * If the date of the assessment where diabetes_followup_adu_q_1 = yes is available => + * mean date between that particular date (when diabetes_followup_adu_q_1 = yes), and the date of the preceding assessment. + * Else + * return undefined onset date * else * error/precondition violated ('diabetes' is not 'active' if the execution reached this point) * @@ -135,7 +140,7 @@ export const onsetDateTime = ():string|undefined => { return lifelinesDateToISO(lifelinesMeanDate(date1,date2)) } else{ - throw Error("Unexpected input (precondition violated): no 'yes' values in neither t2d_followup_adu_q_1 nor t2d_followup_adu_q_1") + return undefined; } @@ -143,11 +148,21 @@ export const onsetDateTime = ():string|undefined => { } -/** + + /* + * + * Helper function for 'onsetDateTime' * * @param diabFollowUp - * @returns - * @precondition there is always a date on the assessment prior to the one where diabetes_followup_adu_q_1 was 'yes' + * + * @return + * If the date of the assessment where diabetes_followup_adu_q_1 = yes is available => + * mean date between that particular date (when diabetes_followup_adu_q_1 = yes), and the date of the preceding assessment. + * Else + * return undefined date + * + * @precondition: there is at least one 'yes'/1 on diabetes_followup_adu_q_1 + * @precondition there is always a date on one of the assessment prior to the one where diabetes_followup_adu_q_1 was 'yes' * */ function findDatesBetweenDiabetesPresenceReport(): [string,string]|undefined{ @@ -160,18 +175,23 @@ function findDatesBetweenDiabetesPresenceReport(): [string,string]|undefined{ assertIsDefined(diabetesRepWave,`A 'yes' value on diabetes_followup_adu_q_1 was expected`) const diabetesRepWaveDate = inputValue("date",diabetesRepWave) - assertIsDefined(diabetesRepWaveDate,`A non-null date is expected in the assessment where diabetes_followup_adu_q_1 is reported`) + if (diabetesRepWaveDate === undefined){ + return undefined + } + else{ + //find the previous non-undefined assessment date + const assessmentDates:variableAssessments = inputValues('date') + const waves = ['1a','1b','1c','2a','3a','3b']; + const previousWaves = waves.slice(0,waves.indexOf(diabetesRepWave)) + const previousAssessmentWave = previousWaves.reverse().find((pwave)=>assessmentDates[pwave]!==undefined) + + assertIsDefined(previousAssessmentWave,`Assessment (with a defined date) expected to exist previous to the one where diabetes_followup_adu_q_1 is reported`) + + const previousAssessmentDate:string = assessmentDates[previousAssessmentWave]!; + return [previousAssessmentDate,diabetesRepWaveDate] + } - //find the previous non-undefined assessment date - const assessmentDates:variableAssessments = inputValues('date') - const waves = ['1a','1b','1c','2a','3a','3b']; - const previousWaves = waves.slice(0,waves.indexOf(diabetesRepWave)) - const previousAssessmentWave = previousWaves.reverse().find((pwave)=>assessmentDates[pwave]!==undefined) - - assertIsDefined(previousAssessmentWave,`Assessment (with a defined date) expected to exist previous to the one where diabetes_followup_adu_q_1 is reported`) - const previousAssessmentDate:string = assessmentDates[previousAssessmentWave]!; - return [previousAssessmentDate,diabetesRepWaveDate] } diff --git a/src/lifelines/HeartFailure.ts b/src/lifelines/HeartFailure.ts index 39c80ef..6bdd31d 100644 --- a/src/lifelines/HeartFailure.ts +++ b/src/lifelines/HeartFailure.ts @@ -154,6 +154,7 @@ const _clinicalStatus = moize((heartfailure_presence:string|undefined,followup_a * * * @precondition: there is at least one 'yes'/1 on heartfailure_followup_adu_q_1 + * @precondition there is always a date on one of the assessment prior to the one where diabetes_followup_adu_q_1 was 'yes' * * If the date of the assessment where heartfailure_followup_adu_q_1 = yes is available => * mean date between that particular date (when heartfailure_followup_adu_q_1 = yes), and the date of the preceding assessment. diff --git a/src/viewerserver/serversettings.ts b/src/viewerserver/serversettings.ts index a01cfeb..b87ca89 100644 --- a/src/viewerserver/serversettings.ts +++ b/src/viewerserver/serversettings.ts @@ -19,6 +19,6 @@ export const targets:MappingTarget[] = [ //{ "module": './lifelines/HaemoglobinConcentration', "template": '../../zib-2017-mappings/generic/LabTestResult_Diagnostic_Report.jsonata' }, //{ "module": './lifelines/HaemoglobinConcentration', "template": '../../zib-2017-mappings/generic/LabTestResult_Observation.jsonata' }, //{ "module": './lifelines/HaemoglobinConcentration', "template": '../../zib-2017-mappings/generic/LabTestResult_Specimen.jsonata' }, - { "template": '../../zib-2017-mappings/generic/Condition.jsonata', "module": './lifelines/HeartFailure' }, + { "template": '../../zib-2017-mappings/Diabetes.jsonata', "module": './lifelines/Diabetes' }, ]