Skip to content

Commit 6a4a748

Browse files
authored
DATAES-749 - Introduce SearchPage as return type for repository methods.
Original PR: spring-projects#397
1 parent dc795eb commit 6a4a748

File tree

6 files changed

+145
-4
lines changed

6 files changed

+145
-4
lines changed

src/main/java/org/springframework/data/elasticsearch/core/SearchHitSupport.java

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@
2121
import java.util.stream.Collectors;
2222
import java.util.stream.Stream;
2323

24+
import org.springframework.data.domain.PageImpl;
2425
import org.springframework.data.domain.Pageable;
2526
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
2627
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
28+
import org.springframework.data.elasticsearch.support.ReactiveSupport;
29+
import org.springframework.lang.Nullable;
2730

2831
/**
2932
* Utility class with helper methods for working with {@link SearchHit}.
@@ -75,9 +78,12 @@ public static Object unwrapSearchHits(Object result) {
7578
return unwrapSearchHits(searchHits.getSearchHits());
7679
}
7780

78-
if (result instanceof Flux) {
79-
Flux<?> flux = (Flux<?>) result;
80-
return flux.map(SearchHitSupport::unwrapSearchHits);
81+
if (ReactiveSupport.isReactorAvailable()) {
82+
83+
if (result instanceof Flux) {
84+
Flux<?> flux = (Flux<?>) result;
85+
return flux.map(SearchHitSupport::unwrapSearchHits);
86+
}
8187
}
8288

8389
return result;
@@ -94,4 +100,28 @@ public static <T> AggregatedPage<SearchHit<T>> page(SearchHits<T> searchHits, Pa
94100
return new AggregatedPageImpl<>(searchHits.getSearchHits(), pageable, searchHits.getTotalHits(),
95101
searchHits.getAggregations(), searchHits.getScrollId(), searchHits.getMaxScore());
96102
}
103+
104+
public static <T> SearchPage<T> searchPageFor(SearchHits<T> searchHits, @Nullable Pageable pageable) {
105+
return new SearchPageImpl<>(searchHits, (pageable != null) ? pageable : Pageable.unpaged());
106+
}
107+
108+
/**
109+
* SearchPage implementation.
110+
*
111+
* @param <T>
112+
*/
113+
static class SearchPageImpl<T> extends PageImpl<SearchHit<T>> implements SearchPage<T> {
114+
115+
private final SearchHits<T> searchHits;
116+
117+
public SearchPageImpl(SearchHits<T> searchHits, Pageable pageable) {
118+
super(searchHits.getSearchHits(), pageable, searchHits.getTotalHits());
119+
this.searchHits = searchHits;
120+
}
121+
122+
@Override
123+
public SearchHits<T> getSearchHits() {
124+
return searchHits;
125+
}
126+
}
97127
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.core;
17+
18+
import org.springframework.data.domain.Page;
19+
20+
/**
21+
* Page definition for repositories that need to return a paged SearchHits.
22+
*
23+
* @author Peter-Josef Meisch
24+
* @since 4.0
25+
*/
26+
public interface SearchPage<T> extends Page<SearchHit<T>> {
27+
SearchHits<T> getSearchHits();
28+
}

src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ public Object execute(Object[] parameters) {
8686
} else if (queryMethod.isPageQuery()) {
8787
query.setPageable(accessor.getPageable());
8888
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
89-
result = SearchHitSupport.page(searchHits, query.getPageable());
89+
if (queryMethod.isSearchPageMethod()) {
90+
result = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
91+
} else {
92+
result = SearchHitSupport.page(searchHits, query.getPageable());
93+
}
9094
} else if (queryMethod.isStreamQuery()) {
9195
if (accessor.getPageable().isUnpaged()) {
9296
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));

