HHH-16848 add SelectionQuery.ascending(int) & descending(int)

This commit is contained in:
Gavin King 2023-06-26 18:09:57 +02:00
parent 23df9eb785
commit bec6cfab12
9 changed files with 181 additions and 1 deletions

View File

@ -1074,6 +1074,16 @@ public class ProcedureCallImpl<R>
throw new UnsupportedOperationException( "Not supported for procedure calls" );
}
@Override
public Query<R> ascending(int element) {
throw new UnsupportedOperationException( "Not supported for procedure calls" );
}
@Override
public Query<R> descending(int element) {
throw new UnsupportedOperationException( "Not supported for procedure calls" );
}
@Override
public Query<R> unordered() {
return this;

View File

@ -905,6 +905,12 @@ public interface Query<R> extends SelectionQuery<R>, MutationQuery, TypedQuery<R
@Override
Query<R> descending(SingularAttribute<? super R, ?> attribute);
@Override
Query<R> ascending(int element);
@Override
Query<R> descending(int element);
@Override
Query<R> unordered();

View File

@ -493,6 +493,28 @@ public interface SelectionQuery<R> extends CommonQueryContract {
@Incubating
SelectionQuery<R> descending(SingularAttribute<? super R, ?> attribute);
/**
* Add an element of the select list to be used to order the query results
* in ascending order.
*
* @param element an integer identifying an element of the select list
*
* @since 6.3
*/
@Incubating
SelectionQuery<R> ascending(int element);
/**
* Add an element of the select list to be used to order the query results
* in descending order.
*
* @param element an integer identifying an element of the select list
*
* @since 6.3
*/
@Incubating
SelectionQuery<R> descending(int element);
/**
* Clear the ordering conditions for this query.
*

View File

@ -136,8 +136,22 @@ public interface SqmQueryImplementor<R> extends QueryImplementor<R>, SqmQuery, N
return this;
}
@Override
default SqmQueryImplementor<R> ascending(int element) {
addOrdering( element, SortOrder.ASCENDING );
return this;
}
@Override
default SqmQueryImplementor<R> descending(int element) {
addOrdering( element, SortOrder.DESCENDING );
return this;
}
SqmQueryImplementor<R> addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order);
SqmQueryImplementor<R> addOrdering(int element, SortOrder order);
@Override
SqmQueryImplementor<R> unordered();

View File

@ -39,7 +39,6 @@ import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.Query;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.ResultListTransformer;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.TupleTransformer;
import org.hibernate.query.named.NamedQueryMemento;
@ -288,6 +287,16 @@ public abstract class AbstractQuery<R>
throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() );
}
@Override
public Query<R> ascending(int element) {
throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() );
}
@Override
public Query<R> descending(int element) {
throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() );
}
@Override
public Query<R> unordered() {
throw new UnsupportedOperationException( "Should be implemented by " + this.getClass().getName() );

View File

@ -1510,6 +1510,16 @@ public class NativeQueryImpl<R>
throw new UnsupportedOperationException("Not yet supported for native queries");
}
@Override
public Query<R> ascending(int element) {
throw new UnsupportedOperationException("Not yet supported for native queries");
}
@Override
public Query<R> descending(int element) {
throw new UnsupportedOperationException("Not yet supported for native queries");
}
@Override
public Query<R> unordered() {
return this;

View File

@ -88,6 +88,7 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
@ -99,6 +100,7 @@ import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
import org.hibernate.sql.results.internal.TupleMetadata;
@ -982,6 +984,36 @@ public class QuerySqmImpl<R>
}
}
@Override
public SqmQueryImplementor<R> addOrdering(int element, SortOrder order) {
if ( sqm instanceof SqmSelectStatement ) {
sqm = sqm.copy( SqmCopyContext.noParamCopyContext() );
SqmSelectStatement<R> select = (SqmSelectStatement<R>) sqm;
int size = select.getSelection().getSelectionItems().size();
if ( element < 1) {
throw new IllegalArgumentException("Cannot order by element " + element + " (the first select item is element 1)");
}
if ( element > size) {
throw new IllegalArgumentException("Cannot order by element " + element + " (there are " + size + " select items)");
}
NodeBuilder nodeBuilder = sqm.nodeBuilder();
List<Order> orders = new ArrayList<>( select.getOrderList() );
orders.add( new SqmSortSpecification(
new SqmAliasedNodeRef(
element,
nodeBuilder.getTypeConfiguration().standardBasicTypeForJavaType( Integer.class ),
nodeBuilder
),
order
) );
select.orderBy( orders );
return this;
}
else {
throw new IllegalStateException( "Not a select query" );
}
}
@Override
public SqmQueryImplementor<R> unordered() {
if ( sqm instanceof SqmSelectStatement ) {

View File

@ -61,11 +61,13 @@ import org.hibernate.query.sqm.internal.SqmInterpretationsKey.InterpretationsKey
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.type.descriptor.java.JavaType;
@ -567,6 +569,18 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
return this;
}
@Override
public SqmSelectionQuery<R> ascending(int element) {
addOrdering( element, SortOrder.ASCENDING );
return this;
}
@Override
public SqmSelectionQuery<R> descending(int element) {
addOrdering( element, SortOrder.DESCENDING );
return this;
}
private void addOrdering(SingularAttribute<? super R, ?> attribute, SortOrder order) {
sqm = sqm.copy( SqmCopyContext.noParamCopyContext() );
NodeBuilder nodeBuilder = sqm.nodeBuilder();
@ -581,6 +595,28 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
sqm.orderBy( orders );
}
private void addOrdering(int element, SortOrder order) {
sqm = sqm.copy( SqmCopyContext.noParamCopyContext() );
int size = sqm.getSelection().getSelectionItems().size();
if ( element < 1) {
throw new IllegalArgumentException("Cannot order by element " + element + " (the first select item is element 1)");
}
if ( element > size) {
throw new IllegalArgumentException("Cannot order by element " + element + " (there are " + size + " select items)");
}
NodeBuilder nodeBuilder = sqm.nodeBuilder();
List<Order> orders = new ArrayList<>( sqm.getOrderList() );
orders.add( new SqmSortSpecification(
new SqmAliasedNodeRef(
element,
nodeBuilder.getTypeConfiguration().standardBasicTypeForJavaType( Integer.class ),
nodeBuilder
),
order
) );
sqm.orderBy( orders );
}
@Override
public SqmSelectionQuery<R> unordered() {
sqm = sqm.copy( SqmCopyContext.noParamCopyContext() );

View File

@ -210,6 +210,47 @@ public class OrderTest {
});
}
@Test void testAscendingDescendingBySelectElement(SessionFactoryScope scope) {
scope.inTransaction( session -> session.createMutationQuery("delete Book").executeUpdate() );
scope.inTransaction( session -> {
session.persist(new Book("9781932394153", "Hibernate in Action"));
session.persist(new Book("9781617290459", "Java Persistence with Hibernate"));
});
scope.inSession(session -> {
List<?> titlesAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class)
.ascending(2)
.getResultList()
.stream().map(book -> book[1])
.collect(toList());
assertEquals("Hibernate in Action", titlesAsc.get(0));
assertEquals("Java Persistence with Hibernate", titlesAsc.get(1));
List<?> titlesDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class)
.descending(2)
.getResultList()
.stream().map(book -> book[1])
.collect(toList());
assertEquals("Hibernate in Action", titlesDesc.get(1));
assertEquals("Java Persistence with Hibernate", titlesDesc.get(0));
List<?> isbnAsc = session.createSelectionQuery("select isbn, title from Book", Object[].class)
.ascending(1).descending(2)
.getResultList()
.stream().map(book -> book[1])
.collect(toList());
assertEquals("Hibernate in Action", isbnAsc.get(1));
assertEquals("Java Persistence with Hibernate", isbnAsc.get(0));
List<?> isbnDesc = session.createSelectionQuery("select isbn, title from Book", Object[].class)
.descending(1).descending(2)
.getResultList()
.stream().map(book -> book[1])
.collect(toList());
assertEquals("Hibernate in Action", isbnDesc.get(0));
assertEquals("Java Persistence with Hibernate", isbnDesc.get(1));
});
}
@Entity(name="Book")
static class Book {
@Id String isbn;