mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-13 07:32:11 +00:00
Add Kotlin extensions for several interfaces and CoroutineElasticsearchRepository.
Original Pull Request #2573 Closes #2545
This commit is contained in:
parent
f973236588
commit
cf09e57736
32
pom.xml
32
pom.xml
@ -202,6 +202,31 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Kotlin extension -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-reactor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
@ -215,6 +240,13 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
|
@ -27,6 +27,4 @@ import org.springframework.data.repository.reactive.ReactiveSortingRepository;
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface ReactiveElasticsearchRepository<T, ID>
|
||||
extends ReactiveSortingRepository<T, ID>, ReactiveCrudRepository<T, ID> {
|
||||
|
||||
}
|
||||
extends ReactiveSortingRepository<T, ID>, ReactiveCrudRepository<T, ID> {}
|
||||
|
@ -29,6 +29,7 @@ import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@ -75,7 +76,9 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
|
||||
public Object execute(Object[] parameters) {
|
||||
|
||||
ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
|
||||
Class<?> clazz = getResultClass();
|
||||
ResultProcessor resultProcessor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor);
|
||||
Class<?> clazz = resultProcessor.getReturnedType().getDomainType();
|
||||
|
||||
Query query = createQuery(parameters);
|
||||
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
|
||||
@ -132,8 +135,10 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
|
||||
|
||||
public Query createQuery(Object[] parameters) {
|
||||
|
||||
Class<?> clazz = getResultClass();
|
||||
ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
|
||||
ResultProcessor resultProcessor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor);
|
||||
Class<?> returnedType = resultProcessor.getReturnedType().getDomainType();
|
||||
|
||||
Query query = createQuery(parameterAccessor);
|
||||
|
||||
Assert.notNull(query, "unsupported query");
|
||||
@ -151,10 +156,6 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
|
||||
return query;
|
||||
}
|
||||
|
||||
private Class<?> getResultClass() {
|
||||
return queryMethod.getResultProcessor().getReturnedType().getDomainType();
|
||||
}
|
||||
|
||||
private ParametersParameterAccessor getParameterAccessor(Object[] parameters) {
|
||||
return new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitSupport;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
@ -81,6 +82,13 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
|
||||
private Object execute(ElasticsearchParameterAccessor parameterAccessor) {
|
||||
|
||||
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor);
|
||||
var returnedType = processor.getReturnedType();
|
||||
Class<?> domainType = returnedType.getDomainType();
|
||||
Class<?> typeToRead = returnedType.getTypeToRead();
|
||||
|
||||
if (SearchHit.class.isAssignableFrom(typeToRead)) {
|
||||
typeToRead = queryMethod.unwrappedReturnType;
|
||||
}
|
||||
|
||||
Query query = createQuery(parameterAccessor);
|
||||
|
||||
@ -100,8 +108,7 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
|
||||
ReactiveElasticsearchQueryExecution execution = getExecution(parameterAccessor,
|
||||
new ResultProcessingConverter(processor));
|
||||
|
||||
var returnedType = processor.getReturnedType();
|
||||
return execution.execute(query, returnedType.getDomainType(), returnedType.getTypeToRead(), index);
|
||||
return execution.execute(query, domainType, typeToRead, index);
|
||||
}
|
||||
|
||||
private ReactiveElasticsearchQueryExecution getExecution(ElasticsearchParameterAccessor accessor,
|
||||
|
@ -43,6 +43,8 @@ import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.util.QueryExecutionConverters;
|
||||
import org.springframework.data.repository.util.ReactiveWrapperConverters;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Nullable;
|
||||
@ -62,9 +64,16 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
|
||||
// the following 2 variables exits in the base class, but are private. We need them for
|
||||
// correct handling of return types (SearchHits), so we have our own values here.
|
||||
// Alas this means that we have to copy code that initializes these variables and in the
|
||||
// base class uses them in order to use our variables
|
||||
protected final Method method;
|
||||
protected final Class<?> unwrappedReturnType;
|
||||
private Boolean unwrappedReturnTypeFromSearchHit = null;
|
||||
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
|
||||
@Nullable private ElasticsearchEntityMetadata<?> metadata;
|
||||
protected final Method method; // private in base class, but needed here and in derived classes as well
|
||||
@Nullable private final Query queryAnnotation;
|
||||
@Nullable private final Highlight highlightAnnotation;
|
||||
private final Lazy<HighlightQuery> highlightQueryLazy = Lazy.of(this::createAnnotatedHighlightQuery);
|
||||
@ -83,6 +92,7 @@ public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
this.queryAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, Query.class);
|
||||
this.highlightAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, Highlight.class);
|
||||
this.sourceFilters = AnnotatedElementUtils.findMergedAnnotation(method, SourceFilters.class);
|
||||
this.unwrappedReturnType = potentiallyUnwrapReturnTypeFor(repositoryMetadata, method);
|
||||
|
||||
verifyCountQueryTypes();
|
||||
}
|
||||
@ -188,6 +198,11 @@ public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
* @since 4.0
|
||||
*/
|
||||
public boolean isSearchHitMethod() {
|
||||
|
||||
if (unwrappedReturnTypeFromSearchHit != null && unwrappedReturnTypeFromSearchHit) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Class<?> methodReturnType = method.getReturnType();
|
||||
|
||||
if (SearchHits.class.isAssignableFrom(methodReturnType)) {
|
||||
@ -322,4 +337,32 @@ public class ElasticsearchQueryMethod extends QueryMethod {
|
||||
|
||||
return fieldNames.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// region Copied from QueryMethod base class
|
||||
/*
|
||||
* Copied from the QueryMethod class adding support for collections of SearchHit instances. No static method here.
|
||||
*/
|
||||
private Class<? extends Object> potentiallyUnwrapReturnTypeFor(RepositoryMetadata metadata, Method method) {
|
||||
TypeInformation<?> returnType = metadata.getReturnType(method);
|
||||
if (!QueryExecutionConverters.supports(returnType.getType())
|
||||
&& !ReactiveWrapperConverters.supports(returnType.getType())) {
|
||||
return returnType.getType();
|
||||
} else {
|
||||
TypeInformation<?> componentType = returnType.getComponentType();
|
||||
if (componentType == null) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Couldn't find component type for return value of method %s", method));
|
||||
} else {
|
||||
|
||||
if (SearchHit.class.isAssignableFrom(componentType.getType())) {
|
||||
unwrappedReturnTypeFromSearchHit = true;
|
||||
return componentType.getComponentType().getType();
|
||||
} else {
|
||||
return componentType.getType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package org.springframework.data.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
import org.springframework.data.elasticsearch.core.query.BulkOptions
|
||||
import org.springframework.data.elasticsearch.core.query.ByQueryResponse
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery
|
||||
import org.springframework.data.elasticsearch.core.query.Query
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery
|
||||
|
||||
/**
|
||||
* Extension functions for [DocumentOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.get(id: String): T? =
|
||||
get(id, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.get(id: String, index: IndexCoordinates): T? =
|
||||
get(id, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.multiGet(query: Query): List<MultiGetItem<T>> =
|
||||
multiGet(query, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.multiGet(query: Query, index: IndexCoordinates): List<MultiGetItem<T>> =
|
||||
multiGet(query, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.exists(id: String): Boolean = exists(id, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.bulkIndex(queries: List<IndexQuery>): List<IndexedObjectInformation> =
|
||||
bulkIndex(queries, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.bulkIndex(
|
||||
queries: List<IndexQuery>,
|
||||
bulkOptions: BulkOptions
|
||||
): List<IndexedObjectInformation> =
|
||||
bulkIndex(queries, bulkOptions, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.bulkUpdate(queries: List<UpdateQuery>) =
|
||||
bulkUpdate(queries, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.delete(id: String): String =
|
||||
delete(id, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> DocumentOperations.delete(query: Query): ByQueryResponse =
|
||||
delete(query, T::class.java)
|
@ -0,0 +1,15 @@
|
||||
package org.springframework.data.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
|
||||
/**
|
||||
* Extension functions for [DocumentOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> ElasticsearchOperations.indexOps(): IndexOperations =
|
||||
indexOps(T::class.java)
|
||||
|
||||
inline fun <reified T : Any> ElasticsearchOperations.getIndexCoordinatesFor(): IndexCoordinates =
|
||||
getIndexCoordinatesFor(T::class.java)
|
@ -0,0 +1,19 @@
|
||||
package org.springframework.data.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
import org.springframework.data.elasticsearch.core.query.Query
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Extension functions for [ReactiveDocumentOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> ReactiveDocumentOperations.multiGet(query: Query): Flux<MultiGetItem<T>> = multiGet(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveDocumentOperations.multiGet(query: Query, index: IndexCoordinates): Flux<MultiGetItem<T>> = multiGet(query, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> ReactiveDocumentOperations.get(id: String): Mono<T> = get(id, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveDocumentOperations.get(id: String, index: IndexCoordinates): Mono<T> = get(id, T::class.java, index)
|
||||
inline fun <reified T : Any> ReactiveDocumentOperations.exists(id: String): Mono<Boolean> = exists(id, T::class.java)
|
@ -0,0 +1,15 @@
|
||||
package org.springframework.data.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
|
||||
/**
|
||||
* Extension functions for [ReacctiveElasticsearchOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> ReactiveElasticsearchOperations.indexOps(): ReactiveIndexOperations =
|
||||
indexOps(T::class.java)
|
||||
|
||||
inline fun <reified T : Any> ReactiveElasticsearchOperations.getIndexCoordinatesFor(): IndexCoordinates =
|
||||
getIndexCoordinatesFor(T::class.java)
|
@ -0,0 +1,26 @@
|
||||
package org.springframework.data.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
import org.springframework.data.elasticsearch.core.query.Query
|
||||
import org.springframework.data.elasticsearch.core.suggest.response.Suggest
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
/**
|
||||
* Extension functions for [SearchOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.count(): Mono<Long> = count(T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.count(query: Query): Mono<Long> = count(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.count(query: Query, index: IndexCoordinates): Mono<Long> = count(query, T::class.java, index)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.search(query: Query): Flux<SearchHit<T>> = search(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.search(query: Query, index: IndexCoordinates): Flux<SearchHit<T>> = search(query, T::class.java, index)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.searchForPage(query: Query): Mono<SearchPage<T>> = searchForPage(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.searchForPage(query: Query, index: IndexCoordinates): Mono<SearchPage<T>> = searchForPage(query, T::class.java, index)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.searchForHits(query: Query): Mono<ReactiveSearchHits<T>> = searchForHits(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.aggregate(query: Query): Flux<out AggregationContainer<*>> = aggregate(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.aggregate(query: Query, index: IndexCoordinates): Flux<out AggregationContainer<*>> = aggregate(query, T::class.java, index)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.suggest(query: Query): Mono<Suggest> = suggest(query, T::class.java)
|
||||
inline fun <reified T : Any> ReactiveSearchOperations.suggest(query: Query, index: IndexCoordinates): Mono<Suggest> = suggest(query, T::class.java, index)
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2023 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.elasticsearch.core
|
||||
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates
|
||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery
|
||||
import org.springframework.data.elasticsearch.core.query.Query
|
||||
|
||||
/**
|
||||
* Extension functions for [SearchOperations] methods that take a Class parameter leveraging reified type parameters.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.count(query: Query): Long = count(query, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.searchOne(query: Query): SearchHit<T>? = searchOne(query, T::class.java)
|
||||
inline fun <reified T : Any> SearchOperations.searchOne(query: Query, index: IndexCoordinates): SearchHit<T>? = searchOne(query, T::class.java, index)
|
||||
inline fun <reified T : Any> SearchOperations.multiSearch(queries: List<out Query>): List<SearchHits<T>> =
|
||||
multiSearch(queries, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.multiSearch(queries: List<out Query>, index: IndexCoordinates): List<SearchHits<T>> =
|
||||
multiSearch(queries, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.search(query: Query): SearchHits<T> =
|
||||
search(query, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.search(query: Query, index: IndexCoordinates): SearchHits<T> =
|
||||
search(query, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.search(query: MoreLikeThisQuery): SearchHits<T> =
|
||||
search(query, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.search(query: MoreLikeThisQuery, index: IndexCoordinates): SearchHits<T> =
|
||||
search(query, T::class.java, index)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.searchForStream(query: Query): SearchHitsIterator<T> =
|
||||
searchForStream(query, T::class.java)
|
||||
|
||||
inline fun <reified T : Any> SearchOperations.searchForStream(query: Query, index: IndexCoordinates): SearchHitsIterator<T> =
|
||||
searchForStream(query, T::class.java, index)
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2023 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.elasticsearch.repository
|
||||
|
||||
import org.springframework.data.repository.NoRepositoryBean
|
||||
import org.springframework.data.repository.kotlin.CoroutineCrudRepository
|
||||
import org.springframework.data.repository.kotlin.CoroutineSortingRepository
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
interface CoroutineElasticsearchRepository<T, ID> : CoroutineCrudRepository<T, ID>, CoroutineSortingRepository<T, ID>
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2023 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.elasticsearch.repository.query
|
||||
|
||||
import org.springframework.context.annotation.*
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchTemplateConfiguration
|
||||
import org.springframework.data.elasticsearch.repository.CoroutineElasticsearchRepository
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider
|
||||
import org.springframework.test.context.ContextConfiguration
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
@ContextConfiguration(classes = [CoroutineRepositoryELCIntegrationTests.Config::class])
|
||||
class CoroutineRepositoryELCIntegrationTests : CoroutineRepositoryIntegrationTests() {
|
||||
|
||||
@Configuration
|
||||
@Import(ReactiveElasticsearchTemplateConfiguration::class)
|
||||
@EnableReactiveElasticsearchRepositories(
|
||||
considerNestedRepositories = true,
|
||||
includeFilters = [ComponentScan.Filter(
|
||||
type = FilterType.ASSIGNABLE_TYPE,
|
||||
classes = [CoroutineElasticsearchRepository::class]
|
||||
)]
|
||||
)
|
||||
open class Config {
|
||||
@Bean
|
||||
open fun indexNameProvider(): IndexNameProvider {
|
||||
return IndexNameProvider("coroutine-repository")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2023 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.elasticsearch.repository.query
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.last
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.elasticsearch.annotations.Document
|
||||
import org.springframework.data.elasticsearch.annotations.Field
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType
|
||||
import org.springframework.data.elasticsearch.core.SearchHit
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest
|
||||
import org.springframework.data.elasticsearch.repository.CoroutineElasticsearchRepository
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider
|
||||
|
||||
/**
|
||||
* Integrationtests for the different methods a [org.springframework.data.elasticsearch.repository.CoroutineElasticsearchRepository] can have.
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
@Suppress("SpringJavaInjectionPointsAutowiringInspection")
|
||||
@SpringIntegrationTest
|
||||
abstract class CoroutineRepositoryIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
lateinit var indexNameProvider: IndexNameProvider
|
||||
|
||||
@Autowired
|
||||
lateinit var repository: CoroutineEntityRepository
|
||||
|
||||
val entities = listOf(
|
||||
Entity("1", "test"),
|
||||
Entity("2", "test"),
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() = runTest {
|
||||
repository.saveAll(entities).last()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should instantiate repository`() = runTest {
|
||||
assertThat(repository).isNotNull()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should run with method returning a list of entities`() = runTest {
|
||||
|
||||
val result = repository.searchByText("test")
|
||||
|
||||
assertThat(result).containsExactlyInAnyOrderElementsOf(entities)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should run with method returning a flow of entities`() = runTest {
|
||||
|
||||
val result = repository.findByText("test").toList(mutableListOf())
|
||||
|
||||
assertThat(result).containsExactlyInAnyOrderElementsOf(entities)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should run with method returning a flow of SearchHit`() = runTest {
|
||||
|
||||
val result = repository.queryByText("test").toList(mutableListOf())
|
||||
|
||||
assertThat(result.map { it.content }).containsExactlyInAnyOrderElementsOf(entities)
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
data class Entity(
|
||||
@Id val id: String?,
|
||||
@Field(type = FieldType.Text) val text: String?,
|
||||
)
|
||||
|
||||
interface CoroutineEntityRepository : CoroutineElasticsearchRepository<Entity, String> {
|
||||
|
||||
suspend fun searchByText(text: String): List<Entity>
|
||||
suspend fun findByText(text: String): Flow<Entity>
|
||||
suspend fun queryByText(text: String): Flow<SearchHit<Entity>>
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.springframework.data.elasticsearch.repository.query
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.data.annotation.Id
|
||||
import org.springframework.data.elasticsearch.annotations.Field
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext
|
||||
import org.springframework.data.elasticsearch.repository.CoroutineElasticsearchRepository
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata
|
||||
import kotlin.coroutines.Continuation
|
||||
|
||||
/**
|
||||
* a@author Peter-Josef Meisch
|
||||
* @since 5.2
|
||||
*/
|
||||
class ReactiveElasticsearchQueryMethodCoroutineUnitTests {
|
||||
|
||||
val projectionFactory = SpelAwareProxyProjectionFactory()
|
||||
|
||||
interface PersonRepository : CoroutineElasticsearchRepository<Person, String> {
|
||||
|
||||
suspend fun findSuspendAllByName(): Flow<Person>
|
||||
|
||||
fun findAllByName(): Flow<Person>
|
||||
|
||||
suspend fun findSuspendByName(): List<Person>
|
||||
}
|
||||
|
||||
@Test // #2545
|
||||
internal fun `should consider methods returning Flow as collection queries`() {
|
||||
|
||||
val method = PersonRepository::class.java.getMethod("findAllByName")
|
||||
val queryMethod = ReactiveElasticsearchQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, SimpleElasticsearchMappingContext())
|
||||
|
||||
assertThat(queryMethod.isCollectionQuery).isTrue()
|
||||
}
|
||||
|
||||
@Test // #2545
|
||||
internal fun `should consider suspended methods returning Flow as collection queries`() {
|
||||
|
||||
val method = PersonRepository::class.java.getMethod("findSuspendAllByName", Continuation::class.java)
|
||||
val queryMethod = ReactiveElasticsearchQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, SimpleElasticsearchMappingContext())
|
||||
|
||||
assertThat(queryMethod.isCollectionQuery).isTrue()
|
||||
}
|
||||
|
||||
@Test // #2545
|
||||
internal fun `should consider suspended methods returning List as collection queries`() {
|
||||
|
||||
val method = PersonRepository::class.java.getMethod("findSuspendByName", Continuation::class.java)
|
||||
val queryMethod = ReactiveElasticsearchQueryMethod(method, DefaultRepositoryMetadata(PersonRepository::class.java), projectionFactory, SimpleElasticsearchMappingContext())
|
||||
|
||||
assertThat(queryMethod.isCollectionQuery).isTrue()
|
||||
}
|
||||
|
||||
data class Person(
|
||||
@Id val id: String?,
|
||||
@Field val name: String?
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user