From 3d39d6e811f123ca69100cb014b4dd968570cafb 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 | 17 +++++++++++++---- .../query/EqlQueryRendererTests.java | 12 ++++++++++++ .../query/JpqlQueryRendererTests.java | 12 ++++++++++++ 6 files changed, 60 insertions(+), 9 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 c05013bb5..272d679c5 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 83bb506bc..a1c69583f 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 @@ -338,7 +338,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 0561b04a8..5bd453a81 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 @@ -1270,15 +1270,23 @@ class EqlQueryRenderer extends EqlBaseVisitor> { @Override public List visitIn_item(EqlParser.In_itemContext ctx) { - List tokens = new ArrayList<>(); - if (ctx.literal() != null) { - tokens.addAll(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) { - tokens.addAll(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 tokens; + return new ArrayList<>(); } @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 4dab0ffb5..58f549ace 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 @@ -1191,15 +1191,24 @@ class JpqlQueryRenderer extends JpqlBaseVisitor> { @Override public List visitIn_item(JpqlParser.In_itemContext ctx) { - List tokens = new ArrayList<>(); if (ctx.literal() != null) { - tokens.addAll(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) { - tokens.addAll(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 tokens; + return new ArrayList<>(); } @Override 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 81375d82a..9da99a1f9 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 @@ -561,6 +561,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 297c5a3cc..af1ee9b0b 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 @@ -562,6 +562,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() {