Skip to content

Commit

Permalink
Implemented plural only embeddable owner VALUES clause support and ad…
Browse files Browse the repository at this point in the history
…d VALUES LIKE clause
  • Loading branch information
beikov committed Nov 8, 2018
1 parent 0a8a00d commit 637f19a
Show file tree
Hide file tree
Showing 40 changed files with 1,049 additions and 338 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,12 @@ public interface JpaMetamodelAccessor {
* @return Whether the attribute is composite
*/
boolean isCompositeNode(Attribute<?, ?> attr);

/**
* Returns whether the given attribute is an element collection.
*
* @param attribute The attribute to check
* @return true if the attribute is an element collection, false otherwise
*/
boolean isElementCollection(Attribute<?, ?> attribute);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ protected boolean collectSplittedOffExpressions(Expression expression) {
} else {
Map<String, ? extends ExtendedAttribute<?, ?>> ownedAttributes;
String prefix = field;
if (baseNode.getParentTreeNode() != null && baseNode.getParentTreeNode().getAttribute().getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION) {
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();
Expand All @@ -141,7 +141,7 @@ protected boolean collectSplittedOffExpressions(Expression expression) {
} else {
ownedAttributes = managedType.getOwnedSingularAttributes();
}
orderedAttributes.addAll(JpaUtils.getEmbeddedPropertyPaths((Map<String, ExtendedAttribute<?, ?>>) ownedAttributes, prefix, false));
orderedAttributes.addAll(JpaUtils.getEmbeddedPropertyPaths((Map<String, ExtendedAttribute<?, ?>>) ownedAttributes, prefix, false, false));
}

// Signal the caller that the expression was eliminated
Expand Down Expand Up @@ -177,6 +177,8 @@ public Boolean visit(PathExpression expr) {
ExtendedManagedType<?> managedType = metamodel.getManagedType(ExtendedManagedType.class, baseNode.getJavaType());
attr = managedType.getAttribute(pathReference.getField()).getAttribute();

// This kind of happens when we do an entity select where the entity is split into it's component paths
// We don't want to split it here though as it won't end up in a group by clause or anything anyway
if (attr instanceof PluralAttribute<?, ?, ?>) {
return true;
}
Expand Down
237 changes: 149 additions & 88 deletions core/impl/src/main/java/com/blazebit/persistence/impl/JoinManager.java

Large diffs are not rendered by default.

86 changes: 67 additions & 19 deletions core/impl/src/main/java/com/blazebit/persistence/impl/JoinNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,11 @@ public class JoinNode implements From, ExpressionModifier, BaseNode {
private final String valuesTypeName;
private final int valueCount;
private final EntityType<?> valueType;
private final String valuesIdName;
private final String valueClazzAttributeName;
private final Set<String> valuesIdNames;
private final String valuesLikeClause;
private final boolean valueClazzAttributeSingular;
private final boolean valueClazzSimpleValue;
private final String valuesLikeAttribute;
private final String valuesCastedParameter;
private final String[] valuesAttributes;
private final String qualificationExpression;
Expand Down Expand Up @@ -110,8 +113,11 @@ private JoinNode(TreatedJoinAliasInfo treatedJoinAliasInfo) {
this.valuesTypeName = treatedJoinNode.valuesTypeName;
this.valueCount = treatedJoinNode.valueCount;
this.valueType = treatedJoinNode.valueType;
this.valuesIdName = treatedJoinNode.valuesIdName;
this.valueClazzAttributeName = treatedJoinNode.valueClazzAttributeName;
this.valuesIdNames = treatedJoinNode.valuesIdNames;
this.valuesLikeClause = treatedJoinNode.valuesLikeClause;
this.valueClazzAttributeSingular = treatedJoinNode.valueClazzAttributeSingular;
this.valueClazzSimpleValue = treatedJoinNode.valueClazzSimpleValue;
this.valuesLikeAttribute = treatedJoinNode.valuesLikeAttribute;
this.valuesCastedParameter = treatedJoinNode.valuesCastedParameter;
this.valuesAttributes = treatedJoinNode.valuesAttributes;
this.aliasInfo = treatedJoinAliasInfo;
Expand All @@ -132,8 +138,11 @@ private JoinNode(JoinNode parent, JoinTreeNode parentTreeNode, JoinType joinType
this.valuesTypeName = null;
this.valueCount = 0;
this.valueType = null;
this.valuesIdName = null;
this.valueClazzAttributeName = null;
this.valuesIdNames = null;
this.valuesLikeClause = null;
this.valueClazzAttributeSingular = false;
this.valueClazzSimpleValue = false;
this.valuesLikeAttribute = null;
this.valuesCastedParameter = null;
this.valuesAttributes = null;
this.qualificationExpression = qualificationExpression;
Expand All @@ -157,7 +166,7 @@ private JoinNode(JoinNode parent, JoinTreeNode parentTreeNode, JoinType joinType
onUpdate(null);
}

private JoinNode(Type<?> nodeType, EntityType<?> valueType, String valuesTypeName, int valueCount, String valuesIdName, String valueClazzAttributeName, String valuesCastedParameter, String[] valuesAttributes, JoinAliasInfo aliasInfo) {
private JoinNode(Type<?> nodeType, EntityType<?> valueType, String valuesTypeName, int valueCount, Set<String> valuesIdNames, String valuesLikeClause, String valueClazzAttributeQualificationExpression, boolean valueClazzAttributeSingular, boolean valueClazzSimpleValue, String valuesLikeAttribute, String valuesCastedParameter, String[] valuesAttributes, JoinAliasInfo aliasInfo) {
this.parent = null;
this.parentTreeNode = null;
this.joinType = null;
Expand All @@ -168,11 +177,14 @@ private JoinNode(Type<?> nodeType, EntityType<?> valueType, String valuesTypeNam
this.valuesTypeName = valuesTypeName;
this.valueCount = valueCount;
this.valueType = valueType;
this.valuesIdName = valuesIdName;
this.valueClazzAttributeName = valueClazzAttributeName;
this.valuesIdNames = valuesIdNames;
this.valuesLikeClause = valuesLikeClause;
this.valueClazzAttributeSingular = valueClazzAttributeSingular;
this.valueClazzSimpleValue = valueClazzSimpleValue;
this.valuesLikeAttribute = valuesLikeAttribute;
this.valuesCastedParameter = valuesCastedParameter;
this.valuesAttributes = valuesAttributes;
this.qualificationExpression = null;
this.qualificationExpression = valueClazzAttributeQualificationExpression;
this.aliasInfo = aliasInfo;
this.joinNodesForTreatConstraint = Collections.emptyList();
onUpdate(null);
Expand All @@ -182,8 +194,8 @@ public static JoinNode createRootNode(EntityType<?> nodeType, JoinAliasInfo alia
return new JoinNode(null, null, null, null, null, nodeType, null, null, aliasInfo);
}

public static JoinNode createValuesRootNode(Type<?> nodeType, EntityType<?> valueType, String valuesTypeName, int valueCount, String valuesIdName, String valueClazzAttributeName, String valuesCastedParameter, String[] valuesAttributes, JoinAliasInfo aliasInfo) {
return new JoinNode(nodeType, valueType, valuesTypeName, valueCount, valuesIdName, valueClazzAttributeName, valuesCastedParameter, valuesAttributes, aliasInfo);
public static JoinNode createValuesRootNode(Type<?> nodeType, EntityType<?> valueType, String valuesTypeName, int valueCount, Set<String> valuesIdName, String valuesLikeClause, String qualificationExpression, boolean valueClazzAttributeSingular, boolean valueClazzSimpleValue, String valuesLikeAttribute, String valuesCastedParameter, String[] valuesAttributes, JoinAliasInfo aliasInfo) {
return new JoinNode(nodeType, valueType, valuesTypeName, valueCount, valuesIdName, valuesLikeClause, qualificationExpression, valueClazzAttributeSingular, valueClazzSimpleValue, valuesLikeAttribute, valuesCastedParameter, valuesAttributes, aliasInfo);
}

public static JoinNode createCorrelationRootNode(JoinNode correlationParent, String correlationPath, Attribute<?, ?> correlatedAttribute, Type<?> nodeType, EntityType<?> treatType, JoinAliasInfo aliasInfo) {
Expand All @@ -202,7 +214,7 @@ public JoinNode cloneRootNode(JoinAliasInfo aliasInfo) {
// NOTE: no cloning of treatedJoinNodes and entityJoinNodes is intentional
JoinNode newNode;
if (valueCount > 0) {
newNode = createValuesRootNode(nodeType, valueType, valuesTypeName, valueCount, valuesIdName, valueClazzAttributeName, valuesCastedParameter, valuesAttributes, aliasInfo);
newNode = createValuesRootNode(nodeType, valueType, valuesTypeName, valueCount, valuesIdNames, valuesLikeClause, qualificationExpression, valueClazzAttributeSingular, valueClazzSimpleValue, valuesLikeAttribute, valuesCastedParameter, valuesAttributes, aliasInfo);
} else if (correlationParent == null) {
newNode = createRootNode((EntityType<?>) nodeType, aliasInfo);
} else {
Expand Down Expand Up @@ -613,12 +625,38 @@ public EntityType<?> getValueType() {
return valueType;
}

public String getValueClazzAttributeName() {
return valueClazzAttributeName;
public boolean isValueClazzAttributeSingular() {
return valueClazzAttributeSingular;
}

public String getValuesIdName() {
return valuesIdName;
public boolean isValueClazzSimpleValue() {
return valueClazzSimpleValue;
}

public String getValuesLikeAttribute() {
return valuesLikeAttribute;
}

public String getValueClazzAlias(String prefix) {
StringBuilder sb = new StringBuilder();
appendValueClazzAlias(sb, prefix);
return sb.toString();
}

public void appendValueClazzAlias(StringBuilder sb, String prefix) {
if (qualificationExpression == null) {
sb.append(prefix).append(valuesLikeAttribute.replace('.', '_'));
} else {
sb.append(prefix).append(valuesAttributes[0].replace('.', '_')).append('_').append(qualificationExpression.toLowerCase());
}
}

public Set<String> getValuesIdNames() {
return valuesIdNames;
}

public String getValuesLikeClause() {
return valuesLikeClause;
}

String getValuesTypeName() {
Expand Down Expand Up @@ -828,11 +866,21 @@ public void appendAlias(StringBuilder sb, boolean renderTreat, boolean externalR
sb.append(".value");
sb.append(')');
}
} else if (valueClazzAttributeName != null) {
} else if (valuesLikeAttribute != null) {
if (externalRepresentation) {
sb.append(aliasInfo.getAlias());
} else if (valueClazzAttributeSingular) {
sb.append(aliasInfo.getAlias()).append('.').append(valuesLikeAttribute.replace('.', '_'));
} else {
sb.append(aliasInfo.getAlias()).append('.').append(valueClazzAttributeName);
if (qualificationExpression != null) {
sb.append(qualificationExpression);
sb.append('(');
sb.append(aliasInfo.getAlias()).append('_').append(valuesLikeAttribute.replace('.', '_'));
sb.append('_').append(qualificationExpression.toLowerCase());
sb.append(')');
} else {
sb.append(aliasInfo.getAlias()).append('_').append(valuesLikeAttribute.replace('.', '_'));
}
}
} else {
if (qualificationExpression != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public static void expandBindings(EntityType<?> bindType, Map<String, Integer> b
// When binding null, we don't have to adapt anything
} else if (selectExpression instanceof PathExpression) {
boolean firstBinding = true;
final Collection<String> embeddedPropertyNames = getEmbeddedPropertyPaths(attributeEntries, attributeName, needsElementCollectionIdCutoffForCompositeIdOwner);
final Collection<String> embeddedPropertyNames = getEmbeddedPropertyPaths(attributeEntries, attributeName, needsElementCollectionIdCutoffForCompositeIdOwner, false);

PathExpression baseExpression = embeddedPropertyNames.size() > 1 ?
((PathExpression) selectExpression).clone(false) : ((PathExpression) selectExpression);
Expand Down Expand Up @@ -155,7 +155,7 @@ public static void expandBindings(EntityType<?> bindType, Map<String, Integer> b
}
}
} else if (selectExpression instanceof ParameterExpression) {
final Collection<String> embeddedPropertyNames = getEmbeddedPropertyPaths(attributeEntries, attributeName, jpaProvider.needsElementCollectionIdCutoff());
final Collection<String> embeddedPropertyNames = getEmbeddedPropertyPaths(attributeEntries, attributeName, jpaProvider.needsElementCollectionIdCutoff(), false);

if (embeddedPropertyNames.size() > 0) {
ParameterExpression parameterExpression = (ParameterExpression) selectExpression;
Expand Down Expand Up @@ -212,11 +212,26 @@ public static void expandBindings(EntityType<?> bindType, Map<String, Integer> b
}
}

public static Collection<String> getEmbeddedPropertyPaths(Map<String, ExtendedAttribute<?, ?>> attributeEntries, String attributeName, boolean needsElementCollectionIdCutoff) {
public static Collection<String> getEmbeddedPropertyPaths(Map<String, ExtendedAttribute<?, ?>> attributeEntries, String attributeName, boolean needsElementCollectionIdCutoff, boolean filterCollections) {
final NavigableSet<String> embeddedPropertyNames = new TreeSet<>();
String prefix = attributeName == null ? "" : attributeName + ".";
for (Map.Entry<String, ExtendedAttribute<?, ?>> entry : attributeEntries.entrySet()) {
int dotCount = -1;
int dotIndex = -1;
do {
dotCount++;
dotIndex = prefix.indexOf('.', dotIndex + 1);
} while (dotIndex != -1);

OUTER: for (Map.Entry<String, ExtendedAttribute<?, ?>> entry : attributeEntries.entrySet()) {
if (entry.getKey().startsWith(prefix)) {
if (filterCollections) {
List<Attribute<?, ?>> attributePath = entry.getValue().getAttributePath();
for (int i = dotCount; i < attributePath.size(); i++) {
if (attributePath.get(i).isCollection()) {
continue OUTER;
}
}
}
String subAttribute = entry.getKey().substring(prefix.length());
String lower = embeddedPropertyNames.lower(subAttribute);
if (lower == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,25 @@

package com.blazebit.persistence.impl;

import java.util.*;
import com.blazebit.persistence.parser.expression.Expression;
import com.blazebit.persistence.parser.expression.ParameterExpression;
import com.blazebit.reflection.PropertyPathExpression;

import javax.persistence.Parameter;
import javax.persistence.Query;
import javax.persistence.TemporalType;

import com.blazebit.lang.ValueRetriever;
import com.blazebit.persistence.parser.expression.Expression;
import com.blazebit.persistence.parser.expression.ParameterExpression;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
*
Expand Down Expand Up @@ -393,7 +403,7 @@ public void unregisterParameterName(String parameterName, ClauseType clauseType,
}
}

public void registerValuesParameter(String parameterName, Class<?> type, String[][] parameterNames, ValueRetriever<Object, Object>[] pathExpressions, AbstractCommonQueryBuilder<?, ?, ?, ?, ?> queryBuilder) {
public void registerValuesParameter(String parameterName, Class<?> type, String[][] parameterNames, PropertyPathExpression<Object, Object>[] pathExpressions, AbstractCommonQueryBuilder<?, ?, ?, ?, ?> queryBuilder) {
if (parameterName == null) {
throw new NullPointerException("parameterName");
}
Expand Down Expand Up @@ -793,7 +803,7 @@ static final class ValuesParameterWrapper implements ParameterValue {
private final ValuesParameterBinder binder;
private Collection<Object> value;

public ValuesParameterWrapper(Class<?> type, String[][] parameterNames, ValueRetriever<Object, Object>[] pathExpressions) {
public ValuesParameterWrapper(Class<?> type, String[][] parameterNames, PropertyPathExpression<Object, Object>[] pathExpressions) {
this.type = type;
this.binder = new ValuesParameterBinder(parameterNames, pathExpressions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.blazebit.persistence.impl;

import com.blazebit.lang.ValueRetriever;
import com.blazebit.reflection.PropertyPathExpression;

import javax.persistence.Query;
import java.util.Collection;
Expand All @@ -30,9 +30,9 @@
public class ValuesParameterBinder {

private final String[][] parameterNames;
private final ValueRetriever<Object, Object>[] pathExpressions;
private final PropertyPathExpression<Object, Object>[] pathExpressions;

public ValuesParameterBinder(String[][] parameterNames, ValueRetriever<Object, Object>[] pathExpressions) {
public ValuesParameterBinder(String[][] parameterNames, PropertyPathExpression<Object, Object>[] pathExpressions) {
this.parameterNames = parameterNames;
this.pathExpressions = pathExpressions;
}
Expand All @@ -43,7 +43,11 @@ public void bind(Query query, Collection<Object> value) {
Object element;
if (iterator.hasNext() && (element = iterator.next()) != null) {
for (int j = 0; j < parameterNames[i].length; j++) {
query.setParameter(parameterNames[i][j], pathExpressions[j].getValue(element));
if (pathExpressions[j] == null) {
query.setParameter(parameterNames[i][j], element);
} else {
query.setParameter(parameterNames[i][j], pathExpressions[j].getNullSafeValue(element));
}
}
} else {
for (int j = 0; j < parameterNames[i].length; j++) {
Expand All @@ -57,7 +61,7 @@ public String[][] getParameterNames() {
return parameterNames;
}

public ValueRetriever<Object, Object>[] getPathExpressions() {
public PropertyPathExpression<Object, Object>[] getPathExpressions() {
return pathExpressions;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void render(FunctionRenderContext functionRenderContext) {
sb.replace(subselectIndex, endIndex, entityName);
}
}
SqlUtils.applyTableNameRemapping(sb, valuesTableSqlAlias, valuesClause, valuesAliases);
SqlUtils.applyTableNameRemapping(sb, valuesTableSqlAlias, valuesClause, valuesAliases, null);
functionRenderContext.addChunk("(");
functionRenderContext.addChunk(sb.toString());
functionRenderContext.addChunk(")");
Expand Down
Loading

0 comments on commit 637f19a

Please sign in to comment.