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