mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-27 16:56:07 +00:00
4360 bulk export questionnaireresponses should get picked when author is not empty (#4361)
* added failing test * implemented solution * added more tests * added changelog * changed the implementation, now extended to get all the patient based search params for a given resource instead of 2 in a fixed list of resources * added test for patient bulk export for resources not in patient compartment, fixed implementation to pass test Co-authored-by: Steven Li <steven@smilecdr.com>
This commit is contained in:
parent
360f32f3e4
commit
29ebb950e8
@ -59,7 +59,7 @@ public class SearchParameterUtil {
|
|||||||
* Given the resource type, fetch its patient-based search parameter name
|
* Given the resource type, fetch its patient-based search parameter name
|
||||||
* 1. Attempt to find one called 'patient'
|
* 1. Attempt to find one called 'patient'
|
||||||
* 2. If that fails, find one called 'subject'
|
* 2. If that fails, find one called 'subject'
|
||||||
* 3. If that fails, find find by Patient Compartment.
|
* 3. If that fails, find one by Patient Compartment.
|
||||||
* 3.1 If that returns >1 result, throw an error
|
* 3.1 If that returns >1 result, throw an error
|
||||||
* 3.2 If that returns 1 result, return it
|
* 3.2 If that returns 1 result, return it
|
||||||
*/
|
*/
|
||||||
@ -76,6 +76,29 @@ public class SearchParameterUtil {
|
|||||||
return Optional.ofNullable(myPatientSearchParam);
|
return Optional.ofNullable(myPatientSearchParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the resource type, fetch all its patient-based search parameter name that's available
|
||||||
|
*/
|
||||||
|
public static Set<String> getPatientSearchParamsForResourceType(FhirContext theFhirContext, String theResourceType) {
|
||||||
|
RuntimeResourceDefinition runtimeResourceDefinition = theFhirContext.getResourceDefinition(theResourceType);
|
||||||
|
|
||||||
|
List<RuntimeSearchParam> searchParams = new ArrayList<>(runtimeResourceDefinition.getSearchParamsForCompartmentName("Patient"));
|
||||||
|
// add patient search parameter for resources that's not in the compartment
|
||||||
|
RuntimeSearchParam myPatientSearchParam = runtimeResourceDefinition.getSearchParam("patient");
|
||||||
|
if (myPatientSearchParam != null) {
|
||||||
|
searchParams.add(myPatientSearchParam);
|
||||||
|
}
|
||||||
|
RuntimeSearchParam mySubjectSearchParam = runtimeResourceDefinition.getSearchParam("subject");
|
||||||
|
if (mySubjectSearchParam != null) {
|
||||||
|
searchParams.add(mySubjectSearchParam);
|
||||||
|
}
|
||||||
|
if (searchParams == null || searchParams.size() == 0) {
|
||||||
|
String errorMessage = String.format("Resource type [%s] is not eligible for this type of export, as it contains no Patient compartment, and no `patient` or `subject` search parameter", runtimeResourceDefinition.getId());
|
||||||
|
throw new IllegalArgumentException(Msg.code(2222) + errorMessage);
|
||||||
|
}
|
||||||
|
// deduplicate list of searchParams and get their names
|
||||||
|
return searchParams.stream().map(RuntimeSearchParam::getName).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search the resource definition for a compartment named 'patient' and return its related Search Parameter.
|
* Search the resource definition for a compartment named 'patient' and return its related Search Parameter.
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 4360
|
||||||
|
title: "Previously, Patient Bulk Export on certain resources with reference to patient only in author or performer did not get exported.
|
||||||
|
This has been fixed."
|
@ -146,9 +146,10 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
|||||||
throw new IllegalStateException(Msg.code(797) + errorMessage);
|
throw new IllegalStateException(Msg.code(797) + errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParams);
|
Set<String> patientSearchParams = SearchParameterUtil.getPatientSearchParamsForResourceType(myContext, theParams.getResourceType());
|
||||||
String patientSearchParam = getPatientSearchParamForCurrentResourceType(theParams.getResourceType()).getName();
|
|
||||||
|
|
||||||
|
for (String patientSearchParam : patientSearchParams) {
|
||||||
|
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParams);
|
||||||
for (SearchParameterMap map : maps) {
|
for (SearchParameterMap map : maps) {
|
||||||
//Ensure users did not monkey with the patient compartment search parameter.
|
//Ensure users did not monkey with the patient compartment search parameter.
|
||||||
validateSearchParametersForPatient(map, theParams);
|
validateSearchParametersForPatient(map, theParams);
|
||||||
@ -163,6 +164,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
|||||||
pids.add(resultIterator.next());
|
pids.add(resultIterator.next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return pids;
|
return pids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,19 +13,25 @@ import com.google.common.collect.Sets;
|
|||||||
import org.apache.commons.io.LineIterator;
|
import org.apache.commons.io.LineIterator;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.Basic;
|
||||||
import org.hl7.fhir.r4.model.Binary;
|
import org.hl7.fhir.r4.model.Binary;
|
||||||
|
import org.hl7.fhir.r4.model.CarePlan;
|
||||||
import org.hl7.fhir.r4.model.Device;
|
import org.hl7.fhir.r4.model.Device;
|
||||||
|
import org.hl7.fhir.r4.model.DocumentReference;
|
||||||
import org.hl7.fhir.r4.model.Encounter;
|
import org.hl7.fhir.r4.model.Encounter;
|
||||||
import org.hl7.fhir.r4.model.Enumerations;
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
import org.hl7.fhir.r4.model.Group;
|
import org.hl7.fhir.r4.model.Group;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.hl7.fhir.r4.model.Location;
|
import org.hl7.fhir.r4.model.Location;
|
||||||
|
import org.hl7.fhir.r4.model.MedicationAdministration;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
import org.hl7.fhir.r4.model.Organization;
|
import org.hl7.fhir.r4.model.Organization;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.hl7.fhir.r4.model.Practitioner;
|
import org.hl7.fhir.r4.model.Practitioner;
|
||||||
import org.hl7.fhir.r4.model.Provenance;
|
import org.hl7.fhir.r4.model.Provenance;
|
||||||
|
import org.hl7.fhir.r4.model.QuestionnaireResponse;
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
|
import org.hl7.fhir.r4.model.ServiceRequest;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -460,6 +466,113 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test {
|
|||||||
verifyBulkExportResults(options, List.of("Patient/P1", obsId, provId, devId, devId2), List.of("Patient/P2", provId2, devId3));
|
verifyBulkExportResults(options, List.of("Patient/P1", obsId, provId, devId, devId2), List.of("Patient/P2", provId2, devId3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatientBulkExportWithReferenceToAuthor_ShouldShowUp() {
|
||||||
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
|
// Create some resources
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P1");
|
||||||
|
patient.setActive(true);
|
||||||
|
myClient.update().resource(patient).execute();
|
||||||
|
|
||||||
|
Basic basic = new Basic();
|
||||||
|
basic.setAuthor(new Reference("Patient/P1"));
|
||||||
|
String basicId = myClient.create().resource(basic).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
DocumentReference documentReference = new DocumentReference();
|
||||||
|
documentReference.setStatus(Enumerations.DocumentReferenceStatus.CURRENT);
|
||||||
|
documentReference.addAuthor(new Reference("Patient/P1"));
|
||||||
|
String docRefId = myClient.create().resource(documentReference).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
QuestionnaireResponse questionnaireResponseSub = new QuestionnaireResponse();
|
||||||
|
questionnaireResponseSub.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
|
||||||
|
questionnaireResponseSub.setSubject(new Reference("Patient/P1"));
|
||||||
|
String questRespSubId = myClient.create().resource(questionnaireResponseSub).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
QuestionnaireResponse questionnaireResponseAuth = new QuestionnaireResponse();
|
||||||
|
questionnaireResponseAuth.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
|
||||||
|
questionnaireResponseAuth.setAuthor(new Reference("Patient/P1"));
|
||||||
|
String questRespAuthId = myClient.create().resource(questionnaireResponseAuth).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
// set the export options
|
||||||
|
BulkDataExportOptions options = new BulkDataExportOptions();
|
||||||
|
options.setResourceTypes(Sets.newHashSet("Patient", "Basic", "DocumentReference", "QuestionnaireResponse"));
|
||||||
|
options.setExportStyle(BulkDataExportOptions.ExportStyle.PATIENT);
|
||||||
|
options.setOutputFormat(Constants.CT_FHIR_NDJSON);
|
||||||
|
verifyBulkExportResults(options, List.of("Patient/P1", basicId, docRefId, questRespAuthId, questRespSubId), Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatientBulkExportWithReferenceToPerformer_ShouldShowUp() {
|
||||||
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
|
// Create some resources
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P1");
|
||||||
|
patient.setActive(true);
|
||||||
|
myClient.update().resource(patient).execute();
|
||||||
|
|
||||||
|
CarePlan carePlan = new CarePlan();
|
||||||
|
carePlan.setStatus(CarePlan.CarePlanStatus.COMPLETED);
|
||||||
|
CarePlan.CarePlanActivityComponent carePlanActivityComponent = new CarePlan.CarePlanActivityComponent();
|
||||||
|
CarePlan.CarePlanActivityDetailComponent carePlanActivityDetailComponent = new CarePlan.CarePlanActivityDetailComponent();
|
||||||
|
carePlanActivityDetailComponent.addPerformer(new Reference("Patient/P1"));
|
||||||
|
carePlanActivityComponent.setDetail(carePlanActivityDetailComponent);
|
||||||
|
carePlan.addActivity(carePlanActivityComponent);
|
||||||
|
String carePlanId = myClient.create().resource(carePlan).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
MedicationAdministration medicationAdministration = new MedicationAdministration();
|
||||||
|
medicationAdministration.setStatus(MedicationAdministration.MedicationAdministrationStatus.COMPLETED);
|
||||||
|
MedicationAdministration.MedicationAdministrationPerformerComponent medicationAdministrationPerformerComponent = new MedicationAdministration.MedicationAdministrationPerformerComponent();
|
||||||
|
medicationAdministrationPerformerComponent.setActor(new Reference("Patient/P1"));
|
||||||
|
medicationAdministration.addPerformer(medicationAdministrationPerformerComponent);
|
||||||
|
String medAdminId = myClient.create().resource(medicationAdministration).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
ServiceRequest serviceRequest = new ServiceRequest();
|
||||||
|
serviceRequest.setStatus(ServiceRequest.ServiceRequestStatus.COMPLETED);
|
||||||
|
serviceRequest.addPerformer(new Reference("Patient/P1"));
|
||||||
|
String sevReqId = myClient.create().resource(serviceRequest).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
Observation observationSub = new Observation();
|
||||||
|
observationSub.setStatus(Observation.ObservationStatus.AMENDED);
|
||||||
|
observationSub.setSubject(new Reference("Patient/P1"));
|
||||||
|
String obsSubId = myClient.create().resource(observationSub).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
Observation observationPer = new Observation();
|
||||||
|
observationPer.setStatus(Observation.ObservationStatus.AMENDED);
|
||||||
|
observationPer.addPerformer(new Reference("Patient/P1"));
|
||||||
|
String obsPerId = myClient.create().resource(observationPer).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
// set the export options
|
||||||
|
BulkDataExportOptions options = new BulkDataExportOptions();
|
||||||
|
options.setResourceTypes(Sets.newHashSet("Patient", "Observation", "CarePlan", "MedicationAdministration", "ServiceRequest"));
|
||||||
|
options.setExportStyle(BulkDataExportOptions.ExportStyle.PATIENT);
|
||||||
|
options.setOutputFormat(Constants.CT_FHIR_NDJSON);
|
||||||
|
verifyBulkExportResults(options, List.of("Patient/P1", carePlanId, medAdminId, sevReqId, obsSubId, obsPerId), Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatientBulkExportWithResourceNotInCompartment_ShouldShowUp() {
|
||||||
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
|
// Create some resources
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("P1");
|
||||||
|
patient.setActive(true);
|
||||||
|
myClient.update().resource(patient).execute();
|
||||||
|
|
||||||
|
Device device = new Device();
|
||||||
|
device.setStatus(Device.FHIRDeviceStatus.ACTIVE);
|
||||||
|
device.setPatient(new Reference("Patient/P1"));
|
||||||
|
String deviceId = myClient.create().resource(device).execute().getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
|
|
||||||
|
// set the export options
|
||||||
|
BulkDataExportOptions options = new BulkDataExportOptions();
|
||||||
|
options.setResourceTypes(Sets.newHashSet("Patient", "Device"));
|
||||||
|
options.setExportStyle(BulkDataExportOptions.ExportStyle.PATIENT);
|
||||||
|
options.setOutputFormat(Constants.CT_FHIR_NDJSON);
|
||||||
|
verifyBulkExportResults(options, List.of("Patient/P1", deviceId), Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyBulkExportResults(BulkDataExportOptions theOptions, List<String> theContainedList, List<String> theExcludedList) {
|
private void verifyBulkExportResults(BulkDataExportOptions theOptions, List<String> theContainedList, List<String> theExcludedList) {
|
||||||
Batch2JobStartResponse startResponse = myJobRunner.startNewJob(BulkExportUtils.createBulkExportJobParametersFromExportOptions(theOptions));
|
Batch2JobStartResponse startResponse = myJobRunner.startNewJob(BulkExportUtils.createBulkExportJobParametersFromExportOptions(theOptions));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user