diff --git a/pom.xml b/pom.xml index c24ec2964..c77686453 100644 --- a/pom.xml +++ b/pom.xml @@ -28,9 +28,9 @@ 16 - + - 4.11.1 + 4.10.1 3.0.3 6.1.4.Final 2.7.1 diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxErrorListener.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarErrorListener.java similarity index 73% rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxErrorListener.java rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarErrorListener.java index 2017eb40a..48805d485 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxErrorListener.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarErrorListener.java @@ -20,16 +20,23 @@ import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; /** - * A {@link BaseErrorListener} that will throw a {@link JpaQueryParsingSyntaxError} if the query is invalid. + * A {@link BaseErrorListener} that will throw a {@link BadJpqlGrammarException} if the query is invalid. * * @author Greg Turnquist * @since 3.1 */ -class JpaQueryParsingSyntaxErrorListener extends BaseErrorListener { +class BadJpqlGrammarErrorListener extends BaseErrorListener { + + private final String query; + + BadJpqlGrammarErrorListener(String query) { + this.query = query; + } @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { - throw new JpaQueryParsingSyntaxError("line " + line + ":" + charPositionInLine + " " + msg); + throw new BadJpqlGrammarException("Line " + line + ":" + charPositionInLine + " " + msg, query, null); } + } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxError.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarException.java similarity index 68% rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxError.java rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarException.java index 6224a8ce5..00f547101 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingSyntaxError.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/BadJpqlGrammarException.java @@ -16,17 +16,26 @@ package org.springframework.data.jpa.repository.query; import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.lang.Nullable; /** * An exception thrown if the JPQL query is invalid. * * @author Greg Turnquist + * @author Mark Paluch * @since 3.1 */ -class JpaQueryParsingSyntaxError extends InvalidDataAccessResourceUsageException { +public class BadJpqlGrammarException extends InvalidDataAccessResourceUsageException { - public JpaQueryParsingSyntaxError(String message) { - super(message); + private final String jpql; + + public BadJpqlGrammarException(String message, String jpql, @Nullable Throwable cause) { + super(message + "; Bad JPQL grammar [" + jpql + "]", cause); + this.jpql = jpql; + } + + public String getJpql() { + return this.jpql; } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryParser.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryParser.java index 1f65272d1..8f9cdcaac 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryParser.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryParser.java @@ -24,46 +24,43 @@ import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; /** - * Implements the parsing operations of a {@link JpaQueryParser} using the ANTLR-generated {@link HqlParser} and - * {@link HqlQueryTransformer}. - * + * Implements the {@code HQL} parsing operations of a {@link JpaQueryParserSupport} using the ANTLR-generated + * {@link HqlParser} and {@link HqlQueryTransformer}. + * * @author Greg Turnquist + * @author Mark Paluch * @since 3.1 */ -class HqlQueryParser extends JpaQueryParser { - - HqlQueryParser(DeclaredQuery declaredQuery) { - super(declaredQuery); - } +class HqlQueryParser extends JpaQueryParserSupport { HqlQueryParser(String query) { super(query); } /** - * Convenience method to parse an HQL query. Will throw a {@link JpaQueryParsingSyntaxError} if the query is invalid. + * Convenience method to parse an HQL query. Will throw a {@link BadJpqlGrammarException} if the query is invalid. * * @param query * @return a parsed query, ready for postprocessing */ - static ParserRuleContext parse(String query) { + public static ParserRuleContext parseQuery(String query) { HqlLexer lexer = new HqlLexer(CharStreams.fromString(query)); HqlParser parser = new HqlParser(new CommonTokenStream(lexer)); - parser.addErrorListener(new JpaQueryParsingSyntaxErrorListener()); + configureParser(query, lexer, parser); return parser.start(); } /** - * Parse the query using {@link #parse(String)}. + * Parse the query using {@link #parseQuery(String)}. * * @return a parsed query */ @Override - protected ParserRuleContext parse() { - return parse(getQuery()); + protected ParserRuleContext parse(String query) { + return parseQuery(query); } /** @@ -74,7 +71,7 @@ class HqlQueryParser extends JpaQueryParser { * @return list of {@link JpaQueryParsingToken}s */ @Override - protected List doCreateQuery(ParserRuleContext parsedQuery, Sort sort) { + protected List applySort(ParserRuleContext parsedQuery, Sort sort) { return new HqlQueryTransformer(sort).visit(parsedQuery); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryTransformer.java index 27fd78dc8..dbb0f9155 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryTransformer.java @@ -18,11 +18,13 @@ package org.springframework.data.jpa.repository.query; import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.antlr.v4.runtime.ParserRuleContext; import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed HQL query. @@ -32,30 +34,35 @@ import org.springframework.lang.Nullable; */ class HqlQueryTransformer extends HqlQueryRenderer { - @Nullable private Sort sort; - private boolean countQuery; + // TODO: Separate input from result parameters, encapsulation... - @Nullable private String countProjection; + private final Sort sort; + private final boolean countQuery; - @Nullable private String alias = null; + private final @Nullable String countProjection; - private List projection = null; + private @Nullable String alias = null; + + private List projection = Collections.emptyList(); + private boolean projectionProcessed; private boolean hasConstructorExpression = false; HqlQueryTransformer() { - this(null, false, null); + this(Sort.unsorted(), false, null); } - HqlQueryTransformer(@Nullable Sort sort) { + HqlQueryTransformer(Sort sort) { this(sort, false, null); } HqlQueryTransformer(boolean countQuery, @Nullable String countProjection) { - this(null, countQuery, countProjection); + this(Sort.unsorted(), countQuery, countProjection); } - private HqlQueryTransformer(@Nullable Sort sort, boolean countQuery, @Nullable String countProjection) { + private HqlQueryTransformer(Sort sort, boolean countQuery, @Nullable String countProjection) { + + Assert.notNull(sort, "Sort must not be null"); this.sort = sort; this.countQuery = countQuery; @@ -94,7 +101,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitOrderedQuery(HqlParser.OrderedQueryContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (ctx.query() != null) { tokens.addAll(visit(ctx.query())); @@ -111,7 +118,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { tokens.addAll(visit(ctx.queryOrder())); } - if (this.sort != null && this.sort.isSorted()) { + if (this.sort.isSorted()) { if (ctx.queryOrder() != null) { @@ -125,7 +132,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { this.sort.forEach(order -> { - JpaQueryParser.checkSortExpression(order); + JpaQueryParserSupport.checkSortExpression(order); if (order.isIgnoreCase()) { tokens.add(TOKEN_LOWER_FUNC); @@ -160,7 +167,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitFromQuery(HqlParser.FromQueryContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (countQuery && !isSubquery(ctx) && ctx.selectClause() == null) { @@ -201,7 +208,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitQueryOrder(HqlParser.QueryOrderContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (!countQuery) { tokens.addAll(visit(ctx.orderByClause())); @@ -224,7 +231,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitFromRoot(HqlParser.FromRootContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (ctx.entityName() != null) { @@ -261,7 +268,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitAlias(HqlParser.AliasContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (ctx.AS() != null) { tokens.add(new JpaQueryParsingToken(ctx.AS())); @@ -279,7 +286,7 @@ class HqlQueryTransformer extends HqlQueryRenderer { @Override public List visitSelectClause(HqlParser.SelectClauseContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); tokens.add(new JpaQueryParsingToken(ctx.SELECT())); @@ -321,8 +328,9 @@ class HqlQueryTransformer extends HqlQueryRenderer { tokens.addAll(selectionListTokens); } - if (projection == null && !isSubquery(ctx)) { + if (!projectionProcessed && !isSubquery(ctx)) { this.projection = selectionListTokens; + this.projectionProcessed = true; } return tokens; @@ -335,4 +343,8 @@ class HqlQueryTransformer extends HqlQueryRenderer { return super.visitInstantiation(ctx); } + + static ArrayList newArrayList() { + return new ArrayList<>(); + } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingEnhancer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancer.java similarity index 59% rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingEnhancer.java rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancer.java index f6ca59eff..b44ca445c 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingEnhancer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryEnhancer.java @@ -17,37 +17,63 @@ package org.springframework.data.jpa.repository.query; import java.util.Set; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * Implementation of {@link QueryEnhancer} using a {@link JpaQueryParser}.
- *
- * NOTE: The parser can find everything it needs to created sorted and count queries. Thus, looking up the alias or the - * projection isn't needed for its primary function, and are simply implemented for test purposes. + * Implementation of {@link QueryEnhancer} to enhance JPA queries using a {@link JpaQueryParserSupport}. * * @author Greg Turnquist + * @author Mark Paluch * @since 3.1 + * @see JpqlQueryParser + * @see HqlQueryParser */ -class JpaQueryParsingEnhancer implements QueryEnhancer { +class JpaQueryEnhancer implements QueryEnhancer { - private final JpaQueryParser queryParser; + private final DeclaredQuery query; + private final JpaQueryParserSupport queryParser; /** - * Initialize with an {@link JpaQueryParser}. - * + * Initialize with an {@link JpaQueryParserSupport}. + * + * @param query * @param queryParser */ - public JpaQueryParsingEnhancer(JpaQueryParser queryParser) { + private JpaQueryEnhancer(DeclaredQuery query, JpaQueryParserSupport queryParser) { - Assert.notNull(queryParser, "queryParse must not be null!"); + this.query = query; this.queryParser = queryParser; } - public JpaQueryParser getQueryParsingStrategy() { + /** + * Factory method to create a {@link JpaQueryParserSupport} for {@link DeclaredQuery} using JPQL grammar. + * + * @param query must not be {@literal null}. + * @return a new {@link JpaQueryEnhancer} using JPQL. + */ + public static JpaQueryEnhancer forJpql(DeclaredQuery query) { + + Assert.notNull(query, "DeclaredQuery must not be null!"); + + return new JpaQueryEnhancer(query, new JpqlQueryParser(query.getQueryString())); + } + + /** + * Factory method to create a {@link JpaQueryParserSupport} for {@link DeclaredQuery} using HQL grammar. + * + * @param query must not be {@literal null}. + * @return a new {@link JpaQueryEnhancer} using HQL. + */ + public static JpaQueryEnhancer forHql(DeclaredQuery query) { + + Assert.notNull(query, "DeclaredQuery must not be null!"); + + return new JpaQueryEnhancer(query, new HqlQueryParser(query.getQueryString())); + } + + protected JpaQueryParserSupport getQueryParsingStrategy() { return queryParser; } @@ -59,7 +85,7 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { */ @Override public String applySorting(Sort sort) { - return queryParser.createQuery(sort); + return queryParser.renderSortedQuery(sort); } /** @@ -75,8 +101,8 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { } /** - * Resolves the alias for the entity in the FROM clause from the JPA query. Since the {@link JpaQueryParser} can - * already find the alias when generating sorted and count queries, this is mainly to serve test cases. + * Resolves the alias for the entity in the FROM clause from the JPA query. Since the {@link JpaQueryParserSupport} + * can already find the alias when generating sorted and count queries, this is mainly to serve test cases. */ @Override public String detectAlias() { @@ -85,7 +111,7 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { /** * Creates a count query from the original query, with no count projection. - * + * * @return Guaranteed to be not {@literal null}; */ @Override @@ -114,8 +140,8 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { } /** - * Looks up the projection of the JPA query. Since the {@link JpaQueryParser} can already find the projection when - * generating sorted and count queries, this is mainly to serve test cases. + * Looks up the projection of the JPA query. Since the {@link JpaQueryParserSupport} can already find the projection + * when generating sorted and count queries, this is mainly to serve test cases. */ @Override public String getProjection() { @@ -123,7 +149,7 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { } /** - * Since the {@link JpaQueryParser} can already fully transform sorted and count queries by itself, this is a + * Since the {@link JpaQueryParserSupport} can already fully transform sorted and count queries by itself, this is a * placeholder method. * * @return empty set @@ -134,10 +160,10 @@ class JpaQueryParsingEnhancer implements QueryEnhancer { } /** - * Look up the {@link DeclaredQuery} from the {@link JpaQueryParser}. + * Look up the {@link DeclaredQuery} from the {@link JpaQueryParserSupport}. */ @Override public DeclaredQuery getQuery() { - return queryParser.getDeclaredQuery(); + return query; } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParser.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParserSupport.java similarity index 63% rename from spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParser.java rename to spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParserSupport.java index c41a4e56c..892476ad2 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParser.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParserSupport.java @@ -20,19 +20,24 @@ import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken import java.util.List; import java.util.regex.Pattern; +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.atn.PredictionMode; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.JpaSort; +import org.springframework.data.util.Lazy; import org.springframework.lang.Nullable; /** * Operations needed to parse a JPA query. * * @author Greg Turnquist + * @author Mark Paluch * @since 3.1 */ -abstract class JpaQueryParser { +abstract class JpaQueryParserSupport { private static final Pattern PUNCTUATION_PATTERN = Pattern.compile(".*((?![._])[\\p{Punct}|\\s])"); @@ -40,22 +45,10 @@ abstract class JpaQueryParser { + "aliases used in the select clause; If you really want to use something other than that for sorting, please use " + "JpaSort.unsafe(…)"; - private final DeclaredQuery declaredQuery; + private final ParseState state; - JpaQueryParser(DeclaredQuery declaredQuery) { - this.declaredQuery = declaredQuery; - } - - JpaQueryParser(String query) { - this(DeclaredQuery.of(query, false)); - } - - DeclaredQuery getDeclaredQuery() { - return declaredQuery; - } - - String getQuery() { - return getDeclaredQuery().getQueryString(); + JpaQueryParserSupport(String query) { + this.state = new ParseState(query); } /** @@ -64,17 +57,11 @@ abstract class JpaQueryParser { * * @param sort can be {@literal null} */ - String createQuery(Sort sort) { + String renderSortedQuery(Sort sort) { try { - ParserRuleContext parsedQuery = parse(); - - if (parsedQuery == null) { - return ""; - } - - return render(doCreateQuery(parsedQuery, sort)); - } catch (JpaQueryParsingSyntaxError e) { + return render(applySort(state.getContext(), sort)); + } catch (BadJpqlGrammarException e) { throw new IllegalArgumentException(e); } } @@ -87,34 +74,21 @@ abstract class JpaQueryParser { String createCountQuery(@Nullable String countProjection) { try { - ParserRuleContext parsedQuery = parse(); - - if (parsedQuery == null) { - return ""; - } - - return render(doCreateCountQuery(parsedQuery, countProjection)); - } catch (JpaQueryParsingSyntaxError e) { + return render(doCreateCountQuery(state.getContext(), countProjection)); + } catch (BadJpqlGrammarException e) { throw new IllegalArgumentException(e); } } /** * Find the projection of the query. - * - * @param parsedQuery */ String projection() { try { - ParserRuleContext parsedQuery = parse(); - - if (parsedQuery == null) { - return ""; - } - - return render(doFindProjection(parsedQuery)); - } catch (JpaQueryParsingSyntaxError e) { + List tokens = doFindProjection(state.getContext()); + return tokens.isEmpty() ? "" : render(tokens); + } catch (BadJpqlGrammarException e) { return ""; } } @@ -124,17 +98,12 @@ abstract class JpaQueryParser { * * @return can be {@literal null} */ + @Nullable String findAlias() { try { - ParserRuleContext parsedQuery = parse(); - - if (parsedQuery == null) { - return null; - } - - return doFindAlias(parsedQuery); - } catch (JpaQueryParsingSyntaxError e) { + return doFindAlias(state.getContext()); + } catch (BadJpqlGrammarException e) { return null; } } @@ -147,18 +116,67 @@ abstract class JpaQueryParser { boolean hasConstructorExpression() { try { - ParserRuleContext parsedQuery = parse(); - - if (parsedQuery == null) { - return false; - } - - return doCheckForConstructor(parsedQuery); - } catch (JpaQueryParsingSyntaxError e) { + return doCheckForConstructor(state.getContext()); + } catch (BadJpqlGrammarException e) { return false; } } + /** + * Parse the JPA query using its corresponding ANTLR parser. + */ + protected abstract ParserRuleContext parse(String query); + + /** + * Apply common configuration (SLL prediction for performance, our own error listeners). + * + * @param query + * @param lexer + * @param parser + */ + static void configureParser(String query, Lexer lexer, Parser parser) { + + BadJpqlGrammarErrorListener errorListener = new BadJpqlGrammarErrorListener(query); + + lexer.removeErrorListeners(); + lexer.addErrorListener(errorListener); + + parser.getInterpreter().setPredictionMode(PredictionMode.SLL); + + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + } + + /** + * Create a {@link JpaQueryParsingToken}-based query with an {@literal order by} applied/amended based upon the + * {@link Sort} parameter. + * + * @param parsedQuery + * @param sort can be {@literal null} + */ + protected abstract List applySort(ParserRuleContext parsedQuery, Sort sort); + + /** + * Create a {@link JpaQueryParsingToken}-based count query. + * + * @param parsedQuery + * @param countProjection + */ + protected abstract List doCreateCountQuery(ParserRuleContext parsedQuery, + @Nullable String countProjection); + + @Nullable + protected abstract String doFindAlias(ParserRuleContext parsedQuery); + + /** + * Find the projection of the query's primary SELECT clause. + * + * @param parsedQuery + */ + protected abstract List doFindProjection(ParserRuleContext parsedQuery); + + protected abstract boolean doCheckForConstructor(ParserRuleContext parsedQuery); + /** * Check any given {@link JpaSort.JpaOrder#isUnsafe()} order for presence of at least one property offending the * {@link #PUNCTUATION_PATTERN} and throw an {@link Exception} indicating potential unsafe order by expression. @@ -177,37 +195,38 @@ abstract class JpaQueryParser { } /** - * Parse the JPA query using its corresponding ANTLR parser. + * Parser state capturing the lazily-parsed parser context. */ - protected abstract ParserRuleContext parse(); + class ParseState { - /** - * Create a {@link JpaQueryParsingToken}-based query with an {@literal order by} applied/amended based upon the - * {@link Sort} parameter. - * - * @param parsedQuery - * @param sort can be {@literal null} - */ - protected abstract List doCreateQuery(ParserRuleContext parsedQuery, Sort sort); + private final Lazy parsedQuery; + private volatile @Nullable BadJpqlGrammarException error; + private final String query; - /** - * Create a {@link JpaQueryParsingToken}-based count query. - * - * @param parsedQuery - * @param countProjection - */ - protected abstract List doCreateCountQuery(ParserRuleContext parsedQuery, - @Nullable String countProjection); + public ParseState(String query) { + this.query = query; + this.parsedQuery = Lazy.of(() -> parse(query)); + } - protected abstract String doFindAlias(ParserRuleContext parsedQuery); + public ParserRuleContext getContext() { - /** - * Find the projection of the query's primary SELECT clause. - * - * @param parsedQuery - */ - protected abstract List doFindProjection(ParserRuleContext parsedQuery); + BadJpqlGrammarException error = this.error; - protected abstract boolean doCheckForConstructor(ParserRuleContext parsedQuery); + if (error != null) { + throw error; + } + + try { + return parsedQuery.get(); + } catch (BadJpqlGrammarException e) { + this.error = error = e; + throw error; + } + } + + public String getQuery() { + return query; + } + } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingToken.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingToken.java index 9ef60b971..5c221e62d 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingToken.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryParsingToken.java @@ -162,10 +162,6 @@ class JpaQueryParsingToken { */ static String render(List tokens) { - if (tokens == null) { - return ""; - } - StringBuilder results = new StringBuilder(); tokens.forEach(token -> { diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryParser.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryParser.java index c7cfef600..2db207e35 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryParser.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryParser.java @@ -24,46 +24,44 @@ import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; /** - * Implements the parsing operations of a {@link JpaQueryParser} using the ANTLR-generated {@link JpqlParser} and - * {@link JpqlQueryTransformer}. + * Implements the {@code JPQL} parsing operations of a {@link JpaQueryParserSupport} using the ANTLR-generated + * {@link JpqlParser} and {@link JpqlQueryTransformer}. * * @author Greg Turnquist + * @author Mark Paluch * @since 3.1 */ -class JpqlQueryParser extends JpaQueryParser { - - JpqlQueryParser(DeclaredQuery declaredQuery) { - super(declaredQuery); - } +class JpqlQueryParser extends JpaQueryParserSupport { JpqlQueryParser(String query) { super(query); } /** - * Convenience method to parse a JPQL query. Will throw a {@link JpaQueryParsingSyntaxError} if the query is invalid. + * Convenience method to parse a JPQL query. Will throw a {@link BadJpqlGrammarException} if the query is invalid. * * @param query * @return a parsed query, ready for postprocessing */ - static ParserRuleContext parse(String query) { + public static ParserRuleContext parseQuery(String query) { JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query)); JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer)); - parser.addErrorListener(new JpaQueryParsingSyntaxErrorListener()); + configureParser(query, lexer, parser); return parser.start(); } + /** - * Parse the query using {@link #parse(String)}. + * Parse the query using {@link #parseQuery(String)}. * * @return a parsed query */ @Override - protected ParserRuleContext parse() { - return parse(getQuery()); + protected ParserRuleContext parse(String query) { + return parseQuery(query); } /** @@ -74,7 +72,7 @@ class JpqlQueryParser extends JpaQueryParser { * @return list of {@link JpaQueryParsingToken}s */ @Override - protected List doCreateQuery(ParserRuleContext parsedQuery, Sort sort) { + protected List applySort(ParserRuleContext parsedQuery, Sort sort) { return new JpqlQueryTransformer(sort).visit(parsedQuery); } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformer.java index fe030c598..3749250ff 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformer.java @@ -18,10 +18,12 @@ package org.springframework.data.jpa.repository.query; import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.springframework.data.domain.Sort; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; /** * An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed JPQL query. @@ -31,30 +33,34 @@ import org.springframework.lang.Nullable; */ class JpqlQueryTransformer extends JpqlQueryRenderer { - @Nullable private Sort sort; - private boolean countQuery; + // TODO: Separate input from result parameters, encapsulation... + private final Sort sort; + private final boolean countQuery; - @Nullable private String countProjection; + private final @Nullable String countProjection; - @Nullable private String alias = null; + private @Nullable String alias = null; - private List projection = null; + private List projection = Collections.emptyList(); + private boolean projectionProcessed; private boolean hasConstructorExpression = false; JpqlQueryTransformer() { - this(null, false, null); + this(Sort.unsorted(), false, null); } - JpqlQueryTransformer(@Nullable Sort sort) { + JpqlQueryTransformer(Sort sort) { this(sort, false, null); } JpqlQueryTransformer(boolean countQuery, @Nullable String countProjection) { - this(null, countQuery, countProjection); + this(Sort.unsorted(), countQuery, countProjection); } - private JpqlQueryTransformer(@Nullable Sort sort, boolean countQuery, @Nullable String countProjection) { + private JpqlQueryTransformer(Sort sort, boolean countQuery, @Nullable String countProjection) { + + Assert.notNull(sort, "Sort must not be null"); this.sort = sort; this.countQuery = countQuery; @@ -77,7 +83,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { @Override public List visitSelect_statement(JpqlParser.Select_statementContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); tokens.addAll(visit(ctx.select_clause())); tokens.addAll(visit(ctx.from_clause())); @@ -100,7 +106,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { tokens.addAll(visit(ctx.orderby_clause())); } - if (this.sort != null && this.sort.isSorted()) { + if (this.sort.isSorted()) { if (ctx.orderby_clause() != null) { @@ -114,7 +120,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { this.sort.forEach(order -> { - JpaQueryParser.checkSortExpression(order); + JpaQueryParserSupport.checkSortExpression(order); if (order.isIgnoreCase()) { tokens.add(TOKEN_LOWER_FUNC); @@ -144,7 +150,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { @Override public List visitSelect_clause(JpqlParser.Select_clauseContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); tokens.add(new JpaQueryParsingToken(ctx.SELECT())); @@ -156,7 +162,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { tokens.add(new JpaQueryParsingToken(ctx.DISTINCT())); } - List selectItemTokens = new ArrayList<>(); + List selectItemTokens = newArrayList(); ctx.select_item().forEach(selectItemContext -> { selectItemTokens.addAll(visit(selectItemContext)); @@ -192,8 +198,9 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { tokens.addAll(selectItemTokens); } - if (projection == null) { + if (!projectionProcessed) { this.projection = selectItemTokens; + this.projectionProcessed = true; } return tokens; @@ -202,7 +209,7 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { @Override public List visitRange_variable_declaration(JpqlParser.Range_variable_declarationContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); tokens.addAll(visit(ctx.entity_name())); @@ -226,4 +233,8 @@ class JpqlQueryTransformer extends JpqlQueryRenderer { return super.visitConstructor_expression(ctx); } + + private static ArrayList newArrayList() { + return new ArrayList<>(); + } } diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java index e74952e13..74aa77e61 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactory.java @@ -17,21 +17,36 @@ package org.springframework.data.jpa.repository.query; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.util.ClassUtils; /** * Encapsulates different strategies for the creation of a {@link QueryEnhancer} from a {@link DeclaredQuery}. * * @author Diego Krupitza * @author Greg Turnquist + * @author Mark Paluch * @since 2.7.0 */ public final class QueryEnhancerFactory { private static final Log LOG = LogFactory.getLog(QueryEnhancerFactory.class); - private static final boolean JSQLPARSER_IN_CLASSPATH = isJSqlParserInClassPath(); + private static final boolean jSqlParserPresent = ClassUtils.isPresent("net.sf.jsqlparser.parser.JSqlParser", + QueryEnhancerFactory.class.getClassLoader()); - private static final boolean HIBERNATE_IN_CLASSPATH = isHibernateInClassPath(); + private static final boolean hibernatePresent = ClassUtils.isPresent("org.hibernate.query.TypedParameterValue", + QueryEnhancerFactory.class.getClassLoader()); + + static { + + if (jSqlParserPresent) { + LOG.info("JSqlParser is in classpath; If applicable, JSqlParser will be used"); + } + + if (hibernatePresent) { + LOG.info("Hibernate is in classpath; If applicable, HQL parser will be used."); + } + } private QueryEnhancerFactory() {} @@ -45,81 +60,17 @@ public final class QueryEnhancerFactory { if (query.isNativeQuery()) { - if (qualifiesForJSqlParserUsage(query)) { - /** + if (jSqlParserPresent) { + /* * If JSqlParser fails, throw some alert signaling that people should write a custom Impl. */ return new JSqlParserQueryEnhancer(query); - } else { - return new DefaultQueryEnhancer(query); } - } else { - if (qualifiedForHqlParserUsage(query)) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)); - } else if (qualifiesForJpqlParserUsage(query)) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(query)); - } else { - return new DefaultQueryEnhancer(query); - } + return new DefaultQueryEnhancer(query); } + + return hibernatePresent ? JpaQueryEnhancer.forHql(query) : JpaQueryEnhancer.forJpql(query); } - /** - * Checks if a given query can be process with the JSqlParser under the condition that the parser is in the classpath. - * - * @param query the query we want to check - * @return true if JSqlParser is in the classpath and the query is classified as a native query and not - * to be bypassed otherwise false - */ - private static boolean qualifiesForJSqlParserUsage(DeclaredQuery query) { - return JSQLPARSER_IN_CLASSPATH && query.isNativeQuery(); - } - - /** - * Checks if the query is a candidate for the HQL parser. - * - * @param query the query we want to check - * @return true if Hibernate is in the classpath and the query is NOT classified as native - */ - private static boolean qualifiedForHqlParserUsage(DeclaredQuery query) { - return HIBERNATE_IN_CLASSPATH && !query.isNativeQuery(); - } - - /** - * Checks if the query is a candidate for the JPQL spec parser. - * - * @param query the query we want to check - * @return true if the query is NOT classified as a native query - */ - private static boolean qualifiesForJpqlParserUsage(DeclaredQuery query) { - return !query.isNativeQuery(); - } - - /** - * Checks whether JSqlParser is in classpath or not. - * - * @return true when in classpath otherwise false - */ - private static boolean isJSqlParserInClassPath() { - - try { - Class.forName("net.sf.jsqlparser.parser.JSqlParser", false, QueryEnhancerFactory.class.getClassLoader()); - LOG.info("JSqlParser is in classpath; If applicable JSqlParser will be used"); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } - - private static boolean isHibernateInClassPath() { - - try { - Class.forName("org.hibernate.query.TypedParameterValue", false, QueryEnhancerFactory.class.getClassLoader()); - LOG.info("Hibernate is in classpath; If applicable Hql61Parser will be used."); - return true; - } catch (ClassNotFoundException e) { - return false; - } - } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java index 256f7af4f..aefc1a2ca 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlParserQueryEnhancerUnitTests.java @@ -22,7 +22,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** - * TCK Tests for {@link HqlQueryParser} mixed into {@link JpaQueryParsingEnhancer}. + * TCK Tests for {@link HqlQueryParser} mixed into {@link JpaQueryEnhancer}. * * @author Greg Turnquist * @since 3.1 @@ -32,8 +32,8 @@ public class HqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests { public static final String HQL_PARSER_DOES_NOT_SUPPORT_NATIVE_QUERIES = "HqlParser does not support native queries"; @Override - QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(declaredQuery)); + QueryEnhancer createQueryEnhancer(DeclaredQuery query) { + return JpaQueryEnhancer.forHql(query); } @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index 2a1c9aff0..c161fd5ea 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java @@ -39,7 +39,7 @@ class HqlQueryRendererTests { /** * Parse the query using {@link HqlParser} then run it through the query-preserving {@link HqlQueryRenderer}. - * + * * @param query */ private static String parseWithoutChanges(String query) { @@ -47,7 +47,7 @@ class HqlQueryRendererTests { HqlLexer lexer = new HqlLexer(CharStreams.fromString(query)); HqlParser parser = new HqlParser(new CommonTokenStream(lexer)); - parser.addErrorListener(new JpaQueryParsingSyntaxErrorListener()); + parser.addErrorListener(new BadJpqlGrammarErrorListener(query)); HqlParser.StartContext parsedQuery = parser.start(); diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java index b8906ddc7..5dbc29f96 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java @@ -27,8 +27,7 @@ import org.springframework.data.jpa.domain.JpaSort; import org.springframework.lang.Nullable; /** - * Verify that HQL queries are properly transformed through the {@link JpaQueryParsingEnhancer} and the - * {@link HqlQueryParser}. + * Verify that HQL queries are properly transformed through the {@link JpaQueryEnhancer} and the {@link HqlQueryParser}. * * @author Greg Turnquist * @since 3.1 @@ -118,7 +117,7 @@ class HqlQueryTransformerTests { var original = "select e from Employee e join e.manager m"; // when - var results = createQueryFor(original, null); + var results = createQueryFor(original, Sort.unsorted()); // then assertThat(results).isEqualTo("select e from Employee e join e.manager m"); @@ -208,12 +207,12 @@ class HqlQueryTransformerTests { Sort sort = Sort.by(Sort.Order.desc("age")); - assertThat(new JpaQueryParsingEnhancer(new HqlQueryParser("select u\n" + // + assertThat(newParser("select u\n" + // "from user u\n" + // "where exists (select u2\n" + // "from user u2\n" + // ")\n" + // - "")).applySorting(sort)).isEqualToIgnoringWhitespace("select u\n" + // + "").applySorting(sort)).isEqualToIgnoringWhitespace("select u\n" + // "from user u\n" + // "where exists (select u2\n" + // "from user u2\n" + // @@ -790,7 +789,7 @@ class HqlQueryTransformerTests { } private String createQueryFor(String query, Sort sort) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)).applySorting(sort); + return newParser(query).applySorting(sort); } private String createCountQueryFor(String query) { @@ -798,18 +797,23 @@ class HqlQueryTransformerTests { } private String createCountQueryFor(String query, @Nullable String countProjection) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)).createCountQueryFor(countProjection); + return newParser(query).createCountQueryFor(countProjection); } + @Nullable private String alias(String query) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)).detectAlias(); + return newParser(query).detectAlias(); } private boolean hasConstructorExpression(String query) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)).hasConstructorExpression(); + return newParser(query).hasConstructorExpression(); } private String projection(String query) { - return new JpaQueryParsingEnhancer(new HqlQueryParser(query)).getProjection(); + return newParser(query).getProjection(); + } + + private QueryEnhancer newParser(String query) { + return JpaQueryEnhancer.forHql(DeclaredQuery.of(query, false)); } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java index 179855736..88d0656c7 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlSpecificationTests.java @@ -38,7 +38,7 @@ class HqlSpecificationTests { @Test void joinExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order AS o JOIN o.lineItems AS l WHERE l.shipped = FALSE @@ -52,7 +52,7 @@ class HqlSpecificationTests { @Test void joinExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l JOIN l.product p WHERE p.productType = 'office_supplies' @@ -65,7 +65,7 @@ class HqlSpecificationTests { @Test void rangeVariableDeclarations() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o1 FROM Order o1, Order o2 WHERE o1.quantity > o2.quantity AND @@ -80,7 +80,7 @@ class HqlSpecificationTests { @Test void pathExpressionsExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT i.name, VALUE(p) FROM Item i JOIN i.photos p WHERE KEY(p) LIKE '%egret' @@ -93,7 +93,7 @@ class HqlSpecificationTests { @Test void pathExpressionsExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT i.name, p FROM Item i JOIN i.photos p WHERE KEY(p) LIKE '%egret' @@ -106,7 +106,7 @@ class HqlSpecificationTests { @Test void pathExpressionsExample3() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p """); @@ -118,7 +118,7 @@ class HqlSpecificationTests { @Test void pathExpressionsExample4() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE e.contactInfo.address.zipcode = '95054' @@ -128,7 +128,7 @@ class HqlSpecificationTests { @Test void pathExpressionSyntaxExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT l.product FROM Order AS o JOIN o.lineItems l """); @@ -137,7 +137,7 @@ class HqlSpecificationTests { @Test void joinsExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize """); } @@ -145,7 +145,7 @@ class HqlSpecificationTests { @Test void joinsExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1 """); } @@ -153,7 +153,7 @@ class HqlSpecificationTests { @Test void joinsInnerExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1 """); } @@ -161,7 +161,7 @@ class HqlSpecificationTests { @Test void joinsInExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1 """); } @@ -169,7 +169,7 @@ class HqlSpecificationTests { @Test void doubleJoinExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE c.address.zipcode = '95054' @@ -179,7 +179,7 @@ class HqlSpecificationTests { @Test void leftJoinExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p GROUP BY s.name @@ -189,7 +189,7 @@ class HqlSpecificationTests { @Test void leftJoinOnExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p ON p.status = 'inStock' @@ -200,7 +200,7 @@ class HqlSpecificationTests { @Test void leftJoinWhereExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p WHERE p.status = 'inStock' @@ -211,7 +211,7 @@ class HqlSpecificationTests { @Test void leftJoinFetchExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT d FROM Department d LEFT JOIN FETCH d.employees WHERE d.deptno = 1 @@ -221,7 +221,7 @@ class HqlSpecificationTests { @Test void collectionMemberExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.product.productType = 'office_supplies' @@ -231,7 +231,7 @@ class HqlSpecificationTests { @Test void collectionMemberInExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o, IN(o.lineItems) l WHERE l.product.productType = 'office_supplies' @@ -241,7 +241,7 @@ class HqlSpecificationTests { @Test void fromClauseExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order AS o JOIN o.lineItems l JOIN l.product p """); @@ -250,7 +250,7 @@ class HqlSpecificationTests { @Test void fromClauseDowncastingExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT b.name, b.ISBN FROM Order o JOIN TREAT(o.product AS Book) b """); @@ -259,7 +259,7 @@ class HqlSpecificationTests { @Test void fromClauseDowncastingExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp WHERE lp.budget > 1000 """); @@ -272,7 +272,7 @@ class HqlSpecificationTests { @Disabled(SPEC_FAULT + "Use double-quotes when it should be using single-quotes for a string literal") void fromClauseDowncastingExample3_SPEC_BUG() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN e.projects p WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' @@ -283,7 +283,7 @@ class HqlSpecificationTests { @Test void fromClauseDowncastingExample3fixed() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN e.projects p WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' @@ -294,7 +294,7 @@ class HqlSpecificationTests { @Test void fromClauseDowncastingExample4() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TREAT(e AS Exempt).vacationDays > 10 OR TREAT(e AS Contractor).hours > 100 @@ -304,7 +304,7 @@ class HqlSpecificationTests { @Test void pathExpressionsNamedParametersExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE c.status = :stat @@ -314,7 +314,7 @@ class HqlSpecificationTests { @Test void betweenExpressionsExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT t FROM CreditCard c JOIN c.transactionHistory t WHERE c.holder.name = 'John Doe' AND INDEX(t) BETWEEN 0 AND 9 @@ -324,7 +324,7 @@ class HqlSpecificationTests { @Test void isEmptyExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -334,7 +334,7 @@ class HqlSpecificationTests { @Test void memberOfExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames @@ -344,7 +344,7 @@ class HqlSpecificationTests { @Test void existsSubSelectExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -357,7 +357,7 @@ class HqlSpecificationTests { @Test void allExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT emp FROM Employee emp WHERE emp.salary > ALL ( @@ -370,7 +370,7 @@ class HqlSpecificationTests { @Test void existsSubSelectExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -383,7 +383,7 @@ class HqlSpecificationTests { @Test void subselectNumericComparisonExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE (SELECT AVG(o.price) FROM c.orders o) > 100 @@ -393,7 +393,7 @@ class HqlSpecificationTests { @Test void subselectNumericComparisonExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT goodCustomer FROM Customer goodCustomer WHERE goodCustomer.balanceOwed < ( @@ -404,7 +404,7 @@ class HqlSpecificationTests { @Test void indexExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT w.name FROM Course c JOIN c.studentWaitlist w WHERE c.name = 'Calculus' @@ -419,7 +419,7 @@ class HqlSpecificationTests { @Disabled(SPEC_FAULT + "FUNCTION calls needs a comparator") void functionInvocationExample_SPEC_BUG() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) @@ -429,7 +429,7 @@ class HqlSpecificationTests { @Test void functionInvocationExampleWithCorrection() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @@ -439,7 +439,7 @@ class HqlSpecificationTests { @Test void updateCaseExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Employee e SET e.salary = CASE WHEN e.rating = 1 THEN e.salary * 1.1 @@ -452,7 +452,7 @@ class HqlSpecificationTests { @Test void updateCaseExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Employee e SET e.salary = CASE e.rating WHEN 1 THEN e.salary * 1.1 @@ -465,7 +465,7 @@ class HqlSpecificationTests { @Test void selectCaseExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e.name, CASE TYPE(e) WHEN Exempt THEN 'Exempt' WHEN Contractor THEN 'Contractor' @@ -480,7 +480,7 @@ class HqlSpecificationTests { @Test void selectCaseExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e.name, f.name, CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum ' @@ -495,7 +495,7 @@ class HqlSpecificationTests { @Test void theRest() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) @@ -505,7 +505,7 @@ class HqlSpecificationTests { @Test void theRest2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (:empType1, :empType2) @@ -515,7 +515,7 @@ class HqlSpecificationTests { @Test void theRest3() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN :empTypes @@ -525,7 +525,7 @@ class HqlSpecificationTests { @Test void theRest4() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT TYPE(e) FROM Employee e WHERE TYPE(e) <> Exempt @@ -535,7 +535,7 @@ class HqlSpecificationTests { @Test void theRest5() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c.status, AVG(c.filledOrderCount), COUNT(c) FROM Customer c GROUP BY c.status @@ -546,7 +546,7 @@ class HqlSpecificationTests { @Test void theRest6() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c.country, COUNT(c) FROM Customer c GROUP BY c.country @@ -557,7 +557,7 @@ class HqlSpecificationTests { @Test void theRest7() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c, COUNT(o) FROM Customer c JOIN c.orders o GROUP BY c @@ -568,7 +568,7 @@ class HqlSpecificationTests { @Test void theRest8() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c.id, c.status FROM Customer c JOIN c.orders o WHERE o.count > 100 @@ -578,7 +578,7 @@ class HqlSpecificationTests { @Test void theRest9() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT v.location.street, KEY(i).title, VALUE(i) FROM VideoStore v JOIN v.videoInventory i WHERE v.location.zipcode = '94301' AND VALUE(i) > 0 @@ -588,7 +588,7 @@ class HqlSpecificationTests { @Test void theRest10() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o.lineItems FROM Order AS o """); } @@ -596,7 +596,7 @@ class HqlSpecificationTests { @Test void theRest11() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c, COUNT(l) AS itemCount FROM Customer c JOIN c.Orders o JOIN o.lineItems l WHERE c.address.state = 'CA' @@ -608,7 +608,7 @@ class HqlSpecificationTests { @Test void theRest12() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.count) FROM Customer c JOIN c.orders o WHERE o.count > 100 @@ -618,7 +618,7 @@ class HqlSpecificationTests { @Test void theRest13() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e.address AS addr FROM Employee e """); @@ -627,7 +627,7 @@ class HqlSpecificationTests { @Test void theRest14() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) FROM Order o """); } @@ -635,7 +635,7 @@ class HqlSpecificationTests { @Test void theRest15() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT SUM(l.price) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -645,7 +645,7 @@ class HqlSpecificationTests { @Test void theRest16() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT COUNT(o) FROM Order o """); } @@ -653,7 +653,7 @@ class HqlSpecificationTests { @Test void theRest17() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT COUNT(l.price) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -663,7 +663,7 @@ class HqlSpecificationTests { @Test void theRest18() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT COUNT(l) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' AND l.price IS NOT NULL @@ -673,7 +673,7 @@ class HqlSpecificationTests { @Test void theRest19() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -684,7 +684,7 @@ class HqlSpecificationTests { @Test void theRest20() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o.quantity, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -695,7 +695,7 @@ class HqlSpecificationTests { @Test void theRest21() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o.quantity, o.cost*1.08 AS taxedCost, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' AND a.county = 'Santa Clara' @@ -706,7 +706,7 @@ class HqlSpecificationTests { @Test void theRest22() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) as q, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -718,7 +718,7 @@ class HqlSpecificationTests { @Test void theRest23() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.product_name FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -732,7 +732,7 @@ class HqlSpecificationTests { @Test void theRest24() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.product_name FROM Order o, IN(o.lineItems) l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -743,7 +743,7 @@ class HqlSpecificationTests { @Test void theRest25() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -753,7 +753,7 @@ class HqlSpecificationTests { @Test void theRest26() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -764,7 +764,7 @@ class HqlSpecificationTests { @Test void theRest27() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Customer c SET c.status = 'outstanding' WHERE c.balance < 10000 @@ -774,7 +774,7 @@ class HqlSpecificationTests { @Test void theRest28() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Employee e SET e.address.building = 22 WHERE e.address.building = 14 @@ -786,7 +786,7 @@ class HqlSpecificationTests { @Test void theRest29() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o """); @@ -795,7 +795,7 @@ class HqlSpecificationTests { @Test void theRest30() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress.state = 'CA' @@ -805,7 +805,7 @@ class HqlSpecificationTests { @Test void theRest31() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o.shippingAddress.state FROM Order o """); @@ -814,7 +814,7 @@ class HqlSpecificationTests { @Test void theRest32() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l """); @@ -823,7 +823,7 @@ class HqlSpecificationTests { @Test void theRest33() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS NOT EMPTY @@ -833,7 +833,7 @@ class HqlSpecificationTests { @Test void theRest34() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -843,7 +843,7 @@ class HqlSpecificationTests { @Test void theRest35() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.shipped = FALSE @@ -853,7 +853,7 @@ class HqlSpecificationTests { @Test void theRest36() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE @@ -866,7 +866,7 @@ class HqlSpecificationTests { @Test void theRest37() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress <> o.billingAddress @@ -876,7 +876,7 @@ class HqlSpecificationTests { @Test void theRest38() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.product.name = ?1 @@ -886,78 +886,78 @@ class HqlSpecificationTests { @Test void hqlQueries() { - HqlQueryParser.parse("from Person"); - HqlQueryParser.parse("select local datetime"); - HqlQueryParser.parse("from Person p select p.name"); - HqlQueryParser.parse("update Person set nickName = 'Nacho' " + // + HqlQueryParser.parseQuery("from Person"); + HqlQueryParser.parseQuery("select local datetime"); + HqlQueryParser.parseQuery("from Person p select p.name"); + HqlQueryParser.parseQuery("update Person set nickName = 'Nacho' " + // "where name = 'Ignacio'"); - HqlQueryParser.parse("update Person p " + // + HqlQueryParser.parseQuery("update Person p " + // "set p.name = :newName " + // "where p.name = :oldName"); - HqlQueryParser.parse("update Person " + // + HqlQueryParser.parseQuery("update Person " + // "set name = :newName " + // "where name = :oldName"); - HqlQueryParser.parse("update versioned Person " + // + HqlQueryParser.parseQuery("update versioned Person " + // "set name = :newName " + // "where name = :oldName"); - HqlQueryParser.parse("insert Person (id, name) " + // + HqlQueryParser.parseQuery("insert Person (id, name) " + // "values (100L, 'Jane Doe')"); - HqlQueryParser.parse("insert Person (id, name) " + // + HqlQueryParser.parseQuery("insert Person (id, name) " + // "values (101L, 'J A Doe III'), " + // "(102L, 'J X Doe'), " + // "(103L, 'John Doe, Jr')"); - HqlQueryParser.parse("insert into Partner (id, name) " + // + HqlQueryParser.parseQuery("insert into Partner (id, name) " + // "select p.id, p.name " + // "from Person p "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name like 'Joe'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name like 'Joe''s'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.id = 1"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.id = 1L"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration > 100.5"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration > 100.5F"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration > 1e+2"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration > 1e+2F"); - HqlQueryParser.parse("from Phone ph " + // + HqlQueryParser.parseQuery("from Phone ph " + // "where ph.type = LAND_LINE"); - HqlQueryParser.parse("select java.lang.Math.PI"); - HqlQueryParser.parse("select 'Customer ' || p.name " + // + HqlQueryParser.parseQuery("select java.lang.Math.PI"); + HqlQueryParser.parseQuery("select 'Customer ' || p.name " + // "from Person p " + // "where p.id = 1"); - HqlQueryParser.parse("select sum(ch.duration) * :multiplier " + // + HqlQueryParser.parseQuery("select sum(ch.duration) * :multiplier " + // "from Person pr " + // "join pr.phones ph " + // "join ph.callHistory ch " + // "where ph.id = 1L "); - HqlQueryParser.parse("select year(local date) - year(p.createdOn) " + // + HqlQueryParser.parseQuery("select year(local date) - year(p.createdOn) " + // "from Person p " + // "where p.id = 1L"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where year(local date) - year(p.createdOn) > 1"); - HqlQueryParser.parse("select " + // + HqlQueryParser.parseQuery("select " + // " case p.nickName " + // " when 'NA' " + // " then '' " + // " else p.nickName " + // " end " + // "from Person p"); - HqlQueryParser.parse("select " + // + HqlQueryParser.parseQuery("select " + // " case " + // " when p.nickName is null " + // " then " + // @@ -969,162 +969,162 @@ class HqlSpecificationTests { " else p.nickName " + // " end " + // "from Person p"); - HqlQueryParser.parse("select " + // + HqlQueryParser.parseQuery("select " + // " case when p.nickName is null " + // " then p.id * 1000 " + // " else p.id " + // " end " + // "from Person p " + // "order by p.id"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where type(p) = CreditCardPayment"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where type(p) = :type"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where length(treat(p as CreditCardPayment).cardNumber) between 16 and 20"); - HqlQueryParser.parse("select nullif(p.nickName, p.name) " + // + HqlQueryParser.parseQuery("select nullif(p.nickName, p.name) " + // "from Person p"); - HqlQueryParser.parse("select " + // + HqlQueryParser.parseQuery("select " + // " case" + // " when p.nickName = p.name" + // " then null" + // " else p.nickName" + // " end " + // "from Person p"); - HqlQueryParser.parse("select coalesce(p.nickName, '') " + // + HqlQueryParser.parseQuery("select coalesce(p.nickName, '') " + // "from Person p"); - HqlQueryParser.parse("select coalesce(p.nickName, p.name, '') " + // + HqlQueryParser.parseQuery("select coalesce(p.nickName, p.name, '') " + // "from Person p"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where size(p.phones) >= 2"); - HqlQueryParser.parse("select concat(p.number, ' : ' , cast(c.duration as string)) " + // + HqlQueryParser.parseQuery("select concat(p.number, ' : ' , cast(c.duration as string)) " + // "from Call c " + // "join c.phone p"); - HqlQueryParser.parse("select substring(p.number, 1, 2) " + // + HqlQueryParser.parseQuery("select substring(p.number, 1, 2) " + // "from Call c " + // "join c.phone p"); - HqlQueryParser.parse("select upper(p.name) " + // + HqlQueryParser.parseQuery("select upper(p.name) " + // "from Person p "); - HqlQueryParser.parse("select lower(p.name) " + // + HqlQueryParser.parseQuery("select lower(p.name) " + // "from Person p "); - HqlQueryParser.parse("select trim(p.name) " + // + HqlQueryParser.parseQuery("select trim(p.name) " + // "from Person p "); - HqlQueryParser.parse("select trim(leading ' ' from p.name) " + // + HqlQueryParser.parseQuery("select trim(leading ' ' from p.name) " + // "from Person p "); - HqlQueryParser.parse("select length(p.name) " + // + HqlQueryParser.parseQuery("select length(p.name) " + // "from Person p "); - HqlQueryParser.parse("select locate('John', p.name) " + // + HqlQueryParser.parseQuery("select locate('John', p.name) " + // "from Person p "); - HqlQueryParser.parse("select abs(c.duration) " + // + HqlQueryParser.parseQuery("select abs(c.duration) " + // "from Call c "); - HqlQueryParser.parse("select mod(c.duration, 10) " + // + HqlQueryParser.parseQuery("select mod(c.duration, 10) " + // "from Call c "); - HqlQueryParser.parse("select sqrt(c.duration) " + // + HqlQueryParser.parseQuery("select sqrt(c.duration) " + // "from Call c "); - HqlQueryParser.parse("select cast(c.duration as String) " + // + HqlQueryParser.parseQuery("select cast(c.duration as String) " + // "from Call c "); - HqlQueryParser.parse("select str(c.timestamp) " + // + HqlQueryParser.parseQuery("select str(c.timestamp) " + // "from Call c "); - HqlQueryParser.parse("select str(cast(duration as float) / 60, 4, 2) " + // + HqlQueryParser.parseQuery("select str(cast(duration as float) / 60, 4, 2) " + // "from Call c "); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where extract(date from c.timestamp) = local date"); - HqlQueryParser.parse("select extract(year from c.timestamp) " + // + HqlQueryParser.parseQuery("select extract(year from c.timestamp) " + // "from Call c "); - HqlQueryParser.parse("select year(c.timestamp) " + // + HqlQueryParser.parseQuery("select year(c.timestamp) " + // "from Call c "); - HqlQueryParser.parse("select var_samp(c.duration) as sampvar, var_pop(c.duration) as popvar " + // + HqlQueryParser.parseQuery("select var_samp(c.duration) as sampvar, var_pop(c.duration) as popvar " + // "from Call c "); - HqlQueryParser.parse("select bit_length(c.phone.number) " + // + HqlQueryParser.parseQuery("select bit_length(c.phone.number) " + // "from Call c "); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration < 30 "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name like 'John%' "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.createdOn > '1950-01-01' "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where p.type = 'MOBILE' "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where p.completed = true "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where type(p) = WireTransferPayment "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p, Phone ph " + // "where p.person = ph.person "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "join p.phones ph " + // "where p.id = 1L and index(ph) between 0 and 3"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.createdOn between '1999-01-01' and '2001-01-02'"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "where c.duration between 5 and 20"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name between 'H' and 'M'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.nickName is not null"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.nickName is null"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name like 'Jo%'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name not like 'Jo%'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.name like 'Dr|_%' escape '|'"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p " + // "where type(p) in (CreditCardPayment, WireTransferPayment)"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where type in ('MOBILE', 'LAND_LINE')"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where type in :types"); - HqlQueryParser.parse("select distinct p " + // + HqlQueryParser.parseQuery("select distinct p " + // "from Phone p " + // "where p.person.id in (" + // " select py.person.id " + // " from Payment py" + // " where py.completed = true and py.amount > 50 " + // ")"); - HqlQueryParser.parse("select distinct p " + // + HqlQueryParser.parseQuery("select distinct p " + // "from Phone p " + // "where p.person in (" + // " select py.person " + // " from Payment py" + // " where py.completed = true and py.amount > 50 " + // ")"); - HqlQueryParser.parse("select distinct p " + // + HqlQueryParser.parseQuery("select distinct p " + // "from Payment p " + // "where (p.amount, p.completed) in (" + // " (50, true)," + // " (100, true)," + // " (5, false)" + // ")"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where 1 in indices(p.phones)"); - HqlQueryParser.parse("select distinct p.person " + // + HqlQueryParser.parseQuery("select distinct p.person " + // "from Phone p " + // "join p.calls c " + // "where 50 > all (" + // @@ -1132,96 +1132,96 @@ class HqlSpecificationTests { " from Call" + // " where phone = p " + // ") "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where local date > all elements(p.repairTimestamps)"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where :phone = some elements(p.phones)"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where :phone member of p.phones"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where exists elements(p.phones)"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.phones is empty"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.phones is not empty"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.phones is not empty"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where 'Home address' member of p.addresses"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where 'Home address' not member of p.addresses"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from org.hibernate.userguide.model.Person p"); - HqlQueryParser.parse("select distinct pr, ph " + // + HqlQueryParser.parseQuery("select distinct pr, ph " + // "from Person pr, Phone ph " + // "where ph.person = pr and ph is not null"); - HqlQueryParser.parse("select distinct pr1 " + // + HqlQueryParser.parseQuery("select distinct pr1 " + // "from Person pr1, Person pr2 " + // "where pr1.id <> pr2.id " + // " and pr1.address = pr2.address " + // " and pr1.createdOn < pr2.createdOn"); - HqlQueryParser.parse("select distinct pr, ph " + // + HqlQueryParser.parseQuery("select distinct pr, ph " + // "from Person pr cross join Phone ph " + // "where ph.person = pr and ph is not null"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Payment p "); - HqlQueryParser.parse("select d.owner, d.payed " + // + HqlQueryParser.parseQuery("select d.owner, d.payed " + // "from (" + // " select p.person as owner, c.payment is not null as payed " + // " from Call c " + // " join c.phone p " + // " where p.number = :phoneNumber) d"); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "join Phone ph on ph.person = pr " + // "where ph.type = :phoneType"); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "join pr.phones ph " + // "where ph.type = :phoneType"); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "inner join pr.phones ph " + // "where ph.type = :phoneType"); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "left join pr.phones ph " + // "where ph is null " + // " or ph.type = :phoneType"); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "left outer join pr.phones ph " + // "where ph is null " + // " or ph.type = :phoneType"); - HqlQueryParser.parse("select pr.name, ph.number " + // + HqlQueryParser.parseQuery("select pr.name, ph.number " + // "from Person pr " + // "left join pr.phones ph with ph.type = :phoneType "); - HqlQueryParser.parse("select pr.name, ph.number " + // + HqlQueryParser.parseQuery("select pr.name, ph.number " + // "from Person pr " + // "left join pr.phones ph on ph.type = :phoneType "); - HqlQueryParser.parse("select distinct pr " + // + HqlQueryParser.parseQuery("select distinct pr " + // "from Person pr " + // "left join fetch pr.phones "); - HqlQueryParser.parse("select a, ccp " + // + HqlQueryParser.parseQuery("select a, ccp " + // "from Account a " + // "join treat(a.payments as CreditCardPayment) ccp " + // "where length(ccp.cardNumber) between 16 and 20"); - HqlQueryParser.parse("select c, ccp " + // + HqlQueryParser.parseQuery("select c, ccp " + // "from Call c " + // "join treat(c.payment as CreditCardPayment) ccp " + // "where length(ccp.cardNumber) between 16 and 20"); - HqlQueryParser.parse("select longest.duration " + // + HqlQueryParser.parseQuery("select longest.duration " + // "from Phone p " + // "left join lateral (" + // " select c.duration as duration " + // @@ -1230,74 +1230,74 @@ class HqlSpecificationTests { " limit 1 " + // " ) longest " + // "where p.number = :phoneNumber"); - HqlQueryParser.parse("select ph " + // + HqlQueryParser.parseQuery("select ph " + // "from Phone ph " + // "where ph.person.address = :address "); - HqlQueryParser.parse("select ph " + // + HqlQueryParser.parseQuery("select ph " + // "from Phone ph " + // "join ph.person pr " + // "where pr.address = :address "); - HqlQueryParser.parse("select ph " + // + HqlQueryParser.parseQuery("select ph " + // "from Phone ph " + // "where ph.person.address = :address " + // " and ph.person.createdOn > :timestamp"); - HqlQueryParser.parse("select ph " + // + HqlQueryParser.parseQuery("select ph " + // "from Phone ph " + // "inner join ph.person pr " + // "where pr.address = :address " + // " and pr.createdOn > :timestamp"); - HqlQueryParser.parse("select ph " + // + HqlQueryParser.parseQuery("select ph " + // "from Person pr " + // "join pr.phones ph " + // "join ph.calls c " + // "where pr.address = :address " + // " and c.duration > :duration"); - HqlQueryParser.parse("select ch " + // + HqlQueryParser.parseQuery("select ch " + // "from Phone ph " + // "join ph.callHistory ch " + // "where ph.id = :id "); - HqlQueryParser.parse("select value(ch) " + // + HqlQueryParser.parseQuery("select value(ch) " + // "from Phone ph " + // "join ph.callHistory ch " + // "where ph.id = :id "); - HqlQueryParser.parse("select key(ch) " + // + HqlQueryParser.parseQuery("select key(ch) " + // "from Phone ph " + // "join ph.callHistory ch " + // "where ph.id = :id "); - HqlQueryParser.parse("select key(ch) " + // + HqlQueryParser.parseQuery("select key(ch) " + // "from Phone ph " + // "join ph.callHistory ch " + // "where ph.id = :id "); - HqlQueryParser.parse("select entry(ch) " + // + HqlQueryParser.parseQuery("select entry(ch) " + // "from Phone ph " + // "join ph.callHistory ch " + // "where ph.id = :id "); - HqlQueryParser.parse("select sum(ch.duration) " + // + HqlQueryParser.parseQuery("select sum(ch.duration) " + // "from Person pr " + // "join pr.phones ph " + // "join ph.callHistory ch " + // "where ph.id = :id " + // " and index(ph) = :phoneIndex"); - HqlQueryParser.parse("select value(ph.callHistory) " + // + HqlQueryParser.parseQuery("select value(ph.callHistory) " + // "from Phone ph " + // "where ph.id = :id "); - HqlQueryParser.parse("select key(ph.callHistory) " + // + HqlQueryParser.parseQuery("select key(ph.callHistory) " + // "from Phone ph " + // "where ph.id = :id "); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.phones[0].type = LAND_LINE"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where p.addresses['HOME'] = :address"); - HqlQueryParser.parse("select pr " + // + HqlQueryParser.parseQuery("select pr " + // "from Person pr " + // "where pr.phones[max(indices(pr.phones))].type = 'LAND_LINE'"); - HqlQueryParser.parse("select p.name, p.nickName " + // + HqlQueryParser.parseQuery("select p.name, p.nickName " + // "from Person p "); - HqlQueryParser.parse("select p.name as name, p.nickName as nickName " + // + HqlQueryParser.parseQuery("select p.name as name, p.nickName as nickName " + // "from Person p "); - HqlQueryParser.parse("select new org.hibernate.userguide.hql.CallStatistics(" + // + HqlQueryParser.parseQuery("select new org.hibernate.userguide.hql.CallStatistics(" + // " count(c), " + // " sum(c.duration), " + // " min(c.duration), " + // @@ -1305,7 +1305,7 @@ class HqlSpecificationTests { " avg(c.duration)" + // ") " + // "from Call c "); - HqlQueryParser.parse("select new map(" + // + HqlQueryParser.parseQuery("select new map(" + // " p.number as phoneNumber , " + // " sum(c.duration) as totalDuration, " + // " avg(c.duration) as averageDuration " + // @@ -1313,86 +1313,86 @@ class HqlSpecificationTests { "from Call c " + // "join c.phone p " + // "group by p.number "); - HqlQueryParser.parse("select new list(" + // + HqlQueryParser.parseQuery("select new list(" + // " p.number, " + // " c.duration " + // ") " + // "from Call c " + // "join c.phone p "); - HqlQueryParser.parse("select distinct p.lastName " + // + HqlQueryParser.parseQuery("select distinct p.lastName " + // "from Person p"); - HqlQueryParser.parse("select " + // + HqlQueryParser.parseQuery("select " + // " count(c), " + // " sum(c.duration), " + // " min(c.duration), " + // " max(c.duration), " + // " avg(c.duration) " + // "from Call c "); - HqlQueryParser.parse("select count(distinct c.phone) " + // + HqlQueryParser.parseQuery("select count(distinct c.phone) " + // "from Call c "); - HqlQueryParser.parse("select p.number, count(c) " + // + HqlQueryParser.parseQuery("select p.number, count(c) " + // "from Call c " + // "join c.phone p " + // "group by p.number"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where max(elements(p.calls)) = :call"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "where min(elements(p.calls)) = :call"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "where max(indices(p.phones)) = 0"); - HqlQueryParser.parse("select count(c) filter (where c.duration < 30) " + // + HqlQueryParser.parseQuery("select count(c) filter (where c.duration < 30) " + // "from Call c "); - HqlQueryParser.parse("select p.number, count(c) filter (where c.duration < 30) " + // + HqlQueryParser.parseQuery("select p.number, count(c) filter (where c.duration < 30) " + // "from Call c " + // "join c.phone p " + // "group by p.number"); - HqlQueryParser.parse("select listagg(p.number, ', ') within group (order by p.type,p.number) " + // + HqlQueryParser.parseQuery("select listagg(p.number, ', ') within group (order by p.type,p.number) " + // "from Phone p " + // "group by p.person"); - HqlQueryParser.parse("select sum(c.duration) " + // + HqlQueryParser.parseQuery("select sum(c.duration) " + // "from Call c "); - HqlQueryParser.parse("select p.name, sum(c.duration) " + // + HqlQueryParser.parseQuery("select p.name, sum(c.duration) " + // "from Call c " + // "join c.phone ph " + // "join ph.person p " + // "group by p.name"); - HqlQueryParser.parse("select p, sum(c.duration) " + // + HqlQueryParser.parseQuery("select p, sum(c.duration) " + // "from Call c " + // "join c.phone ph " + // "join ph.person p " + // "group by p"); - HqlQueryParser.parse("select p.name, sum(c.duration) " + // + HqlQueryParser.parseQuery("select p.name, sum(c.duration) " + // "from Call c " + // "join c.phone ph " + // "join ph.person p " + // "group by p.name " + // "having sum(c.duration) > 1000"); - HqlQueryParser.parse("select p.name from Person p " + // + HqlQueryParser.parseQuery("select p.name from Person p " + // "union " + // "select p.nickName from Person p where p.nickName is not null"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Person p " + // "order by p.name"); - HqlQueryParser.parse("select p.name, sum(c.duration) as total " + // + HqlQueryParser.parseQuery("select p.name, sum(c.duration) as total " + // "from Call c " + // "join c.phone ph " + // "join ph.person p " + // "group by p.name " + // "order by total"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "join c.phone p " + // "order by p.number " + // "limit 50"); - HqlQueryParser.parse("select c " + // + HqlQueryParser.parseQuery("select c " + // "from Call c " + // "join c.phone p " + // "order by p.number " + // "fetch first 50 rows only"); - HqlQueryParser.parse("select p " + // + HqlQueryParser.parseQuery("select p " + // "from Phone p " + // "join fetch p.calls " + // "order by p " + // diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java index 0d65402c3..c16fcd9ce 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlParserQueryEnhancerUnitTests.java @@ -22,7 +22,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; /** - * TCK Tests for {@link JpqlQueryParser} mixed into {@link JpaQueryParsingEnhancer}. + * TCK Tests for {@link JpqlQueryParser} mixed into {@link JpaQueryEnhancer}. * * @author Greg Turnquist * @since 3.1 @@ -33,7 +33,7 @@ public class JpqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests { @Override QueryEnhancer createQueryEnhancer(DeclaredQuery declaredQuery) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(declaredQuery)); + return JpaQueryEnhancer.forJpql(declaredQuery); } @Override diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java index fecc3470c..e0124b690 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java @@ -46,7 +46,7 @@ class JpqlQueryRendererTests { JpqlLexer lexer = new JpqlLexer(CharStreams.fromString(query)); JpqlParser parser = new JpqlParser(new CommonTokenStream(lexer)); - parser.addErrorListener(new JpaQueryParsingSyntaxErrorListener()); + parser.addErrorListener(new BadJpqlGrammarErrorListener(query)); JpqlParser.StartContext parsedQuery = parser.start(); @@ -762,7 +762,7 @@ class JpqlQueryRendererTests { @Test void theRest24() { - assertThatExceptionOfType(JpaQueryParsingSyntaxError.class).isThrownBy(() -> { + assertThatExceptionOfType(BadJpqlGrammarException.class).isThrownBy(() -> { assertQuery(""" SELECT p.product_name FROM Order o, IN(o.lineItems) l JOIN o.customer c diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java index c09469742..557df5515 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java @@ -27,7 +27,7 @@ import org.springframework.data.jpa.domain.JpaSort; import org.springframework.lang.Nullable; /** - * Verify that JPQL queries are properly transformed through the {@link JpaQueryParsingEnhancer} and the + * Verify that JPQL queries are properly transformed through the {@link JpaQueryEnhancer} and the * {@link JpqlQueryParser}. * * @author Greg Turnquist @@ -117,7 +117,7 @@ class JpqlQueryTransformerTests { var original = "select e from Employee e join e.manager m"; // when - var results = createQueryFor(original, null); + var results = createQueryFor(original, Sort.unsorted()); // then assertThat(results).isEqualTo("select e from Employee e join e.manager m"); @@ -197,12 +197,12 @@ class JpqlQueryTransformerTests { Sort sort = Sort.by(Sort.Order.desc("age")); - assertThat(new JpaQueryParsingEnhancer(new JpqlQueryParser("select u\n" + // + assertThat(newParser("select u\n" + // "from user u\n" + // "where exists (select u2\n" + // "from user u2\n" + // ")\n" + // - "")).applySorting(sort)).isEqualToIgnoringWhitespace("select u\n" + // + "").applySorting(sort)).isEqualToIgnoringWhitespace("select u\n" + // "from user u\n" + // "where exists (select u2\n" + // "from user u2\n" + // @@ -679,7 +679,7 @@ class JpqlQueryTransformerTests { } private String createQueryFor(String query, Sort sort) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(query)).applySorting(sort); + return newParser(query).applySorting(sort); } private String createCountQueryFor(String query) { @@ -687,18 +687,22 @@ class JpqlQueryTransformerTests { } private String createCountQueryFor(String original, @Nullable String countProjection) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(original)).createCountQueryFor(countProjection); + return newParser(original).createCountQueryFor(countProjection); } private String alias(String query) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(query)).detectAlias(); + return newParser(query).detectAlias(); } private boolean hasConstructorExpression(String query) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(query)).hasConstructorExpression(); + return newParser(query).hasConstructorExpression(); } private String projection(String query) { - return new JpaQueryParsingEnhancer(new JpqlQueryParser(query)).getProjection(); + return newParser(query).getProjection(); + } + + private QueryEnhancer newParser(String query) { + return JpaQueryEnhancer.forJpql(DeclaredQuery.of(query, false)); } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java index 1451e72ce..df12231d4 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlSpecificationTests.java @@ -39,7 +39,7 @@ class JpqlSpecificationTests { @Test void joinExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order AS o JOIN o.lineItems AS l WHERE l.shipped = FALSE @@ -53,7 +53,7 @@ class JpqlSpecificationTests { @Test void joinExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l JOIN l.product p WHERE p.productType = 'office_supplies' @@ -66,7 +66,7 @@ class JpqlSpecificationTests { @Test void rangeVariableDeclarations() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o1 FROM Order o1, Order o2 WHERE o1.quantity > o2.quantity AND @@ -81,7 +81,7 @@ class JpqlSpecificationTests { @Test void pathExpressionsExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT i.name, VALUE(p) FROM Item i JOIN i.photos p WHERE KEY(p) LIKE '%egret' @@ -94,7 +94,7 @@ class JpqlSpecificationTests { @Test void pathExpressionsExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT i.name, p FROM Item i JOIN i.photos p WHERE KEY(p) LIKE '%egret' @@ -107,7 +107,7 @@ class JpqlSpecificationTests { @Test void pathExpressionsExample3() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p """); @@ -119,7 +119,7 @@ class JpqlSpecificationTests { @Test void pathExpressionsExample4() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE e.contactInfo.address.zipcode = '95054' @@ -129,7 +129,7 @@ class JpqlSpecificationTests { @Test void pathExpressionSyntaxExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT l.product FROM Order AS o JOIN o.lineItems l """); @@ -138,7 +138,7 @@ class JpqlSpecificationTests { @Test void joinsExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize """); } @@ -146,7 +146,7 @@ class JpqlSpecificationTests { @Test void joinsExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1 """); } @@ -154,7 +154,7 @@ class JpqlSpecificationTests { @Test void joinsInnerExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1 """); } @@ -162,7 +162,7 @@ class JpqlSpecificationTests { @Test void joinsInExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1 """); } @@ -170,7 +170,7 @@ class JpqlSpecificationTests { @Test void doubleJoinExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo c JOIN c.phones p WHERE c.address.zipcode = '95054' @@ -180,7 +180,7 @@ class JpqlSpecificationTests { @Test void leftJoinExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p GROUP BY s.name @@ -190,7 +190,7 @@ class JpqlSpecificationTests { @Test void leftJoinOnExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p ON p.status = 'inStock' @@ -201,7 +201,7 @@ class JpqlSpecificationTests { @Test void leftJoinWhereExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT s.name, COUNT(p) FROM Suppliers s LEFT JOIN s.products p WHERE p.status = 'inStock' @@ -212,7 +212,7 @@ class JpqlSpecificationTests { @Test void leftJoinFetchExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT d FROM Department d LEFT JOIN FETCH d.employees WHERE d.deptno = 1 @@ -222,7 +222,7 @@ class JpqlSpecificationTests { @Test void collectionMemberExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.product.productType = 'office_supplies' @@ -232,7 +232,7 @@ class JpqlSpecificationTests { @Test void collectionMemberInExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o, IN(o.lineItems) l WHERE l.product.productType = 'office_supplies' @@ -242,7 +242,7 @@ class JpqlSpecificationTests { @Test void fromClauseExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order AS o JOIN o.lineItems l JOIN l.product p """); @@ -251,7 +251,7 @@ class JpqlSpecificationTests { @Test void fromClauseDowncastingExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT b.name, b.ISBN FROM Order o JOIN TREAT(o.product AS Book) b """); @@ -260,7 +260,7 @@ class JpqlSpecificationTests { @Test void fromClauseDowncastingExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp WHERE lp.budget > 1000 """); @@ -273,7 +273,7 @@ class JpqlSpecificationTests { @Disabled(SPEC_FAULT + "Use double-quotes when it should be using single-quotes for a string literal") void fromClauseDowncastingExample3_SPEC_BUG() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN e.projects p WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' @@ -284,7 +284,7 @@ class JpqlSpecificationTests { @Test void fromClauseDowncastingExample3fixed() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e JOIN e.projects p WHERE TREAT(p AS LargeProject).budget > 1000 OR TREAT(p AS SmallProject).name LIKE 'Persist%' @@ -295,7 +295,7 @@ class JpqlSpecificationTests { @Test void fromClauseDowncastingExample4() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TREAT(e AS Exempt).vacationDays > 10 OR TREAT(e AS Contractor).hours > 100 @@ -305,7 +305,7 @@ class JpqlSpecificationTests { @Test void pathExpressionsNamedParametersExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE c.status = :stat @@ -315,7 +315,7 @@ class JpqlSpecificationTests { @Test void betweenExpressionsExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT t FROM CreditCard c JOIN c.transactionHistory t WHERE c.holder.name = 'John Doe' AND INDEX(t) BETWEEN 0 AND 9 @@ -325,7 +325,7 @@ class JpqlSpecificationTests { @Test void isEmptyExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -335,7 +335,7 @@ class JpqlSpecificationTests { @Test void memberOfExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames @@ -345,7 +345,7 @@ class JpqlSpecificationTests { @Test void existsSubSelectExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -358,7 +358,7 @@ class JpqlSpecificationTests { @Test void allExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT emp FROM Employee emp WHERE emp.salary > ALL ( @@ -371,7 +371,7 @@ class JpqlSpecificationTests { @Test void existsSubSelectExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -384,7 +384,7 @@ class JpqlSpecificationTests { @Test void subselectNumericComparisonExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE (SELECT AVG(o.price) FROM c.orders o) > 100 @@ -394,7 +394,7 @@ class JpqlSpecificationTests { @Test void subselectNumericComparisonExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT goodCustomer FROM Customer goodCustomer WHERE goodCustomer.balanceOwed < ( @@ -405,7 +405,7 @@ class JpqlSpecificationTests { @Test void indexExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT w.name FROM Course c JOIN c.studentWaitlist w WHERE c.name = 'Calculus' @@ -420,7 +420,7 @@ class JpqlSpecificationTests { @Disabled(SPEC_FAULT + "FUNCTION calls needs a comparator") void functionInvocationExample_SPEC_BUG() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) @@ -430,7 +430,7 @@ class JpqlSpecificationTests { @Test void functionInvocationExampleWithCorrection() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @@ -440,7 +440,7 @@ class JpqlSpecificationTests { @Test void updateCaseExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Employee e SET e.salary = CASE WHEN e.rating = 1 THEN e.salary * 1.1 @@ -453,7 +453,7 @@ class JpqlSpecificationTests { @Test void updateCaseExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Employee e SET e.salary = CASE e.rating WHEN 1 THEN e.salary * 1.1 @@ -466,7 +466,7 @@ class JpqlSpecificationTests { @Test void selectCaseExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e.name, CASE TYPE(e) WHEN Exempt THEN 'Exempt' WHEN Contractor THEN 'Contractor' @@ -481,7 +481,7 @@ class JpqlSpecificationTests { @Test void selectCaseExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e.name, f.name, CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum ' @@ -496,7 +496,7 @@ class JpqlSpecificationTests { @Test void theRest() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) @@ -506,7 +506,7 @@ class JpqlSpecificationTests { @Test void theRest2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (:empType1, :empType2) @@ -516,7 +516,7 @@ class JpqlSpecificationTests { @Test void theRest3() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN :empTypes @@ -526,7 +526,7 @@ class JpqlSpecificationTests { @Test void theRest4() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT TYPE(e) FROM Employee e WHERE TYPE(e) <> Exempt @@ -536,7 +536,7 @@ class JpqlSpecificationTests { @Test void theRest5() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c.status, AVG(c.filledOrderCount), COUNT(c) FROM Customer c GROUP BY c.status @@ -547,7 +547,7 @@ class JpqlSpecificationTests { @Test void theRest6() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c.country, COUNT(c) FROM Customer c GROUP BY c.country @@ -558,7 +558,7 @@ class JpqlSpecificationTests { @Test void theRest7() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c, COUNT(o) FROM Customer c JOIN c.orders o GROUP BY c @@ -569,7 +569,7 @@ class JpqlSpecificationTests { @Test void theRest8() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c.id, c.status FROM Customer c JOIN c.orders o WHERE o.count > 100 @@ -579,7 +579,7 @@ class JpqlSpecificationTests { @Test void theRest9() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT v.location.street, KEY(i).title, VALUE(i) FROM VideoStore v JOIN v.videoInventory i WHERE v.location.zipcode = '94301' AND VALUE(i) > 0 @@ -589,7 +589,7 @@ class JpqlSpecificationTests { @Test void theRest10() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o.lineItems FROM Order AS o """); } @@ -597,7 +597,7 @@ class JpqlSpecificationTests { @Test void theRest11() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c, COUNT(l) AS itemCount FROM Customer c JOIN c.Orders o JOIN o.lineItems l WHERE c.address.state = 'CA' @@ -609,7 +609,7 @@ class JpqlSpecificationTests { @Test void theRest12() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT NEW com.acme.example.CustomerDetails(c.id, c.status, o.count) FROM Customer c JOIN c.orders o WHERE o.count > 100 @@ -619,7 +619,7 @@ class JpqlSpecificationTests { @Test void theRest13() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e.address AS addr FROM Employee e """); @@ -628,7 +628,7 @@ class JpqlSpecificationTests { @Test void theRest14() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) FROM Order o """); } @@ -636,7 +636,7 @@ class JpqlSpecificationTests { @Test void theRest15() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT SUM(l.price) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -646,7 +646,7 @@ class JpqlSpecificationTests { @Test void theRest16() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT COUNT(o) FROM Order o """); } @@ -654,7 +654,7 @@ class JpqlSpecificationTests { @Test void theRest17() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT COUNT(l.price) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -664,7 +664,7 @@ class JpqlSpecificationTests { @Test void theRest18() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT COUNT(l) FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' AND l.price IS NOT NULL @@ -674,7 +674,7 @@ class JpqlSpecificationTests { @Test void theRest19() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -685,7 +685,7 @@ class JpqlSpecificationTests { @Test void theRest20() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o.quantity, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -696,7 +696,7 @@ class JpqlSpecificationTests { @Test void theRest21() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o.quantity, o.cost*1.08 AS taxedCost, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' AND a.county = 'Santa Clara' @@ -707,7 +707,7 @@ class JpqlSpecificationTests { @Test void theRest22() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) as q, a.zipcode FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = 'CA' @@ -719,7 +719,7 @@ class JpqlSpecificationTests { @Test void theRest23() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p.product_name FROM Order o JOIN o.lineItems l JOIN l.product p JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -733,8 +733,8 @@ class JpqlSpecificationTests { @Test void theRest24() { - assertThatExceptionOfType(JpaQueryParsingSyntaxError.class).isThrownBy(() -> { - JpqlQueryParser.parse(""" + assertThatExceptionOfType(BadJpqlGrammarException.class).isThrownBy(() -> { + JpqlQueryParser.parseQuery(""" SELECT p.product_name FROM Order o, IN(o.lineItems) l JOIN o.customer c WHERE c.lastname = 'Smith' AND c.firstname = 'John' @@ -746,7 +746,7 @@ class JpqlSpecificationTests { @Test void theRest25() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -756,7 +756,7 @@ class JpqlSpecificationTests { @Test void theRest26() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -767,7 +767,7 @@ class JpqlSpecificationTests { @Test void theRest27() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Customer c SET c.status = 'outstanding' WHERE c.balance < 10000 @@ -777,7 +777,7 @@ class JpqlSpecificationTests { @Test void theRest28() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Employee e SET e.address.building = 22 WHERE e.address.building = 14 @@ -789,7 +789,7 @@ class JpqlSpecificationTests { @Test void theRest29() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o """); @@ -798,7 +798,7 @@ class JpqlSpecificationTests { @Test void theRest30() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress.state = 'CA' @@ -808,7 +808,7 @@ class JpqlSpecificationTests { @Test void theRest31() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o.shippingAddress.state FROM Order o """); @@ -817,7 +817,7 @@ class JpqlSpecificationTests { @Test void theRest32() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l """); @@ -826,7 +826,7 @@ class JpqlSpecificationTests { @Test void theRest33() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS NOT EMPTY @@ -836,7 +836,7 @@ class JpqlSpecificationTests { @Test void theRest34() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -846,7 +846,7 @@ class JpqlSpecificationTests { @Test void theRest35() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.shipped = FALSE @@ -856,7 +856,7 @@ class JpqlSpecificationTests { @Test void theRest36() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE @@ -869,7 +869,7 @@ class JpqlSpecificationTests { @Test void theRest37() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress <> o.billingAddress @@ -879,7 +879,7 @@ class JpqlSpecificationTests { @Test void theRest38() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l WHERE l.product.name = ?1 diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java index a6ec5fd3c..ef90549fd 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerFactoryUnitTests.java @@ -35,9 +35,9 @@ class QueryEnhancerFactoryUnitTests { QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(query); assertThat(queryEnhancer) // - .isInstanceOf(JpaQueryParsingEnhancer.class); + .isInstanceOf(JpaQueryEnhancer.class); - JpaQueryParsingEnhancer queryParsingEnhancer = (JpaQueryParsingEnhancer) queryEnhancer; + JpaQueryEnhancer queryParsingEnhancer = (JpaQueryEnhancer) queryEnhancer; assertThat(queryParsingEnhancer.getQueryParsingStrategy()).isInstanceOf(HqlQueryParser.class); } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java index f8c84c536..78427ece9 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/StringQueryUnitTests.java @@ -21,7 +21,6 @@ import java.util.Arrays; import java.util.List; import org.assertj.core.api.Assertions; -import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.Test; import org.springframework.data.jpa.repository.query.StringQuery.InParameterBinding; import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding; @@ -40,8 +39,6 @@ import org.springframework.data.repository.query.parser.Part.Type; */ class StringQueryUnitTests { - private SoftAssertions softly = new SoftAssertions(); - @Test // DATAJPA-341 void doesNotConsiderPlainLikeABinding() { @@ -115,7 +112,6 @@ class StringQueryUnitTests { assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-461 @@ -133,8 +129,6 @@ class StringQueryUnitTests { assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); assertNamedBinding(InParameterBinding.class, "names", bindings.get(1)); assertNamedBinding(ParameterBinding.class, "bar", bindings.get(2)); - - softly.assertAll(); } @Test // DATAJPA-461 @@ -151,7 +145,6 @@ class StringQueryUnitTests { assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-461 @@ -170,7 +163,6 @@ class StringQueryUnitTests { assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1)); assertPositionalBinding(ParameterBinding.class, 3, bindings.get(2)); - softly.assertAll(); } @Test // DATAJPA-373 @@ -193,7 +185,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-473 @@ -208,11 +199,8 @@ class StringQueryUnitTests { assertNamedBinding(LikeParameterBinding.class, "escapedWord", bindings.get(0)); assertNamedBinding(ParameterBinding.class, "word", bindings.get(1)); - softly.assertThat(query.getQueryString()) - .isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE :escapedWord ESCAPE '~'" - + " OR a.content LIKE :escapedWord ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC"); - - softly.assertAll(); + assertThat(query.getQueryString()).isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE :escapedWord ESCAPE '~'" + + " OR a.content LIKE :escapedWord ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC"); } @Test // DATAJPA-483 @@ -224,8 +212,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "statuses", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -238,7 +224,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "abonnés", bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-545 @@ -250,8 +235,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "øre", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -263,8 +246,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "생일", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -276,8 +257,6 @@ class StringQueryUnitTests { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "ab1babc생일233", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-362 @@ -301,27 +280,20 @@ class StringQueryUnitTests { StringQuery query = new StringQuery("select a from A a where a.b in ?#{#bs} and a.c in ?#{#cs}", true); String queryString = query.getQueryString(); - softly.assertThat(queryString).isEqualTo("select a from A a where a.b in ?1 and a.c in ?2"); - softly.assertThat(query.getParameterBindings().get(0).getExpression()).isEqualTo("#bs"); - softly.assertThat(query.getParameterBindings().get(1).getExpression()).isEqualTo("#cs"); - - softly.assertAll(); + assertThat(queryString).isEqualTo("select a from A a where a.b in ?1 and a.c in ?2"); + assertThat(query.getParameterBindings().get(0).getExpression()).isEqualTo("#bs"); + assertThat(query.getParameterBindings().get(1).getExpression()).isEqualTo("#cs"); } @Test // DATAJPA-864 void detectsConstructorExpressions() { - softly - .assertThat( - new StringQuery("select new com.example.Dto(a.foo, a.bar) from A a", false).hasConstructorExpression()) + assertThat( + new StringQuery("select new com.example.Dto(a.foo, a.bar) from A a", false).hasConstructorExpression()) + .isTrue(); + assertThat(new StringQuery("select new com.example.Dto (a.foo, a.bar) from A a", false).hasConstructorExpression()) .isTrue(); - softly - .assertThat( - new StringQuery("select new com.example.Dto (a.foo, a.bar) from A a", false).hasConstructorExpression()) - .isTrue(); - softly.assertThat(new StringQuery("select a from A a", true).hasConstructorExpression()).isFalse(); - - softly.assertAll(); + assertThat(new StringQuery("select a from A a", true).hasConstructorExpression()).isFalse(); } /** @@ -332,10 +304,8 @@ class StringQueryUnitTests { void detectsConstructorExpressionForDefaultConstructor() { // Parentheses required - softly.assertThat(new StringQuery("select new com.example.Dto(a.name) from A a", false).hasConstructorExpression()) + assertThat(new StringQuery("select new com.example.Dto(a.name) from A a", false).hasConstructorExpression()) .isTrue(); - - softly.assertAll(); } @Test // DATAJPA-1179 @@ -344,15 +314,13 @@ class StringQueryUnitTests { StringQuery query = new StringQuery("select a from A a where a.first = :#{#exp} or a.second = :#{#exp}", true); List bindings = query.getParameterBindings(); - softly.assertThat(bindings).isNotEmpty(); + assertThat(bindings).isNotEmpty(); for (ParameterBinding binding : bindings) { - softly.assertThat(binding.getName()).isNotNull(); - softly.assertThat(query.getQueryString()).contains(binding.getName()); - softly.assertThat(binding.getExpression()).isEqualTo("#exp"); + assertThat(binding.getName()).isNotNull(); + assertThat(query.getQueryString()).contains(binding.getName()); + assertThat(binding.getExpression()).isEqualTo("#exp"); } - - softly.assertAll(); } @Test // DATAJPA-1235 @@ -364,13 +332,11 @@ class StringQueryUnitTests { checkProjection("sect x, y, z from Entity something", "", "missing select", false); checkProjection("select x, y, z fron Entity something", "", "missing from", false); - - softly.assertAll(); } void checkProjection(String query, String expected, String description, boolean nativeQuery) { - softly.assertThat(new StringQuery(query, nativeQuery).getProjection()) // + assertThat(new StringQuery(query, nativeQuery).getProjection()) // .as("%s (%s)", description, query) // .isEqualTo(expected); } @@ -390,13 +356,11 @@ class StringQueryUnitTests { checkAlias("from User as bs", "bs", "ignored as", false); checkAlias("from User as AS", "AS", "ignored as using the second", false); checkAlias("from User asas", "asas", "asas is weird but legal", false); - - softly.assertAll(); } private void checkAlias(String query, String expected, String description, boolean nativeQuery) { - softly.assertThat(new StringQuery(query, nativeQuery).getAlias()) // + assertThat(new StringQuery(query, nativeQuery).getAlias()) // .as("%s (%s)", description, query) // .isEqualTo(expected); } @@ -430,8 +394,6 @@ class StringQueryUnitTests { checkHasNamedParameter("::id", false, "double colon with identifier", false); checkHasNamedParameter("\\:id", false, "escaped colon with identifier", false); checkHasNamedParameter("select something from x where id = #something", false, "hash", true); - - softly.assertAll(); } @Test // DATAJPA-1235 @@ -445,8 +407,6 @@ class StringQueryUnitTests { // checkNumberOfNamedParameters("select something from blah where x = \"'0\":name", 1, "single quote in double // quotes", // false); - - softly.assertAll(); } @Test // DATAJPA-1307 @@ -455,11 +415,9 @@ class StringQueryUnitTests { String queryString = "select u from User u where u.id in ? and u.names in ? and foo = ?"; StringQuery query = new StringQuery(queryString, false); - softly.assertThat(query.getQueryString()).isEqualTo(queryString); - softly.assertThat(query.hasParameterBindings()).isTrue(); - softly.assertThat(query.getParameterBindings()).hasSize(3); - - softly.assertAll(); + assertThat(query.getQueryString()).isEqualTo(queryString); + assertThat(query.hasParameterBindings()).isTrue(); + assertThat(query.getParameterBindings()).hasSize(3); } @Test // DATAJPA-1307 @@ -482,7 +440,7 @@ class StringQueryUnitTests { @Test // DATAJPA-1307 void makesUsageOfJdbcStyleParameterAvailable() { - softly.assertThat(new StringQuery("from Something something where something = ?", false).usesJdbcStyleParameters()) + assertThat(new StringQuery("from Something something where something = ?", false).usesJdbcStyleParameters()) .isTrue(); List testQueries = Arrays.asList( // @@ -493,13 +451,11 @@ class StringQueryUnitTests { for (String testQuery : testQueries) { - softly.assertThat(new StringQuery(testQuery, false) // + assertThat(new StringQuery(testQuery, false) // .usesJdbcStyleParameters()) // - .describedAs(testQuery) // - .isFalse(); + .describedAs(testQuery) // + .isFalse(); } - - softly.assertAll(); } @Test // DATAJPA-1307 @@ -508,11 +464,10 @@ class StringQueryUnitTests { String queryString = "select '? ' from dual"; StringQuery query = new StringQuery(queryString, true); - softly.assertThat(query.getQueryString()).isEqualTo(queryString); - softly.assertThat(query.hasParameterBindings()).isFalse(); - softly.assertThat(query.getParameterBindings()).isEmpty(); + assertThat(query.getQueryString()).isEqualTo(queryString); + assertThat(query.hasParameterBindings()).isFalse(); + assertThat(query.getParameterBindings()).isEmpty(); - softly.assertAll(); } @Test // DATAJPA-1318 @@ -527,7 +482,7 @@ class StringQueryUnitTests { "select a, b from C"); for (String queryString : queriesWithoutDefaultProjection) { - softly.assertThat(new StringQuery(queryString, true).isDefaultProjection()) // + assertThat(new StringQuery(queryString, true).isDefaultProjection()) // .describedAs(queryString) // .isFalse(); } @@ -544,12 +499,10 @@ class StringQueryUnitTests { ); for (String queryString : queriesWithDefaultProjection) { - softly.assertThat(new StringQuery(queryString, true).isDefaultProjection()) // + assertThat(new StringQuery(queryString, true).isDefaultProjection()) // .describedAs(queryString) // .isTrue(); } - - softly.assertAll(); } @Test // DATAJPA-1652 @@ -578,17 +531,17 @@ class StringQueryUnitTests { DeclaredQuery declaredQuery = DeclaredQuery.of(query, nativeQuery); - softly.assertThat(declaredQuery.hasNamedParameter()) // + assertThat(declaredQuery.hasNamedParameter()) // .describedAs("hasNamed Parameter " + label) // .isEqualTo(expectedSize > 0); - softly.assertThat(declaredQuery.getParameterBindings()) // + assertThat(declaredQuery.getParameterBindings()) // .describedAs("parameterBindings " + label) // .hasSize(expectedSize); } private void checkHasNamedParameter(String query, boolean expected, String label, boolean nativeQuery) { - softly.assertThat(new StringQuery(query, nativeQuery).hasNamedParameter()) // + assertThat(new StringQuery(query, nativeQuery).hasNamedParameter()) // .describedAs(String.format("<%s> (%s)", query, label)) // .isEqualTo(expected); } @@ -596,16 +549,16 @@ class StringQueryUnitTests { private void assertPositionalBinding(Class bindingType, Integer position, ParameterBinding expectedBinding) { - softly.assertThat(bindingType.isInstance(expectedBinding)).isTrue(); - softly.assertThat(expectedBinding).isNotNull(); - softly.assertThat(expectedBinding.hasPosition(position)).isTrue(); + assertThat(bindingType.isInstance(expectedBinding)).isTrue(); + assertThat(expectedBinding).isNotNull(); + assertThat(expectedBinding.hasPosition(position)).isTrue(); } private void assertNamedBinding(Class bindingType, String parameterName, ParameterBinding expectedBinding) { - softly.assertThat(bindingType.isInstance(expectedBinding)).isTrue(); - softly.assertThat(expectedBinding).isNotNull(); - softly.assertThat(expectedBinding.hasName(parameterName)).isTrue(); + assertThat(bindingType.isInstance(expectedBinding)).isTrue(); + assertThat(expectedBinding).isNotNull(); + assertThat(expectedBinding.hasName(parameterName)).isTrue(); } }