compiles. now to run the tests...

This commit is contained in:
Ken Stevens 2020-01-23 15:43:41 -05:00
parent 49743352a6
commit ab74e66870
17 changed files with 352 additions and 232 deletions

View File

@ -26,7 +26,6 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao; import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao; import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
@ -38,10 +37,8 @@ import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails; import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage; import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam; import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
import ca.uhn.fhir.jpa.util.*; import ca.uhn.fhir.jpa.util.*;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
@ -130,12 +127,9 @@ public class SearchBuilder implements ISearchBuilder {
private List<ResourcePersistentId> myAlsoIncludePids; private List<ResourcePersistentId> myAlsoIncludePids;
private CriteriaBuilder myBuilder; private CriteriaBuilder myBuilder;
private BaseHapiFhirDao<?> myCallingDao; private BaseHapiFhirDao<?> myCallingDao;
private IndexJoins myIndexJoins = new IndexJoins();
private SearchParameterMap myParams; private SearchParameterMap myParams;
private ArrayList<Predicate> myPredicates;
private String myResourceName; private String myResourceName;
private AbstractQuery<Long> myResourceTableQuery; private AbstractQuery<Long> myResourceTableQuery;
private Root<ResourceTable> myResourceTableRoot;
private Class<? extends IBaseResource> myResourceType; private Class<? extends IBaseResource> myResourceType;
private String mySearchUuid; private String mySearchUuid;
private int myFetchSize; private int myFetchSize;
@ -143,6 +137,7 @@ public class SearchBuilder implements ISearchBuilder {
private Set<ResourcePersistentId> myPidSet; private Set<ResourcePersistentId> myPidSet;
private boolean myHaveIndexJoins = false; private boolean myHaveIndexJoins = false;
private PredicateBuilder myPredicateBuilder; private PredicateBuilder myPredicateBuilder;
private final QueryRoot myQueryRoot = new QueryRoot();
/** /**
* Constructor * Constructor
@ -227,8 +222,6 @@ public class SearchBuilder implements ISearchBuilder {
} }
private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount, RequestDetails theRequest) { private TypedQuery<Long> createQuery(SortSpec sort, Integer theMaximumResults, boolean theCount, RequestDetails theRequest) {
myPredicates = new ArrayList<>();
CriteriaQuery<Long> outerQuery; CriteriaQuery<Long> outerQuery;
/* /*
* Sort * Sort
@ -241,17 +234,16 @@ public class SearchBuilder implements ISearchBuilder {
outerQuery = myBuilder.createQuery(Long.class); outerQuery = myBuilder.createQuery(Long.class);
myResourceTableQuery = outerQuery; myResourceTableQuery = outerQuery;
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class); myQueryRoot.push(myResourceTableQuery.from(ResourceTable.class));
if (theCount) { if (theCount) {
outerQuery.multiselect(myBuilder.countDistinct(myResourceTableRoot)); outerQuery.multiselect(myBuilder.countDistinct(myQueryRoot.getRoot()));
} else { } else {
outerQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); outerQuery.multiselect(myQueryRoot.get("myId").as(Long.class));
} }
List<Order> orders = Lists.newArrayList(); List<Order> orders = Lists.newArrayList();
List<Predicate> predicates = myPredicates; // Lists.newArrayList();
createSort(myBuilder, myResourceTableRoot, sort, orders, predicates); createSort(myBuilder, myQueryRoot, sort, orders);
if (orders.size() > 0) { if (orders.size() > 0) {
outerQuery.orderBy(orders); outerQuery.orderBy(orders);
} }
@ -260,18 +252,18 @@ public class SearchBuilder implements ISearchBuilder {
outerQuery = myBuilder.createQuery(Long.class); outerQuery = myBuilder.createQuery(Long.class);
myResourceTableQuery = outerQuery; myResourceTableQuery = outerQuery;
myResourceTableRoot = myResourceTableQuery.from(ResourceTable.class); myQueryRoot.push(myResourceTableQuery.from(ResourceTable.class));
if (theCount) { if (theCount) {
outerQuery.multiselect(myBuilder.countDistinct(myResourceTableRoot)); outerQuery.multiselect(myBuilder.countDistinct(myQueryRoot.getRoot()));
} else { } else {
outerQuery.multiselect(myResourceTableRoot.get("myId").as(Long.class)); outerQuery.multiselect(myQueryRoot.get("myId").as(Long.class));
outerQuery.distinct(true); outerQuery.distinct(true);
} }
} }
if (myParams.getEverythingMode() != null) { if (myParams.getEverythingMode() != null) {
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT); Join<ResourceTable, ResourceLink> join = myQueryRoot.join("myResourceLinks", JoinType.LEFT);
if (myParams.get(IAnyResource.SP_RES_ID) != null) { if (myParams.get(IAnyResource.SP_RES_ID) != null) {
StringParam idParm = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0); StringParam idParm = (StringParam) myParams.get(IAnyResource.SP_RES_ID).get(0).get(0);
@ -280,11 +272,11 @@ public class SearchBuilder implements ISearchBuilder {
myAlsoIncludePids = new ArrayList<>(1); myAlsoIncludePids = new ArrayList<>(1);
} }
myAlsoIncludePids.add(pid); myAlsoIncludePids.add(pid);
myPredicates.add(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid.getIdAsLong())); myQueryRoot.addPredicate(myBuilder.equal(join.get("myTargetResourcePid").as(Long.class), pid.getIdAsLong()));
} else { } else {
Predicate targetTypePredicate = myBuilder.equal(join.get("myTargetResourceType").as(String.class), myResourceName); Predicate targetTypePredicate = myBuilder.equal(join.get("myTargetResourceType").as(String.class), myResourceName);
Predicate sourceTypePredicate = myBuilder.equal(myResourceTableRoot.get("myResourceType").as(String.class), myResourceName); Predicate sourceTypePredicate = myBuilder.equal(myQueryRoot.get("myResourceType").as(String.class), myResourceName);
myPredicates.add(myBuilder.or(sourceTypePredicate, targetTypePredicate)); myQueryRoot.addPredicate(myBuilder.or(sourceTypePredicate, targetTypePredicate));
} }
} else { } else {
@ -315,7 +307,7 @@ public class SearchBuilder implements ISearchBuilder {
pids = Collections.singletonList(new ResourcePersistentId(-1L)); pids = Collections.singletonList(new ResourcePersistentId(-1L));
} }
myPredicates.add(myResourceTableRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(pids))); myQueryRoot.addPredicate(myQueryRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(pids)));
} }
/* /*
@ -327,17 +319,17 @@ public class SearchBuilder implements ISearchBuilder {
*/ */
if (!myHaveIndexJoins) { if (!myHaveIndexJoins) {
if (myParams.getEverythingMode() == null) { if (myParams.getEverythingMode() == null) {
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), myResourceName)); myQueryRoot.addPredicate(myBuilder.equal(myQueryRoot.get("myResourceType"), myResourceName));
} }
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); myQueryRoot.addPredicate(myBuilder.isNull(myQueryRoot.get("myDeleted")));
} }
// Last updated // Last updated
DateRangeParam lu = myParams.getLastUpdated(); DateRangeParam lu = myParams.getLastUpdated();
List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myResourceTableRoot); List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(lu, myBuilder, myQueryRoot.getRoot());
myPredicates.addAll(lastUpdatedPredicates); myQueryRoot.addPredicates(lastUpdatedPredicates);
myResourceTableQuery.where(myBuilder.and(SearchBuilder.toArray(myPredicates))); myResourceTableQuery.where(myBuilder.and(myQueryRoot.getPredicateArray()));
/* /*
* Now perform the search * Now perform the search
@ -355,32 +347,32 @@ public class SearchBuilder implements ISearchBuilder {
* @return Returns {@literal true} if any search parameter sorts were found, or false if * @return Returns {@literal true} if any search parameter sorts were found, or false if
* no sorts were found, or only non-search parameters ones (e.g. _id, _lastUpdated) * no sorts were found, or only non-search parameters ones (e.g. _id, _lastUpdated)
*/ */
private boolean createSort(CriteriaBuilder theBuilder, Root<ResourceTable> theFrom, SortSpec theSort, List<Order> theOrders, List<Predicate> thePredicates) { private boolean createSort(CriteriaBuilder theBuilder, QueryRoot theQueryRoot, SortSpec theSort, List<Order> theOrders) {
if (theSort == null || isBlank(theSort.getParamName())) { if (theSort == null || isBlank(theSort.getParamName())) {
return false; return false;
} }
if (IAnyResource.SP_RES_ID.equals(theSort.getParamName())) { if (IAnyResource.SP_RES_ID.equals(theSort.getParamName())) {
From<?, ?> forcedIdJoin = theFrom.join("myForcedId", JoinType.LEFT); From<?, ?> forcedIdJoin = theQueryRoot.join("myForcedId", JoinType.LEFT);
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) { if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(forcedIdJoin.get("myForcedId"))); theOrders.add(theBuilder.asc(forcedIdJoin.get("myForcedId")));
theOrders.add(theBuilder.asc(theFrom.get("myId"))); theOrders.add(theBuilder.asc(theQueryRoot.get("myId")));
} else { } else {
theOrders.add(theBuilder.desc(forcedIdJoin.get("myForcedId"))); theOrders.add(theBuilder.desc(forcedIdJoin.get("myForcedId")));
theOrders.add(theBuilder.desc(theFrom.get("myId"))); theOrders.add(theBuilder.desc(theQueryRoot.get("myId")));
} }
return createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates); return createSort(theBuilder, theQueryRoot, theSort.getChain(), theOrders);
} }
if (Constants.PARAM_LASTUPDATED.equals(theSort.getParamName())) { if (Constants.PARAM_LASTUPDATED.equals(theSort.getParamName())) {
if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) { if (theSort.getOrder() == null || theSort.getOrder() == SortOrderEnum.ASC) {
theOrders.add(theBuilder.asc(theFrom.get("myUpdated"))); theOrders.add(theBuilder.asc(theQueryRoot.get("myUpdated")));
} else { } else {
theOrders.add(theBuilder.desc(theFrom.get("myUpdated"))); theOrders.add(theBuilder.desc(theQueryRoot.get("myUpdated")));
} }
return createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates); return createSort(theBuilder, theQueryRoot, theSort.getChain(), theOrders);
} }
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName); RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName);
@ -441,20 +433,20 @@ public class SearchBuilder implements ISearchBuilder {
* sorting on, we'll also sort with it. Otherwise we need a new join. * sorting on, we'll also sort with it. Otherwise we need a new join.
*/ */
SearchBuilderJoinKey key = new SearchBuilderJoinKey(theSort.getParamName(), joinType); SearchBuilderJoinKey key = new SearchBuilderJoinKey(theSort.getParamName(), joinType);
Join<?, ?> join = myIndexJoins.get(key); Join<?, ?> join = theQueryRoot.getIndexJoin(key);
if (join == null) { if (join == null) {
join = theFrom.join(joinAttrName, JoinType.LEFT); join = theQueryRoot.join(joinAttrName, JoinType.LEFT);
if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) { if (param.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
thePredicates.add(join.get("mySourcePath").as(String.class).in(param.getPathsSplit())); theQueryRoot.addPredicate(join.get("mySourcePath").as(String.class).in(param.getPathsSplit()));
} else { } else {
if (myDontUseHashesForSearch) { if (myDontUseHashesForSearch) {
Predicate joinParam1 = theBuilder.equal(join.get("myParamName"), theSort.getParamName()); Predicate joinParam1 = theBuilder.equal(join.get("myParamName"), theSort.getParamName());
thePredicates.add(joinParam1); theQueryRoot.addPredicate(joinParam1);
} else { } else {
Long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(myResourceName, theSort.getParamName()); Long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(myResourceName, theSort.getParamName());
Predicate joinParam1 = theBuilder.equal(join.get("myHashIdentity"), hashIdentity); Predicate joinParam1 = theBuilder.equal(join.get("myHashIdentity"), hashIdentity);
thePredicates.add(joinParam1); theQueryRoot.addPredicate(joinParam1);
} }
} }
} else { } else {
@ -469,7 +461,7 @@ public class SearchBuilder implements ISearchBuilder {
} }
} }
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates); createSort(theBuilder, theQueryRoot, theSort.getChain(), theOrders);
return true; return true;
} }
@ -863,9 +855,9 @@ public class SearchBuilder implements ISearchBuilder {
private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexdString) { private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexdString) {
myHaveIndexJoins = true; myHaveIndexJoins = true;
Join<ResourceTable, ResourceIndexedCompositeStringUnique> join = myResourceTableRoot.join("myParamsCompositeStringUnique", JoinType.LEFT); Join<ResourceTable, ResourceIndexedCompositeStringUnique> join = myQueryRoot.join("myParamsCompositeStringUnique", JoinType.LEFT);
Predicate predicate = myBuilder.equal(join.get("myIndexString"), theIndexdString); Predicate predicate = myBuilder.equal(join.get("myIndexString"), theIndexdString);
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
// Remove any empty parameters remaining after this // Remove any empty parameters remaining after this
theParams.clean(); theParams.clean();
@ -901,16 +893,8 @@ public class SearchBuilder implements ISearchBuilder {
return myBuilder; return myBuilder;
} }
public Root<ResourceTable> getResourceTableRoot() { public QueryRoot getQueryRoot() {
return myResourceTableRoot; return myQueryRoot;
}
public IndexJoins getIndexJoins() {
return myIndexJoins;
}
public ArrayList<Predicate> getPredicates() {
return myPredicates;
} }
public AbstractQuery<Long> getResourceTableQuery() { public AbstractQuery<Long> getResourceTableQuery() {
@ -1220,13 +1204,13 @@ public class SearchBuilder implements ISearchBuilder {
List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from); List<Predicate> lastUpdatedPredicates = createLastUpdatedPredicates(theLastUpdated, builder, from);
lastUpdatedPredicates.add(from.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(thePids))); lastUpdatedPredicates.add(from.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(thePids)));
cq.where(SearchBuilder.toArray(lastUpdatedPredicates)); cq.where(SearchBuilder.toPredicateArray(lastUpdatedPredicates));
TypedQuery<Long> query = theEntityManager.createQuery(cq); TypedQuery<Long> query = theEntityManager.createQuery(cq);
return ResourcePersistentId.fromLongList(query.getResultList()); return ResourcePersistentId.fromLongList(query.getResultList());
} }
private static Predicate[] toArray(List<Predicate> thePredicates) { private static Predicate[] toPredicateArray(List<Predicate> thePredicates) {
return thePredicates.toArray(new Predicate[0]); return thePredicates.toArray(new Predicate[0]);
} }
} }

View File

@ -34,9 +34,7 @@ abstract class BasePredicateBuilder {
boolean myDontUseHashesForSearch; boolean myDontUseHashesForSearch;
final BaseHapiFhirDao<?> myCallingDao; final BaseHapiFhirDao<?> myCallingDao;
final CriteriaBuilder myBuilder; final CriteriaBuilder myBuilder;
final Root<ResourceTable> myResourceTableRoot; final QueryRoot myQueryRoot;
final IndexJoins myIndexJoins;
final ArrayList<Predicate> myPredicates;
final Class<? extends IBaseResource> myResourceType; final Class<? extends IBaseResource> myResourceType;
final String myResourceName; final String myResourceName;
final AbstractQuery<Long> myResourceTableQuery; final AbstractQuery<Long> myResourceTableQuery;
@ -46,9 +44,7 @@ abstract class BasePredicateBuilder {
BasePredicateBuilder(SearchBuilder theSearchBuilder) { BasePredicateBuilder(SearchBuilder theSearchBuilder) {
myCallingDao = theSearchBuilder.getCallingDao(); myCallingDao = theSearchBuilder.getCallingDao();
myBuilder = theSearchBuilder.getBuilder(); myBuilder = theSearchBuilder.getBuilder();
myResourceTableRoot = theSearchBuilder.getResourceTableRoot(); myQueryRoot = theSearchBuilder.getQueryRoot();
myIndexJoins = theSearchBuilder.getIndexJoins();
myPredicates = theSearchBuilder.getPredicates();
myResourceType = theSearchBuilder.getResourceType(); myResourceType = theSearchBuilder.getResourceType();
myResourceName = theSearchBuilder.getResourceName(); myResourceName = theSearchBuilder.getResourceName();
myResourceTableQuery = theSearchBuilder.getResourceTableQuery(); myResourceTableQuery = theSearchBuilder.getResourceTableQuery();
@ -65,59 +61,59 @@ abstract class BasePredicateBuilder {
Join<ResourceTable, ResourceIndexedSearchParamDate> join = null; Join<ResourceTable, ResourceIndexedSearchParamDate> join = null;
switch (theType) { switch (theType) {
case DATE: case DATE:
join = myResourceTableRoot.join("myParamsDate", JoinType.LEFT); join = myQueryRoot.join("myParamsDate", JoinType.LEFT);
break; break;
case NUMBER: case NUMBER:
join = myResourceTableRoot.join("myParamsNumber", JoinType.LEFT); join = myQueryRoot.join("myParamsNumber", JoinType.LEFT);
break; break;
case QUANTITY: case QUANTITY:
join = myResourceTableRoot.join("myParamsQuantity", JoinType.LEFT); join = myQueryRoot.join("myParamsQuantity", JoinType.LEFT);
break; break;
case REFERENCE: case REFERENCE:
join = myResourceTableRoot.join("myResourceLinks", JoinType.LEFT); join = myQueryRoot.join("myResourceLinks", JoinType.LEFT);
break; break;
case STRING: case STRING:
join = myResourceTableRoot.join("myParamsString", JoinType.LEFT); join = myQueryRoot.join("myParamsString", JoinType.LEFT);
break; break;
case URI: case URI:
join = myResourceTableRoot.join("myParamsUri", JoinType.LEFT); join = myQueryRoot.join("myParamsUri", JoinType.LEFT);
break; break;
case TOKEN: case TOKEN:
join = myResourceTableRoot.join("myParamsToken", JoinType.LEFT); join = myQueryRoot.join("myParamsToken", JoinType.LEFT);
break; break;
case COORDS: case COORDS:
join = myResourceTableRoot.join("myParamsCoords", JoinType.LEFT); join = myQueryRoot.join("myParamsCoords", JoinType.LEFT);
break; break;
} }
SearchBuilderJoinKey key = new SearchBuilderJoinKey(theSearchParameterName, theType); SearchBuilderJoinKey key = new SearchBuilderJoinKey(theSearchParameterName, theType);
myIndexJoins.put(key, join); myQueryRoot.putIndex(key, join);
return (Join<ResourceTable, T>) join; return (Join<ResourceTable, T>) join;
} }
void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing) { void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing) {
// if (myDontUseHashesForSearch) { // if (myDontUseHashesForSearch) {
// Join<ResourceTable, SearchParamPresent> paramPresentJoin = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT); // Join<ResourceTable, SearchParamPresent> paramPresentJoin = myQueryRoot.join("mySearchParamPresents", JoinType.LEFT);
// Join<Object, Object> paramJoin = paramPresentJoin.join("mySearchParam", JoinType.LEFT); // Join<Object, Object> paramJoin = paramPresentJoin.join("mySearchParam", JoinType.LEFT);
// //
// myPredicates.add(myBuilder.equal(paramJoin.get("myResourceName"), theResourceName)); // myQueryRoot.addPredicate(myBuilder.equal(paramJoin.get("myResourceName"), theResourceName));
// myPredicates.add(myBuilder.equal(paramJoin.get("myParamName"), theParamName)); // myQueryRoot.addPredicate(myBuilder.equal(paramJoin.get("myParamName"), theParamName));
// myPredicates.add(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing)); // myQueryRoot.addPredicate(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing));
// } // }
Join<ResourceTable, SearchParamPresent> paramPresentJoin = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT); Join<ResourceTable, SearchParamPresent> paramPresentJoin = myQueryRoot.join("mySearchParamPresents", JoinType.LEFT);
Expression<Long> hashPresence = paramPresentJoin.get("myHashPresence").as(Long.class); Expression<Long> hashPresence = paramPresentJoin.get("myHashPresence").as(Long.class);
Long hash = SearchParamPresent.calculateHashPresence(theResourceName, theParamName, !theMissing); Long hash = SearchParamPresent.calculateHashPresence(theResourceName, theParamName, !theMissing);
myPredicates.add(myBuilder.equal(hashPresence, hash)); myQueryRoot.addPredicate(myBuilder.equal(hashPresence, hash));
} }
void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing, Join<ResourceTable, ? extends BaseResourceIndexedSearchParam> theJoin) { void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing, Join<ResourceTable, ? extends BaseResourceIndexedSearchParam> theJoin) {
myPredicates.add(myBuilder.equal(theJoin.get("myResourceType"), theResourceName)); myQueryRoot.addPredicate(myBuilder.equal(theJoin.get("myResourceType"), theResourceName));
myPredicates.add(myBuilder.equal(theJoin.get("myParamName"), theParamName)); myQueryRoot.addPredicate(myBuilder.equal(theJoin.get("myParamName"), theParamName));
myPredicates.add(myBuilder.equal(theJoin.get("myMissing"), theMissing)); myQueryRoot.addPredicate(myBuilder.equal(theJoin.get("myMissing"), theMissing));
} }
Predicate combineParamIndexPredicateWithParamNamePredicate(String theResourceName, String theParamName, From<?, ? extends BaseResourceIndexedSearchParam> theFrom, Predicate thePredicate) { Predicate combineParamIndexPredicateWithParamNamePredicate(String theResourceName, String theParamName, From<?, ? extends BaseResourceIndexedSearchParam> theFrom, Predicate thePredicate) {
@ -133,7 +129,6 @@ abstract class BasePredicateBuilder {
return myBuilder.and(hashIdentityPredicate, thePredicate); return myBuilder.and(hashIdentityPredicate, thePredicate);
} }
Predicate createPredicateNumeric(String theResourceName, Predicate createPredicateNumeric(String theResourceName,
String theParamName, String theParamName,
From<?, ? extends BaseResourceIndexedSearchParam> theFrom, From<?, ? extends BaseResourceIndexedSearchParam> theFrom,
@ -166,7 +161,7 @@ abstract class BasePredicateBuilder {
num = builder.notEqual(thePath, theValue); num = builder.notEqual(thePath, theValue);
break; break;
case APPROXIMATE: case APPROXIMATE:
BigDecimal mul = calculateFuzzAmount(thePrefix, theValue); BigDecimal mul = FuzzCalculator.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;
@ -189,28 +184,6 @@ abstract class BasePredicateBuilder {
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num); return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num);
} }
/**
* Figures out the tolerance for a search. For example, if the user is searching for <code>4.00</code>, this method
* returns <code>0.005</code> because we shold actually match values which are
* <code>4 (+/-) 0.005</code> according to the FHIR specs.
*/
static BigDecimal calculateFuzzAmount(ParamPrefixEnum cmpValue, BigDecimal theValue) {
if (cmpValue == ParamPrefixEnum.APPROXIMATE) {
return theValue.multiply(new BigDecimal(0.1));
} else {
String plainString = theValue.toPlainString();
int dotIdx = plainString.indexOf('.');
if (dotIdx == -1) {
return new BigDecimal(0.5);
}
int precision = plainString.length() - (dotIdx);
double mul = Math.pow(10, -precision);
double val = mul * 5.0d;
return new BigDecimal(val);
}
}
static String createLeftAndRightMatchLikeExpression(String likeExpression) { static String createLeftAndRightMatchLikeExpression(String likeExpression) {
return "%" + likeExpression.replace("%", "[%]") + "%"; return "%" + likeExpression.replace("%", "[%]") + "%";
} }

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.jpa.dao.predicate;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import java.math.BigDecimal;
public interface FuzzCalculator {
/**
* Figures out the tolerance for a search. For example, if the user is searching for <code>4.00</code>, this method
* returns <code>0.005</code> because we shold actually match values which are
* <code>4 (+/-) 0.005</code> according to the FHIR specs.
*/
static BigDecimal calculateFuzzAmount(ParamPrefixEnum cmpValue, BigDecimal theValue) {
if (cmpValue == ParamPrefixEnum.APPROXIMATE) {
return theValue.multiply(new BigDecimal(0.1));
} else {
String plainString = theValue.toPlainString();
int dotIdx = plainString.indexOf('.');
if (dotIdx == -1) {
return new BigDecimal(0.5);
}
int precision = plainString.length() - (dotIdx);
double mul = Math.pow(10, -precision);
double val = mul * 5.0d;
return new BigDecimal(val);
}
}
}

View File

@ -129,7 +129,7 @@ public class PredicateBuilderCoords extends BasePredicateBuilder {
} }
Predicate retVal = myBuilder.or(toArray(codePredicates)); Predicate retVal = myBuilder.or(toArray(codePredicates));
myPredicates.add(retVal); myQueryRoot.addPredicate(retVal);
return retVal; return retVal;
} }
} }

