Search in sources :

Example 16 with ExtendedAttribute

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

the class AbstractInsertCollectionCriteriaBuilder method addBind.

@Override
protected void addBind(String attributeName) {
    if (attributeName.equalsIgnoreCase(keyFunctionExpression)) {
        Integer attributeBindIndex = bindingMap.get(attributeName);
        if (attributeBindIndex != null) {
            throw new IllegalArgumentException("The attribute [" + attributeName + "] has already been bound!");
        }
        bindingMap.put(attributeName, selectManager.getSelectInfos().size());
        return;
    }
    ExtendedAttribute attributeEntry = collectionAttributeEntries.get(attributeName);
    if (attributeEntry == null) {
        Set<String> set = new TreeSet<>(collectionAttributeEntries.keySet());
        if (keyFunctionExpression != null) {
            set.add(keyFunctionExpression);
        }
        throw new IllegalArgumentException("The attribute [" + attributeName + "] does not exist or can't be bound! Allowed attributes are: " + set);
    }
    Integer attributeBindIndex = bindingMap.get(attributeName);
    if (attributeBindIndex != null) {
        throw new IllegalArgumentException("The attribute [" + attributeName + "] has already been bound!");
    }
    bindingMap.put(attributeName, selectManager.getSelectInfos().size());
}
Also used : TreeSet(java.util.TreeSet) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute)

Example 17 with ExtendedAttribute

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

the class AbstractCTECriteriaBuilder method prepareAndGetColumnNames.

protected List<String> prepareAndGetColumnNames() {
    StringBuilder sb = null;
    for (ExtendedAttribute entry : attributeEntries.values()) {
        for (String column : entry.getColumnNames()) {
            if (!columnBindingMap.containsKey(column)) {
                if (sb == null) {
                    sb = new StringBuilder();
                    sb.append("[");
                } else {
                    sb.append(", ");
                }
                sb.append(column);
            }
        }
    }
    if (sb != null) {
        sb.insert(0, "The following column names have not been bound: ");
        sb.append("]");
        throw new IllegalStateException(sb.toString());
    }
    String[] columns = new String[columnBindingMap.size()];
    for (Map.Entry<String, String> columnBinding : columnBindingMap.entrySet()) {
        columns[bindingMap.get(columnBinding.getValue())] = columnBinding.getKey();
    }
    return Arrays.asList(columns);
}
Also used : ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 18 with ExtendedAttribute

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

the class JoinManager method renderCorrelationJoinPath.

