diff --git a/src/extractors/FHIRAdverseEventExtractor.js b/src/extractors/FHIRAdverseEventExtractor.js index cee02685..82903518 100644 --- a/src/extractors/FHIRAdverseEventExtractor.js +++ b/src/extractors/FHIRAdverseEventExtractor.js @@ -1,4 +1,6 @@ const { BaseFHIRExtractor } = require('./BaseFHIRExtractor'); +const { getResearchStudiesFromContext } = require('../helpers/contextUtils'); +const logger = require('../helpers/logger'); const BASE_STUDY = ''; // No base study specified @@ -12,14 +14,28 @@ class FHIRAdverseEventExtractor extends BaseFHIRExtractor { // In addition to default parametrization, add study if specified async parametrizeArgsForFHIRModule({ context }) { const paramsWithID = await super.parametrizeArgsForFHIRModule({ context }); + let allResearchStudyResources = []; + try { + allResearchStudyResources = getResearchStudiesFromContext(context); + } catch (e) { + logger.error(e.message); + logger.debug(e.stack); + } + // The patient is referenced in the 'subject' field of an AdverseEvent paramsWithID.subject = paramsWithID.patient; delete paramsWithID.patient; - // Only add study to parameters if it has been specified - return { + + // If there are research study resources, create a parameters object for each call to be made + const newStudyIds = allResearchStudyResources.map((rs) => rs.id).join(','); + const studyIdsForCurrentPatient = `${this.study}${this.study && newStudyIds ? ',' : ''}${newStudyIds}`; + + // Only add study to parameters if it has been specified or was included from context + const obj = { ...paramsWithID, - ...(this.study && { study: this.study }), + ...(studyIdsForCurrentPatient && { study: studyIdsForCurrentPatient }), }; + return obj; } } diff --git a/src/helpers/contextUtils.js b/src/helpers/contextUtils.js index 4a6c6abd..b970c681 100644 --- a/src/helpers/contextUtils.js +++ b/src/helpers/contextUtils.js @@ -62,9 +62,20 @@ function getEncountersFromContext(context) { return encounterResourcesInContext; } +function getResearchStudiesFromContext(context) { + logger.debug('Getting ResearchStudy resources from context'); + const researchStudyResourcesInContext = getBundleResourcesByType(context, 'ResearchStudy', {}, false); + if (researchStudyResourcesInContext.length === 0) { + throw Error('Could not find any ResearchStudy resources in context; ensure that a ClinicalTrialInformationExtractor or ResearchStudyExtractor is used earlier in your extraction configuration'); + } + logger.debug(`ResearchStudy resources found in context. Found ${researchStudyResourcesInContext.length} ResearchStudy resources.`); + return researchStudyResourcesInContext; +} + module.exports = { getConditionEntriesFromContext, getConditionsFromContext, getEncountersFromContext, getPatientFromContext, + getResearchStudiesFromContext, }; diff --git a/test/extractors/FHIRAdverseEventExtractor.test.js b/test/extractors/FHIRAdverseEventExtractor.test.js index 6a13ba27..b502635b 100644 --- a/test/extractors/FHIRAdverseEventExtractor.test.js +++ b/test/extractors/FHIRAdverseEventExtractor.test.js @@ -15,6 +15,28 @@ const MOCK_CONTEXT = { }, ], }; +const researchStudyResource = { + resourceType: 'ResearchStudy', + id: 'ResearchStudyExample01', +}; +const MOCK_CONTEXT_WITH_RESEARCH_STUDY = { + resourceType: 'Bundle', + type: 'collection', + entry: [ + { + fullUrl: 'context-url-1', + resource: { resourceType: 'Patient', id: MOCK_MRN }, + }, + { + fullUrl: 'context-url-2', + resource: researchStudyResource, + }, + { + fullUrl: 'context-url-3', + resource: { ...researchStudyResource, id: 'ResearchStudyExample02' }, + }, + ], +}; // Construct extractor and create spies for mocking responses const extractor = new FHIRAdverseEventExtractor({ baseFhirUrl: MOCK_URL, requestHeaders: MOCK_HEADERS }); @@ -40,6 +62,12 @@ describe('FHIRAdverseEventExtractor', () => { expect(params).not.toHaveProperty('study'); }); + test('should add study id for all ResearchStudy resources that are in context', async () => { + const params = await extractor.parametrizeArgsForFHIRModule({ context: MOCK_CONTEXT_WITH_RESEARCH_STUDY }); + expect(params).toHaveProperty('study'); + expect(params.study).toEqual(`${researchStudyResource.id},ResearchStudyExample02`); + }); + describe('pass in optional study parameter', () => { test('should add study when set to param values', async () => { const params = await extractorWithStudy.parametrizeArgsForFHIRModule({ context: MOCK_CONTEXT }); @@ -51,6 +79,12 @@ describe('FHIRAdverseEventExtractor', () => { const params = await extractorWithStudy.parametrizeArgsForFHIRModule({ context: MOCK_CONTEXT }); expect(params).not.toHaveProperty('patient'); }); + + test('should add study from study parameter and from context', async () => { + const params = await extractorWithStudy.parametrizeArgsForFHIRModule({ context: MOCK_CONTEXT_WITH_RESEARCH_STUDY }); + expect(params).toHaveProperty('study'); + expect(params.study).toEqual(`${extractorWithStudy.study},${researchStudyResource.id},ResearchStudyExample02`); + }); }); }); }); diff --git a/test/helpers/contextUtils.test.js b/test/helpers/contextUtils.test.js index 3b468bbc..7440449c 100644 --- a/test/helpers/contextUtils.test.js +++ b/test/helpers/contextUtils.test.js @@ -1,6 +1,10 @@ -const { getConditionEntriesFromContext, getConditionsFromContext, getEncountersFromContext, getPatientFromContext } = require('../../src/helpers/contextUtils'); - -const MOCK_PATIENT_MRN = '123'; +const { + getConditionEntriesFromContext, + getConditionsFromContext, + getEncountersFromContext, + getPatientFromContext, + getResearchStudiesFromContext, +} = require('../../src/helpers/contextUtils'); describe('getPatientFromContext', () => { const patientResource = { @@ -124,7 +128,39 @@ describe('getEncountersFromContext', () => { }); test('Should throw an error if there are no encounters in context', () => { - expect(() => getEncountersFromContext(MOCK_PATIENT_MRN, {})) + expect(() => getEncountersFromContext({})) .toThrow('Could not find any encounter resources in context; ensure that an EncounterExtractor is used earlier in your extraction configuration'); }); }); + +describe('getResearchStudyFromContext', () => { + const researchStudyResource = { + resourceType: 'ResearchStudy', + id: 'ResearchStudyExample01', + }; + const researchStudyContext = { + resourceType: 'Bundle', + type: 'collection', + entry: [ + { + fullUrl: 'context-url-1', + resource: researchStudyResource, + }, + { + fullUrl: 'context-url-2', + resource: { ...researchStudyResource, id: 'ResearchStudyExample02' }, + }, + ], + }; + + test('Should return all ResearchStudy resources in context', () => { + const researchStudyResources = getResearchStudiesFromContext(researchStudyContext); + expect(researchStudyResources).toHaveLength(2); + expect(researchStudyResources[0]).toEqual(researchStudyResource); + }); + + test('Should throw an error if there are no research studies in context', () => { + expect(() => getResearchStudiesFromContext({})) + .toThrow('Could not find any ResearchStudy resources in context; ensure that a ClinicalTrialInformationExtractor or ResearchStudyExtractor is used earlier in your extraction configuration'); + }); +});