#407 - Add ReactiveSortingRepository support.

Implements ReactiveSortingRepository on SimpleR2dbcRepository. Also changed R2dbcRepository to extend ReactiveSortingRepository and updated comments where it felt reasonable.

Added a single unit test for the new method, and changed the base interface of LegoSetRepository in AbstractR2dbcRepositoryIntegrationTests for integration testing purposes.

Clarify documentation on reactive repository base interfaces

Adds some language calling out ReactiveSortingRepository and fixes consistency between related examples.

Original pull request: #408.
This commit is contained in:
Stephen Cohen
2020-07-21 20:12:33 -04:00
committed by Mark Paluch
parent d51586890c
commit 4da92bdc7c
6 changed files with 46 additions and 11 deletions

View File

@@ -35,7 +35,7 @@ The following example shows a repository interface for the preceding `Person` cl
====
[source]
----
public interface PersonRepository extends PagingAndSortingRepository<Person, String> {
public interface PersonRepository extends ReactiveCrudRepository<Person, Long> {
// additional custom query methods go here
}
@@ -62,7 +62,8 @@ class ApplicationConfig extends AbstractR2dbcConfiguration {
----
====
Because our domain repository extends `ReactiveCrudRepository`, it provides you with CRUD operations to access the entities.
Because our domain repository extends `ReactiveCrudRepository`, it provides you with reactive CRUD operations to access the entities.
On top of `ReactiveCrudRepository`, there is also `ReactiveSortingRepository`, which adds additional sorting functionality similar to that of `PagingAndSortingRepository`.
Working with the repository instance is merely a matter of dependency injecting it into a client.
Consequently, you can retrieve all `Person` objects with the following code:
@@ -111,7 +112,7 @@ Defining such a query is a matter of declaring a method on the repository interf
====
[source,java]
----
interface ReactivePersonRepository extends ReactiveSortingRepository<Person, String> {
interface ReactivePersonRepository extends ReactiveSortingRepository<Person, Long> {
Flux<Person> findByFirstname(String firstname); <1>

View File

@@ -16,12 +16,13 @@
package org.springframework.data.r2dbc.repository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
/**
* R2DBC specific {@link org.springframework.data.repository.Repository} interface with reactive support.
*
* @author Mark Paluch
* @author Stephen Cohen
*/
@NoRepositoryBean
public interface R2dbcRepository<T, ID> extends ReactiveCrudRepository<T, ID> {}
public interface R2dbcRepository<T, ID> extends ReactiveSortingRepository<T, ID> {}

View File

@@ -34,7 +34,7 @@ import org.springframework.util.Assert;
*
* @author Mark Paluch
* @author Christoph Strobl
* @see org.springframework.data.repository.reactive.ReactiveCrudRepository
* @see org.springframework.data.repository.reactive.ReactiveSortingRepository
*/
public class R2dbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
extends RepositoryFactoryBeanSupport<T, S, ID> {

View File

@@ -20,6 +20,7 @@ import reactor.core.publisher.Mono;
import org.reactivestreams.Publisher;
import org.springframework.data.domain.Sort;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
@@ -29,20 +30,21 @@ import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.query.Query;
import org.springframework.data.relational.repository.query.RelationalEntityInformation;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
import org.springframework.data.util.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
/**
* Simple {@link ReactiveCrudRepository} implementation using R2DBC through {@link DatabaseClient}.
* Simple {@link ReactiveSortingRepository} implementation using R2DBC through {@link DatabaseClient}.
*
* @author Mark Paluch
* @author Jens Schauder
* @author Mingyuan Wu
* @author Stephen Cohen
*/
@Transactional(readOnly = true)
public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, ID> {
public class SimpleR2dbcRepository<T, ID> implements ReactiveSortingRepository<T, ID> {
private final RelationalEntityInformation<T, ID> entity;
private final R2dbcEntityOperations entityOperations;
@@ -172,6 +174,14 @@ public class SimpleR2dbcRepository<T, ID> implements ReactiveCrudRepository<T, I
return this.entityOperations.select(Query.empty(), this.entity.getJavaType());
}
/* (non-Javadoc)
* @see org.springframework.data.repository.reactive.ReactiveSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
@Override
public Flux<T> findAll(Sort sort) {
return this.entityOperations.select(Query.empty().sort(sort), this.entity.getJavaType());
}
/* (non-Javadoc)
* @see org.springframework.data.repository.reactive.ReactiveCrudRepository#findAllById(java.lang.Iterable)
*/

View File

@@ -48,7 +48,7 @@ import org.springframework.data.r2dbc.repository.support.R2dbcRepositoryFactory;
import org.springframework.data.r2dbc.testing.R2dbcIntegrationTestSupport;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.data.repository.reactive.ReactiveSortingRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.reactive.TransactionalOperator;
@@ -56,6 +56,7 @@ import org.springframework.transaction.reactive.TransactionalOperator;
* Abstract base class for integration tests for {@link LegoSetRepository} using {@link R2dbcRepositoryFactory}.
*
* @author Mark Paluch
* @author Stephen Cohen
*/
public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport {
@@ -303,7 +304,7 @@ public abstract class AbstractR2dbcRepositoryIntegrationTests extends R2dbcInteg
}
@NoRepositoryBean
interface LegoSetRepository extends ReactiveCrudRepository<LegoSet, Integer> {
interface LegoSetRepository extends ReactiveSortingRepository<LegoSet, Integer> {
Flux<LegoSet> findByNameContains(String name);

View File

@@ -39,6 +39,7 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.domain.Persistable;
import org.springframework.data.domain.Sort;
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter;
import org.springframework.data.r2dbc.core.DatabaseClient;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
@@ -55,6 +56,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
*
* @author Mark Paluch
* @author Bogdan Ilchyshyn
* @author Stephen Cohen
*/
public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2dbcIntegrationTestSupport {
@@ -313,6 +315,26 @@ public abstract class AbstractSimpleR2dbcRepositoryIntegrationTests extends R2db
}).verifyComplete();
}
@Test // gh-407
public void shouldFindAllWithSort() {
jdbc.execute("INSERT INTO legoset (name, manual) VALUES('FORSCHUNGSSCHIFF', 13)");
jdbc.execute("INSERT INTO legoset (name, manual) VALUES('SCHAUFELRADBAGGER', 12)");
jdbc.execute("INSERT INTO legoset (name, manual) VALUES('VOLTRON', 15)");
jdbc.execute("INSERT INTO legoset (name, manual) VALUES('RALLYEAUTO', 14)");
repository.findAll(Sort.by("manual").ascending()) //
.map(LegoSet::getName) //
.collectList() //
.as(StepVerifier::create) //
.assertNext(actual -> assertThat(actual).containsExactly(
"SCHAUFELRADBAGGER",
"FORSCHUNGSSCHIFF",
"RALLYEAUTO",
"VOLTRON"
)).verifyComplete();
}
@Test
public void shouldFindAllByIdUsingIterable() {