All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ibatis.persist.impl.CriteriaQueryImpl Maven / Gradle / Ivy

Go to download

The jBATIS persistence framework will help you to significantly reduce the amount of Java code that you normally need to access a relational database. iBATIS simply maps JavaBeans to SQL statements using a very simple XML descriptor.

The newest version!
package org.ibatis.persist.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.ibatis.persist.Parameter;
import org.ibatis.persist.criteria.CriteriaQuery;
import org.ibatis.persist.criteria.Expression;
import org.ibatis.persist.criteria.Order;
import org.ibatis.persist.criteria.ParameterExpression;
import org.ibatis.persist.criteria.Predicate;
import org.ibatis.persist.criteria.Root;
import org.ibatis.persist.criteria.Selection;
import org.ibatis.persist.criteria.Subquery;
import org.ibatis.persist.meta.EntityType;

import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;

/**
 * The Hibernate implementation of the JPA {@link CriteriaQuery} contract. Mostly a set of delegation to its internal
 * {@link QueryStructure}.
 */
@SuppressWarnings("unchecked")
public class CriteriaQueryImpl extends AbstractNode implements CriteriaQuery, CriteriaStatement {

    private final Class returnType;

    private final QueryStructure queryStructure;
    private List orderSpecs = Collections.emptyList();

    public CriteriaQueryImpl(CriteriaBuilderImpl criteriaBuilder, Class returnType) {
        super(criteriaBuilder);
        this.returnType = returnType;
        this.queryStructure = new QueryStructure(this, criteriaBuilder, returnType);
    }

    @Override
    public Class getResultType() {
        return returnType;
    }

    // SELECTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    @Override
    public CriteriaQuery distinct(boolean applyDistinction) {
        queryStructure.setDistinct(applyDistinction);
        return this;
    }

    @Override
    public boolean isDistinct() {
        return queryStructure.isDistinct();
    }

    @Override
    public Selection getSelection() {
        return (Selection) queryStructure.getSelection();
    }

    public void applySelection(Selection selection) {
        queryStructure.setSelection(selection);
    }

    @Override
    public CriteriaQuery select(Selection selection) {
        applySelection(selection);
        return this;
    }

    @Override
    public CriteriaQuery multiselect(Selection... selections) {
        return multiselect(Arrays.asList(selections));
    }

    @Override
    public CriteriaQuery multiselect(List> selections) {
        final Selection selection;

        selection = criteriaBuilder().construct(getResultType(), selections);
        applySelection(selection);
        return this;
    }

    // ROOTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    @Override
    public Set> getRoots() {
        return queryStructure.getRoots();
    }

    @Override
    public  Root from(Class entityClass) {
        return queryStructure.from(entityClass);
    }

    @Override
    public  Root from(EntityType entityType) {
        return queryStructure.from(entityType);
    }
    
    // RESTRICTION ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    @Override
    public Predicate getRestriction() {
        return queryStructure.getRestriction();
    }

    @Override
    public CriteriaQuery where(Expression expression) {
        queryStructure.setRestriction(criteriaBuilder().wrap(expression));
        return this;
    }

    @Override
    public CriteriaQuery where(Predicate... predicates) {
        // TODO : assuming this should be a conjuntion, but the spec does not say specifically...
        queryStructure.setRestriction(criteriaBuilder().and(predicates));
        return this;
    }

    // GROUPING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    @Override
    public List> getGroupList() {
        return queryStructure.getGroupings();
    }

    @Override
    public CriteriaQuery groupBy(Expression... groupings) {
        queryStructure.setGroupings(groupings);
        return this;
    }

    @Override
    public CriteriaQuery groupBy(List> groupings) {
        queryStructure.setGroupings(groupings);
        return this;
    }

    @Override
    public Predicate getGroupRestriction() {
        return queryStructure.getHaving();
    }

    @Override
    public CriteriaQuery having(Expression expression) {
        queryStructure.setHaving(criteriaBuilder().wrap(expression));
        return this;
    }

    @Override
    public CriteriaQuery having(Predicate... predicates) {
        queryStructure.setHaving(criteriaBuilder().and(predicates));
        return this;
    }

    // ORDERING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    @Override
    public List getOrderList() {
        return orderSpecs;
    }

    @Override
    public CriteriaQuery orderBy(Order... orders) {
        if (orders != null && orders.length > 0) {
            orderSpecs = Arrays.asList(orders);
        } else {
            orderSpecs = Collections.emptyList();
        }
        return this;
    }

    @Override
    public CriteriaQuery orderBy(List orders) {
        orderSpecs = orders;
        return this;
    }

    @Override
    public Set> getParameters() {
        prepare();
        return rc.getParameters();
    }

