Search in sources :

Example 26 with PathExpression

use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.

the class SizeTransformationVisitor method onModifier.

@Override
protected void onModifier(ExpressionModifier parentModifier) {
    PathExpression sizeArg = (PathExpression) ((FunctionExpression) parentModifier.get()).getExpressions().get(0);
    parentModifier.set(getSizeExpression(parentModifier, sizeArg));
    sizeArg.accept(this);
}
Also used : FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression)

Example 27 with PathExpression

use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.

the class SizeTransformationVisitor method getSizeExpression.

private Expression getSizeExpression(ExpressionModifier parentModifier, PathExpression sizeArg) {
    JoinNode sizeArgJoin = (JoinNode) sizeArg.getBaseNode();
    String property = sizeArg.getPathReference().getField();
    final Type<?> nodeType = ((JoinNode) sizeArg.getBaseNode()).getNodeType();
    if (!(nodeType instanceof EntityType<?>)) {
        throw new IllegalArgumentException("Size on a collection owned by a non-entity type is not supported yet: " + sizeArg);
    }
    final EntityType<?> startType = (EntityType<?>) nodeType;
    AttributeHolder result = JpaUtils.getAttributeForJoining(metamodel, sizeArg);
    PluralAttribute<?, ?, ?> targetAttribute = (PluralAttribute<?, ?, ?>) result.getAttribute();
    if (targetAttribute == null) {
        throw new RuntimeException("Attribute [" + property + "] not found on class " + startType.getJavaType().getName());
    }
    final PluralAttribute.CollectionType collectionType = targetAttribute.getCollectionType();
    final boolean isElementCollection = jpaProvider.getJpaMetamodelAccessor().isElementCollection(targetAttribute);
    boolean subqueryRequired;
    if (isElementCollection) {
        subqueryRequired = false;
    } else {
        ManagedType<?> managedTargetType = (ManagedType<?>) result.getAttributeType();
        if (managedTargetType instanceof EntityType<?>) {
            // we could also generate counts for collections with embeddable id but we do not implement this for now
            subqueryRequired = ((EntityType<?>) managedTargetType).getIdType().getPersistenceType() == PersistenceType.EMBEDDABLE;
        } else {
            throw new RuntimeException("Path [" + sizeArg.toString() + "] does not refer to a collection");
        }
    }
    // build group by id clause
    List<PathExpression> groupByExprs = new ArrayList<>();
    for (SingularAttribute<?, ?> idAttribute : JpaMetamodelUtils.getIdAttributes(startType)) {
        List<PathElementExpression> pathElementExpr = new ArrayList<>(2);
        pathElementExpr.add(new PropertyExpression(sizeArgJoin.getAlias()));
        pathElementExpr.add(new PropertyExpression(idAttribute.getName()));
        PathExpression groupByExpr = new PathExpression(pathElementExpr);
        groupByExprs.add(groupByExpr);
    }
    subqueryRequired = subqueryRequired || // we could also generate counts for collections with IdClass attributes but we do not implement this for now
    !startType.hasSingleIdAttribute() || joinManager.getRoots().size() > 1 || clause == ClauseType.JOIN || !isCountTransformationEnabled() || // for now, we always generate a subquery when a bag is encountered
    jpaProvider.isBag((EntityType<?>) targetAttribute.getDeclaringType(), targetAttribute.getName()) || requiresBlacklistedNode(sizeArg) || aggregateFunctionContext;
    if (subqueryRequired) {
        return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
    } else {
        if (currentJoinNode != null && (!currentJoinNode.equals(sizeArgJoin))) {
            int currentJoinDepth = currentJoinNode.getJoinDepth();
            int sizeArgJoinDepth = sizeArgJoin.getJoinDepth();
            if (currentJoinDepth > sizeArgJoinDepth) {
                return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
            } else {
                // we have to change all transformed expressions to subqueries
                for (TransformedExpressionEntry transformedExpressionEntry : transformedExpressions) {
                    PathExpression originalSizeArg = transformedExpressionEntry.getOriginalSizeArg();
                    Expression subquery = wrapSubqueryConditionally(generateSubquery(originalSizeArg), transformedExpressionEntry.isAggregateFunctionContext());
                    transformedExpressionEntry.getParentModifier().set(subquery);
                }
                transformedExpressions.clear();
                requiredGroupBys.clear();
                lateJoins.clear();
                distinctRequired = false;
                if (currentJoinDepth == sizeArgJoinDepth) {
                    return wrapSubqueryConditionally(generateSubquery(sizeArg), aggregateFunctionContext);
                }
            }
        }
        for (PathExpression groupByExpr : groupByExprs) {
            joinManager.implicitJoin(groupByExpr, true, true, true, null, null, new HashSet<String>(), false, false, false, false);
        }
        PathExpression originalSizeArg = sizeArg.copy(ExpressionCopyContext.EMPTY);
        originalSizeArg.setPathReference(sizeArg.getPathReference());
        sizeArg.setUsedInCollectionFunction(false);
        List<Expression> countArguments = new ArrayList<>();
        String joinLookupKey = getJoinLookupKey(sizeArg);
        LateJoinEntry lateJoin = lateJoins.get(joinLookupKey);
        if (lateJoin == null) {
            lateJoin = new LateJoinEntry();
            lateJoins.put(joinLookupKey, lateJoin);
        }
        lateJoin.getExpressionsToJoin().add(sizeArg);
        lateJoin.getClauseDependencies().add(clause);
        if ((isElementCollection && collectionType != PluralAttribute.CollectionType.MAP) || collectionType == PluralAttribute.CollectionType.SET) {
            if (IDENTIFIABLE_PERSISTENCE_TYPES.contains(targetAttribute.getElementType().getPersistenceType()) && targetAttribute.isCollection()) {
                // append id attribute name of joinable size argument
                PluralAttribute<?, ?, ?> sizeArgTargetAttribute = (PluralAttribute<?, ?, ?>) JpaMetamodelUtils.getAttribute(startType, sizeArg.getPathReference().getField());
                for (Attribute<?, ?> idAttribute : JpaMetamodelUtils.getIdAttributes(((IdentifiableType<?>) sizeArgTargetAttribute.getElementType()))) {
                    List<PathElementExpression> pathElementExpressions = new ArrayList<>(sizeArg.getExpressions().size() + 1);
                    pathElementExpressions.addAll(sizeArg.getExpressions());
                    pathElementExpressions.add(new PropertyExpression(idAttribute.getName()));
                    PathExpression pathExpression = new PathExpression(pathElementExpressions);
                    countArguments.add(pathExpression);
                    lateJoin.getExpressionsToJoin().add(pathExpression);
                }
            } else {
                countArguments.add(sizeArg);
            }
        } else {
            sizeArg.setCollectionQualifiedPath(true);
            if (collectionType == PluralAttribute.CollectionType.LIST) {
                countArguments.add(new ListIndexExpression(sizeArg));
            } else {
                countArguments.add(new MapKeyExpression(sizeArg));
            }
        }
        AggregateExpression countExpr = createCountFunction(distinctRequired, countArguments);
        transformedExpressions.add(new TransformedExpressionEntry(countExpr, originalSizeArg, parentModifier, aggregateFunctionContext));
        currentJoinNode = (JoinNode) originalSizeArg.getBaseNode();
        if (!distinctRequired) {
            if (lateJoins.size() + joinManager.getCollectionJoins().size() > 1) {
                distinctRequired = true;
                /*
                     *  As soon as we encounter another collection join, set previously
                     *  performed transformations to distinct.
                     */
                for (TransformedExpressionEntry transformedExpressionEntry : transformedExpressions) {
                    AggregateExpression transformedExpr = transformedExpressionEntry.getTransformedExpression();
                    if (ExpressionUtils.isCustomFunctionInvocation(transformedExpr) && AbstractCountFunction.FUNCTION_NAME.equalsIgnoreCase(((StringLiteral) transformedExpr.getExpressions().get(0)).getValue())) {
                        Expression possibleDistinct = transformedExpr.getExpressions().get(1);
                        if (!(possibleDistinct instanceof StringLiteral) || !AbstractCountFunction.DISTINCT_QUALIFIER.equals(((StringLiteral) possibleDistinct).getValue())) {
                            transformedExpr.getExpressions().add(1, new StringLiteral(AbstractCountFunction.DISTINCT_QUALIFIER));
                        }
                    } else {
                        transformedExpr.setDistinct(true);
                    }
                }
            }
        }
        for (Expression groupByExpr : groupByExprs) {
            String groupByExprString = groupByExpr.toString();
            ResolvedExpression resolvedExpression = new ResolvedExpression(groupByExprString, groupByExpr);
            Set<ClauseType> clauseTypes = requiredGroupBys.get(resolvedExpression);
            if (clauseTypes == null) {
                requiredGroupBys.put(resolvedExpression, EnumSet.of(clause));
            } else {
                clauseTypes.add(clause);
            }
        }
        return countExpr;
    }
}
Also used : ArrayList(java.util.ArrayList) ResolvedExpression(com.blazebit.persistence.impl.ResolvedExpression) MapKeyExpression(com.blazebit.persistence.parser.expression.MapKeyExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) ListIndexExpression(com.blazebit.persistence.parser.expression.ListIndexExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) AttributeHolder(com.blazebit.persistence.impl.AttributeHolder) ManagedType(javax.persistence.metamodel.ManagedType) IdentifiableType(javax.persistence.metamodel.IdentifiableType) PluralAttribute(javax.persistence.metamodel.PluralAttribute) JoinNode(com.blazebit.persistence.impl.JoinNode) AggregateExpression(com.blazebit.persistence.parser.expression.AggregateExpression) EntityType(javax.persistence.metamodel.EntityType) PathElementExpression(com.blazebit.persistence.parser.expression.PathElementExpression) StringLiteral(com.blazebit.persistence.parser.expression.StringLiteral) ListIndexExpression(com.blazebit.persistence.parser.expression.ListIndexExpression) Expression(com.blazebit.persistence.parser.expression.Expression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) AggregateExpression(com.blazebit.persistence.parser.expression.AggregateExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) ResolvedExpression(com.blazebit.persistence.impl.ResolvedExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression) MapKeyExpression(com.blazebit.persistence.parser.expression.MapKeyExpression) PathElementExpression(com.blazebit.persistence.parser.expression.PathElementExpression) ClauseType(com.blazebit.persistence.impl.ClauseType)