View File

@ -52,12 +52,10 @@ public class PredicateBuilderDate extends BasePredicateBuilder {
} }
Predicate orPredicates = myBuilder.or(toArray(codePredicates)); Predicate orPredicates = myBuilder.or(toArray(codePredicates));
myPredicates.add(orPredicates); myQueryRoot.addPredicate(orPredicates);
return orPredicates; return orPredicates;
} }
public Predicate createPredicateDate(IQueryParameterType theParam, public Predicate createPredicateDate(IQueryParameterType theParam,
String theResourceName, String theResourceName,
String theParamName, String theParamName,

View File

@ -78,7 +78,7 @@ public class PredicateBuilderNumber extends BasePredicateBuilder {
} }
Predicate predicate = myBuilder.or(toArray(codePredicates)); Predicate predicate = myBuilder.or(toArray(codePredicates));
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
return predicate; return predicate;
} }
} }

View File

@ -47,7 +47,7 @@ public class PredicateBuilderQuantity extends BasePredicateBuilder {
} }
Predicate retVal = myBuilder.or(toArray(codePredicates)); Predicate retVal = myBuilder.or(toArray(codePredicates));
myPredicates.add(retVal); myQueryRoot.addPredicate(retVal);
return retVal; return retVal;
} }

View File

@ -161,13 +161,13 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
if (codePredicates.size() > 0) { if (codePredicates.size() > 0) {
Predicate predicate = myBuilder.or(toArray(codePredicates)); Predicate predicate = myBuilder.or(toArray(codePredicates));
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
return predicate; return predicate;
} else { } else {
// Add a predicate that will never match // Add a predicate that will never match
Predicate pidPredicate = join.get("myTargetResourcePid").in(-1L); Predicate pidPredicate = join.get("myTargetResourcePid").in(-1L);
myPredicates.clear(); myQueryRoot.clearPredicates();
myPredicates.add(pidPredicate); myQueryRoot.addPredicate(pidPredicate);
return pidPredicate; return pidPredicate;
} }
} }
@ -305,7 +305,7 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
} }
Predicate predicate = myBuilder.or(toArray(theCodePredicates)); Predicate predicate = myBuilder.or(toArray(theCodePredicates));
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
return predicate; return predicate;
} }
@ -372,29 +372,22 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
* stack and run a subquery * stack and run a subquery
*/ */
Root<ResourceTable> stackRoot = myResourceTableRoot; myQueryRoot.push(subQfrom);
ArrayList<Predicate> stackPredicates = myPredicates; // FIXME KHS stack in all predicates
IndexJoins stackIndexJoins = myIndexJoins;
myResourceTableRoot = subQfrom;
myPredicates = Lists.newArrayList();
myIndexJoins = new IndexJoins();
// Create the subquery predicates // Create the subquery predicates
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), theSubResourceName)); myQueryRoot.addPredicate(myBuilder.equal(myQueryRoot.get("myResourceType"), theSubResourceName));
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted"))); myQueryRoot.addPredicate(myBuilder.isNull(myQueryRoot.get("myDeleted")));
if (theFoundChainMatch) { if (theFoundChainMatch) {
searchForIdsWithAndOr(theSubResourceName, theChain, andOrParams, theRequest); searchForIdsWithAndOr(theSubResourceName, theChain, andOrParams, theRequest);
subQ.where(toArray(myPredicates)); subQ.where(myQueryRoot.getPredicateArray());
} }
/* /*
* Pop the old query root and predicate list back * Pop the old query root and predicate list back
*/ */
myResourceTableRoot = stackRoot; myQueryRoot.pop();
myPredicates = stackPredicates;
myIndexJoins = stackIndexJoins;
return subQ; return subQ;
} }
@ -508,12 +501,13 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
// TODO: we clear the predicates below because the filter builds up // TODO: we clear the predicates below because the filter builds up
// its own collection of predicates. It'd probably be good at some // its own collection of predicates. It'd probably be good at some
// point to do something more fancy... // point to do something more fancy...
ArrayList<Predicate> holdPredicates = new ArrayList<>(myPredicates); // FIXME KHS
ArrayList<Predicate> holdPredicates = new ArrayList<>(myQueryRoot.getPredicates());
Predicate filterPredicate = processFilter(filter, theResourceName, theRequest); Predicate filterPredicate = processFilter(filter, theResourceName, theRequest);
myPredicates.clear(); myQueryRoot.clearPredicates();
myPredicates.addAll(holdPredicates); myQueryRoot.addPredicates(holdPredicates);
myPredicates.add(filterPredicate); myQueryRoot.addPredicate(filterPredicate);
} }
} }
@ -705,13 +699,13 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
Predicate predicate = null; Predicate predicate = null;
if ((operation == null) || if ((operation == null) ||
(operation == SearchFilterParser.CompareOperation.eq)) { (operation == SearchFilterParser.CompareOperation.eq)) {
predicate = myResourceTableRoot.get("myLanguage").as(String.class).in(values); predicate = myQueryRoot.get("myLanguage").as(String.class).in(values);
} else if (operation == SearchFilterParser.CompareOperation.ne) { } else if (operation == SearchFilterParser.CompareOperation.ne) {
predicate = myResourceTableRoot.get("myLanguage").as(String.class).in(values).not(); predicate = myQueryRoot.get("myLanguage").as(String.class).in(values).not();
} else { } else {
throw new InvalidRequestException("Unsupported operator specified in language query, only \"eq\" and \"ne\" are supported"); throw new InvalidRequestException("Unsupported operator specified in language query, only \"eq\" and \"ne\" are supported");
} }
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
if (operation != null) { if (operation != null) {
return predicate; return predicate;
} }
@ -732,7 +726,7 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
throw new InvalidRequestException(msg); throw new InvalidRequestException(msg);
} }
Join<ResourceTable, ResourceHistoryProvenanceEntity> join = myResourceTableRoot.join("myProvenance", JoinType.LEFT); Join<ResourceTable, ResourceHistoryProvenanceEntity> join = myQueryRoot.join("myProvenance", JoinType.LEFT);
List<Predicate> codePredicates = new ArrayList<>(); List<Predicate> codePredicates = new ArrayList<>();
@ -752,7 +746,7 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
} }
Predicate retVal = myBuilder.or(toArray(codePredicates)); Predicate retVal = myBuilder.or(toArray(codePredicates));
myPredicates.add(retVal); myQueryRoot.addPredicate(retVal);
return retVal; return retVal;
} }
@ -809,11 +803,11 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
Subquery<Long> subQ = myPredicateBuilder.createLinkSubquery(true, parameterName, targetResourceType, orValues, theRequest); Subquery<Long> subQ = myPredicateBuilder.createLinkSubquery(true, parameterName, targetResourceType, orValues, theRequest);
Join<ResourceTable, ResourceLink> join = myResourceTableRoot.join("myResourceLinksAsTarget", JoinType.LEFT); Join<ResourceTable, ResourceLink> join = myQueryRoot.join("myResourceLinksAsTarget", JoinType.LEFT);
Predicate pathPredicate = myPredicateBuilder.createResourceLinkPathPredicate(targetResourceType, paramReference, join); Predicate pathPredicate = myPredicateBuilder.createResourceLinkPathPredicate(targetResourceType, paramReference, join);
Predicate pidPredicate = join.get("mySourceResourcePid").in(subQ); Predicate pidPredicate = join.get("mySourceResourcePid").in(subQ);
Predicate andPredicate = myBuilder.and(pathPredicate, pidPredicate); Predicate andPredicate = myBuilder.and(pathPredicate, pidPredicate);
myPredicates.add(andPredicate); myQueryRoot.addPredicate(andPredicate);
} }
} }
@ -828,11 +822,11 @@ public class PredicateBuilderReference extends BasePredicateBuilder {
RuntimeSearchParam left = theParamDef.getCompositeOf().get(0); RuntimeSearchParam left = theParamDef.getCompositeOf().get(0);
IQueryParameterType leftValue = cp.getLeftValue(); IQueryParameterType leftValue = cp.getLeftValue();
myPredicates.add(createCompositeParamPart(theResourceName, myResourceTableRoot, left, leftValue)); myQueryRoot.addPredicate(createCompositeParamPart(theResourceName, myQueryRoot.getRoot(), left, leftValue));
RuntimeSearchParam right = theParamDef.getCompositeOf().get(1); RuntimeSearchParam right = theParamDef.getCompositeOf().get(1);
IQueryParameterType rightValue = cp.getRightValue(); IQueryParameterType rightValue = cp.getRightValue();
myPredicates.add(createCompositeParamPart(theResourceName, myResourceTableRoot, right, rightValue)); myQueryRoot.addPredicate(createCompositeParamPart(theResourceName, myQueryRoot.getRoot(), right, rightValue));
} }

