Search in sources :

Example 1 with LimitBuilder

use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.

the class BlazeCriteriaBuilderRenderer method serializeSubQuery.

private Object serializeSubQuery(Object criteriaBuilder, Expression<?> expression) {
    Object result = expression.accept(new Visitor<Object, Object>() {

        @Override
        public Object visit(Constant<?> constant, Object criteriaBuilder) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object visit(FactoryExpression<?> factoryExpression, Object criteriaBuilder) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object visit(Operation<?> setOperation, Object criteriaBuilder) {
            Expression<?> lhs = setOperation.getArg(0);
            SubQueryExpression<?> lhsSubquery = lhs.accept(GetSubQueryVisitor.INSTANCE, null);
            SetOperationFlag setOperationFlag = lhsSubquery != null ? getSetOperationFlag(lhsSubquery.getMetadata()) : null;
            boolean lhsNestedSet = setOperationFlag != null && LEFT_NESTED_SET_OPERATIONS.contains(setOperation.getOperator());
            if (lhsNestedSet) {
                if (criteriaBuilder instanceof StartOngoingSetOperationBuilder) {
                    StartOngoingSetOperationBuilder<?, ?, ?> ob = (StartOngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder;
                    criteriaBuilder = ob.startSet();
                } else if (criteriaBuilder instanceof SubqueryInitiator) {
                    SubqueryInitiator<?> subqueryInitiator = (SubqueryInitiator<?>) criteriaBuilder;
                    criteriaBuilder = subqueryInitiator.startSet();
                } else {
                    criteriaBuilder = criteriaBuilderFactory.startSet(entityManager, Object.class);
                }
                criteriaBuilder = setOperationFlag.getFlag().accept(this, criteriaBuilder);
                if (criteriaBuilder instanceof OngoingSetOperationBuilder) {
                    criteriaBuilder = ((OngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder).endSetWith();
                    renderOrderBy(lhsSubquery.getMetadata(), (OrderByBuilder<?>) criteriaBuilder);
                    renderModifiers(lhsSubquery.getMetadata().getModifiers(), (LimitBuilder<?>) criteriaBuilder);
                    criteriaBuilder = ((BaseOngoingFinalSetOperationBuilder) criteriaBuilder).endSet();
                } else {
                    throw new UnsupportedOperationException();
                }
            } else {
                criteriaBuilder = lhs.accept(this, criteriaBuilder);
            }
            Expression<?> rhs = setOperation.getArg(1);
            SubQueryExpression<?> rhsSubquery = rhs.accept(GetSubQueryVisitor.INSTANCE, null);
            setOperationFlag = rhsSubquery != null ? getSetOperationFlag(rhsSubquery.getMetadata()) : null;
            boolean isNestedSet = setOperationFlag != null;
            SetOperationBuilder<?, ?> setOperationBuilder = (SetOperationBuilder<?, ?>) criteriaBuilder;
            switch((JPQLNextOps) setOperation.getOperator()) {
                // CHECKSTYLE:OFF: FallThrough
                case SET_UNION:
                case LEFT_NESTED_SET_UNION:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startUnion() : setOperationBuilder.union();
                    break;
                case SET_UNION_ALL:
                case LEFT_NESTED_SET_UNION_ALL:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startUnionAll() : setOperationBuilder.unionAll();
                    break;
                case SET_EXCEPT:
                case LEFT_NESTED_SET_EXCEPT:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startExcept() : setOperationBuilder.except();
                    break;
                case SET_EXCEPT_ALL:
                case LEFT_NESTED_SET_EXCEPT_ALL:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startExceptAll() : setOperationBuilder.exceptAll();
                    break;
                case SET_INTERSECT:
                case LEFT_NESTED_SET_INTERSECT:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startIntersect() : setOperationBuilder.intersect();
                    break;
                case SET_INTERSECT_ALL:
                case LEFT_NESTED_SET_INTERSECT_ALL:
                    criteriaBuilder = isNestedSet ? setOperationBuilder.startIntersectAll() : setOperationBuilder.intersectAll();
                    break;
                default:
                    throw new UnsupportedOperationException("No support for set operation " + setOperation.getOperator());
            }
            if (isNestedSet) {
                criteriaBuilder = setOperationFlag.getFlag().accept(this, criteriaBuilder);
                if (criteriaBuilder instanceof OngoingSetOperationBuilder) {
                    criteriaBuilder = ((OngoingSetOperationBuilder<?, ?, ?>) criteriaBuilder).endSetWith();
                    renderOrderBy(rhsSubquery.getMetadata(), (OrderByBuilder<?>) criteriaBuilder);
                    renderModifiers(rhsSubquery.getMetadata().getModifiers(), (LimitBuilder<?>) criteriaBuilder);
                    criteriaBuilder = ((BaseOngoingFinalSetOperationBuilder) criteriaBuilder).endSet();
                } else {
                    throw new UnsupportedOperationException();
                }
            } else {
                criteriaBuilder = rhs.accept(this, criteriaBuilder);
            }
            return criteriaBuilder;
        }

        @Override
        public Object visit(ParamExpression<?> paramExpression, Object criteriaBuilder) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object visit(Path<?> path, Object criteriaBuilder) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object visit(SubQueryExpression<?> subQuery, Object criteriaBuilder) {
            QueryMetadata subQueryMetadata = subQuery.getMetadata();
            SetOperationFlag setOperationFlag = getSetOperationFlag(subQueryMetadata);
            if (setOperationFlag != null) {
                return setOperationFlag.getFlag().accept(this, criteriaBuilder);
            }
            renderCTEs(subQueryMetadata);
            criteriaBuilder = renderJoins(subQueryMetadata, (FromBaseBuilder) criteriaBuilder);
            criteriaBuilder = renderNamedWindows(subQueryMetadata, (WindowContainerBuilder) criteriaBuilder);
            renderDistinct(subQueryMetadata, (DistinctBuilder<?>) criteriaBuilder);
            renderWhere(subQueryMetadata, (WhereBuilder<?>) criteriaBuilder);
            renderGroupBy(subQueryMetadata, (GroupByBuilder<?>) criteriaBuilder);
            renderHaving(subQueryMetadata, (HavingBuilder<?>) criteriaBuilder);
            Expression<?> select = subQueryMetadata.getProjection();
            if (select instanceof FactoryExpression<?> && criteriaBuilder instanceof FullQueryBuilder<?, ?>) {
                FactoryExpression<T> factoryExpression = (FactoryExpression<T>) select;
                FullQueryBuilder<?, ?> fullQueryBuilder = (FullQueryBuilder<?, ?>) criteriaBuilder;
                criteriaBuilder = fullQueryBuilder.selectNew(new FactoryExpressionObjectBuilder(factoryExpression));
            } else {
                List<? extends Expression<?>> projection = expandProjection(subQueryMetadata.getProjection());
                if (criteriaBuilder instanceof SelectBaseCTECriteriaBuilder) {
                    SelectBaseCTECriteriaBuilder<?> selectBaseCriteriaBuilder = (SelectBaseCTECriteriaBuilder<?>) criteriaBuilder;
                    boolean bindEntity = projection.size() == 1 && subQueryMetadata.getJoins().get(0).getTarget().accept(new JoinTargetAliasPathResolver(), null).equals(projection.get(0));
                    if (bindEntity) {
                        EntityMetamodel metamodel = criteriaBuilderFactory.getService(EntityMetamodel.class);
                        Path<?> pathExpression = (Path<?>) projection.get(0);
                        ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, pathExpression.getType());
                        Map<String, ? extends ExtendedAttribute<?, ?>> ownedSingularAttributes = managedType.getOwnedSingularAttributes();
                        for (Map.Entry<String, ? extends ExtendedAttribute<?, ?>> ownedSingularAttribute : ownedSingularAttributes.entrySet()) {
                            String attributeName = ownedSingularAttribute.getKey();
                            ExtendedAttribute<?, ?> attribute = ownedSingularAttribute.getValue();
                            if (!JpaMetamodelUtils.isAssociation(attribute.getAttribute())) {
                                final SelectBuilder<?> bindBuilder = selectBaseCriteriaBuilder.bind(attributeName);
                                BeanPath<?> beanPath = new BeanPath<Object>(attribute.getElementClass(), pathExpression, attributeName);
                                setExpressionSubqueries(beanPath, null, bindBuilder, SelectBuilderExpressionSetter.INSTANCE);
                            }
                        }
                    } else {
                        for (int i = 0; i < projection.size(); i++) {
                            Expression<?> projExpression = projection.get(i);
                            BindResolverContext bindResolverContext = new BindResolverContext();
                            projExpression = projExpression.accept(BindResolver.INSTANCE, bindResolverContext);
                            Path<?> cteAttribute = bindResolverContext.getCteAttribute();
                            String alias = bindResolverContext.getAliasString();
                            if (cteAttribute == null && cteAliases != null) {
                                cteAttribute = cteAliases.get(i);
                            }
                            if (cteAttribute != null) {
                                Path<?> cteEntityPath = cteAttribute.getRoot();
                                String relativeCteAttributePath = relativePathString(cteEntityPath, cteAttribute);
                                final SelectBuilder<?> bindBuilder = selectBaseCriteriaBuilder.bind(relativeCteAttributePath);
                                setExpressionSubqueries(projExpression, alias, bindBuilder, SelectBuilderExpressionSetter.INSTANCE);
                            } else {
                                throw new UnsupportedOperationException("Select statement should be bound to any CTE attribute");
                            }
                        }
                    }
                } else {
                    for (Expression<?> selection : projection) {
                        renderSingleSelect(selection, (SelectBuilder<?>) criteriaBuilder);
                    }
                }
            }
            renderOrderBy(subQueryMetadata, (OrderByBuilder<?>) criteriaBuilder);
            renderParameters(subQueryMetadata, (ParameterHolder<?>) criteriaBuilder);
            // Limit / offset on full query is set outside of the renderer, based on whether we're rendering a full count query or not
            if (!(criteriaBuilder instanceof Queryable)) {
                renderModifiers(subQueryMetadata.getModifiers(), (LimitBuilder<?>) criteriaBuilder);
            }
            return criteriaBuilder;
        }

        @Override
        public Object visit(TemplateExpression<?> templateExpression, Object criteriaBuilder) {
            throw new UnsupportedOperationException();
        }
    }, criteriaBuilder);
    if (result instanceof BaseOngoingSetOperationBuilder) {
        result = ((BaseOngoingSetOperationBuilder<?, ?, ?>) result).endSet();
    }
    if ((result instanceof FinalSetOperationCriteriaBuilder || result instanceof FinalSetOperationCTECriteriaBuilder || result instanceof FinalSetOperationSubqueryBuilder) && expression instanceof SubQueryExpression<?>) {
        QueryMetadata metadata = ((SubQueryExpression<?>) expression).getMetadata();
        renderOrderBy(metadata, (OrderByBuilder<?>) result);
        // Limit / offset on full query is set outside of the renderer, based on whether we're rendering a full count query or not
        if (!(criteriaBuilder instanceof Queryable)) {
            renderModifiers(metadata.getModifiers(), (LimitBuilder<?>) result);
        }
    }
    return result;
}
Also used : SubQueryExpression(com.querydsl.core.types.SubQueryExpression) QueryMetadata(com.querydsl.core.QueryMetadata) FinalSetOperationCTECriteriaBuilder(com.blazebit.persistence.FinalSetOperationCTECriteriaBuilder) BaseOngoingFinalSetOperationBuilder(com.blazebit.persistence.BaseOngoingFinalSetOperationBuilder) BeanPath(com.querydsl.core.types.dsl.BeanPath) BaseOngoingFinalSetOperationBuilder(com.blazebit.persistence.BaseOngoingFinalSetOperationBuilder) SetOperationBuilder(com.blazebit.persistence.SetOperationBuilder) StartOngoingSetOperationBuilder(com.blazebit.persistence.StartOngoingSetOperationBuilder) BaseOngoingSetOperationBuilder(com.blazebit.persistence.BaseOngoingSetOperationBuilder) OngoingSetOperationBuilder(com.blazebit.persistence.OngoingSetOperationBuilder) SelectBaseCTECriteriaBuilder(com.blazebit.persistence.SelectBaseCTECriteriaBuilder) StartOngoingSetOperationBuilder(com.blazebit.persistence.StartOngoingSetOperationBuilder) FinalSetOperationCriteriaBuilder(com.blazebit.persistence.FinalSetOperationCriteriaBuilder) FullQueryBuilder(com.blazebit.persistence.FullQueryBuilder) OrderByBuilder(com.blazebit.persistence.OrderByBuilder) List(java.util.List) ArrayList(java.util.ArrayList) SubqueryInitiator(com.blazebit.persistence.SubqueryInitiator) MultipleSubqueryInitiator(com.blazebit.persistence.MultipleSubqueryInitiator) HavingBuilder(com.blazebit.persistence.HavingBuilder) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) FinalSetOperationSubqueryBuilder(com.blazebit.persistence.FinalSetOperationSubqueryBuilder) DistinctBuilder(com.blazebit.persistence.DistinctBuilder) ExtendedManagedType(com.blazebit.persistence.spi.ExtendedManagedType) GroupByBuilder(com.blazebit.persistence.GroupByBuilder) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) ParameterHolder(com.blazebit.persistence.ParameterHolder) SetOperationFlag.getSetOperationFlag(com.blazebit.persistence.querydsl.SetOperationFlag.getSetOperationFlag) FactoryExpression(com.querydsl.core.types.FactoryExpression) Queryable(com.blazebit.persistence.Queryable) WhereBuilder(com.blazebit.persistence.WhereBuilder) SelectBuilder(com.blazebit.persistence.SelectBuilder) Path(com.querydsl.core.types.Path) BeanPath(com.querydsl.core.types.dsl.BeanPath) LimitBuilder(com.blazebit.persistence.LimitBuilder) BaseOngoingSetOperationBuilder(com.blazebit.persistence.BaseOngoingSetOperationBuilder) StartOngoingSetOperationBuilder(com.blazebit.persistence.StartOngoingSetOperationBuilder) BaseOngoingSetOperationBuilder(com.blazebit.persistence.BaseOngoingSetOperationBuilder) OngoingSetOperationBuilder(com.blazebit.persistence.OngoingSetOperationBuilder) ParamExpression(com.querydsl.core.types.ParamExpression) Expression(com.querydsl.core.types.Expression) TemplateExpression(com.querydsl.core.types.TemplateExpression) FactoryExpression(com.querydsl.core.types.FactoryExpression) SubQueryExpression(com.querydsl.core.types.SubQueryExpression) JoinExpression(com.querydsl.core.JoinExpression) EntityMetamodel(com.blazebit.persistence.parser.EntityMetamodel)