Example 28 with PathExpression

use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.

the class SimpleQueryGenerator method visit.

@Override
public void visit(final InPredicate predicate) {
    // we have to render false if the parameter list for IN is empty
    List<Expression> rightList = predicate.getRight();
    if (rightList.size() == 1) {
        Expression right = rightList.get(0);
        if (right instanceof ParameterExpression) {
            ParameterExpression parameterExpr = (ParameterExpression) right;
            // We might have named parameters
            if (parameterExpr.getValue() != null && parameterExpr.isCollectionValued()) {
                Object collection = parameterExpr.getValue();
                if (((Collection<?>) collection).isEmpty()) {
                    // and the workarounds like 1 = 0 or case when only work in specific contexts
                    if (booleanLiteralRenderingContext == BooleanLiteralRenderingContext.PREDICATE) {
                        sb.append(getBooleanConditionalExpression(predicate.isNegated()));
                    } else {
                        sb.append(getBooleanExpression(predicate.isNegated()));
                    }
                    return;
                }
            }
        } else if (right instanceof PathExpression) {
            // NOTE: this is a special case where we can transform an IN predicate to an equality predicate
            BooleanLiteralRenderingContext oldConditionalContext = setBooleanLiteralRenderingContext(BooleanLiteralRenderingContext.PLAIN);
            predicate.getLeft().accept(this);
            if (predicate.isNegated()) {
                sb.append(" <> ");
            } else {
                sb.append(" = ");
            }
            right.accept(this);
            setBooleanLiteralRenderingContext(oldConditionalContext);
            return;
        }
    }
    BooleanLiteralRenderingContext oldBooleanLiteralRenderingContext = setBooleanLiteralRenderingContext(BooleanLiteralRenderingContext.PLAIN);
    ParameterRenderingMode oldParameterRenderingMode = setParameterRenderingMode(ParameterRenderingMode.PLACEHOLDER);
    predicate.getLeft().accept(this);
    if (predicate.isNegated()) {
        sb.append(" NOT IN ");
    } else {
        sb.append(" IN ");
    }
    boolean parenthesisRequired;
    if (rightList.size() == 1) {
        // NOTE: other cases are handled by ResolvingQueryGenerator
        Expression singleRightExpression = rightList.get(0);
        if (singleRightExpression instanceof ParameterExpression && ((ParameterExpression) singleRightExpression).isCollectionValued()) {
            parenthesisRequired = false;
        } else {
            parenthesisRequired = !(singleRightExpression instanceof SubqueryExpression) || !isSimpleSubquery((SubqueryExpression) singleRightExpression);
        }
    } else {
        parenthesisRequired = true;
    }
    if (parenthesisRequired) {
        sb.append('(');
    }
    if (!rightList.isEmpty()) {
        rightList.get(0).accept(this);
        for (int i = 1; i < rightList.size(); i++) {
            sb.append(", ");
            rightList.get(i).accept(this);
        }
    }
    if (parenthesisRequired) {
        sb.append(')');
    }
    setBooleanLiteralRenderingContext(oldBooleanLiteralRenderingContext);
    setParameterRenderingMode(oldParameterRenderingMode);
}
Also used : PathExpression(com.blazebit.persistence.parser.expression.PathExpression) ListIndexExpression(com.blazebit.persistence.parser.expression.ListIndexExpression) WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) TreatExpression(com.blazebit.persistence.parser.expression.TreatExpression) ParameterExpression(com.blazebit.persistence.parser.expression.ParameterExpression) ArithmeticExpression(com.blazebit.persistence.parser.expression.ArithmeticExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) TypeFunctionExpression(com.blazebit.persistence.parser.expression.TypeFunctionExpression) AggregateExpression(com.blazebit.persistence.parser.expression.AggregateExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression) ArrayExpression(com.blazebit.persistence.parser.expression.ArrayExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression) PathElementExpression(com.blazebit.persistence.parser.expression.PathElementExpression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) TrimExpression(com.blazebit.persistence.parser.expression.TrimExpression) MapEntryExpression(com.blazebit.persistence.parser.expression.MapEntryExpression) MapValueExpression(com.blazebit.persistence.parser.expression.MapValueExpression) NullExpression(com.blazebit.persistence.parser.expression.NullExpression) SimpleCaseExpression(com.blazebit.persistence.parser.expression.SimpleCaseExpression) MapKeyExpression(com.blazebit.persistence.parser.expression.MapKeyExpression) ParameterExpression(com.blazebit.persistence.parser.expression.ParameterExpression) Collection(java.util.Collection) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression)