View File

@ -35,10 +35,10 @@ public class PredicateBuilderResourceId extends BasePredicateBuilder {
Predicate addPredicateResourceId(List<List<IQueryParameterType>> theValues, String theResourceName, SearchFilterParser.CompareOperation theOperation, RequestDetails theRequest) { Predicate addPredicateResourceId(List<List<IQueryParameterType>> theValues, String theResourceName, SearchFilterParser.CompareOperation theOperation, RequestDetails theRequest) {
Predicate nextPredicate = createPredicateResourceId(myResourceTableRoot, theResourceName, theValues, theOperation, theRequest); Predicate nextPredicate = createPredicateResourceId(myQueryRoot.getRoot(), theResourceName, theValues, theOperation, theRequest);
if (nextPredicate != null) { if (nextPredicate != null) {
myPredicates.add(nextPredicate); myQueryRoot.addPredicate(nextPredicate);
return nextPredicate; return nextPredicate;
} }
@ -96,12 +96,12 @@ public class PredicateBuilderResourceId extends BasePredicateBuilder {
default: default:
case eq: case eq:
codePredicates.add(theRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(allOrPids))); codePredicates.add(theRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(allOrPids)));
codePredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), theResourceName)); codePredicates.add(myBuilder.equal(myQueryRoot.get("myResourceType"), theResourceName));
nextPredicate = myBuilder.and(toArray(codePredicates)); nextPredicate = myBuilder.and(toArray(codePredicates));
break; break;
case ne: case ne:
codePredicates.add(theRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(allOrPids)).not()); codePredicates.add(theRoot.get("myId").as(Long.class).in(ResourcePersistentId.toLongList(allOrPids)).not());
codePredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), theResourceName)); codePredicates.add(myBuilder.equal(myQueryRoot.get("myResourceType"), theResourceName));
nextPredicate = myBuilder.and(toArray(codePredicates)); nextPredicate = myBuilder.and(toArray(codePredicates));
break; break;
} }

