1515 */
1616package example .springdata .jpa .pagination ;
1717
18- import static org .assertj .core .api .AssertionsForClassTypes .*;
18+ import static org .assertj .core .api .Assertions .*;
19+
20+ import jakarta .persistence .EntityManager ;
1921
2022import java .util .List ;
2123import java .util .Random ;
2426import java .util .stream .Collectors ;
2527import java .util .stream .IntStream ;
2628
27- import com .github .javafaker .Faker ;
28- import jakarta .persistence .EntityManager ;
2929import org .junit .jupiter .api .BeforeEach ;
3030import org .junit .jupiter .api .Test ;
31+
3132import org .springframework .beans .factory .annotation .Autowired ;
3233import org .springframework .boot .autoconfigure .EnableAutoConfiguration ;
33- import org .springframework .boot .test .context . SpringBootTest ;
34+ import org .springframework .boot .test .autoconfigure . orm . jpa . DataJpaTest ;
3435import org .springframework .context .annotation .Configuration ;
3536import org .springframework .data .domain .KeysetScrollPosition ;
3637import org .springframework .data .domain .OffsetScrollPosition ;
4041import org .springframework .data .domain .ScrollPosition ;
4142import org .springframework .data .domain .Slice ;
4243import org .springframework .data .domain .Window ;
43- import org .springframework .transaction .annotation .Transactional ;
44+ import org .springframework .data .domain .WindowIterator ;
45+ import org .springframework .data .util .Streamable ;
46+
47+ import com .github .javafaker .Faker ;
4448
4549/**
46- * Show different types of paging styles using {@link Page}, {@link org.springframework.data.domain. Slice} and {@link Window}
50+ * Show different types of paging styles using {@link Page}, {@link Slice} and {@link Window}.
4751 *
4852 * @author Christoph Strobl
53+ * @author Mark Paluch
4954 */
50- @ SpringBootTest
51- @ Transactional
55+ @ DataJpaTest
5256class PaginationTests {
5357
5458 @ Configuration
@@ -57,8 +61,7 @@ static class Config {
5761
5862 }
5963
60- @ Autowired
61- BookRepository books ;
64+ @ Autowired BookRepository books ;
6265
6366 @ BeforeEach
6467 void setUp () {
@@ -71,10 +74,9 @@ void setUp() {
7174 }
7275
7376 /**
74- * Page through the results using an offset/limit approach where the server skips over the number of results
75- * specified via {@link Pageable#getOffset()}.
76- * The {@link Page} return type will run an additional {@literal count} query to read the total number of matching rows
77- * on each request.
77+ * Page through the results using an offset/limit approach where the server skips over the number of results specified
78+ * via {@link Pageable#getOffset()}. The {@link Page} return type will run an additional {@literal count} query to
79+ * read the total number of matching rows on each request.
7880 */
7981 @ Test
8082 void pageThroughResultsWithSkipAndLimit () {
@@ -93,9 +95,9 @@ void pageThroughResultsWithSkipAndLimit() {
9395
9496 /**
9597 * Run through the results using an offset/limit approach where the server skips over the number of results specified
96- * via {@link Pageable#getOffset()}.
97- * No additional {@literal count} query to read the total number of matching rows is issued. Still {@link Slice} requests,
98- * but does not emit, one row more than specified via {@link Page#getSize()} to feed {@link Slice#hasNext()}
98+ * via {@link Pageable#getOffset()}. No additional {@literal count} query to read the total number of matching rows is
99+ * issued. Still {@link Slice} requests, but does not emit, one row more than specified via {@link Page#getSize()} to
100+ * feed {@link Slice#hasNext()}
99101 */
100102 @ Test
101103 void sliceThroughResultsWithSkipAndLimit () {
@@ -133,11 +135,28 @@ void scrollThroughResultsWithSkipAndLimit() {
133135 } while (window .hasNext ());
134136 }
135137
138+ /**
139+ * Scroll through the results using an offset/limit approach where the server skips over the number of results
140+ * specified via {@link OffsetScrollPosition#getOffset()} using {@link WindowIterator}.
141+ * <p>
142+ * This approach is similar to the {@link #sliceThroughResultsWithSkipAndLimit() slicing one}.
143+ */
144+ @ Test
145+ void scrollThroughResultsUsingWindowIteratorWithSkipAndLimit () {
146+
147+ WindowIterator <Book > iterator = WindowIterator
148+ .of (scrollPosition -> books .findTop2ByTitleContainsOrderByPublicationDate ("the-crazy-book-" , scrollPosition ))
149+ .startingAt (OffsetScrollPosition .initial ());
150+
151+ List <Book > allBooks = Streamable .of (() -> iterator ).stream ().toList ();
152+ assertThat (allBooks ).hasSize (50 );
153+ }
154+
136155 /**
137156 * Scroll through the results using an index based approach where the {@link KeysetScrollPosition#getKeys() keyset}
138157 * keeps track of already seen values to resume scrolling by altering the where clause to only return rows after the
139- * values contained in the keyset.
140- * Set {@literal logging.level.org.hibernate.SQL=debug} to show the modified query in the log.
158+ * values contained in the keyset. Set {@literal logging.level.org.hibernate.SQL=debug} to show the modified query in
159+ * the log.
141160 */
142161 @ Test
143162 void scrollThroughResultsWithKeyset () {
@@ -155,8 +174,7 @@ void scrollThroughResultsWithKeyset() {
155174
156175 // --> Test Data
157176
158- @ Autowired
159- EntityManager em ;
177+ @ Autowired EntityManager em ;
160178
161179 private List <Author > createAuthors (Faker faker ) {
162180
@@ -176,18 +194,17 @@ private List<Author> createAuthors(Faker faker) {
176194 private List <Book > createBooks (Faker faker , List <Author > authors ) {
177195
178196 Random rand = new Random ();
179- return IntStream .range (0 , 100 )
180- .mapToObj (id -> {
181-
182- Book book = new Book ();
183- book .setId ("book-%03d" .formatted (id ));
184- book .setTitle (faker .book ().title ());
185- book .setIsbn10 (UUID .randomUUID ().toString ().substring (0 , 10 ));
186- book .setPublicationDate (faker .date ().past (5000 , TimeUnit .DAYS ));
187- book .setAuthor (authors .get (rand .nextInt (authors .size ())));
188-
189- em .persist (book );
190- return book ;
191- }).collect (Collectors .toList ());
197+ return IntStream .range (0 , 100 ).mapToObj (id -> {
198+
199+ Book book = new Book ();
200+ book .setId ("book-%03d" .formatted (id ));
201+ book .setTitle ((id % 2 == 0 ? "the-crazy-book-" : "" ) + faker .book ().title ());
202+ book .setIsbn10 (UUID .randomUUID ().toString ().substring (0 , 10 ));
203+ book .setPublicationDate (faker .date ().past (5000 , TimeUnit .DAYS ));
204+ book .setAuthor (authors .get (rand .nextInt (authors .size ())));
205+
206+ em .persist (book );
207+ return book ;
208+ }).collect (Collectors .toList ());
192209 }
193210}
0 commit comments