From 25973a3519fbbdf1c2893a3ed59109f24fe33832 Mon Sep 17 00:00:00 2001 From: Farid Faoudi Date: Tue, 12 Jan 2021 10:30:14 +0100 Subject: [PATCH] Provide support for GetFieldMapping request. --- .../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.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 @@ * @author Russell Parry * @author Thomas Geese * @author Brian Clozel + * @author Farid Faoudi * @since 3.2 * @see ClientConfiguration * @see ReactiveRestClients @@ -674,6 +677,11 @@ public Mono getMapping(HttpHeaders headers, GetMappingsRequ 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 @@ * @author Peter-Josef Meisch * @author Henrique Amaral * @author Thomas Geese + * @author Farid Faoudi * @since 3.2 * @see ClientConfiguration * @see ReactiveRestClients @@ -1162,6 +1165,50 @@ default Mono getMapping(GetMappingsRequest getMappingsReque */ 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.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 @@ /** * @author Roman Puchkovskiy + * @author Farid Faoudi * @since 4.0 */ public interface RequestCreator { @@ -194,4 +196,11 @@ default Function templatesExist() { 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.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 @@ * * @author Christoph Strobl * @author Peter-Josef Meisch + * @author Farid Faoudi * @since 3.2 */ @SuppressWarnings("JavadocReference") @@ -891,6 +893,24 @@ public static Request deleteTemplate(DeleteIndexTemplateRequest deleteIndexTempl 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 @@ 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 @@ * @author Henrique Amaral * @author Russell Parry * @author Thomas Geese + * @author Farid Faoudi */ @SpringIntegrationTest @ContextConfiguration(classes = { ReactiveElasticsearchClientIntegrationTests.Config.class }) @@ -721,6 +724,61 @@ public void suggestReturnsSuggestionResults() { .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() {