HHH-18979 add JpaCriteriaQuery.getRoot()
making it cleaner to manipulate criteria constructed from HQL also clean up some dodgy unchecked casts
This commit is contained in:
parent
5e107b8981
commit
80fb5950ae
|
@ -919,7 +919,7 @@ It's even possible to transform a HQL query string to a criteria query, and modi
|
|||
----
|
||||
HibernateCriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
|
||||
var query = builder.createQuery("from Book where year(publicationDate) > 2000", Book.class);
|
||||
var root = (Root<Book>) query.getRootList().get(0);
|
||||
var root = query.getRoot(0, Book.class);
|
||||
query.where(builder.like(root.get(Book_.title), builder.literal("Hibernate%")));
|
||||
query.orderBy(builder.asc(root.get(Book_.title)), builder.desc(root.get(Book_.isbn)));
|
||||
List<Book> matchingBooks = session.createSelectionQuery(query).getResultList();
|
||||
|
|
|
@ -53,7 +53,7 @@ import java.util.function.Function;
|
|||
* List<Book> books
|
||||
* = new CriteriaDefinition<>(sessionFactory, Book.class,
|
||||
* "from Book left join fetch authors where type = BOOK") {{
|
||||
* var book = (JpaRoot<Book>) getSelection();
|
||||
* var book = getRoot(0, Book.class);
|
||||
* where(getRestriction(), like(book.get(Book_.title), "%Hibernate%"));
|
||||
* orderBy(desc(book.get(Book_.publicationDate)), asc(book.get(Book_.isbn)));
|
||||
* }}
|
||||
|
@ -408,10 +408,20 @@ public abstract class CriteriaDefinition<R>
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<Root<?>> getRootList() {
|
||||
public List<? extends JpaRoot<?>> getRootList() {
|
||||
return query.getRootList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> JpaRoot<? extends E> getRoot(int position, Class<E> type) {
|
||||
return query.getRoot( position, type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <E> JpaRoot<? extends E> getRoot(String alias, Class<E> type) {
|
||||
return query.getRoot( alias, type );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends JpaCteCriteria<?>> getCteCriterias() {
|
||||
return query.getCteCriterias();
|
||||
|
|
|
@ -61,13 +61,33 @@ public interface JpaCriteriaQuery<T> extends CriteriaQuery<T>, JpaQueryableCrite
|
|||
/**
|
||||
* Return the {@linkplain #getRoots() roots} as a list.
|
||||
*/
|
||||
List<Root<?>> getRootList();
|
||||
List<? extends JpaRoot<?>> getRootList();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
default List<Order> getOrderList() {
|
||||
return (List) getQueryPart().getSortSpecifications();
|
||||
}
|
||||
/**
|
||||
* Get a {@linkplain Root query root} element at the given position
|
||||
* with the given type.
|
||||
*
|
||||
* @param position the position of this root element
|
||||
* @param type the type of the root entity
|
||||
*
|
||||
* @throws IllegalArgumentException if the root entity at the given
|
||||
* position is not of the given type, or if there are not
|
||||
* enough root entities in the query
|
||||
*/
|
||||
<E> JpaRoot<? extends E> getRoot(int position, Class<E> type);
|
||||
|
||||
/**
|
||||
* Get a {@linkplain Root query root} element with the given alias
|
||||
* and the given type.
|
||||
*
|
||||
* @param alias the identification variable of the root element
|
||||
* @param type the type of the root entity
|
||||
*
|
||||
* @throws IllegalArgumentException if the root entity with the
|
||||
* given alias is not of the given type, or if there is
|
||||
* no root entities with the given alias
|
||||
*/
|
||||
<E> JpaRoot<? extends E> getRoot(String alias, Class<E> type);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
|
|
@ -66,9 +66,9 @@ public interface JpaQueryStructure<T> extends JpaQueryPart<T> {
|
|||
|
||||
List<? extends JpaExpression<?>> getGroupingExpressions();
|
||||
|
||||
JpaQueryStructure<T> setGroupingExpressions(List<? extends JpaExpression<?>> grouping);
|
||||
JpaQueryStructure<T> setGroupingExpressions(List<? extends Expression<?>> grouping);
|
||||
|
||||
JpaQueryStructure<T> setGroupingExpressions(JpaExpression<?>... grouping);
|
||||
JpaQueryStructure<T> setGroupingExpressions(Expression<?>... grouping);
|
||||
|
||||
JpaPredicate getGroupRestriction();
|
||||
|
||||
|
|
|
@ -908,19 +908,19 @@ public interface NodeBuilder extends HibernateCriteriaBuilder, BindingContext {
|
|||
SqmSelectStatement<Tuple> createTupleQuery();
|
||||
|
||||
@Override
|
||||
<Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, Selection<?>[] selections);
|
||||
<Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, Selection<?>... selections);
|
||||
|
||||
@Override
|
||||
<Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, List<? extends JpaSelection<?>> arguments);
|
||||
|
||||
@Override
|
||||
JpaCompoundSelection<Tuple> tuple(Selection<?>[] selections);
|
||||
JpaCompoundSelection<Tuple> tuple(Selection<?>... selections);
|
||||
|
||||
@Override
|
||||
JpaCompoundSelection<Tuple> tuple(List<Selection<?>> selections);
|
||||
|
||||
@Override
|
||||
JpaCompoundSelection<Object[]> array(Selection<?>[] selections);
|
||||
JpaCompoundSelection<Object[]> array(Selection<?>... selections);
|
||||
|
||||
@Override
|
||||
JpaCompoundSelection<Object[]> array(List<Selection<?>> selections);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.graph.spi.AppliedGraph;
|
||||
|
@ -150,13 +149,7 @@ abstract class AbstractSqmSelectionQuery<R> extends AbstractSelectionQuery<R> {
|
|||
@Override
|
||||
public SelectionQuery<R> addRestriction(Restriction<? super R> restriction) {
|
||||
final SqmSelectStatement<R> selectStatement = getSqmSelectStatement().copy( noParamCopyContext() );
|
||||
final Root<?> firstRoot = selectStatement.getRootList().get( 0 );
|
||||
if ( !getExpectedResultType().isAssignableFrom( firstRoot.getJavaType() ) ) {
|
||||
throw new IllegalStateException("First root entity of the query did not have the query result type");
|
||||
}
|
||||
@SuppressWarnings("unchecked") // safe, we just checked
|
||||
final Root<? extends R> root = (Root<? extends R>) firstRoot;
|
||||
restriction.apply( selectStatement, root );
|
||||
restriction.apply( selectStatement, selectStatement.<R>getRoot( 0, getExpectedResultType() ) );
|
||||
// TODO: when the QueryInterpretationCache can handle caching criteria queries,
|
||||
// simply cache the new SQM as if it were a criteria query, and remove this:
|
||||
getQueryOptions().setQueryPlanCachingEnabled( false );
|
||||
|
|
|
@ -111,7 +111,7 @@ public class KeyBasedPagination {
|
|||
return builder.construct( resultClass, asList( selected, builder.construct(List.class, newItems ) ) );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static <C extends Comparable<? super C>> SqmPredicate keyPredicate(
|
||||
Expression<? extends C> key, C keyValue, SortDirection direction,
|
||||
List<SqmPath<?>> previousKeys, List<Comparable<?>> keyValues,
|
||||
|
|
|
@ -40,7 +40,6 @@ import org.hibernate.internal.CoreLogging;
|
|||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.SessionFactoryRegistry;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.jpa.spi.JpaCompliance;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
|
@ -167,6 +166,7 @@ import jakarta.persistence.metamodel.Bindable;
|
|||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.determineProperSizing;
|
||||
import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType;
|
||||
import static org.hibernate.query.sqm.TrimSpec.fromCriteriaTrimSpec;
|
||||
|
||||
|
@ -872,7 +872,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JpaCompoundSelection<Tuple> tuple(Selection<?>[] selections) {
|
||||
public JpaCompoundSelection<Tuple> tuple(Selection<?>... selections) {
|
||||
return tuple( Arrays.asList( selections ) );
|
||||
}
|
||||
|
||||
|
@ -916,62 +916,69 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public JpaCompoundSelection<Object[]> array(Selection<?>[] selections) {
|
||||
return array( Arrays.asList( selections ) );
|
||||
public JpaCompoundSelection<Object[]> array(Selection<?>... selections) {
|
||||
return array( Object[].class,
|
||||
Arrays.stream( selections ).map( selection -> (SqmSelectableNode<?>) selection ).toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaCompoundSelection<Object[]> array(List<Selection<?>> selections) {
|
||||
//noinspection unchecked,rawtypes
|
||||
return array( Object[].class, (List) selections );
|
||||
return arrayInternal( Object[].class,
|
||||
selections.stream().map( selection -> (SqmSelectableNode<?>) selection ).toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, Selection<?>[] selections) {
|
||||
//noinspection unchecked
|
||||
return array( resultClass, (List<SqmSelectableNode<?>>) (List<?>) Arrays.asList( selections ) );
|
||||
public <Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, Selection<?>... selections) {
|
||||
return arrayInternal( resultClass,
|
||||
Arrays.stream( selections ).map( selection -> (SqmSelectableNode<?>) selection ).toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y> JpaCompoundSelection<Y> array(Class<Y> resultClass, List<? extends JpaSelection<?>> selections) {
|
||||
//noinspection rawtypes,unchecked
|
||||
checkMultiselect( (List) selections );
|
||||
return arrayInternal( resultClass,
|
||||
selections.stream().map( selection -> (SqmSelectableNode<?>) selection ).toList() );
|
||||
}
|
||||
|
||||
public <Y> JpaCompoundSelection<Y> arrayInternal(Class<Y> resultClass, List<? extends SqmSelectableNode<?>> selections) {
|
||||
checkMultiselect( selections );
|
||||
final JavaType<Y> javaType = getTypeConfiguration().getJavaTypeRegistry().getDescriptor( resultClass );
|
||||
//noinspection unchecked
|
||||
return new SqmJpaCompoundSelection<>( (List<SqmSelectableNode<?>>) selections, javaType, this );
|
||||
return new SqmJpaCompoundSelection<>( selections, javaType, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, Selection<?>[] arguments) {
|
||||
//noinspection unchecked
|
||||
return construct( resultClass, (List<JpaSelection<?>>) (List<?>) Arrays.asList( arguments ) );
|
||||
public <Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, Selection<?>... arguments) {
|
||||
return constructInternal( resultClass,
|
||||
Arrays.stream( arguments ).map( arg -> (SqmSelectableNode<?>) arg ).toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y> JpaCompoundSelection<Y> construct(Class<Y> resultClass, List<? extends JpaSelection<?>> arguments) {
|
||||
//noinspection unchecked,rawtypes
|
||||
checkMultiselect( (List) arguments );
|
||||
final SqmDynamicInstantiation<Y> instantiation;
|
||||
return constructInternal( resultClass,
|
||||
arguments.stream().map( arg -> (SqmSelectableNode<?>) arg ).toList() );
|
||||
}
|
||||
|
||||
private <Y> JpaCompoundSelection<Y> constructInternal(Class<Y> resultClass, List<? extends SqmSelectableNode<?>> arguments) {
|
||||
checkMultiselect( arguments );
|
||||
final SqmDynamicInstantiation<Y> instantiation = createInstantiation( resultClass );
|
||||
for ( SqmSelectableNode<?> argument : arguments ) {
|
||||
final SqmDynamicInstantiationArgument<?> arg =
|
||||
new SqmDynamicInstantiationArgument<>( argument, argument.getAlias(), this );
|
||||
instantiation.addArgument( arg );
|
||||
}
|
||||
return instantiation;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <Y> SqmDynamicInstantiation<Y> createInstantiation(Class<Y> resultClass) {
|
||||
if ( List.class.equals( resultClass ) ) {
|
||||
//noinspection unchecked
|
||||
instantiation = (SqmDynamicInstantiation<Y>) SqmDynamicInstantiation.forListInstantiation( this );
|
||||
return (SqmDynamicInstantiation<Y>) SqmDynamicInstantiation.forListInstantiation( this );
|
||||
}
|
||||
else if ( Map.class.equals( resultClass ) ) {
|
||||
//noinspection unchecked
|
||||
instantiation = (SqmDynamicInstantiation<Y>) SqmDynamicInstantiation.forMapInstantiation( this );
|
||||
return (SqmDynamicInstantiation<Y>) SqmDynamicInstantiation.forMapInstantiation( this );
|
||||
}
|
||||
else {
|
||||
instantiation = SqmDynamicInstantiation.forClassInstantiation( resultClass, this );
|
||||
return SqmDynamicInstantiation.forClassInstantiation( resultClass, this );
|
||||
}
|
||||
|
||||
for ( Selection<?> argument : arguments ) {
|
||||
final SqmSelectableNode<?> arg = (SqmSelectableNode<?>) argument;
|
||||
instantiation.addArgument(
|
||||
new SqmDynamicInstantiationArgument<>( arg, argument.getAlias(), this )
|
||||
);
|
||||
}
|
||||
|
||||
return instantiation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -985,8 +992,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, Serializable {
|
|||
* <i>"An argument to the multiselect method must not be a tuple-
|
||||
* or array-valued compound selection item."</i>
|
||||
*/
|
||||
void checkMultiselect(List<Selection<?>> selections) {
|
||||
final HashSet<String> aliases = new HashSet<>( CollectionHelper.determineProperSizing( selections.size() ) );
|
||||
void checkMultiselect(List<? extends Selection<?>> selections) {
|
||||
final HashSet<String> aliases = new HashSet<>( determineProperSizing( selections.size() ) );
|
||||
|
||||
for ( Selection<?> it : selections ) {
|
||||
final JpaSelection<?> selection = (JpaSelection<?>) it;
|
||||
|
|
|
@ -2437,7 +2437,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
offset = -subResult - i;
|
||||
}
|
||||
else if ( selectableNode instanceof SqmJpaCompoundSelection<?> compoundSelection ) {
|
||||
final List<SqmSelectableNode<?>> selectionItems = compoundSelection.getSelectionItems();
|
||||
final List<? extends SqmSelectableNode<?>> selectionItems = compoundSelection.getSelectionItems();
|
||||
for ( int j = 0; j < selectionItems.size(); j++ ) {
|
||||
if ( selectionItems.get( j ) == node ) {
|
||||
return offset + i + j;
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.hibernate.query.sqm.tree.from;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -14,6 +13,9 @@ import org.hibernate.internal.util.collections.CollectionHelper;
|
|||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
|
||||
/**
|
||||
* Contract representing a from clause.
|
||||
* <p>
|
||||
|
@ -50,7 +52,7 @@ public class SqmFromClause implements Serializable {
|
|||
* mutate the roots
|
||||
*/
|
||||
public List<SqmRoot<?>> getRoots() {
|
||||
return domainRoots == null ? Collections.emptyList() : Collections.unmodifiableList( domainRoots );
|
||||
return domainRoots == null ? emptyList() : unmodifiableList( domainRoots );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.tree.select;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
@ -12,6 +11,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.query.criteria.JpaCteCriteria;
|
||||
import org.hibernate.query.criteria.JpaFunctionRoot;
|
||||
|
@ -40,11 +40,12 @@ import jakarta.persistence.criteria.Subquery;
|
|||
import jakarta.persistence.metamodel.EntityType;
|
||||
|
||||
import static java.lang.Character.isAlphabetic;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class AbstractSqmSelectQuery<T>
|
||||
extends AbstractSqmNode
|
||||
implements SqmSelectQuery<T> {
|
||||
|
@ -110,7 +111,7 @@ public abstract class AbstractSqmSelectQuery<T>
|
|||
return cteStatements.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override @SuppressWarnings("unchecked")
|
||||
public <X> JpaCteCriteria<X> getCteCriteria(String cteName) {
|
||||
return (JpaCteCriteria<X>) cteStatements.get( cteName );
|
||||
}
|
||||
|
@ -222,14 +223,54 @@ public abstract class AbstractSqmSelectQuery<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Set<Root<?>> getRoots() {
|
||||
return (Set) getQuerySpec().getRoots();
|
||||
return unmodifiableSet( getQuerySpec().getRoots() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<Root<?>> getRootList() {
|
||||
return (List) getQuerySpec().getRootList();
|
||||
/**
|
||||
* @see org.hibernate.query.criteria.JpaCriteriaQuery#getRootList()
|
||||
*/
|
||||
public List<? extends JpaRoot<?>> getRootList() {
|
||||
return getQuerySpec().getRootList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.query.criteria.JpaCriteriaQuery#getRoot(int, Class)
|
||||
*/
|
||||
public <E> JpaRoot<? extends E> getRoot(int position, Class<E> type) {
|
||||
final List<SqmRoot<?>> rootList = getQuerySpec().getRootList();
|
||||
if ( rootList.size() <= position ) {
|
||||
throw new IllegalArgumentException( "Not enough root entities" );
|
||||
}
|
||||
return castRoot( rootList.get( position ), type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.query.criteria.JpaCriteriaQuery#getRoot(String, Class)
|
||||
*/
|
||||
public <E> JpaRoot<? extends E> getRoot(String alias, Class<E> type) {
|
||||
final List<SqmRoot<?>> rootList = getQuerySpec().getRootList();
|
||||
for ( SqmRoot<?> root : rootList ) {
|
||||
final String rootAlias = root.getAlias();
|
||||
if ( rootAlias != null && rootAlias.equals( alias ) ) {
|
||||
return castRoot( root, type );
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "No root entity with alias " + alias );
|
||||
}
|
||||
|
||||
private static <E> JpaRoot<? extends E> castRoot(JpaRoot<?> root, Class<E> type) {
|
||||
final Class<?> rootEntityType = root.getJavaType();
|
||||
if ( rootEntityType == null ) {
|
||||
throw new AssertionFailure( "Java type of root entity was null" );
|
||||
}
|
||||
if ( !type.isAssignableFrom( rootEntityType ) ) {
|
||||
throw new IllegalArgumentException( "Root entity of type '" + rootEntityType.getTypeName()
|
||||
+ "' did not have the given type '" + type.getTypeName() + "'");
|
||||
}
|
||||
@SuppressWarnings("unchecked") // safe, we just checked
|
||||
final JpaRoot<? extends E> result = (JpaRoot<? extends E>) root;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -329,20 +370,19 @@ public abstract class AbstractSqmSelectQuery<T>
|
|||
// Grouping
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public List<Expression<?>> getGroupList() {
|
||||
return (List) getQuerySpec().getGroupingExpressions();
|
||||
return unmodifiableList( getQuerySpec().getGroupingExpressions() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmSelectQuery<T> groupBy(Expression<?>... expressions) {
|
||||
return groupBy( Arrays.asList( expressions ) );
|
||||
getQuerySpec().setGroupingExpressions( List.of( expressions ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public SqmSelectQuery<T> groupBy(List<Expression<?>> grouping) {
|
||||
getQuerySpec().setGroupingExpressions( (List) grouping );
|
||||
getQuerySpec().setGroupingExpressions( grouping );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -363,35 +403,6 @@ public abstract class AbstractSqmSelectQuery<T>
|
|||
return this;
|
||||
}
|
||||
|
||||
//
|
||||
// // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// // Limit
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public <X> ExpressionImplementor<X> getLimit() {
|
||||
// return limit;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public C setLimit(JpaExpression<?> limit) {
|
||||
// this.limit = (ExpressionImplementor) limit;
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public <X> ExpressionImplementor<X> getOffset() {
|
||||
// return offset;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public C setOffset(JpaExpression offset) {
|
||||
// this.offset = (ExpressionImplementor) offset;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
if ( !cteStatements.isEmpty() ) {
|
||||
sb.append( "with " );
|
||||
|
@ -404,35 +415,28 @@ public abstract class AbstractSqmSelectQuery<T>
|
|||
sqmQueryPart.appendHqlString( sb );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Selection<? extends T> getResultSelection(Selection<?>[] selections) {
|
||||
final Selection<? extends T> resultSelection;
|
||||
Class<T> resultType = getResultType();
|
||||
final Class<T> resultType = getResultType();
|
||||
if ( resultType == null || resultType == Object.class ) {
|
||||
switch ( selections.length ) {
|
||||
case 0: {
|
||||
throw new IllegalArgumentException(
|
||||
"empty selections passed to criteria query typed as Object"
|
||||
);
|
||||
}
|
||||
case 1: {
|
||||
resultSelection = ( Selection<? extends T> ) selections[0];
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().array( selections );
|
||||
}
|
||||
case 0:
|
||||
throw new IllegalArgumentException( "Empty selections passed to criteria query typed as Object" );
|
||||
case 1:
|
||||
return (Selection<? extends T>) selections[0];
|
||||
default:
|
||||
return (Selection<? extends T>) nodeBuilder().array( selections );
|
||||
}
|
||||
}
|
||||
else if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().tuple( selections );
|
||||
return (Selection<? extends T>) nodeBuilder().tuple( selections );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
resultSelection = nodeBuilder().array( resultType, selections );
|
||||
return nodeBuilder().array( resultType, selections );
|
||||
}
|
||||
else {
|
||||
resultSelection = nodeBuilder().construct( resultType, selections );
|
||||
return nodeBuilder().construct( resultType, selections );
|
||||
}
|
||||
return resultSelection;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,11 +56,11 @@ public class SqmJpaCompoundSelection<T>
|
|||
// can support using tuples in other clauses. If we keep the Easy way is to add a switch in creation of these
|
||||
// whether `SqmJpaCompoundSelection` or `SqmTuple` is used based on `JpaCompliance#isJpaQueryComplianceEnabled`
|
||||
|
||||
private final List<SqmSelectableNode<?>> selectableNodes;
|
||||
private final List<? extends SqmSelectableNode<?>> selectableNodes;
|
||||
private final JavaType<T> javaType;
|
||||
|
||||
public SqmJpaCompoundSelection(
|
||||
List<SqmSelectableNode<?>> selectableNodes,
|
||||
List<? extends SqmSelectableNode<?>> selectableNodes,
|
||||
JavaType<T> javaType,
|
||||
NodeBuilder criteriaBuilder) {
|
||||
super( null, criteriaBuilder );
|
||||
|
@ -111,7 +111,7 @@ public class SqmJpaCompoundSelection<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<SqmSelectableNode<?>> getSelectionItems() {
|
||||
public List<? extends SqmSelectableNode<?>> getSelectionItems() {
|
||||
return selectableNodes;
|
||||
}
|
||||
|
||||
|
|
|
@ -395,10 +395,10 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupingExpressions(List<? extends JpaExpression<?>> groupExpressions) {
|
||||
public SqmQuerySpec<T> setGroupingExpressions(List<? extends Expression<?>> groupExpressions) {
|
||||
this.hasPositionalGroupItem = false;
|
||||
this.groupByClauseExpressions = new ArrayList<>( groupExpressions.size() );
|
||||
for ( JpaExpression<?> groupExpression : groupExpressions ) {
|
||||
for ( Expression<?> groupExpression : groupExpressions ) {
|
||||
if ( groupExpression instanceof SqmAliasedNodeRef ) {
|
||||
this.hasPositionalGroupItem = true;
|
||||
}
|
||||
|
@ -408,10 +408,10 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySpec<T> setGroupingExpressions(JpaExpression<?>... groupExpressions) {
|
||||
public SqmQuerySpec<T> setGroupingExpressions(Expression<?>... groupExpressions) {
|
||||
this.hasPositionalGroupItem = false;
|
||||
this.groupByClauseExpressions = new ArrayList<>( groupExpressions.length );
|
||||
for ( JpaExpression<?> groupExpression : groupExpressions ) {
|
||||
for ( Expression<?> groupExpression : groupExpressions ) {
|
||||
if ( groupExpression instanceof SqmAliasedNodeRef ) {
|
||||
this.hasPositionalGroupItem = true;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import jakarta.persistence.criteria.Selection;
|
|||
import jakarta.persistence.metamodel.EntityType;
|
||||
|
||||
import static java.util.Collections.emptySet;
|
||||
import static java.util.Collections.unmodifiableList;
|
||||
import static java.util.Collections.unmodifiableSet;
|
||||
import static org.hibernate.query.sqm.spi.SqmCreationHelper.combinePredicates;
|
||||
import static org.hibernate.query.sqm.SqmQuerySource.CRITERIA;
|
||||
|
@ -166,6 +167,11 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T>
|
|||
return nodeBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Order> getOrderList() {
|
||||
return unmodifiableList( getQueryPart().getSortSpecifications() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmQuerySource getQuerySource() {
|
||||
return querySource;
|
||||
|
@ -368,33 +374,26 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T>
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Selection<? extends T> getResultSelection(List<?> selectionList) {
|
||||
private Selection<? extends T> getResultSelection(List<?> selections) {
|
||||
final Class<T> resultType = getResultType();
|
||||
//noinspection rawtypes
|
||||
final List<? extends JpaSelection<?>> selections = (List) selectionList;
|
||||
if ( resultType == null || resultType == Object.class ) {
|
||||
switch ( selectionList.size() ) {
|
||||
case 0: {
|
||||
throw new IllegalArgumentException(
|
||||
"empty selections passed to criteria query typed as Object"
|
||||
);
|
||||
}
|
||||
case 1: {
|
||||
return (Selection<? extends T>) selectionList.get( 0 );
|
||||
}
|
||||
default: {
|
||||
return (Selection<? extends T>) nodeBuilder().array( (List) selectionList );
|
||||
}
|
||||
switch ( selections.size() ) {
|
||||
case 0:
|
||||
throw new IllegalArgumentException( "Empty selections passed to criteria query typed as Object" );
|
||||
case 1:
|
||||
return (Selection<? extends T>) selections.get( 0 );
|
||||
default:
|
||||
return (Selection<? extends T>) nodeBuilder().array( (List<Selection<?>>) selections );
|
||||
}
|
||||
}
|
||||
else if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
return (Selection<? extends T>) nodeBuilder().tuple( (List) selectionList );
|
||||
return (Selection<? extends T>) nodeBuilder().tuple( (List<Selection<?>>) selections );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
return nodeBuilder().array( resultType, selections );
|
||||
return nodeBuilder().array( resultType, (List<? extends JpaSelection<?>>) selections );
|
||||
}
|
||||
else {
|
||||
return nodeBuilder().construct( resultType, selections );
|
||||
return nodeBuilder().construct( resultType, (List<? extends JpaSelection<?>>) selections );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,12 @@ public class CriteriaDefinitionTest {
|
|||
orderBy(asc(message.get("text")));
|
||||
}};
|
||||
|
||||
var query3prime = new CriteriaDefinition<>(factory, Message.class, "from Msg") {{
|
||||
var message = getRoot( 0, Message.class );
|
||||
where(ilike(message.get("text"), "%e%"));
|
||||
orderBy(asc(message.get("text")));
|
||||
}};
|
||||
|
||||
var query4 = new CriteriaDefinition<>(factory, Message.class) {{
|
||||
var message = from(Message.class);
|
||||
restrict(like(message.get("text"), "hell%"));
|
||||
|
@ -77,6 +83,9 @@ public class CriteriaDefinitionTest {
|
|||
var messages = session.createSelectionQuery(query3).getResultList();
|
||||
assertEquals(2,messages.size());
|
||||
|
||||
var messagesPrime = session.createSelectionQuery(query3prime).getResultList();
|
||||
assertEquals(2,messagesPrime.size());
|
||||
|
||||
var msg = session.createSelectionQuery(query4).getSingleResult();
|
||||
assertNotNull(msg);
|
||||
assertEquals(1L,msg.id);
|
||||
|
|
|
@ -8,7 +8,6 @@ import jakarta.persistence.Entity;
|
|||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Version;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
@ -251,11 +250,22 @@ public class RestrictionTest {
|
|||
} );
|
||||
scope.inSession( session -> {
|
||||
var query = session.getCriteriaBuilder().createQuery("select title from Book", String.class);
|
||||
var root = (Root<Book>) query.getRootList().get(0);
|
||||
var root = query.getRoot(0, Book.class);
|
||||
equal( isbn, "9781932394153" ).apply( query, root );
|
||||
List<String> titles = session.createQuery( query ).getResultList();
|
||||
assertEquals( 1, titles.size() );
|
||||
} );
|
||||
|
||||
var builder = scope.getSessionFactory().getCriteriaBuilder();
|
||||
var query = builder.createQuery("from Book where pages > 200", Book.class);
|
||||
var root = query.getRoot(0, Book.class);
|
||||
like( title, "Hibernate%" ).apply( query, root );
|
||||
query.orderBy(builder.asc(root.get(title)), builder.desc(root.get(isbn)));
|
||||
scope.inSession( session -> {
|
||||
List<Book> matchingBooks = session.createSelectionQuery(query).getResultList();
|
||||
assertEquals( 1, matchingBooks.size() );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue