Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a965c2fe1 | |||
| 2542634981 | |||
| 24195361d9 | |||
| 3cf8783e44 | |||
| 831b12a686 | |||
| 79813a428b | |||
| bb33ab299d | |||
| 9e85d0f27c | |||
| 535cc84df5 | |||
| 3647fc6463 | |||
| bdb7ca03c6 | |||
| 200a18b4b1 | |||
| d0f7f79968 | |||
| 027ff29436 | |||
| 69d80bd602 | |||
| f7a788ce2d | |||
| 230616a3c3 | |||
| 44ae2b2af5 | |||
| e934a2eea8 | |||
| 468b573b77 | |||
| 9a442df5b9 | |||
| 7b96041bc3 | |||
| ac73ba4774 | |||
| fa7a285606 | |||
| 939179ced4 | |||
| a45281b1fd | |||
| 474ff84d6e | |||
| c58e3b3a8f | |||
| 4ed7f96919 | |||
| 776a30af75 | |||
| c92480b97d | |||
| 6e8357caa7 | |||
| 541faff07f | |||
| 9aeac006d1 | |||
| 6e52b97b76 | |||
| c7550e8d82 | |||
| c17159ce1c | |||
| 0a1d10f8b4 | |||
| ef0e47c6bb | |||
| 7e2ebb299c | |||
| 594566a44a | |||
| bf3248b536 | |||
| c59bb0b434 | |||
| d93d1e0738 | |||
| aebdc8f86b | |||
| 2be27593d6 | |||
| aa22d8239d | |||
| 6746bc5278 | |||
| a6cb959605 | |||
| e04905a1a7 | |||
| 834b10f578 | |||
| 823cfa919a | |||
| ab29ae4219 | |||
| 62fb89208a | |||
| e8c3badc56 |
+2
-2
@@ -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
+6
-32
@@ -20,8 +20,9 @@ pipeline {
|
||||
stages {
|
||||
stage("test: baseline (main)") {
|
||||
when {
|
||||
beforeAgent(true)
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -72,7 +73,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 +97,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"
|
||||
}
|
||||
}
|
||||
@@ -108,8 +109,9 @@ pipeline {
|
||||
|
||||
stage('Release to artifactory') {
|
||||
when {
|
||||
beforeAgent(true)
|
||||
anyOf {
|
||||
branch 'main'
|
||||
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
|
||||
not { triggeredBy 'UpstreamCause' }
|
||||
}
|
||||
}
|
||||
@@ -139,34 +141,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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<version>4.3.11-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.6.2</version>
|
||||
<version>2.6.11-SNAPSHOT</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.11-SNAPSHOT</springdata.commons>
|
||||
<testcontainers>1.15.3</testcontainers>
|
||||
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
@@ -505,8 +505,8 @@
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-release</id>
|
||||
<url>https://repo.spring.io/libs-release</url>
|
||||
<id>spring-libs-snapshot</id>
|
||||
<url>https://repo.spring.io/libs-snapshot</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
|
||||
@@ -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 \, /, *, ?, ", >, <, |, ` ` (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
|
||||
|
||||
@@ -46,7 +46,7 @@ public enum Dynamic {
|
||||
/**
|
||||
* Inherit the dynamic setting from their parent object or from the mapping type.
|
||||
*/
|
||||
INHERIT("nherit");
|
||||
INHERIT("inherit");
|
||||
|
||||
private final String mappedName;
|
||||
|
||||
|
||||
+14
-4
@@ -336,8 +336,13 @@ public class RequestConverters {
|
||||
public static Request index(IndexRequest indexRequest) {
|
||||
String method = Strings.hasLength(indexRequest.id()) ? HttpMethod.PUT.name() : HttpMethod.POST.name();
|
||||
boolean isCreate = (indexRequest.opType() == DocWriteRequest.OpType.CREATE);
|
||||
String endpoint = endpoint(indexRequest.index(), indexRequest.type(), indexRequest.id(),
|
||||
isCreate ? "_create" : null);
|
||||
String endpoint;
|
||||
if (indexRequest.opType() == DocWriteRequest.OpType.CREATE) {
|
||||
endpoint = indexRequest.type().equals("_doc") ? endpoint(indexRequest.index(), "_create", indexRequest.id())
|
||||
: endpoint(indexRequest.index(), indexRequest.type(), indexRequest.id(), "_create");
|
||||
} else {
|
||||
endpoint = endpoint(indexRequest.index(), indexRequest.type(), indexRequest.id());
|
||||
}
|
||||
Request request = new Request(method, endpoint);
|
||||
|
||||
Params parameters = new Params(request);
|
||||
@@ -362,7 +367,9 @@ public class RequestConverters {
|
||||
}
|
||||
|
||||
public static Request update(UpdateRequest updateRequest) {
|
||||
String endpoint = endpoint(updateRequest.index(), updateRequest.type(), updateRequest.id(), "_update");
|
||||
String endpoint = updateRequest.type().equals("_doc")
|
||||
? endpoint(updateRequest.index(), "_update", updateRequest.id())
|
||||
: endpoint(updateRequest.index(), updateRequest.type(), updateRequest.id(), "_update");
|
||||
Request request = new Request(HttpMethod.POST.name(), endpoint);
|
||||
|
||||
Params parameters = new Params(request);
|
||||
@@ -500,8 +507,11 @@ public class RequestConverters {
|
||||
}
|
||||
|
||||
public static Request explain(ExplainRequest explainRequest) {
|
||||
String endpoint = explainRequest.type().equals("_doc")
|
||||
? endpoint(explainRequest.index(), "_explain", explainRequest.id())
|
||||
: endpoint(explainRequest.index(), explainRequest.type(), explainRequest.id(), "_explain");
|
||||
Request request = new Request(HttpMethod.GET.name(),
|
||||
endpoint(explainRequest.index(), explainRequest.type(), explainRequest.id(), "_explain"));
|
||||
endpoint(explainRequest.index(), explainRequest.type(), explainRequest.id(), endpoint));
|
||||
|
||||
Params params = new Params(request);
|
||||
params.withStoredFields(explainRequest.storedFields());
|
||||
|
||||
+9
-3
@@ -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
|
||||
}
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
+11
-10
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
-4
@@ -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) {
|
||||
|
||||
+1
-2
@@ -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;
|
||||
|
||||
+75
-29
@@ -21,6 +21,14 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
@@ -51,16 +59,7 @@ import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.PreferredConstructor;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.EntityInstantiator;
|
||||
import org.springframework.data.mapping.model.EntityInstantiators;
|
||||
import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELExpressionParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.*;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.format.datetime.DateFormatterRegistrar;
|
||||
@@ -196,7 +195,7 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to do the actual writing. The methods originally were in the MappingElasticsearchConverter class, but are
|
||||
* Class to do the actual reading. The methods originally were in the MappingElasticsearchConverter class, but are
|
||||
* refactored to allow for keeping state during the conversion of an object.
|
||||
*/
|
||||
private static class Reader extends Base {
|
||||
@@ -215,10 +214,17 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* Reads the given source into the given type.
|
||||
*
|
||||
* @param type they type to convert the given source to.
|
||||
* @param source the source to create an object of the given type from.
|
||||
* @return the object that was read
|
||||
*/
|
||||
<R> R read(Class<R> type, Document source) {
|
||||
|
||||
TypeInformation<R> typeHint = ClassTypeInformation.from((Class<R>) ClassUtils.getUserClass(type));
|
||||
R r = read(typeHint, source);
|
||||
TypeInformation<R> typeInformation = ClassTypeInformation.from((Class<R>) ClassUtils.getUserClass(type));
|
||||
R r = read(typeInformation, source);
|
||||
|
||||
if (r == null) {
|
||||
throw new ConversionException("could not convert into object of class " + type);
|
||||
@@ -229,11 +235,11 @@ public class MappingElasticsearchConverter
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private <R> R read(TypeInformation<R> type, Map<String, Object> source) {
|
||||
private <R> R read(TypeInformation<R> typeInformation, Map<String, Object> source) {
|
||||
|
||||
Assert.notNull(source, "Source must not be null!");
|
||||
|
||||
TypeInformation<? extends R> typeToUse = typeMapper.readType(source, type);
|
||||
TypeInformation<? extends R> typeToUse = typeMapper.readType(source, typeInformation);
|
||||
Class<? extends R> rawType = typeToUse.getType();
|
||||
|
||||
if (conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
||||
@@ -251,8 +257,8 @@ public class MappingElasticsearchConverter
|
||||
if (typeToUse.equals(ClassTypeInformation.OBJECT)) {
|
||||
return (R) source;
|
||||
}
|
||||
// Retrieve persistent entity info
|
||||
|
||||
// Retrieve persistent entity info
|
||||
ElasticsearchPersistentEntity<?> entity = mappingContext.getPersistentEntity(typeToUse);
|
||||
|
||||
if (entity == null) {
|
||||
@@ -370,7 +376,6 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private ParameterValueProvider<ElasticsearchPersistentProperty> getParameterProvider(
|
||||
@@ -460,12 +465,44 @@ public class MappingElasticsearchConverter
|
||||
} else if (value.getClass().isArray()) {
|
||||
return (T) readCollectionOrArray(type, Arrays.asList((Object[]) value));
|
||||
} else if (value instanceof Map) {
|
||||
|
||||
TypeInformation<?> collectionComponentType = getCollectionComponentType(type);
|
||||
if (collectionComponentType != null) {
|
||||
Object o = read(collectionComponentType, (Map<String, Object>) value);
|
||||
return getCollectionWithSingleElement(type, collectionComponentType, o);
|
||||
}
|
||||
return (T) read(type, (Map<String, Object>) value);
|
||||
} else {
|
||||
|
||||
TypeInformation<?> collectionComponentType = getCollectionComponentType(type);
|
||||
if (collectionComponentType != null
|
||||
&& collectionComponentType.isAssignableFrom(ClassTypeInformation.from(value.getClass()))) {
|
||||
Object o = getPotentiallyConvertedSimpleRead(value, collectionComponentType);
|
||||
return getCollectionWithSingleElement(type, collectionComponentType, o);
|
||||
}
|
||||
|
||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T getCollectionWithSingleElement(TypeInformation<?> collectionType,
|
||||
TypeInformation<?> componentType, Object element) {
|
||||
Collection<Object> collection = CollectionFactory.createCollection(collectionType.getType(),
|
||||
componentType.getType(), 1);
|
||||
collection.add(element);
|
||||
return (T) collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type the type to check
|
||||
* @return true if type is a collectoin, null otherwise,
|
||||
*/
|
||||
@Nullable
|
||||
TypeInformation<?> getCollectionComponentType(TypeInformation<?> type) {
|
||||
return type.isCollectionLike() ? type.getComponentType() : null;
|
||||
}
|
||||
|
||||
private Object propertyConverterRead(ElasticsearchPersistentProperty property, Object source) {
|
||||
PropertyValueConverter propertyValueConverter = Objects.requireNonNull(property.getPropertyValueConverter());
|
||||
|
||||
@@ -1131,17 +1168,18 @@ public class MappingElasticsearchConverter
|
||||
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
if (domainClass != null) {
|
||||
if (domainClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateFieldsAndSourceFilter(query, domainClass);
|
||||
updatePropertiesInFieldsAndSourceFilter(query, domainClass);
|
||||
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updateCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
}
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||
private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
||||
|
||||
@@ -1174,14 +1212,22 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> updateFieldNames(List<String> fields, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
return fields.stream().map(fieldName -> {
|
||||
/**
|
||||
* relaces the fieldName with the property name of a property of the persistentEntity with the corresponding
|
||||
* fieldname. If no such property exists, the original fieldName is kept.
|
||||
*
|
||||
* @param fieldNames list of fieldnames
|
||||
* @param persistentEntity the persistent entity to check
|
||||
* @return an updated list of field names
|
||||
*/
|
||||
private List<String> updateFieldNames(List<String> fieldNames, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
return fieldNames.stream().map(fieldName -> {
|
||||
ElasticsearchPersistentProperty persistentProperty = persistentEntity.getPersistentProperty(fieldName);
|
||||
return persistentProperty != null ? persistentProperty.getFieldName() : fieldName;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
||||
private void updatePropertiesInCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClass) {
|
||||
|
||||
Assert.notNull(criteriaQuery, "criteriaQuery must not be null");
|
||||
Assert.notNull(domainClass, "domainClass must not be null");
|
||||
@@ -1190,17 +1236,17 @@ public class MappingElasticsearchConverter
|
||||
|
||||
if (persistentEntity != null) {
|
||||
for (Criteria chainedCriteria : criteriaQuery.getCriteria().getCriteriaChain()) {
|
||||
updateCriteria(chainedCriteria, persistentEntity);
|
||||
updatePropertiesInCriteria(chainedCriteria, persistentEntity);
|
||||
}
|
||||
for (Criteria subCriteria : criteriaQuery.getCriteria().getSubCriteria()) {
|
||||
for (Criteria chainedCriteria : subCriteria.getCriteriaChain()) {
|
||||
updateCriteria(chainedCriteria, persistentEntity);
|
||||
updatePropertiesInCriteria(chainedCriteria, persistentEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCriteria(Criteria criteria, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
private void updatePropertiesInCriteria(Criteria criteria, ElasticsearchPersistentEntity<?> persistentEntity) {
|
||||
|
||||
Field field = criteria.getField();
|
||||
|
||||
|
||||
+37
-11
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+6
-2
@@ -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 {
|
||||
|
||||
|
||||
+1
-2
@@ -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());
|
||||
|
||||
-95
@@ -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();
|
||||
}
|
||||
}
|
||||
+3
@@ -128,6 +128,9 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
|
||||
|
||||
} else if (tree.isCountProjection()) {
|
||||
result = elasticsearchOperations.count(query, clazz, index);
|
||||
} else if (tree.isExistsProjection()) {
|
||||
long count = elasticsearchOperations.count(query, clazz, index);
|
||||
result = count > 0;
|
||||
} else {
|
||||
result = elasticsearchOperations.searchOne(query, clazz, index);
|
||||
}
|
||||
|
||||
+5
-2
@@ -46,7 +46,11 @@ final public class StringQueryUtil {
|
||||
|
||||
String placeholder = Pattern.quote(matcher.group()) + "(?!\\d+)";
|
||||
int index = NumberUtils.parseNumber(matcher.group(1), Integer.class);
|
||||
result = result.replaceAll(placeholder, Matcher.quoteReplacement(getParameterWithIndex(accessor, index)));
|
||||
String replacement = Matcher.quoteReplacement(getParameterWithIndex(accessor, index));
|
||||
result = result.replaceAll(placeholder, replacement);
|
||||
// need to escape backslashes that are not escapes for quotes so that they are sent as double-backslashes
|
||||
// to Elasticsearch
|
||||
result = result.replaceAll("\\\\([^\"'])", "\\\\\\\\$1");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -56,7 +60,6 @@ final public class StringQueryUtil {
|
||||
Object parameter = accessor.getBindableValue(index);
|
||||
String parameterValue = "null";
|
||||
|
||||
// noinspection ConstantConditions
|
||||
if (parameter != null) {
|
||||
|
||||
parameterValue = convert(parameter);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 4.3.2 (2021.1.2)
|
||||
Spring Data Elasticsearch 4.3.10 (2021.1.10)
|
||||
Copyright (c) [2013-2021] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -25,6 +25,14 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+3
-3
@@ -375,7 +375,7 @@ public class ReactiveElasticsearchClientUnitTests {
|
||||
});
|
||||
|
||||
URI uri = hostProvider.when(HOST).captureUri();
|
||||
assertThat(uri.getRawPath()).isEqualTo("/twitter/_doc/10/_create");
|
||||
assertThat(uri.getRawPath()).isEqualTo("/twitter/_create/10");
|
||||
}
|
||||
|
||||
@Test // DATAES-488
|
||||
@@ -439,7 +439,7 @@ public class ReactiveElasticsearchClientUnitTests {
|
||||
hostProvider.when(HOST) //
|
||||
.receiveUpdateOk();
|
||||
|
||||
client.update(new UpdateRequest("twitter", "doc", "1").doc(Collections.singletonMap("user", "cstrobl"))).then() //
|
||||
client.update(new UpdateRequest("twitter", "1").doc(Collections.singletonMap("user", "cstrobl"))).then() //
|
||||
.as(StepVerifier::create) //
|
||||
.verifyComplete();
|
||||
|
||||
@@ -449,7 +449,7 @@ public class ReactiveElasticsearchClientUnitTests {
|
||||
});
|
||||
|
||||
URI uri = hostProvider.when(HOST).captureUri();
|
||||
assertThat(uri.getRawPath()).isEqualTo("/twitter/doc/1/_update");
|
||||
assertThat(uri.getRawPath()).isEqualTo("/twitter/_update/1");
|
||||
}
|
||||
|
||||
@Test // DATAES-488
|
||||
|
||||
+3
-2
@@ -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);
|
||||
|
||||
+547
-63
@@ -33,6 +33,8 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -623,7 +625,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(target.address).isEqualTo(bigBunsCafe);
|
||||
}
|
||||
|
||||
@Test // DATAES-716
|
||||
@Test
|
||||
// DATAES-716
|
||||
void shouldWriteLocalDate() throws JSONException {
|
||||
Person person = new Person();
|
||||
person.setId("4711");
|
||||
@@ -665,7 +668,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, json, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-716
|
||||
@Test
|
||||
// DATAES-716
|
||||
void shouldReadLocalDate() {
|
||||
Document document = Document.create();
|
||||
document.put("id", "4711");
|
||||
@@ -695,7 +699,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(entity.getDates()).hasSize(2).containsExactly(LocalDate.of(2020, 9, 15), LocalDate.of(2019, 5, 1));
|
||||
}
|
||||
|
||||
@Test // DATAES-763
|
||||
@Test
|
||||
// DATAES-763
|
||||
void writeEntityWithMapDataType() {
|
||||
|
||||
Notification notification = new Notification();
|
||||
@@ -712,7 +717,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(document).isEqualTo(notificationAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-763
|
||||
@Test
|
||||
// DATAES-763
|
||||
void readEntityWithMapDataType() {
|
||||
|
||||
Document document = Document.create();
|
||||
@@ -729,7 +735,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(notification.params.get("content")).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAES-795
|
||||
@Test
|
||||
// DATAES-795
|
||||
void readGenericMapWithSimpleTypes() {
|
||||
Map<String, Object> mapWithSimpleValues = new HashMap<>();
|
||||
mapWithSimpleValues.put("int", 1);
|
||||
@@ -743,7 +750,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(wrapper.getSchemaLessObject()).isEqualTo(mapWithSimpleValues);
|
||||
}
|
||||
|
||||
@Test // DATAES-797
|
||||
@Test
|
||||
// DATAES-797
|
||||
void readGenericListWithMaps() {
|
||||
Map<String, Object> simpleMap = new HashMap<>();
|
||||
simpleMap.put("int", 1);
|
||||
@@ -761,7 +769,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(wrapper.getSchemaLessObject()).isEqualTo(mapWithSimpleList);
|
||||
}
|
||||
|
||||
@Test // DATAES-799
|
||||
@Test
|
||||
// DATAES-799
|
||||
void shouldNotWriteSeqNoPrimaryTermProperty() {
|
||||
EntityWithSeqNoPrimaryTerm entity = new EntityWithSeqNoPrimaryTerm();
|
||||
entity.seqNoPrimaryTerm = new SeqNoPrimaryTerm(1L, 2L);
|
||||
@@ -772,7 +781,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(document).doesNotContainKey("seqNoPrimaryTerm");
|
||||
}
|
||||
|
||||
@Test // DATAES-799
|
||||
@Test
|
||||
// DATAES-799
|
||||
void shouldNotReadSeqNoPrimaryTermProperty() {
|
||||
Document document = Document.create().append("seqNoPrimaryTerm", emptyMap());
|
||||
|
||||
@@ -781,7 +791,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(entity.seqNoPrimaryTerm).isNull();
|
||||
}
|
||||
|
||||
@Test // DATAES-845
|
||||
@Test
|
||||
// DATAES-845
|
||||
void shouldWriteCollectionsWithNullValues() throws JSONException {
|
||||
EntityWithListProperty entity = new EntityWithListProperty();
|
||||
entity.setId("42");
|
||||
@@ -798,7 +809,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, json, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-857
|
||||
@Test
|
||||
// DATAES-857
|
||||
void shouldWriteEntityWithListOfGeoPoints() throws JSONException {
|
||||
|
||||
GeoPointListEntity entity = new GeoPointListEntity();
|
||||
@@ -827,7 +839,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, json, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-857
|
||||
@Test
|
||||
// DATAES-857
|
||||
void shouldReadEntityWithListOfGeoPoints() {
|
||||
|
||||
String json = "{\n" + //
|
||||
@@ -852,7 +865,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(entity.locations).containsExactly(new GeoPoint(12.34, 23.45), new GeoPoint(34.56, 45.67));
|
||||
}
|
||||
|
||||
@Test // DATAES-865
|
||||
@Test
|
||||
// DATAES-865
|
||||
void shouldWriteEntityWithMapAsObject() throws JSONException {
|
||||
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
@@ -1509,6 +1523,305 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
mappingElasticsearchConverter.updateQuery(query, EntityWithCustomValueConverters.class);
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single String into a List property")
|
||||
void shouldReadASingleStringIntoAListProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringList\": \"foo\"\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getStringList()).containsExactly("foo");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a String array into a List property")
|
||||
void shouldReadAStringArrayIntoAListProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringList\": [\"foo\", \"bar\"]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getStringList()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single String into a Set property")
|
||||
void shouldReadASingleStringIntoASetProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringSet\": \"foo\"\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getStringSet()).containsExactly("foo");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a String array into a Set property")
|
||||
void shouldReadAStringArrayIntoASetProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringSet\": [\n" + //
|
||||
" \"foo\",\n" + //
|
||||
" \"bar\"\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getStringSet()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single object into a List property")
|
||||
void shouldReadASingleObjectIntoAListProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenList\": {\n" + //
|
||||
" \"name\": \"child\"\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getChildrenList()).hasSize(1);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read an object array into a List property")
|
||||
void shouldReadAnObjectArrayIntoAListProperty() {
|
||||
|
||||
String json = " {\n" + //
|
||||
" \"childrenList\": [\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child1\"\n" + //
|
||||
" },\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child2\"\n" + //
|
||||
" }\n" + //
|
||||
" ]\n" + //
|
||||
" }\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getChildrenList()).hasSize(2);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child1");
|
||||
assertThat(entity.getChildrenList().get(1).getName()).isEqualTo("child2");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single object into a Set property")
|
||||
void shouldReadASingleObjectIntoASetProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenSet\": {\n" + //
|
||||
" \"name\": \"child\"\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getChildrenSet()).hasSize(1);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenSet().iterator().next().getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read an object array into a Set property")
|
||||
void shouldReadAnObjectArrayIntoASetProperty() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenSet\": [\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child1\"\n" + //
|
||||
" },\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child2\"\n" + //
|
||||
" }\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
EntityWithCollections entity = mappingElasticsearchConverter.read(EntityWithCollections.class, source);
|
||||
|
||||
assertThat(entity.getChildrenSet()).hasSize(2);
|
||||
// noinspection ConstantConditions
|
||||
List<String> names = entity.getChildrenSet().stream().map(EntityWithCollections.Child::getName)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(names).containsExactlyInAnyOrder("child1", "child2");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single String into a List property immutable")
|
||||
void shouldReadASingleStringIntoAListPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringList\": \"foo\"\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getStringList()).containsExactly("foo");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a String array into a List property immutable")
|
||||
void shouldReadAStringArrayIntoAListPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringList\": [\n" + //
|
||||
" \"foo\",\n" + //
|
||||
" \"bar\"\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getStringList()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single String into a Set property immutable")
|
||||
void shouldReadASingleStringIntoASetPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringSet\": \"foo\"\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getStringSet()).containsExactly("foo");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a String array into a Set property immutable")
|
||||
void shouldReadAStringArrayIntoASetPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"stringSet\": [\n" + //
|
||||
" \"foo\",\n" + //
|
||||
" \"bar\"\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getStringSet()).containsExactly("foo", "bar");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single object into a List property immutable")
|
||||
void shouldReadASingleObjectIntoAListPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenList\": {\n" + //
|
||||
" \"name\": \"child\"\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getChildrenList()).hasSize(1);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read an object array into a List property immutable")
|
||||
void shouldReadAnObjectArrayIntoAListPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenList\": [\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child1\"\n" + //
|
||||
" },\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child2\"\n" + //
|
||||
" }\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getChildrenList()).hasSize(2);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenList().get(0).getName()).isEqualTo("child1");
|
||||
assertThat(entity.getChildrenList().get(1).getName()).isEqualTo("child2");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read a single object into a Set property immutable")
|
||||
void shouldReadASingleObjectIntoASetPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenSet\": {\n" + //
|
||||
" \"name\": \"child\"\n" + //
|
||||
" }\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getChildrenSet()).hasSize(1);
|
||||
// noinspection ConstantConditions
|
||||
assertThat(entity.getChildrenSet().iterator().next().getName()).isEqualTo("child");
|
||||
}
|
||||
|
||||
@Test // #2280
|
||||
@DisplayName("should read an object array into a Set property immutable")
|
||||
void shouldReadAnObjectArrayIntoASetPropertyImmutable() {
|
||||
|
||||
String json = "{\n" + //
|
||||
" \"childrenSet\": [\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child1\"\n" + //
|
||||
" },\n" + //
|
||||
" {\n" + //
|
||||
" \"name\": \"child2\"\n" + //
|
||||
" }\n" + //
|
||||
" ]\n" + //
|
||||
"}\n"; //
|
||||
Document source = Document.parse(json);
|
||||
|
||||
ImmutableEntityWithCollections entity = mappingElasticsearchConverter.read(ImmutableEntityWithCollections.class,
|
||||
source);
|
||||
|
||||
assertThat(entity.getChildrenSet()).hasSize(2);
|
||||
// noinspection ConstantConditions
|
||||
List<String> names = entity.getChildrenSet().stream().map(ImmutableEntityWithCollections.Child::getName)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(names).containsExactlyInAnyOrder("child1", "child2");
|
||||
}
|
||||
|
||||
private Map<String, Object> writeToMap(Object source) {
|
||||
|
||||
Document sink = Document.create();
|
||||
@@ -1561,12 +1874,15 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
static class Person {
|
||||
@Nullable @Id String id;
|
||||
@Nullable
|
||||
@Id String id;
|
||||
@Nullable String name;
|
||||
@Nullable @Field(name = "first-name") String firstName;
|
||||
@Nullable @Field(name = "last-name") String lastName;
|
||||
@Nullable @Field(name = "birth-date", type = FieldType.Date, format = {},
|
||||
pattern = "dd.MM.uuuu") LocalDate birthDate;
|
||||
@Nullable
|
||||
@Field(name = "first-name") String firstName;
|
||||
@Nullable
|
||||
@Field(name = "last-name") String lastName;
|
||||
@Nullable
|
||||
@Field(name = "birth-date", type = FieldType.Date, format = {}, pattern = "dd.MM.uuuu") LocalDate birthDate;
|
||||
@Nullable Gender gender;
|
||||
@Nullable Address address;
|
||||
@Nullable List<Person> coWorkers;
|
||||
@@ -1675,34 +1991,46 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Person person = (Person) o;
|
||||
|
||||
if (id != null ? !id.equals(person.id) : person.id != null)
|
||||
if (id != null ? !id.equals(person.id) : person.id != null) {
|
||||
return false;
|
||||
if (name != null ? !name.equals(person.name) : person.name != null)
|
||||
}
|
||||
if (name != null ? !name.equals(person.name) : person.name != null) {
|
||||
return false;
|
||||
if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null)
|
||||
}
|
||||
if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) {
|
||||
return false;
|
||||
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null)
|
||||
}
|
||||
if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) {
|
||||
return false;
|
||||
if (birthDate != null ? !birthDate.equals(person.birthDate) : person.birthDate != null)
|
||||
}
|
||||
if (birthDate != null ? !birthDate.equals(person.birthDate) : person.birthDate != null) {
|
||||
return false;
|
||||
if (gender != person.gender)
|
||||
}
|
||||
if (gender != person.gender) {
|
||||
return false;
|
||||
if (address != null ? !address.equals(person.address) : person.address != null)
|
||||
}
|
||||
if (address != null ? !address.equals(person.address) : person.address != null) {
|
||||
return false;
|
||||
if (coWorkers != null ? !coWorkers.equals(person.coWorkers) : person.coWorkers != null)
|
||||
}
|
||||
if (coWorkers != null ? !coWorkers.equals(person.coWorkers) : person.coWorkers != null) {
|
||||
return false;
|
||||
if (inventoryList != null ? !inventoryList.equals(person.inventoryList) : person.inventoryList != null)
|
||||
}
|
||||
if (inventoryList != null ? !inventoryList.equals(person.inventoryList) : person.inventoryList != null) {
|
||||
return false;
|
||||
}
|
||||
if (shippingAddresses != null ? !shippingAddresses.equals(person.shippingAddresses)
|
||||
: person.shippingAddresses != null)
|
||||
: person.shippingAddresses != null) {
|
||||
return false;
|
||||
}
|
||||
return inventoryMap != null ? inventoryMap.equals(person.inventoryMap) : person.inventoryMap == null;
|
||||
}
|
||||
|
||||
@@ -1724,8 +2052,10 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
static class LocalDatesEntity {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable @Field(name = "dates", type = FieldType.Date, format = DateFormat.custom,
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
@Nullable
|
||||
@Field(name = "dates", type = FieldType.Date, format = DateFormat.custom,
|
||||
pattern = "dd.MM.uuuu") private List<LocalDate> dates;
|
||||
|
||||
@Nullable
|
||||
@@ -1787,15 +2117,18 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Gun gun = (Gun) o;
|
||||
|
||||
if (shotsPerMagazine != gun.shotsPerMagazine)
|
||||
if (shotsPerMagazine != gun.shotsPerMagazine) {
|
||||
return false;
|
||||
}
|
||||
return label.equals(gun.label);
|
||||
}
|
||||
|
||||
@@ -1821,10 +2154,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (!(o instanceof Grenade))
|
||||
}
|
||||
if (!(o instanceof Grenade)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Grenade grenade = (Grenade) o;
|
||||
|
||||
@@ -1857,17 +2192,21 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (!(o instanceof Rifle))
|
||||
}
|
||||
if (!(o instanceof Rifle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Rifle rifle = (Rifle) o;
|
||||
|
||||
if (Double.compare(rifle.weight, weight) != 0)
|
||||
if (Double.compare(rifle.weight, weight) != 0) {
|
||||
return false;
|
||||
if (maxShotsPerMagazine != rifle.maxShotsPerMagazine)
|
||||
}
|
||||
if (maxShotsPerMagazine != rifle.maxShotsPerMagazine) {
|
||||
return false;
|
||||
}
|
||||
return label.equals(rifle.label);
|
||||
}
|
||||
|
||||
@@ -1898,10 +2237,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (!(o instanceof ShotGun))
|
||||
}
|
||||
if (!(o instanceof ShotGun)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShotGun shotGun = (ShotGun) o;
|
||||
|
||||
@@ -1948,17 +2289,21 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (!(o instanceof Address))
|
||||
}
|
||||
if (!(o instanceof Address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Address address = (Address) o;
|
||||
|
||||
if (location != null ? !location.equals(address.location) : address.location != null)
|
||||
if (location != null ? !location.equals(address.location) : address.location != null) {
|
||||
return false;
|
||||
if (street != null ? !street.equals(address.street) : address.street != null)
|
||||
}
|
||||
if (street != null ? !street.equals(address.street) : address.street != null) {
|
||||
return false;
|
||||
}
|
||||
return city != null ? city.equals(address.city) : address.city == null;
|
||||
}
|
||||
|
||||
@@ -1985,10 +2330,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (!(o instanceof Place))
|
||||
}
|
||||
if (!(o instanceof Place)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Place place = (Place) o;
|
||||
|
||||
@@ -2124,16 +2471,20 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
|
||||
@org.springframework.data.elasticsearch.annotations.Document(indexName = "test-index-geo-core-entity-mapper")
|
||||
static class GeoEntity {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
// geo shape - Spring Data
|
||||
@Nullable private Box box;
|
||||
@Nullable private Circle circle;
|
||||
@Nullable private Polygon polygon;
|
||||
// geo point - Custom implementation + Spring Data
|
||||
@Nullable @GeoPointField private Point pointA;
|
||||
@Nullable
|
||||
@GeoPointField private Point pointA;
|
||||
@Nullable private GeoPoint pointB;
|
||||
@Nullable @GeoPointField private String pointC;
|
||||
@Nullable @GeoPointField private double[] pointD;
|
||||
@Nullable
|
||||
@GeoPointField private String pointC;
|
||||
@Nullable
|
||||
@GeoPointField private double[] pointD;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
@@ -2237,7 +2588,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
static class EntityWithListProperty {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
@Nullable private List<String> values;
|
||||
|
||||
@Nullable
|
||||
@@ -2283,7 +2635,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
static class EntityWithObject {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
@Nullable private Object content;
|
||||
|
||||
@Nullable
|
||||
@@ -2306,9 +2659,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
static class EntityWithNullField {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable @Field(type = FieldType.Text) private String notSaved;
|
||||
@Nullable @Field(type = FieldType.Text, storeNullValue = true) private String saved;
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
@Nullable
|
||||
@Field(type = FieldType.Text) private String notSaved;
|
||||
@Nullable
|
||||
@Field(type = FieldType.Text, storeNullValue = true) private String saved;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
@@ -2341,9 +2697,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
private static class ElectricCar extends Car {}
|
||||
|
||||
private static class PersonWithCars {
|
||||
@Id @Nullable String id;
|
||||
@Field(type = FieldType.Text) @Nullable private String name;
|
||||
@Field(type = FieldType.Nested) @Nullable private List<? extends Car> cars;
|
||||
@Id
|
||||
@Nullable String id;
|
||||
@Field(type = FieldType.Text)
|
||||
@Nullable private String name;
|
||||
@Field(type = FieldType.Nested)
|
||||
@Nullable private List<? extends Car> cars;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
@@ -2374,9 +2733,12 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
}
|
||||
|
||||
private static class EntityWithCustomValueConverters {
|
||||
@Nullable @Id private String id;
|
||||
@Nullable @ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
|
||||
@Nullable @ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
|
||||
@Nullable
|
||||
@Id private String id;
|
||||
@Nullable
|
||||
@ValueConverter(ClassBasedValueConverter.class) private String fieldWithClassBasedConverter;
|
||||
@Nullable
|
||||
@ValueConverter(EnumBasedValueConverter.class) private String fieldWithEnumBasedConverter;
|
||||
@Nullable private String dontConvert;
|
||||
|
||||
@Nullable
|
||||
@@ -2442,6 +2804,128 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
return reverse(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EntityWithCollections {
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private List<String> stringList;
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private Set<String> stringSet;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
@Nullable private List<Child> childrenList;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
@Nullable private Set<Child> childrenSet;
|
||||
|
||||
@Nullable
|
||||
public List<String> getStringList() {
|
||||
return stringList;
|
||||
}
|
||||
|
||||
public void setStringList(@Nullable List<String> stringList) {
|
||||
this.stringList = stringList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<String> getStringSet() {
|
||||
return stringSet;
|
||||
}
|
||||
|
||||
public void setStringSet(@Nullable Set<String> stringSet) {
|
||||
this.stringSet = stringSet;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Child> getChildrenList() {
|
||||
return childrenList;
|
||||
}
|
||||
|
||||
public void setChildrenList(@Nullable List<Child> childrenList) {
|
||||
this.childrenList = childrenList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<Child> getChildrenSet() {
|
||||
return childrenSet;
|
||||
}
|
||||
|
||||
public void setChildrenSet(@Nullable Set<Child> childrenSet) {
|
||||
this.childrenSet = childrenSet;
|
||||
}
|
||||
|
||||
public static class Child {
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private String name;
|
||||
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ImmutableEntityWithCollections {
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private List<String> stringList;
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private Set<String> stringSet;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
@Nullable private List<Child> childrenList;
|
||||
|
||||
@Field(type = FieldType.Object)
|
||||
@Nullable private Set<Child> childrenSet;
|
||||
|
||||
public ImmutableEntityWithCollections(@Nullable List<String> stringList, @Nullable Set<String> stringSet,
|
||||
@Nullable List<Child> childrenList, @Nullable Set<Child> childrenSet) {
|
||||
this.stringList = stringList;
|
||||
this.stringSet = stringSet;
|
||||
this.childrenList = childrenList;
|
||||
this.childrenSet = childrenSet;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<String> getStringList() {
|
||||
return stringList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<String> getStringSet() {
|
||||
return stringSet;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<Child> getChildrenList() {
|
||||
return childrenList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<Child> getChildrenSet() {
|
||||
return childrenSet;
|
||||
}
|
||||
|
||||
public static class Child {
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@Nullable private String name;
|
||||
|
||||
public Child(@Nullable String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
private static String reverse(Object o) {
|
||||
|
||||
+49
@@ -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;
|
||||
|
||||
+23
-14
@@ -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() {}
|
||||
|
||||
|
||||
+12
@@ -129,6 +129,18 @@ public class ElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryU
|
||||
"{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"hello \\\"Stranger\\\"\",\"Another string\"] } } } }");
|
||||
}
|
||||
|
||||
@Test // #2326
|
||||
@DisplayName("should escape backslashes in collection query parameters")
|
||||
void shouldEscapeBackslashesInCollectionQueryParameters() throws NoSuchMethodException {
|
||||
|
||||
final List<String> parameters = Arrays.asList("param\\1", "param\\2");
|
||||
List<String> params = new ArrayList<>(parameters);
|
||||
org.springframework.data.elasticsearch.core.query.Query query = createQuery("findByNameIn", params);
|
||||
|
||||
assertThat(query).isInstanceOf(StringQuery.class);
|
||||
assertThat(((StringQuery) query).getSource()).isEqualTo(
|
||||
"{ 'bool' : { 'must' : { 'terms' : { 'name' : [\"param\\\\1\",\"param\\\\2\"] } } } }");
|
||||
}
|
||||
private org.springframework.data.elasticsearch.core.query.Query createQuery(String methodName, Object... args)
|
||||
throws NoSuchMethodException {
|
||||
|
||||
|
||||
+48
-3
@@ -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;
|
||||
|
||||
+13
@@ -321,6 +321,17 @@ class QueryKeywordsTests {
|
||||
assertThat(searchHits.getTotalHits()).isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test // #2162
|
||||
@DisplayName("should run exists query")
|
||||
void shouldRunExistsQuery() {
|
||||
|
||||
Boolean existsCaneSugar = repository.existsByText("Cane sugar");
|
||||
Boolean existsSand = repository.existsByText("Sand");
|
||||
|
||||
assertThat(existsCaneSugar).isTrue();
|
||||
assertThat(existsSand).isFalse();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Document(indexName = "test-index-product-query-keywords")
|
||||
static class Product {
|
||||
@@ -459,6 +470,8 @@ class QueryKeywordsTests {
|
||||
SearchHits<Product> findByNameEmpty();
|
||||
|
||||
SearchHits<Product> findByNameNotEmpty();
|
||||
|
||||
Boolean existsByText(String text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
@@ -19,8 +19,11 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.lang.Boolean;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Order;
|
||||
@@ -139,6 +142,21 @@ public class ReactiveQueryKeywordsIntegrationTests {
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test // #2162
|
||||
@DisplayName("should run exists query")
|
||||
void shouldRunExistsQuery() {
|
||||
|
||||
loadEntities();
|
||||
repository.existsByMessage("message") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete();
|
||||
repository.existsByMessage("without") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(false) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@SuppressWarnings("SpringDataMethodInconsistencyInspection")
|
||||
interface SampleRepository extends ReactiveElasticsearchRepository<SampleEntity, String> {
|
||||
Flux<SearchHit<SampleEntity>> findByMessageExists();
|
||||
@@ -150,6 +168,8 @@ public class ReactiveQueryKeywordsIntegrationTests {
|
||||
Flux<SearchHit<SampleEntity>> findByMessageIsNotEmpty();
|
||||
|
||||
Flux<SearchHit<SampleEntity>> findByMessageIsEmpty();
|
||||
|
||||
Mono<Boolean> existsByMessage(String message);
|
||||
}
|
||||
|
||||
private void loadEntities() {
|
||||
|
||||
+178
-69
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user