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

com.blazebit.persistence.impl.AbstractCustomQuery Maven / Gradle / Ivy

The newest version!
package com.blazebit.persistence.impl;

import com.blazebit.persistence.CommonQueryBuilder;
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.spi.CteQueryWrapper;
import com.blazebit.persistence.spi.ExtendedQuerySupport;

import javax.persistence.Parameter;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import java.util.*;

public abstract class AbstractCustomQuery implements Query, CteQueryWrapper {

    protected final QuerySpecification querySpecification;
    protected final CommonQueryBuilder cqb;
    protected final ExtendedQuerySupport extendedQuerySupport;
    protected final Map valuesParameters;
    protected final Map> parameterQueries;
    protected final Set> parameters;
    protected int firstResult;
    protected int maxResults = Integer.MAX_VALUE;

    public AbstractCustomQuery(QuerySpecification querySpecification, CommonQueryBuilder cqb, ExtendedQuerySupport extendedQuerySupport, Map valuesParameters, Map valuesBinders) {
        this.querySpecification = querySpecification;
        this.cqb = cqb;
        this.extendedQuerySupport = extendedQuerySupport;
        Map valuesParameterMap = new HashMap();
        Map> parameterQueries = new HashMap>();
        Set> parameters = new HashSet>();
        // TODO: Fix this, currently this builds the complete query plan
        for (Query q : querySpecification.getParticipatingQueries()) {
            for (Parameter p : q.getParameters()) {
                String name = p.getName();
                String valuesName = valuesParameters.get(name);
                if (valuesName != null) {
                    // Replace the name with the values parameter name so the query gets registered for that
                    name = valuesName;
                    if (!valuesParameterMap.containsKey(valuesName)) {
                        ValuesParameter param = new ValuesParameter(valuesName, valuesBinders.get(valuesName));
                        parameters.add(param);
                        valuesParameterMap.put(valuesName, param);
                    }
                }

                Set queries = parameterQueries.get(name);
                if (queries == null) {
                    queries = new HashSet();
                    parameterQueries.put(name, queries);
                    if (valuesName == null) {
                        parameters.add(p);
                    }
                }
                queries.add(q);
            }
        }
        this.valuesParameters = Collections.unmodifiableMap(valuesParameterMap);
        this.parameters = Collections.unmodifiableSet(parameters);
        this.parameterQueries = Collections.unmodifiableMap(parameterQueries);
    }

    public QuerySpecification getQuerySpecification() {
        return querySpecification;
    }

    public String getSql() {
        return querySpecification.getSql();
    }

    @Override
    public List getParticipatingQueries() {
        return querySpecification.getParticipatingQueries();
    }

    @Override
    public Query setMaxResults(int maxResults) {
        this.maxResults = maxResults;
        return this;
    }

    @Override
    public int getMaxResults() {
        return maxResults;
    }

    @Override
    public Query setFirstResult(int startPosition) {
        this.firstResult = startPosition;
        return this;
    }

    @Override
    public int getFirstResult() {
        return firstResult;
    }

    private Set queries(String name) {
        Set queries = parameterQueries.get(name);
        if (queries == null) {
            throw new IllegalArgumentException("Parameter '" + name + "' does not exist!");
        }
        return queries;
    }

    @Override
    public  Query setParameter(Parameter param, T value) {
        setParameter(param.getName(), value);
        return this;
    }

    @Override
    public Query setParameter(Parameter param, Calendar value, TemporalType temporalType) {
        setParameter(param.getName(), value, temporalType);
        return this;
    }

    @Override
    public Query setParameter(Parameter param, Date value, TemporalType temporalType) {
        setParameter(param.getName(), value, temporalType);
        return this;
    }

    @Override
    public Query setParameter(String name, Object value) {
        Set queries = queries(name);
        ValuesParameter valuesParameter = valuesParameters.get(name);
        if (valuesParameter != null) {
            for (Query q : queries) {
                valuesParameter.setValue(value);
                valuesParameter.bind(q);
            }
        } else if (queries.size() > 0) {
            querySpecification.onParameterChange(name);
            for (Query q : queries) {
                q.setParameter(name, value);
            }
        }
        return this;
    }

    @Override
    public Query setParameter(String name, Calendar value, TemporalType temporalType) {
        Set queries = queries(name);
        if (queries.size() > 0) {
            querySpecification.onParameterChange(name);
            for (Query q : queries) {
                q.setParameter(name, value, temporalType);
            }
        }
        return this;
    }

    @Override
    public Query setParameter(String name, Date value, TemporalType temporalType) {
        Set queries = queries(name);
        if (queries.size() > 0) {
            querySpecification.onParameterChange(name);
            for (Query q : queries) {
                q.setParameter(name, value, temporalType);
            }
        }
        return this;
    }

    @Override
    public Query setParameter(int position, Object value) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    @Override
    public Query setParameter(int position, Calendar value, TemporalType temporalType) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    @Override
    public Query setParameter(int position, Date value, TemporalType temporalType) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    @Override
    public Set> getParameters() {
        return parameters;
    }

    @Override
    public Parameter getParameter(String name) {
        ValuesParameter valuesParameter = valuesParameters.get(name);
        if (valuesParameter != null) {
            return valuesParameter;
        }

        Set queries = queries(name);
        Query q = queries.iterator().next();
        return q.getParameter(name);
    }

    @Override
    public  Parameter getParameter(String name, Class type) {
        Parameter p = getParameter(name);
        if (!type.isAssignableFrom(p.getParameterType())) {
            throw new IllegalArgumentException("Parameter '" + name + "' is not assignable to '" + type.getName() + "'!");
        }
        return (Parameter) p;
    }

    @Override
    public Parameter getParameter(int position) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    @Override
    public  Parameter getParameter(int position, Class type) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    @Override
    public boolean isBound(Parameter param) {
        ValuesParameter valuesParameter = valuesParameters.get(param.getName());
        if (valuesParameter != null) {
            return valuesParameter.getValue() != null;
        }

        Set queries = queries(param.getName());
        Query q = queries.iterator().next();
        return q.isBound(q.getParameter(param.getName()));
    }

    @Override
    public  T getParameterValue(Parameter param) {
        return (T) getParameterValue(param.getName());
    }

    @Override
    public Object getParameterValue(String name) {
        ValuesParameter valuesParameter = valuesParameters.get(name);
        if (valuesParameter != null) {
            return valuesParameter.getValue();
        }

        Set queries = queries(name);
        return queries.iterator().next().getParameterValue(name);
    }

    @Override
    public Object getParameterValue(int position) {
        throw new IllegalArgumentException("Positional parameters unsupported!");
    }

    static class ValuesParameter implements Parameter {

        private final String name;
        private final ValuesParameterBinder binder;
        private Collection value;

        public ValuesParameter(String name, ValuesParameterBinder binder) {
            this.name = name;
            this.binder = binder;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public Integer getPosition() {
            return null;
        }

        @Override
        public Class getParameterType() {
            return Collection.class;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            if (value == null) {
                throw new IllegalArgumentException("null not allowed for VALUES parameter!");
            }
            if (!(value instanceof Collection)) {
                throw new IllegalArgumentException("Value for VALUES parameter must be a collection! Unsupported type: " + value.getClass());
            }

            Collection collection = (Collection) value;
            if (collection.size() > binder.size()) {
                throw new IllegalArgumentException("The size of the collection must be lower or equal to the specified size for the VALUES clause.");
            }
            this.value = collection;
        }

        public void bind(Query query) {
            binder.bind(query, value);
        }
    }
}