View File

@ -49,7 +49,7 @@ public class PredicateBuilderString extends BasePredicateBuilder {
} }
Predicate retVal = myBuilder.or(toArray(codePredicates)); Predicate retVal = myBuilder.or(toArray(codePredicates));
myPredicates.add(retVal); myQueryRoot.addPredicate(retVal);
return retVal; return retVal;
} }

View File

@ -135,7 +135,13 @@ public class PredicateBuilderTag extends BasePredicateBuilder {
Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class); Root<ResourceTag> subQfrom = subQ.from(ResourceTag.class);
subQ.select(subQfrom.get("myResourceId").as(Long.class)); subQ.select(subQfrom.get("myResourceId").as(Long.class));
myPredicates.add(myBuilder.not(myBuilder.in(myResourceTableRoot.get("myId")).value(subQ))); myQueryRoot.addPredicate(
myBuilder.not(
myBuilder.in(
myQueryRoot.get("myId")
).value(subQ)
)
);
Subquery<Long> defJoin = subQ.subquery(Long.class); Subquery<Long> defJoin = subQ.subquery(Long.class);
Root<TagDefinition> defJoinFrom = defJoin.from(TagDefinition.class); Root<TagDefinition> defJoinFrom = defJoin.from(TagDefinition.class);
@ -149,11 +155,11 @@ public class PredicateBuilderTag extends BasePredicateBuilder {
continue; continue;
} }
Join<ResourceTable, ResourceTag> tagJoin = myResourceTableRoot.join("myTags", JoinType.LEFT); Join<ResourceTable, ResourceTag> tagJoin = myQueryRoot.join("myTags", JoinType.LEFT);
From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag"); From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag");
Predicate tagListPredicate = createPredicateTagList(defJoin, myBuilder, tagType, tokens); Predicate tagListPredicate = createPredicateTagList(defJoin, myBuilder, tagType, tokens);
myPredicates.add(tagListPredicate); myQueryRoot.addPredicate(tagListPredicate);
} }

View File

@ -75,7 +75,7 @@ public class PredicateBuilderToken extends BasePredicateBuilder {
codePredicates.addAll(singleCode); codePredicates.addAll(singleCode);
Predicate spPredicate = myBuilder.or(toArray(codePredicates)); Predicate spPredicate = myBuilder.or(toArray(codePredicates));
myPredicates.add(spPredicate); myQueryRoot.addPredicate(spPredicate);
return spPredicate; return spPredicate;
} }

View File

@ -140,7 +140,7 @@ public class PredicateBuilderUri extends BasePredicateBuilder {
*/ */
if (codePredicates.isEmpty()) { if (codePredicates.isEmpty()) {
Predicate predicate = myBuilder.isNull(join.get("myMissing").as(String.class)); Predicate predicate = myBuilder.isNull(join.get("myMissing").as(String.class));
myPredicates.add(predicate); myQueryRoot.addPredicate(predicate);
return null; return null;
} }
@ -150,7 +150,7 @@ public class PredicateBuilderUri extends BasePredicateBuilder {
theParamName, theParamName,
join, join,
orPredicate); orPredicate);
myPredicates.add(outerPredicate); myQueryRoot.addPredicate(outerPredicate);
return outerPredicate; return outerPredicate;
} }
} }

View File

@ -0,0 +1,65 @@
package ca.uhn.fhir.jpa.dao.predicate;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import javax.persistence.criteria.*;
import java.util.List;
import java.util.Stack;
public class QueryRoot {
private final Stack<QueryRootEntry> myQueryRootStack = new Stack<>();
public void push(Root<ResourceTable> theResourceTableRoot) {
myQueryRootStack.push(new QueryRootEntry(theResourceTableRoot));
}
private QueryRootEntry top() {
return myQueryRootStack.peek();
}
void pop() {
myQueryRootStack.pop();
}
public Root<ResourceTable> getRoot() {
return top().getRoot();
}
public <Y> Path<Y> get(String theAttributeName) {
return top().get(theAttributeName);
}
public <Y> Join<ResourceTable, Y> join(String theAttributeName, JoinType theJoinType) {
return top().join(theAttributeName, theJoinType);
}
public Join<?,?> getIndexJoin(SearchBuilderJoinKey theKey) {
return top().getIndexJoin(theKey);
}
public void addPredicate(Predicate thePredicate) {
top().addPredicate(thePredicate);
}
public void addPredicates(List<Predicate> thePredicates) {
top().addPredicates(thePredicates);
}
public Predicate[] getPredicateArray() {
return top().getPredicateArray();
}
void putIndex(SearchBuilderJoinKey theKey, Join<ResourceTable, ResourceIndexedSearchParamDate> theJoin) {
top().putIndex(theKey, theJoin);
}
void clearPredicates() {
top().clearPredicates();
}
// FIXME KHS don't leak
List<Predicate> getPredicates() {
return top().getPredicates();
}
}

