Skip to content

Commit 3718329

Browse files
committed
HHH-19364 make a Specification convertible to a CriteriaQuery
1 parent 2eae2d4 commit 3718329

File tree

4 files changed

+61
-5
lines changed

4 files changed

+61
-5
lines changed

hibernate-core/src/main/java/org/hibernate/query/programmatic/QuerySpecification.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
package org.hibernate.query.programmatic;
66

77
import jakarta.persistence.EntityManager;
8+
import jakarta.persistence.criteria.CriteriaBuilder;
9+
import jakarta.persistence.criteria.CommonAbstractCriteria;
810

911
import org.hibernate.Incubating;
1012
import org.hibernate.Session;
@@ -53,6 +55,18 @@ public interface QuerySpecification<T> {
5355
*/
5456
CommonQueryContract createQuery(EntityManager entityManager);
5557

58+
/**
59+
* Build a {@link CommonAbstractCriteria criteria query}
60+
* satisfying this specification, using the given
61+
* {@link CriteriaBuilder}.
62+
* <p>
63+
* If the returned criteria query is mutated, the mutations
64+
* will not be not reflected in this specification.
65+
*
66+
* @return a new criteria query
67+
*/
68+
CommonAbstractCriteria buildCriteriaQuery(CriteriaBuilder builder);
69+
5670
/**
5771
* Validate the query.
5872
*/

hibernate-core/src/main/java/org/hibernate/query/programmatic/SelectionSpecification.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import jakarta.persistence.criteria.CriteriaQuery;
99
import jakarta.persistence.criteria.CriteriaBuilder;
1010
import jakarta.persistence.criteria.Root;
11+
1112
import org.hibernate.Incubating;
1213
import org.hibernate.Session;
1314
import org.hibernate.StatelessSession;
@@ -166,6 +167,18 @@ interface Augmentation<T> {
166167
@Override
167168
SelectionQuery<T> createQuery(EntityManager entityManager);
168169

170+
/**
171+
* Build a {@link CriteriaQuery criteria query}
172+
* satisfying this specification, using the given
173+
* {@link CriteriaBuilder}.
174+
* <p>
175+
* If the returned criteria query is mutated, the mutations
176+
* will not be not reflected in this specification.
177+
*
178+
* @return a new criteria query
179+
*/
180+
CriteriaQuery<T> buildCriteriaQuery(CriteriaBuilder builder);
181+
169182
/**
170183
* Returns a specification reference which can be used to programmatically,
171184
* iteratively build a {@linkplain SelectionQuery} for the given entity type,

hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/MutationSpecificationImpl.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
package org.hibernate.query.programmatic.internal;
66

77
import jakarta.persistence.EntityManager;
8+
import jakarta.persistence.criteria.CriteriaBuilder;
89
import jakarta.persistence.criteria.CriteriaDelete;
910
import jakarta.persistence.criteria.CriteriaUpdate;
11+
import jakarta.persistence.criteria.CommonAbstractCriteria;
12+
1013
import org.hibernate.AssertionFailure;
1114
import org.hibernate.Session;
1215
import org.hibernate.SharedSessionContract;
@@ -18,6 +21,7 @@
1821
import org.hibernate.query.restriction.Restriction;
1922
import org.hibernate.query.spi.HqlInterpretation;
2023
import org.hibernate.query.spi.QueryEngine;
24+
import org.hibernate.query.sqm.NodeBuilder;
2125
import org.hibernate.query.sqm.SqmQuerySource;
2226
import org.hibernate.query.sqm.internal.QuerySqmImpl;
2327
import org.hibernate.query.sqm.internal.SqmUtil;
@@ -95,10 +99,15 @@ public MutationQuery createQuery(StatelessSession session) {
9599

96100
public MutationQuery createQuery(SharedSessionContract session) {
97101
final var sessionImpl = (SharedSessionContractImplementor) session;
102+
final SqmDeleteOrUpdateStatement<T> sqmStatement = build( sessionImpl.getFactory().getQueryEngine() );
103+
return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl );
104+
}
105+
106+
private SqmDeleteOrUpdateStatement<T> build(QueryEngine queryEngine) {
98107
final SqmDeleteOrUpdateStatement<T> sqmStatement;
99108
final SqmRoot<T> mutationTargetRoot;
100109
if ( hql != null ) {
101-
sqmStatement = resolveSqmTree( hql, sessionImpl.getFactory().getQueryEngine() );
110+
sqmStatement = resolveSqmTree( hql, queryEngine );
102111
mutationTargetRoot = resolveSqmRoot( sqmStatement, mutationTarget );
103112
}
104113
else if ( deleteOrUpdateStatement != null ) {
@@ -110,14 +119,20 @@ else if ( deleteOrUpdateStatement != null ) {
110119
throw new AssertionFailure( "No HQL or criteria" );
111120
}
112121
specifications.forEach( consumer -> consumer.accept( sqmStatement, mutationTargetRoot ) );
113-
return new QuerySqmImpl<>( sqmStatement, true, null, sessionImpl );
122+
return sqmStatement;
114123
}
115124

116125
@Override
117126
public MutationQuery createQuery(EntityManager entityManager) {
118127
return createQuery( (SharedSessionContract) entityManager );
119128
}
120129

130+
@Override
131+
public CommonAbstractCriteria buildCriteriaQuery(CriteriaBuilder builder) {
132+
final NodeBuilder nodeBuilder = (NodeBuilder) builder;
133+
return build( nodeBuilder.getQueryEngine() );
134+
}
135+
121136
/**
122137
* Used during construction to parse/interpret the incoming HQL
123138
* and produce the corresponding SQM tree.

hibernate-core/src/main/java/org/hibernate/query/programmatic/internal/SelectionSpecificationImpl.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import jakarta.persistence.EntityManager;
88
import jakarta.persistence.criteria.CriteriaQuery;
9+
import jakarta.persistence.criteria.CriteriaBuilder;
10+
911
import org.hibernate.QueryException;
1012
import org.hibernate.Session;
1113
import org.hibernate.SharedSessionContract;
@@ -19,6 +21,7 @@
1921
import org.hibernate.query.restriction.Restriction;
2022
import org.hibernate.query.spi.HqlInterpretation;
2123
import org.hibernate.query.spi.QueryEngine;
24+
import org.hibernate.query.sqm.NodeBuilder;
2225
import org.hibernate.query.sqm.SqmQuerySource;
2326
import org.hibernate.query.sqm.internal.SqmSelectionQueryImpl;
2427
import org.hibernate.query.sqm.internal.SqmUtil;
@@ -135,33 +138,44 @@ public SelectionQuery<T> createQuery(StatelessSession session) {
135138

136139
public SelectionQuery<T> createQuery(SharedSessionContract session) {
137140
final var sessionImpl = (SharedSessionContractImplementor) session;
141+
final SqmSelectStatement<T> sqmStatement = build( sessionImpl.getFactory().getQueryEngine() );
142+
return new SqmSelectionQueryImpl<>( sqmStatement, true, resultType, sessionImpl );
143+
}
144+
145+
private SqmSelectStatement<T> build(QueryEngine queryEngine) {
138146
final SqmSelectStatement<T> sqmStatement;
139147
final SqmRoot<T> sqmRoot;
140148
if ( hql != null ) {
141-
sqmStatement = resolveSqmTree( hql, resultType, sessionImpl.getFactory().getQueryEngine() );
149+
sqmStatement = resolveSqmTree( hql, resultType, queryEngine );
142150
sqmRoot = extractRoot( sqmStatement, resultType, hql );
143151
}
144152
else if ( criteriaQuery != null ) {
145153
sqmStatement = (SqmSelectStatement<T>) criteriaQuery;
146154
sqmRoot = extractRoot( sqmStatement, resultType, "criteria query" );
147155
}
148156
else {
149-
var builder = sessionImpl.getCriteriaBuilder();
157+
var builder = queryEngine.getCriteriaBuilder();
150158
var query = builder.createQuery( resultType );
151159
var root = query.from( resultType );
152160
query.select( root );
153161
sqmRoot = (SqmRoot<T>) root;
154162
sqmStatement = (SqmSelectStatement<T>) query;
155163
}
156164
specifications.forEach( consumer -> consumer.accept( sqmStatement, sqmRoot ) );
157-
return new SqmSelectionQueryImpl<>( sqmStatement, true, resultType, sessionImpl );
165+
return sqmStatement;
158166
}
159167

160168
@Override
161169
public SelectionQuery<T> createQuery(EntityManager entityManager) {
162170
return createQuery( (SharedSessionContract) entityManager );
163171
}
164172

173+
@Override
174+
public CriteriaQuery<T> buildCriteriaQuery(CriteriaBuilder builder) {
175+
final NodeBuilder nodeBuilder = (NodeBuilder) builder;
176+
return build( nodeBuilder.getQueryEngine() );
177+
}
178+
165179
/**
166180
* Used during construction to parse/interpret the incoming HQL
167181
* and produce the corresponding SQM tree.

0 commit comments

Comments
 (0)