Skip to content

Commit

Permalink
Added serialization support and documentation update (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
p3t authored Aug 30, 2024
1 parent f961d7a commit 555f8ba
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 4 deletions.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,25 @@ Such a reversed cursor is, changing the direction of the query, but not the sort

There is only value in this feature, if the client is not able to cache the previous requested pages by himself, i.e. forgets them while moving forward. This might be the case in a very memory limited client scenario which is usually _not_ a web application/web browser.

## API for reverting page-requests (=cursor positions)
There is an API (`PageReqiest::toReversed`) for getting a page-request from an existing page-request, which will traverse the results in the opposite direction - while maintaining the sort order.
Example:
```java
// Extracted from test-case
final PageRequest<DataRecord> request = PageRequest.create( b -> b.pageSize( 5 ).asc( DataRecord_.name )
.asc( DataRecord_.id ) );

final var firstPage = dataRecordRepository.loadPage( request );
final var secondPage = dataRecordRepository.loadPage( firstPage.next().orElseThrow() );
final var reversedFirstPage = dataRecordRepository.loadPage( secondPage.self().toReversed() );

// everything before the second page (self-pointer) is the first page:
assertThat( reversedFirstPage ).containsExactlyElementsOf( firstPage );

// no next before the "first page":
assertThat( reversedFirstPage.next() ).isNotPresent();
```

## Limitations
- Such a cursor implementation is not transaction-safe. Which is good enough for most UIs, and it is not so important, to miss a record or have a duplicate one in two-page requests. This is i.e. the case when the PK is not an ascending numerical ID but maybe a UUID, so that it is possible that an inserted record appears before the page which a client is going to request. In case you need transaction-safe cursor queries, this is most likely a server-side use case, and you can use DB-cursors.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private Position positionOf( final Cursor.Position position ) {
case ASC -> Order.ASC;
case DESC -> Order.DESC;
case UNRECOGNIZED -> throw new IllegalArgumentException( "Unrecognized order" );
} ) );
} ).reversed( position.getReversed() ) );
}

private Attribute attributeOf( final Cursor.Attribute attribute ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private Iterable<Cursor.Position> positions() {
.setValue( valueOf( p.value() ) ).setOrder( switch ( p.order() ) {
case ASC -> Cursor.Order.ASC;
case DESC -> Cursor.Order.DESC;
} )
} ).setReversed( p.reversed() )
.build() ).toList();
}

Expand Down
1 change: 1 addition & 0 deletions cursorpaging-jpa-api/src/main/proto/pagerequest.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ message Position {
Attribute attribute = 1;
Value value = 2;
Order order = 3;
optional bool reversed = 4;
}

message Filter {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package io.vigier.cursorpaging.jpa.serializer;

import static org.assertj.core.api.Assertions.assertThat;

import io.vigier.cursorpaging.jpa.Attribute;
import io.vigier.cursorpaging.jpa.Order;
import io.vigier.cursorpaging.jpa.PageRequest;
import io.vigier.cursorpaging.jpa.Position;
import io.vigier.cursorpaging.jpa.SingleAttribute;
import jakarta.persistence.metamodel.SingularAttribute;
import java.time.Instant;
Expand All @@ -12,6 +12,8 @@
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.assertj.core.api.Assertions.assertThat;

public class SerializerTest {

@Data
Expand Down Expand Up @@ -58,6 +60,18 @@ void shouldSerializePageRequestsWithMultipleAttributes() {
assertThat( deserializeRequest ).isEqualTo( pageRequest );
}

@Test
void shouldSerializeReversedPageRequests() {
final var request = PageRequest.create( r -> r.position( Position.create(
p -> p.reversed( true ).order( Order.ASC ).attribute( Attribute.of( "some_name", String.class ) ) ) ) );
final EntitySerializer<Object> serializer = EntitySerializer.create();
final var serializedRequest = serializer.toBase64( request );
final var deserializedRequest = serializer.toPageRequest( serializedRequest );
assertThat( deserializedRequest.isReversed() ).isTrue();
assertThat( deserializedRequest ).isEqualTo( request );

}

@Test
void shouldLearnAttributesBySerializing() {
final var request = createPageRequest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,8 @@ public PageRequest<E> toReversed() {
public boolean isFirstPage() {
return positions.get( 0 ).isFirst();
}

public boolean isReversed() {
return positions.get( 0 ).reversed();
}
}

0 comments on commit 555f8ba

Please sign in to comment.