From d8133487b215c327c85fa687d91388383e07ab4b Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Mon, 23 Dec 2019 17:14:47 -0500 Subject: [PATCH 1/3] Initial commits. --- .../ca/uhn/fhir/rest/param/DateRangeParam.java | 5 +++++ .../uhn/fhir/rest/param/DateRangeParamTest.java | 17 +++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) 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 8c164c37510..1fd1929d0a0 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 @@ -6,6 +6,7 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.time.DateUtils; import org.hl7.fhir.instance.model.api.IPrimitiveType; @@ -208,6 +209,10 @@ public class DateRangeParam implements IQueryParameterAnd { return this; } + public boolean isDateWithinRange(Date theDate) { + throw new NotImplementedException("Implement this!"); + } + /** * Sets the lower bound using a string that is compliant with * FHIR dateTime format (ISO-8601). 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 72b03f5b4c9..1711834f623 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 @@ -1,19 +1,19 @@ package ca.uhn.fhir.rest.param; -import static org.junit.Assert.assertTrue; - -import java.util.ArrayList; -import java.util.List; - import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.QualifiedParamList; - +import org.apache.commons.lang3.NotImplementedException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertTrue; + @RunWith(JUnit4.class) public class DateRangeParamTest { private FhirContext fhirContext; @@ -23,6 +23,11 @@ public class DateRangeParamTest { fhirContext = Mockito.mock(FhirContext.class); } + @Test + public void testIsDateWithinRange() { + throw new NotImplementedException("Implement this!"); + } + /** Can happen e.g. when the query parameter for {@code _lastUpdated} is left empty. */ @Test public void testParamWithoutPrefixAndWithoutValue() { From 4eaeb7ef9e36bc6d32835a82de37ccd7d104f66d Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Mon, 30 Dec 2019 14:35:51 -0500 Subject: [PATCH 2/3] Implemented isDateWithinRange() and supporting methods. --- .../uhn/fhir/rest/param/DateRangeParam.java | 107 +++++++++- .../fhir/rest/param/DateRangeParamTest.java | 182 +++++++++++++++++- src/changes/changes.xml | 10 + 3 files changed, 289 insertions(+), 10 deletions(-) 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 1fd1929d0a0..88c32914170 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 @@ -6,7 +6,6 @@ import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.time.DateUtils; import org.hl7.fhir.instance.model.api.IPrimitiveType; @@ -209,10 +208,6 @@ public class DateRangeParam implements IQueryParameterAnd { return this; } - public boolean isDateWithinRange(Date theDate) { - throw new NotImplementedException("Implement this!"); - } - /** * Sets the lower bound using a string that is compliant with * FHIR dateTime format (ISO-8601). @@ -286,7 +281,7 @@ public class DateRangeParam implements IQueryParameterAnd { case LESSTHAN_OR_EQUALS: case ENDS_BEFORE: case NOT_EQUAL: - throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getPrefix()); + throw new IllegalStateException("Invalid lower bound comparator: " + myLowerBound.getPrefix()); } } return retVal; @@ -344,7 +339,7 @@ public class DateRangeParam implements IQueryParameterAnd { case APPROXIMATE: case NOT_EQUAL: case STARTS_AFTER: - throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getPrefix()); + throw new IllegalStateException("Invalid upper bound comparator: " + myUpperBound.getPrefix()); } } return retVal; @@ -375,6 +370,104 @@ public class DateRangeParam implements IQueryParameterAnd { return Objects.hash(myLowerBound, myUpperBound); } + public boolean isDateWithinRange(Date theDate) { + boolean retVal = false; + + if (theDate == null) { + throw new NullPointerException("theDate can not be null"); + } + + boolean hasLowerBound = hasBound(myLowerBound); + boolean hasUpperBound = hasBound(myUpperBound); + boolean hasLowerAndUpperBounds = hasLowerBound && hasUpperBound && (myLowerBound.getValue().getTime() != myUpperBound.getValue().getTime()); + + if (hasLowerAndUpperBounds) { + retVal = isDateWithinLowerAndUpperBounds(theDate); + } else if (hasLowerBound) { + retVal = isDateWithinLowerBound(theDate); + } else if (hasUpperBound) { + retVal = isDateWithinUpperBound(theDate); + } + + return retVal; + } + + private boolean isDateWithinLowerAndUpperBounds(Date theDate) { + return isDateWithinLowerBound(theDate, true) && isDateWithinUpperBound(theDate, true); + } + + public boolean isDateWithinLowerBound(Date theDate) { + return isDateWithinLowerBound(theDate, false); + } + + private boolean isDateWithinLowerBound(Date theDate, boolean theIsRange) { + boolean retVal = false; + + if (theDate == null) { + throw new NullPointerException("theDate can not be null"); + } + + if (hasBound(myLowerBound)) { + long lowerBound = myLowerBound.getValue().getTime(); + switch (myLowerBound.getPrefix()) { + case GREATERTHAN: + case STARTS_AFTER: + retVal = theDate.getTime() > lowerBound; + break; + case EQUAL: + if (theIsRange) { + retVal = theDate.getTime() >= lowerBound; + } else { + retVal = theDate.getTime() == lowerBound; + } + break; + case GREATERTHAN_OR_EQUALS: + retVal = theDate.getTime() >= lowerBound; + break; + default: + throw new IllegalStateException("Invalid lower bound comparator: " + myLowerBound.getPrefix()); + } + } + + return retVal; + } + + public boolean isDateWithinUpperBound(Date theDate) { + return isDateWithinUpperBound(theDate, false); + } + + private boolean isDateWithinUpperBound(Date theDate, boolean theIsRange) { + boolean retVal = false; + + if (theDate == null) { + throw new NullPointerException("theDate can not be null"); + } + + if (hasBound(myUpperBound)) { + long upperBound = myUpperBound.getValue().getTime(); + switch (myUpperBound.getPrefix()) { + case LESSTHAN: + case ENDS_BEFORE: + retVal = theDate.getTime() < upperBound; + break; + case EQUAL: + if (theIsRange) { + retVal = theDate.getTime() <= upperBound; + } else { + retVal = theDate.getTime() == upperBound; + } + break; + case LESSTHAN_OR_EQUALS: + retVal = theDate.getTime() <= upperBound; + break; + default: + throw new IllegalStateException("Invalid upper bound comparator: " + myUpperBound.getPrefix()); + } + } + + return retVal; + } + public boolean isEmpty() { return (getLowerBoundAsInstant() == null) && (getUpperBoundAsInstant() == null); } 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 1711834f623..6cfd86d3ad2 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 @@ -2,30 +2,206 @@ package ca.uhn.fhir.rest.param; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.QualifiedParamList; -import org.apache.commons.lang3.NotImplementedException; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; import java.util.ArrayList; +import java.util.Date; import java.util.List; +import static ca.uhn.fhir.rest.param.ParamPrefixEnum.*; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @RunWith(JUnit4.class) public class DateRangeParamTest { private FhirContext fhirContext; + private Date myBefore; + private Date myLower; + private Date myBetween; + private Date myUpper; + private Date myAfter; + + @Rule + public final ExpectedException expectedException = ExpectedException.none(); @Before public void initMockContext() { fhirContext = Mockito.mock(FhirContext.class); } + @Before + public void initDates() throws InterruptedException { + myBefore = new Date(); + Thread.sleep(1L); + myLower = new Date(); + Thread.sleep(1L); + myBetween = new Date(); + Thread.sleep(1L); + myUpper = new Date(); + Thread.sleep(1L); + myAfter = new Date(); + } + @Test - public void testIsDateWithinRange() { - throw new NotImplementedException("Implement this!"); + public void testIsDateWithinRangeExclusive() { + DateParam lowerBound = new DateParam(GREATERTHAN, myLower); + DateParam upperBound = new DateParam(LESSTHAN, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(lowerBound, upperBound); + + assertFalse(dateRangeParam.isDateWithinRange(myBefore)); + assertFalse(dateRangeParam.isDateWithinRange(myLower)); + assertTrue(dateRangeParam.isDateWithinRange(myBetween)); + assertFalse(dateRangeParam.isDateWithinRange(myUpper)); + assertFalse(dateRangeParam.isDateWithinRange(myAfter)); + } + + @Test + public void testIsDateWithinRangeInclusive() { + DateParam lowerBound = new DateParam(EQUAL, myLower); + DateParam upperBound = new DateParam(EQUAL, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(lowerBound, upperBound); + + assertFalse(dateRangeParam.isDateWithinRange(myBefore)); + assertTrue(dateRangeParam.isDateWithinRange(myLower)); + assertTrue(dateRangeParam.isDateWithinRange(myBetween)); + assertTrue(dateRangeParam.isDateWithinRange(myUpper)); + assertFalse(dateRangeParam.isDateWithinRange(myAfter)); + } + + @Test + public void testIsDateWithinRangeOnlyLower() { + DateParam lowerBound = new DateParam(EQUAL, myLower); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setLowerBound(lowerBound); + + assertFalse(dateRangeParam.isDateWithinRange(myBefore)); + assertTrue(dateRangeParam.isDateWithinRange(myLower)); + assertFalse(dateRangeParam.isDateWithinRange(myBetween)); + assertFalse(dateRangeParam.isDateWithinRange(myUpper)); + assertFalse(dateRangeParam.isDateWithinRange(myAfter)); + } + + @Test + public void testIsDateWithinRangeOnlyUpper() { + DateParam upperBound = new DateParam(EQUAL, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setUpperBound(upperBound); + + assertFalse(dateRangeParam.isDateWithinRange(myBefore)); + assertFalse(dateRangeParam.isDateWithinRange(myLower)); + assertFalse(dateRangeParam.isDateWithinRange(myBetween)); + assertTrue(dateRangeParam.isDateWithinRange(myUpper)); + assertFalse(dateRangeParam.isDateWithinRange(myAfter)); + } + + @Test + public void testIsDateWithinLowerBoundGreaterThan() { + DateParam lowerBound = new DateParam(GREATERTHAN, myLower); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setLowerBound(lowerBound); + + assertFalse(dateRangeParam.isDateWithinLowerBound(myBefore)); + assertFalse(dateRangeParam.isDateWithinLowerBound(myLower)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myBetween)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myUpper)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myAfter)); + } + + @Test + public void testIsDateWithinLowerBoundStartsAfter() { + DateParam lowerBound = new DateParam(STARTS_AFTER, myLower); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setLowerBound(lowerBound); + + assertFalse(dateRangeParam.isDateWithinLowerBound(myBefore)); + assertFalse(dateRangeParam.isDateWithinLowerBound(myLower)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myBetween)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myUpper)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myAfter)); + } + + @Test + public void testIsDateWithinLowerBoundEqual() { + DateParam lowerBound = new DateParam(EQUAL, myLower); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setLowerBound(lowerBound); + + assertFalse(dateRangeParam.isDateWithinLowerBound(myBefore)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myLower)); + assertFalse(dateRangeParam.isDateWithinLowerBound(myBetween)); + assertFalse(dateRangeParam.isDateWithinLowerBound(myUpper)); + assertFalse(dateRangeParam.isDateWithinLowerBound(myAfter)); + } + + @Test + public void testIsDateWithinLowerBoundGreaterThanOrEquals() { + DateParam lowerBound = new DateParam(GREATERTHAN_OR_EQUALS, myLower); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setLowerBound(lowerBound); + + assertFalse(dateRangeParam.isDateWithinLowerBound(myBefore)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myLower)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myBetween)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myUpper)); + assertTrue(dateRangeParam.isDateWithinLowerBound(myAfter)); + } + + @Test + public void testIsDateWithinUpperBoundLessThan() { + DateParam upperBound = new DateParam(LESSTHAN, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setUpperBound(upperBound); + + assertTrue(dateRangeParam.isDateWithinUpperBound(myBefore)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myLower)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myBetween)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myUpper)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myAfter)); + } + + @Test + public void testIsDateWithinUpperBoundEndsBefore() { + DateParam upperBound = new DateParam(ENDS_BEFORE, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setUpperBound(upperBound); + + assertTrue(dateRangeParam.isDateWithinUpperBound(myBefore)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myLower)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myBetween)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myUpper)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myAfter)); + } + + @Test + public void testIsDateWithinUpperBoundEqual() { + DateParam upperBound = new DateParam(EQUAL, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setUpperBound(upperBound); + + assertFalse(dateRangeParam.isDateWithinUpperBound(myBefore)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myLower)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myBetween)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myUpper)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myAfter)); + } + + @Test + public void testIsDateWithinUpperBoundLessThanOrEquals() { + DateParam upperBound = new DateParam(LESSTHAN_OR_EQUALS, myUpper); + DateRangeParam dateRangeParam = new DateRangeParam(); + dateRangeParam.setUpperBound(upperBound); + + assertTrue(dateRangeParam.isDateWithinUpperBound(myBefore)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myLower)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myBetween)); + assertTrue(dateRangeParam.isDateWithinUpperBound(myUpper)); + assertFalse(dateRangeParam.isDateWithinUpperBound(myAfter)); } /** Can happen e.g. when the query parameter for {@code _lastUpdated} is left empty. */ diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 498233d327a..1a2eb9963f7 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -77,6 +77,16 @@ An issue with the HAPI FHIR CLI was corrected that prevented the upload of LOINC due to an error regarding the properties file. + + The following utility methods have been added: + +
  • DateRangeParam#isDateWithinRange(Date theDate)
  • +
  • DateRangeParam#isDateWithinLowerBound(Date theDate)
  • +
  • DateRangeParam#isDateWithinUpperBound(Date theDate)
  • + + ]]> +
    From 856993edf8a9f8a7361b9d9b090e32bb737098ff Mon Sep 17 00:00:00 2001 From: Diederik Muylwyk Date: Mon, 30 Dec 2019 15:29:35 -0500 Subject: [PATCH 3/3] Moved changelog entry, and added clarifying comments to DateRangeParam. --- .../uhn/fhir/rest/param/DateRangeParam.java | 27 +++++++++++++++++++ .../hapi/fhir/changelog/4_2_0/changes.yaml | 25 +++++++++++------ src/changes/changes.xml | 10 ------- 3 files changed, 44 insertions(+), 18 deletions(-) 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 88c32914170..aa20383f423 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 @@ -215,6 +215,15 @@ public class DateRangeParam implements IQueryParameterAnd { * This lower bound is assumed to have a ge * (greater than or equals) modifier. *

    + *

    + * Note: An operation can take a DateRangeParam. If only a single date is provided, + * it will still result in a DateRangeParam where the lower and upper bounds + * are the same value. As such, even though the prefixes for the lower and + * upper bounds default to ge and le respectively, + * the resulting prefix is effectively eq where only a single + * date is provided - as required by the FHIR specificiation (i.e. "If no + * prefix is present, the prefix eq is assumed"). + *

    */ public DateRangeParam setLowerBound(String theLowerBound) { setLowerBound(new DateParam(GREATERTHAN_OR_EQUALS, theLowerBound)); @@ -298,6 +307,15 @@ public class DateRangeParam implements IQueryParameterAnd { * This upper bound is assumed to have a le * (less than or equals) modifier. *

    + *

    + * Note: An operation can take a DateRangeParam. If only a single date is provided, + * it will still result in a DateRangeParam where the lower and upper bounds + * are the same value. As such, even though the prefixes for the lower and + * upper bounds default to ge and le respectively, + * the resulting prefix is effectively eq where only a single + * date is provided - as required by the FHIR specificiation (i.e. "If no + * prefix is present, the prefix eq is assumed"). + *

    */ public DateRangeParam setUpperBound(String theUpperBound) { setUpperBound(new DateParam(LESSTHAN_OR_EQUALS, theUpperBound)); @@ -618,6 +636,15 @@ public class DateRangeParam implements IQueryParameterAnd { return b.toString(); } + /** + * Note: An operation can take a DateRangeParam. If only a single date is provided, + * it will still result in a DateRangeParam where the lower and upper bounds + * are the same value. As such, even though the prefixes for the lower and + * upper bounds default to ge and le respectively, + * the resulting prefix is effectively eq where only a single + * date is provided - as required by the FHIR specificiation (i.e. "If no + * prefix is present, the prefix eq is assumed"). + */ private void validateAndSet(DateParam lowerBound, DateParam upperBound) { if (hasBound(lowerBound) && hasBound(upperBound)) { if (lowerBound.getValue().getTime() > upperBound.getValue().getTime()) { diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_2_0/changes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_2_0/changes.yaml index e0c2bfd651c..751ab54a333 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_2_0/changes.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_2_0/changes.yaml @@ -41,18 +41,27 @@ type: "fix" title: "A missing mandatory was added to the SNOMED CT CodeSystem that is uploaded when SCT is uploaded to the JPA server. Thanks to Anders Havn for the pull request!" - item: - issue: 1643 - type: fix + issue: "1643" + type: "fix" title: "When validating resources containing custom valuesets defined in PrePopulatedValidationSupport outside of the JPA server, sometimes code systems could not be found resulting in false negative errors." - item: - issue: 1588 - type: add + issue: "1588" + type: "add" title: "Support for several new operators has been added to the `_filter` support in the JPA server. Thanks to Anthony Sute for the Pull Request!" - item: - issue: 1650 - type: fix - title: Several misleading comments in documentation code snippets were fixed. Thanks to - Jafer Khan for the pull request! + issue: "1650" + type: "fix" + title: "Several misleading comments in documentation code snippets were fixed. Thanks to + Jafer Khan for the pull request!" +- item: + issue: "1645" + type: "add" + title: "The following utility methods have been added: +
      +
    • DateRangeParam#isDateWithinRange(Date theDate)
    • +
    • DateRangeParam#isDateWithinLowerBound(Date theDate)
    • +
    • DateRangeParam#isDateWithinUpperBound(Date theDate)
    • +
    " diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 1a2eb9963f7..498233d327a 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -77,16 +77,6 @@ An issue with the HAPI FHIR CLI was corrected that prevented the upload of LOINC due to an error regarding the properties file.
    - - The following utility methods have been added: - -
  • DateRangeParam#isDateWithinRange(Date theDate)
  • -
  • DateRangeParam#isDateWithinLowerBound(Date theDate)
  • -
  • DateRangeParam#isDateWithinUpperBound(Date theDate)
  • - - ]]> -