Example 2 with LimitBuilder

use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.

the class ExpressionCorrelationJoinTupleElementMapper method applyMapping.

@Override
public void applyMapping(SelectBuilder<?> queryBuilder, ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, boolean asString) {
    String oldViewPath = viewJpqlMacro.getViewPath();
    String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
    viewJpqlMacro.setViewPath(embeddingViewPath);
    embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
    FullQueryBuilder<?, ?> fullQueryBuilder;
    if (queryBuilder instanceof ConstrainedSelectBuilder) {
        fullQueryBuilder = ((ConstrainedSelectBuilder) queryBuilder).getQueryBuilder();
    } else {
        fullQueryBuilder = (FullQueryBuilder<?, ?>) queryBuilder;
    }
    int originalFirstResult = -1;
    int originalMaxResults = -1;
    if (queryBuilder instanceof LimitBuilder<?>) {
        originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
        originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
    }
    JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, fullQueryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
    provider.applyCorrelation(correlationBuilder, correlationBasis);
    if (queryBuilder instanceof LimitBuilder<?>) {
        if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
            throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
        }
    }
    correlationBuilder.finish();
    // Basic element has an alias, subviews don't
    if (alias != null) {
        viewJpqlMacro.setViewPath(null);
        queryBuilder.select(correlationResult, alias);
    }
    viewJpqlMacro.setViewPath(oldViewPath);
    embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
    if (fetches.length != 0) {
        for (int i = 0; i < fetches.length; i++) {
            fullQueryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
        }
    }
}
Also used : JoinCorrelationBuilder(com.blazebit.persistence.view.impl.objectbuilder.transformer.correlation.JoinCorrelationBuilder) LimitBuilder(com.blazebit.persistence.LimitBuilder)

