From b8e8121b16aa448567cb5901e179f1de5a6f7e20 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 14 Apr 2025 08:50:46 +0200 Subject: [PATCH] Fix parsing of EQL/JPQL using string literals and enums in IN items. Closes #3835 --- .../data/jpa/repository/query/Eql.g4 | 5 +++++ .../data/jpa/repository/query/Jpql.g4 | 5 +++++ .../jpa/repository/query/EqlQueryRenderer.java | 18 +++++++++++++----- .../repository/query/JpqlQueryRenderer.java | 10 ++++++++++ .../query/EqlQueryRendererTests.java | 12 ++++++++++++ .../query/JpqlQueryRendererTests.java | 12 ++++++++++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 index 45be6c6ff..9a1136ddd 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 @@ -354,7 +354,12 @@ in_expression in_item : literal + | string_expression + | boolean_literal + | numeric_literal + | date_time_timestamp_literal | single_valued_input_parameter + | conditional_expression ; like_expression diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 index 3b82b67da..98a0df214 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 @@ -342,7 +342,12 @@ in_expression in_item : literal + | string_expression + | boolean_literal + | numeric_literal + | date_time_timestamp_literal | single_valued_input_parameter + | conditional_expression ; like_expression diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java index eb18221ac..8225545c8 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java @@ -1189,15 +1189,23 @@ class EqlQueryRenderer extends EqlBaseVisitor { @Override public QueryTokenStream visitIn_item(EqlParser.In_itemContext ctx) { - QueryRendererBuilder builder = QueryRenderer.builder(); - if (ctx.literal() != null) { - builder.append(visit(ctx.literal())); + return visit(ctx.literal()); + } else if (ctx.string_expression() != null) { + return visit(ctx.string_expression()); + } else if (ctx.boolean_literal() != null) { + return visit(ctx.boolean_literal()); + } else if (ctx.numeric_literal() != null) { + return visit(ctx.numeric_literal()); + } else if (ctx.date_time_timestamp_literal() != null) { + return visit(ctx.date_time_timestamp_literal()); } else if (ctx.single_valued_input_parameter() != null) { - builder.append(visit(ctx.single_valued_input_parameter())); + return visit(ctx.single_valued_input_parameter()); + } else if (ctx.conditional_expression() != null) { + return visit(ctx.conditional_expression()); } - return builder; + return QueryTokenStream.empty(); } @Override diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java index c624f2642..fad4187df 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpqlQueryRenderer.java @@ -1113,8 +1113,18 @@ class JpqlQueryRenderer extends JpqlBaseVisitor { if (ctx.literal() != null) { return visit(ctx.literal()); + } else if (ctx.string_expression() != null) { + return visit(ctx.string_expression()); + } else if (ctx.boolean_literal() != null) { + return visit(ctx.boolean_literal()); + } else if (ctx.numeric_literal() != null) { + return visit(ctx.numeric_literal()); + } else if (ctx.date_time_timestamp_literal() != null) { + return visit(ctx.date_time_timestamp_literal()); } else if (ctx.single_valued_input_parameter() != null) { return visit(ctx.single_valued_input_parameter()); + } else if (ctx.conditional_expression() != null) { + return visit(ctx.conditional_expression()); } return QueryTokenStream.empty(); diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java index 6c036c3e7..72bdfc3b1 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java @@ -555,6 +555,18 @@ class EqlQueryRendererTests { """); } + @Test + void inClauseWithFunctionAndLiterals() { + + assertQuery(""" + select f from FooEntity f where upper(f.name) IN ('Y', 'Basic', 'Remit') + """); + assertQuery( + """ + select count(f) from FooEntity f where f.status IN (com.example.eql_bug_check.entity.FooStatus.FOO, com.example.eql_bug_check.entity.FooStatus.BAR) + """); + } + @Test void notEqualsForTypeShouldWork() { 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 8613362c4..a16a5a880 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 @@ -556,6 +556,18 @@ class JpqlQueryRendererTests { """); } + @Test + void inClauseWithFunctionAndLiterals() { + + assertQuery(""" + select f from FooEntity f where upper(f.name) IN ('Y', 'Basic', 'Remit') + """); + assertQuery( + """ + select count(f) from FooEntity f where f.status IN (com.example.eql_bug_check.entity.FooStatus.FOO, com.example.eql_bug_check.entity.FooStatus.BAR) + """); + } + @Test void notEqualsForTypeShouldWork() {