package edu.gatech.i3l.fhir.jpa.query; import java.math.BigDecimal; import java.util.Date; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.From; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.apache.commons.lang3.StringUtils; import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.ParamPrefixEnum; import edu.gatech.i3l.fhir.jpa.entity.IResourceEntity; public abstract class AbstractPredicateBuilder implements PredicateBuilder{ @Override public Predicate translatePredicateString(Class<? extends IResourceEntity> entity, String theParamName, String likeExpression, From<? extends IResourceEntity, ? extends IResourceEntity> from, CriteriaBuilder theBuilder) { return theBuilder.like(getPath(entity, theParamName, from).as(String.class), likeExpression); } @Override public Predicate translatePredicateDate(Class<? extends IResourceEntity> entity, CriteriaBuilder theBuilder, From<? extends IResourceEntity, ? extends IResourceEntity> from, DateRangeParam theRange, String theParamName, IQueryParameterType theParam) { Date lowerBound = theRange.getLowerBoundAsInstant(); Date upperBound = theRange.getUpperBoundAsInstant(); Predicate lb = null; Path<? extends Object> path = getPath(entity, theParamName, from); if (lowerBound != null) { lb = theBuilder.greaterThanOrEqualTo(path.as(Date.class), lowerBound); } Predicate ub = null; if (upperBound != null) { ub = theBuilder.lessThanOrEqualTo(path.as(Date.class), upperBound); } if (lb != null && ub != null) { return (theBuilder.and(lb, ub)); } else if (lb != null) { return (lb); } else { return (ub); } } @Override public Predicate translatePredicateTokenSystem(Class<? extends IResourceEntity> entity, String theParamName, String system, From<? extends IResourceEntity, ? extends IResourceEntity> from, CriteriaBuilder theBuilder) { if (system == null) { return null; } Path<? extends Object> path = getPath( entity, theParamName, from); if (StringUtils.isNotBlank(system)) { return theBuilder.equal(path, system); } else { return theBuilder.isNull(path); } } @Override public Predicate translatePredicateTokenCode(Class<? extends IResourceEntity> entity, String theParamName, String code, From<? extends IResourceEntity, ? extends IResourceEntity> from, CriteriaBuilder theBuilder) { Path<? extends Object> path = getPath(entity, theParamName, from); if (StringUtils.isNotBlank(code)) { return theBuilder.equal(path, code); } else { return theBuilder.isNull(path); } } @Override public Predicate translatePredicateValueNumber(Class<? extends IResourceEntity> myResourceEntity, CriteriaBuilder builder, Root<? extends IResourceEntity> from, String theParamName, ParamPrefixEnum comparator, BigDecimal value) { Predicate predicate = null; Path<? extends Object> fromObj = getPath(myResourceEntity, theParamName, from); if (comparator == null) { double mul = value.doubleValue() * 1.01; double low = value.doubleValue() - mul; double high = value.doubleValue() + mul; Predicate lowPred = builder.ge(fromObj.as(Long.class), low); Predicate highPred = builder.le(fromObj.as(Long.class), high); predicate= builder.and(lowPred, highPred); } else { switch (comparator) { case GREATERTHAN: predicate = builder.greaterThan(fromObj.as(BigDecimal.class), value); case GREATERTHAN_OR_EQUALS: predicate = builder.ge(fromObj.as(BigDecimal.class), value); break; case LESSTHAN: predicate = builder.lessThan(fromObj.as(BigDecimal.class), value); break; case LESSTHAN_OR_EQUALS: predicate= builder.le(fromObj.as(BigDecimal.class), value); break; } } return predicate; } @Override public Predicate translatePredicateQuantityCode(Class<? extends IResourceEntity> entity, String theParamName, CriteriaBuilder builder, From<? extends IResourceEntity, ? extends IResourceEntity> from, String unitsValue) { return builder.like(getPath(entity, theParamName, from).as(String.class), unitsValue); } @Override public Predicate translatePredicateQuantitySystem(Class<? extends IResourceEntity> entity, String theParamName, CriteriaBuilder builder, From<? extends IResourceEntity, ? extends IResourceEntity> from, String systemValue) { return builder.like(getPath(entity, theParamName, from).as(String.class), systemValue); } /* * (non-Javadoc) * @see edu.gatech.i3l.fhir.jpa.query.PredicateBuilder#addCommonPredicate(javax.persistence.criteria.CriteriaBuilder, javax.persistence.criteria.From) */ @Override public Predicate addCommonPredicate(CriteriaBuilder builder, From<? extends IResourceEntity, ? extends IResourceEntity> from) { // NO COMMON PARAM TO BE ADDED HERE: This implementation of the method has the only purpose to avoid the obligation of subclasses of this // * class(AbstractPredicateBuilder) to implement it. return null; } @Override public Predicate translatePredicateQuantityValue(Class<? extends IResourceEntity> entity, String theParamName, CriteriaBuilder builder, From<? extends IResourceEntity, ? extends IResourceEntity> from, ParamPrefixEnum cmpValue, BigDecimal valueValue, boolean approx) { Predicate num; Path<? extends Object> path = getPath(entity, theParamName, from); if (cmpValue == null) { BigDecimal mul = approx ? new BigDecimal(0.1) : new BigDecimal(0.01); BigDecimal low = valueValue.subtract(valueValue.multiply(mul)); BigDecimal high = valueValue.add(valueValue.multiply(mul)); Predicate lowPred = builder.gt(path.as(BigDecimal.class) , low); Predicate highPred = builder.lt(path.as(BigDecimal.class), high); num = builder.and(lowPred, highPred); } else { switch (cmpValue) { case GREATERTHAN: num = builder.gt(path.as(Number.class), valueValue); break; case GREATERTHAN_OR_EQUALS: num = builder.ge(path.as(Number.class), valueValue); break; case LESSTHAN: num = builder.lt(path.as(Number.class), valueValue); break; case LESSTHAN_OR_EQUALS: num = builder.le(path.as(Number.class), valueValue); break; default: throw new IllegalStateException(cmpValue.getValue()); } } return num; } @Override public Path<? extends Object> getPath(Class<? extends IResourceEntity> entity, String theParamName, Path<? extends IResourceEntity> from) { Path<? extends Object> path = null; try { String translatedParams = entity.newInstance().translateSearchParam(theParamName); String[] chain = translatedParams.contains(".") ? translatedParams.split("\\.") : new String[]{translatedParams}; path = from.get(chain[0]); if(chain != null){ for (int i = 1; i < chain.length; i++) { path = path.get(chain[i]); } } } catch (InstantiationException e){ } catch(IllegalAccessException e) { } return path; } }