View File

@ -0,0 +1,59 @@
package ca.uhn.fhir.jpa.dao.predicate;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.List;
public class QueryRootEntry {
private final Root<ResourceTable> myResourceTableRoot;
private final ArrayList<Predicate> myPredicates = new ArrayList<>();
private final IndexJoins myIndexJoins = new IndexJoins();
public QueryRootEntry(Root<ResourceTable> theResourceTableRoot) {
myResourceTableRoot = theResourceTableRoot;
}
public Root<ResourceTable> getRoot() {
return myResourceTableRoot;
}
public <Y> Path<Y> get(String theAttributeName) {
return myResourceTableRoot.get(theAttributeName);
}
public <Y> Join<ResourceTable, Y> join(String theAttributeName, JoinType theJoinType) {
return myResourceTableRoot.join(theAttributeName, theJoinType);
}
public Join<?,?> getIndexJoin(SearchBuilderJoinKey theKey) {
return myIndexJoins.get(theKey);
}
public void addPredicate(Predicate thePredicate) {
myPredicates.add(thePredicate);
}
public void addPredicates(List<Predicate> thePredicates) {
myPredicates.addAll(thePredicates);
}
public Predicate[] getPredicateArray() {
return myPredicates.toArray(new Predicate[0]);
}
void putIndex(SearchBuilderJoinKey theKey, Join<ResourceTable, ResourceIndexedSearchParamDate> theJoin) {
myIndexJoins.put(theKey, theJoin);
}
void clearPredicates() {
myPredicates.clear();
}
// FIXME KHS don't leak
List<Predicate> getPredicates() {
return myPredicates;
}
}

