Skip to content

Commit 1321fa3

Browse files
joanne-mJoanne MendozaVK-SMILECDRAD1306
authored
6713 support for patient parameter in group export (hapifhir#6753)
* Parse patientIds from reference list * spotless * changes to search parameter map for group export * spotless * minor change * fix test and code * test for group export on id with patient parameter and minor cleanup to JpaBulkExportProcessor * spotless * cleanup * Use ReferenceParam for ID --------- Co-authored-by: Joanne Mendoza <[email protected]> Co-authored-by: Vadim Karantayer <[email protected]> Co-authored-by: ad1306 <[email protected]>
1 parent 2712bde commit 1321fa3

File tree

4 files changed

+96
-32
lines changed

4 files changed

+96
-32
lines changed

hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/bulk/export/svc/JpaBulkExportProcessor.java

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -213,19 +213,19 @@ map, searchRuntime, new SystemRequestDetails(), theParams.getPartitionIdOrAllPar
213213
return pids;
214214
}
215215

216-
private static void filterBySpecificPatient(
216+
private void filterBySpecificPatient(
217217
ExportPIDIteratorParameters theParams,
218218
String resourceType,
219219
String patientSearchParam,
220220
SearchParameterMap map) {
221221
if (resourceType.equalsIgnoreCase("Patient")) {
222222
if (theParams.getPatientIds() != null) {
223-
ReferenceOrListParam referenceOrListParam = getReferenceOrListParam(theParams);
223+
ReferenceOrListParam referenceOrListParam = makeReferenceOrListParam(theParams.getPatientIds());
224224
map.add(PARAM_ID, referenceOrListParam);
225225
}
226226
} else {
227227
if (theParams.getPatientIds() != null) {
228-
ReferenceOrListParam referenceOrListParam = getReferenceOrListParam(theParams);
228+
ReferenceOrListParam referenceOrListParam = makeReferenceOrListParam(theParams.getPatientIds());
229229
map.add(patientSearchParam, referenceOrListParam);
230230
} else {
231231
map.add(patientSearchParam, new ReferenceParam().setMissing(false));
@@ -234,11 +234,9 @@ private static void filterBySpecificPatient(
234234
}
235235

236236
@Nonnull
237-
private static ReferenceOrListParam getReferenceOrListParam(ExportPIDIteratorParameters theParams) {
238-
ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
239-
for (String patientId : theParams.getPatientIds()) {
240-
referenceOrListParam.addOr(new ReferenceParam(patientId));
241-
}
237+
private ReferenceOrListParam makeReferenceOrListParam(@Nonnull List<String> thePatientIds) {
238+
final ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
239+
thePatientIds.forEach(patientId -> referenceOrListParam.addOr(new ReferenceParam(patientId)));
242240
return referenceOrListParam;
243241
}
244242

@@ -443,14 +441,8 @@ private LinkedHashSet<JpaPid> getExpandedPatientList(ExportPIDIteratorParameters
443441
@SuppressWarnings("unchecked")
444442
private List<JpaPid> getMembersFromGroupWithFilter(
445443
ExportPIDIteratorParameters theParameters, boolean theConsiderDateRange) throws IOException {
446-
RuntimeResourceDefinition def = myContext.getResourceDefinition("Patient");
447-
List<JpaPid> resPids = new ArrayList<>();
448-
449-
List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(
450-
def, theParameters, theConsiderDateRange);
451-
452-
maps.forEach(map -> addMembershipToGroupClause(map, theParameters.getGroupId()));
453-
444+
final List<SearchParameterMap> maps = makeSearchParameterMaps(theParameters, theConsiderDateRange);
445+
final List<JpaPid> resPids = new ArrayList<>();
454446
for (SearchParameterMap map : maps) {
455447
ISearchBuilder<JpaPid> searchBuilder = getSearchBuilderForResourceType("Patient");
456448
ourLog.debug(
@@ -472,17 +464,26 @@ private List<JpaPid> getMembersFromGroupWithFilter(
472464
return resPids;
473465
}
474466

475-
/**
476-
* This method takes an {@link SearchParameterMap} and adds a clause to it that will filter the search results to only
477-
* return members of the defined group.
478-
*
479-
* @param theMap the map to add the clause to.
480-
* @param theGroupId the group ID to filter by.
481-
*/
482-
private void addMembershipToGroupClause(SearchParameterMap theMap, String theGroupId) {
483-
HasOrListParam hasOrListParam = new HasOrListParam();
484-
hasOrListParam.addOr(new HasParam("Group", "member", "_id", theGroupId));
485-
theMap.add(PARAM_HAS, hasOrListParam);
467+
@Nonnull
468+
private List<SearchParameterMap> makeSearchParameterMaps(
469+
@Nonnull ExportPIDIteratorParameters theParameters, boolean theConsiderDateRange) {
470+
final RuntimeResourceDefinition def = myContext.getResourceDefinition("Patient");
471+
final List<SearchParameterMap> maps = myBulkExportHelperSvc.createSearchParameterMapsForResourceType(
472+
def, theParameters, theConsiderDateRange);
473+
maps.forEach(map -> {
474+
map.add(PARAM_HAS, makeGroupMemberHasOrListParam(theParameters.getGroupId()));
475+
final List<String> patientIds = theParameters.getPatientIds();
476+
if (patientIds != null && !patientIds.isEmpty()) {
477+
map.add(PARAM_ID, makeReferenceOrListParam(patientIds));
478+
}
479+
});
480+
return maps;
481+
}
482+
483+
@Nonnull
484+
private HasOrListParam makeGroupMemberHasOrListParam(@Nonnull String theGroupId) {
485+
final HasParam hasParam = new HasParam("Group", "member", "_id", theGroupId);
486+
return new HasOrListParam().addOr(hasParam);
486487
}
487488

488489
/**

hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,36 @@ public void testGroupBulkExportWithTypeFilter() {
160160
verifyBulkExportResults(options, Collections.singletonList("Patient/PF"), Collections.singletonList("Patient/PM"));
161161
}
162162

163+
@Test
164+
void testGroupBulkExportWithPatientParameter() {
165+
// setup
166+
// Create some resources
167+
final String patient1Id = "InGroupAndPatientParameter";
168+
final String patient2Id = "InGroupButNotInPatientParameter";
169+
final String patient3Id = "NotInGroupButInPatientParameter";
170+
final String patient4Id = "DoesNotExist";
171+
myClient.update().resource(new Patient().setId(patient1Id)).execute();
172+
myClient.update().resource(new Patient().setId(patient2Id)).execute();
173+
myClient.update().resource(new Patient().setId(patient3Id)).execute();
174+
175+
final Group group = new Group();
176+
group.setId("Group/Group1");
177+
group.addMember().getEntity().setReference("Patient/" + patient1Id);
178+
group.addMember().getEntity().setReference("Patient/" + patient2Id);
179+
myClient.update().resource(group).execute();
180+
181+
// set the export options
182+
final List<String> exportForPatientId = List.of("Patient/" + patient1Id, "Patient/" + patient3Id, "Patient/" + patient4Id);
183+
final BulkExportJobParameters options = new BulkExportJobParameters();
184+
options.setResourceTypes(Sets.newHashSet("Patient"));
185+
options.setGroupId("Group/Group1");
186+
options.setPatientIds(exportForPatientId);
187+
options.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP);
188+
options.setOutputFormat(Constants.CT_FHIR_NDJSON);
189+
// execute & validate
190+
verifyBulkExportResults(options, List.of("Patient/" + patient1Id), List.of("Patient/" + patient2Id, "Patient/" + patient3Id, "Patient/" + patient4Id));
191+
}
192+
163193
@Test
164194
public void testGroupBulkExportWithMissingObservationSearchParams() {
165195
mySearchParameterDao.update(createDisabledObservationPatientSearchParameter(), mySrd);
@@ -1121,11 +1151,9 @@ private JobInstance verifyBulkExportResults(BulkExportJobParameters theOptions,
11211151
}
11221152
}
11231153

1124-
for (String containedString : theContainedList) {
1125-
assertThat(foundIds).as("Didn't find expected ID " + containedString + " in IDS: " + foundIds).contains(containedString);
1126-
}
1127-
for (String excludedString : theExcludedList) {
1128-
assertThat(foundIds).as("Didn't want unexpected ID " + excludedString + " in IDS: " + foundIds).doesNotContain(excludedString);
1154+
assertThat(foundIds).containsAll(theContainedList);
1155+
if(!theExcludedList.isEmpty()) {
1156+
assertThat(foundIds).doesNotContainAnyElementsOf(theExcludedList);
11291157
}
11301158
return jobInstance;
11311159
}

hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersBuilder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import ca.uhn.fhir.util.ArrayUtil;
2626
import ca.uhn.fhir.util.DatatypeUtil;
2727
import org.apache.commons.lang3.StringUtils;
28+
import org.hl7.fhir.instance.model.api.IBaseReference;
2829
import org.hl7.fhir.instance.model.api.IIdType;
2930
import org.hl7.fhir.instance.model.api.IPrimitiveType;
3031

@@ -95,6 +96,16 @@ public BulkExportJobParametersBuilder patientIds(List<IPrimitiveType<String>> th
9596
return this;
9697
}
9798

99+
public BulkExportJobParametersBuilder patientReferences(List<IBaseReference> thePatientReferences) {
100+
myPatientIds = thePatientReferences == null
101+
? null
102+
: thePatientReferences.stream()
103+
.map(IBaseReference::getReferenceElement)
104+
.map(IIdType::getIdPart)
105+
.collect(Collectors.toList());
106+
return this;
107+
}
108+
98109
public BulkExportJobParametersBuilder groupId(IIdType theGroupId) {
99110
myGroupId = DatatypeUtil.toStringValue(theGroupId);
100111
return this;

hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersBuilderTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
import ca.uhn.fhir.model.primitive.StringDt;
77
import ca.uhn.fhir.rest.api.Constants;
88
import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters;
9+
import org.hl7.fhir.instance.model.api.IBaseReference;
910
import org.hl7.fhir.instance.model.api.IPrimitiveType;
1011
import org.hl7.fhir.r4.model.IdType;
12+
import org.hl7.fhir.r4.model.Reference;
1113
import org.junit.jupiter.api.Test;
1214

1315
import java.util.Date;
@@ -127,6 +129,28 @@ void patientIdsWhenNull() {
127129
assertThat(myFixture.build().getPatientIds()).isEmpty();
128130
}
129131

132+
@Test
133+
void patientReferences() {
134+
// Arrange
135+
final List<String> expected = List.of("ID1", "ID2", "ID3");
136+
final List<IBaseReference> patientRefs = expected.stream()
137+
.map(value -> new Reference("Patient/" + value + "/_history/1"))
138+
.map(IBaseReference.class::cast)
139+
.toList();
140+
// Act
141+
myFixture.patientReferences(patientRefs);
142+
// Assert
143+
assertThat(myFixture.build().getPatientIds()).containsAll(expected);
144+
}
145+
146+
@Test
147+
void patientReferencesWhenNull() {
148+
// Act
149+
myFixture.patientReferences(null);
150+
// Assert
151+
assertThat(myFixture.build().getPatientIds()).isEmpty();
152+
}
153+
130154
@Test
131155
void groupId() {
132156
// Arrange

0 commit comments

Comments
 (0)