Work on #164 - Add support for :missing in JPA server

This commit is contained in:
James Agnew 2015-04-30 19:26:26 -04:00
parent 35cdfaabbd
commit 3fc6958ff2
34 changed files with 892 additions and 297 deletions

View File

@ -59,4 +59,16 @@ public interface IQueryParameterType {
*/
public String getQueryParameterQualifier();
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale
* instead of a normal value
*/
Boolean getMissing();
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale
* instead of a normal value
*/
void setMissing(Boolean theMissing);
}

View File

@ -29,6 +29,7 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.param.TokenParam;
public abstract class BaseCodingDt extends BaseIdentifiableElement implements ICompositeDatatype, IQueryParameterType {
@ -172,4 +173,28 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
public abstract BaseCodingDt setSystem(String theUri);
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
}

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.param.StringParam;
public abstract class BaseIdentifierDt extends BaseIdentifiableElement implements ICompositeDatatype, IQueryParameterType {
@ -112,4 +113,29 @@ public abstract class BaseIdentifierDt extends BaseIdentifiableElement implement
}
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
}

View File

@ -33,6 +33,8 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.StringParam;
public abstract class BaseQuantityDt extends BaseIdentifiableElement implements ICompositeDatatype, IQueryParameterType {
@ -208,4 +210,30 @@ public abstract class BaseQuantityDt extends BaseIdentifiableElement implements
* </p>
*/
public abstract DecimalDt getValueElement();
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link QuantityParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link QuantityParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
}

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.model.api.BasePrimitive;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.rest.param.StringParam;
@DatatypeDef(name = "string")
public class StringDt extends BasePrimitive<String> implements IQueryParameterType {
@ -122,4 +123,28 @@ public class StringDt extends BasePrimitive<String> implements IQueryParameterTy
return theValue;
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
}

View File

@ -0,0 +1,33 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.rest.server.Constants;
abstract class BaseClientParam implements IParam {
@Override
public ICriterion<?> isMissing(boolean theMissing) {
return new MissingCriterion(theMissing ? Constants.PARAMQUALIFIER_MISSING_TRUE : Constants.PARAMQUALIFIER_MISSING_FALSE);
}
private class MissingCriterion implements ICriterion<IParam>, ICriterionInternal
{
private String myParameterValue;
public MissingCriterion(String theParameterValue) {
myParameterValue = theParameterValue;
}
@Override
public String getParameterValue() {
return myParameterValue;
}
@Override
public String getParameterName() {
return BaseClientParam.this.getParamName() + Constants.PARAMQUALIFIER_MISSING;
}
}
}

View File

@ -23,7 +23,7 @@ package ca.uhn.fhir.rest.gclient;
/**
* Composite parameter type for use in fluent client interfaces
*/
public class CompositeClientParam<A extends IParam, B extends IParam> implements IParam {
public class CompositeClientParam<A extends IParam, B extends IParam> extends BaseClientParam implements IParam {
private String myName;

View File

@ -28,7 +28,7 @@ import ca.uhn.fhir.model.primitive.DateTimeDt;
/**
* Date parameter type for use in fluent client interfaces
*/
public class DateClientParam implements IParam {
public class DateClientParam extends BaseClientParam implements IParam {
private String myParamName;

View File

@ -22,6 +22,16 @@ package ca.uhn.fhir.rest.gclient;
public interface IParam {
/**
* Returns the name of this parameter
*/
String getParamName();
/**
* Sets the <code>:missing</code> qualifier for this parameter. Set this to <code>true</code>
* to indicate that the server should return resources with this value <p>populated</p>. Set this to
* <code>false</code> to indicate that the server should return resources with this value <b>missing</b>.
*/
ICriterion<?> isMissing(boolean theMissing);
}

View File

@ -23,7 +23,7 @@ package ca.uhn.fhir.rest.gclient;
/**
* Token parameter type for use in fluent client interfaces
*/
public class NumberClientParam implements IParam {
public class NumberClientParam extends BaseClientParam implements IParam {
private String myParamName;

View File

@ -27,7 +27,7 @@ import ca.uhn.fhir.rest.gclient.NumberClientParam.IMatches;
/**
* Token parameter type for use in fluent client interfaces
*/
public class QuantityClientParam implements IParam {
public class QuantityClientParam extends BaseClientParam implements IParam {
private String myParamName;

View File

@ -23,7 +23,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
*/
public class ReferenceClientParam implements IParam {
public class ReferenceClientParam extends BaseClientParam implements IParam {
private String myName;

View File

@ -31,7 +31,7 @@ import ca.uhn.fhir.rest.server.Constants;
* @author james
*
*/
public class StringClientParam implements IParam {
public class StringClientParam extends BaseClientParam implements IParam {
private final String myParamName;

View File

@ -31,7 +31,7 @@ import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
/**
* Token parameter type for use in fluent client interfaces
*/
public class TokenClientParam implements IParam {
public class TokenClientParam extends BaseClientParam implements IParam {
private String myParamName;

View File

@ -28,7 +28,7 @@ import ca.uhn.fhir.model.primitive.StringDt;
/**
*
*/
public class UriClientParam implements IParam {
public class UriClientParam extends BaseClientParam implements IParam {
//TODO: handle :above and :below

View File

@ -26,54 +26,75 @@ import ca.uhn.fhir.rest.server.Constants;
/**
* Base class for RESTful operation parameter types
*/
public class BaseParam implements IQueryParameterType {
abstract class BaseParam implements IQueryParameterType {
private Boolean myMissing;
private Boolean myMissing;
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale
* instead of a normal value
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale instead of a normal value
*/
@Override
public Boolean getMissing() {
return myMissing;
}
@Override
public String getQueryParameterQualifier() {
public final String getQueryParameterQualifier() {
if (myMissing != null) {
return Constants.PARAMQUALIFIER_MISSING;
}
return null;
return doGetQueryParameterQualifier();
}
abstract String doGetQueryParameterQualifier();
abstract String doGetValueAsQueryToken();
@Override
public String getValueAsQueryToken() {
public final String getValueAsQueryToken() {
if (myMissing != null) {
return myMissing ? "true" : "false";
return myMissing ? Constants.PARAMQUALIFIER_MISSING_TRUE : Constants.PARAMQUALIFIER_MISSING_FALSE;
}
return null;
return doGetValueAsQueryToken();
}
/**
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale
* instead of a normal value
* If set to non-null value, indicates that this parameter has been populated with a "[name]:missing=true" or "[name]:missing=false" vale instead of a normal value
*/
@Override
public void setMissing(Boolean theMissing) {
myMissing = theMissing;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
public final void setValueAsQueryToken(String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_MISSING.equals(theQualifier)) {
myMissing = "true".equals(theValue);
} else {
myMissing = null;
doSetValueAsQueryToken(theQualifier, theValue);
}
}
abstract void doSetValueAsQueryToken(String theQualifier, String theValue);
static class ComposableBaseParam extends BaseParam{
@Override
String doGetQueryParameterQualifier() {
return null;
}
@Override
String doGetValueAsQueryToken() {
return null;
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
// nothing
}
}
}

View File

@ -30,7 +30,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class CompositeParam<A extends IQueryParameterType, B extends IQueryParameterType> implements IQueryParameterType {
public class CompositeParam<A extends IQueryParameterType, B extends IQueryParameterType> extends BaseParam implements IQueryParameterType {
private A myLeftType;
private B myRightType;
@ -59,27 +59,13 @@ public class CompositeParam<A extends IQueryParameterType, B extends IQueryParam
}
}
/**
* @return Returns the left value for this parameter (the first of two parameters in this composite)
*/
public A getLeftValue() {
return myLeftType;
}
@Override
public String getQueryParameterQualifier() {
String doGetQueryParameterQualifier() {
return null;
}
/**
* @return Returns the right value for this parameter (the second of two parameters in this composite)
*/
public B getRightValue() {
return myRightType;
}
@Override
public String getValueAsQueryToken() {
String doGetValueAsQueryToken() {
StringBuilder b = new StringBuilder();
if (myLeftType != null) {
b.append(myLeftType.getValueAsQueryToken());
@ -92,7 +78,7 @@ public class CompositeParam<A extends IQueryParameterType, B extends IQueryParam
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
void doSetValueAsQueryToken(String theQualifier, String theValue) {
if (isBlank(theValue)) {
myLeftType.setValueAsQueryToken(theQualifier, "");
myRightType.setValueAsQueryToken(theQualifier, "");
@ -108,4 +94,18 @@ public class CompositeParam<A extends IQueryParameterType, B extends IQueryParam
}
}
/**
* @return Returns the left value for this parameter (the first of two parameters in this composite)
*/
public A getLeftValue() {
return myLeftType;
}
/**
* @return Returns the right value for this parameter (the second of two parameters in this composite)
*/
public B getRightValue() {
return myRightType;
}
}

View File

@ -36,7 +36,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateParam extends DateTimeDt implements IQueryParameterType, IQueryParameterOr<DateParam> {
private QuantityCompararatorEnum myComparator;
private BaseParam myBase=new BaseParam();
private BaseParam myBase=new BaseParam.ComposableBaseParam();
/**
* Constructor
@ -191,4 +191,14 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
return new DateTimeDt(getValueAsString());
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
}

View File

@ -365,6 +365,16 @@ public class InternalCodingDt extends BaseCodingDt implements ICompositeDatatype
return getDisplay();
}
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException();
}
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException();
}

View File

@ -414,6 +414,16 @@ class InternalQuantityDt
return this;
}
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException();
}
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException();
}

View File

@ -45,32 +45,24 @@ public class NumberParam extends BaseParam implements IQueryParameterType {
}
@Override
public String toString() {
String doGetQueryParameterQualifier() {
return null;
}
@Override
String doGetValueAsQueryToken() {
StringBuilder b = new StringBuilder();
b.append(getClass().getSimpleName());
b.append("[");
if (myQuantity.getComparatorElement().isEmpty() == false) {
b.append(myQuantity.getComparatorElement().getValue());
}
if (myQuantity.getValueElement().isEmpty() == false) {
b.append(myQuantity.getValueElement().toString());
}
b.append("]");
return b.toString();
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
}
public BigDecimal getValue() {
return myQuantity.getValueElement().getValue();
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
super.setValueAsQueryToken(theQualifier, theValue);
void doSetValueAsQueryToken(String theQualifier, String theValue) {
if (getMissing() != null && isBlank(theValue)) {
return;
}
@ -91,26 +83,29 @@ public class NumberParam extends BaseParam implements IQueryParameterType {
myQuantity.setValue(new BigDecimal(theValue));
}
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
}
public BigDecimal getValue() {
return myQuantity.getValueElement().getValue();
}
@Override
public String getValueAsQueryToken() {
if (getMissing() != null) {
return super.getQueryParameterQualifier();
}
public String toString() {
StringBuilder b = new StringBuilder();
b.append(getClass().getSimpleName());
b.append("[");
if (myQuantity.getComparatorElement().isEmpty() == false) {
b.append(myQuantity.getComparatorElement().getValue());
}
if (myQuantity.getValueElement().isEmpty() == false) {
b.append(myQuantity.getValueElement().toString());
}
b.append("]");
return b.toString();
}
@Override
public String getQueryParameterQualifier() {
return super.getQueryParameterQualifier();
}
}

View File

@ -142,29 +142,13 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
myApproximate = false;
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
}
@Override
public String getQueryParameterQualifier() {
String doGetQueryParameterQualifier() {
return super.getQueryParameterQualifier();
}
public UriDt getSystem() {
return myQuantity.getSystemElement();
}
public String getUnits() {
return myQuantity.getUnitsElement().getValue();
}
public DecimalDt getValue() {
return myQuantity.getValueElement();
}
@Override
public String getValueAsQueryToken() {
String doGetValueAsQueryToken() {
if (super.getMissing() != null) {
return super.getValueAsQueryToken();
}
@ -191,6 +175,67 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
return b.toString();
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
clear();
super.setValueAsQueryToken(theQualifier, theValue);
if (getMissing() != null) {
return;
}
if (theValue == null) {
return;
}
List<String> parts = ParameterUtil.splitParameterString(theValue, '|', true);
if (parts.size() > 0 && StringUtils.isNotBlank(parts.get(0))) {
if (parts.get(0).startsWith("~")) {
myQuantity.setComparator((QuantityCompararatorEnum) null);
myApproximate = true;
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else if (parts.get(0).startsWith("<=")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith("<")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN);
String valStr = parts.get(0).substring(1);
myQuantity.setValue(new BigDecimal(valStr));
} else if (parts.get(0).startsWith(">=")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith(">")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else {
myQuantity.setValue(new BigDecimal(parts.get(0)));
}
}
if (parts.size() > 1 && StringUtils.isNotBlank(parts.get(1))) {
myQuantity.setSystem(parts.get(1));
}
if (parts.size() > 2 && StringUtils.isNotBlank(parts.get(2))) {
myQuantity.setUnits(parts.get(2));
}
}
public QuantityCompararatorEnum getComparator() {
return myQuantity.getComparatorElement().getValueAsEnum();
}
public UriDt getSystem() {
return myQuantity.getSystemElement();
}
public String getUnits() {
return myQuantity.getUnitsElement().getValue();
}
public DecimalDt getValue() {
return myQuantity.getValueElement();
}
public boolean isApproximate() {
return myApproximate;
}
@ -253,51 +298,6 @@ public class QuantityParam extends BaseParam implements IQueryParameterType {
return this;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
clear();
super.setValueAsQueryToken(theQualifier, theValue);
if (getMissing() != null) {
return;
}
if (theValue == null) {
return;
}
List<String> parts = ParameterUtil.splitParameterString(theValue, '|', true);
if (parts.size() > 0 && StringUtils.isNotBlank(parts.get(0))) {
if (parts.get(0).startsWith("~")) {
myQuantity.setComparator((QuantityCompararatorEnum) null);
myApproximate = true;
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else if (parts.get(0).startsWith("<=")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith("<")) {
myQuantity.setComparator(QuantityCompararatorEnum.LESSTHAN);
String valStr = parts.get(0).substring(1);
myQuantity.setValue(new BigDecimal(valStr));
} else if (parts.get(0).startsWith(">=")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(2)));
} else if (parts.get(0).startsWith(">")) {
myQuantity.setComparator(QuantityCompararatorEnum.GREATERTHAN);
myQuantity.setValue(new BigDecimal(parts.get(0).substring(1)));
} else {
myQuantity.setValue(new BigDecimal(parts.get(0)));
}
}
if (parts.size() > 1 && StringUtils.isNotBlank(parts.get(1))) {
myQuantity.setSystem(parts.get(1));
}
if (parts.size() > 2 && StringUtils.isNotBlank(parts.get(2))) {
myQuantity.setUnits(parts.get(2));
}
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);

View File

@ -32,7 +32,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
public class ReferenceParam extends IdDt implements IQueryParameterType {
private String myChain;
private BaseParam myBase=new BaseParam();
private BaseParam myBase=new BaseParam.ComposableBaseParam();
public ReferenceParam() {
}
@ -206,4 +206,14 @@ public class ReferenceParam extends IdDt implements IQueryParameterType {
return retVal;
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
}

View File

@ -48,23 +48,35 @@ public class StringParam extends BaseParam implements IQueryParameterType {
}
@Override
public String getQueryParameterQualifier() {
if (getMissing() != null) {
return super.getQueryParameterQualifier();
}else if (isExact()) {
String doGetQueryParameterQualifier() {
if (isExact()) {
return Constants.PARAMQUALIFIER_STRING_EXACT;
} else {
return null;
}
}
@Override
String doGetValueAsQueryToken() {
return ParameterUtil.escape(myValue);
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_STRING_EXACT.equals(theQualifier)) {
setExact(true);
} else {
setExact(false);
}
myValue = ParameterUtil.unescape(theValue);
}
public String getValue() {
return myValue;
}
@Override
public String getValueAsQueryToken() {
return ParameterUtil.escape(myValue);
public StringDt getValueAsStringDt() {
return new StringDt(myValue);
}
public String getValueNotNull() {
@ -87,16 +99,6 @@ public class StringParam extends BaseParam implements IQueryParameterType {
myValue = theValue;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
if (Constants.PARAMQUALIFIER_STRING_EXACT.equals(theQualifier)) {
setExact(true);
} else {
setExact(false);
}
myValue = ParameterUtil.unescape(theValue);
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
@ -107,8 +109,4 @@ public class StringParam extends BaseParam implements IQueryParameterType {
return builder.toString();
}
public StringDt getValueAsStringDt() {
return new StringDt(myValue);
}
}

View File

@ -41,21 +41,6 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
public TokenParam() {
}
public TokenParam(String theSystem, String theValue) {
setSystem(theSystem);
setValue(theValue);
}
public TokenParam(String theSystem, String theValue, boolean theText) {
if (theText && isNotBlank(theSystem)) {
throw new IllegalArgumentException(
"theSystem can not be non-blank if theText is true (:text searches do not include a system). In other words, set the first parameter to null for a text search");
}
setSystem(theSystem);
setValue(theValue);
setText(theText);
}
/**
* Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter
*
@ -76,21 +61,56 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
this(toSystemValue(theIdentifierDt.getSystemElement()), theIdentifierDt.getValueElement().getValue());
}
private static String toSystemValue(UriDt theSystem) {
return theSystem.getValueAsString();
public TokenParam(String theSystem, String theValue) {
setSystem(theSystem);
setValue(theValue);
}
public TokenParam(String theSystem, String theValue, boolean theText) {
if (theText && isNotBlank(theSystem)) {
throw new IllegalArgumentException(
"theSystem can not be non-blank if theText is true (:text searches do not include a system). In other words, set the first parameter to null for a text search");
}
setSystem(theSystem);
setValue(theValue);
setText(theText);
}
@Override
public String getQueryParameterQualifier() {
if (getMissing() != null) {
return super.getQueryParameterQualifier();
} else if (isText()) {
String doGetQueryParameterQualifier() {
if (isText()) {
return Constants.PARAMQUALIFIER_TOKEN_TEXT;
} else {
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
String doGetValueAsQueryToken() {
if (getSystem() != null) {
return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|' + ParameterUtil.escape(getValue());
} else {
return ParameterUtil.escape(getValue());
}
}
/**
* {@inheritDoc}
*/
@Override
void doSetValueAsQueryToken(String theQualifier, String theParameter) {
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));
setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
} else {
setValue(ParameterUtil.unescape(theParameter));
}
}
public String getSystem() {
return mySystem;
}
@ -99,18 +119,8 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
return myValue;
}
/**
* {@inheritDoc}
*/
@Override
public String getValueAsQueryToken() {
if (getMissing() != null) {
return super.getValueAsQueryToken();
} else if (getSystem() != null) {
return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|' + ParameterUtil.escape(getValue());
} else {
return ParameterUtil.escape(getValue());
}
public InternalCodingDt getValueAsCoding() {
return new InternalCodingDt(mySystem, myValue);
}
public String getValueNotNull() {
@ -137,25 +147,6 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
myValue = theValue;
}
/**
* {@inheritDoc}
*/
@Override
public void setValueAsQueryToken(String theQualifier, String theParameter) {
super.setValueAsQueryToken(theQualifier, theParameter);
if (getMissing() != null) {
return;
}
int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|');
if (barIndex != -1) {
setSystem(theParameter.substring(0, barIndex));
setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1)));
} else {
setValue(ParameterUtil.unescape(theParameter));
}
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
@ -170,8 +161,8 @@ public class TokenParam extends BaseParam implements IQueryParameterType {
return builder.toString();
}
public InternalCodingDt getValueAsCoding() {
return new InternalCodingDt(mySystem, myValue);
private static String toSystemValue(UriDt theSystem) {
return theSystem.getValueAsString();
}
}

View File

@ -42,21 +42,30 @@ public class UriParam extends BaseParam implements IQueryParameterType {
}
@Override
public String getQueryParameterQualifier() {
if (getMissing() != null) {
return super.getQueryParameterQualifier();
} else {
return null;
}
String doGetQueryParameterQualifier() {
return null;
}
@Override
String doGetValueAsQueryToken() {
return ParameterUtil.escape(myValue);
}
@Override
void doSetValueAsQueryToken(String theQualifier, String theValue) {
myValue = ParameterUtil.unescape(theValue);
}
public String getValue() {
return myValue;
}
@Override
public String getValueAsQueryToken() {
return ParameterUtil.escape(myValue);
public StringDt getValueAsStringDt() {
return new StringDt(myValue);
}
public UriDt getValueAsUriDt() {
return new UriDt(myValue);
}
public String getValueNotNull() {
@ -71,11 +80,6 @@ public class UriParam extends BaseParam implements IQueryParameterType {
myValue = theValue;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
myValue = ParameterUtil.unescape(theValue);
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
@ -83,12 +87,4 @@ public class UriParam extends BaseParam implements IQueryParameterType {
return builder.toString();
}
public StringDt getValueAsStringDt() {
return new StringDt(myValue);
}
public UriDt getValueAsUriDt() {
return new UriDt(myValue);
}
}

View File

@ -123,6 +123,8 @@ public class Constants {
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
public static final String URL_TOKEN_HISTORY = "_history";
public static final String URL_TOKEN_METADATA = "metadata";
public static final String PARAMQUALIFIER_MISSING_TRUE = "true";
public static final String PARAMQUALIFIER_MISSING_FALSE = "false";
static {
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();

View File

@ -42,4 +42,5 @@ ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionInvalidUrl=Unable to perform {0
ca.uhn.fhir.jpa.dao.BaseFhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists
ca.uhn.fhir.jpa.dao.BaseFhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create resource with ID[{0}], no resource with this ID exists and clients may only assign IDs which begin with a non-numeric character on this server
ca.uhn.fhir.jpa.dao.BaseFhirResourceDao.failedToCreateWithClientAssignedId=Can not create resource with ID[{0}], ID must not be supplied on a create (POST) operation
ca.uhn.fhir.jpa.dao.BaseFhirResourceDao.multipleParamsWithSameNameOneIsMissingTrue=This server does not know how to handle multiple "{0}" parameters where one has a value of :missing=true
ca.uhn.fhir.jpa.dao.BaseFhirResourceDao.unableToDeleteNotFound=Unable to find resource matching URL "{0}". Deletion failed.

View File

@ -47,6 +47,7 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
@ -72,6 +73,7 @@ import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.BaseTag;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
@ -141,6 +143,8 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
private String mySecondaryPrimaryKeyParamName;
private Set<Long> addPredicateComposite(RuntimeSearchParam theParamDef, Set<Long> thePids, List<? extends IQueryParameterType> theNextAnd) {
// TODO: fail if missing is set for a composite query
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceTable> from = cq.from(ResourceTable.class);
@ -178,6 +182,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return thePids;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myParamsDate");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamDate> from = cq.from(ResourceIndexedSearchParamDate.class);
@ -185,6 +193,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) {
if (addPredicateMissingFalseIfPresent(theParamName, from, codePredicates, nextOr)) {
continue;
}
IQueryParameterType params = nextOr;
Predicate p = createPredicateDate(builder, from, params);
codePredicates.add(p);
@ -205,50 +217,6 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return new HashSet<Long>(q.getResultList());
}
private Predicate addPredicateDateFromRange(CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theFrom, DateRangeParam theRange) {
Date lowerBound = theRange.getLowerBoundAsInstant();
Date upperBound = theRange.getUpperBoundAsInstant();
Predicate lb = null;
if (lowerBound != null) {
Predicate gt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueLow"), lowerBound);
Predicate lt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueHigh"), lowerBound);
lb = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate hbo = builder.or(lt, lin);
// lb = builder.and(lbo, hbo);
}
Predicate ub = null;
if (upperBound != null) {
Predicate gt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueLow"), upperBound);
Predicate lt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueHigh"), upperBound);
ub = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate ubo = builder.or(lt, lin);
// ub = builder.and(ubo, lbo);
}
if (lb != null && ub != null) {
return (theBuilder.and(lb, ub));
} else if (lb != null) {
return (lb);
} else {
return (ub);
}
}
// private Set<Long> addPredicateComposite(String theParamName, Set<Long> thePids, List<? extends
// IQueryParameterType> theList) {
// }
private Set<Long> addPredicateId(Set<Long> theExistingPids, Set<Long> thePids) {
if (thePids == null || thePids.isEmpty()) {
return Collections.emptySet();
@ -273,6 +241,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return found;
}
// private Set<Long> addPredicateComposite(String theParamName, Set<Long> thePids, List<? extends
// IQueryParameterType> theList) {
// }
private Set<Long> addPredicateLanguage(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList) {
if (theList == null || theList.isEmpty()) {
return thePids;
@ -323,6 +295,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return thePids;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myParamsNumber");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamNumber> from = cq.from(ResourceIndexedSearchParamNumber.class);
@ -332,6 +308,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresent(theParamName, from, codePredicates, nextOr)) {
continue;
}
if (params instanceof NumberParam) {
NumberParam param = (NumberParam) params;
@ -385,10 +365,30 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateParamMissing(Set<Long> thePids, String joinName) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceTable> from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
Join<Object, Object> join = from.join(joinName, JoinType.LEFT);
if (thePids.size() > 0) {
Predicate inPids = (from.get("myId").in(thePids));
cq.where(builder.and(inPids, join.isNull()));
} else {
cq.where(join.isNull());
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
}
private Set<Long> addPredicateQuantity(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
if (theList == null || theList.isEmpty()) {
return thePids;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myParamsQuantity");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
@ -399,6 +399,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresent(theParamName, from, codePredicates, nextOr)) {
continue;
}
String systemValue;
String unitsValue;
QuantityCompararatorEnum cmpValue;
@ -500,6 +504,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return pidsToRetain;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myResourceLinks");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceLink> from = cq.from(ResourceLink.class);
@ -510,6 +518,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
for (IQueryParameterType nextOr : theList) {
IQueryParameterType params = nextOr;
if (addPredicateMissingFalseIfPresentForResourceLink(theParamName, from, codePredicates, nextOr)) {
continue;
}
if (params instanceof ReferenceParam) {
ReferenceParam ref = (ReferenceParam) params;
@ -594,6 +606,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return thePids;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myParamsString");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamString> from = cq.from(ResourceIndexedSearchParamString.class);
@ -602,7 +618,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
List<Predicate> codePredicates = new ArrayList<Predicate>();
for (IQueryParameterType nextOr : theList) {
IQueryParameterType theParameter = nextOr;
if (addPredicateMissingFalseIfPresent(theParamName, from, codePredicates, nextOr)) {
continue;
}
Predicate singleCode = createPredicateString(theParameter, theParamName, builder, from);
codePredicates.add(singleCode);
}
@ -622,11 +641,41 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
return new HashSet<Long>(q.getResultList());
}
private boolean addPredicateMissingFalseIfPresent(String theParamName, Root<? extends BaseResourceIndexedSearchParam> from, List<Predicate> codePredicates, IQueryParameterType nextOr) {
boolean missingFalse = false;
if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirResourceDao.class, "multipleParamsWithSameNameOneIsMissingTrue", theParamName));
}
Predicate singleCode = from.get("myId").isNotNull();
codePredicates.add(singleCode);
missingFalse = true;
}
return missingFalse;
}
private boolean addPredicateMissingFalseIfPresentForResourceLink(String theParamName, Root<? extends ResourceLink> from, List<Predicate> codePredicates, IQueryParameterType nextOr) {
boolean missingFalse = false;
if (nextOr.getMissing() != null) {
if (nextOr.getMissing().booleanValue() == true) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirResourceDao.class, "multipleParamsWithSameNameOneIsMissingTrue", theParamName));
}
Predicate singleCode = from.get("mySourceResource").isNotNull();
codePredicates.add(singleCode);
missingFalse = true;
}
return missingFalse;
}
private Set<Long> addPredicateToken(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
if (theList == null || theList.isEmpty()) {
return thePids;
}
if (Boolean.TRUE.equals(theList.get(0).getMissing())) {
return addPredicateParamMissing(thePids, "myParamsToken");
}
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceIndexedSearchParamToken> from = cq.from(ResourceIndexedSearchParamToken.class);
@ -641,6 +690,10 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
}
}
if (addPredicateMissingFalseIfPresent(theParamName, from, codePredicates, nextOr)) {
continue;
}
Predicate singleCode = createPredicateToken(nextOr, theParamName, builder, from);
codePredicates.add(singleCode);
}
@ -759,20 +812,60 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
DateParam date = (DateParam) theParam;
if (!date.isEmpty()) {
DateRangeParam range = new DateRangeParam(date);
p = addPredicateDateFromRange(theBuilder, theFrom, range);
p = createPredicateDateFromRange(theBuilder, theFrom, range);
} else {
// TODO: handle missing date param?
p = null;
}
} else if (theParam instanceof DateRangeParam) {
DateRangeParam range = (DateRangeParam) theParam;
p = addPredicateDateFromRange(theBuilder, theFrom, range);
p = createPredicateDateFromRange(theBuilder, theFrom, range);
} else {
throw new IllegalArgumentException("Invalid token type: " + theParam.getClass());
}
return p;
}
private Predicate createPredicateDateFromRange(CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theFrom, DateRangeParam theRange) {
Date lowerBound = theRange.getLowerBoundAsInstant();
Date upperBound = theRange.getUpperBoundAsInstant();
Predicate lb = null;
if (lowerBound != null) {
Predicate gt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueLow"), lowerBound);
Predicate lt = theBuilder.greaterThanOrEqualTo(theFrom.<Date> get("myValueHigh"), lowerBound);
lb = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate hbo = builder.or(lt, lin);
// lb = builder.and(lbo, hbo);
}
Predicate ub = null;
if (upperBound != null) {
Predicate gt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueLow"), upperBound);
Predicate lt = theBuilder.lessThanOrEqualTo(theFrom.<Date> get("myValueHigh"), upperBound);
ub = theBuilder.or(gt, lt);
// Predicate gin = builder.isNull(from.get("myValueLow"));
// Predicate lbo = builder.or(gt, gin);
// Predicate lin = builder.isNull(from.get("myValueHigh"));
// Predicate ubo = builder.or(lt, lin);
// ub = builder.and(ubo, lbo);
}
if (lb != null && ub != null) {
return (theBuilder.and(lb, ub));
} else if (lb != null) {
return (lb);
} else {
return (ub);
}
}
private Predicate createPredicateString(IQueryParameterType theParameter, String theParamName, CriteriaBuilder theBuilder,
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> theFrom) {
String rawSearchTerm;
@ -1166,7 +1259,7 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
}
HashSet<Long> pidsToInclude = new HashSet<Long>();
for (Include nextInclude : theRevIncludes) {
boolean matchAll = "*".equals(nextInclude.getValue());
if (matchAll) {
@ -1208,7 +1301,7 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
}
}
}
theMatches.addAll(pidsToInclude);
}
@ -1532,9 +1625,8 @@ public abstract class BaseFhirResourceDao<T extends IResource> extends BaseFhirD
loadResourcesByPid(pidsSubList, retVal, BundleEntrySearchModeEnum.MATCH);
/*
* Load _include resources - Note that _revincludes are handled differently
* than _include ones, as they are counted towards the total count and paged,
* so they are loaded outside the bundle provider
* Load _include resources - Note that _revincludes are handled differently than _include ones, as they are counted towards the total count and paged, so they are loaded
* outside the bundle provider
*/
if (theParams.getIncludes() != null && theParams.getIncludes().isEmpty() == false) {
Set<IdDt> previouslyLoadedPids = new HashSet<IdDt>();

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
@ -866,16 +867,16 @@ public class FhirResourceDaoDstu2Test {
public void testReverseIncludes() {
String methodName = "testReverseIncludes";
Organization org = new Organization();
org.setName("X"+methodName+"X");
org.setName("X" + methodName + "X");
IdDt orgId = ourOrganizationDao.create(org).getId();
Patient pat = new Patient();
pat.addName().addFamily("X"+methodName+"X");
pat.addName().addFamily("X" + methodName + "X");
pat.getManagingOrganization().setReference(orgId.toUnqualifiedVersionless());
ourPatientDao.create(pat);
SearchParameterMap map = new SearchParameterMap();
map.add(Organization.SP_NAME, new StringParam("X"+methodName+"X"));
map.add(Organization.SP_NAME, new StringParam("X" + methodName + "X"));
map.setRevIncludes(Collections.singleton(Patient.INCLUDE_ORGANIZATION));
IBundleProvider resultsP = ourOrganizationDao.search(map);
assertEquals(2, resultsP.size());
@ -884,11 +885,11 @@ public class FhirResourceDaoDstu2Test {
assertEquals(Organization.class, results.get(0).getClass());
assertEquals(Patient.class, results.get(1).getClass());
}
@Test
public void testResourceInstanceMetaOperation() {
deleteEverything();
String methodName = "testResourceInstanceMetaOperation";
IdDt id1, id2;
{
@ -1521,6 +1522,195 @@ public class FhirResourceDaoDstu2Test {
}
@Test
public void testSearchWithMissingString() {
IdDt orgId = ourOrganizationDao.create(new Organization()).getId();
IdDt notMissing;
IdDt missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDate(new DateDt("2011-01-01"));
patient.getManagingOrganization().setReference(orgId);
notMissing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
// String Param
{
HashMap<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
StringParam param = new StringParam();
param.setMissing(false);
params.put(Patient.SP_FAMILY, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
StringParam param = new StringParam();
param.setMissing(true);
params.put(Patient.SP_FAMILY, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingQuantity() {
IdDt notMissing;
IdDt missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = ourObservationDao.create(obs).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.setValue(new QuantityDt(123));
notMissing = ourObservationDao.create(obs).getId().toUnqualifiedVersionless();
}
// Quantity Param
{
HashMap<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
QuantityParam param = new QuantityParam();
param.setMissing(false);
params.put(Observation.SP_VALUE_QUANTITY, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
QuantityParam param = new QuantityParam();
param.setMissing(true);
params.put(Observation.SP_VALUE_QUANTITY, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithToken() {
IdDt notMissing;
IdDt missing;
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("001");
missing = ourObservationDao.create(obs).getId().toUnqualifiedVersionless();
}
{
Observation obs = new Observation();
obs.addIdentifier().setSystem("urn:system").setValue("002");
obs.getCode().addCoding().setSystem("urn:system").setCode("002");
notMissing = ourObservationDao.create(obs).getId().toUnqualifiedVersionless();
}
// Token Param
{
HashMap<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
TokenParam param = new TokenParam();
param.setMissing(false);
params.put(Observation.SP_CODE, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
TokenParam param = new TokenParam();
param.setMissing(true);
params.put(Observation.SP_CODE, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingDate() {
IdDt orgId = ourOrganizationDao.create(new Organization()).getId();
IdDt notMissing;
IdDt missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDate(new DateDt("2011-01-01"));
patient.getManagingOrganization().setReference(orgId);
notMissing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
// Date Param
{
HashMap<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
DateParam param = new DateParam();
param.setMissing(false);
params.put(Patient.SP_BIRTHDATE, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
DateParam param = new DateParam();
param.setMissing(true);
params.put(Patient.SP_BIRTHDATE, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchWithMissingReference() {
IdDt orgId = ourOrganizationDao.create(new Organization()).getId();
IdDt notMissing;
IdDt missing;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
missing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchStringParam").addGiven("John");
patient.setBirthDate(new DateDt("2011-01-01"));
patient.getManagingOrganization().setReference(orgId);
notMissing = ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
// Reference Param
{
HashMap<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
ReferenceParam param = new ReferenceParam();
param.setMissing(false);
params.put(Patient.SP_ORGANIZATION, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, not(containsInRelativeOrder(missing)));
assertThat(patients, containsInRelativeOrder(notMissing));
}
{
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
ReferenceParam param = new ReferenceParam();
param.setMissing(true);
params.put(Patient.SP_ORGANIZATION, param);
List<IdDt> patients = toUnqualifiedVersionlessIds(ourPatientDao.search(params));
assertThat(patients, containsInRelativeOrder(missing));
assertThat(patients, not(containsInRelativeOrder(notMissing)));
}
}
@Test
public void testSearchStringParamWithNonNormalized() {
{
@ -2343,14 +2533,12 @@ public class FhirResourceDaoDstu2Test {
FhirSystemDaoDstu2Test.doDeleteEverything(ourSystemDao);
}
@Test
public void testSearchWithNoResults() {
Device dev = new Device();
dev.addIdentifier().setSystem("Foo");
ourDeviceDao.create(dev);
IBundleProvider value = ourDeviceDao.search(new SearchParameterMap());
ourLog.info("Initial size: " + value.size());
for (IResource next : value.getResources(0, value.size())) {

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
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.dstu.resource.Device;
@ -286,7 +287,7 @@ public class ResourceProviderDstu2Test {
response.close();
}
}
@Test
public void testSearchWithInclude() throws Exception {
Organization org = new Organization();
@ -317,6 +318,59 @@ public class ResourceProviderDstu2Test {
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
}
@Test
public void testSearchWithMissing() throws Exception {
String methodName = "testSearchWithMissing";
Organization org = new Organization();
org.addIdentifier().setSystem("urn:system:rpdstu2").setValue(methodName + "01");
org.setName(methodName + "name");
IdDt orgNotMissing = ourClient.create().resource(org).prettyPrint().encodedXml().execute().getId().toUnqualifiedVersionless();
org = new Organization();
org.addIdentifier().setSystem("urn:system:rpdstu2").setValue(methodName + "01");
IdDt orgMissing = ourClient.create().resource(org).prettyPrint().encodedXml().execute().getId().toUnqualifiedVersionless();
{
//@formatter:off
Bundle found = ourClient
.search()
.forResource(Organization.class)
.where(Organization.NAME.isMissing(false))
.prettyPrint()
.execute();
//@formatter:on
List<IdDt> list = toIdListUnqualifiedVersionless(found);
ourLog.info(list.toString());
assertThat(list, containsInRelativeOrder(orgNotMissing));
assertThat(list, not(containsInRelativeOrder(orgMissing)));
}
{
//@formatter:off
Bundle found = ourClient
.search()
.forResource(Organization.class)
.where(Organization.NAME.isMissing(true))
.prettyPrint()
.execute();
//@formatter:on
List<IdDt> list = toIdListUnqualifiedVersionless(found);
ourLog.info(list.toString());
assertThat(list, not(containsInRelativeOrder(orgNotMissing)));
assertThat(list, containsInRelativeOrder(orgMissing));
}
}
private List<IdDt> toIdListUnqualifiedVersionless(Bundle found) {
List<IdDt> list = new ArrayList<IdDt>();
for (BundleEntry next : found.getEntries()) {
list.add(next.getResource().getId().toUnqualifiedVersionless());
}
return list;
}
@Test
public void testEverythingOperation() throws Exception {
String methodName = "testEverythingOperation";
@ -692,7 +746,8 @@ public class ResourceProviderDstu2Test {
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
IdDt p1Id = ourClient.create().resource(p1).execute().getId();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint()
.execute();
assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -790,7 +845,8 @@ public class ResourceProviderDstu2Test {
assertThat(p1Id.getValue(), containsString("Patient/testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2/_history"));
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2")).encodedJson().prettyPrint().execute();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2"))
.encodedJson().prettyPrint().execute();
assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());

View File

@ -147,7 +147,30 @@ public class GenericClientTest {
}
@Test
public void testMissing() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return (new ReaderInputStream(new StringReader(getPatientFeedWithOneResult()), Charset.forName("UTF-8")));
}});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
client.search().forResource("Patient").where(Patient.NAME.isMissing(true)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=true", capt.getValue().getRequestLine().getUri());
client.search().forResource("Patient").where(Patient.NAME.isMissing(false)).execute();
assertEquals("http://example.com/fhir/Patient?name%3Amissing=false", capt.getValue().getRequestLine().getUri());
}
@Test
public void testCreateWithStringAutoDetectsEncoding() throws Exception {

View File

@ -33,6 +33,7 @@ import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.param.StringParam;
/**
* HAPI/FHIR <b>Identifier</b> Datatype
@ -402,5 +403,29 @@ public class IdentifierDt
return null;
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public Boolean getMissing() {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
/**
* <b>Not supported!</b>
*
* @deprecated get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you
* need this functionality
*/
@Deprecated
@Override
public void setMissing(Boolean theMissing) {
throw new UnsupportedOperationException("get/setMissing is not supported in StringDt. Use {@link StringParam} instead if you need this functionality");
}
}

View File

@ -185,9 +185,17 @@
</action>
<action type="add" issue="164">
Improve error message when a user tries to perform a create/update with an invalid
or missing Content-Type header. Thanks to wanghaisheng for reporting!
or missing Content-Type header. Thanks to wanghaisheng for reporting! (This was
actually a three part bug, so the following two fixes also reference this
bug number)
</action>
</release>
<action type="add" issue="164">
Add support for :missing qualifier in generic/fluent client.
</action>
<action type="add" issue="164">
Add support for :missing qualifier in JPA server.
</action>
</release>
<release version="0.9" date="2015-Mar-14">
<action type="add">
Support for DSTU2 features introduced: New resource definitions, Bundle resource,