Package org.datanucleus.api.jdo.query

Source Code of org.datanucleus.api.jdo.query.JDOTypesafeQuery

/**********************************************************************
Copyright (c) 2010 Andy Jefferson and others. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Contributors:
   ...
**********************************************************************/
package org.datanucleus.api.jdo.query;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Date;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.jdo.FetchPlan;
import javax.jdo.JDOException;
import javax.jdo.JDOUserException;
import javax.jdo.PersistenceManager;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.api.jdo.JDOFetchPlan;
import org.datanucleus.api.jdo.NucleusJDOHelper;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.query.JDOQLQueryHelper;
import org.datanucleus.query.compiler.QueryCompilation;
import org.datanucleus.query.expression.Literal;
import org.datanucleus.query.expression.ParameterExpression;
import org.datanucleus.query.typesafe.BooleanExpression;
import org.datanucleus.query.typesafe.CharacterExpression;
import org.datanucleus.query.typesafe.CollectionExpression;
import org.datanucleus.query.typesafe.DateExpression;
import org.datanucleus.query.typesafe.DateTimeExpression;
import org.datanucleus.query.typesafe.Expression;
import org.datanucleus.query.typesafe.ListExpression;
import org.datanucleus.query.typesafe.MapExpression;
import org.datanucleus.query.typesafe.NumericExpression;
import org.datanucleus.query.typesafe.OrderExpression;
import org.datanucleus.query.typesafe.StringExpression;
import org.datanucleus.query.typesafe.TimeExpression;
import org.datanucleus.query.typesafe.TypesafeSubquery;
import org.datanucleus.query.typesafe.OrderExpression.OrderDirection;
import org.datanucleus.query.typesafe.PersistableExpression;
import org.datanucleus.query.typesafe.TypesafeQuery;
import org.datanucleus.store.query.NoQueryResultsException;
import org.datanucleus.store.query.Query;

/**
* Implementation of a typesafe Query for JDO.
*/
public class JDOTypesafeQuery<T> extends AbstractTypesafeQuery<T> implements TypesafeQuery<T>
{
    FetchPlan fp;

    /** Whether to ignore the cache when evaluating the query. */
    boolean ignoreCache = false;

    /** Whether to include subclasses of the candidate in the query. */
    boolean subclasses = true;

    /** Any result class. */
    Class resultClass = null;

    /** Whether the result is unique (single row). */
    boolean unique = false;

    protected Collection<T> candidates = null;

    /** Range : lower limit expression. */
    protected ExpressionImpl rangeLowerExpr;

    /** Range : upper limit expression. */
    protected ExpressionImpl rangeUpperExpr;

    /** Any extensions */
    protected Map<String, Object> extensions = null;

    /** Map of parameter expression keyed by the name. */
    protected Map<String, ExpressionImpl> parameterExprByName = null;

    /** Map of parameters keyed by their name/expression. */
    protected Map<String, Object> parameterValuesByName = null;

    /** Set of any subqueries used by this query. */
    protected transient HashSet<JDOTypesafeSubquery> subqueries = null;

    /** Internal queries generated by this typesafe query. Managed so that they can be closed. */
    protected transient HashSet<Query> internalQueries = null;

    /** The single-string query that this equates to (cached). */
    String queryString = null;

    /**
     * Constructor for a typesafe query.
     * @param pm Persistence Manager
     * @param candidateClass The candidate class
     */
    public JDOTypesafeQuery(PersistenceManager pm, Class<T> candidateClass)
    {
        super(pm, candidateClass, "this");
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#candidate()
     */
    public PersistableExpression candidate()
    {
        String candName = candidateCls.getName();
        int pos = candName.lastIndexOf('.');
        String qName = candName.substring(0, pos+1) + getQueryClassNameForClassName(candName.substring(pos+1));
        try
        {
            // Use the candidate() static method for access
            Class qClass = ec.getClassLoaderResolver().classForName(qName);
            Method method = qClass.getMethod("candidate", new Class[] {});
            Object candObj = method.invoke(null, (Object[])null);
            if (candObj == null || !(candObj instanceof PersistableExpression))
            {
                throw new JDOException("Class " + candidateCls.getName() + " has a Query class but the candidate is invalid");
            }
            return (PersistableExpression)candObj;
        }
        catch (NoSuchMethodException nsfe)
        {
            throw new JDOException("Class " + candidateCls.getName() + " has a Query class but the candidate is invalid");
        }
        catch (InvocationTargetException ite)
        {
            throw new JDOException("Class " + candidateCls.getName() + " has a Query class but the candidate is invalid");
        }
        catch (IllegalAccessException iae)
        {
            throw new JDOException("Class " + candidateCls.getName() + " has a Query class but the candidate is invalid");
        }
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#parameter(java.lang.String, java.lang.Class)
     */
    public Expression parameter(String name, Class type)
    {
        discardCompiled();

        ExpressionImpl paramExpr = null;
        if (type == Boolean.class || type == boolean.class)
        {
            paramExpr = new BooleanExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Byte.class || type == byte.class)
        {
            paramExpr = new ByteExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Character.class || type == char.class)
        {
            paramExpr = new CharacterExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Double.class || type == double.class)
        {
            paramExpr = new NumericExpressionImpl<Double>(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Float.class || type == float.class)
        {
            paramExpr = new NumericExpressionImpl<Float>(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Integer.class || type == int.class)
        {
            paramExpr = new NumericExpressionImpl<Integer>(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Long.class || type == long.class)
        {
            paramExpr = new NumericExpressionImpl<Long>(type, name, ExpressionType.PARAMETER);
        }
        else if (type == Short.class || type == short.class)
        {
            paramExpr = new NumericExpressionImpl<Short>(type, name, ExpressionType.PARAMETER);
        }
        else if (type == String.class)
        {
            paramExpr = new StringExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (Time.class.isAssignableFrom(type))
        {
            paramExpr = new TimeExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (Date.class.isAssignableFrom(type))
        {
            paramExpr = new DateExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (java.util.Date.class.isAssignableFrom(type))
        {
            paramExpr = new DateTimeExpressionImpl(type, name, ExpressionType.PARAMETER);
        }
        else if (ec.getApiAdapter().isPersistable(type))
        {
            // Persistable class
            String typeName = type.getName();
            int pos = typeName.lastIndexOf('.');
            String qName = typeName.substring(0, pos+1) + getQueryClassNameForClassName(typeName.substring(pos+1));
            try
            {
                Class qClass = ec.getClassLoaderResolver().classForName(qName);
                Constructor ctr = qClass.getConstructor(new Class[] {Class.class, String.class, ExpressionType.class});
                Object candObj = ctr.newInstance(new Object[] {type, name, ExpressionType.PARAMETER});
                paramExpr = (ExpressionImpl)candObj;
            }
            catch (NoSuchMethodException nsme)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for parameters");
            }
            catch (IllegalAccessException iae)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for parameters");
            }
            catch (InvocationTargetException ite)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for parameters");
            }
            catch (InstantiationException ie)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for parameters");
            }
        }
        else
        {
            paramExpr = new ObjectExpressionImpl(type, name, ExpressionType.PARAMETER);
        }

        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);

        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#stringParameter(java.lang.String)
     */
    public StringExpression stringParameter(String name)
    {
        StringExpressionImpl paramExpr = new StringExpressionImpl(String.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#characterParameter(java.lang.String)
     */
    public CharacterExpression characterParameter(String name)
    {
        CharacterExpressionImpl paramExpr = new CharacterExpressionImpl(Character.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#longParameter(java.lang.String)
     */
    public NumericExpression<Long> longParameter(String name)
    {
        NumericExpressionImpl<Long> paramExpr = new NumericExpressionImpl(Long.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#integerParameter(java.lang.String)
     */
    public NumericExpression<Integer> integerParameter(String name)
    {
        NumericExpressionImpl<Integer> paramExpr = new NumericExpressionImpl(Integer.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#shortParameter(java.lang.String)
     */
    public NumericExpression<Short> shortParameter(String name)
    {
        NumericExpressionImpl<Short> paramExpr = new NumericExpressionImpl(Short.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#doubleParameter(java.lang.String)
     */
    public NumericExpression<Double> doubleParameter(String name)
    {
        NumericExpressionImpl<Double> paramExpr = new NumericExpressionImpl(Double.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#floatParameter(java.lang.String)
     */
    public NumericExpression<Float> floatParameter(String name)
    {
        NumericExpressionImpl<Float> paramExpr = new NumericExpressionImpl(Float.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#dateParameter(java.lang.String)
     */
    public DateExpression<Date> dateParameter(String name)
    {
        DateExpressionImpl paramExpr = new DateExpressionImpl(Date.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#timeParameter(java.lang.String)
     */
    public TimeExpression<Time> timeParameter(String name)
    {
        TimeExpressionImpl paramExpr = new TimeExpressionImpl(Date.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#datetimeParameter(java.lang.String)
     */
    public DateTimeExpression<java.util.Date> datetimeParameter(String name)
    {
        DateTimeExpressionImpl paramExpr = new DateTimeExpressionImpl(java.util.Date.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#collectionParameter(java.lang.String)
     */
    public CollectionExpression collectionParameter(String name)
    {
        CollectionExpressionImpl paramExpr = new CollectionExpressionImpl(java.util.Collection.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#mapParameter(java.lang.String)
     */
    public MapExpression mapParameter(String name)
    {
        MapExpressionImpl paramExpr = new MapExpressionImpl(java.util.Map.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#listParameter(java.lang.String)
     */
    public ListExpression listParameter(String name)
    {
        ListExpressionImpl paramExpr = new ListExpressionImpl(java.util.List.class, name, ExpressionType.PARAMETER);
        if (parameterExprByName == null)
        {
            parameterExprByName = new HashMap<String, ExpressionImpl>();
        }
        parameterExprByName.put(name, paramExpr);
        return paramExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#variable(java.lang.String, java.lang.Class)
     */
    public Expression variable(String name, Class type)
    {
        discardCompiled();

        Expression varExpr = null;
        if (ec.getApiAdapter().isPersistable(type))
        {
            // Persistable class
            String typeName = type.getName();
            int pos = typeName.lastIndexOf('.');
            String qName = typeName.substring(0, pos+1) + getQueryClassNameForClassName(typeName.substring(pos+1));
            try
            {
                Class qClass = ec.getClassLoaderResolver().classForName(qName);
                Constructor ctr = qClass.getConstructor(new Class[] {Class.class, String.class, ExpressionType.class});
                Object candObj = ctr.newInstance(new Object[] {type, name, ExpressionType.VARIABLE});
                varExpr = (Expression)candObj;
            }
            catch (NoSuchMethodException nsme)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for variables");
            }
            catch (IllegalAccessException iae)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for variables");
            }
            catch (InvocationTargetException ite)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for variables");
            }
            catch (InstantiationException ie)
            {
                throw new JDOException("Class " + typeName + " has a Query class but has no constructor for variables");
            }
        }
        else if (type == Boolean.class || type == boolean.class)
        {
            varExpr = new BooleanExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Byte.class || type == byte.class)
        {
            varExpr = new ByteExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Character.class || type == char.class)
        {
            varExpr = new CharacterExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Double.class || type == double.class)
        {
            varExpr = new NumericExpressionImpl<Double>(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Float.class || type == float.class)
        {
            varExpr = new NumericExpressionImpl<Float>(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Integer.class || type == int.class)
        {
            varExpr = new NumericExpressionImpl<Integer>(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Long.class || type == long.class)
        {
            varExpr = new NumericExpressionImpl<Long>(type, name, ExpressionType.VARIABLE);
        }
        else if (type == Short.class || type == short.class)
        {
            varExpr = new NumericExpressionImpl<Short>(type, name, ExpressionType.VARIABLE);
        }
        else if (type == String.class)
        {
            varExpr = new StringExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (Time.class.isAssignableFrom(type))
        {
            varExpr = new TimeExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (Date.class.isAssignableFrom(type))
        {
            varExpr = new DateExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else if (java.util.Date.class.isAssignableFrom(type))
        {
            varExpr = new DateTimeExpressionImpl(type, name, ExpressionType.VARIABLE);
        }
        else
        {
            varExpr = new ObjectExpressionImpl(type, name, ExpressionType.VARIABLE);
        }

        return varExpr;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#excludeSubclasses()
     */
    public TypesafeQuery<T> excludeSubclasses()
    {
        this.subclasses = false;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#includeSubclasses()
     */
    public TypesafeQuery<T> includeSubclasses()
    {
        this.subclasses = true;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#filter(org.datanucleus.query.typesafe.BooleanExpression)
     */
    public TypesafeQuery<T> filter(BooleanExpression expr)
    {
        discardCompiled();
        this.filter = (BooleanExpressionImpl)expr;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#groupBy(org.datanucleus.query.typesafe.Expression[])
     */
    public TypesafeQuery<T> groupBy(Expression... exprs)
    {
        discardCompiled();
        if (exprs != null && exprs.length > 0)
        {
            grouping = new ArrayList<ExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                grouping.add((ExpressionImpl)exprs[i]);
            }
        }
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#having(org.datanucleus.query.typesafe.Expression)
     */
    public TypesafeQuery<T> having(Expression expr)
    {
        discardCompiled();
        this.having = (ExpressionImpl)expr;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#orderBy(org.datanucleus.query.typesafe.OrderExpression[])
     */
    public TypesafeQuery<T> orderBy(OrderExpression... exprs)
    {
        discardCompiled();
        if (exprs != null && exprs.length > 0)
        {
            ordering = new ArrayList<OrderExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                ordering.add((OrderExpressionImpl)exprs[i]);
            }
        }
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#range(long, long)
     */
    public TypesafeQuery<T> range(long lowerIncl, long upperExcl)
    {
        discardCompiled();
        this.rangeLowerExpr = new NumericExpressionImpl<T>(new Literal(lowerIncl));
        this.rangeUpperExpr = new NumericExpressionImpl<T>(new Literal(upperExcl));
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#range(org.datanucleus.query.typesafe.NumericExpression, org.datanucleus.query.typesafe.NumericExpression)
     */
    public TypesafeQuery<T> range(NumericExpression lowerInclExpr, NumericExpression upperExclExpr)
    {
        discardCompiled();
        this.rangeLowerExpr = (ExpressionImpl)lowerInclExpr;
        this.rangeUpperExpr = (ExpressionImpl)upperExclExpr;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#range(java.lang.String, java.lang.String)
     */
    public TypesafeQuery<T> range(Expression paramLowerInclExpr, Expression paramUpperExclExpr)
    {
        discardCompiled();
        if (!((ExpressionImpl)paramLowerInclExpr).isParameter())
        {
            throw new JDOUserException("lower inclusive expression should be a parameter");
        }
        else if (!((ExpressionImpl)paramUpperExclExpr).isParameter())
        {
            throw new JDOUserException("upper exclusive expression should be a parameter");
        }
        this.rangeLowerExpr = (ExpressionImpl)paramLowerInclExpr;
        this.rangeUpperExpr = (ExpressionImpl)paramUpperExclExpr;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#subquery(Class, String)
     */
    public <S> TypesafeSubquery<S> subquery(Class<S> candidateClass, String candidateAlias)
    {
        JDOTypesafeSubquery<S> subquery = new JDOTypesafeSubquery<S>(pm, candidateClass, candidateAlias, this);
        if (subqueries == null)
        {
            subqueries = new HashSet<JDOTypesafeSubquery>();
        }
        subqueries.add(subquery);
        return subquery;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#subquery(java.lang.String)
     */
    public TypesafeSubquery<T> subquery(String candidateAlias)
    {
        JDOTypesafeSubquery<T> subquery = new JDOTypesafeSubquery<T>(pm, this.candidateCls, candidateAlias, this);
        if (subqueries == null)
        {
            subqueries = new HashSet<JDOTypesafeSubquery>();
        }
        subqueries.add(subquery);
        return subquery;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#setParameter(org.datanucleus.query.typesafe.Expression, java.lang.Object)
     */
    public TypesafeQuery<T> setParameter(Expression paramExpr, Object value)
    {
        discardCompiled();

        ParameterExpression internalParamExpr = (ParameterExpression) ((ExpressionImpl)paramExpr).getQueryExpression();
        if (parameterExprByName == null ||
                (parameterExprByName != null && !parameterExprByName.containsKey(internalParamExpr.getAlias())))
        {
            throw new JDOUserException("Parameter with name " + internalParamExpr.getAlias() + " doesnt exist for this query");
        }

        if (parameterValuesByName == null)
        {
            parameterValuesByName = new HashMap<String, Object>();
        }
        parameterValuesByName.put(internalParamExpr.getAlias(), value);
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#setParameter(java.lang.String, java.lang.Object)
     */
    public TypesafeQuery<T> setParameter(String paramName, Object value)
    {
        discardCompiled();

        if (parameterExprByName == null ||
                (parameterExprByName != null && !parameterExprByName.containsKey(paramName)))
        {
            throw new JDOUserException("Parameter with name " + paramName + " doesnt exist for this query");
        }

        if (parameterValuesByName == null)
        {
            parameterValuesByName = new HashMap<String, Object>();
        }
        parameterValuesByName.put(paramName, value);
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#setCandidates(java.util.Collection)
     */
    public TypesafeQuery<T> setCandidates(Collection<T> candidates)
    {
        if (candidates != null)
        {
            this.candidates = new ArrayList<T>(candidates);
        }
        else
        {
            this.candidates = null;
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeList()
     */
    @SuppressWarnings("hiding")
    public <T> List<T> executeList()
    {
        if (result != null || resultDistinct != null || resultClass != null)
        {
            discardCompiled();
            result = null;
            resultClass = null;
            resultDistinct = null;
        }
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        unique = false;

        return (List<T>)executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeUnique()
     */
    @SuppressWarnings("hiding")
    public <T> T executeUnique()
    {
        if (result != null || resultDistinct != null || resultClass != null)
        {
            discardCompiled();
            result = null;
            resultClass = null;
            resultDistinct = null;
        }
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        unique = true;

        return (T)executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeResultList(boolean, org.datanucleus.query.typesafe.Expression[])
     */
    public List<Object[]> executeResultList(boolean distinct, Expression... exprs)
    {
        discardCompiled();
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        result = null;
        if (exprs != null && exprs.length > 0)
        {
            result = new ArrayList<ExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                result.add((ExpressionImpl)exprs[i]);
            }
        }
        this.resultClass = null;
        this.resultDistinct = distinct;

        return (List<Object[]>)executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeResultList(java.lang.Class, boolean, org.datanucleus.query.typesafe.Expression[])
     */
    public <R> List<R> executeResultList(Class<R> resultCls, boolean distinct, Expression... exprs)
    {
        discardCompiled();
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        result = null;
        if (exprs != null && exprs.length > 0)
        {
            result = new ArrayList<ExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                result.add((ExpressionImpl)exprs[i]);
            }
        }
        this.resultClass = resultCls;
        this.resultDistinct = distinct;
        this.unique = false;

        return (List<R>)executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeResultUnique(boolean, org.datanucleus.query.typesafe.Expression[])
     */
    public Object[] executeResultUnique(boolean distinct, Expression... exprs)
    {
        discardCompiled();
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        result = null;
        if (exprs != null && exprs.length > 0)
        {
            result = new ArrayList<ExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                result.add((ExpressionImpl)exprs[i]);
            }
        }
        this.resultClass = null;
        this.resultDistinct = distinct;
        this.unique = true;

        return (Object[])executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#executeResultUnique(java.lang.Class, boolean, org.datanucleus.query.typesafe.Expression[])
     */
    public <R> R executeResultUnique(Class<R> resultCls, boolean distinct, Expression... exprs)
    {
        discardCompiled();
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        result = null;
        if (exprs != null && exprs.length > 0)
        {
            result = new ArrayList<ExpressionImpl>();
            for (int i=0;i<exprs.length;i++)
            {
                result.add((ExpressionImpl)exprs[i]);
            }
        }
        this.resultClass = resultCls;
        this.resultDistinct = distinct;
        this.unique = true;

        return (R)executeInternalQuery(getInternalQuery());
    }

    /**
     * Convenience method to generate an internal DataNucleus Query and apply the generic compilation to it.
     * @return The internal DataNucleus query
     */
    protected Query getInternalQuery()
    {
        // Create a DataNucleus query and set the generic compilation
        Query internalQuery =
            ec.getStoreManager().getQueryManager().newQuery("JDOQL", ec, toString());
        internalQuery.setIgnoreCache(ignoreCache);
        if (!subclasses)
        {
            internalQuery.setSubclasses(false);
        }
        if (type == QueryType.SELECT)
        {
            if (resultDistinct != null)
            {
                internalQuery.setResultDistinct(resultDistinct.booleanValue());
            }
            internalQuery.setResultClass(resultClass);
            internalQuery.setUnique(unique);
        }
        if (extensions != null)
        {
            internalQuery.setExtensions(extensions);
        }
        if (fp != null)
        {
            internalQuery.setFetchPlan(((JDOFetchPlan)fp).getInternalFetchPlan());
        }
        if (type == QueryType.SELECT)
        {
            if (candidates != null)
            {
                internalQuery.setCandidates(candidates);
            }
        }

        QueryCompilation compilation = getCompilation();
        internalQuery.setCompilation(compilation);

        return internalQuery;
    }

    protected Object executeInternalQuery(Query internalQuery)
    {
        // Cache the internal query
        if (internalQueries == null)
        {
            internalQueries = new HashSet<Query>();
        }
        internalQueries.add(internalQuery);

        try
        {
            if (parameterValuesByName != null || parameterExprByName != null)
            {
                validateParameters();

                return internalQuery.executeWithMap(parameterValuesByName);
            }
            else
            {
                return internalQuery.execute();
            }
        }
        catch (NoQueryResultsException nqre)
        {
            return null;
        }
        catch (NucleusException jpe)
        {
            // Convert any exceptions into what JDO expects
            throw NucleusJDOHelper.getJDOExceptionForNucleusException(jpe);
        }
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#deletePersistentAll()
     */
    public long deletePersistentAll()
    {
        if (result != null || resultClass != null)
        {
            discardCompiled();
            result = null;
            resultClass = null;
        }
        type = QueryType.SELECT;
        updateExprs = null;
        updateVals = null;
        unique = false;

        try
        {
            Query internalQuery = getInternalQuery();
            if (parameterValuesByName != null || parameterExprByName != null)
            {
                validateParameters();

                return internalQuery.deletePersistentAll(parameterValuesByName);
            }
            else
            {
                return internalQuery.deletePersistentAll();
            }
        }
        catch (NucleusException jpe)
        {
            // Convert any exceptions into what JDO expects
            throw NucleusJDOHelper.getJDOExceptionForNucleusException(jpe);
        }
    }

    /**
     * Convenience method to validate the defined parameters, and the values provided for these parameters.
     * @throws JDOUserException if they are inconsistent
     */
    private void validateParameters()
    {
        int numParams = (parameterExprByName != null ? parameterExprByName.size() : 0);
        int numValues = (parameterValuesByName != null ? parameterValuesByName.size() : 0);

        // Validate the defined parameters and the provided values
        if (numParams != numValues)
        {
            throw new JDOUserException("Query has " + numParams + " but " +
                numValues + " values have been provided");
        }

        Iterator<String> paramIter = parameterExprByName.keySet().iterator();
        while (paramIter.hasNext())
        {
            String paramName = paramIter.next();
            if (!parameterValuesByName.containsKey(paramName))
            {
                throw new JDOUserException("Query has a parameter " + paramName +
                    " defined but no value supplied");
            }
        }
    }

    /**
     * Method to specify the update of a field of the candidate.
     * @param expr Expression for field of the candidate
     * @param val The new value
     * @return The query
     */
    public TypesafeQuery<T> set(Expression expr, Object val)
    {
        type = QueryType.BULK_UPDATE;

        // TODO Check that expr relates to the candidate
        if (updateExprs == null)
        {
            updateExprs = new ArrayList<ExpressionImpl>();
            updateVals = new ArrayList<ExpressionImpl>();
        }

        ExpressionImpl valExpr = null;
        org.datanucleus.query.expression.Expression literalExpr = new Literal(val);
        if (val instanceof String)
        {
            valExpr = new StringExpressionImpl(literalExpr);
        }
        else if (val instanceof Number)
        {
            valExpr = new NumericExpressionImpl(literalExpr);
        }
        else if (val instanceof java.sql.Time)
        {
            valExpr = new TimeExpressionImpl(literalExpr);
        }
        else if (val instanceof java.sql.Date)
        {
            valExpr = new DateExpressionImpl(literalExpr);
        }
        else if (val instanceof java.util.Date)
        {
            valExpr = new DateTimeExpressionImpl(literalExpr);
        }
        else if (val instanceof Boolean)
        {
            valExpr = new BooleanExpressionImpl(literalExpr);
        }
        else if (val instanceof Byte)
        {
            valExpr = new ByteExpressionImpl(literalExpr);
        }
        else if (val instanceof Enum)
        {
            valExpr = new EnumExpressionImpl(literalExpr);
        }

        updateExprs.add((ExpressionImpl) expr);
        updateVals.add(valExpr);

        return this;
    }

    /**
     * Extension method to provide bulk update capabilities (not part of JDO).
     * @return Number of instances that were updated
     */
    public long update()
    {
        type = QueryType.BULK_UPDATE;
        if (updateExprs == null || updateExprs.size() == 0)
        {
            throw new JDOUserException("No update expressions defined. Use set() method");
        }

        return (Long)executeInternalQuery(getInternalQuery());
    }

    /**
     * Extension method to provide bulk delete capabilities (not part of JDO).
     * This differs from deletePersistentAll() in that it doesn't cascade to related objects (unless the
     * datastore does that automatically), and that it doesn't attempt to update cached objects state to
     * reflect the deletion.
     * @return Number of instances that were deleted
     */
    public long delete()
    {
        type = QueryType.BULK_DELETE;
        updateExprs = null;
        updateVals = null;
        return (Long)executeInternalQuery(getInternalQuery());
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#getFetchPlan()
     */
    public FetchPlan getFetchPlan()
    {
        if (fp == null)
        {
            fp = new JDOFetchPlan(ec.getFetchPlan().getCopy());
        }
        return fp;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#getPersistenceManager()
     */
    public PersistenceManager getPersistenceManager()
    {
        return pm;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#setIgnoreCache(boolean)
     */
    public TypesafeQuery setIgnoreCache(boolean ignore)
    {
        this.ignoreCache = ignore;
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#addExtension(java.lang.String, java.lang.Object)
     */
    public TypesafeQuery addExtension(String key, Object value)
    {
        if (extensions == null)
        {
            extensions = new HashMap();
        }
        extensions.put(key, value);
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#setExtensions(java.util.Map)
     */
    public TypesafeQuery setExtensions(Map<String, Object> extensions)
    {
        this.extensions = new HashMap(extensions);
        return this;
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#close(java.lang.Object)
     */
    public void close(Object result)
    {
        if (internalQueries != null)
        {
            Iterator<Query> iter = internalQueries.iterator();
            while (iter.hasNext())
            {
                Query query = iter.next();
                query.close(result);
            }
        }
    }

    /* (non-Javadoc)
     * @see org.datanucleus.query.typesafe.TypesafeQuery#closeAll()
     */
    public void closeAll()
    {
        if (internalQueries != null)
        {
            Iterator<Query> iter = internalQueries.iterator();
            while (iter.hasNext())
            {
                Query query = iter.next();
                query.closeAll();
            }
            internalQueries.clear();
            internalQueries = null;
        }
    }

    /**
     * Method to compile the typesafe query.
     * @return The generic compilation
     */
    public QueryCompilation compile(MetaDataManager mmgr, ClassLoaderResolver clr)
    {
        QueryCompilation compilation = super.compile(mmgr, clr);

        // Add compilation of any subqueries
        if (subqueries != null && !subqueries.isEmpty())
        {
            Iterator<JDOTypesafeSubquery> iter = subqueries.iterator();
            int i = 0;
            while (iter.hasNext())
            {
                JDOTypesafeSubquery subquery = iter.next();
                QueryCompilation subqueryCompilation = subquery.getCompilation();
                compilation.addSubqueryCompilation(subquery.getAlias(), subqueryCompilation);
                i++;
            }
        }

        return compilation;
    }

    /**
     * Method to return the single-string form of this JDOQL query.
     * @return Single-string form of the query
     */
    public String toString()
    {
        if (queryString == null)
        {
            StringBuffer str = null;
            if (type == QueryType.BULK_UPDATE)
            {
                str = new StringBuffer("UPDATE");
            }
            else if (type == QueryType.BULK_DELETE)
            {
                str = new StringBuffer("DELETE");
            }
            else
            {
                str = new StringBuffer("SELECT");
            }

            if (type == QueryType.SELECT)
            {
                if (unique)
                {
                    str.append(" UNIQUE");
                }

                // Result
                if (result != null && !result.isEmpty())
                {
                    if (resultDistinct != null && resultDistinct.booleanValue())
                    {
                        str.append(" DISTINCT");
                    }
                    str.append(" ");
                    Iterator<ExpressionImpl> iter = result.iterator();
                    while (iter.hasNext())
                    {
                        ExpressionImpl resultExpr = iter.next();
                        str.append(JDOQLQueryHelper.getJDOQLForExpression(resultExpr.getQueryExpression()));
                        if (iter.hasNext())
                        {
                            str.append(",");
                        }
                    }
                }

                // Result class
                if (resultClass != null)
                {
                    str.append(" INTO ").append(resultClass.getName());
                }
            }

            // Candidate
            if (type == QueryType.SELECT || type == QueryType.BULK_DELETE)
            {
                str.append(" FROM ").append(candidateCls.getName());
            }
            else
            {
                str.append(" " + candidateCls.getName());
            }
            if (!subclasses)
            {
                str.append(" EXCLUDE SUBCLASSES");
            }

            if (type == QueryType.BULK_UPDATE)
            {
                str.append(" SET");
                Iterator<ExpressionImpl> exprIter = updateExprs.iterator();
                Iterator<ExpressionImpl> valIter = updateVals.iterator();
                while (exprIter.hasNext())
                {
                    ExpressionImpl expr = exprIter.next();
                    ExpressionImpl val = valIter.next();
                    str.append(" ").append(JDOQLQueryHelper.getJDOQLForExpression(expr.getQueryExpression()));
                    str.append(" = ").append(JDOQLQueryHelper.getJDOQLForExpression(val.getQueryExpression()));
                    if (exprIter.hasNext())
                    {
                        str.append(",");
                    }
                }
            }

            // Filter
            if (filter != null)
            {
                str.append(" WHERE ");
                str.append(JDOQLQueryHelper.getJDOQLForExpression(filter.getQueryExpression()));
            }

            if (type == QueryType.SELECT)
            {
                // Grouping
                if (grouping != null && !grouping.isEmpty())
                {
                    str.append(" GROUP BY ");
                    Iterator<ExpressionImpl> iter = grouping.iterator();
                    while (iter.hasNext())
                    {
                        ExpressionImpl groupExpr = iter.next();
                        str.append(JDOQLQueryHelper.getJDOQLForExpression(groupExpr.getQueryExpression()));
                        if (iter.hasNext())
                        {
                            str.append(",");
                        }
                    }
                }

                // Having
                if (having != null)
                {
                    str.append(" HAVING ");
                    str.append(JDOQLQueryHelper.getJDOQLForExpression(having.getQueryExpression()));
                }

                // Ordering
                if (ordering != null && !ordering.isEmpty())
                {
                    str.append(" ORDER BY ");
                    Iterator<OrderExpressionImpl> iter = ordering.iterator();
                    while (iter.hasNext())
                    {
                        OrderExpressionImpl orderExpr = iter.next();
                        str.append(JDOQLQueryHelper.getJDOQLForExpression(
                            ((ExpressionImpl)orderExpr.getExpression()).getQueryExpression()));
                        str.append(" " + (orderExpr.getDirection() == OrderDirection.ASC ? "ASCENDING" : "DESCENDING"));
                        if (iter.hasNext())
                        {
                            str.append(",");
                        }
                    }
                }

                // Range
                if (rangeLowerExpr != null && rangeUpperExpr != null)
                {
                    str.append(" RANGE ");
                    str.append(JDOQLQueryHelper.getJDOQLForExpression(rangeLowerExpr.getQueryExpression()));
                    str.append(",");
                    str.append(JDOQLQueryHelper.getJDOQLForExpression(rangeUpperExpr.getQueryExpression()));
                }
            }

            queryString = str.toString();
        }
        return queryString;
    }

    /**
     * Called when something is set on the query making any compilation invalid.
     */
    protected void discardCompiled()
    {
        super.discardCompiled();
        queryString = null;
    }

    /**
     * Method to return the (simple) name of the query class for a specified class name.
     * Currently just returns "Q{className}"
     * @param name Simple name of the class (without package)
     * @return Simple name of the query class
     */
    public static String getQueryClassNameForClassName(String name)
    {
        return QUERY_CLASS_PREFIX + name;
    }
}
TOP

Related Classes of org.datanucleus.api.jdo.query.JDOTypesafeQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.