HHH-16814 add HibernateCriteriaBuilder.createQuery(hql, resultType)

- also add missing createCriteriaInsertValues() method
- also add some missing @Incubating annotations
This commit is contained in:
Gavin King 2023-06-27 10:35:56 +02:00
parent 7cbc0e01fe
commit da7f169371
9 changed files with 143 additions and 2 deletions

View File

@ -44,7 +44,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression;
*
* @author Steve Ebersole
*/
@Incubating
public interface HibernateCriteriaBuilder extends CriteriaBuilder {
<X, T> JpaExpression<X> cast(JpaExpression<T> expression, Class<X> castTargetJavaType);
@ -75,8 +75,22 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
@Override
<T> JpaCriteriaDelete<T> createCriteriaDelete(Class<T> targetEntity);
<T> JpaCriteriaInsertValues<T> createCriteriaInsertValues(Class<T> targetEntity);
<T> JpaCriteriaInsertSelect<T> createCriteriaInsertSelect(Class<T> targetEntity);
/**
* Transform the given HQL {@code select} query to an equivalent criteria query.
*
* @param hql The HQL {@code select} query
* @param resultClass The result type of the query
*
* @return The equivalent criteria query
*
* @since 6.3
*/
<T> JpaCriteriaQuery<T> createQuery(String hql, Class<T> resultClass);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set operation

View File

@ -0,0 +1,34 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.criteria;
import org.hibernate.Incubating;
/**
* A representation of SqmInsertValuesStatement at the
* {@link org.hibernate.query.criteria} level, even though JPA does
* not define support for insert-values criteria.
*
* @see org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement
*
* @apiNote Incubating mainly for 2 purposes:<ul>
* <li>
* to decide how to handle the typing for the "selection part". Should it
* be {@code <T>} or {@code <X>}. For the time being we expose it as
* {@code <T>} because that is what was done (without intention) originally,
* and it is the easiest form to validate
* </li>
* <li>
* Would be better to expose non-SQM contracts here
* </li>
* </ul>
*
* @author Gavin King
*/
@Incubating
public interface JpaCriteriaInsertValues<T> extends JpaManipulationCriteria<T> {
}

View File

@ -10,4 +10,7 @@
*
* @see org.hibernate.query.criteria.HibernateCriteriaBuilder
*/
@Incubating
package org.hibernate.query.criteria;
import org.hibernate.Incubating;

View File

@ -28,6 +28,7 @@ import org.hibernate.query.criteria.JpaCollectionJoin;
import org.hibernate.query.criteria.JpaCompoundSelection;
import org.hibernate.query.criteria.JpaCriteriaDelete;
import org.hibernate.query.criteria.JpaCriteriaInsertSelect;
import org.hibernate.query.criteria.JpaCriteriaInsertValues;
import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaCriteriaUpdate;
import org.hibernate.query.criteria.JpaCteCriteriaAttribute;
@ -110,6 +111,11 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
return criteriaBuilder.createQuery( resultClass );
}
@Override
public <T> JpaCriteriaQuery<T> createQuery(String hql, Class<T> resultClass) {
return criteriaBuilder.createQuery( hql, resultClass );
}
@Override
public JpaCriteriaQuery<Tuple> createTupleQuery() {
return criteriaBuilder.createTupleQuery();
@ -125,6 +131,11 @@ public class HibernateCriteriaBuilderDelegate implements HibernateCriteriaBuilde
return criteriaBuilder.createCriteriaDelete( targetEntity );
}
@Override
public <T> JpaCriteriaInsertValues<T> createCriteriaInsertValues(Class<T> targetEntity) {
return criteriaBuilder.createCriteriaInsertValues( targetEntity );
}
@Override
public <T> JpaCriteriaInsertSelect<T> createCriteriaInsertSelect(Class<T> targetEntity) {
return criteriaBuilder.createCriteriaInsertSelect( targetEntity );

View File

@ -9,4 +9,7 @@
* SPI for extending {@link org.hibernate.query.criteria.HibernateCriteriaBuilder}
* with additional functionality by registering a {@link org.hibernate.service.Service}.
*/
@Incubating
package org.hibernate.query.criteria.spi;
import org.hibernate.Incubating;

View File

@ -22,6 +22,7 @@ import org.hibernate.metamodel.model.domain.JpaMetamodel;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
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.JpaParameterExpression;
import org.hibernate.query.criteria.JpaSearchedCase;
@ -41,6 +42,7 @@ import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.predicate.SqmInPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
@ -100,6 +102,9 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
@Override
<T> SqmSelectStatement<T> createQuery(Class<T> resultClass);
@Override
<T> SqmSelectStatement<T> createQuery(String hql, Class<T> resultClass);
@Override
SqmSelectStatement<Tuple> createTupleQuery();
@ -127,6 +132,9 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
@Override
<T> SqmDeleteStatement<T> createCriteriaDelete(Class<T> targetEntity);
@Override
<T> SqmInsertValuesStatement<T> createCriteriaInsertValues(Class<T> targetEntity);
@Override
<T> SqmInsertSelectStatement<T> createCriteriaInsertSelect(Class<T> targetEntity);

View File

@ -86,6 +86,7 @@ import org.hibernate.query.sqm.produce.function.FunctionArgumentException;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.spi.SqmCreationContext;
import org.hibernate.query.sqm.tree.SqmQuery;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.cte.SqmCteTableColumn;
@ -125,6 +126,7 @@ import org.hibernate.query.sqm.tree.expression.SqmWindowFrame;
import org.hibernate.query.sqm.tree.expression.ValueBindJpaCriteriaParameter;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -349,6 +351,19 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
return new SqmSelectStatement<>( resultClass, this );
}
@Override
public <T> SqmSelectStatement<T> createQuery(String hql, Class<T> resultClass) {
final SqmStatement<T> statement =
sessionFactory.get().getQueryEngine().getHqlTranslator()
.translate( hql, resultClass );
if ( statement instanceof SqmSelectStatement ) {
return (SqmSelectStatement<T>) statement;
}
else {
throw new IllegalArgumentException("Not a 'select' statement");
}
}
@Override
public SqmSelectStatement<Tuple> createTupleQuery() {
return new SqmSelectStatement<>( Tuple.class, this );
@ -364,6 +379,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
return new SqmDeleteStatement<>( targetEntity, SqmQuerySource.CRITERIA, this );
}
@Override
public <T> SqmInsertValuesStatement<T> createCriteriaInsertValues(Class<T> targetEntity) {
return new SqmInsertValuesStatement<>( targetEntity, this );
}
@Override
public <T> SqmInsertSelectStatement<T> createCriteriaInsertSelect(Class<T> targetEntity) {
return new SqmInsertSelectStatement<>( targetEntity, this );

View File

@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.query.criteria.JpaCriteriaInsertValues;
import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
@ -25,7 +26,7 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
/**
* @author Gavin King
*/
public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> {
public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> implements JpaCriteriaInsertValues<T> {
private final List<SqmValues> valuesList;
public SqmInsertValuesStatement(SqmRoot<T> targetRoot, NodeBuilder nodeBuilder) {
@ -33,6 +34,20 @@ public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> {
this.valuesList = new ArrayList<>();
}
public SqmInsertValuesStatement(Class<T> targetEntity, NodeBuilder nodeBuilder) {
super(
new SqmRoot<>(
nodeBuilder.getDomainModel().entity( targetEntity ),
null,
false,
nodeBuilder
),
SqmQuerySource.CRITERIA,
nodeBuilder
);
this.valuesList = new ArrayList<>();
}
private SqmInsertValuesStatement(
NodeBuilder builder,
SqmQuerySource querySource,

View File

@ -0,0 +1,33 @@
package org.hibernate.orm.test.jpa.criteria.query;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SessionFactory
@DomainModel(annotatedClasses = CriteriaFromHqlTest.Message.class)
public class CriteriaFromHqlTest {
@Test void test(SessionFactoryScope scope) {
scope.inSession( s -> {
JpaCriteriaQuery<Object[]> query =
s.getFactory().getCriteriaBuilder()
.createQuery("select id, text from Msg order by id", Object[].class);
assertEquals(2, query.getSelection().getSelectionItems().size());
assertEquals(1, query.getOrderList().size());
assertEquals(1, query.getRoots().size());
s.createSelectionQuery(query).getResultList();
});
}
@Entity(name="Msg")
static class Message {
@Id
Long id;
String text;
}
}