Example 3 with LimitBuilder

use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.

the class AbstractCorrelatedSubselectTupleTransformer method prepare.

private void prepare() {
    JpaProvider jpaProvider = entityViewConfiguration.getCriteriaBuilder().getService(JpaProvider.class);
    FullQueryBuilder<?, ?> queryBuilder = entityViewConfiguration.getCriteriaBuilder();
    Map<String, Object> optionalParameters = entityViewConfiguration.getOptionalParameters();
    Class<?> correlationBasisEntityType = correlationBasisEntity;
    String viewRootExpression = viewRootAlias;
    EmbeddingViewJpqlMacro embeddingViewJpqlMacro = entityViewConfiguration.getEmbeddingViewJpqlMacro();
    ViewJpqlMacro viewJpqlMacro = entityViewConfiguration.getViewJpqlMacro();
    if (queryBuilder instanceof PaginatedCriteriaBuilder<?>) {
        criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
    } else {
        LimitBuilder<?> limitBuilder = (LimitBuilder<?>) queryBuilder;
        // To set the limit, we need the JPA provider to support this
        if (jpaProvider.supportsSubqueryInFunction() && (limitBuilder.getFirstResult() > 0 || limitBuilder.getMaxResults() < Integer.MAX_VALUE)) {
            // we must turn this query builder into a paginated criteria builder first
            try {
                criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, true).page(limitBuilder.getFirstResult(), limitBuilder.getMaxResults()).copyCriteriaBuilder(Object[].class, false);
            } catch (IllegalStateException ex) {
                LOG.log(Level.WARNING, "Could not create a paginated criteria builder for SUBSELECT fetching which might lead to bad performance", ex);
                criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
            }
        } else {
            // Regular query without limit/offset
            criteriaBuilder = queryBuilder.copyCriteriaBuilder(Object[].class, false);
        }
    }
    int originalFirstResult = 0;
    int originalMaxResults = Integer.MAX_VALUE;
    // A copied query that is extended with further joins can't possibly use the limits provided by the outer query
    ((LimitBuilder<?>) criteriaBuilder).setFirstResult(originalFirstResult);
    ((LimitBuilder<?>) criteriaBuilder).setMaxResults(originalMaxResults);
    this.viewRootJpqlMacro = new CorrelatedSubqueryViewRootJpqlMacro(criteriaBuilder, optionalParameters, false, viewRootEntityClass, idAttributePath, viewRootExpression);
    criteriaBuilder.registerMacro("view", viewJpqlMacro);
    criteriaBuilder.registerMacro("view_root", viewRootJpqlMacro);
    criteriaBuilder.registerMacro("embedding_view", embeddingViewJpqlMacro);
    String oldViewPath = viewJpqlMacro.getViewPath();
    String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
    viewJpqlMacro.setViewPath(correlationResultExpression);
    embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
    String joinBase = embeddingViewPath;
    SubqueryCorrelationBuilder correlationBuilder = new SubqueryCorrelationBuilder(queryBuilder, optionalParameters, criteriaBuilder, correlationAlias, correlationExternalAlias, correlationResultExpression, correlationBasisType, correlationBasisEntityType, joinBase, attributePath, 1, limiter, true);
    CorrelationProvider provider = correlationProviderFactory.create(entityViewConfiguration.getCriteriaBuilder(), entityViewConfiguration.getOptionalParameters());
    provider.applyCorrelation(correlationBuilder, correlationBasisExpression);
    if (criteriaBuilder instanceof LimitBuilder<?>) {
        if (originalFirstResult != ((LimitBuilder<?>) criteriaBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) criteriaBuilder).getMaxResults()) {
            throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
        }
    }
    if (fetches.length != 0) {
        for (int i = 0; i < fetches.length; i++) {
            criteriaBuilder.fetch(fetches[i]);
        }
    }
    if (indexFetches.length != 0) {
        for (int i = 0; i < indexFetches.length; i++) {
            criteriaBuilder.fetch(indexFetches[i]);
        }
    }
    // Before we can determine whether we use view roots or embedding views, we need to add all selects, otherwise macros might report false although they are used
    final String correlationRoot = correlationBuilder.getCorrelationRoot();
    final int tupleSuffix = maximumViewMapperCount + 1 + (indexCorrelator == null && indexExpression == null ? 0 : 1);
    ObjectBuilder<Object[]> objectBuilder = (ObjectBuilder<Object[]>) correlator.finish(criteriaBuilder, entityViewConfiguration, 0, tupleSuffix, correlationRoot, embeddingViewJpqlMacro, true);
    final boolean usesViewRoot = viewRootJpqlMacro.usesViewMacro();
    final boolean usesEmbeddingView = embeddingViewJpqlMacro.usesEmbeddingView();
    if (usesEmbeddingView && !(embeddingViewType instanceof ViewType<?>)) {
        throw new IllegalStateException("The use of EMBEDDING_VIEW in the correlation for '" + embeddingViewType.getJavaType().getName() + "." + attributePath.substring(attributePath.lastIndexOf('.') + 1) + "' is illegal because the embedding view type '" + embeddingViewType.getJavaType().getName() + "' does not declare a @IdMapping!");
    } else if (usesViewRoot && !(viewRootType instanceof ViewType<?>)) {
        throw new IllegalStateException("The use of VIEW_ROOT in the correlation for '" + embeddingViewType.getJavaType().getName() + "." + attributePath.substring(attributePath.lastIndexOf('.') + 1) + "' is illegal because the view root type '" + viewRootType.getJavaType().getName() + "' does not declare a @IdMapping!");
    }
    final int maximumSlotsFilled;
    final int elementKeyIndex;
    final int elementViewIndex;
    if (usesEmbeddingView) {
        maximumSlotsFilled = embeddingViewIdMapperCount == 0 ? 1 : embeddingViewIdMapperCount;
        elementKeyIndex = (maximumViewMapperCount - maximumSlotsFilled) + 2 + valueIndex;
        elementViewIndex = (maximumViewMapperCount - maximumSlotsFilled) + 1 + valueIndex;
        viewIndex = embeddingViewIndex;
    } else if (usesViewRoot) {
        maximumSlotsFilled = viewRootIdMapperCount == 0 ? 1 : viewRootIdMapperCount;
        elementKeyIndex = (maximumViewMapperCount - maximumSlotsFilled) + 2 + valueIndex;
        elementViewIndex = (maximumViewMapperCount - maximumSlotsFilled) + 1 + valueIndex;
        viewIndex = viewRootIndex;
    } else {
        maximumSlotsFilled = 0;
        elementKeyIndex = maximumViewMapperCount + 1 + valueIndex;
        elementViewIndex = 1 + valueIndex;
        viewIndex = -1;
    }
    for (int i = maximumSlotsFilled; i < maximumViewMapperCount; i++) {
        criteriaBuilder.select("NULL");
    }
    ExpressionFactory ef = criteriaBuilder.getService(ExpressionFactory.class);
    if (usesEmbeddingView) {
        EntityViewConfiguration configuration = new EntityViewConfiguration(criteriaBuilder, ef, new MutableViewJpqlMacro(), new MutableEmbeddingViewJpqlMacro(), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), entityViewConfiguration.getFetches(), attributePath);
        ObjectBuilder<Object[]> embeddingViewObjectBuilder = createViewAwareObjectBuilder(criteriaBuilder, embeddingViewType, configuration, embeddingViewIdExpression);
        if (embeddingViewObjectBuilder == null) {
            criteriaBuilder.select(embeddingViewIdExpression);
        } else {
            criteriaBuilder.selectNew(objectBuilder = new LateAdditionalObjectBuilder(objectBuilder, embeddingViewObjectBuilder, true));
        }
    } else if (usesViewRoot) {
        EntityViewConfiguration configuration = new EntityViewConfiguration(criteriaBuilder, ef, new MutableViewJpqlMacro(), new MutableEmbeddingViewJpqlMacro(), Collections.<String, Object>emptyMap(), Collections.<String, Object>emptyMap(), entityViewConfiguration.getFetches(), attributePath);
        ObjectBuilder<Object[]> viewRootObjectBuilder = createViewAwareObjectBuilder(criteriaBuilder, viewRootType, configuration, viewRootIdExpression);
        if (viewRootObjectBuilder == null) {
            criteriaBuilder.select(viewRootIdExpression);
        } else {
            criteriaBuilder.selectNew(objectBuilder = new LateAdditionalObjectBuilder(objectBuilder, viewRootObjectBuilder, true));
        }
    }
    criteriaBuilder.select(correlationKeyExpression);
    if (indexCorrelator != null) {
        ObjectBuilder<?> indexBuilder = indexCorrelator.finish(criteriaBuilder, entityViewConfiguration, maximumViewMapperCount + 2, 0, indexExpression, embeddingViewJpqlMacro, true);
        if (indexBuilder != null) {
            criteriaBuilder.selectNew(new LateAdditionalObjectBuilder(objectBuilder, indexBuilder, false));
        }
    }
    populateParameters(entityViewConfiguration, criteriaBuilder);
    viewJpqlMacro.setViewPath(oldViewPath);
    embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
    List<Object[]> resultList = (List<Object[]>) criteriaBuilder.getResultList();
    Map<Object, Map<Object, Object>> collections = new HashMap<>(resultList.size());
    for (int i = 0; i < resultList.size(); i++) {
        Object[] element = resultList.get(i);
        Map<Object, Object> viewRootResult = collections.get(element[elementViewIndex]);
        if (viewRootResult == null) {
            viewRootResult = new HashMap<>();
            collections.put(element[elementViewIndex], viewRootResult);
        }
        if (this.containerAccumulator == null) {
            viewRootResult.put(element[elementKeyIndex], element[valueIndex]);
        } else {
            Object result = viewRootResult.get(element[elementKeyIndex]);
            if (result == null) {
                result = createDefaultResult();
                viewRootResult.put(element[elementKeyIndex], result);
            }
            Object indexObject = null;
            if (indexCorrelator != null || indexExpression != null) {
                indexObject = element[elementKeyIndex + 1];
            }
            this.containerAccumulator.add(result, indexObject, element[valueIndex], isRecording());
        }
    }
    this.collections = collections;
}
Also used : EntityViewConfiguration(com.blazebit.persistence.view.impl.EntityViewConfiguration) LateAdditionalObjectBuilder(com.blazebit.persistence.view.impl.objectbuilder.LateAdditionalObjectBuilder) HashMap(java.util.HashMap) ViewJpqlMacro(com.blazebit.persistence.view.spi.ViewJpqlMacro) EmbeddingViewJpqlMacro(com.blazebit.persistence.view.spi.EmbeddingViewJpqlMacro) MutableViewJpqlMacro(com.blazebit.persistence.view.impl.macro.MutableViewJpqlMacro) MutableEmbeddingViewJpqlMacro(com.blazebit.persistence.view.impl.macro.MutableEmbeddingViewJpqlMacro) PaginatedCriteriaBuilder(com.blazebit.persistence.PaginatedCriteriaBuilder) MutableEmbeddingViewJpqlMacro(com.blazebit.persistence.view.impl.macro.MutableEmbeddingViewJpqlMacro) List(java.util.List) ExpressionFactory(com.blazebit.persistence.parser.expression.ExpressionFactory) JpaProvider(com.blazebit.persistence.spi.JpaProvider) LimitBuilder(com.blazebit.persistence.LimitBuilder) CorrelatedSubqueryViewRootJpqlMacro(com.blazebit.persistence.view.impl.macro.CorrelatedSubqueryViewRootJpqlMacro) EmbeddingViewJpqlMacro(com.blazebit.persistence.view.spi.EmbeddingViewJpqlMacro) MutableEmbeddingViewJpqlMacro(com.blazebit.persistence.view.impl.macro.MutableEmbeddingViewJpqlMacro) ObjectBuilder(com.blazebit.persistence.ObjectBuilder) LateAdditionalObjectBuilder(com.blazebit.persistence.view.impl.objectbuilder.LateAdditionalObjectBuilder) MutableViewJpqlMacro(com.blazebit.persistence.view.impl.macro.MutableViewJpqlMacro) CorrelationProvider(com.blazebit.persistence.view.CorrelationProvider) HashMap(java.util.HashMap) Map(java.util.Map) UpdatableViewMap(com.blazebit.persistence.view.impl.objectbuilder.transformator.UpdatableViewMap) ManagedViewType(com.blazebit.persistence.view.metamodel.ManagedViewType) ViewType(com.blazebit.persistence.view.metamodel.ViewType)

