DATAMONGO-1979 - Polishing.

Rename QueryUtils method to decorateSort(…) to reflect the nature of the method. Add missing generics. Convert ReactiveMongoRepositoryTests to AssertJ. Add missing verifyComplete() steps to StepVerifier. Slight tweaks to Javadoc and reference docs.

Original pull request: #566.
This commit is contained in:
Mark Paluch
2018-06-07 09:57:51 +02:00
parent 8f11916014
commit 794b026f73
9 changed files with 43 additions and 40 deletions

View File

@@ -80,14 +80,14 @@ public @interface Query {
/**
* Defines a default sort order for the given query.<br />
* <strong>NOTE</strong> The so set defaults can be altered / overwritten via an explicit
* <strong>NOTE:</strong> The so set defaults can be altered / overwritten using an explicit
* {@link org.springframework.data.domain.Sort} argument of the query method.
*
* <pre>
* <code>
*
*
* &#64;Query(sort = "{ age : -1 }") // order by age descending
* List<Person> findByFirstname(String firstname);
* List<Person> findByFirstname(String firstname);
* </code>
* </pre>
*

View File

@@ -151,7 +151,7 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
return query;
}
return QueryUtils.sneakInDefaultSort(query, Document.parse(method.getAnnotatedSort()));
return QueryUtils.decorateSort(query, Document.parse(method.getAnnotatedSort()));
}
/**

View File

@@ -193,7 +193,7 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery {
return query;
}
return QueryUtils.sneakInDefaultSort(query, Document.parse(method.getAnnotatedSort()));
return QueryUtils.decorateSort(query, Document.parse(method.getAnnotatedSort()));
}
/**

View File

@@ -80,7 +80,7 @@ public class MongoQueryMethod extends QueryMethod {
this.method = method;
this.mappingContext = mappingContext;
this.annotationCache = new ConcurrentReferenceHashMap();
this.annotationCache = new ConcurrentReferenceHashMap<>();
}
/*
@@ -124,6 +124,7 @@ public class MongoQueryMethod extends QueryMethod {
*
* @return
*/
@Nullable
String getFieldSpecification() {
return lookupQueryAnnotation() //
@@ -159,7 +160,7 @@ public class MongoQueryMethod extends QueryMethod {
MongoPersistentEntity<?> collectionEntity = domainClass.isAssignableFrom(returnedObjectType) ? returnedEntity
: managedEntity;
this.metadata = new SimpleMongoEntityMetadata<Object>((Class<Object>) returnedEntity.getType(),
this.metadata = new SimpleMongoEntityMetadata<>((Class<Object>) returnedEntity.getType(),
collectionEntity);
}
}
@@ -315,9 +316,10 @@ public class MongoQueryMethod extends QueryMethod {
"Expected to find @Query annotation but did not. Make sure to check hasAnnotatedSort() before."));
}
@SuppressWarnings("unchecked")
private <A extends Annotation> Optional<A> doFindAnnotation(Class<A> annotationType) {
return (Optional) this.annotationCache.computeIfAbsent(annotationType,
return (Optional<A>) this.annotationCache.computeIfAbsent(annotationType,
it -> Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method, it)));
}
}

View File

@@ -31,14 +31,14 @@ import org.springframework.data.mongodb.core.query.Query;
class QueryUtils {
/**
* Add a default sort expression to the given Query. Attributes of the given {@code sort} may be overwritten by the
* sort explicitly defined by the {@link Query} itself.
* Decorate {@link Query} and add a default sort expression to the given {@link Query}. Attributes of the given
* {@code sort} may be overwritten by the sort explicitly defined by the {@link Query} itself.
*
* @param query the {@link Query} to decorate.
* @param defaultSort the default sort expression to apply to the query.
* @return the query having the given {@code sort} applied.
*/
static Query sneakInDefaultSort(Query query, Document defaultSort) {
static Query decorateSort(Query query, Document defaultSort) {
if (defaultSort.isEmpty()) {
return query;

View File

@@ -79,7 +79,7 @@ public class ReactiveMongoQueryMethod extends MongoQueryMethod {
ClassUtils.getShortName(method.getDeclaringClass()), method.getName()));
}
if (!multiWrapper && !singleWrapperWithWrappedPageableResult) {
if (!multiWrapper) {
throw new IllegalStateException(String.format(
"Method has to use a either multi-item reactive wrapper return type or a wrapped Page/Slice type. Offending method: %s",
method.toString()));

View File

@@ -15,13 +15,11 @@
*/
package org.springframework.data.mongodb.repository;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.assertj.core.api.Assertions.offset;
import static org.springframework.data.domain.Sort.Direction.*;
import static org.springframework.data.mongodb.test.util.Assertions.assertThat;
import lombok.NoArgsConstructor;
import org.hamcrest.collection.IsIterableContainingInOrder;
import org.springframework.data.domain.Sort.Direction;
import reactor.core.Disposable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -45,6 +43,7 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
@@ -130,12 +129,12 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
@Test // DATAMONGO-1444
public void shouldFindOneByLastName() {
StepVerifier.create(repository.findOneByLastname(carter.getLastname())).expectNext(carter);
StepVerifier.create(repository.findOneByLastname(carter.getLastname())).expectNext(carter).verifyComplete();
}
@Test // DATAMONGO-1444
public void shouldFindOneByPublisherOfLastName() {
StepVerifier.create(repository.findByLastname(Mono.just(carter.getLastname()))).expectNext(carter);
StepVerifier.create(repository.findByLastname(Mono.just(carter.getLastname()))).expectNext(carter).verifyComplete();
}
@Test // DATAMONGO-1444
@@ -164,6 +163,7 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
@Test // DATAMONGO-1444
public void shouldFindByLastNameAndSort() {
StepVerifier.create(repository.findByLastname("Matthews", Sort.by(ASC, "age"))) //
.expectNext(oliver, dave) //
.verifyComplete();
@@ -188,11 +188,11 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
Disposable disposable = cappedRepository.findByKey("value").doOnNext(documents::add).subscribe();
assertThat(documents.poll(5, TimeUnit.SECONDS), is(notNullValue()));
assertThat(documents.poll(5, TimeUnit.SECONDS)).isNotNull();
StepVerifier.create(template.insert(new Capped("value", Math.random()))).expectNextCount(1).verifyComplete();
assertThat(documents.poll(5, TimeUnit.SECONDS), is(notNullValue()));
assertThat(documents.isEmpty(), is(true));
assertThat(documents.poll(5, TimeUnit.SECONDS)).isNotNull();
assertThat(documents).isEmpty();
disposable.dispose();
}
@@ -213,16 +213,16 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
Disposable disposable = cappedRepository.findProjectionByKey("value").doOnNext(documents::add).subscribe();
CappedProjection projection1 = documents.poll(5, TimeUnit.SECONDS);
assertThat(projection1, is(notNullValue()));
assertThat(projection1.getRandom(), is(not(0)));
assertThat(projection1).isNotNull();
assertThat(projection1.getRandom()).isNotEqualTo(0);
StepVerifier.create(template.insert(new Capped("value", Math.random()))).expectNextCount(1).verifyComplete();
CappedProjection projection2 = documents.poll(5, TimeUnit.SECONDS);
assertThat(projection2, is(notNullValue()));
assertThat(projection2.getRandom(), is(not(0)));
assertThat(projection2).isNotNull();
assertThat(projection2.getRandom()).isNotEqualTo(0);
assertThat(documents.isEmpty(), is(true));
assertThat(documents).isEmpty();
disposable.dispose();
}
@@ -263,8 +263,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
new Distance(2000, Metrics.KILOMETERS)) //
).consumeNextWith(actual -> {
assertThat(actual.getDistance().getValue(), is(closeTo(1, 1)));
assertThat(actual.getContent(), is(equalTo(dave)));
assertThat(actual.getDistance().getValue()).isCloseTo(1, offset(1d));
assertThat(actual.getContent()).isEqualTo(dave);
}).verifyComplete();
}
@@ -280,8 +280,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
PageRequest.of(0, 10))) //
.consumeNextWith(actual -> {
assertThat(actual.getDistance().getValue(), is(closeTo(1, 1)));
assertThat(actual.getContent(), is(equalTo(dave)));
assertThat(actual.getDistance().getValue()).isCloseTo(1, offset(1d));
assertThat(actual.getContent()).isEqualTo(dave);
}).verifyComplete();
}
@@ -313,8 +313,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
public void findAppliesAnnotatedSort() {
repository.findByAgeGreaterThan(40).collectList().as(StepVerifier::create).consumeNextWith(result -> {
assertThat(result, IsIterableContainingInOrder.contains(carter, boyd, dave, leroi));
});
assertThat(result).containsSequence(carter, boyd, dave, leroi);
}).verifyComplete();
}
@Test // DATAMONGO-1979
@@ -322,8 +322,8 @@ public class ReactiveMongoRepositoryTests implements BeanClassLoaderAware, BeanF
repository.findByAgeGreaterThan(40, Sort.by(Direction.ASC, "age")).collectList().as(StepVerifier::create)
.consumeNextWith(result -> {
assertThat(result, IsIterableContainingInOrder.contains(leroi, dave, boyd, carter));
});
assertThat(result).containsSequence(leroi, dave, boyd, carter);
}).verifyComplete();
}
interface ReactivePersonRepository extends ReactiveMongoRepository<Person, String> {

View File

@@ -13,6 +13,7 @@
* Tailable cursors for imperative driver.
* <<mongo.sessions, MongoDB 3.6 Session>> support for the imperative and reactive Template APIs.
* <<mongo.transactions, MongoDB 4.0 Transaction>> support and a MongoDB-specific transaction manager implementation.
* <<mongodb.repositories.queries.sort,Default sort specifications for repository query methods>> using `@Query(sort=…)`.
[[new-features.2-0-0]]
== What's New in Spring Data MongoDB 2.0

View File

@@ -398,9 +398,9 @@ The query in the preceding example returns only the `firstname`, `lastname` and
[[mongodb.repositories.queries.sort]]
=== Sorting Query Method results
When it comes to sorting MongoDB query results via the repository interface there are several options as listed below.
MongoDB repositories allow various approaches to define sorting order. Let's take a look at the following example:
.Sorting query results
.Sorting Query Results
====
[source,java]
----
@@ -417,10 +417,10 @@ public interface PersonRepository extends MongoRepository<Person, String> {
List<Person> findByLastname(String lastname, Sort sort); <4>
}
----
<1> Fixed sorting derived from method name. `SortByAgeDesc` results in `{ age : -1 }` sort parameter.
<2> Dynamic sorting via method argument. `Sort.by(DESC, "age")` creates a `{ age : -1 }` sort parameter.
<3> Fixed sorting via `Query` annotation. Sort parameter applied as stated in the `sort` attribute.
<4> Default sorting via `Query` annotation combined with dynamic one via method argument. `Sort.unsorted()`
<1> Static sorting derived from method name. `SortByAgeDesc` results in `{ age : -1 }` for the sort parameter.
<2> Dynamic sorting using a method argument. `Sort.by(DESC, "age")` creates `{ age : -1 }` for the sort parameter.
<3> Static sorting via `Query` annotation. Sort parameter applied as stated in the `sort` attribute.
<4> Default sorting via `Query` annotation combined with dynamic one via a method argument. `Sort.unsorted()`
results in `{ age : -1 }`. Using `Sort.by(ASC, "age")` overrides the defaults and creates `{ age : 1 }`. `Sort.by
(ASC, "firstname")` alters the default and results in `{ age : -1, firstname : 1 }`.
====