Example 29 with PathExpression

use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.

the class EqualityCheckingVisitor method visit.

@Override
public Boolean visit(PathExpression expression) {
    if (referenceExpression.getClass() != expression.getClass()) {
        return Boolean.TRUE;
    }
    PathExpression reference = (PathExpression) referenceExpression;
    List<PathElementExpression> referenceExpressions = reference.getExpressions();
    List<PathElementExpression> expressions = expression.getExpressions();
    PathExpression leftMostPathExpression = ExpressionUtils.getLeftMostPathExpression(expression);
    int size = expressions.size();
    if (leftMostPathExpression.getExpressions().get(0) instanceof PropertyExpression) {
        PropertyExpression propertyExpression = (PropertyExpression) leftMostPathExpression.getExpressions().get(0);
        if (ArrayExpression.ELEMENT_NAME.equals(propertyExpression.getProperty())) {
            try {
                leftMostPathExpression.getExpressions().set(0, new PropertyExpression(alias));
                for (int i = 0; i < size; i++) {
                    referenceExpression = referenceExpressions.get(i);
                    if (expressions.get(i).accept(this)) {
                        return Boolean.TRUE;
                    }
                }
                return Boolean.FALSE;
            } finally {
                leftMostPathExpression.getExpressions().set(0, propertyExpression);
            }
        }
    }
    PathReference referencePathReference = reference.getPathReference();
    PathReference pathReference = expression.getPathReference();
    if (referencePathReference == null || pathReference == null) {
        return reference.equals(expression) ? Boolean.FALSE : Boolean.TRUE;
    }
    if (referencePathReference.getBaseNode() != pathReference.getBaseNode()) {
        return Boolean.TRUE;
    }
    return Objects.equals(referencePathReference.getField(), pathReference.getField()) ? Boolean.FALSE : Boolean.TRUE;
}
Also used : PathReference(com.blazebit.persistence.parser.expression.PathReference) PathElementExpression(com.blazebit.persistence.parser.expression.PathElementExpression) PathExpression(com.blazebit.persistence.parser.expression.PathExpression) PropertyExpression(com.blazebit.persistence.parser.expression.PropertyExpression)