    @Override
    public  Subquery subquery(Class subqueryType) {
        return queryStructure.subquery(subqueryType);
    }

    void validate() {
        // getRoots() is explicitly supposed to return empty if none defined, no need to check for null
        if (getRoots().isEmpty()) {
            throw new IllegalStateException("No criteria query roots were specified");
        }

        // if there is not an explicit selection, there is an *implicit* selection of the root entity provided only
        // a single query root was defined.
        if (getSelection() == null && !hasImplicitSelection()) {
            throw new IllegalStateException("No explicit selection and an implicit one could not be determined");
        }
    }

    /**
     * If no explicit selection was defined, we have a condition called an implicit selection if the query specified a
     * single {@link Root} and the java type of that {@link Root root's} model is the same as this criteria's
     * {@link #getResultType() result type}.
     *
     * @return True if there is an explicit selection; false otherwise.
     */
    private boolean hasImplicitSelection() {
        if (getRoots().size() != 1) {
            return false;
        }

        Root root = getRoots().iterator().next();
        Class javaType = root.getModel().getJavaType();
        if (javaType != null && javaType != returnType) {
            return false;
        }

        return true;
    }


    @Override
    public  CriteriaQuery setParameter(Parameter param, R value) {
        ParameterInfo pi = (ParameterInfo) param;
        pi.setParameterValue(value);
        return this;
    }

    @Override
    public  CriteriaQuery setParameter(String name, R value) {
        return setParameter((Parameter) getParameter(name), value);
    }

    @Override
    public  CriteriaQuery setParameter(int position, R value) {
        for (Parameter p : getParameters()) {
            if (p.getPosition() != null && p.getPosition() == position) {
                setParameter((Parameter) p, value);
                return this;
            }
        }
        throw new IllegalArgumentException("" + position);
    }

    @Override
    public Parameter getParameter(String name) {
        for (Parameter p : getParameters()) {
            if (name.equals(p.getName())) {
                return p;
            }
        }
        throw new IllegalArgumentException(name);
    }

    @Override
    public  Parameter getParameter(String name, Class type) {
        for (Parameter p : getParameters()) {
            if (name.equals(p.getName()) && type.isAssignableFrom(p.getParameterType())) {
                return (Parameter) p;
            }
        }
        throw new IllegalArgumentException(name);
    }

    @Override
    public boolean isBound(Parameter param) {
        Object r = ((ParameterInfo) param).getParameterValue();
        return r != ParameterInfo.None;
    }

    @Override
    public  R getParameterValue(Parameter param) {
        R r = ((ParameterInfo) param).getParameterValue();
        if (r == ParameterInfo.None) {
            return null;
        }
        return r;
    }

    @Override
    public  R getParameterValue(String name) {
        return getParameterValue((Parameter) getParameter(name));
    }

    RenderingContext rc;
    @Override
    public synchronized void prepare() {
        if (rc == null) {
            rc = new RenderingContext();
            validate();
            queryStructure.render(rc);

            if (!getOrderList().isEmpty()) {
                rc.append(" order by ");
                String sep = "";
                for (Order orderSpec : getOrderList()) {
                    rc.append(sep);
                    ((Renderable) orderSpec.getExpression()).render(rc);
                    rc.append(orderSpec.isAscending() ? " asc" : " desc");
                    sep = ", ";
                }
            }
        }
    }

    @Override
    public boolean isQuery() {
        return true;
    }

    @Override
    public String getSql() {
        prepare();
        return rc.getSql();
    }

    @Override
    public ParameterInfo[] getParameterInfos() {
        prepare();
        return rc.getParameterInfos();
    }

    ParameterMap parameterMap;
    @Override
    public ParameterMap makeParameterMap(SqlMapExecutorDelegate delegate) {
        if (parameterMap == null) {
            parameterMap = new ParameterMap(delegate);
            List maps = new ArrayList();
            for (ParameterInfo pi : getParameterInfos()) {
                ParameterMapping map = new ParameterMapping();
                map.setMode("IN");
                map.setTypeHandler(delegate.getTypeHandlerFactory().getTypeHandler(pi.getParameterType()));
                map.setJavaType(pi.getParameterType());
                maps.add(map);
            }
            parameterMap.setParameterMappingList(maps);
        }
        return parameterMap;
    }

    @Override
    public void flushCache(SqlMapExecutorDelegate delegate) {
        // ## do nothing
    }

    @Override
    public EntityType getQueryCacheType() {
        Set> roots = queryStructure.getRoots();
        if (roots.size() == 1) {
            Root root = roots.iterator().next();
            if (root.getModel().isCacheable()) {
                return root.getModel();
            }
        }
        return null;
    }

}