Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 59f3a6b120 | |||
| e534e952a1 | |||
| 868a9d049a | |||
| 28727c6b36 | |||
| 89528e0e59 | |||
| 42e49e8ff7 | |||
| b52fc2f0d7 | |||
| 1923721ebf | |||
| 8834cbfe03 | |||
| 2dabb2f89f | |||
| 40a91d01a8 | |||
| aab18b55ab | |||
| 6351b9f026 | |||
| 7d5b9d5b7c | |||
| 5cf7b2baae | |||
| b005c77cad | |||
| d90d0ed71c | |||
| 5b3cf9af4c | |||
| 85a7ed7dc8 | |||
| a64c24e64b |
+2
-2
@@ -1,3 +1,3 @@
|
||||
#Fri Jun 03 09:32:51 CEST 2022
|
||||
#Mon Feb 20 11:59:41 CET 2023
|
||||
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.5/apache-maven-3.8.5-bin.zip
|
||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# Java versions
|
||||
java.main.tag=17.0.5_8-jdk-focal
|
||||
java.main.tag=17.0.6_10-jdk-focal
|
||||
|
||||
# Docker container images - standard
|
||||
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
|
||||
|
||||
# Supported versions of MongoDB
|
||||
docker.mongodb.4.4.version=4.4.17
|
||||
docker.mongodb.5.0.version=5.0.13
|
||||
docker.mongodb.6.0.version=6.0.2
|
||||
docker.mongodb.4.4.version=4.4.18
|
||||
docker.mongodb.5.0.version=5.0.14
|
||||
docker.mongodb.6.0.version=6.0.4
|
||||
|
||||
# Supported versions of Redis
|
||||
docker.redis.6.version=6.2.6
|
||||
docker.redis.6.version=6.2.10
|
||||
|
||||
# Supported versions of Cassandra
|
||||
docker.cassandra.3.version=3.11.14
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>5.0.1</version>
|
||||
<version>5.0.4</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.0.4</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -18,10 +18,10 @@
|
||||
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
|
||||
|
||||
<properties>
|
||||
<springdata.commons>3.0.1</springdata.commons>
|
||||
<springdata.commons>3.0.4</springdata.commons>
|
||||
|
||||
<!-- version of the RestHighLevelClient -->
|
||||
<elasticsearch-rhlc>7.17.8</elasticsearch-rhlc>
|
||||
<elasticsearch-rhlc>7.17.9</elasticsearch-rhlc>
|
||||
<!-- version of the new ElasticsearchClient -->
|
||||
<elasticsearch-java>8.5.3</elasticsearch-java>
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ The old deprecated `RestHighLevelClient` can still be used, but you will need to
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-high-level-client</artifactId>
|
||||
<version>7.17.5</version>
|
||||
<version>7.17.9</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
@@ -165,4 +165,4 @@ The old deprecated `RestHighLevelClient` can still be used, but you will need to
|
||||
----
|
||||
====
|
||||
|
||||
Make sure to specify the version 7.17.6 explicitly, otherwise maven will resolve to 8.5.3, and this does not exist.
|
||||
Make sure to specify the version 7.17.9 explicitly, otherwise maven will resolve to 8.5.3, and this does not exist.
|
||||
|
||||
@@ -29,7 +29,7 @@ See <<elasticsearch.repositories.autocreation>>
|
||||
|
||||
|
||||
* `@Id`: Applied at the field level to mark the field used for identity purpose.
|
||||
* `@Transient`: By default all fields are mapped to the document when it is stored or retrieved, this annotation excludes the field.
|
||||
* `@Transient`, `@ReadOnlyProperty`, `@WriteOnlyProperty`: see the following section <<elasticsearch.mapping.meta-model.annotations.read-write>> for detailed information.
|
||||
* `@PersistenceConstructor`: Marks a given constructor - even a package protected one - to use when instantiating the object from the database.
|
||||
Constructor arguments are mapped by name to the key values in the retrieved Document.
|
||||
* `@Field`: Applied at the field level and defines properties of the field, most of the attributes map to the respective https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html[Elasticsearch Mapping] definitions (the following list is not complete, check the annotation Javadoc for a complete reference):
|
||||
@@ -49,6 +49,25 @@ In difference to a registered Spring `Converter` this only converts the annotate
|
||||
|
||||
The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic.
|
||||
|
||||
[[elasticsearch.mapping.meta-model.annotations.read-write]]
|
||||
==== Controlling which properties are written to and read from Elasticsearch
|
||||
|
||||
This section details the annotations that define if the value of a property is written to or
|
||||
read from Elasticsearch.
|
||||
|
||||
`@Transient`: A property annotated with this annotation will not be written to the mapping, it's value will not be
|
||||
sent to Elasticsearch and when documents are returned from Elasticsearch, this property will not be set in the
|
||||
resulting entity.
|
||||
|
||||
`@ReadOnlyProperty`: A property with this annotaiton will not have its value written to Elasticsearch, but when
|
||||
returning data, the proeprty will be filled with the value returned in the document from Elasticsearch. One use case
|
||||
for this are runtime fields defined in the index mapping.
|
||||
|
||||
`@WriteOnlyProperty`: A property with this annotaiton will have its value stored in Elasticsearch but will not be set
|
||||
with any value when reading document. This can be used for example for synthesized fields which should go into the
|
||||
Elasticsearch index but are not used elsewhere.
|
||||
|
||||
|
||||
[[elasticsearch.mapping.meta-model.annotations.date-formats]]
|
||||
==== Date format mapping
|
||||
|
||||
|
||||
+2
-1
@@ -154,7 +154,8 @@ public class ReactiveIndicesTemplate
|
||||
|
||||
@Override
|
||||
public Mono<Void> refresh() {
|
||||
return Mono.from(execute(ReactiveElasticsearchIndicesClient::refresh)).then();
|
||||
RefreshRequest refreshRequest = requestConverter.indicesRefreshRequest(getIndexCoordinates());
|
||||
return Mono.from(execute(client -> client.refresh(refreshRequest))).then();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-27
@@ -78,6 +78,7 @@ import jakarta.json.stream.JsonParser;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
@@ -176,14 +177,12 @@ class RequestConverter {
|
||||
createRequestBuilder.index(indexCoordinates.getIndexName());
|
||||
|
||||
// note: the new client does not support the index.storeType anymore
|
||||
String settingsJson = Document.from(settings).toJson();
|
||||
IndexSettings indexSettings = fromJson(settingsJson, IndexSettings._DESERIALIZER);
|
||||
createRequestBuilder.settings(indexSettings);
|
||||
createRequestBuilder.settings(IndexSettings.of(b -> b //
|
||||
.withJson(new StringReader(Document.from(settings).toJson()))));
|
||||
|
||||
if (mapping != null) {
|
||||
String mappingJson = mapping.toJson();
|
||||
TypeMapping typeMapping = fromJson(mappingJson, TypeMapping._DESERIALIZER);
|
||||
createRequestBuilder.mappings(typeMapping);
|
||||
createRequestBuilder.mappings(TypeMapping.of(b -> b //
|
||||
.withJson(new StringReader(mapping.toJson()))));
|
||||
}
|
||||
|
||||
return createRequestBuilder.build();
|
||||
@@ -275,11 +274,12 @@ class RequestConverter {
|
||||
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
|
||||
Assert.notNull(mapping, "mapping must not be null");
|
||||
|
||||
PutMappingRequest.Builder builder = new PutMappingRequest.Builder();
|
||||
builder.index(Arrays.asList(indexCoordinates.getIndexNames()));
|
||||
addPropertiesToMapping(builder, mapping);
|
||||
PutMappingRequest request = new PutMappingRequest.Builder() //
|
||||
.withJson(new StringReader(mapping.toJson())) //
|
||||
.index(Arrays.asList(indexCoordinates.getIndexNames())) //
|
||||
.build();
|
||||
|
||||
return builder.build();
|
||||
return request;
|
||||
}
|
||||
|
||||
public GetMappingRequest indicesGetMappingRequest(IndexCoordinates indexCoordinates) {
|
||||
@@ -289,23 +289,6 @@ class RequestConverter {
|
||||
return new GetMappingRequest.Builder().index(Arrays.asList(indexCoordinates.getIndexNames())).build();
|
||||
}
|
||||
|
||||
private void addPropertiesToMapping(PutMappingRequest.Builder builder, Document mapping) {
|
||||
Object properties = mapping.get("properties");
|
||||
|
||||
if (properties != null) {
|
||||
|
||||
if (properties instanceof Map) {
|
||||
Map<String, Property> propertiesMap = new HashMap<>();
|
||||
// noinspection unchecked
|
||||
((Map<String, Object>) properties).forEach((key, value) -> {
|
||||
Property property = getProperty(value);
|
||||
propertiesMap.put(key, property);
|
||||
});
|
||||
builder.properties(propertiesMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Property getProperty(Object value) {
|
||||
// noinspection SpellCheckingInspection
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
+61
-58
@@ -362,6 +362,67 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
public abstract List<IndexedObjectInformation> doBulkOperation(List<?> queries, BulkOptions bulkOptions,
|
||||
IndexCoordinates index);
|
||||
|
||||
@Override
|
||||
public <T> UpdateResponse update(T entity) {
|
||||
|
||||
Assert.notNull(entity, "entity must not be null");
|
||||
|
||||
return update(buildUpdateQueryByEntity(entity), getIndexCoordinatesFor(entity.getClass()));
|
||||
}
|
||||
|
||||
protected <T> UpdateQuery buildUpdateQueryByEntity(T entity) {
|
||||
|
||||
Assert.notNull(entity, "entity must not be null");
|
||||
|
||||
String id = getEntityId(entity);
|
||||
Assert.notNull(id, "entity must have an id that is notnull");
|
||||
|
||||
UpdateQuery.Builder updateQueryBuilder = UpdateQuery.builder(id)
|
||||
.withDocument(elasticsearchConverter.mapObject(entity));
|
||||
|
||||
String routing = getEntityRouting(entity);
|
||||
if (StringUtils.hasText(routing)) {
|
||||
updateQueryBuilder.withRouting(routing);
|
||||
}
|
||||
|
||||
return updateQueryBuilder.build();
|
||||
}
|
||||
|
||||
protected <T> T updateIndexedObject(T entity, IndexedObjectInformation indexedObjectInformation) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = elasticsearchConverter.getMappingContext()
|
||||
.getPersistentEntity(entity.getClass());
|
||||
|
||||
if (persistentEntity != null) {
|
||||
PersistentPropertyAccessor<Object> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
|
||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with text because ES generated Ids are strings!
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isReadable()
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
|
||||
}
|
||||
|
||||
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
|
||||
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
|
||||
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
|
||||
// noinspection ConstantConditions
|
||||
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
|
||||
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
|
||||
}
|
||||
|
||||
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
|
||||
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
// noinspection ConstantConditions
|
||||
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
|
||||
}
|
||||
|
||||
// noinspection unchecked
|
||||
return (T) propertyAccessor.getBean();
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region SearchOperations
|
||||
@@ -463,64 +524,6 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
return getRequiredPersistentEntity(clazz).getIndexCoordinates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> UpdateResponse update(T entity) {
|
||||
return update(buildUpdateQueryByEntity(entity), getIndexCoordinatesFor(entity.getClass()));
|
||||
}
|
||||
|
||||
protected <T> UpdateQuery buildUpdateQueryByEntity(T entity) {
|
||||
|
||||
Assert.notNull(entity, "entity must not be null");
|
||||
|
||||
String id = getEntityId(entity);
|
||||
Assert.notNull(id, "entity must have an id that is notnull");
|
||||
|
||||
UpdateQuery.Builder updateQueryBuilder = UpdateQuery.builder(id)
|
||||
.withDocument(elasticsearchConverter.mapObject(entity));
|
||||
|
||||
String routing = getEntityRouting(entity);
|
||||
if (StringUtils.hasText(routing)) {
|
||||
updateQueryBuilder.withRouting(routing);
|
||||
}
|
||||
|
||||
return updateQueryBuilder.build();
|
||||
}
|
||||
|
||||
protected <T> T updateIndexedObject(T entity, IndexedObjectInformation indexedObjectInformation) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = elasticsearchConverter.getMappingContext()
|
||||
.getPersistentEntity(entity.getClass());
|
||||
|
||||
if (persistentEntity != null) {
|
||||
PersistentPropertyAccessor<Object> propertyAccessor = persistentEntity.getPropertyAccessor(entity);
|
||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with text because ES generated Ids are strings!
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable()
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
|
||||
}
|
||||
|
||||
if (indexedObjectInformation.getSeqNo() != null && indexedObjectInformation.getPrimaryTerm() != null
|
||||
&& persistentEntity.hasSeqNoPrimaryTermProperty()) {
|
||||
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
|
||||
// noinspection ConstantConditions
|
||||
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
|
||||
new SeqNoPrimaryTerm(indexedObjectInformation.getSeqNo(), indexedObjectInformation.getPrimaryTerm()));
|
||||
}
|
||||
|
||||
if (indexedObjectInformation.getVersion() != null && persistentEntity.hasVersionProperty()) {
|
||||
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
// noinspection ConstantConditions
|
||||
propertyAccessor.setProperty(versionProperty, indexedObjectInformation.getVersion());
|
||||
}
|
||||
|
||||
// noinspection unchecked
|
||||
return (T) propertyAccessor.getBean();
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
ElasticsearchPersistentEntity<?> getRequiredPersistentEntity(Class<?> clazz) {
|
||||
return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz);
|
||||
}
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ abstract public class AbstractReactiveElasticsearchTemplate
|
||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with text because ES generated Ids are strings!
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable()
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isReadable()
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
|
||||
}
|
||||
|
||||
+2
-2
@@ -349,7 +349,7 @@ public class MappingElasticsearchConverter
|
||||
PersistentPropertyAccessor<R> propertyAccessor = new ConvertingPropertyAccessor<>(
|
||||
targetEntity.getPropertyAccessor(result), conversionService);
|
||||
// Only deal with String because ES generated Ids are strings !
|
||||
if (idProperty != null && idProperty.isWritable() && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
if (idProperty != null && idProperty.isReadable() && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, document.getId());
|
||||
}
|
||||
}
|
||||
@@ -411,7 +411,7 @@ public class MappingElasticsearchConverter
|
||||
|
||||
for (ElasticsearchPersistentProperty prop : entity) {
|
||||
|
||||
if (entity.isCreatorArgument(prop) || !prop.isReadable() || !prop.isWritable()) {
|
||||
if (entity.isCreatorArgument(prop) || !prop.isReadable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public interface ElasticsearchPersistentProperty extends PersistentProperty<Elas
|
||||
PropertyValueConverter getPropertyValueConverter();
|
||||
|
||||
/**
|
||||
* Returns true if the property may be read.
|
||||
* Returns true if the property may be read from the store into the entity.
|
||||
*
|
||||
* @return true if readable, false otherwise
|
||||
* @since 4.0
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.domain.Range;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
@@ -119,7 +120,7 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
|
||||
@Override
|
||||
public boolean isWritable() {
|
||||
return super.isWritable() && !isSeqNoPrimaryTermProperty();
|
||||
return !isTransient() && !isSeqNoPrimaryTermProperty() && !isAnnotationPresent(ReadOnlyProperty.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -62,6 +62,8 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
|
||||
String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService())
|
||||
.replacePlaceholders(this.queryString, parameterAccessor);
|
||||
|
||||
return new StringQuery(queryString);
|
||||
var query = new StringQuery(queryString);
|
||||
query.addSort(parameterAccessor.getSort());
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 5.0.1 (2022.0.1)
|
||||
Spring Data Elasticsearch 5.0.4 (2022.0.4)
|
||||
Copyright (c) [2013-2021] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -17,3 +17,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2021-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client.elc;
|
||||
|
||||
import co.elastic.clients.elasticsearch.indices.RefreshRequest;
|
||||
import co.elastic.clients.json.JsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* @author Urs Keller
|
||||
* @since 5.0
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class ReactiveIndicesTemplateTest {
|
||||
@Mock private ElasticsearchConverter elasticsearchConverter;
|
||||
@Mock private ReactiveElasticsearchIndicesClient client;
|
||||
@Mock private ElasticsearchTransport transport;
|
||||
@Mock private JsonpMapper jsonpMapper;
|
||||
@Captor ArgumentCaptor<RefreshRequest> refreshRequest;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
doReturn(transport).when(client)._transport();
|
||||
doReturn(jsonpMapper).when(transport).jsonpMapper();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that refresh is called with the indices bound to the template
|
||||
*/
|
||||
@Test
|
||||
void refresh() {
|
||||
IndexCoordinates indexCoordinate = IndexCoordinates.of("i1", "i2");
|
||||
ReactiveIndicesTemplate template = new ReactiveIndicesTemplate(client, elasticsearchConverter, indexCoordinate);
|
||||
doReturn(Mono.empty()).when(client).refresh(any(RefreshRequest.class));
|
||||
|
||||
template.refresh().as(StepVerifier::create).verifyComplete();
|
||||
|
||||
verify(client).refresh(refreshRequest.capture());
|
||||
assertEquals(List.of("i1", "i2"), refreshRequest.getValue().index());
|
||||
|
||||
verifyNoMoreInteractions(elasticsearchConverter, client, transport, jsonpMapper);
|
||||
}
|
||||
}
|
||||
+14
-29
@@ -15,21 +15,20 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.springframework.data.elasticsearch.annotations.Document.VersionType.EXTERNAL_GTE;
|
||||
import static java.util.Collections.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.annotations.Document.VersionType.*;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.Integer;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.Keyword;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.Text;
|
||||
import static org.springframework.data.elasticsearch.core.document.Document.create;
|
||||
import static org.springframework.data.elasticsearch.core.document.Document.parse;
|
||||
import static org.springframework.data.elasticsearch.utils.IdGenerator.nextIdAsString;
|
||||
import static org.springframework.data.elasticsearch.utils.IndexBuilder.buildIndex;
|
||||
import static org.springframework.data.elasticsearch.core.document.Document.*;
|
||||
import static org.springframework.data.elasticsearch.utils.IdGenerator.*;
|
||||
import static org.springframework.data.elasticsearch.utils.IndexBuilder.*;
|
||||
|
||||
import java.lang.Double;
|
||||
import java.lang.Integer;
|
||||
import java.lang.Long;
|
||||
import java.lang.Object;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -55,7 +54,6 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.AccessType;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -79,20 +77,7 @@ import org.springframework.data.elasticsearch.core.index.AliasActions;
|
||||
import org.springframework.data.elasticsearch.core.index.Settings;
|
||||
import org.springframework.data.elasticsearch.core.join.JoinField;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.IndicesOptions;
|
||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
||||
import org.springframework.data.elasticsearch.core.query.SourceFilter;
|
||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.*;
|
||||
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
|
||||
import org.springframework.data.elasticsearch.core.query.highlight.HighlightField;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
@@ -4582,7 +4567,7 @@ public abstract class ElasticsearchIntegrationTests {
|
||||
@Field(type = FieldType.Keyword) private String part2;
|
||||
|
||||
@Id
|
||||
@ReadOnlyProperty
|
||||
@WriteOnlyProperty
|
||||
@AccessType(AccessType.Type.PROPERTY)
|
||||
public String getId() {
|
||||
return part1 + '-' + part2;
|
||||
|
||||
+2
-2
@@ -52,7 +52,6 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.OptimisticLockingFailureException;
|
||||
import org.springframework.data.annotation.AccessType;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -63,6 +62,7 @@ import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.annotations.WriteOnlyProperty;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.NativeSearchQuery;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.NativeSearchQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
|
||||
@@ -1503,7 +1503,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
|
||||
@Field(type = FieldType.Keyword) private String part2;
|
||||
|
||||
@Id
|
||||
@ReadOnlyProperty
|
||||
@WriteOnlyProperty
|
||||
@AccessType(AccessType.Type.PROPERTY)
|
||||
public String getId() {
|
||||
return part1 + '-' + part2;
|
||||
|
||||
+66
-5
@@ -17,19 +17,24 @@ package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.NewElasticsearchClientDevelopment;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
@@ -44,14 +49,13 @@ public abstract class RuntimeFieldsIntegrationTests {
|
||||
|
||||
@Autowired private ElasticsearchOperations operations;
|
||||
@Autowired protected IndexNameProvider indexNameProvider;
|
||||
private IndexOperations indexOperations;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
indexNameProvider.increment();
|
||||
indexOperations = operations.indexOps(SomethingToBuy.class);
|
||||
indexOperations.createWithMapping();
|
||||
operations.indexOps(SomethingToBuy.class).createWithMapping();
|
||||
operations.indexOps(Person.class).createWithMapping();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -91,6 +95,24 @@ public abstract class RuntimeFieldsIntegrationTests {
|
||||
assertThat(searchHits.getSearchHit(0).getId()).isEqualTo("1");
|
||||
}
|
||||
|
||||
@Test // #2431
|
||||
@DisplayName("should return value from runtime field defined in mapping")
|
||||
void shouldReturnValueFromRuntimeFieldDefinedInMapping() {
|
||||
|
||||
var person = new Person();
|
||||
var years = 10;
|
||||
person.setBirthDate(LocalDate.now().minusDays(years * 365 + 100));
|
||||
operations.save(person);
|
||||
var query = Query.findAll();
|
||||
query.addFields("age");
|
||||
query.addSourceFilter(new FetchSourceFilterBuilder().withIncludes("*").build());
|
||||
|
||||
var searchHits = operations.search(query, Person.class);
|
||||
|
||||
assertThat(searchHits.getTotalHits()).isEqualTo(1);
|
||||
assertThat(searchHits.getSearchHit(0).getContent().getAge()).isEqualTo(years);
|
||||
}
|
||||
|
||||
private void insert(String id, String description, double price) {
|
||||
SomethingToBuy entity = new SomethingToBuy();
|
||||
entity.setId(id);
|
||||
@@ -99,7 +121,7 @@ public abstract class RuntimeFieldsIntegrationTests {
|
||||
operations.save(entity);
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}-something")
|
||||
private static class SomethingToBuy {
|
||||
private @Id @Nullable String id;
|
||||
|
||||
@@ -136,4 +158,43 @@ public abstract class RuntimeFieldsIntegrationTests {
|
||||
this.price = price;
|
||||
}
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}-person")
|
||||
@Mapping(runtimeFieldsPath = "/runtime-fields-person.json")
|
||||
public class Person {
|
||||
@Nullable private String id;
|
||||
|
||||
@Field(type = FieldType.Date, format = DateFormat.basic_date)
|
||||
@Nullable private LocalDate birthDate;
|
||||
|
||||
@ReadOnlyProperty // do not write to prevent ES from automapping
|
||||
@Nullable private Integer age;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public LocalDate getBirthDate() {
|
||||
return birthDate;
|
||||
}
|
||||
|
||||
public void setBirthDate(@Nullable LocalDate birthDate) {
|
||||
this.birthDate = birthDate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(@Nullable Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-3
@@ -43,7 +43,16 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.NewElasticsearchClientDevelopment;
|
||||
import org.springframework.data.elasticsearch.annotations.*;
|
||||
import org.springframework.data.elasticsearch.annotations.DateFormat;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Dynamic;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.InnerField;
|
||||
import org.springframework.data.elasticsearch.annotations.Mapping;
|
||||
import org.springframework.data.elasticsearch.annotations.MultiField;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.elasticsearch.annotations.TermVector;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.IndexOperations;
|
||||
import org.springframework.data.elasticsearch.core.MappingContextBaseTests;
|
||||
@@ -205,11 +214,37 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
|
||||
}
|
||||
|
||||
@Test // #1767
|
||||
@DisplayName("should write dynamic mapping annotations")
|
||||
void shouldWriteDynamicMappingAnnotations() {
|
||||
@DisplayName("should write dynamic mapping annotations on create")
|
||||
void shouldWriteDynamicMappingAnnotationsOnCreate() {
|
||||
|
||||
IndexOperations indexOps = operations.indexOps(DynamicMappingAnnotationEntity.class);
|
||||
indexOps.createWithMapping();
|
||||
|
||||
var mapping = indexOps.getMapping();
|
||||
var dynamic = mapping.get("dynamic");
|
||||
if (dynamic instanceof String s) {
|
||||
assertThat(dynamic).isEqualTo("false");
|
||||
} else {
|
||||
assertThat(mapping.get("dynamic")).isEqualTo(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test // #2478
|
||||
@DisplayName("should write dynamic mapping annotations on put")
|
||||
void shouldWriteDynamicMappingAnnotationsOnPut() {
|
||||
|
||||
IndexOperations indexOps = operations.indexOps(DynamicMappingAnnotationEntity.class);
|
||||
indexOps.create();
|
||||
|
||||
indexOps.putMapping();
|
||||
|
||||
var mapping = indexOps.getMapping();
|
||||
var dynamic = mapping.get("dynamic");
|
||||
if (dynamic instanceof String s) {
|
||||
assertThat(dynamic).isEqualTo("false");
|
||||
} else {
|
||||
assertThat(mapping.get("dynamic")).isEqualTo(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test // #1871
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"age": {
|
||||
"type": "long",
|
||||
"script": {
|
||||
"lang": "painless",
|
||||
"source": "Instant currentDate = Instant.ofEpochMilli(new Date().getTime()); Instant startDate = doc['birthDate'].value.toInstant(); emit(ChronoUnit.DAYS.between(startDate, currentDate) / 365);"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user