From 3c6dd641d749d6f76479f7de60efa84141d0f26c Mon Sep 17 00:00:00 2001 From: Farid Faoudi Date: Wed, 13 Jan 2021 08:24:49 +0100 Subject: [PATCH] Add support for GetFieldMapping request in ReactiveElasticsearchClient. Original Pull Request #1641 Closes #1640 --- .../DefaultReactiveElasticsearchClient.java | 8 +++ .../reactive/ReactiveElasticsearchClient.java | 47 +++++++++++++++ .../client/reactive/RequestCreator.java | 9 +++ .../client/util/RequestConverters.java | 20 +++++++ ...veElasticsearchClientIntegrationTests.java | 58 +++++++++++++++++++ 5 files changed, 142 insertions(+) diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java index 0673b32a9..e1e131a97 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/DefaultReactiveElasticsearchClient.java @@ -22,6 +22,8 @@ import io.netty.handler.ssl.IdentityCipherSuiteFilter; import io.netty.handler.ssl.JdkSslContext; import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.WriteTimeoutHandler; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; +import org.elasticsearch.client.indices.GetFieldMappingsResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.netty.http.client.HttpClient; @@ -139,6 +141,7 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe * @author Russell Parry * @author Thomas Geese * @author Brian Clozel + * @author Farid Faoudi * @since 3.2 * @see ClientConfiguration * @see ReactiveRestClients @@ -674,6 +677,11 @@ public class DefaultReactiveElasticsearchClient implements ReactiveElasticsearch return sendRequest(getMappingsRequest, requestCreator.getMapping(), GetMappingsResponse.class, headers).next(); } + @Override + public Mono getFieldMapping(HttpHeaders headers, GetFieldMappingsRequest getFieldMappingsRequest) { + return sendRequest(getFieldMappingsRequest, requestCreator.getFieldMapping(), GetFieldMappingsResponse.class, headers).next(); + } + @Override public Mono getSettings(HttpHeaders headers, GetSettingsRequest getSettingsRequest) { return sendRequest(getSettingsRequest, requestCreator.getSettings(), GetSettingsResponse.class, headers).next(); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java index 4cfb13038..85054a49e 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClient.java @@ -15,6 +15,8 @@ */ package org.springframework.data.elasticsearch.client.reactive; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; +import org.elasticsearch.client.indices.GetFieldMappingsResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -77,6 +79,7 @@ import org.springframework.web.reactive.function.client.WebClient; * @author Peter-Josef Meisch * @author Henrique Amaral * @author Thomas Geese + * @author Farid Faoudi * @since 3.2 * @see ClientConfiguration * @see ReactiveRestClients @@ -1162,6 +1165,50 @@ public interface ReactiveElasticsearchClient { */ Mono getMapping(HttpHeaders headers, GetMappingsRequest getMappingsRequest); + /** + * Execute the given {@link GetFieldMappingsRequest} against the {@literal indices} API. + * + * @param consumer never {@literal null}. + * @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index + * does not exist. + * @see Indices + * Flush API on elastic.co + * @since 4.2 + */ + default Mono getFieldMapping(Consumer consumer) { + + GetFieldMappingsRequest request = new GetFieldMappingsRequest(); + consumer.accept(request); + return getFieldMapping(request); + } + + /** + * Execute the given {@link GetFieldMappingsRequest} against the {@literal indices} API. + * + * @param getFieldMappingsRequest must not be {@literal null}. + * @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index + * does not exist. + * @see Indices + * Flush API on elastic.co + * @since 4.2 + */ + default Mono getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest) { + return getFieldMapping(HttpHeaders.EMPTY, getFieldMappingsRequest); + } + + /** + * Execute the given {@link GetFieldMappingsRequest} against the {@literal indices} API. + * + * @param headers Use {@link HttpHeaders} to provide eg. authentication data. Must not be {@literal null}. + * @param getFieldMappingsRequest must not be {@literal null}. + * @return a {@link Mono} signalling operation completion or an {@link Mono#error(Throwable) error} if eg. the index + * does not exist. + * @see Indices + * Flush API on elastic.co + * @since 4.2 + */ + Mono getFieldMapping(HttpHeaders headers, GetFieldMappingsRequest getFieldMappingsRequest); + /** * Execute the given {@link IndicesAliasesRequest} against the {@literal indices} API. * diff --git a/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java b/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java index 2c3fb0ae6..9f3f79397 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/reactive/RequestCreator.java @@ -28,6 +28,7 @@ import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.Request; import org.elasticsearch.client.core.CountRequest; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutIndexTemplateRequest; @@ -37,6 +38,7 @@ import org.springframework.data.elasticsearch.client.util.RequestConverters; /** * @author Roman Puchkovskiy + * @author Farid Faoudi * @since 4.0 */ public interface RequestCreator { @@ -194,4 +196,11 @@ public interface RequestCreator { default Function deleteTemplate() { return RequestConverters::deleteTemplate; } + + /** + * @since 4.2 + */ + default Function getFieldMapping() { + return RequestConverters::getFieldMapping; + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java b/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java index 58fdf2190..905665394 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/util/RequestConverters.java @@ -71,6 +71,7 @@ import org.elasticsearch.client.Requests; import org.elasticsearch.client.RethrottleRequest; import org.elasticsearch.client.core.CountRequest; import org.elasticsearch.client.indices.AnalyzeRequest; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutIndexTemplateRequest; @@ -115,6 +116,7 @@ import org.springframework.lang.Nullable; * * @author Christoph Strobl * @author Peter-Josef Meisch + * @author Farid Faoudi * @since 3.2 */ @SuppressWarnings("JavadocReference") @@ -891,6 +893,24 @@ public class RequestConverters { return request; } + public static Request getFieldMapping(GetFieldMappingsRequest getFieldMappingsRequest) { + String[] indices = getFieldMappingsRequest.indices() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.indices(); + String[] fields = getFieldMappingsRequest.fields() == null ? Strings.EMPTY_ARRAY : getFieldMappingsRequest.fields(); + + final String endpoint = new EndpointBuilder().addCommaSeparatedPathParts(indices) + .addPathPartAsIs("_mapping").addPathPartAsIs("field") + .addCommaSeparatedPathParts(fields) + .build(); + + Request request = new Request(HttpMethod.GET.name(), endpoint); + + RequestConverters.Params parameters = new Params(request); + parameters.withIndicesOptions(getFieldMappingsRequest.indicesOptions()); + parameters.withIncludeDefaults(getFieldMappingsRequest.includeDefaults()); + parameters.withIncludeTypeName(false); + return request; + } + static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) { try { diff --git a/src/test/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClientIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClientIntegrationTests.java index 8f91dc593..a1d36efd6 100644 --- a/src/test/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClientIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/client/reactive/ReactiveElasticsearchClientIntegrationTests.java @@ -18,12 +18,14 @@ package org.springframework.data.elasticsearch.client.reactive; import static org.assertj.core.api.Assertions.*; import lombok.SneakyThrows; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.time.Duration; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; @@ -73,6 +75,7 @@ import org.springframework.test.context.ContextConfiguration; * @author Henrique Amaral * @author Russell Parry * @author Thomas Geese + * @author Farid Faoudi */ @SpringIntegrationTest @ContextConfiguration(classes = { ReactiveElasticsearchClientIntegrationTests.Config.class }) @@ -721,6 +724,61 @@ public class ReactiveElasticsearchClientIntegrationTests { .verifyComplete(); } + @Test // #1640 + void getFieldMapping() { + + operations.indexOps(IndexCoordinates.of(INDEX_I)).create().block(); + + Map properties = new HashMap<>(); + properties.put("message1", Collections.singletonMap("type", "text")); + properties.put("message2", Collections.singletonMap("type", "keyword")); + + Map jsonMap = Collections.singletonMap("properties", properties); + + final PutMappingRequest putMappingRequest = new PutMappingRequest(INDEX_I) + .source(jsonMap); + + client.indices().putMapping(putMappingRequest).block(); + + client.indices().getFieldMapping(request -> request.indices(INDEX_I).fields("message1", "message2")) + .as(StepVerifier::create) + .consumeNextWith(it -> { + assertThat(it.mappings().get(INDEX_I).keySet().size()).isEqualTo(2); + assertThat(it.mappings().get(INDEX_I).get("message1").sourceAsMap()).isEqualTo(Collections.singletonMap("message1", Collections.singletonMap("type", "text"))); + assertThat(it.mappings().get(INDEX_I).get("message2").sourceAsMap()).isEqualTo(Collections.singletonMap("message2", Collections.singletonMap("type", "keyword"))); + }) + .verifyComplete(); + } + + @Test // #1640 + void getFieldMappingNonExistingField() { + + operations.indexOps(IndexCoordinates.of(INDEX_I)).create().block(); + + Map jsonMap = Collections.singletonMap("properties", + Collections.singletonMap("message", Collections.singletonMap("type", "text"))); + + final PutMappingRequest putMappingRequest = new PutMappingRequest(INDEX_I) + .source(jsonMap); + + client.indices().putMapping(putMappingRequest).block(); + + client.indices().getFieldMapping(request -> request.indices(INDEX_I).fields("message1")) + .as(StepVerifier::create) + .consumeNextWith(it -> { + assertThat(it.mappings().get(INDEX_I).keySet().size()).isZero(); + }) + .verifyComplete(); + } + + @Test // #1640 + void getFieldMappingNonExistingIndex() { + + client.indices().getFieldMapping(request -> request.indices(INDEX_I).fields("message1")) + .as(StepVerifier::create) + .verifyError(ElasticsearchStatusException.class); + } + @Test // DATAES-796 @DisplayName("should return the whole SearchResponse") void shouldReturnTheWholeSearchResponse() {