private boolean renderCorrelationJoinPath(StringBuilder sb, JoinNode joinBase, JoinNode node, String correlationPath, List<String> whereConjuncts, List<String> optionalWhereConjuncts, boolean externalRepresentation) {
    JoinAliasInfo joinBaseAliasInfo = joinBase.getAliasInfo();
    StringBuilder whereSb = null;
    if (node.getJoinNodesNeedingTreatConjunct() != null) {
        whereSb = new StringBuilder();
        for (JoinNode joinNode : node.getJoinNodesNeedingTreatConjunct()) {
            whereSb.setLength(0);
            whereSb.append("TYPE(");
            joinNode.appendAlias(whereSb, false, externalRepresentation);
            whereSb.append(") = ");
            whereSb.append(joinNode.getTreatType().getName());
            whereConjuncts.add(whereSb.toString());
        }
    }
    final boolean renderTreat = mainQuery.jpaProvider.supportsTreatJoin() && (!mainQuery.jpaProvider.supportsSubtypeRelationResolving() || node.getJoinType() == JoinType.INNER);
    if (mainQuery.jpaProvider.needsCorrelationPredicateWhenCorrelatingWithWhereClause() || node.getTreatType() != null && !renderTreat && !mainQuery.jpaProvider.supportsSubtypeRelationResolving()) {
        ExtendedManagedType<?> extendedManagedType = metamodel.getManagedType(ExtendedManagedType.class, joinBase.getManagedType());
        ExtendedAttribute attribute = extendedManagedType.getAttribute(correlationPath);
        if (StringUtils.isEmpty(attribute.getMappedBy())) {
            if (attribute.getAttribute() instanceof ListAttribute<?, ?> && !attribute.isBag()) {
                // What the hell Hibernate? Why just for indexed lists?
                sb.append(joinBase.getEntityType().getName());
                sb.append(" _synthetic_");
                sb.append(node.getAlias());
                sb.append(" JOIN _synthetic_");
                sb.append(node.getAlias());
                sb.append('.').append(correlationPath);
                if (whereSb == null) {
                    whereSb = new StringBuilder();
                } else {
                    whereSb.setLength(0);
                }
                whereSb.append("_synthetic_").append(node.getAlias());
                boolean singleValuedAssociationId = mainQuery.jpaProvider.supportsSingleValuedAssociationIdExpressions() && extendedManagedType.getIdAttributes().size() == 1;
                if (singleValuedAssociationId) {
                    whereSb.append('.').append(extendedManagedType.getIdAttribute().getName());
                }
                whereSb.append(" = ");
                joinBase.appendAlias(whereSb, false, externalRepresentation);
                if (singleValuedAssociationId) {
                    whereSb.append('.').append(extendedManagedType.getIdAttribute().getName());
                }
                whereConjuncts.add(whereSb.toString());
                return true;
            }
        } else {
            boolean renderAlias = true;
            sb.append(node.getEntityType().getName());
            if (whereSb == null) {
                whereSb = new StringBuilder();
            } else {
                whereSb.setLength(0);
            }
            ExtendedManagedType elementManagedType = metamodel.getManagedType(ExtendedManagedType.class, node.getManagedType());
            if (elementManagedType.getAttribute(attribute.getMappedBy()).getAttribute().isCollection()) {
                renderAlias = false;
                sb.append(' ');
                sb.append(node.getAlias());
                sb.append(" JOIN ");
                sb.append(node.getAlias());
                sb.append('.').append(attribute.getMappedBy());
                sb.append(" _synthetic_");
                sb.append(node.getAlias());
                whereSb.append(" _synthetic_").append(node.getAlias());
            } else {
                whereSb.append(node.getAlias());
                whereSb.append('.').append(attribute.getMappedBy());
            }
            boolean singleValuedAssociationId = mainQuery.jpaProvider.supportsSingleValuedAssociationIdExpressions() && extendedManagedType.getIdAttributes().size() == 1;
            if (singleValuedAssociationId) {
                whereSb.append('.').append(extendedManagedType.getIdAttribute().getName());
            }
            whereSb.append(" = ");
            joinBase.appendAlias(whereSb, false, externalRepresentation);
            if (singleValuedAssociationId) {
                whereSb.append('.').append(extendedManagedType.getIdAttribute().getName());
            }
            whereConjuncts.add(whereSb.toString());
            return renderAlias;
        }
    }
    if (node.getTreatType() != null) {
        if (renderTreat) {
            sb.append("TREAT(");
            renderAlias(sb, joinBaseAliasInfo.getJoinNode(), mainQuery.jpaProvider.supportsRootTreat(), externalRepresentation);
            sb.append('.');
            sb.append(correlationPath);
            sb.append(" AS ");
            sb.append(node.getTreatType().getName());
            sb.append(')');
        } else if (mainQuery.jpaProvider.supportsSubtypeRelationResolving()) {
            joinBaseAliasInfo.getJoinNode().appendAlias(sb, false, externalRepresentation);
            sb.append('.').append(correlationPath);
        } else {
            throw new IllegalArgumentException("Treat should not be used as the JPA provider does not support subtype property access!");
        }
    } else {
        JoinNode baseNode = joinBaseAliasInfo.getJoinNode();
        if (baseNode.getTreatType() != null) {
            if (mainQuery.jpaProvider.supportsRootTreatJoin()) {
                baseNode.appendAlias(sb, true, externalRepresentation);
            } else if (mainQuery.jpaProvider.supportsSubtypeRelationResolving()) {
                baseNode.appendAlias(sb, false, externalRepresentation);
            } else {
                throw new IllegalArgumentException("Treat should not be used as the JPA provider does not support subtype property access!");
            }
        } else {
            baseNode.appendAlias(sb, false, externalRepresentation);
        }
        sb.append('.').append(correlationPath);
    }
    return true;
}
Also used : ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) ExtendedManagedType(com.blazebit.persistence.spi.ExtendedManagedType)

Example 19 with ExtendedAttribute

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

the class FunctionalDependencyAnalyzerVisitor method visit.

