Skip to content

Commit 0ad881d

Browse files
committed
Implement EQL parser.
Implement support for EclipseLink Query Language (EQL), handling the various extensions it offers. See #3170
1 parent 6fcab2a commit 0ad881d

File tree

12 files changed

+6985
-1
lines changed

12 files changed

+6985
-1
lines changed

spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4

+897
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright 2022-2023 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jpa.repository.query;
17+
18+
import java.util.List;
19+
20+
import org.antlr.v4.runtime.CharStreams;
21+
import org.antlr.v4.runtime.CommonTokenStream;
22+
import org.antlr.v4.runtime.ParserRuleContext;
23+
import org.springframework.data.domain.Sort;
24+
import org.springframework.lang.Nullable;
25+
26+
/**
27+
* Implements the {@code EQL} parsing operations of a {@link JpaQueryParserSupport} using the ANTLR-generated
28+
* {@link EqlParser} and {@link EqlQueryTransformer}.
29+
*
30+
* @author Greg Turnquist
31+
* @since 3.2
32+
*/
33+
class EqlQueryParser extends JpaQueryParserSupport {
34+
35+
EqlQueryParser(String query) {
36+
super(query);
37+
}
38+
39+
/**
40+
* Convenience method to parse a EQL query. Will throw a {@link BadJpqlGrammarException} if the query is invalid.
41+
*
42+
* @param query
43+
* @return a parsed query, ready for postprocessing
44+
*/
45+
public static ParserRuleContext parseQuery(String query) {
46+
47+
EqlLexer lexer = new EqlLexer(CharStreams.fromString(query));
48+
EqlParser parser = new EqlParser(new CommonTokenStream(lexer));
49+
50+
configureParser(query, lexer, parser);
51+
52+
return parser.start();
53+
}
54+
55+
/**
56+
* Parse the query using {@link #parseQuery(String)}.
57+
*
58+
* @return a parsed query
59+
*/
60+
@Override
61+
protected ParserRuleContext parse(String query) {
62+
return parseQuery(query);
63+
}
64+
65+
/**
66+
* Use the {@link EqlQueryTransformer} to transform the original query into a query with the {@link Sort} applied.
67+
*
68+
* @param parsedQuery
69+
* @param sort can be {@literal null}
70+
* @return list of {@link JpaQueryParsingToken}s
71+
*/
72+
@Override
73+
protected List<JpaQueryParsingToken> applySort(ParserRuleContext parsedQuery, Sort sort) {
74+
return new EqlQueryTransformer(sort).visit(parsedQuery);
75+
}
76+
77+
/**
78+
* Use the {@link EqlQueryTransformer} to transform the original query into a count query.
79+
*
80+
* @param parsedQuery
81+
* @param countProjection
82+
* @return list of {@link JpaQueryParsingToken}s
83+
*/
84+
@Override
85+
protected List<JpaQueryParsingToken> doCreateCountQuery(ParserRuleContext parsedQuery,
86+
@Nullable String countProjection) {
87+
return new EqlQueryTransformer(true, countProjection).visit(parsedQuery);
88+
}
89+
90+
/**
91+
* Run the parsed query through {@link EqlQueryTransformer} to find the primary FROM clause's alias.
92+
*
93+
* @param parsedQuery
94+
* @return can be {@literal null}
95+
*/
96+
@Override
97+
protected String doFindAlias(ParserRuleContext parsedQuery) {
98+
99+
EqlQueryTransformer transformVisitor = new EqlQueryTransformer();
100+
transformVisitor.visit(parsedQuery);
101+
return transformVisitor.getAlias();
102+
}
103+
104+
/**
105+
* Use {@link EqlQueryTransformer} to find the projection of the query.
106+
*
107+
* @param parsedQuery
108+
* @return
109+
*/
110+
@Override
111+
protected List<JpaQueryParsingToken> doFindProjection(ParserRuleContext parsedQuery) {
112+
113+
EqlQueryTransformer transformVisitor = new EqlQueryTransformer();
114+
transformVisitor.visit(parsedQuery);
115+
return transformVisitor.getProjection();
116+
}
117+
118+
/**
119+
* Use {@link EqlQueryTransformer} to detect if the query uses a {@code new com.example.Dto()} DTO constructor in the
120+
* primary select clause.
121+
*
122+
* @param parsedQuery
123+
* @return Guaranteed to be {@literal true} or {@literal false}.
124+
*/
125+
@Override
126+
protected boolean doCheckForConstructor(ParserRuleContext parsedQuery) {
127+
128+
EqlQueryTransformer transformVisitor = new EqlQueryTransformer();
129+
transformVisitor.visit(parsedQuery);
130+
return transformVisitor.hasConstructorExpression();
131+
}
132+
}

0 commit comments

Comments
 (0)