DATACASS-56 - Cassandra paging support.
We now support forward-only paging with Cassandra through the Template API and Repositories. Results in Cassandra are paged by navigating forward-only through pages described by a binary paging state encapsulated by CassandraPageRequest and accessible via the returned Slice. Spring Data Page's do not fit to Cassandra's paging concept because Cassandra paging is not based on limit/offset.
Page requests are applicable to a Query and as parameter of query methods.
Query query = Query.empty().pageRequest(CassandraPageRequest.first(10));
Slice<User> slice = template.slice(query, User.class);
do {
// consume slice
if (slice.hasNext()) {
slice = template.select(query, slice.nextPageable(), User.class);
} else {
break;
}
} while (!slice.getContent().isEmpty());
assertThat(ids).hasSize(100);
assertThat(iterations).isEqualTo(10);
interface UserRepository implements Repository<User, String> {
Slice<User> findAllByName(String name, Pageable pageRequest);
}
This commit is contained in:
@@ -111,7 +111,7 @@ class ApplicationConfig extends AbstractCassandraConfiguration {
|
||||
As our domain Repository extends `CrudRepository` it provides you with basic CRUD operations.
|
||||
Working with the Repository instance is just a matter of injecting the Repository as a dependency into a client.
|
||||
|
||||
.Paging access to Person entities
|
||||
.Basic access to Person entities
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@@ -131,6 +131,35 @@ public class PersonRepositoryTests {
|
||||
----
|
||||
====
|
||||
|
||||
Cassandra repositories support paging and sorting for paginated and sorted access to the entities. Cassandra paging requires a paging state to forward-only navigate through pages. A `Slice` keeps track of the current paging state and allows creation of a `Pageable` to request the next page.
|
||||
|
||||
.Paging access to Person entities
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class PersonRepositoryTests {
|
||||
|
||||
@Autowired PersonRepository repository;
|
||||
|
||||
@Test
|
||||
public void readsPagesCorrectly() {
|
||||
|
||||
Slice<Person> firstBatch = repository.findAll(CassandraPageRequest.first(10));
|
||||
|
||||
assertThat(firstBatch).hasSize(10);
|
||||
|
||||
Page<Person> nextBatch = repository.findAll(firstBatch.nextPageable());
|
||||
|
||||
// …
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
NOTE: Cassandra repositories do not extend `PagingAndSortingRepository` because classic paging patterns using limit/offset are not applicable to Cassandra.
|
||||
|
||||
The sample creates an application context with Spring's unit test support, which will perform annotation-based
|
||||
dependency injection into the test class. Inside the test cases (test methods) we simply use the Repository to query
|
||||
the data store. We invoke the Repository query method that requests the all `Person` instances.
|
||||
@@ -147,26 +176,30 @@ the Apache Cassandra database. Defining such a query is just a matter of declari
|
||||
----
|
||||
public interface PersonRepository extends CrudRepository<Person, String> {
|
||||
|
||||
List<Person> findByLastname(String lastname); <1>
|
||||
List<Person> findByLastname(String lastname); <1>
|
||||
|
||||
List<Person> findByFirstname(String firstname, Sort sort); <2>
|
||||
Slice<Person> findByFirstname(String firstname, Pageable pageRequest); <2>
|
||||
|
||||
List<Person> findByFirstname(String firstname, QueryOptions opts); <3>
|
||||
List<Person> findByFirstname(String firstname, QueryOptions opts); <3>
|
||||
|
||||
Person findByShippingAddress(Address address); <4>
|
||||
List<Person> findByFirstname(String firstname, Sort sort); <4>
|
||||
|
||||
Stream<Person> findAllBy(); <5>
|
||||
Person findByShippingAddress(Address address); <5>
|
||||
|
||||
Stream<Person> findAllBy(); <6>
|
||||
>>>>>>> 18c314d... DATACASS-56 - Cassandra paging support.
|
||||
}
|
||||
----
|
||||
<1> The method shows a query for all people with the given `lastname`. The query will be derived from parsing
|
||||
the method name for constraints which can be concatenated with `And`. Thus the method name will result in
|
||||
a query expression of `SELECT * from person WHERE lastname = 'lastname'`.
|
||||
<2> Applies dynamic sorting to a query. Just add a `Sort` parameter to your method signature and Spring Data.
|
||||
will automatically apply ordering to the query accordingly.
|
||||
<2> Applies pagination to a query. Just equip your method signature with a `Pageable` parameter and let the method return a `Slice` instance and we will automatically page the query accordingly.
|
||||
<3> Passing a `QueryOptions` object will apply the query options to the resulting query before it's execution.
|
||||
<4> Shows that you can query based on properties which are not a primitive type using registered `Converter`'s.
|
||||
<4> Applies dynamic sorting to a query. Just add a `Sort` parameter to your method signature and Spring Data
|
||||
will automatically apply ordering to the query accordingly.
|
||||
<5> Shows that you can query based on properties which are not a primitive type using registered `Converter`'s
|
||||
in `CustomConversions`.
|
||||
<5> Uses a Java 8 `Stream` which reads and converts individual elements while iterating the stream.
|
||||
<6> Uses a Java 8 `Stream` which reads and converts individual elements while iterating the stream.
|
||||
====
|
||||
|
||||
NOTE: Querying non-primary key properties requires secondary indexes.
|
||||
|
||||
@@ -1137,6 +1137,7 @@ The `Query` class has some additional methods used to provide options for the qu
|
||||
* `Query` *and* `(CriteriaDefinition criteria)` used to add additional criteria to the query.
|
||||
* `Query` *columns* `(Columns columns)` used to define columns to be included in the query results.
|
||||
* `Query` *limit* `(long limit)` used to limit the size of the returned results to the provided limit (used for paging).
|
||||
* `Query` *pageRequest* `(Pageable pageRequest)` used to associate `Sort`, `PagingState` and `fetchSize` with the query (used for paging).
|
||||
* `Query` *pagingState* `(PagingState pagingState)` used to associate a `PagingState` with the query (used for paging).
|
||||
* `Query` *queryOptions* `(QueryOptions queryOptions)` used to associate `QueryOptions` with the query.
|
||||
* `Query` *sort* `(Sort sort)` used to provide sort definition for the results.
|
||||
@@ -1151,8 +1152,9 @@ The query methods need to specify the target type T that will be returned.
|
||||
|
||||
* `List<T>` *select* `(Query query, Class<T> entityClass)` Query for a list of objects of type T from the table.
|
||||
* `T` *selectOneById* `(Query query, Class<T> entityClass)` Query for a single object of type T from the table.
|
||||
* `Slice<T>` *slice* `(Query query, Class<T> entityClass)` Start or continue paging by querying for a `Slice` of objects of type T from the table.
|
||||
* `T` *selectOne* `(Query query, Class<T> entityClass)` Query for a single object of type T from the table.
|
||||
* `Stream<T>` *stream* `(Query query, Class<T> entityClass)` Query for a stream of objects of type T from the table.
|
||||
|
||||
* `List<T>` *select* `(String cql, Class<T> entityClass)` Ad-hoc query for a list of objects of type T from the table providing a CQL statement.
|
||||
* `T` *selectOneById* `(String cql, Class<T> entityClass)` Ad-hoc query for a single object of type T from the table providing a CQL statement.
|
||||
* `Stream<T>` *stream* `(String cql, Class<T> entityClass)` Ad-hoc query for a stream of objects of type T from the table providing a CQL statement.
|
||||
|
||||
Reference in New Issue
Block a user