18
18
import jakarta .persistence .EntityManager ;
19
19
import jakarta .persistence .Query ;
20
20
21
+ import java .util .function .Supplier ;
22
+
23
+ import org .apache .commons .logging .Log ;
24
+ import org .apache .commons .logging .LogFactory ;
25
+ import org .springframework .data .domain .Pageable ;
26
+ import org .springframework .data .domain .Sort ;
27
+ import org .springframework .data .jpa .repository .QueryRewriter ;
21
28
import org .springframework .data .repository .query .QueryMethodEvaluationContextProvider ;
22
29
import org .springframework .data .repository .query .ResultProcessor ;
23
30
import org .springframework .data .repository .query .ReturnedType ;
35
42
* @author David Madden
36
43
* @author Mark Paluch
37
44
* @author Diego Krupitza
45
+ * @author Greg Turnquist
38
46
*/
39
47
abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
40
48
49
+ private static final Log LOGGER = LogFactory .getLog (AbstractStringBasedJpaQuery .class );
50
+
41
51
private final DeclaredQuery query ;
42
52
private final DeclaredQuery countQuery ;
43
53
private final QueryMethodEvaluationContextProvider evaluationContextProvider ;
44
54
private final SpelExpressionParser parser ;
45
55
private final QueryParameterSetter .QueryMetadataCache metadataCache = new QueryParameterSetter .QueryMetadataCache ();
56
+ private final Supplier <QueryRewriter > queryRewriterSupplier ;
46
57
47
58
/**
48
59
* Creates a new {@link AbstractStringBasedJpaQuery} from the given {@link JpaQueryMethod}, {@link EntityManager} and
@@ -57,7 +68,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
57
68
*/
58
69
public AbstractStringBasedJpaQuery (JpaQueryMethod method , EntityManager em , String queryString ,
59
70
@ Nullable String countQueryString , QueryMethodEvaluationContextProvider evaluationContextProvider ,
60
- SpelExpressionParser parser ) {
71
+ SpelExpressionParser parser , QueryRewriterProvider queryRewriterProvider ) {
61
72
62
73
super (method , em );
63
74
@@ -74,6 +85,7 @@ public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, Stri
74
85
method .isNativeQuery ());
75
86
76
87
this .parser = parser ;
88
+ this .queryRewriterSupplier = queryRewriterProvider .of (method );
77
89
78
90
Assert .isTrue (method .isNativeQuery () || !query .usesJdbcStyleParameters (),
79
91
"JDBC style parameters (?) are not supported for JPA queries." );
@@ -86,7 +98,8 @@ public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
86
98
.applySorting (accessor .getSort (), query .getAlias ());
87
99
ResultProcessor processor = getQueryMethod ().getResultProcessor ().withDynamicProjection (accessor );
88
100
89
- Query query = createJpaQuery (sortedQueryString , processor .getReturnedType ());
101
+ Query query = createJpaQuery (sortedQueryString , accessor .getSort (), accessor .getPageable (),
102
+ processor .getReturnedType ());
90
103
91
104
QueryParameterSetter .QueryMetadata metadata = metadataCache .getMetadata (sortedQueryString , query );
92
105
@@ -137,18 +150,41 @@ public DeclaredQuery getCountQuery() {
137
150
* Creates an appropriate JPA query from an {@link EntityManager} according to the current {@link AbstractJpaQuery}
138
151
* type.
139
152
*/
140
- protected Query createJpaQuery (String queryString , ReturnedType returnedType ) {
153
+ protected Query createJpaQuery (String queryString , Sort sort , @ Nullable Pageable pageable ,
154
+ ReturnedType returnedType ) {
141
155
142
156
EntityManager em = getEntityManager ();
143
157
144
158
if (this .query .hasConstructorExpression () || this .query .isDefaultProjection ()) {
145
- return em .createQuery (queryString );
159
+ return em .createQuery (potentiallyRewriteQuery ( queryString , sort , pageable ) );
146
160
}
147
161
148
162
Class <?> typeToRead = getTypeToRead (returnedType );
149
163
150
164
return typeToRead == null //
151
- ? em .createQuery (queryString ) //
152
- : em .createQuery (queryString , typeToRead );
165
+ ? em .createQuery (potentiallyRewriteQuery (queryString , sort , pageable )) //
166
+ : em .createQuery (potentiallyRewriteQuery (queryString , sort , pageable ), typeToRead );
167
+ }
168
+
169
+ /**
170
+ * Use the {@link QueryRewriter}, potentially rewrite the query, using relevant {@link Sort} and {@link Pageable}
171
+ * information.
172
+ *
173
+ * @param originalQuery
174
+ * @param sort
175
+ * @param pageable
176
+ * @return
177
+ */
178
+ protected String potentiallyRewriteQuery (String originalQuery , Sort sort , @ Nullable Pageable pageable ) {
179
+
180
+ QueryRewriter queryRewriter = this .queryRewriterSupplier .get ();
181
+
182
+ if (queryRewriter == null ) {
183
+ return originalQuery ;
184
+ }
185
+
186
+ return pageable != null && pageable .isPaged () //
187
+ ? queryRewriter .rewrite (originalQuery , pageable ) //
188
+ : queryRewriter .rewrite (originalQuery , sort );
153
189
}
154
190
}
0 commit comments