Repository: jakartaee/data
Pull request #339 (2023-11-08 19:38:06)

Make Optional return the cursor


Patch:
diff --git a/api/src/main/java/jakarta/data/page/Pageable.java b/api/src/main/java/jakarta/data/page/Pageable.java
index f18b1b29..766b8425 100644
--- a/api/src/main/java/jakarta/data/page/Pageable.java
+++ b/api/src/main/java/jakarta/data/page/Pageable.java
@@ -24,6 +24,7 @@ import jakarta.data.repository.Query;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * <p>This class represents pagination information.</p>
@@ -155,9 +156,9 @@ public interface Pageable {
      * Returns the keyset values which are the starting point for
      * keyset pagination.
      *
-     * @return the keyset values; <code>null</code> if using offset pagination.
+     * @return the keyset values; {@link Optional#empty()} if using offset pagination.
      */
-    Cursor cursor();
+    Optional<Cursor> cursor();
 
     /**
      * Returns the type of pagination.
diff --git a/api/src/main/java/jakarta/data/page/Pagination.java b/api/src/main/java/jakarta/data/page/Pagination.java
index 55fc14cd..81af7096 100644
--- a/api/src/main/java/jakarta/data/page/Pagination.java
+++ b/api/src/main/java/jakarta/data/page/Pagination.java
@@ -20,13 +20,14 @@ package jakarta.data.page;
 import jakarta.data.Sort;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
 /**
  * Built-in implementation of Pageable.
  */
-record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor cursor) implements Pageable {
+record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor type) implements Pageable {
 
     Pagination {
         if (page < 1) {
@@ -35,7 +36,7 @@ record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor curso
             throw new IllegalArgumentException("maxPageSize: " + size);
         }
 
-        if (mode != Mode.OFFSET && (cursor == null || cursor.size() == 0)) {
+        if (mode != Mode.OFFSET && (type == null || type.size() == 0)) {
             throw new IllegalArgumentException("No keyset values were provided.");
         }
     }
@@ -60,6 +61,11 @@ record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor curso
         return new Pagination(page, size, sorts, Mode.CURSOR_PREVIOUS, keysetCursor);
     }
 
+    @Override
+    public Optional<Cursor> cursor() {
+        return Optional.ofNullable(type);
+    }
+
     @Override
     public Pageable next() {
         if (mode == Mode.OFFSET) {
@@ -75,9 +81,9 @@ record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor curso
         StringBuilder s = new StringBuilder(mode == Mode.OFFSET ? 100 : 150)
                 .append("Pageable{page=").append(page)
                 .append(", size=").append(size);
-        if (cursor != null) {
+        if (type != null) {
             s.append(", mode=").append(mode)
-            .append(", ").append(cursor.size()).append(" keys");
+            .append(", ").append(type.size()).append(" keys");
         }
         for (Sort sort : sorts) {
             s.append(", ").append(sort.property());
@@ -91,12 +97,12 @@ record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor curso
 
     @Override
     public Pageable page(long pageNumber) {
-        return new Pagination(pageNumber, size, sorts, mode, cursor);
+        return new Pagination(pageNumber, size, sorts, mode, type);
     }
 
     @Override
     public Pageable size(int maxPageSize) {
-        return new Pagination(page, maxPageSize, sorts, mode, cursor);
+        return new Pagination(page, maxPageSize, sorts, mode, type);
     }
 
     @Override
@@ -104,11 +110,11 @@ record Pagination(long page, int size, List<Sort> sorts, Mode mode, Cursor curso
         List<Sort> sortList = sorts == null
                 ? Collections.emptyList()
                 : StreamSupport.stream(sorts.spliterator(), false).collect(Collectors.toUnmodifiableList());
-        return new Pagination(page, size, sortList, mode, cursor);
+        return new Pagination(page, size, sortList, mode, type);
     }
 
     @Override
     public Pageable sortBy(Sort... sorts) {
-        return new Pagination(page, size, sorts == null ? Collections.emptyList() : List.of(sorts), mode, cursor);
+        return new Pagination(page, size, sorts == null ? Collections.emptyList() : List.of(sorts), mode, type);
     }
 }
\ No newline at end of file


Test patch:
diff --git a/api/src/test/java/jakarta/data/page/KeysetPageableTest.java b/api/src/test/java/jakarta/data/page/KeysetPageableTest.java
index 82e2185b..bc56bc79 100644
--- a/api/src/test/java/jakarta/data/page/KeysetPageableTest.java
+++ b/api/src/test/java/jakarta/data/page/KeysetPageableTest.java
@@ -40,10 +40,10 @@ class KeysetPageableTest {
             softly.assertThat(pageable.size()).isEqualTo(20);
             softly.assertThat(pageable.page()).isEqualTo(1L);
             softly.assertThat(pageable.mode()).isEqualTo(Pageable.Mode.CURSOR_NEXT);
-            softly.assertThat(pageable.cursor().size()).isEqualTo(3);
-            softly.assertThat(pageable.cursor().getKeysetElement(0)).isEqualTo("First");
-            softly.assertThat(pageable.cursor().getKeysetElement(1)).isEqualTo(2L);
-            softly.assertThat(pageable.cursor().getKeysetElement(2)).isEqualTo(3);
+            softly.assertThat(pageable.cursor()).get().extracting(Pageable.Cursor::size).isEqualTo(3);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo("First");
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo(2L);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(2)).isEqualTo(3);
         });
     }
 
@@ -58,9 +58,9 @@ class KeysetPageableTest {
             softly.assertThat(pageable.page()).isEqualTo(1L);
             softly.assertThat(pageable.sorts()).isEqualTo(List.of(Sort.asc("name"), Sort.asc("id")));
             softly.assertThat(pageable.mode()).isEqualTo(Pageable.Mode.CURSOR_NEXT);
-            softly.assertThat(pageable.cursor().size()).isEqualTo(2);
-            softly.assertThat(pageable.cursor().getKeysetElement(0)).isEqualTo("me");
-            softly.assertThat(pageable.cursor().getKeysetElement(1)).isEqualTo(200);
+            softly.assertThat(pageable.cursor()).get().extracting(Pageable.Cursor::size).isEqualTo(2);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo("me");
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo(200);
         });
     }
 
@@ -74,9 +74,9 @@ class KeysetPageableTest {
             softly.assertThat(pageable.page()).isEqualTo(10L);
             softly.assertThat(pageable.sorts()).isEqualTo(List.of(Sort.desc("yearBorn"), Sort.asc("ssn")));
             softly.assertThat(pageable.mode()).isEqualTo(Pageable.Mode.CURSOR_PREVIOUS);
-            softly.assertThat(pageable.cursor().size()).isEqualTo(2);
-            softly.assertThat(pageable.cursor().getKeysetElement(0)).isEqualTo(1991);
-            softly.assertThat(pageable.cursor().getKeysetElement(1)).isEqualTo("123-45-6789");
+            softly.assertThat(pageable.cursor()).get().extracting(Pageable.Cursor::size).isEqualTo(2);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo(1991);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo("123-45-6789");
         });
     }
 
@@ -91,12 +91,12 @@ class KeysetPageableTest {
             softly.assertThat(pageable.page()).isEqualTo(8L);
             softly.assertThat(pageable.sorts()).isEqualTo(Collections.EMPTY_LIST);
             softly.assertThat(pageable.mode()).isEqualTo(Pageable.Mode.CURSOR_PREVIOUS);
-            softly.assertThat(pageable.cursor().size()).isEqualTo(5);
-            softly.assertThat(pageable.cursor().getKeysetElement(0)).isEqualTo(900L);
-            softly.assertThat(pageable.cursor().getKeysetElement(1)).isEqualTo(300);
-            softly.assertThat(pageable.cursor().getKeysetElement(2)).isEqualTo("testing");
-            softly.assertThat(pageable.cursor().getKeysetElement(3)).isEqualTo(120);
-            softly.assertThat(pageable.cursor().getKeysetElement(4)).isEqualTo('T');
+            softly.assertThat(pageable.cursor()).get().extracting(Pageable.Cursor::size).isEqualTo(5);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo(900L);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo(300);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(2)).isEqualTo("testing");
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(3)).isEqualTo(120);
+            softly.assertThat(pageable.cursor()).get().extracting(c -> c.getKeysetElement(4)).isEqualTo('T');
         });
     }
 
@@ -175,8 +175,8 @@ class KeysetPageableTest {
             softly.assertThat(cursor1.equals(cursor4)).isFalse(); // different classes
             softly.assertThat(cursor4.equals(cursor1)).isFalse(); // different classes
 
-            softly.assertThat(pageable25p1s0a1.cursor()).isEqualTo(cursor1);
-            softly.assertThat(pageable25p1s0a1match.cursor()).isEqualTo(cursor1);
+            softly.assertThat(pageable25p1s0a1.cursor()).get().isEqualTo(cursor1);
+            softly.assertThat(pageable25p1s0a1match.cursor()).get().isEqualTo(cursor1);
 
             softly.assertThat(pageable25p1s0a1.equals(pageable25p1s0a1)).isTrue();
             softly.assertThat(pageable25p1s0a1.equals(null)).isFalse();
@@ -209,14 +209,14 @@ class KeysetPageableTest {
 
         assertSoftly(softly -> {
             softly.assertThat(p1.mode()).isEqualTo(Pageable.Mode.CURSOR_NEXT);
-            softly.assertThat(p1.cursor().getKeysetElement(0)).isEqualTo("last1");
-            softly.assertThat(p1.cursor().getKeysetElement(1)).isEqualTo("fname1");
-            softly.assertThat(p1.cursor().getKeysetElement(2)).isEqualTo(100);
+            softly.assertThat(p1.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo("last1");
+            softly.assertThat(p1.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo("fname1");
+            softly.assertThat(p1.cursor()).get().extracting(c -> c.getKeysetElement(2)).isEqualTo(100);
 
             softly.assertThat(p2.mode()).isEqualTo(Pageable.Mode.CURSOR_PREVIOUS);
-            softly.assertThat(p2.cursor().getKeysetElement(0)).isEqualTo("lname2");
-            softly.assertThat(p2.cursor().getKeysetElement(1)).isEqualTo("fname2");
-            softly.assertThat(p2.cursor().getKeysetElement(2)).isEqualTo(200);
+            softly.assertThat(p2.cursor()).get().extracting(c -> c.getKeysetElement(0)).isEqualTo("lname2");
+            softly.assertThat(p2.cursor()).get().extracting(c -> c.getKeysetElement(1)).isEqualTo("fname2");
+            softly.assertThat(p2.cursor()).get().extracting(c -> c.getKeysetElement(2)).isEqualTo(200);
 
             softly.assertThat(p1.sorts()).isEqualTo(List.of(Sort.asc("lastName"), Sort.asc("firstName"), Sort.asc("id")));
             softly.assertThat(p2.sorts()).isEqualTo(List.of(Sort.asc("lastName"), Sort.asc("firstName"), Sort.asc("id")));