Skip to content

Commit

Permalink
Implemented treat support for criteria implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov committed Apr 14, 2017
1 parent b77ac09 commit 7ac770d
Show file tree
Hide file tree
Showing 106 changed files with 2,113 additions and 1,008 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ public void visit(MapValueExpression expression) {

@Override
public void visit(FunctionExpression expression) {
// A type constraint of a treat expression from within an aggregate may not "escape" the aggregate
Map<JoinNode, Boolean> oldTreatedJoinNodesForConstraints = treatedJoinNodesForConstraints;
if (expression instanceof AggregateExpression) {
treatedJoinNodesForConstraints = null;
}

if (com.blazebit.persistence.impl.util.ExpressionUtils.isOuterFunction(expression)) {
// Outer can only have paths, no need to set expression context for parameters
expression.getExpressions().get(0).accept(this);
Expand All @@ -130,6 +136,8 @@ public void visit(FunctionExpression expression) {
} else {
super.visit(expression);
}

treatedJoinNodesForConstraints = oldTreatedJoinNodesForConstraints;
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,9 +417,13 @@ escape_character : Character_literal
| Input_parameter
;

null_comparison_expression : (single_valued_path_expression | Input_parameter) IS (not=NOT)? NULL
null_comparison_expression : (single_valued_path_expression | Input_parameter | null_comparison_expression_extension) IS (not=NOT)? NULL
;

// NOTE: This is not standard compliant but not allowing this seems strange..
null_comparison_expression_extension : scalar_expression
;

empty_collection_comparison_expression : collection_valued_path_expression IS (not=NOT)? EMPTY
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,9 @@ public class TypeFunctionExpression extends FunctionExpression {
public TypeFunctionExpression(Expression expression) {
super("TYPE", new ArrayList<Expression>(Arrays.asList(expression)));
}

@Override
public TypeFunctionExpression clone(boolean resolved) {
return new TypeFunctionExpression(expressions.get(0).clone(resolved));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,32 @@ protected String treatRoot(String path, Class<?> type, String property) {
throw new IllegalArgumentException("Treat should not be used as the JPA provider does not support subtype property access!");
}

protected String treatRootWhereFragment(String alias, Class<?> treatType, String after, boolean negatedContext) {
if (jpaProvider.supportsTreatJoin()) {
return "TREAT(" + alias + " AS " + treatType.getSimpleName() + ")" + after;
} else if (jpaProvider.supportsSubtypePropertyResolving()) {
String operator;
String logicalOperator;
String predicate;

if (negatedContext) {
operator = " = ";
logicalOperator = " AND ";
} else {
operator = " <> ";
logicalOperator = " OR ";
}

predicate = alias + after;
return "(TYPE(" + alias + ")" + operator + treatType.getSimpleName() + logicalOperator + predicate + ")";
}

throw new IllegalArgumentException("Treat should not be used as the JPA provider does not support subtype property access!");
}

protected String treatJoinWhereFragment(String alias, Class<?> type, JoinType joinType, String whereFragment) {
if (jpaProvider.supportsTreatJoin() || joinType != JoinType.INNER) {
return whereFragment;
return whereFragment == null ? "" : whereFragment;
}
String constraint = "TYPE(" + alias + ") = " + type.getSimpleName();
if (whereFragment == null || whereFragment.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ public void implicitJoinTreatedRoot() {
criteria.getResultList();
}

@Test
// NOTE: Datanucleus does not support root treats properly with joined inheritance. Maybe a bug? TODO: report the error
@Category({ NoDatanucleus.class })
public void treatInAggregateHaving() {
CriteriaBuilder<Integer> criteria = cbf.create(em, Integer.class);
criteria.from(PolymorphicBase.class, "p");
criteria.select("SUM(TREAT(p AS PolymorphicSub1).sub1Value)");
criteria.groupBy("p.name");
criteria.having("SUM(TREAT(p AS PolymorphicSub1).sub1Value)").gt(1L);
assertEquals("SELECT SUM(" + treatRoot("p", PolymorphicSub1.class, "sub1Value") + ")" +
" FROM PolymorphicBase p" +
" GROUP BY p.name" +
" HAVING SUM(" + treatRoot("p", PolymorphicSub1.class, "sub1Value") + ") > :param_0", criteria.getQueryString());
criteria.getResultList();
}

@Test
// NOTE: Datanucleus does not support root treats properly with joined inheritance. Maybe a bug? TODO: report the error
@Category({ NoDatanucleus.class })
Expand Down
3 changes: 2 additions & 1 deletion jpa-criteria/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
limitations under the License.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ public interface BlazeAbstractQuery<T> extends AbstractQuery<T>, BlazeCommonAbst
* Like {@link AbstractQuery#from(Class)} but allows to set the alias of the {@link BlazeRoot}.
*
* @param entityClass the entity class
* @param alias The alias for the {@link BlazeRoot}
* @param <X> The entity type
* @param alias The alias for the {@link BlazeRoot}
* @param <X> The entity type
* @return query root corresponding to the given entity
*/
public <X> BlazeRoot<X> from(Class<X> entityClass, String alias);
Expand All @@ -51,8 +51,8 @@ public interface BlazeAbstractQuery<T> extends AbstractQuery<T>, BlazeCommonAbst
* Like {@link AbstractQuery#from(EntityType)} but allows to set the alias of the {@link BlazeRoot}.
*
* @param entityType the entity type
* @param alias The alias for the {@link BlazeRoot}
* @param <X> The entity type
* @param alias The alias for the {@link BlazeRoot}
* @param <X> The entity type
* @return query root corresponding to the given entity
*/
public <X> BlazeRoot<X> from(EntityType<X> entityType, String alias);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,23 @@
*/
public interface BlazeCollectionJoin<Z, E> extends CollectionJoin<Z, E>, BlazeJoin<Z, E> {

/**
* Like {@link BlazeJoin#treatAs} but returns the subtype {@link BlazeCollectionJoin} instead.
*
* @param type type to be downcast to
* @param <T> The target treat type
* @return The treated join object
*/
<T extends E> BlazeCollectionJoin<Z, T> treatAs(Class<T> type);

/* Compatibility for JPA 2.1 */

/**
* Modify the join to restrict the result according to the
* specified ON condition. Replaces the previous ON condition,
* if any.
* Return the join object
*
* @param restriction a simple or compound boolean expression
* @return the modified join object
*/
Expand All @@ -47,6 +57,7 @@ public interface BlazeCollectionJoin<Z, E> extends CollectionJoin<Z, E>, BlazeJo
* specified ON condition. Replaces the previous ON condition,
* if any.
* Return the join object
*
* @param restrictions zero or more restriction predicates
* @return the modified join object
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import javax.persistence.criteria.ListJoin;
import javax.persistence.criteria.MapJoin;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.SetJoin;
import java.util.Map;

/**
* An extended version of {@link CriteriaBuilder}.
Expand All @@ -35,21 +37,58 @@
*/
public interface BlazeCriteriaBuilder extends CriteriaBuilder {


/**
* Create a predicate that tests whether a map is empty.
*
* @param map expression
* @param <C> map type
* @return is-empty predicate
*/
public <C extends Map<?, ?>> Predicate isMapEmpty(Expression<C> map);

/**
* Create a predicate that tests whether a map is not empty.
*
* @param map expression
* @param <C> map type
* @return is-not-empty predicate
*/
public <C extends Map<?, ?>> Predicate isMapNotEmpty(Expression<C> map);

/**
* Create an expression that tests the size of a map.
*
* @param map map
* @param <C> map type
* @return size expression
*/
public <C extends Map<?, ?>> Expression<Integer> mapSize(Expression<C> map);

/**
* Create an expression that tests the size of a map.
*
* @param map map
* @param <C> map type
* @return size expression
*/
public <C extends Map<?, ?>> Expression<Integer> mapSize(C map);

/**
* Convenience method that uses the JPA 2.1 <code>FUNCTION</code> function to generically call DBMS functions.
*
* @param name The DBMS function name
* @param name The DBMS function name
* @param returnType The expected result type
* @param arguments The function arguments
* @param <T> The type of the result
* @param arguments The function arguments
* @param <T> The type of the result
* @return The function expression
*/
public <T> Expression<T> functionFunction(String name, Class<T> returnType, Expression<?>... arguments);

/**
* Like {@link CriteriaBuilder#asc(Expression)} but allows to also specify the null precedence.
*
* @param x The expression used to define the ordering
* @param x The expression used to define the ordering
* @param nullsFirst True if nulls should be first, false otherwise
* @return ascending ordering corresponding to the expression
*/
Expand All @@ -58,7 +97,7 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
/**
* Like {@link CriteriaBuilder#desc(Expression)} but allows to also specify the null precedence.
*
* @param x The expression used to define the ordering
* @param x The expression used to define the ordering
* @param nullsFirst True if nulls should be first, false otherwise
* @return descending ordering corresponding to the expression
*/
Expand All @@ -68,8 +107,8 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
* Like {@link BlazeCriteriaBuilder#createCriteriaUpdate(Class)} but also sets the alias for the entity.
*
* @param targetEntity target type for update operation
* @param alias The alias for the entity
* @param <T> The type of the entity
* @param alias The alias for the entity
* @param <T> The type of the entity
* @return the query object
*/
public <T> BlazeCriteriaUpdate<T> createCriteriaUpdate(Class<T> targetEntity, String alias);
Expand All @@ -78,8 +117,8 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
* Like {@link BlazeCriteriaBuilder#createCriteriaDelete(Class)} but also sets the alias for the entity.
*
* @param targetEntity target type for delete operation
* @param alias The alias for the entity
* @param <T> The type of the entity
* @param alias The alias for the entity
* @param <T> The type of the entity
* @return the query object
*/
public <T> BlazeCriteriaDelete<T> createCriteriaDelete(Class<T> targetEntity, String alias);
Expand Down Expand Up @@ -107,7 +146,7 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
* Create a query object to perform a bulk update operation.
*
* @param targetEntity target type for update operation
* @param <T> The type of the entity
* @param <T> The type of the entity
* @return the query object
*/
public <T> BlazeCriteriaUpdate<T> createCriteriaUpdate(Class<T> targetEntity);
Expand All @@ -116,7 +155,7 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
* Create a query object to perform a bulk delete operation.
*
* @param targetEntity target type for delete operation
* @param <T> The type of the entity
* @param <T> The type of the entity
* @return the query object
*/
public <T> BlazeCriteriaDelete<T> createCriteriaDelete(Class<T> targetEntity);
Expand All @@ -126,9 +165,9 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param join Join object
* @param type type to be downcast to
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <V> The target treat type
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <V> The target treat type
* @return Join object of the specified type
*/
public <X, T, V extends T> BlazeJoin<X, V> treat(Join<X, T> join, Class<V> type);
Expand All @@ -138,9 +177,9 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param join CollectionJoin object
* @param type type to be downcast to
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @return CollectionJoin object of the specified type
*/
public <X, T, E extends T> BlazeCollectionJoin<X, E> treat(CollectionJoin<X, T> join, Class<E> type);
Expand All @@ -150,9 +189,9 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param join SetJoin object
* @param type type to be downcast to
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @return SetJoin object of the specified type
*/
public <X, T, E extends T> BlazeSetJoin<X, E> treat(SetJoin<X, T> join, Class<E> type);
Expand All @@ -162,9 +201,9 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param join ListJoin object
* @param type type to be downcast to
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <E> The target treat type
* @return ListJoin object of the specified type
*/
public <X, T, E extends T> BlazeListJoin<X, E> treat(ListJoin<X, T> join, Class<E> type);
Expand All @@ -174,10 +213,10 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param join MapJoin object
* @param type type to be downcast to
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <K> The key type of the joined relation
* @param <V> The target treat type
* @param <X> The source type
* @param <T> The type of the joined relation
* @param <K> The key type of the joined relation
* @param <V> The target treat type
* @return MapJoin object of the specified type
*/
public <X, K, T, V extends T> BlazeMapJoin<X, K, V> treat(MapJoin<X, K, T> join, Class<V> type);
Expand All @@ -187,8 +226,8 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param path path
* @param type type to be downcast to
* @param <X> The path type
* @param <T> The target treat type
* @param <X> The path type
* @param <T> The target treat type
* @return Path object of the specified type
*/
public <X, T extends X> Path<T> treat(Path<X> path, Class<T> type);
Expand All @@ -198,8 +237,8 @@ public interface BlazeCriteriaBuilder extends CriteriaBuilder {
*
* @param root root
* @param type type to be downcast to
* @param <X> The root type
* @param <T> The target treat type
* @param <X> The root type
* @param <T> The target treat type
* @return Path object of the specified type
*/
public <X, T extends X> BlazeRoot<T> treat(Root<X> root, Class<T> type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public interface BlazeCriteriaDelete<T> extends CriteriaDelete<T>, BlazeCommonAb
* Like {@link CriteriaDelete#from(Class)} but allows to set the alias of the {@link BlazeRoot}.
*
* @param entityClass the entity class
* @param alias The alias for the {@link BlazeRoot}
* @param alias The alias for the {@link BlazeRoot}
* @return query root corresponding to the given entity
*/
public BlazeRoot<T> from(Class<T> entityClass, String alias);
Expand All @@ -45,7 +45,7 @@ public interface BlazeCriteriaDelete<T> extends CriteriaDelete<T>, BlazeCommonAb
* Like {@link CriteriaDelete#from(EntityType)} but allows to set the alias of the {@link BlazeRoot}.
*
* @param entityType the entity type
* @param alias The alias for the {@link BlazeRoot}
* @param alias The alias for the {@link BlazeRoot}
* @return query root corresponding to the given entity
*/
public BlazeRoot<T> from(EntityType<T> entityType, String alias);
Expand Down
Loading

0 comments on commit 7ac770d

Please sign in to comment.