Example 30 with PathExpression

use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.

the class AbstractCommonQueryBuilder method getPath.

public Path getPath(String path) {
    if (path == null || path.isEmpty()) {
        JoinNode node = joinManager.getRootNodeOrFail("No or multiple query roots, can't find single root!");
        return new SimplePathReference(node, null, node.getType());
    }
    PathExpression pathExpression = expressionFactory.createPathExpression(path);
    joinManager.implicitJoin(pathExpression, true, true, true, null, null, new HashSet<String>(), false, false, true, false);
    // If we expose the path to the outside world, we can't remove it if it is a default select node
    if (pathExpression.getPathReference() != null) {
        selectManager.removeDefaultSelectNode((JoinNode) pathExpression.getBaseNode());
    }
    return (Path) pathExpression.getPathReference();
}
Also used : Path(com.blazebit.persistence.Path) PathExpression(com.blazebit.persistence.parser.expression.PathExpression)

Aggregations

PathExpression (com.blazebit.persistence.parser.expression.PathExpression)55 PropertyExpression (com.blazebit.persistence.parser.expression.PropertyExpression)37 PathElementExpression (com.blazebit.persistence.parser.expression.PathElementExpression)29 Expression (com.blazebit.persistence.parser.expression.Expression)27 FunctionExpression (com.blazebit.persistence.parser.expression.FunctionExpression)26 SubqueryExpression (com.blazebit.persistence.parser.expression.SubqueryExpression)22 MapKeyExpression (com.blazebit.persistence.parser.expression.MapKeyExpression)21 ArrayExpression (com.blazebit.persistence.parser.expression.ArrayExpression)20 ParameterExpression (com.blazebit.persistence.parser.expression.ParameterExpression)19 ArrayList (java.util.ArrayList)17 ListIndexExpression (com.blazebit.persistence.parser.expression.ListIndexExpression)16 TreatExpression (com.blazebit.persistence.parser.expression.TreatExpression)16 MapValueExpression (com.blazebit.persistence.parser.expression.MapValueExpression)15 GeneralCaseExpression (com.blazebit.persistence.parser.expression.GeneralCaseExpression)11 MapEntryExpression (com.blazebit.persistence.parser.expression.MapEntryExpression)11 QualifiedExpression (com.blazebit.persistence.parser.expression.QualifiedExpression)10 ExtendedManagedType (com.blazebit.persistence.spi.ExtendedManagedType)10 EntityType (javax.persistence.metamodel.EntityType)10 PathReference (com.blazebit.persistence.parser.expression.PathReference)8 NullExpression (com.blazebit.persistence.parser.expression.NullExpression)7