diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/DateRangeParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/DateRangeParam.java index ac634ea7972..8aaffa92551 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/DateRangeParam.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/DateRangeParam.java @@ -89,6 +89,7 @@ public class DateRangeParam implements IQueryParameterAnd { setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString()); } else { switch (theDateParam.getPrefix()) { + case NOT_EQUAL: case EQUAL: setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString()); break; @@ -161,41 +162,42 @@ public class DateRangeParam implements IQueryParameterAnd { } private void addParam(DateParam theParsed) throws InvalidRequestException { - if (theParsed.getPrefix() == null || theParsed.getPrefix() == EQUAL) { - if (myLowerBound != null || myUpperBound != null) { - throw new InvalidRequestException(Msg.code(1922) + "Can not have multiple date range parameters for the same param without a qualifier"); - } - - if (theParsed.getMissing() != null) { - myLowerBound = theParsed; - myUpperBound = theParsed; - } else { - myLowerBound = new DateParam(EQUAL, theParsed.getValueAsString()); - myUpperBound = new DateParam(EQUAL, theParsed.getValueAsString()); - } - - } else { - - switch (theParsed.getPrefix()) { - case GREATERTHAN: - case GREATERTHAN_OR_EQUALS: - if (myLowerBound != null) { - throw new InvalidRequestException(Msg.code(1923) + "Can not have multiple date range parameters for the same param that specify a lower bound"); - } - myLowerBound = theParsed; - break; - case LESSTHAN: - case LESSTHAN_OR_EQUALS: - if (myUpperBound != null) { - throw new InvalidRequestException(Msg.code(1924) + "Can not have multiple date range parameters for the same param that specify an upper bound"); - } - myUpperBound = theParsed; - break; - default: - throw new InvalidRequestException(Msg.code(1925) + "Unknown comparator: " + theParsed.getPrefix()); - } - + if (theParsed.getPrefix() == null){ + theParsed.setPrefix(EQUAL); } + + switch (theParsed.getPrefix()) { + case NOT_EQUAL: + case EQUAL: + if (myLowerBound != null || myUpperBound != null) { + throw new InvalidRequestException(Msg.code(1922) + "Can not have multiple date range parameters for the same param without a qualifier"); + } + if (theParsed.getMissing() != null) { + myLowerBound = theParsed; + myUpperBound = theParsed; + } else { + myLowerBound = new DateParam(theParsed.getPrefix(), theParsed.getValueAsString()); + myUpperBound = new DateParam(theParsed.getPrefix(), theParsed.getValueAsString()); + } + break; + case GREATERTHAN: + case GREATERTHAN_OR_EQUALS: + if (myLowerBound != null) { + throw new InvalidRequestException(Msg.code(1923) + "Can not have multiple date range parameters for the same param that specify a lower bound"); + } + myLowerBound = theParsed; + break; + case LESSTHAN: + case LESSTHAN_OR_EQUALS: + if (myUpperBound != null) { + throw new InvalidRequestException(Msg.code(1924) + "Can not have multiple date range parameters for the same param that specify an upper bound"); + } + myUpperBound = theParsed; + break; + default: + throw new InvalidRequestException(Msg.code(1925) + "Unknown comparator: " + theParsed.getPrefix()); + } + } @Override diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java index 3da72a6a4b8..4d5a746fffb 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java @@ -10,6 +10,7 @@ import org.mockito.Mockito; import java.util.ArrayList; import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -25,7 +26,7 @@ public class DateRangeParamTest { * Can happen e.g. when the query parameter for {@code _lastUpdated} is left empty. */ @Test - public void testParamWithoutPrefixAndWithoutValue() { + public void testParamWithoutPrefixAndWithoutValue_dateRangeParamRemainsEmpty() { QualifiedParamList qualifiedParamList = new QualifiedParamList(1); qualifiedParamList.add(""); @@ -41,7 +42,7 @@ public class DateRangeParamTest { * Can happen e.g. when the query parameter for {@code _lastUpdated} is given as {@code lt} without any value. */ @Test - public void testUpperBoundWithPrefixWithoutValue() { + public void testUpperBoundWithPrefixWithoutValue_throwsDateFormatException() { QualifiedParamList qualifiedParamList = new QualifiedParamList(1); qualifiedParamList.add("lt"); @@ -60,7 +61,7 @@ public class DateRangeParamTest { * Can happen e.g. when the query parameter for {@code _lastUpdated} is given as {@code gt} without any value. */ @Test - public void testLowerBoundWithPrefixWithoutValue() { + public void testLowerBoundWithPrefixWithoutValue_throwsDateFormatException() { QualifiedParamList qualifiedParamList = new QualifiedParamList(1); qualifiedParamList.add("gt"); @@ -74,4 +75,52 @@ public class DateRangeParamTest { // good } } + + @Test + public void testSetValueAsQueryTokens_neYear_setsUpperAndLowerBounds() { + QualifiedParamList qualifiedParamList = new QualifiedParamList(1); + qualifiedParamList.add("ne1965"); + + List params = new ArrayList<>(1); + params.add(qualifiedParamList); + DateRangeParam dateRangeParam = new DateRangeParam(); + + dateRangeParam.setValuesAsQueryTokens(fhirContext, "_lastUpdated", params); + assertEquals("1965", dateRangeParam.getLowerBound().getValueAsString()); + assertEquals("1965", dateRangeParam.getUpperBound().getValueAsString()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getLowerBound().getPrefix()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getUpperBound().getPrefix()); + } + + @Test + public void testSetValueAsQueryTokens_neMonth_setsUpperAndLowerBounds() { + QualifiedParamList qualifiedParamList = new QualifiedParamList(1); + qualifiedParamList.add("ne1965-11"); + + List params = new ArrayList<>(1); + params.add(qualifiedParamList); + DateRangeParam dateRangeParam = new DateRangeParam(); + + dateRangeParam.setValuesAsQueryTokens(fhirContext, "_lastUpdated", params); + assertEquals("1965-11", dateRangeParam.getLowerBound().getValueAsString()); + assertEquals("1965-11", dateRangeParam.getUpperBound().getValueAsString()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getLowerBound().getPrefix()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getUpperBound().getPrefix()); + } + + @Test + public void testSetValueAsQueryTokens_neDay_setsUpperAndLowerBounds() { + QualifiedParamList qualifiedParamList = new QualifiedParamList(1); + qualifiedParamList.add("ne1965-11-23"); + + List params = new ArrayList<>(1); + params.add(qualifiedParamList); + DateRangeParam dateRangeParam = new DateRangeParam(); + + dateRangeParam.setValuesAsQueryTokens(fhirContext, "_lastUpdated", params); + assertEquals("1965-11-23", dateRangeParam.getLowerBound().getValueAsString()); + assertEquals("1965-11-23", dateRangeParam.getUpperBound().getValueAsString()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getLowerBound().getPrefix()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, dateRangeParam.getUpperBound().getPrefix()); + } } diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_0_0/3470-ne-date-search.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_0_0/3470-ne-date-search.yaml new file mode 100644 index 00000000000..8758dda5237 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_0_0/3470-ne-date-search.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 3470 +title: "The server now supports date searches with the NOT_EQUALS (`ne`) prefix." diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamR4Test.java index b78d8afba58..48e20056279 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamR4Test.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamR4Test.java @@ -195,6 +195,20 @@ public class DateRangeParamR4Test { assertEquals(ParamPrefixEnum.LESSTHAN_OR_EQUALS, ourLastDateRange.getUpperBound().getPrefix()); } + @Test + public void testSearchForOneQualifiedDateNe() throws Exception { + HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=ne2012-01-01"); + CloseableHttpResponse status = ourClient.execute(httpGet); + consumeResponse(status); + assertEquals(200, status.getStatusLine().getStatusCode()); + + assertEquals("2012-01-01", ourLastDateRange.getLowerBound().getValueAsString()); + assertEquals("2012-01-01", ourLastDateRange.getUpperBound().getValueAsString()); + + assertEquals(ParamPrefixEnum.NOT_EQUAL, ourLastDateRange.getLowerBound().getPrefix()); + assertEquals(ParamPrefixEnum.NOT_EQUAL, ourLastDateRange.getUpperBound().getPrefix()); + } + @Test public void testRangeWithDatePrecision() throws Exception { HttpGet httpGet = new HttpGet(ourBaseUrl + "?birthdate=gt2012-01-01&birthdate=lt2012-01-03");