Skip to content

Aggregation query method should be able to return Slice and Stream #3645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,28 @@ static void appendLimitAndOffsetIfPresent(List<AggregationOperation> aggregation

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 />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
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;
Expand Down Expand Up @@ -76,18 +78,17 @@ public StringBasedAggregation(MongoQueryMethod method, MongoOperations mongoOper
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);
Expand Down Expand Up @@ -118,7 +119,17 @@ protected Object doExecute(MongoQueryMethod method, ResultProcessor resultProces

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
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;
Expand Down Expand Up @@ -220,13 +222,10 @@ public void aggregateWithCollationParameter() {
}

@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
Expand Down Expand Up @@ -319,7 +318,7 @@ private interface SampleRepository extends Repository<Person, Long> {
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();
Expand Down