Skip to content

Commit f98bcea

Browse files
committed
Use leaf property when validating case-insensitive transformation in query derivation.
We now use the correct leaf property instead of using the root property (owning segment). Closes #4087
1 parent 588c02e commit f98bcea

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ public JpqlQueryBuilder.Predicate build() {
491491
case NOT_LIKE:
492492

493493
PartTreeParameterBinding parameter = provider.next(part, String.class);
494-
JpqlQueryBuilder.Expression parameterExpression = potentiallyIgnoreCase(part.getProperty(),
494+
JpqlQueryBuilder.Expression parameterExpression = potentiallyIgnoreCase(part.getProperty().getLeafProperty(),
495495
placeholder(parameter));
496496

497497
// Predicate like = builder.like(propertyExpression, parameterExpression, escape.getEscapeCharacter());
@@ -512,7 +512,8 @@ public JpqlQueryBuilder.Predicate build() {
512512
return type.equals(SIMPLE_PROPERTY) ? where.isNull() : where.isNotNull();
513513
}
514514

515-
JpqlQueryBuilder.Expression expression = potentiallyIgnoreCase(property, placeholder(simple));
515+
JpqlQueryBuilder.Expression expression = potentiallyIgnoreCase(property.getLeafProperty(),
516+
placeholder(simple));
516517
return type.equals(SIMPLE_PROPERTY) ? whereIgnoreCase.eq(expression) : whereIgnoreCase.neq(expression);
517518
case IS_EMPTY:
518519
case IS_NOT_EMPTY:
@@ -624,7 +625,7 @@ private static String getDistanceFunction(ScoringFunction scoringFunction) {
624625
* @return
625626
*/
626627
private <T> JpqlQueryBuilder.Expression potentiallyIgnoreCase(JpqlQueryBuilder.Origin source, PropertyPath path) {
627-
return potentiallyIgnoreCase(path, JpqlQueryBuilder.expression(source, path));
628+
return potentiallyIgnoreCase(path.getLeafProperty(), JpqlQueryBuilder.expression(source, path));
628629
}
629630

630631
/**
@@ -635,7 +636,7 @@ private <T> JpqlQueryBuilder.Expression potentiallyIgnoreCase(JpqlQueryBuilder.O
635636
* @return
636637
*/
637638
private <T> JpqlQueryBuilder.Expression potentiallyIgnoreCase(JpqlQueryBuilder.PathExpression path) {
638-
return potentiallyIgnoreCase(path.getPropertyPath(), path);
639+
return potentiallyIgnoreCase(path.getPropertyPath().getLeafProperty(), path);
639640
}
640641

641642
/**

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryCreatorTests.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import static org.mockito.Mockito.*;
2020

2121
import jakarta.persistence.ElementCollection;
22+
import jakarta.persistence.Embeddable;
23+
import jakarta.persistence.Embedded;
2224
import jakarta.persistence.EntityManager;
2325
import jakarta.persistence.Id;
2426
import jakarta.persistence.ManyToOne;
@@ -67,7 +69,7 @@
6769
class JpaQueryCreatorTests {
6870

6971
private static final TestMetaModel ORDER = TestMetaModel.hibernateModel(Order.class, LineItem.class, Product.class);
70-
private static final TestMetaModel PERSON = TestMetaModel.hibernateModel(Person.class);
72+
private static final TestMetaModel PERSON = TestMetaModel.hibernateModel(Person.class, EmailAddress.class);
7173
private static final TestMetaModel REFERENCE_IDS = TestMetaModel.hibernateModel(
7274
ReferencingEmbeddedIdExampleEmployee.class, EmbeddedIdExampleEmployee.class, EmbeddedIdExampleEmployeePK.class,
7375
EmbeddedIdExampleDepartment.class);
@@ -716,7 +718,8 @@ void tupleProjection(Class<?> resultType) {
716718
.returning(resultType) //
717719
.withParameters("chris") //
718720
.as(QueryCreatorTester::create) //
719-
.expectJpql("SELECT p.id id, p.firstname firstname, p.lastname lastname FROM %s p WHERE p.firstname = ?1",
721+
.expectJpql(
722+
"SELECT p.id id, p.emailAddress emailAddress, p.firstname firstname, p.lastname lastname FROM %s p WHERE p.firstname = ?1",
720723
DefaultJpaEntityMetadata.unqualify(Person.class)) //
721724
.validateQuery();
722725
}
@@ -769,6 +772,18 @@ void createsJoinForReferenceName() {
769772
.validateQuery();
770773
}
771774

775+
@Test // GH-4087
776+
void considersLeafPropertyTypeForIgnoreCase() {
777+
778+
queryCreator(PERSON) //
779+
.forTree(Person.class, "findByEmailAddress_EmailIgnoreCase") //
780+
.withParameters("foo") //
781+
.as(QueryCreatorTester::create) //
782+
.expectJpql(
783+
"SELECT p FROM JpaQueryCreatorTests$Person p INNER JOIN p.emailAddress e WHERE UPPER(e.email) = UPPER(?1)") //
784+
.validateQuery();
785+
}
786+
772787
QueryCreatorBuilder queryCreator(Metamodel metamodel) {
773788
return new DefaultCreatorBuilder(metamodel);
774789
}
@@ -838,6 +853,13 @@ static class Person {
838853
@Id Long id;
839854
String firstname;
840855
String lastname;
856+
857+
@Embedded EmailAddress emailAddress;
858+
}
859+
860+
@Embeddable
861+
static class EmailAddress {
862+
String email;
841863
}
842864

843865
@jakarta.persistence.Entity

0 commit comments

Comments
 (0)