From bfb0f22a01658cf76449d0e1e28fde4e15bbbbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kraus?= Date: Thu, 31 Aug 2023 16:54:41 +0200 Subject: [PATCH] jakartaee/persistence#440 - add support for 'nulls first' and 'nulls last' in queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomáš Kraus --- .../jpa/querydef/CriteriaBuilderImpl.java | 43 ++++++------------- .../jpa/querydef/CriteriaQueryImpl.java | 14 +++--- .../internal/jpa/querydef/OrderImpl.java | 25 +++++++---- 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java index 659f5e275ea..e9f372d15ad 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaBuilderImpl.java @@ -168,47 +168,32 @@ public CompoundSelection array(Selection... selections){ return new CompoundSelectionImpl(ClassConstants.AOBJECT, selections, true); } - /** - * Create an ordering by the ascending value of the expression. - * - * @param x - * expression used to define the ordering - * @return ascending ordering corresponding to the expression - */ @Override - public Order asc(Expression x){ - if (((InternalSelection)x).getCurrentNode() == null){ - throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); - } - return new OrderImpl(x); + public Order asc(Expression expression) { + return asc(expression, Nulls.NONE); } - // TODO-API-3.2 + // TODO-API-3.2 - Nulls added to OrderImpl and ObjectLevelReadQuery in CriteriaQueryImpl, but no tests exist @Override public Order asc(Expression expression, Nulls nullPrecedence) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + if (((InternalSelection)expression).getCurrentNode() == null){ + throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); + } + return new OrderImpl(expression, true, nullPrecedence); } - /** - * Create an ordering by the descending value of the expression. - * - * @param x - * expression used to define the ordering - * @return descending ordering corresponding to the expression - */ @Override - public Order desc(Expression x){ - if (((InternalSelection)x).getCurrentNode() == null){ - throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); - } - OrderImpl order = new OrderImpl(x, false); - return order; + public Order desc(Expression expression){ + return desc(expression, Nulls.NONE); } - // TODO-API-3.2 + // TODO-API-3.2 - Nulls added to OrderImpl and ObjectLevelReadQuery in CriteriaQueryImpl, but no tests exist @Override public Order desc(Expression expression, Nulls nullPrecedence) { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + if (((InternalSelection)expression).getCurrentNode() == null){ + throw new IllegalArgumentException(ExceptionLocalization.buildMessage("OPERATOR_EXPRESSION_IS_CONJUNCTION")); + } + return new OrderImpl(expression, false, nullPrecedence); } // aggregate functions: diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java index 07812c1296d..4eecf9da9ed 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/CriteriaQueryImpl.java @@ -723,11 +723,15 @@ public DatabaseQuery translate() { if (this.orderBy != null && !this.orderBy.isEmpty()) { for (Order order : this.orderBy) { OrderImpl orderImpl = (OrderImpl) order; - org.eclipse.persistence.expressions.Expression orderExp = ((ExpressionImpl) orderImpl.getExpression()).getCurrentNode(); - if (orderImpl.isAscending()) { - orderExp = orderExp.ascending(); - } else { - orderExp = orderExp.descending(); + org.eclipse.persistence.expressions.Expression orderExp = ((ExpressionImpl) orderImpl.getExpression()).getCurrentNode(); + orderExp = orderImpl.isAscending() ? orderExp.ascending() : orderExp.descending(); + switch (orderImpl.getNullPrecedence()) { + case FIRST: + orderExp = orderExp.nullsFirst(); + break; + case LAST: + orderExp = orderExp.nullsLast(); + break; } query.addOrdering(orderExp); } diff --git a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/OrderImpl.java b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/OrderImpl.java index 27f0cc18465..f862661f68b 100644 --- a/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/OrderImpl.java +++ b/jpa/org.eclipse.persistence.jpa/src/main/java/org/eclipse/persistence/internal/jpa/querydef/OrderImpl.java @@ -12,7 +12,8 @@ // Contributors: // Gordon Yorke - Initial development -// +// 08/31/2023: Tomas Kraus +// - New Jakarta Persistence 3.2 Features package org.eclipse.persistence.internal.jpa.querydef; import java.io.Serializable; @@ -21,18 +22,26 @@ import jakarta.persistence.criteria.Nulls; import jakarta.persistence.criteria.Order; +/** + * An object that defines an ordering over the query results. + */ public class OrderImpl implements Order, Serializable{ protected Expression expression; protected boolean isAscending; + protected Nulls nullPrecedence; - public OrderImpl(Expression expression){ - this(expression, true); - } - - public OrderImpl(Expression expression, boolean isAscending){ + /** + * Creates an instance of ordering over the query results definition. + * + * @param expression the query expression + * @param isAscending whether ascending ordering is in effect + * @param nullPrecedence the precedence of {@code null} values within query result sets + */ + public OrderImpl(Expression expression, boolean isAscending, Nulls nullPrecedence) { this.expression = expression; this.isAscending = isAscending; + this.nullPrecedence = nullPrecedence; } @Override @@ -48,12 +57,12 @@ public boolean isAscending() { // TODO-API-3.2 @Override public Nulls getNullPrecedence() { - throw new UnsupportedOperationException("Jakarta Persistence 3.2 API was not implemented yet"); + return nullPrecedence; } @Override public Order reverse() { - return new OrderImpl(this.expression, false); + return new OrderImpl(expression, !isAscending, nullPrecedence); } public void findRootAndParameters(CommonAbstractCriteriaImpl query) {