From cb3369cc8a8a5e2e2e57dc6fce304593b0ab62b6 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 9 Aug 2023 20:08:52 +0200 Subject: [PATCH] add support for 'nulls first' and 'nulls last' in queries see #76. --- .../persistence/criteria/CriteriaBuilder.java | 28 ++++++++++--- .../persistence/criteria/NullPrecedence.java | 39 +++++++++++++++++++ .../jakarta/persistence/criteria/Order.java | 7 ++++ spec/src/main/asciidoc/appendixes.adoc | 2 + .../main/asciidoc/ch04-query-language.adoc | 14 ++++--- 5 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 api/src/main/java/jakarta/persistence/criteria/NullPrecedence.java diff --git a/api/src/main/java/jakarta/persistence/criteria/CriteriaBuilder.java b/api/src/main/java/jakarta/persistence/criteria/CriteriaBuilder.java index 07d8a321..d708b3c2 100644 --- a/api/src/main/java/jakarta/persistence/criteria/CriteriaBuilder.java +++ b/api/src/main/java/jakarta/persistence/criteria/CriteriaBuilder.java @@ -117,19 +117,37 @@ public interface CriteriaBuilder { /** * Create an ordering by the ascending value of the expression. - * @param x expression used to define the ordering + * @param expression expression used to define the ordering * @return ascending ordering corresponding to the expression */ - Order asc(Expression x); + Order asc(Expression expression); /** * Create an ordering by the descending value of the expression. - * @param x expression used to define the ordering + * @param expression expression used to define the ordering * @return descending ordering corresponding to the expression */ - Order desc(Expression x); + Order desc(Expression expression); + + /** + * Create an ordering by the ascending value of the expression. + * @param expression expression used to define the ordering + * @param nullPrecedence the precedence of null values + * @return ascending ordering corresponding to the expression + * @since 3.2 + */ + Order asc(Expression expression, NullPrecedence nullPrecedence); + + /** + * Create an ordering by the descending value of the expression. + * @param expression expression used to define the ordering + * @param nullPrecedence the precedence of null values + * @return descending ordering corresponding to the expression + * @since 3.2 + */ + Order desc(Expression expression, NullPrecedence nullPrecedence); + - //aggregate functions: /** diff --git a/api/src/main/java/jakarta/persistence/criteria/NullPrecedence.java b/api/src/main/java/jakarta/persistence/criteria/NullPrecedence.java new file mode 100644 index 00000000..ec3dffdc --- /dev/null +++ b/api/src/main/java/jakarta/persistence/criteria/NullPrecedence.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +// Contributors: +// Gavin King - 3.2 + +package jakarta.persistence.criteria; + +/** + * Specifies the precedence of null values within query result sets. + * + * @see CriteriaBuilder#asc(Expression, NullPrecedence) + * @see CriteriaBuilder#desc(Expression, NullPrecedence) + * + * @since 3.2 + */ +public enum NullPrecedence { + /** + * Null precedence not specified. + */ + NONE, + /** + * Null values occur at the beginning of the result set. + */ + FIRST, + /** + * Null values occur at the end of the result set. + */ + LAST +} \ No newline at end of file diff --git a/api/src/main/java/jakarta/persistence/criteria/Order.java b/api/src/main/java/jakarta/persistence/criteria/Order.java index d3ea653c..ddca102a 100644 --- a/api/src/main/java/jakarta/persistence/criteria/Order.java +++ b/api/src/main/java/jakarta/persistence/criteria/Order.java @@ -35,6 +35,13 @@ public interface Order { */ boolean isAscending(); + /** + * Return the precedence of null values. + * @return the NullPrecedence + * @since 3.2 + */ + NullPrecedence getNullPrecedence(); + /** * Return the expression that is used for ordering. * @return expression used for ordering diff --git a/spec/src/main/asciidoc/appendixes.adoc b/spec/src/main/asciidoc/appendixes.adoc index 6e2ab49e..b1a76282 100644 --- a/spec/src/main/asciidoc/appendixes.adoc +++ b/spec/src/main/asciidoc/appendixes.adoc @@ -108,6 +108,8 @@ Added support for Java record types as embeddable classes Added `||` string concatenation operator +Added support for specifying null precedence when ordering JPQL and criteria queries + Added _getSingleResultOrNull()_ to _Query_, _TypedQuery_, _StoredProcedureQuery_ Added _concat()_ overload accepting list of expressions to _CriteriaBuilder_ diff --git a/spec/src/main/asciidoc/ch04-query-language.adoc b/spec/src/main/asciidoc/ch04-query-language.adoc index b95def71..19af1a5d 100644 --- a/spec/src/main/asciidoc/ch04-query-language.adoc +++ b/spec/src/main/asciidoc/ch04-query-language.adoc @@ -320,10 +320,10 @@ future use.] are reserved identifiers: ABS, ALL, AND, ANY, AS, ASC, AVG, BETWEEN, BIT_LENGTH, BOTH, BY, CASE, CEILING, CHAR_LENGTH, CHARACTER_LENGTH, CLASS, COALESCE, CONCAT, COUNT, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, DELETE, DESC, DISTINCT, ELSE, EMPTY, -END, ENTRY, ESCAPE, EXISTS, EXP, EXTRACT, FALSE, FETCH, FLOOR, FROM, -FUNCTION, GROUP, HAVING, IN, INDEX, INNER, IS, JOIN, KEY, LEADING, -LEFT, LENGTH, LIKE, LOCAL, LN, LOCATE, LOWER, MAX, MEMBER, MIN, MOD, -NEW, NOT, NULL, NULLIF, OBJECT, OF, ON, OR, ORDER, OUTER, POSITION, +END, ENTRY, ESCAPE, EXISTS, EXP, EXTRACT, FALSE, FETCH, FIRST, FLOOR, +FROM, FUNCTION, GROUP, HAVING, IN, INDEX, INNER, IS, JOIN, KEY, LEADING, +LAST, LEFT, LENGTH, LIKE, LOCAL, LN, LOCATE, LOWER, MAX, MEMBER, MIN, MOD, +NEW, NOT, NULL, NULLS, NULLIF, OBJECT, OF, ON, OR, ORDER, OUTER, POSITION, POWER, ROUND, SELECT, SET, SIGN, SIZE, SOME, SQRT, SUBSTRING, SUM, THEN, TRAILING, TREAT, TRIM, TRUE, TYPE, UNKNOWN, UPDATE, UPPER, VALUE, WHEN, WHERE. @@ -2510,6 +2510,7 @@ orderby_clause ::= ORDER BY orderby_item {, orderby_item}* orderby_item ::= {state_field_path_expression | general_identification_variable | result_variable} [ASC | DESC] + [NULLS {FIRST | LAST}] ---- An orderby_item must be one of the following: @@ -2586,7 +2587,9 @@ ordering be used for the associated _orderby_item_; the keyword DESC specifies that descending ordering be used. Ascending ordering is the default. -SQL rules for the ordering of null values +The keyword NULLS specifies the ordering of null values, either FIRST or LAST. + +If NULLS is not specified, SQL rules for the ordering of null values apply: that is, all null values must appear before all non-null values in the ordering or all null values must appear after all non-null values in the ordering, but it is not specified which. @@ -2985,6 +2988,7 @@ orderby_item ::= general_identification_variable | result_variable [ASC | DESC] + [NULLS {FIRST | LAST}] subquery ::= simple_select_clause subquery_from_clause [where_clause] [groupby_clause] [having_clause] subquery_from_clause ::=