Browse Source

Polishing.

Move SliceUtils to another package for reuse. Slightly alter its API, add tests and update javadoc.

Original Pull Request: #4890
pull/4906/head
Christoph Strobl 10 months ago
parent
commit
49db28dc77
No known key found for this signature in database
GPG Key ID: E6054036D0C37A4B
  1. 3
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java
  2. 7
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java
  3. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
  4. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
  5. 10
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbQuery.java
  6. 37
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/util/SliceUtils.java
  7. 80
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/util/SliceUtilsUnitTests.java

3
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java

@ -36,6 +36,7 @@ import org.springframework.data.mongodb.core.MongoOperations; @@ -36,6 +36,7 @@ import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
import org.springframework.data.mongodb.repository.util.SliceUtils;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
@ -87,7 +88,7 @@ interface MongoQueryExecution { @@ -87,7 +88,7 @@ interface MongoQueryExecution {
int pageSize = pageable.getPageSize();
// Apply Pageable but tweak limit to peek into next page
Query modifiedQuery = query.with(pageable).limit(pageSize + 1);
Query modifiedQuery = SliceUtils.limitResult(query, pageable).with(pageable.getSort());
List result = find.matching(modifiedQuery).all();
boolean hasNext = result.size() > pageSize;

7
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.repository.support;
import org.springframework.data.mongodb.repository.util.SliceUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -113,14 +114,16 @@ class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<Re @@ -113,14 +114,16 @@ class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<Re
/**
* Fetch all matching query results as Slice.
*
* @param pageable defines range and sort of requested slice
* @return {@link Mono} emitting the requested Slice.
* @since 4.5
*/
Mono<Slice<K>> fetchSlice(Pageable pageable) {
Mono<List<K>> content = createQuery().map(it -> SliceUtils.getQuery(it, pageable))
Mono<List<K>> content = createQuery().map(it -> SliceUtils.limitResult(it, pageable).with(pageable.getSort()))
.flatMapMany(it -> find.matching(it).all()).collectList();
return content.map(it -> SliceUtils.getSlice(it, pageable));
return content.map(it -> SliceUtils.sliceResult(it, pageable));
}
/**

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java

@ -43,6 +43,7 @@ import org.springframework.data.mongodb.core.query.Criteria; @@ -43,6 +43,7 @@ import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
import org.springframework.data.mongodb.repository.util.SliceUtils;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.data.util.StreamUtils;
import org.springframework.data.util.Streamable;
@ -460,9 +461,9 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> { @@ -460,9 +461,9 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
Assert.notNull(pageable, "Pageable must not be null");
List<T> resultList = createQuery(q -> SliceUtils.getQuery(q, pageable)).all();
List<T> resultList = createQuery(q -> SliceUtils.limitResult(q, pageable).with(pageable.getSort())).all();
return SliceUtils.getSlice(resultList, pageable);
return SliceUtils.sliceResult(resultList, pageable);
}
@Override

5
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java

@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.support; @@ -17,6 +17,7 @@ package org.springframework.data.mongodb.repository.support;
import static org.springframework.data.mongodb.core.query.Criteria.*;
import org.springframework.data.mongodb.repository.util.SliceUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -596,8 +597,8 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -596,8 +597,8 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
@Override
public Mono<Slice<T>> slice(Pageable pageable) {
return createQuery(q -> SliceUtils.getQuery(q, pageable)).all().collectList()
.map(it -> SliceUtils.getSlice(it, pageable));
return createQuery(q -> SliceUtils.limitResult(q, pageable).with(pageable.getSort())).all().collectList()
.map(it -> SliceUtils.sliceResult(it, pageable));
}
@Override

10
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbQuery.java

@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.MongoOperations; @@ -34,6 +34,7 @@ import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.mapping.FieldName;
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.repository.util.SliceUtils;
import org.springframework.data.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
@ -187,14 +188,15 @@ public class SpringDataMongodbQuery<T> extends SpringDataMongodbQuerySupport<Spr @@ -187,14 +188,15 @@ public class SpringDataMongodbQuery<T> extends SpringDataMongodbQuerySupport<Spr
/**
* Fetch a {@link Slice}.
*
* @param pageable
* @return
* @param pageable defines range and sort of requested slice
* @return new instance of {@link Slice} containing matching results within range.
* @since 4.5
*/
public Slice<T> fetchSlice(Pageable pageable) {
List<T> content = find.matching(SliceUtils.getQuery(createQuery(), pageable)).all();
List<T> content = find.matching(SliceUtils.limitResult(createQuery(), pageable).with(pageable.getSort())).all();
return SliceUtils.getSlice(content, pageable);
return SliceUtils.sliceResult(content, pageable);
}
@Override

37
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SliceUtils.java → spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/util/SliceUtils.java

@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.support;
package org.springframework.data.mongodb.repository.util;
import java.util.List;
@ -26,19 +26,21 @@ import org.springframework.data.mongodb.core.query.Query; @@ -26,19 +26,21 @@ import org.springframework.data.mongodb.core.query.Query;
* Utility methods for {@link Slice} handling.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 4.5
*/
class SliceUtils {
public class SliceUtils {
/**
* Creates a {@link Slice} given {@link Pageable} and {@link List} of results.
*
* @param <T>
* @param resultList
* @param pageable
* @return
* @param <T> the element type.
* @param resultList the source list holding the result of the request. If the result list contains more elements
* (indicating a next slice is available) it is trimmed to the {@link Pageable#getPageSize() page size}.
* @param pageable the source pageable.
* @return new instance of {@link Slice}.
*/
public static <T> Slice<T> getSlice(List<T> resultList, Pageable pageable) {
public static <T> Slice<T> sliceResult(List<T> resultList, Pageable pageable) {
boolean hasNext = resultList.size() > pageable.getPageSize();
@ -50,16 +52,23 @@ class SliceUtils { @@ -50,16 +52,23 @@ class SliceUtils {
}
/**
* Customize query for slice retrieval.
* Customize query for {@link #sliceResult sliced result} retrieval. If {@link Pageable#isPaged() paged} the
* {@link Query#limit(int) limit} is set to {@code pagesize + 1} in order to determine if more data is available.
*
* @param query
* @param pageable
* @return
* @param query the source query
* @param pageable paging to apply.
* @return new instance of {@link Query} if either {@link Pageable#isPaged() paged}, the source query otherwise.
*/
public static Query getQuery(Query query, Pageable pageable) {
public static Query limitResult(Query query, Pageable pageable) {
query.with(pageable);
if (pageable.isUnpaged()) {
return query;
}
Query target = Query.of(query);
target.skip(pageable.getOffset());
target.limit(pageable.getPageSize() + 1);
return pageable.isPaged() ? query.limit(pageable.getPageSize() + 1) : query;
return target;
}
}

80
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/util/SliceUtilsUnitTests.java

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verifyNoInteractions;
import java.util.stream.Stream;
import org.bson.Document;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
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.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.core.query.Query;
/**
* Unit test for {@link SliceUtils}.
*
* @author Christoph Strobl
*/
class SliceUtilsUnitTests {
@ParameterizedTest // GH-4889
@MethodSource("paged")
void pagedPageableModifiesQuery(Pageable page) {
Query source = new BasicQuery(Document.parse("{ 'spring' : 'data' }"));
Query target = SliceUtils.limitResult(source, page);
assertThat(target.getQueryObject()).isEqualTo(source.getQueryObject());
assertThat(target).isNotSameAs(source);
assertThat(target.isLimited()).isTrue();
assertThat(target.getSkip()).isEqualTo(page.getOffset());
assertThat(target.getLimit()).isEqualTo(page.toLimit().max() + 1);
assertThat(target.getSortObject()).isEqualTo(source.getSortObject());
}
@ParameterizedTest // GH-4889
@MethodSource("unpaged")
void unpagedPageableDoesNotModifyQuery(Pageable page) {
Query source = spy(new BasicQuery(Document.parse("{ 'spring' : 'data' }")));
Query target = SliceUtils.limitResult(source, page);
verifyNoInteractions(source);
assertThat(target).isSameAs(source);
assertThat(target.isLimited()).isFalse();
}
public static Stream<Arguments> paged() {
return Stream.of(Arguments.of(Pageable.ofSize(1)), Arguments.of(PageRequest.of(0, 10)),
Arguments.of(PageRequest.of(0, 10, Direction.ASC, "name")));
}
public static Stream<Arguments> unpaged() {
return Stream.of(Arguments.of(Pageable.unpaged()), Arguments.of(Pageable.unpaged(Sort.by("name"))));
}
}
Loading…
Cancel
Save