Skip to content

Commit 51d8211

Browse files
committed
Fix null check for querydsl predicate executor
Signed-off-by: Ilya Bakaev <stupid58fly@gmail.com>
1 parent d5afe31 commit 51d8211

2 files changed

Lines changed: 129 additions & 3 deletions

File tree

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/QuerydslJpaPredicateExecutor.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
import com.querydsl.core.types.ConstantImpl;
5353
import com.querydsl.core.types.EntityPath;
5454
import com.querydsl.core.types.Expression;
55-
import com.querydsl.core.types.NullExpression;
5655
import com.querydsl.core.types.Ops;
5756
import com.querydsl.core.types.OrderSpecifier;
5857
import com.querydsl.core.types.Predicate;
@@ -74,6 +73,7 @@
7473
* @author Jens Schauder
7574
* @author Greg Turnquist
7675
* @author Yanming Zhou
76+
* @author Ilya Bakaev
7777
*/
7878
public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecutor<T>, JpaRepositoryConfigurationAware {
7979

@@ -424,8 +424,9 @@ public BooleanExpression compare(Order order, Expression<?> propertyExpression,
424424

425425
@Override
426426
public BooleanExpression compare(String property, Expression<?> propertyExpression, @Nullable Object value) {
427-
return Expressions.booleanOperation(Ops.EQ, propertyExpression,
428-
value == null ? NullExpression.DEFAULT : ConstantImpl.create(value));
427+
return value == null
428+
? Expressions.booleanOperation(Ops.IS_NULL, propertyExpression)
429+
: Expressions.booleanOperation(Ops.EQ, propertyExpression, ConstantImpl.create(value));
429430
}
430431

431432
@Override

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

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
* @author Geoffrey Deremetz
105105
* @author Krzysztof Krason
106106
* @author Yanming Zhou
107+
* @author Ilya Bakaev
107108
*/
108109
@ExtendWith(SpringExtension.class)
109110
@ContextConfiguration("classpath:application-context.xml")
@@ -1522,6 +1523,130 @@ void scrollByPartTreeKeysetBackward() {
15221523
assertThat(previousWindow.hasNext()).isFalse();
15231524
}
15241525

1526+
@Test
1527+
void scrollByPredicateKeysetWithAscNullsFirst() {
1528+
1529+
User jane1 = new User("Jane", "Doe", "jane@doe1.com");
1530+
User jane2 = new User("Jane", null, "jane@doe2.com");
1531+
User jane3 = new User("Jane", null, "jane@doe3.com");
1532+
User john1 = new User("John", "Doe", "john@doe1.com");
1533+
User john2 = new User("John", null, "john@doe2.com");
1534+
User john3 = new User("John", null, "john@doe3.com");
1535+
1536+
repository.saveAllAndFlush(Arrays.asList(john1, john2, john3, jane1, jane2, jane3));
1537+
1538+
Sort sort = Sort.by(
1539+
Order.asc("firstname"),
1540+
Order.asc("lastname").nullsFirst(),
1541+
Order.asc("emailAddress")
1542+
);
1543+
1544+
Window<User> firstWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1545+
q -> q.limit(1).sortBy(sort).scroll(ScrollPosition.keyset()));
1546+
1547+
assertThat(firstWindow).containsOnly(jane2);
1548+
assertThat(firstWindow.hasNext()).isTrue();
1549+
1550+
Window<User> nextWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1551+
q -> q.limit(3).sortBy(sort).scroll(firstWindow.positionAt(0)));
1552+
1553+
assertThat(nextWindow).containsExactly(jane3, jane1, john2);
1554+
assertThat(nextWindow.hasNext()).isTrue();
1555+
}
1556+
1557+
@Test // GH-2878
1558+
void scrollByPredicateKeysetWithDescNullsFirst() {
1559+
1560+
User jane1 = new User("Jane", "Doe", "jane@doe1.com");
1561+
User jane2 = new User("Jane", null, "jane@doe2.com");
1562+
User jane3 = new User("Jane", null, "jane@doe3.com");
1563+
User john1 = new User("John", "Doe", "john@doe1.com");
1564+
User john2 = new User("John", null, "john@doe2.com");
1565+
User john3 = new User("John", null, "john@doe3.com");
1566+
1567+
repository.saveAllAndFlush(Arrays.asList(john1, john2, john3, jane1, jane2, jane3));
1568+
1569+
Sort sort = Sort.by(
1570+
Order.asc("firstname"),
1571+
Order.desc("lastname").nullsFirst(),
1572+
Order.asc("emailAddress")
1573+
);
1574+
1575+
Window<User> firstWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1576+
q -> q.limit(1).sortBy(sort).scroll(ScrollPosition.keyset()));
1577+
1578+
assertThat(firstWindow).containsOnly(jane2);
1579+
assertThat(firstWindow.hasNext()).isTrue();
1580+
1581+
Window<User> nextWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1582+
q -> q.limit(3).sortBy(sort).scroll(firstWindow.positionAt(0)));
1583+
1584+
assertThat(nextWindow).containsExactly(jane3, jane1, john2);
1585+
assertThat(nextWindow.hasNext()).isTrue();
1586+
}
1587+
1588+
@Test // GH-2878
1589+
void scrollByPredicateKeysetWithAscNullsLast() {
1590+
1591+
User jane1 = new User("Jane", "Doe", "jane@doe1.com");
1592+
User jane2 = new User("Jane", null, "jane@doe2.com");
1593+
User jane3 = new User("Jane", null, "jane@doe3.com");
1594+
User john1 = new User("John", "Doe", "john@doe1.com");
1595+
User john2 = new User("John", null, "john@doe2.com");
1596+
User john3 = new User("John", null, "john@doe3.com");
1597+
1598+
repository.saveAllAndFlush(Arrays.asList(john1, john2, john3, jane1, jane2, jane3));
1599+
1600+
Sort sort = Sort.by(
1601+
Order.asc("firstname"),
1602+
Order.asc("lastname").nullsLast(),
1603+
Order.asc("emailAddress")
1604+
);
1605+
1606+
Window<User> firstWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1607+
q -> q.limit(1).sortBy(sort).scroll(ScrollPosition.keyset()));
1608+
1609+
assertThat(firstWindow).containsOnly(jane1);
1610+
assertThat(firstWindow.hasNext()).isTrue();
1611+
1612+
Window<User> nextWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1613+
q -> q.limit(3).sortBy(sort).scroll(firstWindow.positionAt(0)));
1614+
1615+
assertThat(nextWindow).containsExactly(jane2, jane3, john1);
1616+
assertThat(nextWindow.hasNext()).isTrue();
1617+
}
1618+
1619+
@Test // GH-2878
1620+
void scrollByPredicateKeysetWithDescNullsLast() {
1621+
1622+
User jane1 = new User("Jane", "Doe", "jane@doe1.com");
1623+
User jane2 = new User("Jane", null, "jane@doe2.com");
1624+
User jane3 = new User("Jane", null, "jane@doe3.com");
1625+
User john1 = new User("John", "Doe", "john@doe1.com");
1626+
User john2 = new User("John", null, "john@doe2.com");
1627+
User john3 = new User("John", null, "john@doe3.com");
1628+
1629+
repository.saveAllAndFlush(Arrays.asList(john1, john2, john3, jane1, jane2, jane3));
1630+
1631+
Sort sort = Sort.by(
1632+
Order.asc("firstname"),
1633+
Order.desc("lastname").nullsLast(),
1634+
Order.asc("emailAddress")
1635+
);
1636+
1637+
Window<User> firstWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1638+
q -> q.limit(1).sortBy(sort).scroll(ScrollPosition.keyset()));
1639+
1640+
assertThat(firstWindow).containsOnly(jane1);
1641+
assertThat(firstWindow.hasNext()).isTrue();
1642+
1643+
Window<User> nextWindow = repository.findBy(QUser.user.firstname.startsWith("J"),
1644+
q -> q.limit(3).sortBy(sort).scroll(firstWindow.positionAt(0)));
1645+
1646+
assertThat(nextWindow).containsExactly(jane2, jane3, john1);
1647+
assertThat(nextWindow.hasNext()).isTrue();
1648+
}
1649+
15251650
@Test // GH-3015, GH-3407
15261651
void shouldApplyOffsetScrollPosition() {
15271652

0 commit comments

Comments
 (0)