Example 4 with LimitBuilder

use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.

the class CorrelatedSubviewJoinTupleTransformerFactory method create.

@Override
public TupleTransformer create(ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, EntityViewConfiguration entityViewConfiguration) {
    if (!entityViewConfiguration.hasSubFetches(attributePath)) {
        return new NullTupleTransformer(template);
    }
    // For now it's ok, but at some point we will want to support correlated attributes somehow and need to think of a fallback solution here
    if (parameterHolder instanceof FullQueryBuilder<?, ?>) {
        FullQueryBuilder<?, ?> queryBuilder = (FullQueryBuilder<?, ?>) parameterHolder;
        CorrelationProvider provider = correlationProviderFactory.create(parameterHolder, optionalParameters);
        JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, queryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
        int originalFirstResult = -1;
        int originalMaxResults = -1;
        if (queryBuilder instanceof LimitBuilder<?>) {
            originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
            originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
        }
        ViewJpqlMacro viewJpqlMacro = entityViewConfiguration.getViewJpqlMacro();
        EmbeddingViewJpqlMacro embeddingViewJpqlMacro = entityViewConfiguration.getEmbeddingViewJpqlMacro();
        String oldViewPath = viewJpqlMacro.getViewPath();
        String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
        // If this uses a static path, we need to avoid setting the embedding view path etc.
        if (!(provider instanceof StaticPathCorrelationProvider)) {
            viewJpqlMacro.setViewPath(correlationBuilder.getCorrelationAlias());
            embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
        }
        provider.applyCorrelation(correlationBuilder, correlationBasis);
        if (queryBuilder instanceof LimitBuilder<?>) {
            if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
                throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
            }
        }
        correlationBuilder.finish();
        if (!(provider instanceof StaticPathCorrelationProvider)) {
            viewJpqlMacro.setViewPath(oldViewPath);
            embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
        }
        if (fetches.length != 0) {
            for (int i = 0; i < fetches.length; i++) {
                queryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
            }
        }
        ObjectBuilder<Object[]> objectBuilder = template.createObjectBuilder(parameterHolder, optionalParameters, entityViewConfiguration, 0, true, false);
        return new CorrelatedSubviewJoinTupleTransformer(template, objectBuilder);
    } else {
        throw new UnsupportedOperationException("Converting views with correlated attributes isn't supported!");
    }
}
Also used : LimitBuilder(com.blazebit.persistence.LimitBuilder) EmbeddingViewJpqlMacro(com.blazebit.persistence.view.spi.EmbeddingViewJpqlMacro) ViewJpqlMacro(com.blazebit.persistence.view.spi.ViewJpqlMacro) EmbeddingViewJpqlMacro(com.blazebit.persistence.view.spi.EmbeddingViewJpqlMacro) CorrelationProvider(com.blazebit.persistence.view.CorrelationProvider) StaticPathCorrelationProvider(com.blazebit.persistence.view.impl.StaticPathCorrelationProvider) StaticPathCorrelationProvider(com.blazebit.persistence.view.impl.StaticPathCorrelationProvider) FullQueryBuilder(com.blazebit.persistence.FullQueryBuilder) NullTupleTransformer(com.blazebit.persistence.view.impl.objectbuilder.transformer.NullTupleTransformer)

Example 5 with LimitBuilder

use of com.blazebit.persistence.LimitBuilder in project blaze-persistence by Blazebit.

the class ParameterizedExpressionCorrelationJoinTupleElementMapper method applyMapping.

@Override
public void applyMapping(SelectBuilder<?> queryBuilder, ParameterHolder<?> parameterHolder, Map<String, Object> optionalParameters, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, boolean asString) {
    String oldViewPath = viewJpqlMacro.getViewPath();
    String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
    viewJpqlMacro.setViewPath(embeddingViewPath);
    embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
    FullQueryBuilder<?, ?> fullQueryBuilder;
    if (queryBuilder instanceof ConstrainedSelectBuilder) {
        fullQueryBuilder = ((ConstrainedSelectBuilder) queryBuilder).getQueryBuilder();
    } else {
        fullQueryBuilder = (FullQueryBuilder<?, ?>) queryBuilder;
    }
    int originalFirstResult = -1;
    int originalMaxResults = -1;
    if (queryBuilder instanceof LimitBuilder<?>) {
        originalFirstResult = ((LimitBuilder<?>) queryBuilder).getFirstResult();
        originalMaxResults = ((LimitBuilder<?>) queryBuilder).getMaxResults();
    }
    JoinCorrelationBuilder correlationBuilder = new JoinCorrelationBuilder(parameterHolder, optionalParameters, fullQueryBuilder, joinBase, correlationAlias, correlationExternalAlias, attributePath, JoinType.LEFT, limiter);
    CorrelationProvider provider = providerFactory.create(parameterHolder, optionalParameters);
    provider.applyCorrelation(correlationBuilder, correlationBasis);
    if (queryBuilder instanceof LimitBuilder<?>) {
        if (originalFirstResult != ((LimitBuilder<?>) queryBuilder).getFirstResult() || originalMaxResults != ((LimitBuilder<?>) queryBuilder).getMaxResults()) {
            throw new IllegalArgumentException("Correlation provider '" + provider + "' wrongly uses setFirstResult() or setMaxResults() on the query builder which might lead to wrong results. Use SELECT fetching with batch size 1 or reformulate the correlation provider to use the limit/offset in a subquery!");
        }
    }
    correlationBuilder.finish();
    // Basic element has an alias, subviews don't
    if (alias != null) {
        viewJpqlMacro.setViewPath(null);
        queryBuilder.select(correlationResult, alias);
    }
    viewJpqlMacro.setViewPath(oldViewPath);
    embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
    if (fetches.length != 0) {
        for (int i = 0; i < fetches.length; i++) {
            fullQueryBuilder.fetch(correlationBuilder.getCorrelationAlias() + "." + fetches[i]);
        }
    }
}
Also used : JoinCorrelationBuilder(com.blazebit.persistence.view.impl.objectbuilder.transformer.correlation.JoinCorrelationBuilder) LimitBuilder(com.blazebit.persistence.LimitBuilder) CorrelationProvider(com.blazebit.persistence.view.CorrelationProvider)

