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

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

The newest version!
/*
 * Copyright 2015 Blazebit.
 *
 * 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 com.blazebit.persistence.impl;

import java.util.*;

import javax.persistence.Query;
import javax.persistence.TypedQuery;

import com.blazebit.persistence.BaseFinalSetOperationBuilder;
import com.blazebit.persistence.BaseOngoingFinalSetOperationBuilder;
import com.blazebit.persistence.impl.query.CTENode;
import com.blazebit.persistence.impl.query.EntityFunctionNode;
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.impl.query.SetOperationQuerySpecification;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DbmsStatementType;
import com.blazebit.persistence.spi.OrderByElement;
import com.blazebit.persistence.spi.SetOperationType;

/**
 *
 * @param  The query result type
 * @author Christian Beikov
 * @since 1.1.0
 */
public class BaseFinalSetOperationBuilderImpl, Y extends BaseFinalSetOperationBuilderImpl> extends AbstractCommonQueryBuilder, AbstractCommonQueryBuilder, Y> implements BaseFinalSetOperationBuilder, BaseOngoingFinalSetOperationBuilder {

    protected T endSetResult;
    
    protected final SetOperationManager setOperationManager;
    protected final List orderByElements;

    public BaseFinalSetOperationBuilderImpl(MainQuery mainQuery, boolean isMainQuery, Class clazz, SetOperationType operator, boolean nested, T endSetResult) {
        super(mainQuery, isMainQuery, DbmsStatementType.SELECT, clazz, null);
        this.endSetResult = endSetResult;
        this.setOperationManager = new SetOperationManager(operator, nested);
        this.orderByElements = new ArrayList(0);
    }
    
    private static boolean isNested(AbstractCommonQueryBuilder queryBuilder) {
        if (queryBuilder instanceof BaseFinalSetOperationBuilderImpl) {
            return ((BaseFinalSetOperationBuilderImpl) queryBuilder).setOperationManager.isNested();
        }
        
        return false;
    }
    
    @SuppressWarnings("unchecked")
    public X orderBy(String expression, boolean ascending, boolean nullFirst) {
        prepareAndCheck();
        AbstractCommonQueryBuilder leftMostQuery = getLeftMost(setOperationManager.getStartQueryBuilder());
        
        AliasInfo aliasInfo = leftMostQuery.aliasManager.getAliasInfo(expression);
        if (aliasInfo != null) {
            // find out the position by JPQL alias
            int position = cbf.getExtendedQuerySupport().getSqlSelectAliasPosition(em, leftMostQuery.getTypedQuery(), expression);
            orderByElements.add(new DefaultOrderByElement(expression, position, ascending, nullFirst));
            return (X) this;
        }

        int position = cbf.getExtendedQuerySupport().getSqlSelectAttributePosition(em, leftMostQuery.getTypedQuery(), expression);
        orderByElements.add(new DefaultOrderByElement(expression, position, ascending, nullFirst));
        
        return (X) this;
    }
    
    private AbstractCommonQueryBuilder getLeftMost(AbstractCommonQueryBuilder queryBuilder) {
        if (queryBuilder instanceof BaseFinalSetOperationBuilderImpl) {
            return getLeftMost(((BaseFinalSetOperationBuilderImpl) queryBuilder).setOperationManager.getStartQueryBuilder());
        }
        
        return queryBuilder;
    }
    
    protected List getOrderByElements() {
        return orderByElements;
    }
    
    public T getEndSetResult() {
        return endSetResult;
    }
    
    public void setEndSetResult(T endSetResult) {
        this.endSetResult = endSetResult;
    }

    public T endSet() {
        return endSetResult;
    }

    @Override
    protected void prepareAndCheck() {
        // nothing to do here
    }

    @Override
    protected void buildBaseQueryString(StringBuilder sbSelectFrom, boolean externalRepresentation) {
        boolean nested = isNested(setOperationManager.getStartQueryBuilder());
        if (nested) {
            sbSelectFrom.append('(');
        }
        
        setOperationManager.getStartQueryBuilder().buildBaseQueryString(sbSelectFrom, externalRepresentation);
        
        if (nested) {
            sbSelectFrom.append(')');
        }
        
        if (setOperationManager.hasSetOperations()) {
            String operator = getOperator(setOperationManager.getOperator());
            for (AbstractCommonQueryBuilder setOperand : setOperationManager.getSetOperations()) {
                sbSelectFrom.append("\n");
                sbSelectFrom.append(operator);
                sbSelectFrom.append("\n");
                
                nested = isNested(setOperand);
                if (nested) {
                    sbSelectFrom.append('(');
                }
                
                setOperand.buildBaseQueryString(sbSelectFrom, externalRepresentation);
                
                if (nested) {
                    sbSelectFrom.append(')');
                }
            }
            
            applySetOrderBy(sbSelectFrom);
            applyJpaLimit(sbSelectFrom);
        }
    }
    
    protected void applySetOrderBy(StringBuilder sbSelectFrom) {
        if (orderByElements.isEmpty()) {
            return;
        }
        
        sbSelectFrom.append("\nORDER BY ");
        
        for (int i = 0; i < orderByElements.size(); i++) {
            if (i != 0) {
                sbSelectFrom.append(", ");
            }
            
            DefaultOrderByElement elem = orderByElements.get(i);
            sbSelectFrom.append(elem.getName());

            if (elem.isAscending()) {
                sbSelectFrom.append(" ASC");
            } else {
                sbSelectFrom.append(" DESC");
            }
            
            if (elem.isNullsFirst()) {
                sbSelectFrom.append(" NULLS FIRST");
            } else {
                sbSelectFrom.append(" NULLS LAST");
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    protected TypedQuery getTypedQuery() {
        Set parameterListNames = new HashSet();
        TypedQuery leftMostQuery = (TypedQuery) setOperationManager.getStartQueryBuilder().getTypedQuery();
        TypedQuery baseQuery;

        parameterManager.collectParameterListNames(leftMostQuery, parameterListNames);

        if (leftMostQuery instanceof CustomSQLQuery) {
            CustomSQLQuery customQuery = (CustomSQLQuery) leftMostQuery;
            List customQueryParticipants = customQuery.getParticipatingQueries();
            baseQuery = (TypedQuery) customQueryParticipants.get(0);
        } else if (leftMostQuery instanceof CustomSQLTypedQuery) {
            CustomSQLTypedQuery customQuery = (CustomSQLTypedQuery) leftMostQuery;
            List customQueryParticipants = customQuery.getParticipatingQueries();
            baseQuery = (TypedQuery) customQueryParticipants.get(0);
        } else {
            baseQuery = leftMostQuery;
        }
        
        List setOperands = new ArrayList();

        for (AbstractCommonQueryBuilder setOperand : setOperationManager.getSetOperations()) {
            Query q = setOperand.getQuery();
            setOperands.add(q);
            parameterManager.collectParameterListNames(q, parameterListNames);
        }

        String limit = null;
        String offset = null;
        
        if (firstResult != 0) {
            offset = Integer.toString(firstResult);
        }
        if (maxResults != Integer.MAX_VALUE) {
            limit = Integer.toString(maxResults);
        }

        Set keyRestrictedLeftJoins = joinManager.getKeyRestrictedLeftJoins();
        List keyRestrictedLeftJoinAliases = getKeyRestrictedLeftJoinAliases(baseQuery, keyRestrictedLeftJoins, Collections.EMPTY_SET);
        List entityFunctionNodes = getEntityFunctionNodes(baseQuery);
        boolean shouldRenderCteNodes = renderCteNodes(false);
        List ctes = shouldRenderCteNodes ? getCteNodes(baseQuery, false) : Collections.EMPTY_LIST;
        QuerySpecification querySpecification = new SetOperationQuerySpecification(
                this,
                leftMostQuery,
                baseQuery,
                setOperands,
                setOperationManager.getOperator(),
                getOrderByElements(),
                setOperationManager.isNested(),
                parameterListNames,
                limit,
                offset,
                keyRestrictedLeftJoinAliases,
                entityFunctionNodes,
                mainQuery.cteManager.isRecursive(),
                ctes,
                shouldRenderCteNodes
        );
        
        // Unfortunately we need this little adapter here
        @SuppressWarnings("rawtypes")
        TypedQuery query = new CustomSQLTypedQuery(
                querySpecification,
                baseQuery,
                new CommonQueryBuilderAdapter(this),
                cbf.getExtendedQuerySupport(),
                parameterManager.getValuesParameters(),
                parameterManager.getValuesBinders()
        );

        // TODO: needs tests
        if (selectManager.getSelectObjectBuilder() != null) {
            query = transformQuery(query);
        }
        
        return query;
    }
    
    protected String getOperator(SetOperationType type) {
        switch (type) {
            case UNION: return "UNION";
            case UNION_ALL: return "UNION ALL";
            case INTERSECT: return "INTERSECT";
            case INTERSECT_ALL: return "INTERSECT ALL";
            case EXCEPT: return "EXCEPT";
            case EXCEPT_ALL: return "EXCEPT ALL";
        }
        
        return null;
    }

    @Override
    public TypedQuery getQuery() {
        return getTypedQuery();
    }

    public List getResultList() {
        return getTypedQuery().getResultList();
    }

    public T getSingleResult() {
        return getTypedQuery().getSingleResult();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy