From 3132f4945b69b87dad4d3d68afe14fa92dcfc051 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 13 Jun 2023 09:25:51 +0200 Subject: [PATCH] Retain scroll direction in Keyset position function of the correct item. Closes #2999 --- .../jpa/repository/query/ScrollDelegate.java | 6 ++--- .../jpa/repository/UserRepositoryTests.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java index 10681ac69..eb244a020 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/ScrollDelegate.java @@ -80,14 +80,14 @@ public class ScrollDelegate { JpaEntityInformation entity, List result) { KeysetScrollDelegate delegate = KeysetScrollDelegate.of(direction); - List resultsToUse = delegate.postProcessResults(result); + List resultsToUse = delegate.getResultWindow(delegate.postProcessResults(result), limit); IntFunction positionFunction = value -> { - T object = result.get(value); + T object = resultsToUse.get(value); Map keys = entity.getKeyset(sort.stream().map(Order::getProperty).toList(), object); - return ScrollPosition.forward(keys); + return ScrollPosition.of(keys, direction); }; return Window.from(delegate.getResultWindow(resultsToUse, limit), positionFunction, hasMoreElements(result, limit)); diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java index 844e2ec9f..c9d22e52b 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -60,6 +60,7 @@ import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatcher; import org.springframework.data.domain.ExampleMatcher.StringMatcher; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; +import org.springframework.data.domain.ExampleMatcher.*; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.sample.Address; import org.springframework.data.jpa.domain.sample.QUser; @@ -1308,6 +1309,31 @@ class UserRepositoryTests { assertThat(previousWindow.hasNext()).isTrue(); } + @Test // GH-2999 + void scrollInitiallyByExampleKeysetBackward() { + + User jane1 = new User("Jane", "Doe", "jane@doe1.com"); + User jane2 = new User("Jane", "Doe", "jane@doe2.com"); + User john1 = new User("John", "Doe", "john@doe1.com"); + User john2 = new User("John", "Doe", "john@doe2.com"); + + repository.saveAllAndFlush(Arrays.asList(john1, john2, jane1, jane2)); + + Example example = Example.of(new User("J", null, null), + matching().withMatcher("firstname", GenericPropertyMatcher::startsWith).withIgnorePaths("age", "createdAt", + "dateOfBirth")); + + Window firstWindow = repository.findBy(example, + q -> q.limit(2).sortBy(Sort.by("firstname", "emailAddress")).scroll(ScrollPosition.keyset().backward())); + + assertThat(firstWindow).containsExactly(john1, john2); + + Window previousWindow = repository.findBy(example, + q -> q.limit(2).sortBy(Sort.by("firstname", "emailAddress")).scroll(firstWindow.positionAt(0))); + + assertThat(previousWindow).containsExactly(jane1, jane2); + } + @Test // GH-2878 void scrollByPredicateOffset() {