HHH-18517 allow composition of CriteriaDefinitions

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-08-23 23:09:46 +02:00
parent 4fd9a4f0df
commit d306aadb9d
3 changed files with 66 additions and 3 deletions

View File

@ -18,6 +18,8 @@ import org.hibernate.query.QueryProducer;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.criteria.spi.HibernateCriteriaBuilderDelegate;
import org.hibernate.query.sqm.FetchClauseType;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import java.util.Collection;
import java.util.List;
@ -85,6 +87,28 @@ import java.util.function.Function;
* ...
* });
* </pre>
* A {@code CriteriaDefinition} may be used to modify another {@code CriteriaDefinition}:
* <pre>
* var bookFilter
* = new CriteriaDefinition&lt;&gt;(sessionFactory, Book.class) {{
* where(like(from(Book.class).get(Book_.title), "%Hibernate%"));
* }};
* long count
* = new CriteriaDefinition&lt;&gt;(bookFilter, Long.class) {{
* select(count());
* }}
* .createSelectionQuery(session)
* .getSingleResult();
* var books =
* = new CriteriaDefinition&lt;&gt;(bookFilter) {{
* var book = (Root&lt;Book&gt;) getRootList().get(0);
* book.fetch(Book_.authors);
* orderBy(desc(book.get(Book_.publicationDate)), asc(book.get(Book_.isbn)));
* }}
* .createSelectionQuery(session)
* .setMaxResults(10)
* .getResultList();
* </pre>
*
* @param <R> the query result type
*
@ -99,6 +123,37 @@ public abstract class CriteriaDefinition<R>
private final JpaCriteriaQuery<R> query;
/**
* Construct a new {@code CriteriaDefinition} based on the given
* {@code CriteriaDefinition}, with the same query return type.
*
* @param template the original query
*
* @since 7.0
*/
public CriteriaDefinition(CriteriaDefinition<R> template) {
super( template.getCriteriaBuilder() );
query = ((SqmSelectStatement<R>) template.query)
.copy( SqmCopyContext.simpleContext() );
}
/**
* Construct a new {@code CriteriaDefinition} based on the given
* {@code CriteriaDefinition}. This overload permits changing the
* query return type. It is expected that {@link #select} be called
* to rewrite the selection list.
*
* @param template the original query
* @param resultType the new return type
*
* @since 7.0
*/
public CriteriaDefinition(CriteriaDefinition<?> template, Class<R> resultType) {
super( template.getCriteriaBuilder() );
query = ((SqmSelectStatement<?>) template.query)
.createCopy( SqmCopyContext.simpleContext(), resultType );
}
public CriteriaDefinition(SessionFactory factory, Class<R> resultType) {
super( factory.getCriteriaBuilder() );
query = createQuery( resultType );

View File

@ -13,6 +13,7 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.hibernate.Internal;
import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaSelection;
@ -26,8 +27,6 @@ import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.expression.ValueBindJpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmStar;
import org.hibernate.query.sqm.tree.expression.ValueBindJpaCriteriaParameter;
import org.hibernate.query.sqm.tree.from.SqmFromClause;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.from.SqmRoot;
@ -127,7 +126,8 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
return createCopy( context, getResultType() );
}
private <X> SqmSelectStatement<X> createCopy(SqmCopyContext context, Class<X> resultType) {
@Internal
public <X> SqmSelectStatement<X> createCopy(SqmCopyContext context, Class<X> resultType) {
final Set<SqmParameter<?>> parameters;
if ( this.parameters == null ) {
parameters = null;

View File

@ -54,6 +54,11 @@ public class CriteriaDefinitionTest {
orderBy(asc(message.get("id")));
}};
var query5 = new CriteriaDefinition<>(query4, Long.class) {{
select(count());
orderBy();
}};
scope.inSession(session -> {
var idAndText = session.createSelectionQuery(query1).getSingleResult();
assertNotNull(idAndText);
@ -72,6 +77,9 @@ public class CriteriaDefinitionTest {
assertNotNull(msg);
assertEquals(1L,msg.id);
assertEquals("hello",msg.text);
long count = session.createSelectionQuery(query5).getSingleResult();
assertEquals(1L,count);
});
}