@Override
public Boolean visit(PathExpression expr) {
    PathReference pathReference = expr.getPathReference();
    if (pathReference == null) {
        Expression aliasedExpression = ((SelectInfo) aliasManager.getAliasInfo(expr.toString())).getExpression();
        return aliasedExpression.accept(this);
    }
    JoinNode baseNode = (JoinNode) pathReference.getBaseNode();
    String field = pathReference.getField();
    if (field == null) {
        lastJoinNode = baseNode;
        functionalDependencyRootExpressions.put(baseNode, Collections.singletonList(currentResolvedExpression));
        // This is a basic element collection. The element is it's unique key
        if (baseNode.getType().getPersistenceType() == Type.PersistenceType.BASIC) {
            return true;
        }
        // The key of a collection is it's unique key
        if (inKey) {
            return true;
        }
        field = baseNode.getParentTreeNode().getRelationName();
        baseNode = baseNode.getParent();
    }
    // First we check if the target attribute is unique, if it isn't, we don't need to check the join structure
    ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getManagedType());
    Attribute attr = managedType.getAttribute(field).getAttribute();
    if (attr instanceof PluralAttribute<?, ?, ?>) {
        lastJoinNode = baseNode;
        if (inKey) {
            registerFunctionalDependencyRootExpression(baseNode);
            return true;
        }
        throw new IllegalArgumentException("Ordering by plural attribute '" + expr + "' does not make sense! Please order by it's id instead!");
    }
    // Right now we only support ids, but we actually should check for unique constraints
    boolean isEmbeddedIdPart = false;
    SingularAttribute<?, ?> singularAttr = (SingularAttribute<?, ?>) attr;
    if (!singularAttr.isId() && !(isEmbeddedIdPart = isEmbeddedIdPart(baseNode, field, singularAttr))) {
        registerFunctionalDependencyRootExpression(baseNode);
        return false;
    }
    Object baseNodeKey;
    // Check if we have a single valued id access
    int dotIndex = expr.getField().lastIndexOf('.');
    if (dotIndex == -1) {
        baseNodeKey = baseNode;
        if (singularAttr.getType() instanceof EmbeddableType<?>) {
            expressionToSplit = expr;
        }
    } else if (isEmbeddedIdPart) {
        baseNodeKey = baseNode;
    } else {
        // We have to correct the base node for single valued id paths
        String associationName = expr.getField().substring(0, dotIndex);
        ExtendedManagedType<?> extendedManagedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getManagedType());
        ExtendedAttribute<?, ?> extendedAttribute = extendedManagedType.getAttribute(associationName);
        Attribute<?, ?> attribute = extendedAttribute.getAttribute();
        baseNodeKey = new AbstractMap.SimpleEntry<>(baseNode, associationName);
        if (attribute.getPersistentAttributeType() != Attribute.PersistentAttributeType.ONE_TO_ONE) {
            boolean nonConstantParent = true;
            Map<String, Boolean> constantifiedAttributes = constantifiedJoinNodeAttributeCollector.getConstantifiedJoinNodeAttributes().get(baseNodeKey);
            if (constantifiedAttributes != null) {
                Map<String, Boolean> orderedAttributes = new HashMap<>();
                addAttributes(baseNode.getEntityType(), null, "", "", (SingularAttribute<?, ?>) attribute, orderedAttributes);
                initConstantifiedAttributes(orderedAttributes, constantifiedAttributes.keySet());
                orderedAttributes.remove(expr.getField());
                String singleNonConstantifiedAttribute = getSingleNonConstantifiedAttribute(orderedAttributes);
                // If the identifiers are constantified, we don't care if this is a one-to-one
                if (singleNonConstantifiedAttribute != null && (singleNonConstantifiedAttribute.isEmpty() || equalsAny(singleNonConstantifiedAttribute, extendedManagedType.getAttribute(expr.getField()).getColumnEquivalentAttributes()))) {
                    nonConstantParent = false;
                    orderedAttributes.clear();
                    managedType = metamodel.getManagedType(ExtendedManagedType.class, JpaMetamodelUtils.resolveFieldClass(baseNode.getJavaType(), attribute));
                }
            } else if (attribute instanceof SingularAttribute<?, ?> && ((SingularAttribute<?, ?>) attribute).isId()) {
                baseNodeKey = baseNode;
                // This is an id class attribute
                nonConstantParent = false;
                // This is not 100% correct as it is not an embedded id, but works because we only need to append the association name field part
                isEmbeddedIdPart = true;
            }
            if (nonConstantParent) {
                registerFunctionalDependencyRootExpression(baseNodeKey);
                return false;
            }
        } else {
            managedType = metamodel.getManagedType(ExtendedManagedType.class, JpaMetamodelUtils.resolveFieldClass(baseNode.getJavaType(), attribute));
        }
    }
    registerFunctionalDependencyRootExpression(baseNodeKey);
    // First we initialize the names of the id attributes as set for the join node
    Map<String, Boolean> orderedAttributes = getUniquenessMissingAttributes(baseNodeKey, managedType);
    // We remove for every id attribute from the initialized set of id attribute names
    String prefix;
    if (dotIndex == -1 && baseNode.getParentTreeNode() != null && !baseNode.getParentTreeNode().isCollection()) {
        prefix = baseNode.getParentTreeNode().getRelationName() + ".";
        JoinNode node = baseNode.getParent();
        while (node.getParentTreeNode() != null) {
            prefix = node.getParentTreeNode().getRelationName() + "." + prefix;
            node = node.getParent();
        }
    } else {
        prefix = isEmbeddedIdPart ? field.substring(0, dotIndex + 1) : "";
    }
    if (removeAttribute(prefix, singularAttr, orderedAttributes) && currentResolvedExpression != null) {
        List<ResolvedExpression> resolvedExpressions = uniquenessFormingJoinNodeExpressions.get(baseNodeKey);
        if (resolvedExpressions == null) {
            resolvedExpressions = new ArrayList<>(orderedAttributes.size() + 1);
            uniquenessFormingJoinNodeExpressions.put(baseNodeKey, resolvedExpressions);
        }
        resolvedExpressions.add(currentResolvedExpression);
    }
    lastJoinNode = baseNodeKey;
    // While there still are some attribute names left, we simply report that it isn't unique, yet
    if (hasNonConstantifiedAttribute(orderedAttributes)) {
        return false;
    }
    // But even now that we order by all id attribute parts, we still have to make sure this join node is uniqueness preserving
    String subPath = field;
    while (baseNode.getParent() != null) {
        if (baseNode.getParentTreeNode() == null) {
            // Only assume uniqueness when the encountered cross or entity join are constantified
            return constantifiedJoinNodeAttributeCollector.isConstantified(baseNode);
        } else {
            subPath = baseNode.getParentTreeNode().getRelationName() + "." + subPath;
            attr = baseNode.getParentTreeNode().getAttribute();
            // Only one-to-one relation joins i.e. joins having a unique key with unique key equality predicate are uniqueness preserving
            baseNode = baseNode.getParent();
            if (attr.getPersistentAttributeType() != Attribute.PersistentAttributeType.ONE_TO_ONE) {
                Map<String, Boolean> constantifiedAttributes = constantifiedJoinNodeAttributeCollector.getConstantifiedJoinNodeAttributes().get(baseNode);
                if (constantifiedAttributes != null) {
                    // If there are constantified attributes for the node, we check if they cover the identifier
                    // This is relevant for queries like `select e.manyToOne.id, e.manyToOne.name from Entity e order by e.manyToOne.id`
                    // Normally, the expression `e.manyToOne.id` wouldn't be considered unique, unless there is a unique key with constant equality predicate
                    // i.e. a predicate like `e.id = 1` that essentially "constantifies" the parent join node
                    ExtendedManagedType<?> extendedManagedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getManagedType());
                    orderedAttributes = new HashMap<>();
                    addAttributes(baseNode.getEntityType(), null, "", "", (SingularAttribute<?, ?>) attr, orderedAttributes);
                    initConstantifiedAttributes(orderedAttributes, constantifiedAttributes.keySet());
                    orderedAttributes.remove(subPath);
                    String singleNonConstantifiedAttribute = getSingleNonConstantifiedAttribute(orderedAttributes);
                    // If the identifiers are constantified, we don't care if this is a one-to-one
                    if (singleNonConstantifiedAttribute != null && (singleNonConstantifiedAttribute.isEmpty() || extendedManagedType.getAttributes().containsKey(subPath) && equalsAny(singleNonConstantifiedAttribute, extendedManagedType.getAttribute(subPath).getColumnEquivalentAttributes()))) {
                        continue;
                    }
                }
                return false;
            }
        }
    }
    return true;
}
Also used : PathReference(com.blazebit.persistence.parser.expression.PathReference) SingularAttribute(javax.persistence.metamodel.SingularAttribute) Attribute(javax.persistence.metamodel.Attribute) PluralAttribute(javax.persistence.metamodel.PluralAttribute) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) EmbeddableType(javax.persistence.metamodel.EmbeddableType) PluralAttribute(javax.persistence.metamodel.PluralAttribute) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) ExtendedManagedType(com.blazebit.persistence.spi.ExtendedManagedType) SingularAttribute(javax.persistence.metamodel.SingularAttribute) ListIndexExpression(com.blazebit.persistence.parser.expression.ListIndexExpression) WhenClauseExpression(com.blazebit.persistence.parser.expression.WhenClauseExpression) Expression(com.blazebit.persistence.parser.expression.Expression) GeneralCaseExpression(com.blazebit.persistence.parser.expression.GeneralCaseExpression) TrimExpression(com.blazebit.persistence.parser.expression.TrimExpression) 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) MapEntryExpression(com.blazebit.persistence.parser.expression.MapEntryExpression) MapValueExpression(com.blazebit.persistence.parser.expression.MapValueExpression) ArrayExpression(com.blazebit.persistence.parser.expression.ArrayExpression) NullExpression(com.blazebit.persistence.parser.expression.NullExpression) FunctionExpression(com.blazebit.persistence.parser.expression.FunctionExpression) SimpleCaseExpression(com.blazebit.persistence.parser.expression.SimpleCaseExpression) SubqueryExpression(com.blazebit.persistence.parser.expression.SubqueryExpression) MapKeyExpression(com.blazebit.persistence.parser.expression.MapKeyExpression) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) AbstractMap(java.util.AbstractMap)

