Skip to content

Commit

Permalink
JPA #442 - Overload where(), having(), concat(), and() and or() to ac…
Browse files Browse the repository at this point in the history
…cept List.

Signed-off-by: Tomáš Kraus <tomas.kraus@oracle.com>
  • Loading branch information
Tomas-Kraus authored and lukasj committed Sep 20, 2023
1 parent f24afd7 commit 6d4ba8d
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -15,11 +15,14 @@
// Gordon Yorke - Initial development
// 02/03/2017 - Dalia Abo Sheasha
// - 509693 : EclipseLink generates inconsistent SQL statements for SubQuery
// 08/22/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.jpa.querydef;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import jakarta.persistence.criteria.AbstractQuery;
Expand Down Expand Up @@ -106,12 +109,13 @@ public AbstractQuery<T> groupBy(Expression<?>... grouping){
* Specify a restriction over the groups of the query. Replaces the previous
* having restriction(s), if any.
*
* @param restriction
* a simple or compound boolean expression
* @param restriction a simple or compound boolean expression
* @return the modified query
* @throws NullPointerException when restriction expression is {@code null}
*/
@Override
public AbstractQuery<T> having(Expression<Boolean> restriction) {
Objects.requireNonNull(restriction, "Restriction expression is null");
findRootAndParameters(restriction);
if (((InternalExpression)restriction).isCompoundExpression() || ((InternalExpression)restriction).isPredicate()) {
this.havingClause = (Predicate) restriction;
Expand All @@ -127,20 +131,29 @@ public AbstractQuery<T> having(Expression<Boolean> restriction) {
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed.
*
* @param restrictions
* zero or more restriction predicates
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
@Override
public AbstractQuery<T> having(Predicate... restrictions){
if (restrictions != null && restrictions.length > 0) {
Predicate conjunction = this.queryBuilder.conjunction();
for (Predicate predicate : restrictions) {
conjunction = this.queryBuilder.and(conjunction, predicate);
}
findRootAndParameters(conjunction);
this.havingClause = conjunction;
}
public AbstractQuery<T> having(Predicate... restrictions) {
return having(restrictions != null ? List.of(restrictions) : null);
}

/**
* Specify restrictions over the groups of the query according the
* conjunction of the specified restriction predicates. Replaces the
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed.
*
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
// TODO-API-3.2: Prototype is missing in API
//@Override
public AbstractQuery<T> having(List<Predicate> restrictions) {
Predicate predicate = queryBuilder.and(restrictions);
findRootAndParameters(predicate);
this.havingClause = predicate;
return this;
}

Expand Down Expand Up @@ -273,11 +286,12 @@ public <X> Root<X> from(Class<X> entityClass) {
* This method only overrides the return type of the corresponding
* AbstractQuery method.
*
* @param restriction
* a simple or compound boolean expression
* @param restriction a simple or compound boolean expression
* @return the modified query
* @throws NullPointerException when restriction expression is {@code null}
*/
@Override
@SuppressWarnings("unchecked")
public AbstractQuery<T> where(Expression<Boolean> restriction){
return (AbstractQuery<T>)super.where(restriction);
}
Expand All @@ -290,13 +304,32 @@ public AbstractQuery<T> where(Expression<Boolean> restriction){
* method only overrides the return type of the corresponding AbstractQuery
* method.
*
* @param restrictions
* zero or more restriction predicates
* @param restrictions zero or more restriction predicates
* @return the modified query
* @throws NullPointerException when restrictions array is {@code null}
*/
@Override
@SuppressWarnings("unchecked")
public AbstractQuery<T> where(Predicate... restrictions) {
return (AbstractQuery<T>) super.where(restrictions);
}

/**
* Modify the query to restrict the query result according to the
* conjunction of the specified restriction predicates. Replaces the
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed. This
* method only overrides the return type of the corresponding AbstractQuery
* method.
*
* @param restrictions zero or more restriction predicates
* @return the modified query
* @throws NullPointerException when restrictions {@link List} is {@code null}
*/
@Override
@SuppressWarnings("unchecked")
public AbstractQuery<T> where(List<Predicate> restrictions) {
return (AbstractQuery<T>) super.where(restrictions);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -14,10 +14,14 @@
// Contributors:
// 10/26/2012-2.5 Chris Delahunt
// - 350469: JPA 2.1 Criteria Query framework Bulk Update/Delete support
// 08/22/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.jpa.querydef;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import jakarta.persistence.criteria.CommonAbstractCriteria;
Expand Down Expand Up @@ -125,8 +129,7 @@ public Root internalFrom(Class<?> entityClass) {
* Modify the query to restrict the query results according to the specified
* boolean expression. Replaces the previously added restriction(s), if any.
*
* @param restriction
* a simple or compound boolean expression
* @param restriction a simple or compound boolean expression
* @return the modified query
*/
public CommonAbstractCriteria where(Expression<Boolean> restriction) {
Expand All @@ -141,17 +144,26 @@ public CommonAbstractCriteria where(Expression<Boolean> restriction) {
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed.
*
* @param restrictions
* zero or more restriction predicates
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
public CommonAbstractCriteria where(Predicate... restrictions) {
if (restrictions == null || restrictions.length == 0){
this.where = null;
}
Predicate predicate = this.queryBuilder.and(restrictions);
return where(restrictions != null ? List.of(restrictions) : null);
}

/**
* Modify the query to restrict the query results according to the
* conjunction of the specified restriction predicates. Replaces the
* previously added restriction(s), if any. If no restrictions are
* specified, any previously added restrictions are simply removed.
*
* @param restrictions zero or more restriction predicates
* @return the modified query
*/
public CommonAbstractCriteria where(List<Predicate> restrictions) {
Predicate predicate = queryBuilder.and(restrictions);
findRootAndParameters(predicate);
this.where = predicate;
where = predicate;
return this;
}

Expand All @@ -172,10 +184,12 @@ public <U> Subquery<U> subquery(Class<U> type) {
protected abstract void integrateRoot(RootImpl root);

protected void findRootAndParameters(Expression<?> predicate) {
Objects.requireNonNull(predicate, "Predicate expression is null");
((InternalSelection) predicate).findRootAndParameters(this);
}

protected void findRootAndParameters(Order order) {
Objects.requireNonNull(order, "Order is null");
((OrderImpl) order).findRootAndParameters(this);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2022 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
Expand All @@ -17,6 +17,8 @@
// - Issue 1442: Implement New Jakarta Persistence 3.1 Features
// 04/19/2022: Jody Grassel
// - Issue 579726: CriteriaBuilder neg() only returns Integer type, instead of it's argument expression type.
// 08/22/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.jpa.querydef;

import java.io.Serializable;
Expand Down Expand Up @@ -459,57 +461,81 @@ public Predicate or(Expression<Boolean> x, Expression<Boolean> y){
}

/**
* Create a conjunction of the given restriction predicates. A conjunction
* of zero predicates is true.
* Create a conjunction of the given restriction predicates.
* A conjunction of {@code null} or zero predicates is {@code true}.
*
* @param restrictions
* zero or more restriction predicates
* @param restrictions zero or more restriction predicates
* @return and predicate
*/
@Override
public Predicate and(Predicate... restrictions){
int max = restrictions.length;
if (max == 0){
return this.conjunction();
}
Predicate a = restrictions[0];
for (int i = 1; i < max; ++i){
a = this.and(a, restrictions[i]);
}
return a;
public Predicate and(Predicate... restrictions) {
return and(restrictions != null ? List.of(restrictions) : null);
}

/**
* Create a conjunction of the given restriction predicates.
* A conjunction of {@code null} or zero predicates is {@code true}.
*
* @param restrictions a list of zero or more restriction predicates
* @return and predicate
*/
// TODO-API-3.2
//@Override
public Predicate and(List<Predicate> list) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
public Predicate and(List<Predicate> restrictions) {
// PERF: Build simple cases directly
switch (restrictions != null ? restrictions.size() : 0) {
case 0:
return this.conjunction();
case 1:
return restrictions.get(0);
case 2:
return and(restrictions.get(0), restrictions.get(1));
default:
Predicate predicate = restrictions.get(0);
for (int i = 1; i < restrictions.size(); i++) {
predicate = and(predicate, restrictions.get(i));
}
return predicate;
}
}

/**
* Create a disjunction of the given restriction predicates. A disjunction
* of zero predicates is false.
* Create a disjunction of the given restriction predicates.
* A disjunction of {@code null} or zero predicates is {@code false}.
*
* @param restrictions
* zero or more restriction predicates
* @param restrictions zero or more restriction predicates
* @return and predicate
*/
@Override
public Predicate or(Predicate... restrictions){
int max = restrictions.length;
if (max == 0){
return this.disjunction();
}
Predicate a = restrictions[0];
for (int i = 1; i < max; ++i){
a = this.or(a, restrictions[i]);
}
return a;
public Predicate or(Predicate... restrictions) {
return or(restrictions != null ? List.of(restrictions) : null);
}

/**
* Create a disjunction of the given restriction predicates.
* A disjunction of {@code null} or zero predicates is {@code false}.
*
* @param restrictions a list of zero or more restriction predicates
* @return or predicate
*/
// TODO-API-3.2
//@Override
public Predicate or(List<Predicate> list) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
public Predicate or(List<Predicate> restrictions) {
// PERF: Build simple cases directly
switch (restrictions != null ? restrictions.size() : 0) {
case 0:
return this.disjunction();
case 1:
return restrictions.get(0);
case 2:
return or(restrictions.get(0), restrictions.get(1));
default:
Predicate predicate = restrictions.get(0);
for (int i = 1; i < restrictions.size(); i++) {
predicate = or(predicate, restrictions.get(i));
}
return predicate;
}
}

/**
Expand Down Expand Up @@ -1889,10 +1915,30 @@ public Predicate notLike(Expression<String> x, String pattern, char escapeChar){
return this.notLike(x, this.internalLiteral(pattern), this.internalLiteral(escapeChar));
}

/**
* Create an expression for {@link String} concatenation.
* If the given list of expressions is {@code null} or empty, returns an expression equivalent to {@code literal("")}.
*
* @param expressions {@link String} expressions
* @return expression corresponding to concatenation
*/
// TODO-API-3.2
//@Override
public Expression<String> concat(List<Expression<String>> list) {
throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet");
public Expression<String> concat(List<Expression<String>> expressions) {
switch(expressions != null ? expressions.size() : 0) {
case 0:
return literal("");
case 1:
return expressions.get(0);
case 2:
return concat(expressions.get(0), expressions.get(1));
default:
Expression<String> expression = expressions.get(0);
for (int i = 1; i < expressions.size(); i++) {
expression = concat(expression, expressions.get(i));
}
return expression;
}
}

/**
Expand Down

0 comments on commit 6d4ba8d

Please sign in to comment.