Custom search parameters could not chain an extension param
This commit is contained in:
parent
5ac91bfb94
commit
7bb9e5edd9
|
@ -24,6 +24,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.substring;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.MathContext;
|
import java.math.MathContext;
|
||||||
|
@ -67,15 +68,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
import ca.uhn.fhir.context.*;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeDeclaredChildDefinition;
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
|
|
||||||
import ca.uhn.fhir.context.RuntimeChildResourceDefinition;
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||||
|
@ -438,27 +431,57 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
List<Class<? extends IBaseResource>> resourceTypes;
|
final List<Class<? extends IBaseResource>> resourceTypes;
|
||||||
String resourceId;
|
String resourceId;
|
||||||
if (!ref.getValue().matches("[a-zA-Z]+\\/.*")) {
|
if (!ref.getValue().matches("[a-zA-Z]+\\/.*")) {
|
||||||
|
|
||||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(myResourceName, theParamName);
|
||||||
String paramPath = myCallingDao.getSearchParamByName(resourceDef, theParamName).getPath();
|
resourceTypes = new ArrayList<Class<? extends IBaseResource>>();
|
||||||
if (paramPath.endsWith(".as(Reference)")) {
|
|
||||||
paramPath = paramPath.substring(0, paramPath.length() - ".as(Reference)".length()) + "Reference";
|
Set<String> targetTypes = param.getTargets();
|
||||||
|
|
||||||
|
if (targetTypes != null && !targetTypes.isEmpty()) {
|
||||||
|
for (String next : targetTypes) {
|
||||||
|
resourceTypes.add(myContext.getResourceDefinition(next).getImplementingClass());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, paramPath);
|
if (resourceTypes.isEmpty()) {
|
||||||
if (def instanceof RuntimeChildChoiceDefinition) {
|
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||||
RuntimeChildChoiceDefinition choiceDef = (RuntimeChildChoiceDefinition) def;
|
String paramPath = myCallingDao.getSearchParamByName(resourceDef, theParamName).getPath();
|
||||||
resourceTypes = choiceDef.getResourceTypes();
|
if (paramPath.endsWith(".as(Reference)")) {
|
||||||
} else if (def instanceof RuntimeChildResourceDefinition) {
|
paramPath = paramPath.substring(0, paramPath.length() - ".as(Reference)".length()) + "Reference";
|
||||||
RuntimeChildResourceDefinition resDef = (RuntimeChildResourceDefinition) def;
|
}
|
||||||
resourceTypes = resDef.getResourceTypes();
|
|
||||||
} else {
|
if (paramPath.contains(".extension(")) {
|
||||||
throw new ConfigurationException("Property " + paramPath + " of type " + myResourceName + " is not a resource: " + def.getClass());
|
int startIdx = paramPath.indexOf(".extension(");
|
||||||
|
int endIdx = paramPath.indexOf(')', startIdx);
|
||||||
|
if (startIdx != -1 && endIdx != -1) {
|
||||||
|
paramPath = paramPath.substring(0, startIdx + 10) + paramPath.substring(endIdx + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, paramPath);
|
||||||
|
if (def instanceof RuntimeChildChoiceDefinition) {
|
||||||
|
RuntimeChildChoiceDefinition choiceDef = (RuntimeChildChoiceDefinition) def;
|
||||||
|
resourceTypes.addAll(choiceDef.getResourceTypes());
|
||||||
|
} else if (def instanceof RuntimeChildResourceDefinition) {
|
||||||
|
RuntimeChildResourceDefinition resDef = (RuntimeChildResourceDefinition) def;
|
||||||
|
resourceTypes.addAll(resDef.getResourceTypes());
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationException("Property " + paramPath + " of type " + myResourceName + " is not a resource: " + def.getClass());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resourceTypes.isEmpty()) {
|
||||||
|
for (BaseRuntimeElementDefinition<?> next : myContext.getElementDefinitions()) {
|
||||||
|
if (next instanceof RuntimeResourceDefinition) {
|
||||||
|
RuntimeResourceDefinition nextResDef = (RuntimeResourceDefinition)next;
|
||||||
|
resourceTypes.add(nextResDef.getImplementingClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resourceId = ref.getValue();
|
resourceId = ref.getValue();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -888,32 +911,32 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
private Predicate createCompositeParamPart(String theResourceName, Root<ResourceTable> theRoot, RuntimeSearchParam theParam, IQueryParameterType leftValue) {
|
private Predicate createCompositeParamPart(String theResourceName, Root<ResourceTable> theRoot, RuntimeSearchParam theParam, IQueryParameterType leftValue) {
|
||||||
Predicate retVal = null;
|
Predicate retVal = null;
|
||||||
switch (theParam.getParamType()) {
|
switch (theParam.getParamType()) {
|
||||||
case STRING: {
|
case STRING: {
|
||||||
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> stringJoin = theRoot.join("myParamsString", JoinType.INNER);
|
From<ResourceIndexedSearchParamString, ResourceIndexedSearchParamString> stringJoin = theRoot.join("myParamsString", JoinType.INNER);
|
||||||
retVal = createPredicateString(leftValue, theResourceName, theParam.getName(), myBuilder, stringJoin);
|
retVal = createPredicateString(leftValue, theResourceName, theParam.getName(), myBuilder, stringJoin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKEN: {
|
case TOKEN: {
|
||||||
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> tokenJoin = theRoot.join("myParamsToken", JoinType.INNER);
|
From<ResourceIndexedSearchParamToken, ResourceIndexedSearchParamToken> tokenJoin = theRoot.join("myParamsToken", JoinType.INNER);
|
||||||
retVal = createPredicateToken(leftValue, theResourceName, theParam.getName(), myBuilder, tokenJoin);
|
retVal = createPredicateToken(leftValue, theResourceName, theParam.getName(), myBuilder, tokenJoin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DATE: {
|
case DATE: {
|
||||||
From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> dateJoin = theRoot.join("myParamsDate", JoinType.INNER);
|
From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> dateJoin = theRoot.join("myParamsDate", JoinType.INNER);
|
||||||
retVal = createPredicateDate(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin);
|
retVal = createPredicateDate(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QUANTITY: {
|
case QUANTITY: {
|
||||||
From<ResourceIndexedSearchParamQuantity, ResourceIndexedSearchParamQuantity> dateJoin = theRoot.join("myParamsQuantity", JoinType.INNER);
|
From<ResourceIndexedSearchParamQuantity, ResourceIndexedSearchParamQuantity> dateJoin = theRoot.join("myParamsQuantity", JoinType.INNER);
|
||||||
retVal = createPredicateQuantity(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin);
|
retVal = createPredicateQuantity(leftValue, theResourceName, theParam.getName(), myBuilder, dateJoin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
case HAS:
|
case HAS:
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
case URI:
|
case URI:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
|
@ -984,41 +1007,41 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
String invalidMessageName) {
|
String invalidMessageName) {
|
||||||
Predicate num;
|
Predicate num;
|
||||||
switch (thePrefix) {
|
switch (thePrefix) {
|
||||||
case GREATERTHAN:
|
case GREATERTHAN:
|
||||||
num = builder.gt(thePath, theValue);
|
num = builder.gt(thePath, theValue);
|
||||||
break;
|
break;
|
||||||
case GREATERTHAN_OR_EQUALS:
|
case GREATERTHAN_OR_EQUALS:
|
||||||
num = builder.ge(thePath, theValue);
|
num = builder.ge(thePath, theValue);
|
||||||
break;
|
break;
|
||||||
case LESSTHAN:
|
case LESSTHAN:
|
||||||
num = builder.lt(thePath, theValue);
|
num = builder.lt(thePath, theValue);
|
||||||
break;
|
break;
|
||||||
case LESSTHAN_OR_EQUALS:
|
case LESSTHAN_OR_EQUALS:
|
||||||
num = builder.le(thePath, theValue);
|
num = builder.le(thePath, theValue);
|
||||||
break;
|
break;
|
||||||
case APPROXIMATE:
|
case APPROXIMATE:
|
||||||
case EQUAL:
|
case EQUAL:
|
||||||
case NOT_EQUAL:
|
case NOT_EQUAL:
|
||||||
BigDecimal mul = calculateFuzzAmount(thePrefix, theValue);
|
BigDecimal mul = calculateFuzzAmount(thePrefix, theValue);
|
||||||
BigDecimal low = theValue.subtract(mul, MathContext.DECIMAL64);
|
BigDecimal low = theValue.subtract(mul, MathContext.DECIMAL64);
|
||||||
BigDecimal high = theValue.add(mul, MathContext.DECIMAL64);
|
BigDecimal high = theValue.add(mul, MathContext.DECIMAL64);
|
||||||
Predicate lowPred;
|
Predicate lowPred;
|
||||||
Predicate highPred;
|
Predicate highPred;
|
||||||
if (thePrefix != ParamPrefixEnum.NOT_EQUAL) {
|
if (thePrefix != ParamPrefixEnum.NOT_EQUAL) {
|
||||||
lowPred = builder.ge(thePath.as(BigDecimal.class), low);
|
lowPred = builder.ge(thePath.as(BigDecimal.class), low);
|
||||||
highPred = builder.le(thePath.as(BigDecimal.class), high);
|
highPred = builder.le(thePath.as(BigDecimal.class), high);
|
||||||
num = builder.and(lowPred, highPred);
|
num = builder.and(lowPred, highPred);
|
||||||
ourLog.trace("Searching for {} <= val <= {}", low, high);
|
ourLog.trace("Searching for {} <= val <= {}", low, high);
|
||||||
} else {
|
} else {
|
||||||
// Prefix was "ne", so reverse it!
|
// Prefix was "ne", so reverse it!
|
||||||
lowPred = builder.lt(thePath.as(BigDecimal.class), low);
|
lowPred = builder.lt(thePath.as(BigDecimal.class), low);
|
||||||
highPred = builder.gt(thePath.as(BigDecimal.class), high);
|
highPred = builder.gt(thePath.as(BigDecimal.class), high);
|
||||||
num = builder.or(lowPred, highPred);
|
num = builder.or(lowPred, highPred);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
String msg = myContext.getLocalizer().getMessage(SearchBuilder.class, invalidMessageName, thePrefix.getValue(), theParam.getValueAsQueryToken(myContext));
|
String msg = myContext.getLocalizer().getMessage(SearchBuilder.class, invalidMessageName, thePrefix.getValue(), theParam.getValueAsQueryToken(myContext));
|
||||||
throw new InvalidRequestException(msg);
|
throw new InvalidRequestException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theParamName == null) {
|
if (theParamName == null) {
|
||||||
|
@ -1388,36 +1411,36 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
String[] sortAttrName;
|
String[] sortAttrName;
|
||||||
|
|
||||||
switch (param.getParamType()) {
|
switch (param.getParamType()) {
|
||||||
case STRING:
|
case STRING:
|
||||||
joinAttrName = "myParamsString";
|
joinAttrName = "myParamsString";
|
||||||
sortAttrName = new String[] { "myValueExact" };
|
sortAttrName = new String[] { "myValueExact" };
|
||||||
break;
|
break;
|
||||||
case DATE:
|
case DATE:
|
||||||
joinAttrName = "myParamsDate";
|
joinAttrName = "myParamsDate";
|
||||||
sortAttrName = new String[] { "myValueLow" };
|
sortAttrName = new String[] { "myValueLow" };
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
joinAttrName = "myResourceLinks";
|
joinAttrName = "myResourceLinks";
|
||||||
sortAttrName = new String[] { "myTargetResourcePid" };
|
sortAttrName = new String[] { "myTargetResourcePid" };
|
||||||
break;
|
break;
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
joinAttrName = "myParamsToken";
|
joinAttrName = "myParamsToken";
|
||||||
sortAttrName = new String[] { "mySystem", "myValue" };
|
sortAttrName = new String[] { "mySystem", "myValue" };
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
joinAttrName = "myParamsNumber";
|
joinAttrName = "myParamsNumber";
|
||||||
sortAttrName = new String[] { "myValue" };
|
sortAttrName = new String[] { "myValue" };
|
||||||
break;
|
break;
|
||||||
case URI:
|
case URI:
|
||||||
joinAttrName = "myParamsUri";
|
joinAttrName = "myParamsUri";
|
||||||
sortAttrName = new String[] { "myUri" };
|
sortAttrName = new String[] { "myUri" };
|
||||||
break;
|
break;
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
joinAttrName = "myParamsQuantity";
|
joinAttrName = "myParamsQuantity";
|
||||||
sortAttrName = new String[] { "myValue" };
|
sortAttrName = new String[] { "myValue" };
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidRequestException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName());
|
throw new InvalidRequestException("This server does not support _sort specifications of type " + param.getParamType() + " - Can't serve _sort=" + theSort.getParamName());
|
||||||
}
|
}
|
||||||
|
|
||||||
From<?, ?> join = theFrom.join(joinAttrName, JoinType.LEFT);
|
From<?, ?> join = theFrom.join(joinAttrName, JoinType.LEFT);
|
||||||
|
@ -1500,10 +1523,10 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
for (int i = 0; i < pids.size(); i += maxLoad) {
|
for (int i = 0; i < pids.size(); i += maxLoad) {
|
||||||
int to = i + maxLoad;
|
int to = i + maxLoad;
|
||||||
to = Math.min(to, pids.size());
|
to = Math.min(to, pids.size());
|
||||||
List<Long> pidsSubList = pids.subList(i, to);
|
List<Long> pidsSubList = pids.subList(i, to);
|
||||||
doLoadPids(theResourceListToPopulate, theRevIncludedPids, theForHistoryOperation, entityManager, context, theDao, position, pidsSubList);
|
doLoadPids(theResourceListToPopulate, theRevIncludedPids, theForHistoryOperation, entityManager, context, theDao, position, pidsSubList);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLoadPids(List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager entityManager, FhirContext context, IDao theDao,
|
private void doLoadPids(List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager entityManager, FhirContext context, IDao theDao,
|
||||||
|
@ -1724,49 +1747,49 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
|
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
|
||||||
if (nextParamDef != null) {
|
if (nextParamDef != null) {
|
||||||
switch (nextParamDef.getParamType()) {
|
switch (nextParamDef.getParamType()) {
|
||||||
case DATE:
|
case DATE:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateDate(theResourceName, theParamName, nextAnd);
|
addPredicateDate(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateQuantity(theResourceName, theParamName, nextAnd);
|
addPredicateQuantity(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateReference(theResourceName, theParamName, nextAnd);
|
addPredicateReference(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateString(theResourceName, theParamName, nextAnd);
|
addPredicateString(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateToken(theResourceName, theParamName, nextAnd);
|
addPredicateToken(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateNumber(theResourceName, theParamName, nextAnd);
|
addPredicateNumber(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateComposite(theResourceName, nextParamDef, nextAnd);
|
addPredicateComposite(theResourceName, nextParamDef, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case URI:
|
case URI:
|
||||||
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
|
||||||
addPredicateUri(theResourceName, theParamName, nextAnd);
|
addPredicateUri(theResourceName, theParamName, nextAnd);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HAS:
|
case HAS:
|
||||||
// should not happen
|
// should not happen
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (Constants.PARAM_CONTENT.equals(theParamName) || Constants.PARAM_TEXT.equals(theParamName)) {
|
if (Constants.PARAM_CONTENT.equals(theParamName) || Constants.PARAM_TEXT.equals(theParamName)) {
|
||||||
|
@ -1786,35 +1809,35 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
private IQueryParameterType toParameterType(RuntimeSearchParam theParam) {
|
private IQueryParameterType toParameterType(RuntimeSearchParam theParam) {
|
||||||
IQueryParameterType qp;
|
IQueryParameterType qp;
|
||||||
switch (theParam.getParamType()) {
|
switch (theParam.getParamType()) {
|
||||||
case DATE:
|
case DATE:
|
||||||
qp = new DateParam();
|
qp = new DateParam();
|
||||||
break;
|
break;
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
qp = new NumberParam();
|
qp = new NumberParam();
|
||||||
break;
|
break;
|
||||||
case QUANTITY:
|
case QUANTITY:
|
||||||
qp = new QuantityParam();
|
qp = new QuantityParam();
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
qp = new StringParam();
|
qp = new StringParam();
|
||||||
break;
|
break;
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
qp = new TokenParam();
|
qp = new TokenParam();
|
||||||
break;
|
break;
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
List<RuntimeSearchParam> compositeOf = theParam.getCompositeOf();
|
List<RuntimeSearchParam> compositeOf = theParam.getCompositeOf();
|
||||||
if (compositeOf.size() != 2) {
|
if (compositeOf.size() != 2) {
|
||||||
throw new InternalErrorException("Parameter " + theParam.getName() + " has " + compositeOf.size() + " composite parts. Don't know how handlt this.");
|
throw new InternalErrorException("Parameter " + theParam.getName() + " has " + compositeOf.size() + " composite parts. Don't know how handlt this.");
|
||||||
}
|
}
|
||||||
IQueryParameterType leftParam = toParameterType(compositeOf.get(0));
|
IQueryParameterType leftParam = toParameterType(compositeOf.get(0));
|
||||||
IQueryParameterType rightParam = toParameterType(compositeOf.get(1));
|
IQueryParameterType rightParam = toParameterType(compositeOf.get(1));
|
||||||
qp = new CompositeParam<IQueryParameterType, IQueryParameterType>(leftParam, rightParam);
|
qp = new CompositeParam<IQueryParameterType, IQueryParameterType>(leftParam, rightParam);
|
||||||
break;
|
break;
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
qp = new ReferenceParam();
|
qp = new ReferenceParam();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType());
|
||||||
}
|
}
|
||||||
return qp;
|
return qp;
|
||||||
}
|
}
|
||||||
|
@ -1908,8 +1931,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchNext() {
|
private void fetchNext() {
|
||||||
|
|
||||||
// If we don't have
|
// If we don't have
|
||||||
if (myResultsIterator == null) {
|
if (myResultsIterator == null) {
|
||||||
final TypedQuery<Long> query = createQuery(mySort);
|
final TypedQuery<Long> query = createQuery(mySort);
|
||||||
myResultsIterator = query.getResultList().iterator();
|
myResultsIterator = query.getResultList().iterator();
|
||||||
|
|
|
@ -38,7 +38,7 @@ public abstract class BaseResourceIndexedSearchParam implements Serializable {
|
||||||
// TODO: make this nullable=false and a primitive (written may 2017)
|
// TODO: make this nullable=false and a primitive (written may 2017)
|
||||||
@Field()
|
@Field()
|
||||||
@Column(name = "SP_MISSING", nullable = true)
|
@Column(name = "SP_MISSING", nullable = true)
|
||||||
private Boolean myMissing;
|
private Boolean myMissing = Boolean.FALSE;
|
||||||
|
|
||||||
@Field
|
@Field
|
||||||
@Column(name = "SP_NAME", length = MAX_SP_NAME, nullable = false)
|
@Column(name = "SP_NAME", length = MAX_SP_NAME, nullable = false)
|
||||||
|
|
|
@ -201,35 +201,134 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchForExtensionReference() {
|
public void testSearchForExtensionReferenceWithNonMatchingTarget() {
|
||||||
|
SearchParameter siblingSp = new SearchParameter();
|
||||||
|
siblingSp.addBase("Patient");
|
||||||
SearchParameter eyeColourSp = new SearchParameter();
|
siblingSp.setCode("sibling");
|
||||||
eyeColourSp.addBase("Patient");
|
siblingSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE);
|
||||||
eyeColourSp.setCode("sibling");
|
siblingSp.setTitle("Sibling");
|
||||||
eyeColourSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE);
|
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||||
eyeColourSp.setTitle("Sibling");
|
siblingSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||||
eyeColourSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||||
eyeColourSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||||
eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
mySearchParameterDao.create(siblingSp, mySrd);
|
||||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
|
||||||
|
|
||||||
mySearchParamRegsitry.forceRefresh();
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
p1.setActive(true);
|
p1.addName().setFamily("P1");
|
||||||
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient p2 = new Patient();
|
Patient p2 = new Patient();
|
||||||
p2.setActive(true);
|
p2.addName().setFamily("P2");
|
||||||
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||||
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
// Try with custom gender SP
|
SearchParameterMap map;
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
IBundleProvider results;
|
||||||
|
List<String> foundResources;
|
||||||
|
|
||||||
|
// Search by ref
|
||||||
|
map = new SearchParameterMap();
|
||||||
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||||
IBundleProvider results = myPatientDao.search(map);
|
results = myPatientDao.search(map);
|
||||||
List<String> foundResources = toUnqualifiedVersionlessIdValues(results);
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, empty());
|
||||||
|
|
||||||
|
// Search by chain
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, empty());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchForExtensionReferenceWithoutTarget() {
|
||||||
|
SearchParameter siblingSp = new SearchParameter();
|
||||||
|
siblingSp.addBase("Patient");
|
||||||
|
siblingSp.setCode("sibling");
|
||||||
|
siblingSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE);
|
||||||
|
siblingSp.setTitle("Sibling");
|
||||||
|
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||||
|
siblingSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||||
|
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||||
|
mySearchParameterDao.create(siblingSp, mySrd);
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
|
Patient p1 = new Patient();
|
||||||
|
p1.addName().setFamily("P1");
|
||||||
|
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Patient p2 = new Patient();
|
||||||
|
p2.addName().setFamily("P2");
|
||||||
|
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||||
|
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider results;
|
||||||
|
List<String> foundResources;
|
||||||
|
|
||||||
|
// Search by ref
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, contains(p2id.getValue()));
|
||||||
|
|
||||||
|
// Search by chain
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, contains(p2id.getValue()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchForExtensionReferenceWithTarget() {
|
||||||
|
SearchParameter siblingSp = new SearchParameter();
|
||||||
|
siblingSp.addBase("Patient");
|
||||||
|
siblingSp.setCode("sibling");
|
||||||
|
siblingSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE);
|
||||||
|
siblingSp.setTitle("Sibling");
|
||||||
|
siblingSp.setExpression("Patient.extension('http://acme.org/sibling')");
|
||||||
|
siblingSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||||
|
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||||
|
siblingSp.getTarget().add(new CodeType("Patient"));
|
||||||
|
mySearchParameterDao.create(siblingSp, mySrd);
|
||||||
|
|
||||||
|
mySearchParamRegsitry.forceRefresh();
|
||||||
|
|
||||||
|
Patient p1 = new Patient();
|
||||||
|
p1.addName().setFamily("P1");
|
||||||
|
IIdType p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Patient p2 = new Patient();
|
||||||
|
p2.addName().setFamily("P2");
|
||||||
|
p2.addExtension().setUrl("http://acme.org/sibling").setValue(new Reference(p1id));
|
||||||
|
IIdType p2id = myPatientDao.create(p2).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
SearchParameterMap map;
|
||||||
|
IBundleProvider results;
|
||||||
|
List<String> foundResources;
|
||||||
|
|
||||||
|
// Search by ref
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("sibling", new ReferenceParam(p1id.getValue()));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
assertThat(foundResources, contains(p2id.getValue()));
|
||||||
|
|
||||||
|
// Search by chain
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add("sibling", new ReferenceParam("name", "P1"));
|
||||||
|
results = myPatientDao.search(map);
|
||||||
|
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||||
assertThat(foundResources, contains(p2id.getValue()));
|
assertThat(foundResources, contains(p2id.getValue()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,10 @@
|
||||||
will live after all. Interceptors registered to this method will now be treated
|
will live after all. Interceptors registered to this method will now be treated
|
||||||
appropriately if they implement IServerOperationInterceptor too.
|
appropriately if they implement IServerOperationInterceptor too.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
JPA server did not correctly support searching on a custom search parameter whose
|
||||||
|
path pointed to an extension, where the client used a chained value.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="2.4" date="2017-04-19">
|
<release version="2.4" date="2017-04-19">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue