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());
}
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);
}
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;
}
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;
}
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;
}
Aggregations