From 79bdd94f72fe4e62f4a423e491aa87f9222ee66b Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Fri, 21 Mar 2014 08:12:44 -0400
Subject: [PATCH] Some unit test fixes, still some failures
---
.../java/ca/uhn/fhir/context/FhirContext.java | 3 +
.../fhir/model/api/TemporalPrecisionEnum.java | 44 +++++-
.../java/ca/uhn/fhir/parser/BaseParser.java | 3 +-
.../main/java/ca/uhn/fhir/parser/IParser.java | 2 +-
.../java/ca/uhn/fhir/parser/JsonParser.java | 148 +++++++++---------
.../java/ca/uhn/fhir/parser/ParserState.java | 4 +-
.../java/ca/uhn/fhir/parser/XmlParser.java | 10 +-
.../uhn/fhir/rest/param/DateRangeParam.java | 35 ++++-
.../java/example/FhirContextIntro.java | 9 +-
.../RestfulPatientResourceProviderMore.java | 17 ++
.../src/site/xdoc/doc_rest_operations.xml | 48 +++++-
.../ca/uhn/fhir/parser/JsonParserTest.java | 4 +-
.../ca/uhn/fhir/parser/XmlParserTest.java | 2 +-
.../fhir/rest/param/DateRangeParamTest.java | 84 ++++++++++
14 files changed, 309 insertions(+), 104 deletions(-)
create mode 100644 hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
index b81c6900726..a519c273846 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java
@@ -27,6 +27,9 @@ public class FhirContext {
this(toCollection(theResourceType));
}
+ public FhirContext() {
+ }
+
public FhirContext(Class>... theResourceTypes) {
this(toCollection(theResourceTypes));
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TemporalPrecisionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TemporalPrecisionEnum.java
index 2bf8ef416e3..2e27f092a4c 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TemporalPrecisionEnum.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/TemporalPrecisionEnum.java
@@ -1,14 +1,45 @@
package ca.uhn.fhir.model.api;
import java.util.Calendar;
+import java.util.Date;
+
+import org.apache.commons.lang3.time.DateUtils;
public enum TemporalPrecisionEnum {
- YEAR(Calendar.YEAR),
- MONTH(Calendar.MONTH),
- DAY(Calendar.DATE),
- SECOND(Calendar.SECOND),
- MILLI(Calendar.MILLISECOND),
+ YEAR(Calendar.YEAR) {
+ @Override
+ public Date add(Date theInput, int theAmount) {
+ return DateUtils.addYears(theInput, theAmount);
+ }
+ },
+
+ MONTH(Calendar.MONTH) {
+ @Override
+ public Date add(Date theInput, int theAmount) {
+ return DateUtils.addMonths(theInput, theAmount);
+ }
+ },
+ DAY(Calendar.DATE) {
+ @Override
+ public Date add(Date theInput, int theAmount) {
+ return DateUtils.addDays(theInput, theAmount);
+ }
+ },
+ SECOND(Calendar.SECOND) {
+ @Override
+ public Date add(Date theInput, int theAmount) {
+ return DateUtils.addSeconds(theInput, theAmount);
+ }
+ },
+
+ MILLI(Calendar.MILLISECOND) {
+ @Override
+ public Date add(Date theInput, int theAmount) {
+ return DateUtils.addMilliseconds(theInput, theAmount);
+ }
+ },
+
;
private int myCalendarConstant;
@@ -17,7 +48,10 @@ public enum TemporalPrecisionEnum {
myCalendarConstant = theCalendarConstant;
}
+ public abstract Date add(Date theInput, int theAmount);
+
public int getCalendarConstant() {
return myCalendarConstant;
}
+
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
index 1332244444c..1f17d9b35ed 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
@@ -30,6 +30,7 @@ public abstract class BaseParser implements IParser {
public IResource parseResource(Reader theReader) throws ConfigurationException, DataFormatException {
return parseResource(null, theReader);
}
+
public void containResourcesForEncoding(IResource theResource) {
List allElements = theResource.getAllPopulatedChildElementsOfType(ResourceReferenceDt.class);
@@ -46,7 +47,7 @@ public abstract class BaseParser implements IParser {
theResource.getContained().getContainedResources().add(resource);
allIds.add(resource.getId().getValue());
}
-
+
next.setReference("#" + resource.getId().getValue());
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java
index 1276c2b23f8..df0f387102a 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/IParser.java
@@ -28,7 +28,7 @@ public interface IParser {
T parseResource(Class theResourceType, String theMessageString);
- IResource parseResource(Class extends IResource> theResourceType, Reader theReader);
+ T parseResource(Class theResourceType, Reader theReader);
IParser setPrettyPrint(boolean thePrettyPrint);
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
index ca9ae7daf05..8035860fa08 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
@@ -4,6 +4,7 @@ import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.Reader;
+import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
@@ -65,21 +66,6 @@ public class JsonParser extends BaseParser implements IParser {
return stringWriter.toString();
}
- private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
- if (StringUtils.isNotBlank(theStringDt.getValue())) {
- theEventWriter.write(theElementName, theStringDt.getValue());
- } else {
- theEventWriter.writeNull(theElementName);
- }
- }
-
- private void writeOptionalTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IPrimitiveDatatype> theInstantDt) {
- String str = theInstantDt.getValueAsString();
- if (StringUtils.isNotBlank(str)) {
- theEventWriter.write(theElementName, theInstantDt.getValueAsString());
- }
- }
-
@Override
public void encodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException {
JsonGenerator eventWriter = createJsonGenerator(theWriter);
@@ -132,26 +118,6 @@ public class JsonParser extends BaseParser implements IParser {
eventWriter.close();
}
- private void writeAuthor(BaseBundle theBundle, JsonGenerator eventWriter) {
- if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
- eventWriter.writeStartArray("author");
- eventWriter.writeStartObject();
- writeTagWithTextNode(eventWriter, "name", theBundle.getAuthorName());
- writeOptionalTagWithTextNode(eventWriter, "uri", theBundle.getAuthorUri());
- eventWriter.writeEnd();
- eventWriter.writeEnd();
- }
- }
-
- private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) {
- if (isNotBlank(theLink.getValue())) {
- theEventWriter.writeStartObject();
- theEventWriter.write("rel", theRel);
- theEventWriter.write("href", theLink.getValue());
- theEventWriter.writeEnd();
- }
- }
-
@Override
public String encodeResourceToString(IResource theResource) throws DataFormatException, IOException {
Writer stringWriter = new StringWriter();
@@ -172,16 +138,6 @@ public class JsonParser extends BaseParser implements IParser {
// }
}
- private JsonGenerator createJsonGenerator(Writer theWriter) {
- Map properties = new HashMap(1);
- if (myPrettyPrint) {
- properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
- }
- JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
- JsonGenerator eventWriter = jgf.createGenerator(theWriter);
- return eventWriter;
- }
-
@Override
public Bundle parseBundle(Reader theReader) {
// TODO Auto-generated method stub
@@ -195,24 +151,29 @@ public class JsonParser extends BaseParser implements IParser {
}
@Override
- public IResource parseResource(Class extends IResource> theResourceType, Reader theReader) {
+ public T parseResource(Class theResourceType, String theMessageString) {
+ return parseResource(theResourceType, new StringReader(theMessageString));
+ }
+
+ @Override
+ public T parseResource(Class theResourceType, Reader theReader) {
JsonReader reader = Json.createReader(theReader);
JsonObject object = reader.readObject();
-
- JsonValue resourceTypeObj = object.remove("resourceType");
+
+ JsonValue resourceTypeObj = object.get("resourceType");
assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType");
- String resourceType = ((JsonString)resourceTypeObj).getString();
-
+ String resourceType = ((JsonString) resourceTypeObj).getString();
+
if (theResourceType != null) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
- }else {
+ } else {
RuntimeResourceDefinition def = myContext.getResourceDefinition(resourceType);
}
-
+
PushbackJsonParser parser = new PushbackJsonParser(Json.createParser(theReader));
-
+
while (parser.hasNext()) {
-
+
Event next = parser.next();
switch (next) {
case END_ARRAY:
@@ -236,28 +197,14 @@ public class JsonParser extends BaseParser implements IParser {
break;
default:
break;
-
+
}
-
-
+
}
-
+
return null;
}
- private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
- if (theResourceTypeObj.getValueType() != theValueType) {
- throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
- }
- }
-
- @Override
- public T parseResource(Class theResourceType, String theMessageString) {
- // TODO Auto-generated method stub
- return null;
- }
-
-
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
@@ -279,6 +226,22 @@ public class JsonParser extends BaseParser implements IParser {
}
}
+ private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) {
+ if (theResourceTypeObj.getValueType() != theValueType) {
+ throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType);
+ }
+ }
+
+ private JsonGenerator createJsonGenerator(Writer theWriter) {
+ Map properties = new HashMap(1);
+ if (myPrettyPrint) {
+ properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint);
+ }
+ JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
+ JsonGenerator eventWriter = jgf.createGenerator(theWriter);
+ return eventWriter;
+ }
+
private void encodeChildElementToStreamWriter(JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition> theChildDef, String theChildName) throws IOException {
switch (theChildDef.getChildType()) {
@@ -318,7 +281,7 @@ public class JsonParser extends BaseParser implements IParser {
if (theChildName != null) {
theWriter.writeStartObject(theChildName);
} else {
- theWriter.flush();//TODO: remove
+ theWriter.flush();// TODO: remove
theWriter.writeStartObject();
}
encodeCompositeElementToStreamWriter(theValue, theWriter, childCompositeDef);
@@ -424,7 +387,7 @@ public class JsonParser extends BaseParser implements IParser {
}
currentChildName = childName;
} else {
- theEventWriter.flush();//TODO: remove
+ theEventWriter.flush();// TODO: remove
encodeChildElementToStreamWriter(theEventWriter, nextValue, childDef, null);
}
@@ -462,7 +425,7 @@ public class JsonParser extends BaseParser implements IParser {
}
if (!haveContent) {
-// theEventWriter.writeEnd();
+ // theEventWriter.writeEnd();
theEventWriter.flush(); // TODO: remove
theEventWriter.writeNull();
}
@@ -520,7 +483,7 @@ public class JsonParser extends BaseParser implements IParser {
}
theEventWriter.write("resourceType", resDef.getName());
- if (theResource.getId() !=null && isNotBlank(theResource.getId().getValue())) {
+ if (theResource.getId() != null && isNotBlank(theResource.getId().getValue())) {
theEventWriter.write("id", theResource.getId().getValue());
}
@@ -559,6 +522,41 @@ public class JsonParser extends BaseParser implements IParser {
theWriter.writeEnd();
}
+ private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) {
+ if (isNotBlank(theLink.getValue())) {
+ theEventWriter.writeStartObject();
+ theEventWriter.write("rel", theRel);
+ theEventWriter.write("href", theLink.getValue());
+ theEventWriter.writeEnd();
+ }
+ }
+
+ private void writeAuthor(BaseBundle theBundle, JsonGenerator eventWriter) {
+ if (StringUtils.isNotBlank(theBundle.getAuthorName().getValue())) {
+ eventWriter.writeStartArray("author");
+ eventWriter.writeStartObject();
+ writeTagWithTextNode(eventWriter, "name", theBundle.getAuthorName());
+ writeOptionalTagWithTextNode(eventWriter, "uri", theBundle.getAuthorUri());
+ eventWriter.writeEnd();
+ eventWriter.writeEnd();
+ }
+ }
+
+ private void writeOptionalTagWithTextNode(JsonGenerator theEventWriter, String theElementName, IPrimitiveDatatype> theInstantDt) {
+ String str = theInstantDt.getValueAsString();
+ if (StringUtils.isNotBlank(str)) {
+ theEventWriter.write(theElementName, theInstantDt.getValueAsString());
+ }
+ }
+
+ private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
+ if (StringUtils.isNotBlank(theStringDt.getValue())) {
+ theEventWriter.write(theElementName, theStringDt.getValue());
+ } else {
+ theEventWriter.writeNull(theElementName);
+ }
+ }
+
private class HeldExtension {
private UndeclaredExtension myUndeclaredExtension;
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
index 5cd3a9aac12..cee0fa9b9b5 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
@@ -115,8 +115,8 @@ class ParserState {
* @param theResourceType
* May be null
*/
- public static ParserState getPreResourceInstance(Class extends IResource> theResourceType, FhirContext theContext) throws DataFormatException {
- ParserState retVal = new ParserState(theContext);
+ public static ParserState getPreResourceInstance(Class theResourceType, FhirContext theContext) throws DataFormatException {
+ ParserState retVal = new ParserState(theContext);
retVal.push(retVal.new PreResourceState(theResourceType));
return retVal;
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
index 01a7ce9947b..32f9a9ef815 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java
@@ -138,6 +138,10 @@ public class XmlParser extends BaseParser implements IParser {
@Override
public String encodeResourceToString(IResource theResource) throws DataFormatException {
+ if (theResource==null) {
+ throw new NullPointerException("Resource can not be null");
+ }
+
Writer stringWriter = new StringWriter();
encodeResourceToWriter(theResource, stringWriter);
return stringWriter.toString();
@@ -183,7 +187,7 @@ public class XmlParser extends BaseParser implements IParser {
}
@Override
- public IResource parseResource(Class extends IResource> theResourceType, Reader theReader) {
+ public T parseResource(Class theResourceType, Reader theReader) {
XMLEventReader streamReader;
try {
streamReader = myXmlInputFactory.createXMLEventReader(theReader);
@@ -545,8 +549,8 @@ public class XmlParser extends BaseParser implements IParser {
return doXmlLoop(theStreamReader, parserState);
}
- private IResource parseResource(Class extends IResource> theResourceType, XMLEventReader theStreamReader) {
- ParserState parserState = ParserState.getPreResourceInstance(theResourceType, myContext);
+ private T parseResource(Class theResourceType, XMLEventReader theStreamReader) {
+ ParserState parserState = ParserState.getPreResourceInstance(theResourceType, myContext);
return doXmlLoop(theStreamReader, parserState);
}
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 b856ce05ba1..d4ca2d95c9b 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 java.util.Date;
import java.util.List;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
+import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateRangeParam implements IQueryParameterAnd {
@@ -91,13 +92,39 @@ public class DateRangeParam implements IQueryParameterAnd {
}
public Date getLowerBoundAsInstant() {
- // TODO: account for precision
- return myLowerBound.getValue();
+ Date retVal = myLowerBound.getValue();
+ if (myLowerBound.getComparator() != null) {
+ switch (myLowerBound.getComparator()) {
+ case GREATERTHAN:
+ retVal = myLowerBound.getPrecision().add(retVal, 1);
+ break;
+ case GREATERTHAN_OR_EQUALS:
+ break;
+ case LESSTHAN:
+ case LESSTHAN_OR_EQUALS:
+ throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getComparator());
+ }
+ }
+ return retVal;
}
public Date getUpperBoundAsInstant() {
- // TODO: account for precision
- return myUpperBound.getValue();
+ Date retVal = myUpperBound.getValue();
+ if (myUpperBound.getComparator() != null) {
+ switch (myUpperBound.getComparator()) {
+ case LESSTHAN:
+ retVal = new Date(retVal.getTime() - 1L);
+ break;
+ case LESSTHAN_OR_EQUALS:
+ retVal = myUpperBound.getPrecision().add(retVal, 1);
+ retVal = new Date(retVal.getTime() - 1L);
+ break;
+ case GREATERTHAN_OR_EQUALS:
+ case GREATERTHAN:
+ throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getComparator());
+ }
+ }
+ return retVal;
}
}
diff --git a/hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java b/hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java
index 2e131ce1550..661bc7f9c85 100644
--- a/hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java
+++ b/hapi-fhir-base/src/site/example/java/example/FhirContextIntro.java
@@ -17,12 +17,7 @@ public class FhirContextIntro {
public static void creatingContext() {
// START SNIPPET: creatingContext
-/*
- * Create a FhirContex instance which is able to parse and encode
- * the Patient and Observation resources, and any resources referenced
- * from these.
- */
-FhirContext ctx = new FhirContext(Patient.class, Observation.class);
+FhirContext ctx = new FhirContext();
// END SNIPPET: creatingContext
}
@@ -103,7 +98,7 @@ StringDt familyName = patient.getName().get(0).getFamily().get(0);
CodeDt gender = patient.getGender().getCoding().get(0).getCode();
/*
- * The
+ * The various datatype classes have accessors called getValue()
*/
System.out.println(patientId.getValue()); // PRP1660
System.out.println(familyName.getValue()); // Cardinal
diff --git a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java b/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java
index 8f571199707..9bcecb75209 100644
--- a/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java
+++ b/hapi-fhir-base/src/site/example/java/example/RestfulPatientResourceProviderMore.java
@@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.annotation.Required;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.client.ITestClient;
import ca.uhn.fhir.rest.param.CodingListParam;
+import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
@@ -161,6 +162,22 @@ public List getDiagnosticReport( @Required(name=DiagnosticRepo
}
//END SNIPPET: pathSpec
+//START SNIPPET: dateRange
+@Search()
+public List getObservationsByDateRange(@Required(name="subject.identifier") IdentifierDt theSubjectId,
+ @Required(name=Observation.SP_DATE) DateRangeParam theRange) {
+ List retVal = new ArrayList();
+
+ // The following two will be set as the start and end
+ // of the range specified by the query parameter
+ Date from = theRange.getLowerBoundAsInstant();
+ Date to = theRange.getUpperBoundAsInstant();
+
+ // ... populate ...
+ return retVal;
+}
+//END SNIPPET: dateRange
+
private DiagnosticReport loadSomeDiagnosticReportFromDatabase(IdentifierDt theIdentifier) {
return null;
}
diff --git a/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml b/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml
index 2a1523a4e27..cee6662b814 100644
--- a/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml
+++ b/hapi-fhir-base/src/site/xdoc/doc_rest_operations.xml
@@ -159,15 +159,15 @@
may be optional. To add a second required parameter, annotate the
parameter with
@Required.
- To add an optional parameter (which will be pased in as null
if no value
+ To add an optional parameter (which will be passed in as null
if no value
is supplied), annotate the method with
@Optional.
You may annotate a method with any combination of as many @Required and as many @Optional
- parameters as you want. It is valid to have no @Required parameters, or
- no @Optional parameters as well.
+ parameters as you want. It is valid to have only @Required parameters, or
+ only @Optional parameters, or any combination of the two.
@@ -230,7 +230,7 @@
-
+
The FHIR specification provides a sytax for specifying
@@ -270,6 +270,46 @@
+
+
+
+ A common scenario in searches is to allow searching for resources
+ with values (i.e timestamps) within a range of dates.
+
+
+
+ FHIR allows for multiple parameters with the same key, and interprets
+ these as being an "AND" set. So, for example, a range of
+ DATE >= 2011-01-01
and DATE < 2011-02-01
+ can be interpreted as any date within January 2011.
+
+
+
+ The following snippet shows how to accept such a range, and combines it
+ with a specific identifier, which is a common scenario. (i.e. Give me a list
+ of observations for a specific patient within a given date range)
+
+
+
+
+
+
+
+ Example URL to invoke this method:
+ http://fhir.example.com/Observation?subject.identifier=7000135&date=>=2011-01-01&date=<2011-02-01
+
+
+
+ Invoking a client of thie type involves the following syntax:
+
+
+
+
+
+
+
+
+
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java
index cc22506eacd..4afe40ec9e6 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java
@@ -80,17 +80,19 @@ public class JsonParserTest {
}
+ @Test
public void testSimpleParse() throws DataFormatException, IOException {
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/example-patient-general.json"));
FhirContext ctx = new FhirContext(Patient.class);
IParser p = ctx.newJsonParser();
+ ourLog.info("Reading in message: {}", msg);
Patient res = p.parseResource(Patient.class, msg);
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
ourLog.info(encoded);
- }
+ }
@Test
public void testEncodeContainedResourcesMore() throws IOException {
diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java
index 3350b98d798..7ce45b551f6 100644
--- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java
@@ -82,7 +82,7 @@ public class XmlParserTest {
String str = p.encodeResourceToString(rpt);
ourLog.info(str);
- assertThat(str, StringContains.containsString("
AAA
"));
+ assertThat(str, StringContains.containsString("AAA
"));
assertThat(str, StringContains.containsString("reference value=\"#"));
int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length();
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
new file mode 100644
index 00000000000..3f53830101a
--- /dev/null
+++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java
@@ -0,0 +1,84 @@
+package ca.uhn.fhir.rest.param;
+
+import static org.junit.Assert.*;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+
+public class DateRangeParamTest {
+
+ private static SimpleDateFormat ourFmt;
+
+ @BeforeClass
+ public static void beforeClass() {
+ ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
+ }
+
+ @Test
+ public void testYear() throws Exception {
+ assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011", "<2012").getLowerBoundAsInstant());
+ assertEquals(parseM1("2012-01-01 00:00:00.0000"), create(">=2011", "<2012").getUpperBoundAsInstant());
+
+ assertEquals(parse("2012-01-01 00:00:00.0000"), create(">2011", "<=2012").getLowerBoundAsInstant());
+ assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant());
+ }
+
+ @Test
+ public void testMonth() throws Exception {
+ assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-02-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getUpperBoundAsInstant());
+
+ assertEquals(parse("2011-02-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-03-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getUpperBoundAsInstant());
+ }
+
+ @Test
+ public void testDay() throws Exception {
+ assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-01-02 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getUpperBoundAsInstant());
+
+ assertEquals(parse("2011-01-02 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-01-03 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getUpperBoundAsInstant());
+ }
+
+ @Test
+ public void testSecond() throws Exception {
+ assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-01-01 02:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T02:00:00").getUpperBoundAsInstant());
+
+ assertEquals(parse("2011-01-01 00:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getLowerBoundAsInstant());
+ assertEquals(parseM1("2011-01-01 02:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getUpperBoundAsInstant());
+ }
+
+ private Date parse(String theString) throws ParseException {
+ return ourFmt.parse(theString);
+ }
+
+ private Date parseM1(String theString) throws ParseException {
+ return new Date(ourFmt.parse(theString).getTime() - 1L);
+ }
+
+ private Date parseP1(String theString) throws ParseException {
+ return new Date(ourFmt.parse(theString).getTime() + 1L);
+ }
+
+
+ private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
+ DateRangeParam p = new DateRangeParam();
+ List> tokens=new ArrayList>();
+ tokens.add(Collections.singletonList(theLower));
+ tokens.add(Collections.singletonList(theUpper));
+ p.setValuesAsQueryTokens(tokens);
+ return p;
+ }
+
+}