diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index 124e3668ee1..4e30159e585 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -1676,8 +1676,6 @@ public class SearchBuilder implements ISearchBuilder { Predicate predicate; if ((operation == null) || - (operation == SearchFilterParser.CompareOperation.eq) || - (operation == SearchFilterParser.CompareOperation.co) || (operation == SearchFilterParser.CompareOperation.sw) || (operation == SearchFilterParser.CompareOperation.ew)) { @@ -1685,6 +1683,11 @@ public class SearchBuilder implements ISearchBuilder { Predicate hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash); Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression); predicate = theBuilder.and(hashCode, singleCode); + } else if (operation == SearchFilterParser.CompareOperation.eq) { + Long hash = ResourceIndexedSearchParamString.calculateHashNormalized(myDaoConfig.getModelConfig(), theResourceName, theParamName, normalizedString); + Predicate hashCode = theBuilder.equal(theFrom.get("myHashNormalizedPrefix").as(Long.class), hash); + Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), normalizedString); + predicate = theBuilder.and(hashCode, singleCode); } else if (operation == SearchFilterParser.CompareOperation.ne) { Predicate singleCode = theBuilder.notEqual(theFrom.get("myValueNormalized").as(String.class), likeExpression); predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode); @@ -1701,7 +1704,7 @@ public class SearchBuilder implements ISearchBuilder { Predicate singleCode = theBuilder.lessThanOrEqualTo(theFrom.get("myValueNormalized").as(String.class), likeExpression); predicate = combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, singleCode); } else { - throw new IllegalArgumentException("Unknown operation type: " + operation); + throw new IllegalArgumentException("Don't yet know how to handle operation " + operation + " on a string"); } return predicate; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4FilterTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4FilterTest.java index cfecc19072f..9088233c5f3 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4FilterTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4FilterTest.java @@ -6,15 +6,18 @@ import ca.uhn.fhir.jpa.util.TestUtil; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import org.hamcrest.Matchers; import org.hl7.fhir.r4.model.Patient; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatchers; import java.util.List; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.emptyString; import static org.junit.Assert.*; @SuppressWarnings({"Duplicates"}) @@ -44,7 +47,7 @@ public class FhirResourceDaoR4FilterTest extends BaseJpaR4Test { } @Test - public void testChainWithMultipleTypePossibilities() { + public void testBrackets() { Patient p= new Patient(); p.addName().setFamily("Smith").addGiven("John"); @@ -73,6 +76,36 @@ public class FhirResourceDaoR4FilterTest extends BaseJpaR4Test { } + @Test + public void testStringComparatorEq() { + + Patient p= new Patient(); + p.addName().setFamily("Smith").addGiven("John"); + p.setActive(true); + String id1 = myPatientDao.create(p).getId().toUnqualifiedVersionless().getValue(); + + p = new Patient(); + p.addName().setFamily("Jones").addGiven("Frank"); + p.setActive(false); + String id2 = myPatientDao.create(p).getId().toUnqualifiedVersionless().getValue(); + + SearchParameterMap map; + List found; + + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Constants.PARAM_FILTER, new StringParam("name eq smi")); + found = toUnqualifiedVersionlessIdValues(myPatientDao.search(map)); + assertThat(found, Matchers.empty()); + + map = new SearchParameterMap(); + map.setLoadSynchronous(true); + map.add(Constants.PARAM_FILTER, new StringParam("name eq smith")); + found = toUnqualifiedVersionlessIdValues(myPatientDao.search(map)); + assertThat(found, containsInAnyOrder(id1)); + + } + @Test public void testFilterDisabled() { myDaoConfig.setFilterParameterEnabled(false); diff --git a/pom.xml b/pom.xml index 84b1e35d3ea..51ded534115 100755 --- a/pom.xml +++ b/pom.xml @@ -558,7 +558,7 @@ - 4.0.0 + 4.0.1-SNAPSHOT 1.0.2 diff --git a/src/changes/changes.xml b/src/changes/changes.xml index d3bdf8ceecc..261ca2b399d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -19,6 +19,11 @@ when deciding how to encode the resource being sent. Thanks to Sean McIlvenna for the pull request! + + When using the _filter search parameter, string comparisons using the "eq" operator + were incorrectly performing a partial match. This has been corrected. Thanks to + Marc Sandberg for pointing this out! + diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml index 1a21f643deb..6359a63a6f5 100644 --- a/src/site/xdoc/index.xml +++ b/src/site/xdoc/index.xml @@ -102,7 +102,7 @@ - James Agnew



- +

May 30, 2019 - HAPI FHIR 3.8.0 (Hippo) Released - The next release of HAPI has now been uploaded to the Maven repos and