From f87a8f5a4a90238a557c5f69d2ceaaf999e3cdc5 Mon Sep 17 00:00:00 2001 From: Dylan Mendelowitz Date: Tue, 26 Sep 2023 13:32:16 -0400 Subject: [PATCH 1/2] Adding Period to ResearchSubjects in CSVClinicalTrialInformationExtractor --- .../CSVClinicalTrialInformationExtractor.js | 5 +++++ src/helpers/schemas/csv.js | 2 ++ src/templates/EncounterTemplate.js | 8 ++++---- src/templates/ResearchSubjectTemplate.js | 13 +++++++++++++ .../CSVClinicalTrialInformationExtractor.test.js | 4 ++++ .../csv-clinical-trial-information-bundle.json | 8 ++++++-- ...-clinical-trial-information-module-response.json | 4 +++- .../clinical-trial-information.csv | 8 ++++---- .../fixtures/research-subject-resource.json | 4 ++++ test/templates/researchSubject.test.js | 6 ++++++ 10 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/extractors/CSVClinicalTrialInformationExtractor.js b/src/extractors/CSVClinicalTrialInformationExtractor.js index 73b431f0..2ca44d58 100644 --- a/src/extractors/CSVClinicalTrialInformationExtractor.js +++ b/src/extractors/CSVClinicalTrialInformationExtractor.js @@ -4,6 +4,7 @@ const { firstEntryInBundle, getEmptyBundle } = require('../helpers/fhirUtils'); const { getPatientFromContext } = require('../helpers/contextUtils'); const { generateMcodeResources } = require('../templates'); const logger = require('../helpers/logger'); +const { formatDateTime } = require('../helpers/dateUtils'); const { CSVClinicalTrialInformationSchema } = require('../helpers/schemas/csv'); @@ -25,6 +26,8 @@ class CSVClinicalTrialInformationExtractor extends BaseCSVExtractor { trialresearchid: trialResearchID, trialstatus: trialStatus, trialresearchsystem: trialResearchSystem, + startdate: startDate, + enddate: endDate, } = clinicalTrialData; const { clinicalSiteID, clinicalSiteSystem } = this; @@ -40,6 +43,8 @@ class CSVClinicalTrialInformationExtractor extends BaseCSVExtractor { trialResearchID, patientId, trialResearchSystem, + startDate: !startDate ? null : formatDateTime(startDate), + endDate: !endDate ? null : formatDateTime(endDate), }, formattedDataStudy: { trialStatus, diff --git a/src/helpers/schemas/csv.js b/src/helpers/schemas/csv.js index 04f813a7..f0de3fef 100644 --- a/src/helpers/schemas/csv.js +++ b/src/helpers/schemas/csv.js @@ -54,6 +54,8 @@ const CSVClinicalTrialInformationSchema = { { name: 'trialResearchID', required: true }, { name: 'trialStatus', required: true }, { name: 'trialResearchSystem' }, + { name: 'startDate' }, + { name: 'endDate' }, ], }; diff --git a/src/templates/EncounterTemplate.js b/src/templates/EncounterTemplate.js index 08529212..eb44e770 100644 --- a/src/templates/EncounterTemplate.js +++ b/src/templates/EncounterTemplate.js @@ -1,11 +1,11 @@ -const { ifAllArgsObj } = require('../helpers/templateUtils'); +const { ifAllArgsObj, ifSomeArgsObj } = require('../helpers/templateUtils'); const { coding, reference } = require('./snippets'); function periodTemplate({ startDate, endDate }) { return { period: { - start: startDate, - end: endDate, + ...(startDate && { start: startDate }), + ...(endDate && { end: endDate }), }, }; } @@ -42,7 +42,7 @@ function encounterTemplate({ ...classTemplate({ classCode, classSystem }), ...subjectTemplate({ subject }), ...ifAllArgsObj(typeTemplate)({ typeCode, typeSystem }), - ...ifAllArgsObj(periodTemplate)({ startDate, endDate }), + ...ifSomeArgsObj(periodTemplate)({ startDate, endDate }), }; } diff --git a/src/templates/ResearchSubjectTemplate.js b/src/templates/ResearchSubjectTemplate.js index 3e980ffe..8c97f148 100644 --- a/src/templates/ResearchSubjectTemplate.js +++ b/src/templates/ResearchSubjectTemplate.js @@ -1,4 +1,5 @@ const { reference, identifier, identifierArr } = require('./snippets'); +const { ifSomeArgsObj } = require('../helpers/templateUtils'); function studyTemplate(trialResearchID, trialResearchSystem) { return { @@ -31,6 +32,15 @@ function researchSubjectIdentifiersTemplate(trialSubjectID) { ); } +function periodTemplate({ startDate, endDate }) { + return { + period: { + ...(startDate && { start: startDate }), + ...(endDate && { end: endDate }), + }, + }; +} + function researchSubjectTemplate({ id, enrollmentStatus, @@ -38,6 +48,8 @@ function researchSubjectTemplate({ trialResearchID, patientId, trialResearchSystem, + startDate, + endDate, }) { if (!(id && enrollmentStatus && trialSubjectID && trialResearchID && patientId)) { throw Error('Trying to render a ResearchStudyTemplate, but a required argument is missing; ensure that id, trialStatus, trialResearchID, clinicalSiteID are all present'); @@ -50,6 +62,7 @@ function researchSubjectTemplate({ ...studyTemplate(trialResearchID, trialResearchSystem), ...individualTemplate(patientId), ...researchSubjectIdentifiersTemplate(trialSubjectID), + ...ifSomeArgsObj(periodTemplate)({ startDate, endDate }), }; } diff --git a/test/extractors/CSVClinicalTrialInformationExtractor.test.js b/test/extractors/CSVClinicalTrialInformationExtractor.test.js index d8fee6b5..4f8a22d8 100644 --- a/test/extractors/CSVClinicalTrialInformationExtractor.test.js +++ b/test/extractors/CSVClinicalTrialInformationExtractor.test.js @@ -40,6 +40,8 @@ describe('CSVClinicalTrialInformationExtractor', () => { expect(csvClinicalTrialInformationExtractor.joinClinicalTrialData(clonedData, patientId)).toEqual(expect.anything()); if (key === 'patientId') return; // MRN is optional if (key === 'trialresearchsystem') return; // trialResearchSystem is optional + if (key === 'startdate') return; // startDate is optional + if (key === 'enddate') return; // endDate is optional delete clonedData[key]; expect(() => csvClinicalTrialInformationExtractor.joinClinicalTrialData(clonedData, patientId)).toThrow(new Error(expectedErrorString)); }); @@ -52,6 +54,8 @@ describe('CSVClinicalTrialInformationExtractor', () => { trialResearchID: firstClinicalTrialInfoResponse.trialresearchid, patientId, trialResearchSystem: firstClinicalTrialInfoResponse.trialresearchsystem, + startDate: firstClinicalTrialInfoResponse.startdate, + endDate: firstClinicalTrialInfoResponse.enddate, }, formattedDataStudy: { trialStatus: firstClinicalTrialInfoResponse.trialstatus, diff --git a/test/extractors/fixtures/csv-clinical-trial-information-bundle.json b/test/extractors/fixtures/csv-clinical-trial-information-bundle.json index f583d355..792b2caf 100644 --- a/test/extractors/fixtures/csv-clinical-trial-information-bundle.json +++ b/test/extractors/fixtures/csv-clinical-trial-information-bundle.json @@ -3,10 +3,10 @@ "type": "collection", "entry": [ { - "fullUrl": "urn:uuid:a9235b06dfe8c24b40b938c7a1265ed3087cf0fa43ef0f11375effbb25ecca25", + "fullUrl": "urn:uuid:aea78e13731d4b105b3a731a48ce77602f159d46299bb02aaaf80e49530115bd", "resource": { "resourceType": "ResearchSubject", - "id": "a9235b06dfe8c24b40b938c7a1265ed3087cf0fa43ef0f11375effbb25ecca25", + "id": "aea78e13731d4b105b3a731a48ce77602f159d46299bb02aaaf80e49530115bd", "identifier": [ { "system": "http://example.com/clinicaltrialsubjectids", @@ -26,6 +26,10 @@ "individual": { "reference": "urn:uuid:mrn-1", "type": "Patient" + }, + "period": { + "start": "2020-01-01", + "end": "2021-01-01" } } }, diff --git a/test/extractors/fixtures/csv-clinical-trial-information-module-response.json b/test/extractors/fixtures/csv-clinical-trial-information-module-response.json index f7317f26..591f8836 100644 --- a/test/extractors/fixtures/csv-clinical-trial-information-module-response.json +++ b/test/extractors/fixtures/csv-clinical-trial-information-module-response.json @@ -5,6 +5,8 @@ "enrollmentstatus": "example-enrollment-status", "trialresearchid": "example-researchId", "trialstatus": "example-trialStatus", - "trialresearchsystem":"example-system" + "trialresearchsystem":"example-system", + "startdate": "2020-01-01", + "enddate": "2021-01-01" } ] diff --git a/test/sample-client-data/clinical-trial-information.csv b/test/sample-client-data/clinical-trial-information.csv index be74ba37..c5b37081 100644 --- a/test/sample-client-data/clinical-trial-information.csv +++ b/test/sample-client-data/clinical-trial-information.csv @@ -1,4 +1,4 @@ -mrn,trialSubjectID,enrollmentStatus,trialResearchID,trialStatus,trialResearchSystem -123,subjectId-1,potential-candidate,researchId-1,approved,system-1 -456,subjectId-2,on-study-intervention,researchId-1,completed,system-2 -789,subjectId-3,on-study-observation,researchId-2,active, +mrn,trialSubjectID,enrollmentStatus,trialResearchID,trialStatus,trialResearchSystem,startDate,endDate +123,subjectId-1,potential-candidate,researchId-1,approved,system-1,2020-01-01,2021-01-03 +456,subjectId-2,on-study-intervention,researchId-1,completed,system-2,2023-05-03, +789,subjectId-3,on-study-observation,researchId-2,active,,, diff --git a/test/templates/fixtures/research-subject-resource.json b/test/templates/fixtures/research-subject-resource.json index 58c133e0..e4ec2245 100644 --- a/test/templates/fixtures/research-subject-resource.json +++ b/test/templates/fixtures/research-subject-resource.json @@ -16,5 +16,9 @@ }, "individual": { "reference": "urn:uuid:mCODEPatient1" + }, + "period": { + "start": "2020-01-01", + "end": "2021-01-01" } } diff --git a/test/templates/researchSubject.test.js b/test/templates/researchSubject.test.js index 172b87a2..dadd650e 100644 --- a/test/templates/researchSubject.test.js +++ b/test/templates/researchSubject.test.js @@ -8,6 +8,8 @@ const VALID_DATA = { trialSubjectID: 'trial-123', trialResearchID: 'rs1', patientId: 'mCODEPatient1', + startDate: '2020-01-01', + endDate: '2021-01-01', }; const INVALID_DATA = { @@ -16,6 +18,8 @@ const INVALID_DATA = { trialResearchID: 'rs1', patientId: 'mCODEPatient1', trialSubjectID: null, + startDate: '2020-01-01', + endDate: '2021-01-01', }; describe('test ResearchSubject template', () => { @@ -25,6 +29,8 @@ describe('test ResearchSubject template', () => { expect(generatedResearchSubject.id).toEqual(validResearchSubject.id); expect(generatedResearchSubject.trialStatus).toEqual(validResearchSubject.trialStatus); expect(generatedResearchSubject.trialResearchID).toEqual(validResearchSubject.trialResearchID); + expect(generatedResearchSubject.period.start).toEqual(validResearchSubject.period.start); + expect(generatedResearchSubject.period.end).toEqual(validResearchSubject.period.end); expect(isValidFHIR(generatedResearchSubject)).toBeTruthy(); }); From dde33b60406667ea9ff5114c17f8506387caaa63 Mon Sep 17 00:00:00 2001 From: Dylan Mendelowitz Date: Thu, 28 Sep 2023 11:26:36 -0400 Subject: [PATCH 2/2] Moving periodTemplate to snippets for reuse --- src/templates/EncounterTemplate.js | 11 +---------- src/templates/ResearchSubjectTemplate.js | 11 +---------- src/templates/snippets/index.js | 2 ++ src/templates/snippets/period.js | 12 ++++++++++++ 4 files changed, 16 insertions(+), 20 deletions(-) create mode 100644 src/templates/snippets/period.js diff --git a/src/templates/EncounterTemplate.js b/src/templates/EncounterTemplate.js index eb44e770..76f69c41 100644 --- a/src/templates/EncounterTemplate.js +++ b/src/templates/EncounterTemplate.js @@ -1,14 +1,5 @@ const { ifAllArgsObj, ifSomeArgsObj } = require('../helpers/templateUtils'); -const { coding, reference } = require('./snippets'); - -function periodTemplate({ startDate, endDate }) { - return { - period: { - ...(startDate && { start: startDate }), - ...(endDate && { end: endDate }), - }, - }; -} +const { coding, reference, periodTemplate } = require('./snippets'); function classTemplate({ classCode, classSystem }) { return { diff --git a/src/templates/ResearchSubjectTemplate.js b/src/templates/ResearchSubjectTemplate.js index 8c97f148..cd86a5a0 100644 --- a/src/templates/ResearchSubjectTemplate.js +++ b/src/templates/ResearchSubjectTemplate.js @@ -1,4 +1,4 @@ -const { reference, identifier, identifierArr } = require('./snippets'); +const { reference, identifier, identifierArr, periodTemplate } = require('./snippets'); const { ifSomeArgsObj } = require('../helpers/templateUtils'); function studyTemplate(trialResearchID, trialResearchSystem) { @@ -32,15 +32,6 @@ function researchSubjectIdentifiersTemplate(trialSubjectID) { ); } -function periodTemplate({ startDate, endDate }) { - return { - period: { - ...(startDate && { start: startDate }), - ...(endDate && { end: endDate }), - }, - }; -} - function researchSubjectTemplate({ id, enrollmentStatus, diff --git a/src/templates/snippets/index.js b/src/templates/snippets/index.js index f21199cb..b73fde20 100644 --- a/src/templates/snippets/index.js +++ b/src/templates/snippets/index.js @@ -10,6 +10,7 @@ const { stagingMethodTemplate } = require('./cancerStaging'); const { medicationTemplate } = require('./medication'); const { subjectTemplate } = require('./subject'); const { treatmentReasonTemplate } = require('./treatmentReason'); +const { periodTemplate } = require('./period'); module.exports = { bodySiteTemplate, @@ -22,6 +23,7 @@ module.exports = { medicationTemplate, meta, narrative, + periodTemplate, reference, stagingMethodTemplate, subjectTemplate, diff --git a/src/templates/snippets/period.js b/src/templates/snippets/period.js new file mode 100644 index 00000000..d9e62b20 --- /dev/null +++ b/src/templates/snippets/period.js @@ -0,0 +1,12 @@ +function periodTemplate({ startDate, endDate }) { + return { + period: { + ...(startDate && { start: startDate }), + ...(endDate && { end: endDate }), + }, + }; +} + +module.exports = { + periodTemplate, +};