1
0
mirror of synced 2026-05-23 04:33:17 +00:00

Compare commits

...

31 Commits

Author SHA1 Message Date
Christoph Strobl 939179ced4 Release version 4.3.6 (2021.1.6).
See #2185
2022-07-15 10:34:18 +02:00
Christoph Strobl a45281b1fd Prepare 4.3.6 (2021.1.6).
See #2185
2022-07-15 10:33:40 +02:00
diamondT 474ff84d6e Fix handling of array-of-strings parameters for @Query-annotated queries.
Original Pull Request  #2182
Closes #2135

(cherry picked from commit 259c43af19)
(cherry picked from commit aa4aecacdf)
2022-07-12 20:57:48 +02:00
Peter-Josef Meisch c58e3b3a8f Fix updatebyquery request.
Original Pull Request #2197
Closes #2191

(cherry picked from commit f901380766)
(cherry picked from commit ae66cbd619)
2022-06-25 20:11:03 +02:00
Mark Paluch 4ed7f96919 After release cleanups.
See #2141
2022-06-20 11:12:23 +02:00
Mark Paluch 776a30af75 Prepare next development iteration.
See #2141
2022-06-20 11:12:20 +02:00
Mark Paluch c92480b97d Release version 4.3.5 (2021.1.5).
See #2141
2022-06-20 10:59:11 +02:00
Mark Paluch 6e8357caa7 Prepare 4.3.5 (2021.1.5).
See #2141
2022-06-20 10:58:45 +02:00
Mark Paluch 541faff07f Upgrade to Maven Wrapper 3.8.5.
See #2179
2022-06-03 09:42:29 +02:00
Mark Paluch 9aeac006d1 Update CI properties.
See #2141
2022-06-03 09:35:44 +02:00
panzhenchao 6e52b97b76 Fix incorrect argument check asserts.
Original Pull Request #2169
Closes #2170

(cherry picked from commit c826adb152)
(cherry picked from commit 7efd4b3be7)
2022-05-27 20:42:28 +02:00
Christoph Strobl c7550e8d82 After release cleanups.
See #2119
2022-04-19 12:13:25 +02:00
Christoph Strobl c17159ce1c Prepare next development iteration.
See #2119
2022-04-19 12:13:22 +02:00
Christoph Strobl 0a1d10f8b4 Release version 4.3.4 (2021.1.4).
See #2119
2022-04-19 12:03:16 +02:00
Christoph Strobl ef0e47c6bb Prepare 4.3.4 (2021.1.4).
See #2119
2022-04-19 12:02:46 +02:00
Mark Paluch 7e2ebb299c After release cleanups.
See #2091
2022-03-21 15:06:38 +01:00
Mark Paluch 594566a44a Prepare next development iteration.
See #2091
2022-03-21 15:06:36 +01:00
Mark Paluch bf3248b536 Release version 4.3.3 (2021.1.3).
See #2091
2022-03-21 14:58:52 +01:00
Mark Paluch c59bb0b434 Prepare 4.3.3 (2021.1.3).
See #2091
2022-03-21 14:58:28 +01:00
Peter-Josef Meisch d93d1e0738 Set visibility SimpleElasticsearchPersistentEntity.ContextConfiguration to public.
Original Pull Request #2116
Closes #2114

(cherry picked from commit 709b4c615e)
2022-03-21 09:31:08 +01:00
Mark Paluch aebdc8f86b Use Java 8 to build snapshots for Artifactory.
Closes #2095
2022-03-15 14:20:01 +01:00
Peter-Josef Meisch 2be27593d6 MappingBuilder must set configured date formats for date_range fields.
Original Pull Request #2103
Closes #2102

(cherry picked from commit bf080002bc)
2022-02-22 21:13:43 +01:00
Mark Paluch aa22d8239d Update CI properties.
See #2091
2022-02-22 14:09:14 +01:00
Mark Paluch 6746bc5278 Upgrade to Maven Wrapper 3.8.4.
See #2100
2022-02-22 13:56:16 +01:00
Mark Paluch a6cb959605 Polishing.
Fix Javadoc errors.

See #2095
2022-02-22 09:56:23 +01:00
Mark Paluch e04905a1a7 Use Java 17 to build snapshots for Artifactory.
Closes #2095
2022-02-22 08:53:04 +01:00
Peter-Josef Meisch 834b10f578 Remove blocking code in SearchDocument processing.
Original Pull Request #2094
Closes #2025

(cherry picked from commit c1a1ea9724)
2022-02-20 13:34:49 +01:00
Peter-Josef Meisch 823cfa919a keep the documentation change from the cherrypick 2022-02-18 20:51:46 +01:00
Peter-Josef Meisch ab29ae4219 Documentation about compatibility headers.
Original Pull Request #2093
Closes #2088

