Group bulk export _since parameter issue (#4389)
* Test + fix * javadoc
This commit is contained in:
parent
e4ad370314
commit
51797c3c1e
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 4387
|
||||||
|
title: "Previously, when use group bulk export, if the group was referenced to a patient resource and the patient has not been updated after the _since parameter of the bulk export, none of their data/sub-resources comes through even if the sub-resources were qualified (By qualified, I mean the sub-resources were upadted/created after _since parameter).
|
||||||
|
Now, this issue has been fixed."
|
|
@ -149,7 +149,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
Set<String> patientSearchParams = SearchParameterUtil.getPatientSearchParamsForResourceType(myContext, theParams.getResourceType());
|
Set<String> patientSearchParams = SearchParameterUtil.getPatientSearchParamsForResourceType(myContext, theParams.getResourceType());
|
||||||
|
|
||||||
for (String patientSearchParam : patientSearchParams) {
|
for (String patientSearchParam : patientSearchParams) {
|
||||||
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParams);
|
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParams, false);
|
||||||
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);
|
||||||
|
@ -196,7 +196,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
private LinkedHashSet<JpaPid> getPidsForSystemStyleExport(ExportPIDIteratorParameters theParams, String theJobId, RuntimeResourceDefinition theDef) {
|
private LinkedHashSet<JpaPid> getPidsForSystemStyleExport(ExportPIDIteratorParameters theParams, String theJobId, RuntimeResourceDefinition theDef) {
|
||||||
LinkedHashSet<JpaPid> pids = new LinkedHashSet<>();
|
LinkedHashSet<JpaPid> pids = new LinkedHashSet<>();
|
||||||
// System
|
// System
|
||||||
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(theDef, theParams);
|
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(theDef, theParams, true);
|
||||||
ISearchBuilder<JpaPid> searchBuilder = getSearchBuilderForResourceType(theParams.getResourceType());
|
ISearchBuilder<JpaPid> searchBuilder = getSearchBuilderForResourceType(theParams.getResourceType());
|
||||||
|
|
||||||
for (SearchParameterMap map : maps) {
|
for (SearchParameterMap map : maps) {
|
||||||
|
@ -311,7 +311,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
* possibly expanded by MDM, and don't have to go and fetch other resource DAOs.
|
* possibly expanded by MDM, and don't have to go and fetch other resource DAOs.
|
||||||
*/
|
*/
|
||||||
private LinkedHashSet<JpaPid> getExpandedPatientList(ExportPIDIteratorParameters theParameters) {
|
private LinkedHashSet<JpaPid> getExpandedPatientList(ExportPIDIteratorParameters theParameters) {
|
||||||
List<JpaPid> members = getMembersFromGroupWithFilter(theParameters);
|
List<JpaPid> members = getMembersFromGroupWithFilter(theParameters, true);
|
||||||
List<IIdType> ids = members.stream().map(member -> new IdDt("Patient/" + member)).collect(Collectors.toList());
|
List<IIdType> ids = members.stream().map(member -> new IdDt("Patient/" + member)).collect(Collectors.toList());
|
||||||
ourLog.info("While extracting patients from a group, we found {} patients.", ids.size());
|
ourLog.info("While extracting patients from a group, we found {} patients.", ids.size());
|
||||||
ourLog.info("Found patients: {}", ids.stream().map(id -> id.getValue()).collect(Collectors.joining(", ")));
|
ourLog.info("Found patients: {}", ids.stream().map(id -> id.getValue()).collect(Collectors.joining(", ")));
|
||||||
|
@ -339,12 +339,11 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
*
|
*
|
||||||
* @return A list of strings representing the Patient IDs of the members (e.g. ["P1", "P2", "P3"]
|
* @return A list of strings representing the Patient IDs of the members (e.g. ["P1", "P2", "P3"]
|
||||||
*/
|
*/
|
||||||
private List<JpaPid> getMembersFromGroupWithFilter(ExportPIDIteratorParameters theParameters) {
|
private List<JpaPid> getMembersFromGroupWithFilter(ExportPIDIteratorParameters theParameters, boolean theConsiderSince) {
|
||||||
RuntimeResourceDefinition def = myContext.getResourceDefinition("Patient");
|
RuntimeResourceDefinition def = myContext.getResourceDefinition("Patient");
|
||||||
List<String> pids = new ArrayList<>();
|
|
||||||
List<JpaPid> resPids = new ArrayList<>();
|
List<JpaPid> resPids = new ArrayList<>();
|
||||||
|
|
||||||
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParameters);
|
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(def, theParameters, theConsiderSince);
|
||||||
|
|
||||||
maps.forEach(map -> addMembershipToGroupClause(map, theParameters.getGroupId()));
|
maps.forEach(map -> addMembershipToGroupClause(map, theParameters.getGroupId()));
|
||||||
|
|
||||||
|
@ -432,7 +431,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
|
|
||||||
//Build SP map
|
//Build SP map
|
||||||
//First, inject the _typeFilters and _since from the export job
|
//First, inject the _typeFilters and _since from the export job
|
||||||
List<SearchParameterMap> expandedSpMaps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(theDef, theParams);
|
List<SearchParameterMap> expandedSpMaps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(theDef, theParams, true);
|
||||||
for (SearchParameterMap expandedSpMap : expandedSpMaps) {
|
for (SearchParameterMap expandedSpMap : expandedSpMaps) {
|
||||||
|
|
||||||
//Since we are in a bulk job, we have to ensure the user didn't jam in a patient search param, since we need to manually set that.
|
//Since we are in a bulk job, we have to ensure the user didn't jam in a patient search param, since we need to manually set that.
|
||||||
|
@ -520,7 +519,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
||||||
|
|
||||||
//Now manually add the members of the group (its possible even with mdm expansion that some members dont have MDM matches,
|
//Now manually add the members of the group (its possible even with mdm expansion that some members dont have MDM matches,
|
||||||
//so would be otherwise skipped
|
//so would be otherwise skipped
|
||||||
List<JpaPid> membersFromGroupWithFilter = getMembersFromGroupWithFilter(theParams);
|
List<JpaPid> membersFromGroupWithFilter = getMembersFromGroupWithFilter(theParams, false);
|
||||||
ourLog.debug("Group with ID [{}] has been expanded to: {}", theParams.getGroupId(), membersFromGroupWithFilter);
|
ourLog.debug("Group with ID [{}] has been expanded to: {}", theParams.getGroupId(), membersFromGroupWithFilter);
|
||||||
expandedIds.addAll(membersFromGroupWithFilter);
|
expandedIds.addAll(membersFromGroupWithFilter);
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ public class JpaBulkExportProcessorTest {
|
||||||
// when
|
// when
|
||||||
when(myDaoConfig.getIndexMissingFields())
|
when(myDaoConfig.getIndexMissingFields())
|
||||||
.thenReturn(DaoConfig.IndexEnabledEnum.ENABLED);
|
.thenReturn(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters)))
|
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters), any(boolean.class)))
|
||||||
.thenReturn(maps);
|
.thenReturn(maps);
|
||||||
// from getSearchBuilderForLocalResourceType
|
// from getSearchBuilderForLocalResourceType
|
||||||
when(myDaoRegistry.getResourceDao(anyString()))
|
when(myDaoRegistry.getResourceDao(anyString()))
|
||||||
|
@ -259,7 +259,7 @@ public class JpaBulkExportProcessorTest {
|
||||||
ISearchBuilder searchBuilder = mock(ISearchBuilder.class);
|
ISearchBuilder searchBuilder = mock(ISearchBuilder.class);
|
||||||
|
|
||||||
// from getMembersFromGroupWithFilter
|
// from getMembersFromGroupWithFilter
|
||||||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters)))
|
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters), any(boolean.class)))
|
||||||
.thenReturn(Collections.singletonList(new SearchParameterMap()));
|
.thenReturn(Collections.singletonList(new SearchParameterMap()));
|
||||||
// from getSearchBuilderForLocalResourceType
|
// from getSearchBuilderForLocalResourceType
|
||||||
when(myDaoRegistry.getResourceDao(not(eq("Group"))))
|
when(myDaoRegistry.getResourceDao(not(eq("Group"))))
|
||||||
|
@ -355,7 +355,7 @@ public class JpaBulkExportProcessorTest {
|
||||||
.thenReturn(groupResource);
|
.thenReturn(groupResource);
|
||||||
when(myIdHelperService.getPidOrNull(any(), eq(groupResource)))
|
when(myIdHelperService.getPidOrNull(any(), eq(groupResource)))
|
||||||
.thenReturn(groupId);
|
.thenReturn(groupId);
|
||||||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters)))
|
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters), any(boolean.class)))
|
||||||
.thenReturn(Collections.singletonList(new SearchParameterMap()));
|
.thenReturn(Collections.singletonList(new SearchParameterMap()));
|
||||||
when(myDaoRegistry.getResourceDao(not(eq("Group"))))
|
when(myDaoRegistry.getResourceDao(not(eq("Group"))))
|
||||||
.thenReturn(mockDao);
|
.thenReturn(mockDao);
|
||||||
|
@ -412,7 +412,8 @@ public class JpaBulkExportProcessorTest {
|
||||||
// when
|
// when
|
||||||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(
|
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(
|
||||||
any(RuntimeResourceDefinition.class),
|
any(RuntimeResourceDefinition.class),
|
||||||
any(ExportPIDIteratorParameters.class)
|
any(ExportPIDIteratorParameters.class),
|
||||||
|
any(boolean.class)
|
||||||
)).thenReturn(Collections.singletonList(new SearchParameterMap()));
|
)).thenReturn(Collections.singletonList(new SearchParameterMap()));
|
||||||
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
||||||
.thenReturn(dao);
|
.thenReturn(dao);
|
||||||
|
|
|
@ -22,6 +22,7 @@ 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.InstantType;
|
||||||
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.MedicationAdministration;
|
||||||
import org.hl7.fhir.r4.model.Observation;
|
import org.hl7.fhir.r4.model.Observation;
|
||||||
|
@ -43,6 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -469,6 +471,46 @@ 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 testGroupBulkExport_QualifiedSubResourcesOfUnqualifiedPatientShouldShowUp() throws InterruptedException {
|
||||||
|
|
||||||
|
// Patient with lastUpdated before _since
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("A");
|
||||||
|
myClient.update().resource(patient).execute();
|
||||||
|
|
||||||
|
// Sleep for 1 sec
|
||||||
|
ourLog.info("Patient lastUpdated: " + InstantType.withCurrentTime().getValueAsString());
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// LastUpdated since now
|
||||||
|
Date timeDate = InstantType.now().getValue();
|
||||||
|
ourLog.info(timeDate.toString());
|
||||||
|
|
||||||
|
// Group references to Patient/A
|
||||||
|
Group group = new Group();
|
||||||
|
group.setId("B");
|
||||||
|
group.addMember().getEntity().setReference("Patient/A");
|
||||||
|
myClient.update().resource(group).execute();
|
||||||
|
|
||||||
|
// Observation references to Patient/A
|
||||||
|
Observation observation = new Observation();
|
||||||
|
observation.setId("C");
|
||||||
|
observation.setSubject(new Reference("Patient/A"));
|
||||||
|
myClient.update().resource(observation).execute();
|
||||||
|
|
||||||
|
// Set the export options
|
||||||
|
BulkDataExportOptions options = new BulkDataExportOptions();
|
||||||
|
options.setResourceTypes(Sets.newHashSet("Patient", "Observation", "Group"));
|
||||||
|
options.setGroupId(new IdType("Group", "B"));
|
||||||
|
options.setFilters(new HashSet<>());
|
||||||
|
options.setExportStyle(BulkDataExportOptions.ExportStyle.GROUP);
|
||||||
|
options.setSince(timeDate);
|
||||||
|
options.setOutputFormat(Constants.CT_FHIR_NDJSON);
|
||||||
|
// Should get the sub-resource (Observation) even the patient hasn't been updated after the _since param
|
||||||
|
verifyBulkExportResults(options, List.of("Observation/C", "Group/B"), List.of("Patient/A"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPatientBulkExportWithReferenceToAuthor_ShouldShowUp() {
|
public void testPatientBulkExportWithReferenceToAuthor_ShouldShowUp() {
|
||||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||||
|
|
|
@ -47,7 +47,12 @@ public class BulkExportHelperService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
|
||||||
public List<SearchParameterMap> createSearchParameterMapsForResourceType(RuntimeResourceDefinition theDef, ExportPIDIteratorParameters theParams) {
|
/**
|
||||||
|
* Given the parameters, create the search parameter map based on type filters and the _since parameter.
|
||||||
|
*
|
||||||
|
* The input boolean theConsiderSince determines whether to consider the lastUpdated date in the search parameter map.
|
||||||
|
*/
|
||||||
|
public List<SearchParameterMap> createSearchParameterMapsForResourceType(RuntimeResourceDefinition theDef, ExportPIDIteratorParameters theParams, boolean theConsiderSince) {
|
||||||
String resourceType = theDef.getName();
|
String resourceType = theDef.getName();
|
||||||
List<String> typeFilters = theParams.getFilters();
|
List<String> typeFilters = theParams.getFilters();
|
||||||
List<SearchParameterMap> spMaps = null;
|
List<SearchParameterMap> spMaps = null;
|
||||||
|
@ -63,7 +68,9 @@ public class BulkExportHelperService {
|
||||||
//None of the _typeFilters applied to the current resource type, so just make a simple one.
|
//None of the _typeFilters applied to the current resource type, so just make a simple one.
|
||||||
if (spMaps.isEmpty()) {
|
if (spMaps.isEmpty()) {
|
||||||
SearchParameterMap defaultMap = new SearchParameterMap();
|
SearchParameterMap defaultMap = new SearchParameterMap();
|
||||||
|
if (theConsiderSince) {
|
||||||
enhanceSearchParameterMapWithCommonParameters(defaultMap, theParams.getStartDate());
|
enhanceSearchParameterMapWithCommonParameters(defaultMap, theParams.getStartDate());
|
||||||
|
}
|
||||||
spMaps = Collections.singletonList(defaultMap);
|
spMaps = Collections.singletonList(defaultMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue