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

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

There is a newer version: 1.2.0-Alpha1
Show 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.ArrayList;
import java.util.List;
import java.util.Map;

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

import com.blazebit.persistence.BaseFinalSetOperationBuilder;
import com.blazebit.persistence.BaseOngoingFinalSetOperationBuilder;
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 getQueryString1(StringBuilder sbSelectFrom) {
        boolean nested = isNested(setOperationManager.getStartQueryBuilder());
        if (nested) {
            sbSelectFrom.append('(');
        }
        
        setOperationManager.getStartQueryBuilder().getQueryString1(sbSelectFrom);
        
        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.getQueryString1(sbSelectFrom);
                
                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() {
        TypedQuery leftMostQuery = (TypedQuery) setOperationManager.getStartQueryBuilder().getTypedQuery();
        
        TypedQuery baseQuery;
        String sqlQuery;
        List participatingQueries = new ArrayList();
        
        if (leftMostQuery instanceof CustomSQLQuery) {
            CustomSQLQuery customQuery = (CustomSQLQuery) leftMostQuery;
            List customQueryParticipants = customQuery.getParticipatingQueries();
            participatingQueries.addAll(customQueryParticipants);
            baseQuery = (TypedQuery) customQueryParticipants.get(0);
            sqlQuery = customQuery.getSql();
        } else if (leftMostQuery instanceof CustomSQLTypedQuery) {
            CustomSQLTypedQuery customQuery = (CustomSQLTypedQuery) leftMostQuery;
            List customQueryParticipants = customQuery.getParticipatingQueries();
            participatingQueries.addAll(customQueryParticipants);
            baseQuery = (TypedQuery) customQueryParticipants.get(0);
            sqlQuery = customQuery.getSql();
        } else {
            baseQuery = leftMostQuery;
            participatingQueries.add(baseQuery);
            sqlQuery = cbf.getExtendedQuerySupport().getSql(em, baseQuery);
        }
        
        int size = sqlQuery.length() + 10;
        List setOperands = new ArrayList();
        setOperands.add(sqlQuery);
        
        for (AbstractCommonQueryBuilder setOperand : setOperationManager.getSetOperations()) {
            Query q = setOperand.getQuery();
            String setOperandSql;
            
            if (q instanceof CustomSQLQuery) {
                CustomSQLQuery customQuery = (CustomSQLQuery) q;
                List customQueryParticipants = customQuery.getParticipatingQueries();
                participatingQueries.addAll(customQueryParticipants);
                
                setOperandSql = customQuery.getSql();
            } else if (q instanceof CustomSQLTypedQuery) {
                CustomSQLTypedQuery customQuery = (CustomSQLTypedQuery) q;
                List customQueryParticipants = customQuery.getParticipatingQueries();
                participatingQueries.addAll(customQueryParticipants);

                setOperandSql = customQuery.getSql();
            } else {
                setOperandSql = cbf.getExtendedQuerySupport().getSql(em, q);
                participatingQueries.add(q);
            }
            
            setOperands.add(setOperandSql);
            size += setOperandSql.length() + 30;
        }

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

        dbmsDialect.appendSet(sqlSb, setOperationManager.getOperator(), setOperationManager.isNested(), setOperands, getOrderByElements(), limit, offset);
        StringBuilder withClause = applyCtes(sqlSb, baseQuery, false, participatingQueries);
        applyExtendedSql(sqlSb, false, false, withClause, null, null);
        
        String finalQuery = sqlSb.toString();
        // Unfortunately we need this little adapter here
        @SuppressWarnings("rawtypes")
        TypedQuery query = new CustomSQLTypedQuery(participatingQueries, baseQuery, new CommonQueryBuilderAdapter(this), cbf.getExtendedQuerySupport(), finalQuery);

        // TODO: needs tests
        if (selectManager.getSelectObjectBuilder() != null) {
            query = transformQuery(query);
        }
        
        return query;
    }
    
    protected Map applyExtendedSql(StringBuilder sqlSb, boolean isSubquery, boolean isEmbedded, StringBuilder withClause, String[] returningColumns, Map includedModificationStates) {
        // No limit/offset here because we need to handle that differently 
        return dbmsDialect.appendExtendedSql(sqlSb, statementType, isSubquery, isEmbedded, withClause, null, null, returningColumns, includedModificationStates);
    }

    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