Merge branch 'main' into wip/6.0

This commit is contained in:
Andrea Boriero 2021-12-06 17:39:07 +01:00
commit 74a395d744
3 changed files with 127 additions and 0 deletions

View File

@ -743,4 +743,20 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override
JpaOrder desc(Expression<?> x);
/**
* Create an ordering by the ascending value of the expression.
* @param x expression used to define the ordering
* @param nullsFirst Whether <code>null</code> should be sorted first
* @return ascending ordering corresponding to the expression
*/
JpaOrder asc(Expression<?> x, boolean nullsFirst);
/**
* Create an ordering by the descending value of the expression.
* @param x expression used to define the ordering
* @param nullsFirst Whether <code>null</code> should be sorted first
* @return descending ordering corresponding to the expression
*/
JpaOrder desc(Expression<?> x, boolean nullsFirst);
}

View File

@ -63,6 +63,7 @@ import org.hibernate.query.criteria.JpaCoalesce;
import org.hibernate.query.criteria.JpaCompoundSelection;
import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaOrder;
import org.hibernate.query.criteria.JpaParameterExpression;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.criteria.ValueHandlingMode;
@ -397,6 +398,24 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
return new SqmSortSpecification( (SqmExpression<?>) x, SortOrder.DESCENDING );
}
@Override
public JpaOrder asc(Expression<?> x, boolean nullsFirst) {
return new SqmSortSpecification(
(SqmExpression<?>) x,
SortOrder.ASCENDING,
nullsFirst ? NullPrecedence.FIRST : NullPrecedence.LAST
);
}
@Override
public JpaOrder desc(Expression<?> x, boolean nullsFirst) {
return new SqmSortSpecification(
(SqmExpression<?>) x,
SortOrder.DESCENDING,
nullsFirst ? NullPrecedence.FIRST : NullPrecedence.LAST
);
}
@Override
public JpaCompoundSelection<Tuple> tuple(Selection<?>[] selections) {
//noinspection unchecked

View File

@ -0,0 +1,92 @@
package org.hibernate.query.criteria.internal;
import java.util.List;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author Christian Beikov
*/
@TestForIssue(jiraKey = "HHH-14897")
@Jpa(
annotatedClasses = { NullPrecedenceTest.Foo.class }
)
public class NullPrecedenceTest {
@Test
public void testNullPrecedence(EntityManagerFactoryScope scope) {
scope.inTransaction( entityManager -> {
entityManager.persist( new Foo( 1L, null ) );
entityManager.persist( new Foo( 2L, "ABC" ) );
entityManager.persist( new Foo( 3L, "DEF" ) );
entityManager.persist( new Foo( 4L, "DEF" ) );
final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder();
final CriteriaQuery<Foo> cq = cb.createQuery( Foo.class );
final Root<Foo> foo = cq.from( Foo.class );
cq.orderBy(
cb.desc( foo.get( "bar" ), true ),
cb.desc( foo.get( "id" ) )
);
final TypedQuery<Foo> tq = entityManager.createQuery( cq );
final List<Foo> resultList = tq.getResultList();
assertEquals( 4, resultList.size() );
assertEquals( 1L, resultList.get( 0 ).getId() );
assertEquals( 4L, resultList.get( 1 ).getId() );
assertEquals( 3L, resultList.get( 2 ).getId() );
assertEquals( 2L, resultList.get( 3 ).getId() );
} );
}
@Entity(name = "Foo")
public static class Foo {
private long id;
private String bar;
public Foo() {
}
public Foo(long id, String bar) {
this.id = id;
this.bar = bar;
}
@Id
@Column(nullable = false)
public long getId() {
return this.id;
}
public void setId(final long id) {
this.id = id;
}
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
}