(cherry picked from commit cf380e289d)
2022-02-18 20:36:51 +01:00
Mark Paluch 62fb89208a After release cleanups.
See #2056
2022-02-18 10:49:02 +01:00
Mark Paluch e8c3badc56 Prepare next development iteration.
See #2056
2022-02-18 10:49:00 +01:00
26 changed files with 422 additions and 275 deletions
+2 -2
View File
@@ -1,3 +1,3 @@
#Mon Oct 11 14:30:32 CEST 2021
#Fri Jun 03 09:42:29 CEST 2022
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip
Vendored
+2 -30
View File
@@ -72,7 +72,7 @@ pipeline {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=java11 ci/verify.sh'
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
}
}
@@ -96,7 +96,7 @@ pipeline {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.lts.image']).inside(p['docker.java.inside.docker']) {
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
sh 'PROFILE=java11 ci/verify.sh'
sh 'PROFILE=none ci/verify.sh'
sh "ci/clean.sh"
}
}
@@ -139,34 +139,6 @@ pipeline {
}
}
}
stage('Publish documentation') {
when {
branch 'main'
}
agent {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
}
steps {
script {
docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.basic']) {
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,distribute -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch-non-root ' +
'-Dartifactory.server=https://repo.spring.io ' +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.distribution-repository=temp-private-local " +
'-Dmaven.test.skip=true clean deploy -U -B'
}
}
}
}
}
}
post {
+8 -8
View File
@@ -1,7 +1,7 @@
# Java versions
java.main.tag=8u312-b07-jdk
java.next.tag=11.0.13_8-jdk
java.lts.tag=17.0.1_12-jdk
java.main.tag=8u332-b09-jdk
java.next.tag=11.0.15_10-jdk
java.lts.tag=17.0.3_7-jdk
# Docker container images - standard
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
@@ -9,15 +9,15 @@ docker.java.next.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/ecli
docker.java.lts.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.lts.tag}
# Supported versions of MongoDB
docker.mongodb.4.0.version=4.0.23
docker.mongodb.4.4.version=4.4.4
docker.mongodb.5.0.version=5.0.3
docker.mongodb.4.0.version=4.0.28
docker.mongodb.4.4.version=4.4.12
docker.mongodb.5.0.version=5.0.6
# Supported versions of Redis
docker.redis.6.version=6.2.4
docker.redis.6.version=6.2.6
# Supported versions of Cassandra
docker.cassandra.3.version=3.11.10
docker.cassandra.3.version=3.11.12
# Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
+3 -3
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.3.2</version>
<version>4.3.6</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.6.2</version>
<version>2.6.6</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -21,7 +21,7 @@
<elasticsearch>7.15.2</elasticsearch>
<log4j>2.17.0</log4j>
<netty>4.1.65.Final</netty>
<springdata.commons>2.6.2</springdata.commons>
<springdata.commons>2.6.6</springdata.commons>
<testcontainers>1.15.3</testcontainers>
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
<java-module-name>spring.data.elasticsearch</java-module-name>
@@ -199,6 +199,29 @@ Default is 5 sec.
IMPORTANT: Adding a Header supplier as shown in above example allows to inject headers that may change over the time, like authentication JWT tokens.
If this is used in the reactive setup, the supplier function *must not* block!
=== Elasticsearch 7 compatibility headers
When using Spring Data Elasticsearch 4 - which uses the Elasticsearch 7 client libraries - and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticserach documentation].
This should be done using a header supplier like shown above:
====
[source,java]
----
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
// ...
.withHeaders(() -> {
HttpHeaders defaultCompatibilityHeaders = new HttpHeaders();
defaultCompatibilityHeaders.add("Accept",
"application/vnd.elasticsearch+json;compatible-with=7");
defaultCompatibilityHeaders.add("Content-Type",
"application/vnd.elasticsearch+json;compatible-with=7");
return defaultCompatibilityHeaders;
});
----
====
[[elasticsearch.clients.logging]]
== Client Logging
@@ -44,7 +44,7 @@ public @interface Document {
* Name of the Elasticsearch index.
* <ul>
* <li>Lowercase only</li>
* <li>Cannot include \, /, *, ?, ", <, >, |, ` ` (space character), ,, #</li>
* <li>Cannot include \, /, *, ?, ", &gt;, &lt;, |, ` ` (space character), ,, #</li>
* <li>Cannot start with -, _, +</li>
* <li>Cannot be . or ..</li>
* <li>Cannot be longer than 255 bytes (note it is bytes, so multi-byte characters will count towards the 255 limit
@@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -109,7 +110,8 @@ public abstract class AbstractElasticsearchRestTransportTemplate extends Abstrac
List<SearchHits<T>> res = new ArrayList<>(queries.size());
int c = 0;
for (Query query : queries) {
res.add(callback.doWith(SearchDocumentResponse.from(items[c++].getResponse(), documentCallback::doWith)));
res.add(
callback.doWith(SearchDocumentResponse.from(items[c++].getResponse(), getEntityCreator(documentCallback))));
}
return res;
}
@@ -142,7 +144,7 @@ public abstract class AbstractElasticsearchRestTransportTemplate extends Abstrac
index);
SearchResponse response = items[c++].getResponse();
res.add(callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith)));
res.add(callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback))));
}
return res;
}
@@ -175,7 +177,7 @@ public abstract class AbstractElasticsearchRestTransportTemplate extends Abstrac
index);
SearchResponse response = items[c++].getResponse();
res.add(callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith)));
res.add(callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback))));
}
return res;
}
@@ -215,5 +217,9 @@ public abstract class AbstractElasticsearchRestTransportTemplate extends Abstrac
return suggest(suggestion, getIndexCoordinatesFor(clazz));
}
protected <T> SearchDocumentResponse.EntityCreator<T> getEntityCreator(ReadDocumentCallback<T> documentCallback) {
return searchDocument -> CompletableFuture.completedFuture(documentCallback.doWith(searchDocument));
}
// endregion
}
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2021 the original author or authors.
* Copyright 2013-2022 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.
@@ -319,7 +319,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchRestTranspor
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchHits<T>> callback = new ReadSearchDocumentResponseCallback<>(clazz, index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -336,7 +336,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchRestTranspor
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchScrollHits<T>> callback = new ReadSearchScrollDocumentResponseCallback<>(clazz,
index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -351,7 +351,7 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchRestTranspor
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchScrollHits<T>> callback = new ReadSearchScrollDocumentResponseCallback<>(clazz,
index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -378,8 +378,8 @@ public class ElasticsearchRestTemplate extends AbstractElasticsearchRestTranspor
Assert.isTrue(items.length == request.requests().size(), "Response should has same length with queries");
return items;
}
// endregion
// endregion
// region ClientCallback
/**
* Callback interface to be used with {@link #execute(ClientCallback)} for operating directly on
@@ -354,7 +354,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchRestTransportTem
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchHits<T>> callback = new ReadSearchDocumentResponseCallback<>(clazz, index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -372,7 +372,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchRestTransportTem
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchScrollHits<T>> callback = new ReadSearchScrollDocumentResponseCallback<>(clazz,
index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -389,7 +389,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchRestTransportTem
ReadDocumentCallback<T> documentCallback = new ReadDocumentCallback<T>(elasticsearchConverter, clazz, index);
SearchDocumentResponseCallback<SearchScrollHits<T>> callback = new ReadSearchScrollDocumentResponseCallback<>(clazz,
index);
return callback.doWith(SearchDocumentResponse.from(response, documentCallback::doWith));
return callback.doWith(SearchDocumentResponse.from(response, getEntityCreator(documentCallback)));
}
@Override
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2021 the original author or authors.
* Copyright 2018-2022 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.
@@ -23,7 +23,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.elasticsearch.Version;
@@ -771,15 +770,18 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
});
}
private Mono<SearchDocumentResponse> doFindForResponse(Query query, Class<?> clazz, IndexCoordinates index) {
private <T> Mono<SearchDocumentResponse> doFindForResponse(Query query, Class<?> clazz, IndexCoordinates index) {
return Mono.defer(() -> {
SearchRequest request = requestFactory.searchRequest(query, clazz, index);
request = prepareSearchRequest(request, false);
SearchDocumentCallback<?> documentCallback = new ReadSearchDocumentCallback<>(clazz, index);
// noinspection unchecked
SearchDocumentResponse.EntityCreator<T> entityCreator = searchDocument -> ((Mono<T>) documentCallback
.toEntity(searchDocument)).toFuture();
return doFindForResponse(request, searchDocument -> documentCallback.toEntity(searchDocument).block());
return doFindForResponse(request, entityCreator);
});
}
@@ -896,19 +898,18 @@ public class ReactiveElasticsearchTemplate implements ReactiveElasticsearchOpera
* Customization hook on the actual execution result {@link Mono}. <br />
*
* @param request the already prepared {@link SearchRequest} ready to be executed.
* @param suggestEntityCreator
* @param entityCreator
* @return a {@link Mono} emitting the result of the operation converted to s {@link SearchDocumentResponse}.
*/
protected Mono<SearchDocumentResponse> doFindForResponse(SearchRequest request,
Function<SearchDocument, ? extends Object> suggestEntityCreator) {
protected <T> Mono<SearchDocumentResponse> doFindForResponse(SearchRequest request,
SearchDocumentResponse.EntityCreator<T> entityCreator) {
if (QUERY_LOGGER.isDebugEnabled()) {
QUERY_LOGGER.debug("Executing doFindForResponse: {}", request);
}
return Mono.from(execute(client1 -> client1.searchForResponse(request))).map(searchResponse -> {
return SearchDocumentResponse.from(searchResponse, suggestEntityCreator);
});
return Mono.from(execute(client -> client.searchForResponse(request)))
.map(searchResponse -> SearchDocumentResponse.from(searchResponse, entityCreator));
}
/**
@@ -123,7 +123,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param <T>
@@ -137,7 +136,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param resultType the projection result type.
@@ -150,7 +148,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param index the target index, must not be {@literal null}
@@ -165,7 +162,6 @@ public interface ReactiveSearchOperations {
/**
* Search the index for entities matching the given {@link Query query}.
*
* @param <T>
* @param query must not be {@literal null}.
* @param entityType must not be {@literal null}.
* @param resultType the projection result type.
@@ -1472,8 +1472,7 @@ class RequestFactory {
public UpdateByQueryRequest updateByQueryRequest(UpdateQuery query, IndexCoordinates index) {
String indexName = index.getIndexName();
final UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(indexName);
final UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(index.getIndexNames());
updateByQueryRequest.setScript(getScript(query));
if (query.getAbortOnVersionConflict() != null) {
@@ -66,7 +66,6 @@ final public class ElasticsearchDateConverter {
*/
public static ElasticsearchDateConverter of(String pattern) {
Assert.notNull(pattern, "pattern must not be null");
Assert.hasText(pattern, "pattern must not be empty");
String[] subPatterns = pattern.split("\\|\\|");
@@ -86,7 +85,7 @@ final public class ElasticsearchDateConverter {
*/
public String format(TemporalAccessor accessor) {
Assert.notNull("accessor", "accessor must not be null");
Assert.notNull(accessor, "accessor must not be null");
if (accessor instanceof Instant) {
Instant instant = (Instant) accessor;
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-2022 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.
@@ -17,8 +17,11 @@ package org.springframework.data.elasticsearch.core.document;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
@@ -38,13 +41,15 @@ import org.springframework.util.Assert;
/**
* This represents the complete search response from Elasticsearch, including the returned documents. Instances must be
* created with the {@link #from(SearchResponse,Function)} method.
* created with the {@link #from(SearchResponse, EntityCreator)} method.
*
* @author Peter-Josef Meisch
* @since 4.0
*/
public class SearchDocumentResponse {
private static final Log LOGGER = LogFactory.getLog(SearchDocumentResponse.class);
private final long totalHits;
private final String totalHitsRelation;
private final float maxScore;
@@ -98,12 +103,11 @@ public class SearchDocumentResponse {
* creates a SearchDocumentResponse from the {@link SearchResponse}
*
* @param searchResponse must not be {@literal null}
* @param suggestEntityCreator function to create an entity from a {@link SearchDocument}
* @param entityCreator function to create an entity from a {@link SearchDocument}
* @param <T> entity type
* @return the SearchDocumentResponse
*/
public static <T> SearchDocumentResponse from(SearchResponse searchResponse,
Function<SearchDocument, T> suggestEntityCreator) {
public static <T> SearchDocumentResponse from(SearchResponse searchResponse, EntityCreator<T> entityCreator) {
Assert.notNull(searchResponse, "searchResponse must not be null");
@@ -112,7 +116,7 @@ public class SearchDocumentResponse {
Aggregations aggregations = searchResponse.getAggregations();
org.elasticsearch.search.suggest.Suggest suggest = searchResponse.getSuggest();
return from(searchHits, scrollId, aggregations, suggest, suggestEntityCreator);
return from(searchHits, scrollId, aggregations, suggest, entityCreator);
}
/**
@@ -122,14 +126,14 @@ public class SearchDocumentResponse {
* @param scrollId scrollId
* @param aggregations aggregations
* @param suggestES the suggestion response from Elasticsearch
* @param suggestEntityCreator function to create an entity from a {@link SearchDocument}
* @param entityCreator function to create an entity from a {@link SearchDocument}
* @param <T> entity type
* @return the {@link SearchDocumentResponse}
* @since 4.3
*/
public static <T> SearchDocumentResponse from(SearchHits searchHits, @Nullable String scrollId,
@Nullable Aggregations aggregations, @Nullable org.elasticsearch.search.suggest.Suggest suggestES,
Function<SearchDocument, T> suggestEntityCreator) {
EntityCreator<T> entityCreator) {
TotalHits responseTotalHits = searchHits.getTotalHits();
@@ -153,14 +157,14 @@ public class SearchDocumentResponse {
}
}
Suggest suggest = suggestFrom(suggestES, suggestEntityCreator);
Suggest suggest = suggestFrom(suggestES, entityCreator);
return new SearchDocumentResponse(totalHits, totalHitsRelation, maxScore, scrollId, searchDocuments, aggregations,
suggest);
}
@Nullable
private static <T> Suggest suggestFrom(@Nullable org.elasticsearch.search.suggest.Suggest suggestES,
Function<SearchDocument, T> entityCreator) {
EntityCreator<T> entityCreator) {
if (suggestES == null) {
return null;
@@ -219,7 +223,19 @@ public class SearchDocumentResponse {
List<CompletionSuggestion.Entry.Option<T>> options = new ArrayList<>();
for (org.elasticsearch.search.suggest.completion.CompletionSuggestion.Entry.Option optionES : entryES) {
SearchDocument searchDocument = optionES.getHit() != null ? DocumentAdapters.from(optionES.getHit()) : null;
T hitEntity = searchDocument != null ? entityCreator.apply(searchDocument) : null;
T hitEntity = null;
if (searchDocument != null) {
try {
hitEntity = entityCreator.apply(searchDocument).get();
} catch (Exception e) {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Error creating entity from SearchDocument");
}
}
}
options.add(new CompletionSuggestion.Entry.Option<T>(textToString(optionES.getText()),
textToString(optionES.getHighlighted()), optionES.getScore(), optionES.collateMatch(),
optionES.getContexts(), scoreDocFrom(optionES.getDoc()), searchDocument, hitEntity));
@@ -254,4 +270,14 @@ public class SearchDocumentResponse {
private static String textToString(@Nullable Text text) {
return text != null ? text.string() : "";
}
/**
* A function to convert a {@link SearchDocument} async into an entity. Asynchronous so that it can be used from the
* imperative and the reactive code.
*
* @param <T> the entity type
*/
@FunctionalInterface
public interface EntityCreator<T> extends Function<SearchDocument, CompletableFuture<T>> {}
}
@@ -20,7 +20,7 @@ import org.springframework.data.elasticsearch.core.convert.GeoConverters;
import org.springframework.data.elasticsearch.core.document.Document;
/**
* Interface definition for structures defined in <a href="https://geojson.org/>GeoJSON</a> format. copied from Spring
* Interface definition for structures defined in <a href="https://geojson.org/">GeoJSON</a> format. copied from Spring
* Data Mongodb
*
* @author Christoph Strobl
@@ -239,7 +239,7 @@ public final class MappingParameters {
if (type != FieldType.Auto) {
objectNode.put(FIELD_PARAM_TYPE, type.getMappedName());
if (type == FieldType.Date) {
if (type == FieldType.Date || type == FieldType.Date_Nanos || type == FieldType.Date_Range) {
List<String> formats = new ArrayList<>();
// built-in formats
@@ -172,7 +172,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
@Override
public boolean writeTypeHints() {
boolean writeTypeHints = contextConfiguration.writeTypeHints;
boolean writeTypeHints = contextConfiguration.getWriteTypeHints();
if (document != null) {
switch (document.writeTypeHint()) {
@@ -548,7 +548,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
/**
* Configuration settings passed in from the creating {@link SimpleElasticsearchMappingContext}.
*/
static class ContextConfiguration {
public static class ContextConfiguration {
private final FieldNamingStrategy fieldNamingStrategy;
private final boolean writeTypeHints;
@@ -561,6 +561,10 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
public FieldNamingStrategy getFieldNamingStrategy() {
return fieldNamingStrategy;
}
public boolean getWriteTypeHints() {
return writeTypeHints;
}
}
@Override
@@ -30,7 +30,7 @@ import org.springframework.lang.Nullable;
* @author Mohsin Husen
* @author Peter-Josef Meisch
* @author Farid Faoudi
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html>docs</a>
* @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html">docs</a>
*/
public class UpdateQuery {
@@ -82,8 +82,7 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor);
Query query = createQuery(
new ConvertingParameterAccessor(elasticsearchOperations.getElasticsearchConverter(), parameterAccessor));
Query query = createQuery(parameterAccessor);
if (queryMethod.hasAnnotatedHighlight()) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
@@ -1,95 +0,0 @@
/*
* Copyright 2019-2021 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 java.util.Iterator;
import java.util.Optional;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.lang.Nullable;
/**
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @since 3.2
*/
public class ConvertingParameterAccessor implements ElasticsearchParameterAccessor {
private final ElasticsearchConverter converter;
private final ElasticsearchParameterAccessor delegate;
public ConvertingParameterAccessor(ElasticsearchConverter converter, ElasticsearchParameterAccessor delegate) {
this.converter = converter;
this.delegate = delegate;
}
@Override
public Object[] getValues() {
return delegate.getValues();
}
@Override
public Pageable getPageable() {
return delegate.getPageable();
}
@Override
public Sort getSort() {
return delegate.getSort();
}
@Override
public Optional<Class<?>> getDynamicProjection() {
return delegate.getDynamicProjection();
}
@Override
public Class<?> findDynamicProjection() {
return delegate.findDynamicProjection();
}
@Override
public Object getBindableValue(int index) {
return getConvertedValue(delegate.getBindableValue(index));
}
@Override
public boolean hasBindableNullValue() {
return delegate.hasBindableNullValue();
}
@Override
public Iterator<Object> iterator() {
return delegate.iterator();
}
@Nullable
private Object getConvertedValue(Object value) {
if (value == null) {
return "null";
}
if (converter.getConversionService().canConvert(value.getClass(), String.class)) {
return converter.getConversionService().convert(value, String.class);
}
return value.toString();
}
}
+5 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 4.3.2 (2021.1.2)
Spring Data Elasticsearch 4.3.6 (2021.1.6)
Copyright (c) [2013-2021] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -29,6 +29,10 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
@@ -124,7 +124,7 @@ public class ElasticsearchRestTemplateTests extends ElasticsearchTemplateTests {
assertThat(fetchSourceContext.excludes()).containsExactlyInAnyOrder("excl");
}
@Test // #1446
@Test // #1446, #2191
void shouldUseAllOptionsFromUpdateByQuery() throws JSONException {
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) //
@@ -154,9 +154,10 @@ public class ElasticsearchRestTemplateTests extends ElasticsearchTemplateTests {
" }" + " }" + '}';
// when
UpdateByQueryRequest request = getRequestFactory().updateByQueryRequest(updateQuery, IndexCoordinates.of("index"));
UpdateByQueryRequest request = getRequestFactory().updateByQueryRequest(updateQuery, IndexCoordinates.of("index1", "index2"));
// then
assertThat(request.indices()).containsExactlyInAnyOrder("index1", "index2");
assertThat(request).isNotNull();
assertThat(request.getSearchRequest().indicesOptions()).usingRecursiveComparison()
.isEqualTo(IndicesOptions.LENIENT_EXPAND_OPEN);
@@ -42,6 +42,7 @@ import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.elasticsearch.annotations.*;
import org.springframework.data.elasticsearch.core.MappingContextBaseTests;
import org.springframework.data.elasticsearch.core.Range;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
@@ -721,6 +722,29 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
assertEquals(expected, mapping, false);
}
@Test // #2102
@DisplayName("should write date formats for date range fields")
void shouldWriteDateFormatsForDateRangeFields() throws JSONException {
String expected = "{\n" + //
" \"properties\": {\n" + //
" \"_class\": {\n" + //
" \"type\": \"keyword\",\n" + //
" \"index\": false,\n" + //
" \"doc_values\": false\n" + //
" },\n" + //
" \"field2\": {\n" + //
" \"type\": \"date_range\",\n" + //
" \"format\": \"date\"\n" + //
" }\n" + //
" }\n" + //
"}\n"; //
String mapping = getMappingBuilder().buildPropertyMapping(DateRangeEntity.class);
assertEquals(expected, mapping, false);
}
@Test // #1454
@DisplayName("should write type hints when context is configured to do so")
void shouldWriteTypeHintsWhenContextIsConfiguredToDoSo() throws JSONException {
@@ -1911,6 +1935,31 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
}
}
private static class DateRangeEntity {
@Nullable
@Id private String id;
@Nullable
@Field(type = Date_Range, format = DateFormat.date) private Range<LocalDateTime> field2;
@Nullable
public String getId() {
return id;
}
public void setId(@Nullable String id) {
this.id = id;
}
@Nullable
public Range<LocalDateTime> getField2() {
return field2;
}
public void setField2(@Nullable Range<LocalDateTime> field2) {
this.field2 = field2;
}
}
@Document(indexName = "magazine")
private static class Magazine {
@Id @Nullable private String id;
@@ -1,5 +1,5 @@
/*
* Copyright 2021 the original author or authors.
* Copyright 2021-2022 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.
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core.suggest;
import static org.assertj.core.api.Assertions.*;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.ArrayList;
@@ -39,8 +40,8 @@ import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.suggest.response.CompletionSuggestion;
import org.springframework.data.elasticsearch.core.suggest.response.Suggest;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
@@ -86,13 +87,11 @@ public class ReactiveElasticsearchTemplateSuggestIntegrationTests {
@DisplayName("should find suggestions for given prefix completion")
void shouldFindSuggestionsForGivenPrefixCompletion() {
loadCompletionObjectEntities();
NativeSearchQuery query = new NativeSearchQueryBuilder().withSuggestBuilder(new SuggestBuilder()
.addSuggestion("test-suggest", SuggestBuilders.completionSuggestion("suggest").prefix("m", Fuzziness.AUTO)))
.build();
operations.suggest(query, CompletionEntity.class) //
loadCompletionObjectEntities() //
.flatMap(unused -> {
Query query = getSuggestQuery("test-suggest", "suggest", "m");
return operations.suggest(query, CompletionEntity.class);
}) //
.as(StepVerifier::create) //
.assertNext(suggest -> {
Suggest.Suggestion<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> suggestion = suggest
@@ -105,13 +104,21 @@ public class ReactiveElasticsearchTemplateSuggestIntegrationTests {
assertThat(options).hasSize(2);
assertThat(options.get(0).getText()).isIn("Marchand", "Mohsin");
assertThat(options.get(1).getText()).isIn("Marchand", "Mohsin");
}) //
.verifyComplete();
}
protected Query getSuggestQuery(String suggestionName, String fieldName, String prefix) {
return new NativeSearchQueryBuilder() //
.withSuggestBuilder(new SuggestBuilder() //
.addSuggestion(suggestionName, //
SuggestBuilders.completionSuggestion(fieldName) //
.prefix(prefix, Fuzziness.AUTO))) //
.build(); //
}
// region helper functions
private void loadCompletionObjectEntities() {
private Mono<CompletionEntity> loadCompletionObjectEntities() {
CompletionEntity rizwan_idrees = new CompletionEntityBuilder("1").name("Rizwan Idrees")
.suggest(new String[] { "Rizwan Idrees" }).build();
@@ -124,7 +131,7 @@ public class ReactiveElasticsearchTemplateSuggestIntegrationTests {
List<CompletionEntity> entities = new ArrayList<>(
Arrays.asList(rizwan_idrees, franck_marchand, mohsin_husen, artur_konczak));
IndexCoordinates index = IndexCoordinates.of(indexNameProvider.indexName());
operations.saveAll(entities, index).blockLast();
return operations.saveAll(entities, index).last();
}
// endregion
@@ -132,11 +139,13 @@ public class ReactiveElasticsearchTemplateSuggestIntegrationTests {
@Document(indexName = "#{@indexNameProvider.indexName()}")
static class CompletionEntity {
@Nullable @Id private String id;
@Nullable
@Id private String id;
@Nullable private String name;
@Nullable @CompletionField(maxInputLength = 100) private Completion suggest;
@Nullable
@CompletionField(maxInputLength = 100) private Completion suggest;
private CompletionEntity() {}
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-2022 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.
@@ -144,10 +144,37 @@ public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStri
.isEqualTo("{ 'bool' : { 'must' : { 'term' : { 'car' : 'Toyota-Prius' } } } }");
}
@Test // #2135
@DisplayName("should handle array-of-strings parameters correctly")
void shouldHandleArrayOfStringsParametersCorrectly() throws Exception {
List<String> otherNames = Arrays.asList("Wesley", "Emmett");
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByOtherNames", otherNames);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'terms' : { 'otherNames' : [\"Wesley\",\"Emmett\"] } } } }");
}
@Test // #2135
@DisplayName("should handle array-of-Integers parameters correctly")
void shouldHandleArrayOfIntegerParametersCorrectly() throws Exception {
List<Integer> ages = Arrays.asList(42, 57);
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByAges", ages);
assertThat(query).isInstanceOf(StringQuery.class);
assertThat(((StringQuery) query).getSource())
.isEqualTo("{ 'bool' : { 'must' : { 'terms' : { 'ages' : [42,57] } } } }");
}
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
throws NoSuchMethodException {
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass).toArray(Class[]::new);
Class<?>[] argTypes = Arrays.stream(args).map(Object::getClass)
.map(clazz -> Collection.class.isAssignableFrom(clazz) ? List.class : clazz).toArray(Class[]::new);
ReactiveElasticsearchQueryMethod queryMethod = getQueryMethod(methodName, argTypes);
ReactiveElasticsearchStringQuery elasticsearchStringQuery = queryForMethod(queryMethod);
@@ -195,6 +222,12 @@ public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStri
@Query("{ 'bool' : { 'must' : { 'term' : { 'car' : '?0' } } } }")
Mono<Person> findByCar(Car car);
@Query("{ 'bool' : { 'must' : { 'terms' : { 'otherNames' : ?0 } } } }")
Flux<Person> findByOtherNames(List<String> otherNames);
@Query("{ 'bool' : { 'must' : { 'terms' : { 'ages' : ?0 } } } }")
Flux<Person> findByAges(List<Integer> ages);
}
/**
@@ -206,10 +239,13 @@ public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStri
@Document(indexName = "test-index-person-reactive-repository-string-query")
public class Person {
@Nullable @Id private String id;
@Nullable
@Id private String id;
@Nullable private String name;
@Nullable private List<String> otherNames;
@Nullable @Field(type = FieldType.Nested) private List<Car> car;
@Nullable @Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
@@ -232,6 +268,15 @@ public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStri
this.name = name;
}
@Nullable
public List<String> getOtherNames() {
return otherNames;
}
public void setOtherNames(List<String> otherNames) {
this.otherNames = otherNames;
}
@Nullable
public List<Car> getCar() {
return car;
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import static org.springframework.data.elasticsearch.core.query.Query.*;
import org.springframework.data.elasticsearch.annotations.FieldType;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
@@ -91,7 +92,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
operations.indexOps(IndexCoordinates.of(INDEX)).delete().block();
}
@Test // DATAES-519
@Test
// DATAES-519
void saveShouldSaveSingleEntity() {
repository.save(new SampleEntity()) //
@@ -105,7 +107,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
return operations.exists(id, IndexCoordinates.of(INDEX));
}
@Test // DATAES-519
@Test
// DATAES-519
void saveShouldComputeMultipleEntities() {
repository.saveAll(Arrays.asList(new SampleEntity(), new SampleEntity(), new SampleEntity()))
@@ -118,46 +121,50 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519, DATAES-767, DATAES-822
@Test
// DATAES-519, DATAES-767, DATAES-822
void findByIdShouldErrorIfIndexDoesNotExist() {
repository.findById("id-two") //
.as(StepVerifier::create) //
.expectError(RestStatusException.class);
}
@Test // DATAES-519
@Test
// DATAES-519
void findShouldRetrieveSingleEntityById() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two"), //
new SampleEntity("id-three")) //
.block();
.block();
repository.findById("id-two").as(StepVerifier::create)//
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-two")) //
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void findByIdShouldCompleteIfNothingFound() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two"), //
new SampleEntity("id-three")) //
.block();
.block();
repository.findById("does-not-exist").as(StepVerifier::create) //
.verifyComplete();
}
@Test // DATAES-720
@Test
// DATAES-720
void findAllShouldReturnAllElements() {
// make sure to be above the default page size of the Query interface
int count = DEFAULT_PAGE_SIZE * 2;
bulkIndex(IntStream.range(1, count + 1) //
.mapToObj(it -> new SampleEntity(String.valueOf(it))) //
.toArray(SampleEntity[]::new)) //
.block();
.block();
repository.findAll() //
.as(StepVerifier::create) //
@@ -165,18 +172,20 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void findAllByIdByIdShouldCompleteIfIndexDoesNotExist() {
repository.findAllById(Arrays.asList("id-two", "id-two")).as(StepVerifier::create).verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void findAllByIdShouldRetrieveMatchingDocuments() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two"), //
new SampleEntity("id-three")) //
.block();
.block();
repository.findAllById(Arrays.asList("id-one", "id-two")) //
.as(StepVerifier::create)//
@@ -185,26 +194,28 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void findAllByIdShouldCompleteWhenNothingFound() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two"), //
new SampleEntity("id-three")) //
.block();
.block();
repository.findAllById(Arrays.asList("can't", "touch", "this")) //
.as(StepVerifier::create)//
.verifyComplete();
}
@Test // DATAES-717
@Test
// DATAES-717
void shouldReturnFluxOfSearchHit() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "message"), //
new SampleEntity("id-three", "message")) //
.block();
.block();
repository.queryAllByMessage("message") //
.as(StepVerifier::create) //
@@ -213,13 +224,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-717
@Test
// DATAES-717
void shouldReturnFluxOfSearchHitForStringQuery() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "message"), //
new SampleEntity("id-three", "message")) //
.block();
.block();
repository.queryByMessageWithString("message") //
.as(StepVerifier::create) //
@@ -228,13 +240,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-372
@Test
// DATAES-372
void shouldReturnHighlightsOnAnnotatedMethod() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "message"), //
new SampleEntity("id-three", "message")) //
.block();
.block();
repository.queryAllByMessage("message") //
.as(StepVerifier::create) //
@@ -246,13 +259,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-372
@Test
// DATAES-372
void shouldReturnHighlightsOnAnnotatedStringQueryMethod() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "message"), //
new SampleEntity("id-three", "message")) //
.block();
.block();
repository.queryByMessageWithString("message") //
.as(StepVerifier::create) //
@@ -264,30 +278,33 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519, DATAES-767, DATAES-822
@Test
// DATAES-519, DATAES-767, DATAES-822
void countShouldErrorWhenIndexDoesNotExist() {
repository.count() //
.as(StepVerifier::create) //
.expectError(RestStatusException.class);
}
@Test // DATAES-519
@Test
// DATAES-519
void countShouldCountDocuments() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two")) //
.block();
.block();
repository.count().as(StepVerifier::create).expectNext(2L).verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void existsByIdShouldReturnTrueIfExists() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.existsById("id-two") //
.as(StepVerifier::create) //
@@ -295,13 +312,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void existsByIdShouldReturnFalseIfNotExists() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.existsById("wrecking ball") //
.as(StepVerifier::create) //
@@ -309,7 +327,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void countShouldCountMatchingDocuments() {
bulkIndex(new SampleEntity("id-one", "message"), //
@@ -336,13 +355,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void existsShouldReturnTrueIfExists() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.existsAllByMessage("message") //
.as(StepVerifier::create) //
@@ -350,13 +370,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void existsShouldReturnFalseIfNotExists() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.existsAllByMessage("these days") //
.as(StepVerifier::create) //
@@ -364,24 +385,27 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void deleteByIdShouldCompleteIfNothingDeleted() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two")) //
.block();
.block();
repository.deleteById("does-not-exist").as(StepVerifier::create).verifyComplete();
}
@Test // DATAES-519, DATAES-767, DATAES-822, DATAES-678
@Test
// DATAES-519, DATAES-767, DATAES-822, DATAES-678
void deleteByIdShouldCompleteWhenIndexDoesNotExist() {
repository.deleteById("does-not-exist") //
.as(StepVerifier::create) //
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void deleteByIdShouldDeleteEntry() {
SampleEntity toBeDeleted = new SampleEntity("id-two");
@@ -393,19 +417,22 @@ class SimpleReactiveElasticsearchRepositoryTests {
assertThat(documentWithIdExistsInIndex(toBeDeleted.getId()).block()).isFalse();
}
@Test // DATAES-976
@Test
// DATAES-976
void deleteAllByIdShouldDeleteEntry() {
SampleEntity toBeDeleted = new SampleEntity("id-two");
bulkIndex(new SampleEntity("id-one"), toBeDeleted) //
.block();
repository.deleteAllById(Collections.singletonList(toBeDeleted.getId())).as(StepVerifier::create).verifyComplete();
repository.deleteAllById(Collections.singletonList(toBeDeleted.getId())).as(StepVerifier::create)
.verifyComplete();
assertThat(documentWithIdExistsInIndex(toBeDeleted.getId()).block()).isFalse();
}
@Test // DATAES-519
@Test
// DATAES-519
void deleteShouldDeleteEntry() {
SampleEntity toBeDeleted = new SampleEntity("id-two");
@@ -417,7 +444,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
assertThat(documentWithIdExistsInIndex(toBeDeleted.getId()).block()).isFalse();
}
@Test // DATAES-519
@Test
// DATAES-519
void deleteAllShouldDeleteGivenEntries() {
SampleEntity toBeDeleted = new SampleEntity("id-one");
@@ -434,13 +462,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
assertThat(documentWithIdExistsInIndex(hangInThere.getId()).block()).isTrue();
}
@Test // DATAES-519
@Test
// DATAES-519
void deleteAllShouldDeleteAllEntries() {
bulkIndex(new SampleEntity("id-one"), //
new SampleEntity("id-two"), //
new SampleEntity("id-three")) //
.block();
.block();
repository.deleteAll().as(StepVerifier::create).verifyComplete();
@@ -450,13 +479,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderMethodShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.findAllByMessageLike("test") //
.as(StepVerifier::create) //
@@ -464,13 +494,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderMethodShouldBeExecutedCorrectlyWhenGivenPublisher() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.findAllByMessage(Mono.just("test")) //
.as(StepVerifier::create) //
@@ -478,13 +509,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderWithDerivedSortMethodShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "test", 3), //
new SampleEntity("id-two", "test test", 1), //
new SampleEntity("id-three", "test test", 2)) //
.block();
.block();
repository.findAllByMessageLikeOrderByRate("test") //
.as(StepVerifier::create) //
@@ -494,13 +526,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderMethodWithSortParameterShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "test", 3), //
new SampleEntity("id-two", "test test", 1), //
new SampleEntity("id-three", "test test", 2)) //
.block();
.block();
repository.findAllByMessage("test", Sort.by(Order.asc("rate"))) //
.as(StepVerifier::create) //
@@ -510,13 +543,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderMethodWithPageableParameterShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "test", 3), //
new SampleEntity("id-two", "test test", 1), //
new SampleEntity("id-three", "test test", 2)) //
.block();
.block();
repository.findAllByMessage("test", PageRequest.of(0, 2, Sort.by(Order.asc("rate")))) //
.as(StepVerifier::create) //
@@ -525,13 +559,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedFinderMethodReturningMonoShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.findFirstByMessageLike("test") //
.as(StepVerifier::create) //
@@ -539,7 +574,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void annotatedFinderMethodShouldBeExecutedCorrectly() {
int count = 30;
@@ -555,7 +591,8 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // #1917
@Test
// #1917
void annotatedFinderMethodPagedShouldBeExecutedCorrectly() {
int count = 30;
@@ -575,13 +612,14 @@ class SimpleReactiveElasticsearchRepositoryTests {
.verifyComplete();
}
@Test // DATAES-519
@Test
// DATAES-519
void derivedDeleteMethodShouldBeExecutedCorrectly() {
bulkIndex(new SampleEntity("id-one", "message"), //
new SampleEntity("id-two", "test message"), //
new SampleEntity("id-three", "test test")) //
.block();
.block();
repository.deleteAllByMessage("message") //
.as(StepVerifier::create) //
@@ -593,6 +631,56 @@ class SimpleReactiveElasticsearchRepositoryTests {
assertThat(documentWithIdExistsInIndex("id-three").block()).isTrue();
}
@Test
// #2135
void FluxOfSearchHitForArrayQuery() {
bulkIndex(new SampleEntity("id-one", "message1"), //
new SampleEntity("id-two", "message2"), //
new SampleEntity("id-three", "message3")) //
.block();
repository.findAllViaAnnotatedQueryByMessageIn(Arrays.asList("message1", "message3")) //
.as(StepVerifier::create) //
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-one")) //
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-three")) //
.verifyComplete();
}
@Test
// #2135
void FluxOfSearchHitForIntegerArrayQuery() {
bulkIndex(new SampleEntity("id-one", "test", 3), //
new SampleEntity("id-two", "test test", 1), //
new SampleEntity("id-three", "test test", 2)) //
.block();
repository.findAllViaAnnotatedQueryByRatesIn(Arrays.asList(2, 3)) //
.as(StepVerifier::create) //
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-one")) //
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-three")) //
.verifyComplete();
}
@Test
// #2135
void FluxOfSearchHitForStringAndIntegerArrayQuery() {
bulkIndex(new SampleEntity("id-one", "message1", 1), //
new SampleEntity("id-two", "message2", 2), //
new SampleEntity("id-three", "message3", 3), //
new SampleEntity("id-four", "message4", 4), //
new SampleEntity("id-five", "message5", 5)) //
.block();
repository.findAllViaAnnotatedQueryByMessageInAndRatesIn(Arrays.asList("message5", "message3"), Arrays.asList(2,
3)) //
.as(StepVerifier::create) //
.consumeNextWith(it -> assertThat(it.getId()).isEqualTo("id-three")) //
.verifyComplete();
}
Mono<Void> bulkIndex(SampleEntity... entities) {
return operations.saveAll(Arrays.asList(entities), IndexCoordinates.of(INDEX)).then();
}
@@ -609,11 +697,11 @@ class SimpleReactiveElasticsearchRepositoryTests {
Flux<SampleEntity> findAllByMessage(Publisher<String> message);
@Highlight(fields = { @HighlightField(name = "message") })
@Highlight(fields = {@HighlightField(name = "message")})
Flux<SearchHit<SampleEntity>> queryAllByMessage(String message);
@Query("{\"bool\": {\"must\": [{\"term\": {\"message\": \"?0\"}}]}}")
@Highlight(fields = { @HighlightField(name = "message") })
@Highlight(fields = {@HighlightField(name = "message")})
Flux<SearchHit<SampleEntity>> queryByMessageWithString(String message);
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"message\" : \"?0\" } } } }")
@@ -632,18 +720,39 @@ class SimpleReactiveElasticsearchRepositoryTests {
@CountQuery(value = "{\"bool\": {\"must\": [{\"term\": {\"message\": \"?0\"}}]}}")
Mono<Long> retrieveCountByText(String message);
@Query("{ \"terms\": { \"message\": ?0 } }")
Flux<SampleEntity> findAllViaAnnotatedQueryByMessageIn(List<String> messages);
@Query("{ \"terms\": { \"rate\": ?0 } }")
Flux<SampleEntity> findAllViaAnnotatedQueryByRatesIn(List<Integer> rates);
@Query("{\"bool\": {\"must\": [{ \"terms\": { \"message\": ?0 } }, { \"terms\": { \"rate\": ?1 } }] } }")
Flux<SampleEntity> findAllViaAnnotatedQueryByMessageInAndRatesIn(List<String> messages, List<Integer> rates);
}
@Document(indexName = INDEX)
static class SampleEntity {
@Nullable @Id private String id;
@Nullable @Field(type = Text, store = true, fielddata = true) private String type;
@Nullable @Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
@Nullable private boolean available;
@Nullable @Version private Long version;
@Nullable
@Id
private String id;
@Nullable
@Field(type = FieldType.Text, store = true, fielddata = true)
private String type;
@Nullable
@Field(type = FieldType.Text, store = true, fielddata = true)
private String message;
@Nullable
private int rate;
@Nullable
private boolean available;
@Nullable
@Version
private Long version;
public SampleEntity() {}
public SampleEntity() {
}
public SampleEntity(@Nullable String id) {
this.id = id;