use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.
the class JoinVisitor method getNaturalIdAttribute.
private String getNaturalIdAttribute(Expression expression) {
// Hibernate fails to do this and instead compares the primary key with the natural key which might go by unnoticed
if (expression instanceof PathExpression) {
PathExpression pathExpression = (PathExpression) expression;
visit(pathExpression, false);
PathReference pathReference = (pathExpression).getPathReference();
// We only attach the natural id to paths referring to entity types
if (pathReference != null && pathReference.getField() != null && pathReference.getType() instanceof EntityType<?>) {
JoinNode node = (JoinNode) pathReference.getBaseNode();
// We need a parent tree node to determine the natural id attribute
Collection<String> identifierOrUniqueKeyEmbeddedPropertyNames = metamodel.getJpaProvider().getJoinMappingPropertyNames(node.getEntityType(), null, pathReference.getField()).keySet();
if (identifierOrUniqueKeyEmbeddedPropertyNames.size() == 1) {
// This "fix" only works if we have a single id attribute
String naturalIdAttribute = identifierOrUniqueKeyEmbeddedPropertyNames.iterator().next();
ExtendedManagedType extendedManagedType = metamodel.getManagedType(ExtendedManagedType.class, (ManagedType<?>) pathReference.getType());
if (!extendedManagedType.getIdAttribute().getName().equals(naturalIdAttribute)) {
// Now we finally know the natural id attribute name
return naturalIdAttribute;
}
}
}
}
return null;
}
use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.
the class JoinVisitor method visit.
private void visit(PathExpression expression, boolean idRemovable) {
Expression aliasedExpression;
String alias = expression.getExpressions().size() == 1 ? expression.toString() : null;
if (alias != null && !currentlyResolvingAliases.contains(alias) && (aliasedExpression = joinManager.getJoinableSelectAlias(expression, fromClause == ClauseType.SELECT, false)) != null) {
try {
currentlyResolvingAliases.add(alias);
aliasedExpression.accept(this);
// We initialize the aliased PathExpression properly
if (aliasedExpression instanceof PathExpression) {
PathExpression aliasedPathExpression = (PathExpression) aliasedExpression;
if (aliasedPathExpression.isCollectionQualifiedPath()) {
expression.setCollectionQualifiedPath(true);
}
if (aliasedPathExpression.isUsedInCollectionFunction()) {
expression.setUsedInCollectionFunction(true);
}
}
} finally {
currentlyResolvingAliases.remove(alias);
}
} else if (ArrayExpression.ELEMENT_NAME.equals(alias)) {
// We will not resolve the ArrayExpression.ELEMENT_NAME alias, this must be done in the join manager and is only allowed within an ArrayExpression
} else {
if (relativeExpressionPrefix != null) {
PathExpression leftMost = ExpressionUtils.getLeftMostPathExpression(expression);
String leftMostAlias;
if (leftMost.getExpressions().get(0) instanceof ArrayExpression) {
leftMostAlias = ((ArrayExpression) leftMost.getExpressions().get(0)).getBase().toString();
} else {
leftMostAlias = ((PropertyExpression) leftMost.getExpressions().get(0)).getProperty();
}
if (ArrayExpression.ELEMENT_NAME.equals(leftMostAlias)) {
return;
}
JoinAliasInfo aliasInfo = (JoinAliasInfo) joinManager.getAliasManager().getAliasInfo(leftMostAlias);
if (aliasInfo == null) {
leftMost.getExpressions().add(0, new PropertyExpression(ArrayExpression.ELEMENT_NAME));
return;
}
}
try {
// But allow joins if this expression was joined before already to avoid possible side-effects of implicit joining multiple times
if (expression.getBaseNode() != null) {
}
joinManager.implicitJoin(expression, joinAllowed, true, joinWithObjectLeafAllowed, null, fromClause, null, currentJoinNode, currentlyResolvingAliases, false, false, joinRequired, idRemovable, false, reuseExisting);
if (parentVisitor != null) {
JoinNode baseNode = (JoinNode) expression.getBaseNode();
AliasManager aliasOwner = baseNode.getAliasInfo().getAliasOwner();
if (aliasOwner != joinManager.getAliasManager()) {
addParentClauseDependencies(baseNode, aliasOwner);
}
}
} catch (ImplicitJoinNotAllowedException ex) {
if (conjunctionPathExpressionFindingVisitor == null) {
conjunctionPathExpressionFindingVisitor = new ConjunctionPathExpressionFindingVisitor();
}
correlationPathReplacementVisitor.addPathExpression(expression, ex, conjunctionPathExpressionFindingVisitor.isInConjunction(currentJoinNode.getOnPredicate(), expression));
}
}
}
use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.
the class EmbeddableSplittingVisitor method collectSplittedOffExpressions.
protected boolean collectSplittedOffExpressions(Expression expression) {
splittedOffExpressions.clear();
if (expressionToSplit != null) {
JoinNode baseNode;
String field;
if (expressionToSplit instanceof PathExpression) {
PathReference pathReference = ((PathExpression) expressionToSplit).getPathReference();
baseNode = (JoinNode) pathReference.getBaseNode();
field = pathReference.getField();
} else if (expressionToSplit instanceof MapKeyExpression) {
baseNode = ((JoinNode) ((MapKeyExpression) expressionToSplit).getPath().getBaseNode()).getKeyJoinNode();
field = null;
} else {
// This should never happen
return false;
}
String fieldPrefix = field == null ? "" : field + ".";
ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getManagedType());
Map<String, Boolean> orderedAttributes = new TreeMap<>();
EntityType<?> ownerType;
if ((baseNode.getParentTreeNode() == null || splitEntity && baseNode.getManagedType() instanceof EntityType<?>) && field == null) {
ownerType = baseNode.getEntityType();
for (SingularAttribute<?, ?> idAttribute : managedType.getIdAttributes()) {
addAttributes(ownerType, null, fieldPrefix, "", idAttribute, orderedAttributes);
}
} else {
Map<String, ? extends ExtendedAttribute<?, ?>> ownedAttributes;
String prefix = field;
if (baseNode.getParentTreeNode() != null && jpaProvider.getJpaMetamodelAccessor().isElementCollection(baseNode.getParentTreeNode().getAttribute())) {
String elementCollectionPath = baseNode.getParentTreeNode().getRelationName();
ExtendedManagedType entityManagedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getParent().getEntityType());
ownedAttributes = entityManagedType.getAttributes();
if (prefix == null) {
prefix = elementCollectionPath;
} else {
prefix = elementCollectionPath + "." + prefix;
}
} else {
ownedAttributes = managedType.getOwnedSingularAttributes();
}
for (String embeddedPropertyPath : JpaUtils.getEmbeddedPropertyPaths((Map<String, ExtendedAttribute<?, ?>>) ownedAttributes, prefix, false, false)) {
orderedAttributes.put(embeddedPropertyPath, Boolean.FALSE);
}
}
// Signal the caller that the expression was eliminated
if (orderedAttributes.isEmpty()) {
return true;
}
for (String orderedAttribute : orderedAttributes.keySet()) {
splittedOffExpressions.add(splittingVisitor.splitOff(expression, expressionToSplit, orderedAttribute));
}
}
return false;
}
use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.
the class EmbeddableSplittingVisitor method visit.
@Override
public Boolean visit(MapKeyExpression expression) {
PathExpression path = expression.getPath();
PathReference pathReference = path.getPathReference();
while (pathReference == null) {
Expression aliasedExpression = ((SelectInfo) aliasManager.getAliasInfo(path.toString())).getExpression();
if (aliasedExpression instanceof PathExpression) {
path = (PathExpression) aliasedExpression;
pathReference = path.getPathReference();
} else {
// This should never happen
return false;
}
}
JoinNode baseNode = (JoinNode) pathReference.getBaseNode();
Attribute attr;
if (baseNode.getParentTreeNode() != null) {
attr = baseNode.getParentTreeNode().getAttribute();
Type<?> t;
if (attr instanceof MapAttribute<?, ?, ?> && ((t = ((MapAttribute<?, ?, ?>) attr).getKeyType()) instanceof EmbeddableType<?> || splitEntity && t instanceof EntityType<?>)) {
expressionToSplit = expression;
}
}
return false;
}
use of com.blazebit.persistence.parser.expression.PathExpression in project blaze-persistence by Blazebit.
the class ImplicitJoinCorrelationPathReplacementVisitor method addPathExpression.
public void addPathExpression(PathExpression pathExpression, ImplicitJoinNotAllowedException ex, boolean isInConjunction) {
if (!pathIdentitiesToCorrelate.containsKey(pathExpression)) {
StringBuilder sb = new StringBuilder();
if (ex.getTreatType() != null) {
sb.append("TREAT(");
}
if (isInConjunction) {
ex.getBaseNode().appendAlias(sb, true, false);
} else {
String syntheticAlias = "_synthetic_" + ex.getBaseNode().getAlias();
List<PathElementExpression> list1 = new ArrayList<>(1);
list1.add(new PropertyExpression(syntheticAlias));
List<PathElementExpression> list2 = new ArrayList<>(1);
list2.add(new PropertyExpression(ex.getBaseNode().getAlias()));
Predicate predicate = new EqPredicate(new PathExpression(list1), new PathExpression(list2));
rootsToCorrelate.put(syntheticAlias, new RootCorrelationEntry(syntheticAlias, ex.getBaseNode().getNodeType().getJavaType(), predicate));
sb.append(syntheticAlias);
}
sb.append('.');
sb.append(ex.getJoinRelationName());
if (ex.getTreatType() != null) {
sb.append(" AS ").append(ex.getTreatType()).append(')');
}
String correlationExpression = sb.toString();
String alias;
CorrelationTransformEntry existingEntry = pathsToCorrelate.get(correlationExpression);
if (existingEntry != null) {
alias = existingEntry.alias;
} else {
alias = "_synth_subquery_" + pathIdentitiesToCorrelate.size();
}
PathExpression transformedExpression = pathExpression.copy(ExpressionCopyContext.EMPTY);
// For now, we only support 2 levels of treats, but this obviously should be improved
if (transformedExpression.getExpressions().get(0) instanceof TreatExpression) {
// Only the first expression in the list can be a treat expression
TreatExpression treatExpression = (TreatExpression) transformedExpression.getExpressions().get(0);
if (treatExpression.getType().equals(ex.getTreatType())) {
// The not-allowed implicit join is the one within the treat
PathExpression pathExpressionToModify = (PathExpression) treatExpression.getExpression();
removeMatchingJoinAttributePathElements(ex, pathExpressionToModify);
if (pathExpressionToModify.getExpressions().isEmpty()) {
transformedExpression.getExpressions().set(0, new PropertyExpression(alias));
} else {
throw new IllegalArgumentException("Can't transform nested TREAT expression: " + pathExpression);
}
} else {
// The not-allowed implicit join happens after dereferencing the treat
PathExpression pathExpressionToModify = (PathExpression) treatExpression.getExpression();
// In addition, we also need to make sure the root treat alias matches the not-allowed implicit joins base node alias
if ((ex.getBaseNode().getTreatType() == null && ex.getBaseNode().getEntityType().getName().equals(treatExpression.getType()) || ex.getBaseNode().getTreatType() != null && ex.getBaseNode().getTreatType().getName().equals(treatExpression.getType())) && pathExpressionToModify.getExpressions().size() == 1 && ex.getBaseNode().getAlias().equals(pathExpressionToModify.getExpressions().get(0).toString())) {
// Root treat
removeMatchingJoinAttributePathElements(ex, transformedExpression);
transformedExpression.getExpressions().add(0, new PropertyExpression(alias));
} else {
removeMatchingJoinAttributePathElements(ex, pathExpressionToModify);
pathExpressionToModify.getExpressions().add(0, new PropertyExpression(alias));
}
}
} else {
removeMatchingJoinAttributePathElements(ex, transformedExpression);
transformedExpression.getExpressions().add(0, new PropertyExpression(alias));
}
CorrelationTransformEntry correlationTransformEntry = new CorrelationTransformEntry(alias, correlationExpression, transformedExpression, isInConjunction);
pathIdentitiesToCorrelate.put(pathExpression, correlationTransformEntry);
if (existingEntry == null) {
pathsToCorrelate.put(correlationExpression, correlationTransformEntry);
}
}
}
Aggregations