Example 20 with ExtendedAttribute

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

the class JpaUtils method getCollectionAttributeEntries.

public static Map<String, ExtendedAttribute<?, ?>> getCollectionAttributeEntries(EntityMetamodel metamodel, EntityType<?> entityType, ExtendedAttribute<?, ?> attribute) {
    Map<String, ExtendedAttribute<?, ?>> collectionAttributeEntries = new HashMap<>();
    JoinTable joinTable = attribute.getJoinTable();
    if (joinTable == null) {
        throw new IllegalArgumentException("Inserting into or updating an inverse collection via DML API is not supported!");
    }
    ExtendedManagedType<?> extendedManagedType = metamodel.getManagedType(ExtendedManagedType.class, entityType);
    for (String idAttributeName : joinTable.getIdAttributeNames()) {
        collectionAttributeEntries.put(idAttributeName, extendedManagedType.getAttribute(idAttributeName));
    }
    if (((PluralAttribute<?, ?, ?>) attribute.getAttribute()).getElementType() instanceof ManagedType<?>) {
        String prefix = attribute.getAttributePathString() + ".";
        for (Map.Entry<String, ? extends ExtendedAttribute<?, ?>> entry : extendedManagedType.getAttributes().entrySet()) {
            if (entry.getKey().startsWith(prefix)) {
                collectionAttributeEntries.put(entry.getKey(), entry.getValue());
            }
        }
    }
    collectionAttributeEntries.put(attribute.getAttributePathString(), attribute);
    return collectionAttributeEntries;
}
Also used : ExtendedManagedType(com.blazebit.persistence.spi.ExtendedManagedType) ManagedType(javax.persistence.metamodel.ManagedType) HashMap(java.util.HashMap) ExtendedAttribute(com.blazebit.persistence.spi.ExtendedAttribute) HashMap(java.util.HashMap) Map(java.util.Map) JoinTable(com.blazebit.persistence.spi.JoinTable)