Aggregations

LimitBuilder (com.blazebit.persistence.LimitBuilder)5 CorrelationProvider (com.blazebit.persistence.view.CorrelationProvider)3 FullQueryBuilder (com.blazebit.persistence.FullQueryBuilder)2 EmbeddingViewJpqlMacro (com.blazebit.persistence.view.spi.EmbeddingViewJpqlMacro)2 ViewJpqlMacro (com.blazebit.persistence.view.spi.ViewJpqlMacro)2 List (java.util.List)2 Map (java.util.Map)2 BaseOngoingFinalSetOperationBuilder (com.blazebit.persistence.BaseOngoingFinalSetOperationBuilder)1 BaseOngoingSetOperationBuilder (com.blazebit.persistence.BaseOngoingSetOperationBuilder)1 DistinctBuilder (com.blazebit.persistence.DistinctBuilder)1 FinalSetOperationCTECriteriaBuilder (com.blazebit.persistence.FinalSetOperationCTECriteriaBuilder)1 FinalSetOperationCriteriaBuilder (com.blazebit.persistence.FinalSetOperationCriteriaBuilder)1 FinalSetOperationSubqueryBuilder (com.blazebit.persistence.FinalSetOperationSubqueryBuilder)1 GroupByBuilder (com.blazebit.persistence.GroupByBuilder)1 HavingBuilder (com.blazebit.persistence.HavingBuilder)1 MultipleSubqueryInitiator (com.blazebit.persistence.MultipleSubqueryInitiator)1 ObjectBuilder (com.blazebit.persistence.ObjectBuilder)1 OngoingSetOperationBuilder (com.blazebit.persistence.OngoingSetOperationBuilder)1 OrderByBuilder (com.blazebit.persistence.OrderByBuilder)1 PaginatedCriteriaBuilder (com.blazebit.persistence.PaginatedCriteriaBuilder)1