src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchQueryMethod.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.elasticsearch.annotations.Query;
2626
import org.springframework.data.elasticsearch.core.SearchHit;
2727
import org.springframework.data.elasticsearch.core.SearchHits;
28+
import org.springframework.data.elasticsearch.core.SearchPage;
2829
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
2930
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
3031
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
@@ -171,6 +172,25 @@ public boolean isSearchHitMethod() {
171172
return false;
172173
}
173174

175+
/**
176+
* checks if the return type is {@link SearchPage}.
177+
*
178+
* @since 4.0
179+
*/
180+
public boolean isSearchPageMethod() {
181+
return SearchPage.class.isAssignableFrom(methodReturnType());
182+
}
183+
184+
/**
185+
* retusn the declared return type for this method.
186+
*
187+
* @return the return type
188+
* @since 4.0
189+
*/
190+
public Class<?> methodReturnType() {
191+
return method.getReturnType();
192+
}
193+
174194
protected boolean isAllowedGenericType(ParameterizedType methodGenericReturnType) {
175195
return Collection.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType())
176196
|| Stream.class.isAssignableFrom((Class<?>) methodGenericReturnType.getRawType());
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.support;
17+
18+
import java.util.concurrent.atomic.AtomicBoolean;
19+
20+
import org.springframework.data.repository.util.ClassUtils;
21+
22+
/**
23+
* @author Peter-Josef Meisch
24+
* @since 4.0
25+
*/
26+
public final class ReactiveSupport {
27+
private ReactiveSupport() {}
28+
29+
/**
30+
* @return true if project reactor is on the classpath
31+
*/
32+
public static boolean isReactorAvailable() {
33+
AtomicBoolean available = new AtomicBoolean(false);
34+
ClassUtils.ifPresent("reactor.core.publisher.Flux", null, aClass -> {
35+
available.set(true);
36+
});
37+
return available.get();
38+
}
39+
}

src/test/java/org/springframework/data/elasticsearch/repositories/custommethod/CustomMethodRepositoryBaseTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import org.springframework.data.elasticsearch.core.IndexOperations;
5454
import org.springframework.data.elasticsearch.core.SearchHit;
5555
import org.springframework.data.elasticsearch.core.SearchHits;
56+
import org.springframework.data.elasticsearch.core.SearchPage;
5657
import org.springframework.data.elasticsearch.core.geo.GeoBox;
5758
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
5859
import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder;
@@ -1479,6 +1480,23 @@ void shouldUseGeoSortParameter() {
14791480
assertThat(searchHits.getSearchHit(2).getId()).isEqualTo("oslo");
14801481
}
14811482

1483+
@Test // DATAES-749
1484+
void shouldReturnSearchPage() {
1485+
List<SampleEntity> entities = createSampleEntities("abc", 20);
1486+
repository.saveAll(entities);
1487+
1488+
// when
1489+
SearchPage<SampleEntity> searchPage = repository.searchByMessage("Message", PageRequest.of(0, 10));
1490+
1491+
assertThat(searchPage).isNotNull();
1492+
SearchHits<SampleEntity> searchHits = searchPage.getSearchHits();
1493+
assertThat(searchHits).isNotNull();
1494+
assertThat((searchHits.getTotalHits())).isEqualTo(20);
1495+
assertThat(searchHits.getSearchHits()).hasSize(10);
1496+
Pageable nextPageable = searchPage.nextPageable();
1497+
assertThat((nextPageable.getPageNumber())).isEqualTo(1);
1498+
}
1499+
14821500
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
14831501

14841502
List<SampleEntity> entities = new ArrayList<>();
@@ -1627,6 +1645,8 @@ public interface SampleCustomMethodRepository extends ElasticsearchRepository<Sa
16271645
Stream<SearchHit<SampleEntity>> readByMessage(String message);
16281646

16291647
SearchHits<SampleEntity> searchBy(Sort sort);
1648+
1649+
SearchPage<SampleEntity> searchByMessage(String message, Pageable pageable);
16301650
}
16311651

16321652
/**

0 commit comments

Comments
 (0)