Aggregations

ExtendedAttribute (com.blazebit.persistence.spi.ExtendedAttribute)21 ExtendedManagedType (com.blazebit.persistence.spi.ExtendedManagedType)13 Map (java.util.Map)7 PathExpression (com.blazebit.persistence.parser.expression.PathExpression)5 HashMap (java.util.HashMap)5 ArrayList (java.util.ArrayList)4 Attribute (javax.persistence.metamodel.Attribute)4 PluralAttribute (javax.persistence.metamodel.PluralAttribute)4 PathReference (com.blazebit.persistence.parser.expression.PathReference)3 EntityMetamodel (com.blazebit.persistence.parser.EntityMetamodel)2 ArrayExpression (com.blazebit.persistence.parser.expression.ArrayExpression)2 Expression (com.blazebit.persistence.parser.expression.Expression)2 FunctionExpression (com.blazebit.persistence.parser.expression.FunctionExpression)2 MapKeyExpression (com.blazebit.persistence.parser.expression.MapKeyExpression)2 NullExpression (com.blazebit.persistence.parser.expression.NullExpression)2 ParameterExpression (com.blazebit.persistence.parser.expression.ParameterExpression)2 PropertyExpression (com.blazebit.persistence.parser.expression.PropertyExpression)2 IdentityHashMap (java.util.IdentityHashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 List (java.util.List)2