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

grails.gorm.DetachedCriteria.groovy Maven / Gradle / Ivy

There is a newer version: 8.1.2
Show newest version
/* Copyright (C) 2011 SpringSource
 *
 * 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.
 */

package grails.gorm

import groovy.transform.CompileStatic
import groovy.transform.TypeCheckingMode
import org.grails.datastore.gorm.GormEnhancer
import org.grails.datastore.gorm.GormStaticApi
import org.grails.datastore.gorm.finders.DynamicFinder
import org.grails.datastore.gorm.query.GormOperations
import org.grails.datastore.gorm.query.criteria.AbstractDetachedCriteria
import org.grails.datastore.mapping.core.Session
import org.grails.datastore.mapping.query.Query
import org.grails.datastore.mapping.query.api.Criteria
import org.grails.datastore.mapping.query.api.ProjectionList
import org.grails.datastore.mapping.query.api.QueryAliasAwareSession
import org.grails.datastore.mapping.query.api.QueryArgumentsAware
import org.grails.datastore.mapping.query.api.QueryableCriteria

import javax.persistence.criteria.JoinType

/**
 * Represents criteria that is not bound to the current connection and can be built up and re-used at a later date.
 *
 * @author Graeme Rocher
 * @since 1.0
 */
@CompileStatic
class DetachedCriteria extends AbstractDetachedCriteria implements GormOperations, QueryableCriteria, Iterable {

    /**
     * Constructs a DetachedCriteria instance target the given class and alias for the name
     * @param targetClass The target class
     * @param alias The root alias to be used in queries
     */
    DetachedCriteria(Class targetClass, String alias = null) {
        super(targetClass, alias)
    }


    /**
     * Where method derives a new query from this query. This method will not mutate the original query, but instead return a new one.
     *
     * @param additionalQuery The additional query
     * @return A new query
     */
    @Override
    DetachedCriteria where(@DelegatesTo(DetachedCriteria) Closure additionalQuery) {
        DetachedCriteria newQuery = clone()
        return newQuery.build(additionalQuery)
    }

    @Override
    DetachedCriteria withConnection(String name) {
        return (DetachedCriteria)super.withConnection(name)
    }
/**
     * Where method derives a new query from this query. This method will not mutate the original query, but instead return a new one.
     *
     * @param additionalQuery The additional query
     * @return A new query
     */
    @Override
    DetachedCriteria whereLazy(@DelegatesTo(DetachedCriteria) Closure additionalQuery) {
        DetachedCriteria newQuery = clone()
        return newQuery.build(additionalQuery)
    }

    /**
     * Synonym for #get
     */
    T find(Map args = Collections.emptyMap(), @DelegatesTo(DetachedCriteria) Closure additionalCriteria = null) {
        get(args, additionalCriteria)
    }

    /**
     * Defines projections.
     *
     * @param callable The callable
     * @return This detached criteria
     */
    DetachedCriteria projections(@DelegatesTo(ProjectionList) Closure callable) {
        callable.delegate = projectionList
        callable.resolveStrategy = Closure.DELEGATE_FIRST
        callable.call()
        return this
    }

    /**
     * Synonym for #get
     */
    T find(@DelegatesTo(DetachedCriteria) Closure additionalCriteria) {
        get(Collections.emptyMap(), additionalCriteria)
    }

    /**
     * Returns a single result matching the criterion contained within this DetachedCriteria instance
     *
     * @return A single entity
     */
    T get(Map args = Collections.emptyMap(), @DelegatesTo(DetachedCriteria) Closure additionalCriteria = null) {
        (T)withPopulatedQuery(args, additionalCriteria) { Query query ->
            query.singleResult()
        }
    }

    /**
     * Returns a single result matching the criterion contained within this DetachedCriteria instance
     *
     * @return A single entity
     */
    T get(@DelegatesTo(DetachedCriteria) Closure additionalCriteria) {
        get(Collections.emptyMap(), additionalCriteria)
    }

    /**
     * Lists all records matching the criterion contained within this DetachedCriteria instance
     *
     * @return A list of matching instances
     */
    List list(Map args = Collections.emptyMap(), @DelegatesTo(DetachedCriteria) Closure additionalCriteria = null) {
        (List)withPopulatedQuery(args, additionalCriteria) { Query query ->
            if (args?.max) {
                return new PagedResultList(query)
            }
            return query.list()
        }
    }

    /**
     * Lists all records matching the criterion contained within this DetachedCriteria instance
     *
     * @return A list of matching instances
     */
    List list(@DelegatesTo(DetachedCriteria) Closure additionalCriteria) {
        list(Collections.emptyMap(), additionalCriteria)
    }

    @Override
    Iterator iterator() {
        return list().iterator()
    }

    @Override
    DetachedCriteria join(String property) {
        return (DetachedCriteria)super.join(property)
    }

    @Override
    DetachedCriteria join(String property, JoinType joinType) {
        return (DetachedCriteria)super.join(property, joinType)
    }

    @Override
    DetachedCriteria select(String property) {
        return (DetachedCriteria)super.select(property)
    }

    @Override
    DetachedCriteria and(@DelegatesTo(AbstractDetachedCriteria) Closure callable) {
        return (DetachedCriteria)super.and(callable)
    }

    @Override
    DetachedCriteria or(@DelegatesTo(AbstractDetachedCriteria) Closure callable) {
        return (DetachedCriteria)super.or(callable)
    }

    @Override
    DetachedCriteria not(@DelegatesTo(AbstractDetachedCriteria) Closure callable) {
        return (DetachedCriteria)super.not(callable)
    }

    @Override
    DetachedCriteria "in"(String propertyName, Collection values) {
        return (DetachedCriteria)super.in(propertyName, values)
    }

    @Override
    DetachedCriteria "in"(String propertyName, QueryableCriteria subquery) {
        return (DetachedCriteria)super.in(propertyName, subquery)
    }

    @Override
    DetachedCriteria inList(String propertyName, QueryableCriteria subquery) {
        return (DetachedCriteria)super.inList(propertyName, subquery)
    }

    @Override
    DetachedCriteria "in"(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure subquery) {
        return (DetachedCriteria)super.in(propertyName, subquery)
    }

    @Override
    DetachedCriteria inList(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure subquery) {
        return (DetachedCriteria)super.inList(propertyName, subquery)
    }

    @Override
    DetachedCriteria "in"(String propertyName, Object[] values) {
        return (DetachedCriteria)super.in(propertyName, values)
    }

    @Override
    DetachedCriteria notIn(String propertyName, QueryableCriteria subquery) {
        return (DetachedCriteria)super.notIn(propertyName, subquery)
    }

    @Override
    DetachedCriteria notIn(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure subquery) {
        return (DetachedCriteria)super.notIn(propertyName, subquery)
    }

    @Override
    DetachedCriteria order(String propertyName) {
        return (DetachedCriteria)super.order(propertyName)
    }

    @Override
    DetachedCriteria order(Query.Order o) {
        return (DetachedCriteria)super.order(o)
    }

    @Override
    DetachedCriteria order(String propertyName, String direction) {
        return (DetachedCriteria)super.order(propertyName, direction)
    }

    @Override
    DetachedCriteria inList(String propertyName, Collection values) {
        return (DetachedCriteria)super.inList(propertyName, values)
    }

    @Override
    DetachedCriteria inList(String propertyName, Object[] values) {
        return (DetachedCriteria)super.inList(propertyName, values)
    }

    @Override
    DetachedCriteria sizeEq(String propertyName, int size) {
        return (DetachedCriteria)super.sizeEq(propertyName, size)
    }

    @Override
    DetachedCriteria sizeGt(String propertyName, int size) {
        return (DetachedCriteria)super.sizeGt(propertyName, size)
    }

    @Override
    DetachedCriteria sizeGe(String propertyName, int size) {
        return (DetachedCriteria)super.sizeGe(propertyName, size)
    }

    @Override
    DetachedCriteria sizeLe(String propertyName, int size) {
        return (DetachedCriteria)super.sizeLe(propertyName, size)
    }

    @Override
    DetachedCriteria sizeLt(String propertyName, int size) {
        return (DetachedCriteria)super.sizeLt(propertyName, size)
    }

    @Override
    DetachedCriteria sizeNe(String propertyName, int size) {
        return (DetachedCriteria)super.sizeNe(propertyName, size)
    }

    @Override
    DetachedCriteria eqProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.eqProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria neProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.neProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria allEq(Map propertyValues) {
        return (DetachedCriteria)super.allEq(propertyValues)
    }

    @Override
    DetachedCriteria gtProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.gtProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria geProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.geProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria ltProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.ltProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria leProperty(String propertyName, String otherPropertyName) {
        return (DetachedCriteria)super.leProperty(propertyName, otherPropertyName)
    }

    @Override
    DetachedCriteria idEquals(Object value) {
        return (DetachedCriteria)super.idEquals(value)
    }

    @Override
    DetachedCriteria exists(QueryableCriteria subquery) {
        return (DetachedCriteria)super.exists(subquery)
    }

    @Override
    DetachedCriteria notExists(QueryableCriteria subquery) {
        return (DetachedCriteria)super.notExists(subquery)
    }

    @Override
    DetachedCriteria isEmpty(String propertyName) {
        return (DetachedCriteria)super.isEmpty(propertyName)
    }

    @Override
    DetachedCriteria isNotEmpty(String propertyName) {
        return (DetachedCriteria)super.isNotEmpty(propertyName)
    }

    @Override
    DetachedCriteria isNull(String propertyName) {
        return (DetachedCriteria)super.isNull(propertyName)
    }

    @Override
    DetachedCriteria isNotNull(String propertyName) {
        return (DetachedCriteria)super.isNotNull(propertyName)
    }

    @Override
    DetachedCriteria eq(String propertyName, Object propertyValue) {
        return (DetachedCriteria)super.eq(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria idEq(Object propertyValue) {
        return (DetachedCriteria)super.idEq(propertyValue)
    }

    @Override
    DetachedCriteria ne(String propertyName, Object propertyValue) {
        return (DetachedCriteria)super.ne(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria between(String propertyName, Object start, Object finish) {
        return (DetachedCriteria)super.between(propertyName, start, finish)
    }

    @Override
    DetachedCriteria gte(String property, Object value) {
        return (DetachedCriteria)super.gte(property, value)
    }

    @Override
    DetachedCriteria ge(String property, Object value) {
        return (DetachedCriteria)super.ge(property, value)
    }

    @Override
    DetachedCriteria gt(String property, Object value) {
        return (DetachedCriteria)super.gt(property, value)
    }

    @Override
    DetachedCriteria lte(String property, Object value) {
        return (DetachedCriteria)super.lte(property, value)
    }

    @Override
    DetachedCriteria le(String property, Object value) {
        return (DetachedCriteria)super.le(property, value)
    }

    @Override
    DetachedCriteria lt(String property, Object value) {
        return (DetachedCriteria)super.lt(property, value)
    }

    @Override
    DetachedCriteria like(String propertyName, Object propertyValue) {
        return (DetachedCriteria)super.like(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria ilike(String propertyName, Object propertyValue) {
        return (DetachedCriteria)super.ilike(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria rlike(String propertyName, Object propertyValue) {
        return (DetachedCriteria)super.rlike(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria eqAll(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.eqAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria gtAll(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.gtAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria ltAll(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.ltAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria geAll(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.geAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria leAll(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.leAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria eqAll(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.eqAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria gtAll(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.gtAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria gtSome(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.gtSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria gtSome(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.gtSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria geSome(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.geSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria geSome(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.geSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria ltSome(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.ltSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria ltSome(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.ltSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria leSome(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.leSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria leSome(String propertyName, @DelegatesTo(AbstractDetachedCriteria) Closure propertyValue) {
        return (DetachedCriteria)super.leSome(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria ltAll(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.ltAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria geAll(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.geAll(propertyName, propertyValue)
    }

    @Override
    DetachedCriteria leAll(String propertyName, QueryableCriteria propertyValue) {
        return (DetachedCriteria)super.leAll(propertyName, propertyValue)
    }
    /**
     * Counts the number of records returned by the query
     *
     * @param args The arguments
     * @return The count
     */
    Number count(Map args = Collections.emptyMap(), @DelegatesTo(DetachedCriteria) Closure additionalCriteria = null) {
        (Number)withPopulatedQuery(args, additionalCriteria) { Query query ->
            query.projections().count()
            query.singleResult()
        }
    }

    /**
     * Counts the number of records returned by the query
     *
     * @param args The arguments
     * @return The count
     */
    Number count(@DelegatesTo(DetachedCriteria) Closure additionalCriteria) {
        (Number)withPopulatedQuery(Collections.emptyMap(), additionalCriteria) { Query query ->
            query.projections().count()
            query.singleResult()
        }
    }

    /**
     * Synonym for #count()
     */
    Number size() {
        count()
    }

    /**
     * Counts the number of records returned by the query
     *
     * @param args The arguments
     * @return The count
     */

    boolean asBoolean(@DelegatesTo(DetachedCriteria) Closure additionalCriteria = null) {
        (Boolean)withPopulatedQuery(Collections.emptyMap(), additionalCriteria) { Query query ->
            query.projections().count()
            ((Number)query.singleResult()) > 0
        }
    }

    /**
     * Deletes all entities matching this criteria
     *
     * @return The total number deleted
     */
    Number deleteAll() {
        GormEnhancer.findStaticApi(targetClass, connectionName).withDatastoreSession { Session session ->
            session.deleteAll(this)
        }
    }

    /**
     * Updates all entities matching this criteria
     *
     * @return The total number updated
     */
    Number updateAll(Map properties) {
        GormEnhancer.findStaticApi(targetClass, connectionName).withDatastoreSession { Session session ->
            session.updateAll(this, properties)
        }
    }

    /**
     * Enable the builder syntax for constructing Criteria
     *
     * @param callable The callable closure
     * @return A new criteria instance
     */
    @Override
    DetachedCriteria build(@DelegatesTo(DetachedCriteria) Closure callable) {
        (DetachedCriteria)super.build(callable)
    }

    /**
     * Enable the builder syntax for constructing Criteria
     *
     * @param callable The callable closure
     * @return A new criteria instance
     */
    @Override
    DetachedCriteria buildLazy(@DelegatesTo(DetachedCriteria) Closure callable) {
        (DetachedCriteria)super.buildLazy(callable)
    }

    /**
     * Sets the default max to use and returns a new criteria instance. This method does not mutate the original criteria!
     *
     * @param max The max to use
     * @return A new DetachedCriteria instance derived from this
     */
    @Override
    DetachedCriteria max(int max) {
        (DetachedCriteria)super.max(max)
    }

    /**
     * Sets the default offset to use and returns a new criteria instance. This method does not mutate the original criteria!
     *
     * @param offset The offset to use
     * @return A new DetachedCriteria instance derived from this
     */
    @Override
    DetachedCriteria offset(int offset) {
        (DetachedCriteria)super.offset(offset)
    }

    /**
     * Adds a sort order to this criteria instance
     *
     * @param property The property to sort by
     * @return This criteria instance
     */
    DetachedCriteria sort(String property) {
        (DetachedCriteria)super.sort(property)
    }

    /**
     * Adds a sort order to this criteria instance
     *
     * @param property The property to sort by
     * @param direction The direction to sort by
     * @return This criteria instance
     */
    DetachedCriteria sort(String property, String direction) {
        (DetachedCriteria)super.sort(property,direction)
    }

    /**
     * Adds a property projection
     *
     * @param property The property to project
     * @return This criteria instance
     */
    DetachedCriteria property(String property) {
        (DetachedCriteria)super.property(property)
    }

    /**
     * Adds an id projection
     *
     * @param property The property to project
     * @return This criteria instance
     */
    DetachedCriteria id() {
        (DetachedCriteria)super.id()
    }

    /**
     * Adds a avg projection
     *
     * @param property The property to avg by
     * @return This criteria instance
     */
    DetachedCriteria avg(String property) {
        (DetachedCriteria)super.avg(property)
    }

    /**
     * Adds a sum projection
     *
     * @param property The property to sum by
     * @return This criteria instance
     */
    DetachedCriteria sum(String property) {
        (DetachedCriteria)super.sum(property)
    }

    /**
     * Adds a sum projection
     *
     * @param property The property to min by
     * @return This criteria instance
     */
    DetachedCriteria min(String property) {
        (DetachedCriteria)super.min(property)
    }

    /**
     * Adds a min projection
     *
     * @param property The property to max by
     * @return This criteria instance
     */
    DetachedCriteria max(String property) {
        (DetachedCriteria)super.max(property)
    }

    /**
     * Adds a distinct property projection
     *
     * @param property The property to obtain the distinct value for
     * @return This criteria instance
     */
    DetachedCriteria distinct(String property) {
        (DetachedCriteria)super.distinct(property)
    }


    @Override
    protected DetachedCriteria newInstance() {
        new DetachedCriteria(targetClass, alias)
    }

    @Override
    protected DetachedCriteria clone() {
        return (DetachedCriteria)super.clone()
    }

    protected void handleJunction(Closure callable) {
        try {
            callable.delegate = this
            callable.resolveStrategy = Closure.DELEGATE_FIRST
            callable.call()
        }
        finally {
            def lastJunction = junctions.remove(junctions.size() - 1)
            add lastJunction
        }
    }

    protected QueryableCriteria buildQueryableCriteria(Closure queryClosure) {
        return new DetachedCriteria(targetClass).build(queryClosure)
    }

    private withPopulatedQuery(Map args, Closure additionalCriteria, Closure callable)  {

        GormStaticApi staticApi = persistentEntity.isMultiTenant() ? GormEnhancer.findStaticApi(targetClass) : GormEnhancer.findStaticApi(targetClass, connectionName)
        staticApi.withDatastoreSession { Session session ->
            applyLazyCriteria()
            Query query
            if(alias && (session instanceof QueryAliasAwareSession)) {
                query = session.createQuery(targetClass, alias)
            }
            else {
                query = session.createQuery(targetClass)
            }

            if (defaultMax != null) {
                query.max(defaultMax)
            }
            if (defaultOffset != null) {
                query.offset(defaultOffset)
            }
            DynamicFinder.applyDetachedCriteria(query, this)

            if(query instanceof QueryArgumentsAware) {
                ((QueryArgumentsAware)query).arguments = args
            }

            if (additionalCriteria != null) {
                def additionalDetached = new DetachedCriteria(targetClass).build(additionalCriteria)
                DynamicFinder.applyDetachedCriteria(query, additionalDetached)
            }

            DynamicFinder.populateArgumentsForCriteria(targetClass, query, args)

            callable.call(query)
        }
    }

    protected void applyLazyCriteria() {
        if (lazyQuery == null) {
            return
        }

        def criteria = lazyQuery
        lazyQuery = null
        this.with criteria
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy