diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ReferenceClientParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ReferenceClientParam.java index 49fdaa6b060..6b8176b0b76 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ReferenceClientParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/ReferenceClientParam.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.rest.gclient; +import java.util.Collection; + import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.primitive.IdDt; @@ -57,6 +59,17 @@ public class ReferenceClientParam extends BaseClientParam implements IParam { return new StringCriterion(getParamName(), theId); } + /** + * Match the referenced resource if the resource has ANY of the given IDs + * (this is an OR search, not an AND search), (this can be the logical ID or + * the absolute URL of the resource). Note that to specify an AND search, + * simply add a subsequent {@link IQuery#where(ICriterion) where} criteria + * with the same parameter. + */ + public ICriterion hasAnyOf(Collection theIds) { + return new StringCriterion(getParamName(), theIds); + } + private static class ReferenceChainCriterion implements ICriterion, ICriterionInternal { private String myParamName; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java index 2492a4be1bd..6480b67654d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.rest.gclient; import static org.apache.commons.lang3.StringUtils.isBlank; +import java.util.Collection; import java.util.List; import org.apache.commons.lang3.StringUtils; @@ -47,7 +48,7 @@ class StringCriterion implements ICriterion, ICriterionInte myValue = ParameterUtil.escapeWithDefault(theValue); } - public StringCriterion(String theName, List theValue) { + public StringCriterion(String theName, Collection theValue) { myName=theName; StringBuilder b = new StringBuilder(); for (String next : theValue) { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java index e23cea035cd..0dd2ac54000 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java @@ -26,8 +26,11 @@ import java.net.Socket; import java.net.SocketTimeoutException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -47,6 +50,7 @@ import org.junit.Ignore; import org.junit.Test; import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; @@ -1563,6 +1567,43 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test { assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart()); } + + @Test + public void testSearchByReferenceIds() { + Organization o1 = new Organization(); + o1.setName("testSearchByResourceChainName01"); + IdDt o1id = (IdDt) ourClient.create().resource(o1).execute().getId().toUnqualifiedVersionless(); + Organization o2 = new Organization(); + o2.setName("testSearchByResourceChainName02"); + IdDt o2id = (IdDt) ourClient.create().resource(o2).execute().getId().toUnqualifiedVersionless(); + + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testSearchByReferenceIds01"); + p1.addName().addFamily("testSearchByReferenceIdsFamily01").addGiven("testSearchByReferenceIdsGiven01"); + p1.setManagingOrganization(new ResourceReferenceDt(o1id.toUnqualifiedVersionless())); + IdDt p1Id = (IdDt) ourClient.create().resource(p1).execute().getId(); + + Patient p2 = new Patient(); + p2.addIdentifier().setSystem("urn:system").setValue("testSearchByReferenceIds02"); + p2.addName().addFamily("testSearchByReferenceIdsFamily02").addGiven("testSearchByReferenceIdsGiven02"); + p2.setManagingOrganization(new ResourceReferenceDt(o2id.toUnqualifiedVersionless())); + IdDt p2Id = (IdDt) ourClient.create().resource(p2).execute().getId(); + + //@formatter:off + Bundle actual = ourClient.search() + .forResource(Patient.class) + .where(Patient.ORGANIZATION.hasAnyOf(Arrays.asList(o1id.getIdPart(), o2id.getIdPart()))) + .encodedJson().prettyPrint().execute(); + //@formatter:on + Set expectedIds = new HashSet(); + expectedIds.add(p1Id.getIdPart()); + expectedIds.add(p2Id.getIdPart()); + Set actualIds = new HashSet(); + for (BundleEntry ele : actual.getEntries()) { + actualIds.add(ele.getResource().getId().getIdPart()); + } + assertEquals("Expects to retrieve the 2 patients which reference the two different organizations", expectedIds, actualIds); + } @Test public void testSearchLastUpdatedParamRp() throws InterruptedException { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java index acd3e20be6b..b07b76a279e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java @@ -61,8 +61,6 @@ import org.junit.Test; import com.google.common.collect.Lists; -import ca.uhn.fhir.jpa.dao.SearchParameterMap; -import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum; import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.parser.IParser; @@ -2254,6 +2252,43 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { assertEquals(p1Id.getIdPart(), actual.getEntry().get(0).getResource().getIdElement().getIdPart()); } + + @Test + public void testSearchByReferenceIds() { + Organization o1 = new Organization(); + o1.setName("testSearchByResourceChainName01"); + IIdType o1id = ourClient.create().resource(o1).execute().getId().toUnqualifiedVersionless(); + Organization o2 = new Organization(); + o2.setName("testSearchByResourceChainName02"); + IIdType o2id = ourClient.create().resource(o2).execute().getId().toUnqualifiedVersionless(); + + Patient p1 = new Patient(); + p1.addIdentifier().setSystem("urn:system").setValue("testSearchByReferenceIds01"); + p1.addName().addFamily("testSearchByReferenceIdsFamily01").addGiven("testSearchByReferenceIdsGiven01"); + p1.setManagingOrganization(new Reference(o1id.toUnqualifiedVersionless())); + IIdType p1Id = ourClient.create().resource(p1).execute().getId(); + + Patient p2 = new Patient(); + p2.addIdentifier().setSystem("urn:system").setValue("testSearchByReferenceIds02"); + p2.addName().addFamily("testSearchByReferenceIdsFamily02").addGiven("testSearchByReferenceIdsGiven02"); + p2.setManagingOrganization(new Reference(o2id.toUnqualifiedVersionless())); + IIdType p2Id = ourClient.create().resource(p2).execute().getId(); + + //@formatter:off + Bundle actual = ourClient.search() + .forResource(Patient.class) + .where(Patient.ORGANIZATION.hasAnyOf(Arrays.asList(o1id.getIdPart(), o2id.getIdPart()))) + .encodedJson().prettyPrint().returnBundle(Bundle.class).execute(); + //@formatter:on + Set expectedIds = new HashSet(); + expectedIds.add(p1Id.getIdPart()); + expectedIds.add(p2Id.getIdPart()); + Set actualIds = new HashSet(); + for (BundleEntryComponent ele : actual.getEntry()) { + actualIds.add(ele.getResource().getIdElement().getIdPart()); + } + assertEquals("Expects to retrieve the 2 patients which reference the two different organizations", expectedIds, actualIds); + } @Test public void testSearchLastUpdatedParamRp() throws InterruptedException {