Browse Source

Aggregation query method should be able to return Slice and Stream.

Aggregation query methods can not return Slice and Stream.

interface PersonRepository extends CrudReppsitory<Person, String> {

  @Aggregation("{ $group: { _id : $lastname, names : { $addToSet : ?0 } } }")
  Slice<PersonAggregate> groupByLastnameAnd(String property, Pageable page);

  @Aggregation("{ $group: { _id : $lastname, names : { $addToSet : $firstname } } }")
  Stream<PersonAggregate> groupByLastnameAndFirstnamesAsStream();
}

Closes #3543.
Original pull request: #3645.
pull/3647/head
divya_jnu08 5 years ago committed by Mark Paluch
parent
commit
9a48e32565
No known key found for this signature in database
GPG Key ID: 4406B84C1661DCD1
  1. 22
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java
  2. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedAggregation.java
  3. 15
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationUnitTests.java

22
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java

@ -145,6 +145,28 @@ abstract class AggregationUtils { @@ -145,6 +145,28 @@ abstract class AggregationUtils {
aggregationPipeline.add(Aggregation.limit(pageable.getPageSize()));
}
/**
* Append {@code $skip} and {@code $limit} aggregation stage if {@link ConvertingParameterAccessor#getSort()} is
* present.
*
* @param aggregationPipeline
* @param accessor
*/
static void appendModifiedLimitAndOffsetIfPresent(List<AggregationOperation> aggregationPipeline,
ConvertingParameterAccessor accessor) {
Pageable pageable = accessor.getPageable();
if (pageable.isUnpaged()) {
return;
}
if (pageable.getOffset() > 0) {
aggregationPipeline.add(Aggregation.skip(pageable.getOffset()));
}
aggregationPipeline.add(Aggregation.limit(pageable.getPageSize()+1));
}
/**
* Extract a single entry from the given {@link Document}. <br />

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringBasedAggregation.java

@ -20,6 +20,8 @@ import java.util.List; @@ -20,6 +20,8 @@ import java.util.List;
import java.util.stream.Collectors;
import org.bson.Document;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.core.MongoOperations;
@ -76,18 +78,17 @@ public class StringBasedAggregation extends AbstractMongoQuery { @@ -76,18 +78,17 @@ public class StringBasedAggregation extends AbstractMongoQuery {
protected Object doExecute(MongoQueryMethod method, ResultProcessor resultProcessor,
ConvertingParameterAccessor accessor, Class<?> typeToRead) {
if (method.isPageQuery() || method.isSliceQuery()) {
throw new InvalidMongoDbApiUsageException(String.format(
"Repository aggregation method '%s' does not support '%s' return type. Please use eg. 'List' instead.",
method.getName(), method.getReturnType().getType().getSimpleName()));
}
Class<?> sourceType = method.getDomainClass();
Class<?> targetType = typeToRead;
List<AggregationOperation> pipeline = computePipeline(method, accessor);
AggregationUtils.appendSortIfPresent(pipeline, accessor, typeToRead);
AggregationUtils.appendLimitAndOffsetIfPresent(pipeline, accessor);
if (method.isSliceQuery()) {
AggregationUtils.appendModifiedLimitAndOffsetIfPresent(pipeline, accessor);
}else{
AggregationUtils.appendLimitAndOffsetIfPresent(pipeline, accessor);
}
boolean isSimpleReturnType = isSimpleReturnType(typeToRead);
boolean isRawAggregationResult = ClassUtils.isAssignable(AggregationResults.class, typeToRead);
@ -118,7 +119,17 @@ public class StringBasedAggregation extends AbstractMongoQuery { @@ -118,7 +119,17 @@ public class StringBasedAggregation extends AbstractMongoQuery {
return result.getMappedResults();
}
List mappedResults = result.getMappedResults();
if(method.isSliceQuery()) {
Pageable pageable = accessor.getPageable();
int pageSize = pageable.getPageSize();
boolean hasNext = mappedResults.size() > pageSize;
return new SliceImpl<Object>(hasNext ? mappedResults.subList(0, pageSize) : mappedResults, pageable, hasNext);
}
Object uniqueResult = result.getUniqueMappedResult();
return isSimpleReturnType

15
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationUnitTests.java

@ -36,6 +36,8 @@ import org.mockito.Mock; @@ -36,6 +36,8 @@ import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -220,13 +222,10 @@ public class StringBasedAggregationUnitTests { @@ -220,13 +222,10 @@ public class StringBasedAggregationUnitTests {
}
@Test // DATAMONGO-2506
public void aggregateRaisesErrorOnInvalidReturnType() {
StringBasedAggregation sba = createAggregationForMethod("invalidPageReturnType", Pageable.class);
assertThatExceptionOfType(InvalidMongoDbApiUsageException.class) //
.isThrownBy(() -> sba.execute(new Object[] { PageRequest.of(0, 1) })) //
.withMessageContaining("invalidPageReturnType") //
.withMessageContaining("Page");
public void aggregationWithSliceReturnType() {
StringBasedAggregation sba = createAggregationForMethod("aggregationWithSliceReturnType", Pageable.class);
Object result = sba.execute(new Object[] { PageRequest.of(0, 1) });
assertThat(result.getClass()).isEqualTo(SliceImpl.class);
}
@Test // DATAMONGO-2557
@ -319,7 +318,7 @@ public class StringBasedAggregationUnitTests { @@ -319,7 +318,7 @@ public class StringBasedAggregationUnitTests {
PersonAggregate aggregateWithCollation(Collation collation);
@Aggregation(RAW_GROUP_BY_LASTNAME_STRING)
Page<Person> invalidPageReturnType(Pageable page);
Slice<Person> aggregationWithSliceReturnType(Pageable page);
@Aggregation(RAW_GROUP_BY_LASTNAME_STRING)
String simpleReturnType();

Loading…
Cancel
Save