From 4aa2af5514fa399c9d14e003b01af0739856b986 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 14 Mar 2023 10:17:30 +0100 Subject: [PATCH] Polishing. Align ANTLR version with Hibernate's ANTLR version to avoid version mismatch reports to syserr. Rename types for consistent naming. Avoid duplicate creation of DeclaredQuery within the parsers. Lazify parsing and reuse cached results to avoid parser overhead. Add common configuration for parsers for consistent parser and lexer configurations. Simplify factory methods for HQL and JPQL parsers. Simplify condition flow for query enhancer creation. Refine fields for non-nullability requirements, avoid handing out null for a List. --- pom.xml | 4 +- ....java => BadJpqlGrammarErrorListener.java} | 13 +- ...rror.java => BadJpqlGrammarException.java} | 15 +- .../jpa/repository/query/HqlQueryParser.java | 27 +- .../repository/query/HqlQueryTransformer.java | 48 +- ...ingEnhancer.java => JpaQueryEnhancer.java} | 70 ++- ...Parser.java => JpaQueryParserSupport.java} | 171 ++++--- .../query/JpaQueryParsingToken.java | 4 - .../jpa/repository/query/JpqlQueryParser.java | 26 +- .../query/JpqlQueryTransformer.java | 43 +- .../query/QueryEnhancerFactory.java | 91 +--- .../HqlParserQueryEnhancerUnitTests.java | 6 +- .../query/HqlQueryRendererTests.java | 4 +- .../query/HqlQueryTransformerTests.java | 24 +- .../query/HqlSpecificationTests.java | 450 +++++++++--------- .../JpqlParserQueryEnhancerUnitTests.java | 4 +- .../query/JpqlQueryRendererTests.java | 4 +- .../query/JpqlQueryTransformerTests.java | 22 +- .../query/JpqlSpecificationTests.java | 160 +++---- .../query/QueryEnhancerFactoryUnitTests.java | 4 +- .../query/StringQueryUnitTests.java | 123 ++--- 21 files changed, 650 insertions(+), 663 deletions(-) rename spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/{JpaQueryParsingSyntaxErrorListener.java => BadJpqlGrammarErrorListener.java} (73%) rename spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/{JpaQueryParsingSyntaxError.java => BadJpqlGrammarException.java} (68%) rename spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/{JpaQueryParsingEnhancer.java => JpaQueryEnhancer.java} (59%) rename spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/{JpaQueryParser.java => JpaQueryParserSupport.java} (63%) diff --git a/pom.xml b/pom.xml index 1d5414c937..ba026cddc7 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 2017eb40a7..48805d4851 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.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 6224a8ce5b..00f5471014 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 1f65272d15..8f9cdcaacf 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.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 @@ protected ParserRuleContext parse() { * @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 27fd78dc85..dbb0f91558 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 @@ 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 @@ */ 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 @@ private static boolean isSubquery(ParserRuleContext ctx) { @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 @@ public List visitOrderedQuery(HqlParser.OrderedQueryContex tokens.addAll(visit(ctx.queryOrder())); } - if (this.sort != null && this.sort.isSorted()) { + if (this.sort.isSorted()) { if (ctx.queryOrder() != null) { @@ -125,7 +132,7 @@ public List visitOrderedQuery(HqlParser.OrderedQueryContex this.sort.forEach(order -> { - JpaQueryParser.checkSortExpression(order); + JpaQueryParserSupport.checkSortExpression(order); if (order.isIgnoreCase()) { tokens.add(TOKEN_LOWER_FUNC); @@ -160,7 +167,7 @@ public List visitOrderedQuery(HqlParser.OrderedQueryContex @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 @@ public List visitFromQuery(HqlParser.FromQueryContext ctx) @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 @@ public List visitQueryOrder(HqlParser.QueryOrderContext ct @Override public List visitFromRoot(HqlParser.FromRootContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); if (ctx.entityName() != null) { @@ -261,7 +268,7 @@ public List visitFromRoot(HqlParser.FromRootContext ctx) { @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 @@ public List visitAlias(HqlParser.AliasContext ctx) { @Override public List visitSelectClause(HqlParser.SelectClauseContext ctx) { - List tokens = new ArrayList<>(); + List tokens = newArrayList(); tokens.add(new JpaQueryParsingToken(ctx.SELECT())); @@ -321,8 +328,9 @@ public List visitSelectClause(HqlParser.SelectClauseContex tokens.addAll(selectionListTokens); } - if (projection == null && !isSubquery(ctx)) { + if (!projectionProcessed && !isSubquery(ctx)) { this.projection = selectionListTokens; + this.projectionProcessed = true; } return tokens; @@ -335,4 +343,8 @@ public List visitInstantiation(HqlParser.InstantiationCont 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 f6ca59eff7..b44ca445ce 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 @@ 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 @@ public JpaQueryParser getQueryParsingStrategy() { */ @Override public String applySorting(Sort sort) { - return queryParser.createQuery(sort); + return queryParser.renderSortedQuery(sort); } /** @@ -75,8 +101,8 @@ public String applySorting(Sort sort, String alias) { } /** - * 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 @@ public String detectAlias() { /** * Creates a count query from the original query, with no count projection. - * + * * @return Guaranteed to be not {@literal null}; */ @Override @@ -114,8 +140,8 @@ public boolean hasConstructorExpression() { } /** - * 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 @@ public String getProjection() { } /** - * 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 @@ public Set getJoinAliases() { } /** - * 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 c41a4e56cb..892476ad23 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 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 @@ String getQuery() { * * @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 @@ String createQuery(Sort sort) { 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 @@ String projection() { * * @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,39 +116,36 @@ String findAlias() { 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; } } /** - * 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. + * 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 order + * @param query + * @param lexer + * @param parser */ - static void checkSortExpression(Sort.Order order) { + static void configureParser(String query, Lexer lexer, Parser parser) { - if (order instanceof JpaSort.JpaOrder && ((JpaSort.JpaOrder) order).isUnsafe()) { - return; - } + BadJpqlGrammarErrorListener errorListener = new BadJpqlGrammarErrorListener(query); - if (PUNCTUATION_PATTERN.matcher(order.getProperty()).find()) { - throw new InvalidDataAccessApiUsageException(String.format(UNSAFE_PROPERTY_REFERENCE, order)); - } - } + lexer.removeErrorListeners(); + lexer.addErrorListener(errorListener); - /** - * Parse the JPA query using its corresponding ANTLR parser. - */ - protected abstract ParserRuleContext parse(); + 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 @@ -188,7 +154,7 @@ static void checkSortExpression(Sort.Order order) { * @param parsedQuery * @param sort can be {@literal null} */ - protected abstract List doCreateQuery(ParserRuleContext parsedQuery, Sort sort); + protected abstract List applySort(ParserRuleContext parsedQuery, Sort sort); /** * Create a {@link JpaQueryParsingToken}-based count query. @@ -197,8 +163,9 @@ static void checkSortExpression(Sort.Order order) { * @param countProjection */ protected abstract List doCreateCountQuery(ParserRuleContext parsedQuery, - @Nullable String countProjection); + @Nullable String countProjection); + @Nullable protected abstract String doFindAlias(ParserRuleContext parsedQuery); /** @@ -210,4 +177,56 @@ protected abstract List doCreateCountQuery(ParserRuleConte 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. + * + * @param order + */ + static void checkSortExpression(Sort.Order order) { + + if (order instanceof JpaSort.JpaOrder && ((JpaSort.JpaOrder) order).isUnsafe()) { + return; + } + + if (PUNCTUATION_PATTERN.matcher(order.getProperty()).find()) { + throw new InvalidDataAccessApiUsageException(String.format(UNSAFE_PROPERTY_REFERENCE, order)); + } + } + + /** + * Parser state capturing the lazily-parsed parser context. + */ + class ParseState { + + private final Lazy parsedQuery; + private volatile @Nullable BadJpqlGrammarException error; + private final String query; + + public ParseState(String query) { + this.query = query; + this.parsedQuery = Lazy.of(() -> parse(query)); + } + + public ParserRuleContext getContext() { + + BadJpqlGrammarException error = this.error; + + 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 9ef60b9710..5c221e62d4 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 @@ static void CLIP(List tokens) { */ 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 c7cfef600c..2db207e351 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.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 @@ protected ParserRuleContext parse() { * @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 fe030c598a..3749250ff6 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 @@ 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 @@ */ 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 @@ public boolean hasConstructorExpression() { @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 @@ public List visitSelect_statement(JpqlParser.Select_statem 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 @@ public List visitSelect_statement(JpqlParser.Select_statem this.sort.forEach(order -> { - JpaQueryParser.checkSortExpression(order); + JpaQueryParserSupport.checkSortExpression(order); if (order.isIgnoreCase()) { tokens.add(TOKEN_LOWER_FUNC); @@ -144,7 +150,7 @@ public List visitSelect_statement(JpqlParser.Select_statem @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 @@ public List visitSelect_clause(JpqlParser.Select_clauseCon 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 @@ public List visitSelect_clause(JpqlParser.Select_clauseCon tokens.addAll(selectItemTokens); } - if (projection == null) { + if (!projectionProcessed) { this.projection = selectItemTokens; + this.projectionProcessed = true; } return tokens; @@ -202,7 +209,7 @@ public List visitSelect_clause(JpqlParser.Select_clauseCon @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 @@ public List visitConstructor_expression(JpqlParser.Constru 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 e74952e134..74aa77e611 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 @@ 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 static QueryEnhancer forQuery(DeclaredQuery query) { 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); } - } - /** - * 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(); + return hibernatePresent ? JpaQueryEnhancer.forHql(query) : JpaQueryEnhancer.forJpql(query); } - /** - * 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 256f7af4fd..aefc1a2ca9 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.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 2a1c9aff02..c161fd5eab 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 @@ private static String parseWithoutChanges(String query) { 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 b8906ddc77..5dbc29f961 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.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 @@ void multipleAliasesShouldBeGathered() { 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 @@ void applySortingAccountsForNewlinesInSubselect() { 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 @@ private void assertCountQuery(String originalQuery, String countQuery) { } 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 @@ private String createCountQueryFor(String query) { } 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 179855736c..88d0656c7b 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 @@ void joinExample1() { @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 @@ void joinExample2() { @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 @@ void rangeVariableDeclarations() { @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 @@ WHERE KEY(p) LIKE '%egret' @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 @@ WHERE KEY(p) LIKE '%egret' @Test void pathExpressionsExample3() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p """); @@ -118,7 +118,7 @@ void pathExpressionsExample3() { @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 @@ void pathExpressionsExample4() { @Test void pathExpressionSyntaxExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT l.product FROM Order AS o JOIN o.lineItems l """); @@ -137,7 +137,7 @@ void pathExpressionSyntaxExample1() { @Test void joinsExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize """); } @@ -145,7 +145,7 @@ void joinsExample1() { @Test void joinsExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1 """); } @@ -153,7 +153,7 @@ void joinsExample2() { @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 @@ void joinsInnerExample() { @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 @@ SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1 @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 @@ void doubleJoinExample() { @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 @@ SELECT s.name, COUNT(p) @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 @@ SELECT s.name, COUNT(p) @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 @@ SELECT s.name, COUNT(p) @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 @@ void leftJoinFetchExample() { @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 @@ void collectionMemberExample() { @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 @@ FROM Order o, IN(o.lineItems) l @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 @@ void fromClauseExample() { @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 @@ FROM Order o JOIN TREAT(o.product AS Book) b @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 @@ SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp @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 @@ OR TREAT(p AS SmallProject).name LIKE 'Persist%' @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 @@ OR TREAT(p AS SmallProject).name LIKE 'Persist%' @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 @@ OR TREAT(e AS Contractor).hours > 100 @Test void pathExpressionsNamedParametersExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE c.status = :stat @@ -314,7 +314,7 @@ void pathExpressionsNamedParametersExample() { @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 @@ void betweenExpressionsExample() { @Test void isEmptyExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -334,7 +334,7 @@ void isEmptyExample() { @Test void memberOfExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames @@ -344,7 +344,7 @@ void memberOfExample() { @Test void existsSubSelectExample1() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -357,7 +357,7 @@ WHERE EXISTS ( @Test void allExample() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT emp FROM Employee emp WHERE emp.salary > ALL ( @@ -370,7 +370,7 @@ WHERE emp.salary > ALL ( @Test void existsSubSelectExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -383,7 +383,7 @@ WHERE EXISTS ( @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 @@ void subselectNumericComparisonExample1() { @Test void subselectNumericComparisonExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT goodCustomer FROM Customer goodCustomer WHERE goodCustomer.balanceOwed < ( @@ -404,7 +404,7 @@ SELECT AVG(c.balanceOwed)/2.0 FROM Customer c) @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 @@ AND INDEX(w) = 0 @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 @@ WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) @Test void functionInvocationExampleWithCorrection() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @@ -439,7 +439,7 @@ WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @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 @@ void updateCaseExample1() { @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 @@ void updateCaseExample2() { @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 @@ CASE TYPE(e) WHEN Exempt THEN 'Exempt' @Test void selectCaseExample2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e.name, f.name, CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum ' @@ -495,7 +495,7 @@ void selectCaseExample2() { @Test void theRest() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) @@ -505,7 +505,7 @@ WHERE TYPE(e) IN (Exempt, Contractor) @Test void theRest2() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (:empType1, :empType2) @@ -515,7 +515,7 @@ WHERE TYPE(e) IN (:empType1, :empType2) @Test void theRest3() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN :empTypes @@ -525,7 +525,7 @@ WHERE TYPE(e) IN :empTypes @Test void theRest4() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT TYPE(e) FROM Employee e WHERE TYPE(e) <> Exempt @@ -535,7 +535,7 @@ WHERE TYPE(e) <> Exempt @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 @@ HAVING c.status IN (1, 2) @Test void theRest6() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT c.country, COUNT(c) FROM Customer c GROUP BY c.country @@ -557,7 +557,7 @@ HAVING COUNT(c) > 30 @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 @@ HAVING COUNT(o) >= 5 @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 @@ void theRest8() { @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 @@ SELECT v.location.street, KEY(i).title, VALUE(i) @Test void theRest10() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o.lineItems FROM Order AS o """); } @@ -596,7 +596,7 @@ void theRest10() { @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 @@ SELECT c, COUNT(l) AS itemCount @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 @@ void theRest12() { @Test void theRest13() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT e.address AS addr FROM Employee e """); @@ -627,7 +627,7 @@ void theRest13() { @Test void theRest14() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) FROM Order o """); } @@ -635,7 +635,7 @@ SELECT AVG(o.quantity) FROM Order o @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 @@ SELECT SUM(l.price) @Test void theRest16() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT COUNT(o) FROM Order o """); } @@ -653,7 +653,7 @@ SELECT COUNT(o) FROM Order o @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 @@ SELECT COUNT(l.price) @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 @@ SELECT COUNT(l) @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 @@ void theRest19() { @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 @@ void theRest20() { @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 @@ void theRest21() { @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 @@ SELECT AVG(o.quantity) as q, a.zipcode @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 @@ void theRest23() { @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 @@ FROM Order o, IN(o.lineItems) l JOIN o.customer c @Test void theRest25() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -753,7 +753,7 @@ void theRest25() { @Test void theRest26() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -764,7 +764,7 @@ void theRest26() { @Test void theRest27() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Customer c SET c.status = 'outstanding' WHERE c.balance < 10000 @@ -774,7 +774,7 @@ void theRest27() { @Test void theRest28() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" UPDATE Employee e SET e.address.building = 22 WHERE e.address.building = 14 @@ -786,7 +786,7 @@ void theRest28() { @Test void theRest29() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o """); @@ -795,7 +795,7 @@ void theRest29() { @Test void theRest30() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress.state = 'CA' @@ -805,7 +805,7 @@ void theRest30() { @Test void theRest31() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o.shippingAddress.state FROM Order o """); @@ -814,7 +814,7 @@ void theRest31() { @Test void theRest32() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l """); @@ -823,7 +823,7 @@ void theRest32() { @Test void theRest33() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS NOT EMPTY @@ -833,7 +833,7 @@ void theRest33() { @Test void theRest34() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -843,7 +843,7 @@ void theRest34() { @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 @@ void theRest35() { @Test void theRest36() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE @@ -866,7 +866,7 @@ void theRest36() { @Test void theRest37() { - HqlQueryParser.parse(""" + HqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress <> o.billingAddress @@ -876,7 +876,7 @@ void theRest37() { @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 @@ void theRest38() { @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 @@ void hqlQueries() { " 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 @@ void hqlQueries() { " 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 @@ void hqlQueries() { " 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 @@ void hqlQueries() { " 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 @@ void hqlQueries() { "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 0d65402c33..c16fcd9ce0 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.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 fecc3470ca..e0124b6907 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 @@ private static String parseWithoutChanges(String query) { 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 @@ void theRest23() { @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 c09469742a..557df55156 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.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 @@ void multipleAliasesShouldBeGathered() { 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 @@ void applySortingAccountsForNewlinesInSubselect() { 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 @@ private void assertCountQuery(String originalQuery, String countQuery) { } 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 @@ private String createCountQueryFor(String query) { } 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 1451e72ced..df12231d43 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 @@ void joinExample1() { @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 @@ void joinExample2() { @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 @@ void rangeVariableDeclarations() { @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 @@ WHERE KEY(p) LIKE '%egret' @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 @@ WHERE KEY(p) LIKE '%egret' @Test void pathExpressionsExample3() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p """); @@ -119,7 +119,7 @@ void pathExpressionsExample3() { @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 @@ void pathExpressionsExample4() { @Test void pathExpressionSyntaxExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT l.product FROM Order AS o JOIN o.lineItems l """); @@ -138,7 +138,7 @@ void pathExpressionSyntaxExample1() { @Test void joinsExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c, Employee e WHERE c.hatsize = e.shoesize """); } @@ -146,7 +146,7 @@ void joinsExample1() { @Test void joinsExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c JOIN c.orders o WHERE c.status = 1 """); } @@ -154,7 +154,7 @@ void joinsExample2() { @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 @@ void joinsInnerExample() { @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 @@ SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1 @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 @@ void doubleJoinExample() { @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 @@ SELECT s.name, COUNT(p) @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 @@ SELECT s.name, COUNT(p) @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 @@ SELECT s.name, COUNT(p) @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 @@ void leftJoinFetchExample() { @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 @@ void collectionMemberExample() { @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 @@ FROM Order o, IN(o.lineItems) l @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 @@ void fromClauseExample() { @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 @@ FROM Order o JOIN TREAT(o.product AS Book) b @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 @@ SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp @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 @@ OR TREAT(p AS SmallProject).name LIKE 'Persist%' @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 @@ OR TREAT(p AS SmallProject).name LIKE 'Persist%' @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 @@ OR TREAT(e AS Contractor).hours > 100 @Test void pathExpressionsNamedParametersExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE c.status = :stat @@ -315,7 +315,7 @@ void pathExpressionsNamedParametersExample() { @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 @@ void betweenExpressionsExample() { @Test void isEmptyExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -335,7 +335,7 @@ void isEmptyExample() { @Test void memberOfExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT p FROM Person p WHERE 'Joe' MEMBER OF p.nicknames @@ -345,7 +345,7 @@ void memberOfExample() { @Test void existsSubSelectExample1() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -358,7 +358,7 @@ WHERE EXISTS ( @Test void allExample() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT emp FROM Employee emp WHERE emp.salary > ALL ( @@ -371,7 +371,7 @@ WHERE emp.salary > ALL ( @Test void existsSubSelectExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT emp FROM Employee emp WHERE EXISTS ( @@ -384,7 +384,7 @@ WHERE EXISTS ( @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 @@ void subselectNumericComparisonExample1() { @Test void subselectNumericComparisonExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT goodCustomer FROM Customer goodCustomer WHERE goodCustomer.balanceOwed < ( @@ -405,7 +405,7 @@ SELECT AVG(c.balanceOwed)/2.0 FROM Customer c) @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 @@ AND INDEX(w) = 0 @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 @@ WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) @Test void functionInvocationExampleWithCorrection() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c FROM Customer c WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @@ -440,7 +440,7 @@ WHERE FUNCTION('hasGoodCredit', c.balance, c.creditLimit) = TRUE @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 @@ void updateCaseExample1() { @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 @@ void updateCaseExample2() { @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 @@ CASE TYPE(e) WHEN Exempt THEN 'Exempt' @Test void selectCaseExample2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e.name, f.name, CONCAT(CASE WHEN f.annualMiles > 50000 THEN 'Platinum ' @@ -496,7 +496,7 @@ void selectCaseExample2() { @Test void theRest() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor) @@ -506,7 +506,7 @@ WHERE TYPE(e) IN (Exempt, Contractor) @Test void theRest2() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN (:empType1, :empType2) @@ -516,7 +516,7 @@ WHERE TYPE(e) IN (:empType1, :empType2) @Test void theRest3() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e FROM Employee e WHERE TYPE(e) IN :empTypes @@ -526,7 +526,7 @@ WHERE TYPE(e) IN :empTypes @Test void theRest4() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT TYPE(e) FROM Employee e WHERE TYPE(e) <> Exempt @@ -536,7 +536,7 @@ WHERE TYPE(e) <> Exempt @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 @@ HAVING c.status IN (1, 2) @Test void theRest6() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT c.country, COUNT(c) FROM Customer c GROUP BY c.country @@ -558,7 +558,7 @@ HAVING COUNT(c) > 30 @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 @@ HAVING COUNT(o) >= 5 @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 @@ void theRest8() { @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 @@ SELECT v.location.street, KEY(i).title, VALUE(i) @Test void theRest10() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o.lineItems FROM Order AS o """); } @@ -597,7 +597,7 @@ void theRest10() { @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 @@ SELECT c, COUNT(l) AS itemCount @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 @@ void theRest12() { @Test void theRest13() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT e.address AS addr FROM Employee e """); @@ -628,7 +628,7 @@ void theRest13() { @Test void theRest14() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT AVG(o.quantity) FROM Order o """); } @@ -636,7 +636,7 @@ SELECT AVG(o.quantity) FROM Order o @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 @@ SELECT SUM(l.price) @Test void theRest16() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT COUNT(o) FROM Order o """); } @@ -654,7 +654,7 @@ SELECT COUNT(o) FROM Order o @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 @@ SELECT COUNT(l.price) @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 @@ SELECT COUNT(l) @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 @@ void theRest19() { @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 @@ void theRest20() { @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 @@ void theRest21() { @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 @@ SELECT AVG(o.quantity) as q, a.zipcode @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 @@ void theRest23() { @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 @@ FROM Order o, IN(o.lineItems) l JOIN o.customer c @Test void theRest25() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -756,7 +756,7 @@ void theRest25() { @Test void theRest26() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" DELETE FROM Customer c WHERE c.status = 'inactive' @@ -767,7 +767,7 @@ void theRest26() { @Test void theRest27() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Customer c SET c.status = 'outstanding' WHERE c.balance < 10000 @@ -777,7 +777,7 @@ void theRest27() { @Test void theRest28() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" UPDATE Employee e SET e.address.building = 22 WHERE e.address.building = 14 @@ -789,7 +789,7 @@ void theRest28() { @Test void theRest29() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o """); @@ -798,7 +798,7 @@ void theRest29() { @Test void theRest30() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress.state = 'CA' @@ -808,7 +808,7 @@ void theRest30() { @Test void theRest31() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o.shippingAddress.state FROM Order o """); @@ -817,7 +817,7 @@ void theRest31() { @Test void theRest32() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT DISTINCT o FROM Order o JOIN o.lineItems l """); @@ -826,7 +826,7 @@ void theRest32() { @Test void theRest33() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS NOT EMPTY @@ -836,7 +836,7 @@ void theRest33() { @Test void theRest34() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.lineItems IS EMPTY @@ -846,7 +846,7 @@ void theRest34() { @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 @@ void theRest35() { @Test void theRest36() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE @@ -869,7 +869,7 @@ void theRest36() { @Test void theRest37() { - JpqlQueryParser.parse(""" + JpqlQueryParser.parseQuery(""" SELECT o FROM Order o WHERE o.shippingAddress <> o.billingAddress @@ -879,7 +879,7 @@ void theRest37() { @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 a6ec5fd3c9..ef90549fd4 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 @@ void createsParsingImplementationForNonNativeQuery() { 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 f8c84c536c..78427ece9a 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.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 @@ */ class StringQueryUnitTests { - private SoftAssertions softly = new SoftAssertions(); - @Test // DATAJPA-341 void doesNotConsiderPlainLikeABinding() { @@ -115,7 +112,6 @@ void detectsNamedInParameterBindings() { assertNamedBinding(InParameterBinding.class, "ids", bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-461 @@ -133,8 +129,6 @@ void detectsMultipleNamedInParameterBindings() { 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 @@ void detectsPositionalInParameterBindings() { assertPositionalBinding(InParameterBinding.class, 1, bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-461 @@ -170,7 +163,6 @@ void detectsMultiplePositionalInParameterBindings() { assertPositionalBinding(InParameterBinding.class, 2, bindings.get(1)); assertPositionalBinding(ParameterBinding.class, 3, bindings.get(2)); - softly.assertAll(); } @Test // DATAJPA-373 @@ -193,7 +185,6 @@ void treatsGreaterThanBindingAsSimpleBinding() { assertThat(bindings).hasSize(1); assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-473 @@ -208,11 +199,8 @@ void removesLikeBindingsFromQueryIfQueryContainsSimpleBinding() { 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 @@ void detectsInBindingWithParentheses() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "statuses", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -238,7 +224,6 @@ void detectsInBindingWithSpecialFrenchCharactersInParentheses() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "abonnés", bindings.get(0)); - softly.assertAll(); } @Test // DATAJPA-545 @@ -250,8 +235,6 @@ void detectsInBindingWithSpecialCharactersInParentheses() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "øre", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -263,8 +246,6 @@ void detectsInBindingWithSpecialAsianCharactersInParentheses() { assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "생일", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-545 @@ -276,8 +257,6 @@ void detectsInBindingWithSpecialCharactersAndWordCharactersMixedInParentheses() assertThat(bindings).hasSize(1); assertNamedBinding(InParameterBinding.class, "ab1babc생일233", bindings.get(0)); - - softly.assertAll(); } @Test // DATAJPA-362 @@ -301,27 +280,20 @@ void shouldReplaceAllPositionExpressionParametersWithInClause() { 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()) - .isTrue(); - 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 a from A a", true).hasConstructorExpression()).isFalse(); - - softly.assertAll(); + assertThat(new StringQuery("select a from A a", true).hasConstructorExpression()).isFalse(); } /** @@ -332,10 +304,8 @@ void detectsConstructorExpressions() { 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 @@ void bindingsMatchQueryForIdenticalSpelExpressions() { 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 @@ void getProjection() { 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 @@ void getAlias() { 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 @@ void testHasNamedParameter() { 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 @@ void ignoresQuotedNamedParameterLookAlike() { // 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 @@ void detectsMultiplePositionalParameterBindingsWithoutIndex() { 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 @@ void failOnMixedBindingsWithoutIndex() { @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 @@ void makesUsageOfJdbcStyleParameterAvailable() { 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 @@ void questionMarkInStringLiteral() { 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 @@ void isNotDefaultProjection() { "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 @@ void isNotDefaultProjection() { ); 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 @@ void checkNumberOfNamedParameters(String query, int expectedSize, String label, 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 @@ private void checkHasNamedParameter(String query, boolean expected, String label 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(); } }