View File

@ -4,107 +4,25 @@ import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.ResourceLink; import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.TypedQuery; import javax.persistence.TypedQuery;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class SearchBuilderTest { public class SearchBuilderTest {
private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilderTest.class);
@Test
public void testCalculateMultiplierEqualNoDecimal() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_() {
BigDecimal in = new BigDecimal("200.");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision123_010() {
BigDecimal in = new BigDecimal("123.010");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005"));
BigDecimal low = in.subtract(out, MathContext.DECIMAL64);
BigDecimal high = in.add(out, MathContext.DECIMAL64);
ourLog.info("{} <= {} <= {}", new Object[] {low.toPlainString(), in.toPlainString(), high.toPlainString()});
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_0() {
BigDecimal in = new BigDecimal("200.0");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_3() {
BigDecimal in = new BigDecimal("200.3");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300() {
BigDecimal in = new BigDecimal("200.300");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_30000000() {
BigDecimal in = new BigDecimal("200.30000000");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.000000005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300000001() {
BigDecimal in = new BigDecimal("200.300000001");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0000000005000000"));
}
@Test
public void testCalculateMultiplierApprox() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = SearchBuilder.calculateFuzzAmount(ParamPrefixEnum.APPROXIMATE, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("20.000"));
}
@Test @Test
public void testIncludeIterator() { public void testIncludeIterator() {

View File

@ -0,0 +1,94 @@
package ca.uhn.fhir.jpa.dao.predicate;
import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.dao.SearchBuilderTest;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.math.MathContext;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.*;
public class FuzzCalculatorTest {
private static final Logger ourLog = LoggerFactory.getLogger(SearchBuilderTest.class);
@Test
public void testCalculateMultiplierEqualNoDecimal() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_() {
BigDecimal in = new BigDecimal("200.");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertEquals("0.5", out.toPlainString());
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision123_010() {
BigDecimal in = new BigDecimal("123.010");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005"));
BigDecimal low = in.subtract(out, MathContext.DECIMAL64);
BigDecimal high = in.add(out, MathContext.DECIMAL64);
ourLog.info("{} <= {} <= {}", new Object[] {low.toPlainString(), in.toPlainString(), high.toPlainString()});
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_0() {
BigDecimal in = new BigDecimal("200.0");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_3() {
BigDecimal in = new BigDecimal("200.3");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.05000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300() {
BigDecimal in = new BigDecimal("200.300");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_30000000() {
BigDecimal in = new BigDecimal("200.30000000");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.000000005000000"));
}
@Test
public void testCalculateMultiplierEqualDecimalPrecision200_300000001() {
BigDecimal in = new BigDecimal("200.300000001");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.EQUAL, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("0.0000000005000000"));
}
@Test
public void testCalculateMultiplierApprox() {
BigDecimal in = new BigDecimal("200");
BigDecimal out = FuzzCalculator.calculateFuzzAmount(ParamPrefixEnum.APPROXIMATE, in);
ourLog.info(out.toPlainString());
assertThat(out.toPlainString(), startsWith("20.000"));
}
}