Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a876901c0 | |||
| f59d9c6eae | |||
| a1094527a9 | |||
| cd8fabe499 | |||
| b61f44d872 | |||
| 933ebab0e0 | |||
| edac49c470 | |||
| cb65bc5ead | |||
| c99d633ac6 | |||
| 7372f9120d | |||
| c09138f985 | |||
| 5ac167290c | |||
| 06db4fde05 | |||
| c823ce1946 | |||
| 2fa15f772a | |||
| 02b6d54cc9 | |||
| 8bb3474c05 | |||
| 7e904cdbe7 | |||
| e46b4977a4 | |||
| 5de2e0b96e | |||
| c36b878cee | |||
| 2efa79d469 | |||
| 20fde914df | |||
| 988736dd41 | |||
| 346c5cce58 | |||
| a3ebd8be78 | |||
| 3c6d96e49f | |||
| be70a398be | |||
| e3e666fd2e | |||
| cb3d1e11d3 | |||
| 9e17bf3df8 |
@@ -1,7 +1,7 @@
|
||||
# Java versions
|
||||
java.main.tag=8u332-b09-jdk
|
||||
java.next.tag=11.0.15_10-jdk
|
||||
java.lts.tag=17.0.3_7-jdk
|
||||
java.main.tag=8u345-b01-jdk-focal
|
||||
java.next.tag=11.0.16.1_1-jdk-focal
|
||||
java.lts.tag=17.0.4.1_1-jdk-focal
|
||||
|
||||
# Docker container images - standard
|
||||
docker.java.main.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclipse-temurin:${java.main.tag}
|
||||
@@ -10,14 +10,14 @@ docker.java.lts.image=harbor-repo.vmware.com/dockerhub-proxy-cache/library/eclip
|
||||
|
||||
# Supported versions of MongoDB
|
||||
docker.mongodb.4.0.version=4.0.28
|
||||
docker.mongodb.4.4.version=4.4.12
|
||||
docker.mongodb.5.0.version=5.0.6
|
||||
docker.mongodb.4.4.version=4.4.17
|
||||
docker.mongodb.5.0.version=5.0.13
|
||||
|
||||
# Supported versions of Redis
|
||||
docker.redis.6.version=6.2.6
|
||||
|
||||
# Supported versions of Cassandra
|
||||
docker.cassandra.3.version=3.11.12
|
||||
docker.cassandra.3.version=3.11.14
|
||||
|
||||
# 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.4.2</version>
|
||||
<version>4.4.6</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.7.2</version>
|
||||
<version>2.7.6</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -19,12 +19,12 @@
|
||||
|
||||
<properties>
|
||||
<!-- version of the RestHighLevelClient -->
|
||||
<elasticsearch-rhlc>7.17.4</elasticsearch-rhlc>
|
||||
<elasticsearch-rhlc>7.17.7</elasticsearch-rhlc>
|
||||
<!-- version of the new ElasticsearchClient -->
|
||||
<elasticsearch-java>7.17.4</elasticsearch-java>
|
||||
<elasticsearch-java>7.17.7</elasticsearch-java>
|
||||
<log4j>2.17.1</log4j>
|
||||
<netty>4.1.65.Final</netty>
|
||||
<springdata.commons>2.7.2</springdata.commons>
|
||||
<springdata.commons>2.7.6</springdata.commons>
|
||||
<testcontainers>1.16.2</testcontainers>
|
||||
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
|
||||
@@ -29,15 +29,15 @@ Requires an installation of https://www.elastic.co/products/elasticsearch[Elasti
|
||||
[[preface.versions]]
|
||||
=== Versions
|
||||
|
||||
The following table shows the Elasticsearch versions that are used by Spring Data release trains and version of
|
||||
Spring Data Elasticsearch included in that, as well as the Spring Boot versions referring to that particular Spring
|
||||
Data release train. The Elasticsearch version given shows with which client libraries Spring Data Elasticsearch was
|
||||
The following table shows the Elasticsearch versions that are used by Spring Data release trains and version of
|
||||
Spring Data Elasticsearch included in that, as well as the Spring Boot versions referring to that particular Spring
|
||||
Data release train. The Elasticsearch version given shows with which client libraries Spring Data Elasticsearch was
|
||||
built and tested.
|
||||
|
||||
[cols="^,^,^,^,^",options="header"]
|
||||
|===
|
||||
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot
|
||||
| 2021.2 (Raj) | 4.4.x | 7.17.4 | 5.3.x | 2.7.x
|
||||
| 2021.2 (Raj) | 4.4.x | 7.17.7 | 5.3.x | 2.7.x
|
||||
| 2021.1 (Q) | 4.3.x | 7.15.2 | 5.3.x | 2.6.x
|
||||
| 2021.0 (Pascal) | 4.2.xfootnote:oom[Out of maintenance] | 7.12.0 | 5.3.x | 2.5.x
|
||||
| 2020.0 (Ockham)footnote:oom[] | 4.1.xfootnote:oom[] | 7.9.3 | 5.3.2 | 2.4.x
|
||||
|
||||
@@ -82,7 +82,7 @@ The dependencies for the new Elasticsearch client are still optional in Spring D
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>7.17.4</version>
|
||||
<version>7.17.7</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
@@ -93,7 +93,7 @@ The dependencies for the new Elasticsearch client are still optional in Spring D
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>elasticsearch-rest-client</artifactId> <!-- is Apache 2-->
|
||||
<version>7.17.4</version>
|
||||
<version>7.17.7</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
== New in Spring Data Elasticsearch 4.4
|
||||
|
||||
* Introduction of new imperative and reactive clients using the classes from the new Elasticsearch Java client
|
||||
* Upgrade to Elasticsearch 7.17.4.
|
||||
* Upgrade to Elasticsearch 7.17.6.
|
||||
|
||||
[[new-features.4-3-0]]
|
||||
== New in Spring Data Elasticsearch 4.3
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+19
-4
@@ -32,7 +32,16 @@ import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
|
||||
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
|
||||
import co.elastic.clients.elasticsearch._types.query_dsl.Like;
|
||||
import co.elastic.clients.elasticsearch.cluster.HealthRequest;
|
||||
import co.elastic.clients.elasticsearch.core.*;
|
||||
import co.elastic.clients.elasticsearch.core.BulkRequest;
|
||||
import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest;
|
||||
import co.elastic.clients.elasticsearch.core.DeleteRequest;
|
||||
import co.elastic.clients.elasticsearch.core.GetRequest;
|
||||
import co.elastic.clients.elasticsearch.core.IndexRequest;
|
||||
import co.elastic.clients.elasticsearch.core.MgetRequest;
|
||||
import co.elastic.clients.elasticsearch.core.MsearchRequest;
|
||||
import co.elastic.clients.elasticsearch.core.SearchRequest;
|
||||
import co.elastic.clients.elasticsearch.core.UpdateByQueryRequest;
|
||||
import co.elastic.clients.elasticsearch.core.UpdateRequest;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.CreateOperation;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation;
|
||||
@@ -42,7 +51,6 @@ import co.elastic.clients.elasticsearch.core.search.Highlight;
|
||||
import co.elastic.clients.elasticsearch.core.search.Rescore;
|
||||
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
|
||||
import co.elastic.clients.elasticsearch.indices.*;
|
||||
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
|
||||
import co.elastic.clients.elasticsearch.indices.update_aliases.Action;
|
||||
import co.elastic.clients.json.JsonData;
|
||||
import co.elastic.clients.json.JsonpDeserializer;
|
||||
@@ -820,7 +828,11 @@ class RequestConverter {
|
||||
.refresh(reindexRequest.getRefresh()) //
|
||||
.requireAlias(reindexRequest.getRequireAlias()) //
|
||||
.requestsPerSecond(reindexRequest.getRequestsPerSecond()) //
|
||||
.slices(reindexRequest.getSlices());
|
||||
;
|
||||
|
||||
if (reindexRequest.getSlices() != null) {
|
||||
builder.slices(sb -> sb.value(reindexRequest.getSlices().intValue()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
@@ -963,9 +975,12 @@ class RequestConverter {
|
||||
.pipeline(updateQuery.getPipeline()) //
|
||||
.requestsPerSecond(
|
||||
updateQuery.getRequestsPerSecond() != null ? updateQuery.getRequestsPerSecond().longValue() : null) //
|
||||
.slices(updateQuery.getSlices() != null ? Long.valueOf(updateQuery.getSlices()) : null) //
|
||||
;
|
||||
|
||||
if (updateQuery.getSlices() != null) {
|
||||
ub.slices(sb -> sb.value(updateQuery.getSlices() != null ? updateQuery.getSlices() : null));
|
||||
}
|
||||
|
||||
if (updateQuery.getAbortOnVersionConflict() != null) {
|
||||
ub.conflicts(updateQuery.getAbortOnVersionConflict() ? Conflicts.Abort : Conflicts.Proceed);
|
||||
}
|
||||
|
||||
+9
@@ -256,6 +256,15 @@ public interface WebClientProvider {
|
||||
HttpHeaders suppliedHeaders = clientConfiguration.getHeadersSupplier().get();
|
||||
|
||||
if (suppliedHeaders != null && suppliedHeaders != HttpHeaders.EMPTY) {
|
||||
|
||||
// remove content-type and accept if they are provided by the client configuration (ES7 compatibility headers)
|
||||
if (suppliedHeaders.containsKey(HttpHeaders.CONTENT_TYPE)) {
|
||||
httpHeaders.remove(HttpHeaders.CONTENT_TYPE);
|
||||
}
|
||||
if (suppliedHeaders.containsKey(HttpHeaders.ACCEPT)) {
|
||||
httpHeaders.remove(HttpHeaders.ACCEPT);
|
||||
}
|
||||
|
||||
httpHeaders.addAll(suppliedHeaders);
|
||||
}
|
||||
}));
|
||||
|
||||
+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());
|
||||
|
||||
+1
-1
@@ -478,7 +478,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
|
||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
// Only deal with text because ES generated Ids are strings!
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable()
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
|
||||
}
|
||||
|
||||
+1
-1
@@ -259,7 +259,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
|
||||
if (indexedObjectInformation.getId() != null && idProperty != null && idProperty.isWritable()
|
||||
&& idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, indexedObjectInformation.getId());
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ class RequestFactory {
|
||||
Object queryObject = query.getObject();
|
||||
|
||||
if (queryObject != null) {
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(queryObject) : query.getId();
|
||||
String id = StringUtils.hasText(query.getId()) ? query.getId() : getPersistentEntityId(queryObject);
|
||||
// If we have a query id and a document id, do not ask ES to generate one.
|
||||
if (id != null) {
|
||||
indexRequest = new IndexRequest(indexName).id(id);
|
||||
@@ -1027,7 +1027,14 @@ class RequestFactory {
|
||||
if (params == null) {
|
||||
params = new HashMap<>();
|
||||
}
|
||||
Script script = new Script(getScriptType(query.getScriptType()), query.getLang(), query.getScript(), params);
|
||||
org.elasticsearch.script.ScriptType scriptType = getScriptType(query.getScriptType());
|
||||
String lang = query.getLang();
|
||||
|
||||
if (scriptType == org.elasticsearch.script.ScriptType.INLINE && lang == null) {
|
||||
lang = "painless";
|
||||
}
|
||||
|
||||
Script script = new Script(scriptType, lang, query.getScript(), params);
|
||||
updateRequest.script(script);
|
||||
}
|
||||
|
||||
|
||||
+82
-22
@@ -40,6 +40,7 @@ import org.springframework.data.elasticsearch.core.document.SearchDocument;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
|
||||
@@ -192,7 +193,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 {
|
||||
@@ -211,10 +212,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);
|
||||
@@ -225,11 +233,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)) {
|
||||
@@ -247,8 +255,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) {
|
||||
@@ -333,7 +341,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.getType().isAssignableFrom(String.class)) {
|
||||
if (idProperty != null && idProperty.isWritable() && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
propertyAccessor.setProperty(idProperty, document.getId());
|
||||
}
|
||||
}
|
||||
@@ -365,7 +373,6 @@ public class MappingElasticsearchConverter
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private ParameterValueProvider<ElasticsearchPersistentProperty> getParameterProvider(
|
||||
@@ -397,7 +404,7 @@ public class MappingElasticsearchConverter
|
||||
|
||||
for (ElasticsearchPersistentProperty prop : entity) {
|
||||
|
||||
if (entity.isConstructorArgument(prop) || !prop.isReadable()) {
|
||||
if (entity.isConstructorArgument(prop) || !prop.isReadable() || !prop.isWritable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -455,12 +462,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());
|
||||
|
||||
@@ -649,7 +688,8 @@ public class MappingElasticsearchConverter
|
||||
* @see org.springframework.data.mapping.model.SpELExpressionParameterValueProvider#potentiallyConvertSpelValue(java.lang.Object, org.springframework.data.mapping.PreferredConstructor.Parameter)
|
||||
*/
|
||||
@Override
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, ElasticsearchPersistentProperty> parameter) {
|
||||
protected <T> T potentiallyConvertSpelValue(Object object,
|
||||
Parameter<T, ElasticsearchPersistentProperty> parameter) {
|
||||
return readValue(object, parameter.getType());
|
||||
}
|
||||
}
|
||||
@@ -1117,17 +1157,29 @@ public class MappingElasticsearchConverter
|
||||
|
||||
Assert.notNull(query, "query must not be null");
|
||||
|
||||
if (domainClass != null) {
|
||||
if (query instanceof BaseQuery) {
|
||||
|
||||
updateFieldsAndSourceFilter(query, domainClass);
|
||||
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updateCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
if (((BaseQuery) query).queryIsUpdatedByConverter()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (domainClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
updatePropertiesInFieldsAndSourceFilter(query, domainClass);
|
||||
|
||||
if (query instanceof CriteriaQuery) {
|
||||
updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass);
|
||||
}
|
||||
|
||||
if (query instanceof BaseQuery) {
|
||||
((BaseQuery) query).setQueryIsUpdatedByConverter(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||
private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(domainClass);
|
||||
|
||||
@@ -1165,14 +1217,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");
|
||||
@@ -1181,17 +1241,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();
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ public class BaseQuery implements Query {
|
||||
protected final List<RuntimeField> runtimeFields = new ArrayList<>();
|
||||
@Nullable protected List<IndexBoost> indicesBoost;
|
||||
|
||||
private boolean queryIsUpdatedByConverter = false;
|
||||
|
||||
public BaseQuery() {}
|
||||
|
||||
public <Q extends BaseQuery, B extends BaseQueryBuilder<Q, B>> BaseQuery(BaseQueryBuilder<Q, B> builder) {
|
||||
@@ -440,4 +442,23 @@ public class BaseQuery implements Query {
|
||||
public List<IndexBoost> getIndicesBoost() {
|
||||
return indicesBoost;
|
||||
}
|
||||
|
||||
/**
|
||||
* used internally. Not considered part of the API.
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public boolean queryIsUpdatedByConverter() {
|
||||
return queryIsUpdatedByConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* used internally. Not considered part of the API.
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public void setQueryIsUpdatedByConverter(boolean queryIsUpdatedByConverter) {
|
||||
this.queryIsUpdatedByConverter = queryIsUpdatedByConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+130
@@ -15,9 +15,24 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitSupport;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitsImpl;
|
||||
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* AbstractElasticsearchRepositoryQuery
|
||||
@@ -32,11 +47,13 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
|
||||
protected static final int DEFAULT_STREAM_BATCH_SIZE = 500;
|
||||
protected ElasticsearchQueryMethod queryMethod;
|
||||
protected ElasticsearchOperations elasticsearchOperations;
|
||||
protected final ElasticsearchConverter elasticsearchConverter;
|
||||
|
||||
public AbstractElasticsearchRepositoryQuery(ElasticsearchQueryMethod queryMethod,
|
||||
ElasticsearchOperations elasticsearchOperations) {
|
||||
this.queryMethod = queryMethod;
|
||||
this.elasticsearchOperations = elasticsearchOperations;
|
||||
this.elasticsearchConverter = elasticsearchOperations.getElasticsearchConverter();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,4 +66,117 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
|
||||
* @since 4.2
|
||||
*/
|
||||
public abstract boolean isCountQuery();
|
||||
|
||||
protected abstract boolean isDeleteQuery();
|
||||
|
||||
protected abstract boolean isExistsQuery();
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
|
||||
ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
|
||||
Class<?> clazz = getResultClass();
|
||||
Query query = createQuery(parameters);
|
||||
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
|
||||
|
||||
Object result = null;
|
||||
|
||||
if (isDeleteQuery()) {
|
||||
result = countOrGetDocumentsForDelete(query, parameterAccessor);
|
||||
elasticsearchOperations.delete(query, clazz, index);
|
||||
elasticsearchOperations.indexOps(index).refresh();
|
||||
} else if (isCountQuery()) {
|
||||
result = elasticsearchOperations.count(query, clazz, index);
|
||||
} else if (isExistsQuery()) {
|
||||
result = elasticsearchOperations.count(query, clazz, index) > 0;
|
||||
} else if (queryMethod.isPageQuery()) {
|
||||
query.setPageable(parameterAccessor.getPageable());
|
||||
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
|
||||
if (queryMethod.isSearchPageMethod()) {
|
||||
result = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
|
||||
} else {
|
||||
result = SearchHitSupport.unwrapSearchHits(SearchHitSupport.searchPageFor(searchHits, query.getPageable()));
|
||||
}
|
||||
} else if (queryMethod.isStreamQuery()) {
|
||||
query.setPageable(parameterAccessor.getPageable().isPaged() ? parameterAccessor.getPageable()
|
||||
: PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
|
||||
result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(query, clazz, index));
|
||||
} else if (queryMethod.isCollectionQuery()) {
|
||||
|
||||
if (parameterAccessor.getPageable().isUnpaged()) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, clazz, index);
|
||||
|
||||
if (itemCount == 0) {
|
||||
result = new SearchHitsImpl<>(0, TotalHitsRelation.EQUAL_TO, Float.NaN, null, Collections.emptyList(), null,
|
||||
null);
|
||||
} else {
|
||||
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
|
||||
}
|
||||
} else {
|
||||
query.setPageable(parameterAccessor.getPageable());
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
result = elasticsearchOperations.search(query, clazz, index);
|
||||
}
|
||||
|
||||
} else {
|
||||
result = elasticsearchOperations.searchOne(query, clazz, index);
|
||||
}
|
||||
|
||||
return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod())
|
||||
? SearchHitSupport.unwrapSearchHits(result)
|
||||
: result;
|
||||
}
|
||||
|
||||
public Query createQuery(Object[] parameters) {
|
||||
|
||||
Class<?> clazz = getResultClass();
|
||||
ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
|
||||
Query query = createQuery(parameterAccessor);
|
||||
|
||||
Assert.notNull(query, "unsupported query");
|
||||
|
||||
if (queryMethod.hasAnnotatedHighlight()) {
|
||||
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
private Class<?> getResultClass() {
|
||||
return queryMethod.getResultProcessor().getReturnedType().getDomainType();
|
||||
}
|
||||
|
||||
private ParametersParameterAccessor getParameterAccessor(Object[] parameters) {
|
||||
return new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object countOrGetDocumentsForDelete(Query query, ParametersParameterAccessor accessor) {
|
||||
|
||||
Object result = null;
|
||||
Class<?> entityClass = queryMethod.getEntityInformation().getJavaType();
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(entityClass);
|
||||
|
||||
if (queryMethod.isCollectionQuery()) {
|
||||
|
||||
if (accessor.getPageable().isUnpaged()) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, entityClass, index);
|
||||
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
result = elasticsearchOperations.search(query, entityClass, index);
|
||||
}
|
||||
|
||||
if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
|
||||
result = elasticsearchOperations.count(query, entityClass, index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract Query createQuery(ParametersParameterAccessor accessor);
|
||||
}
|
||||
|
||||
+12
-101
@@ -15,26 +15,18 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitSupport;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitsImpl;
|
||||
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
|
||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.BaseQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* ElasticsearchPartQuery
|
||||
@@ -49,13 +41,11 @@ import org.springframework.util.ClassUtils;
|
||||
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery {
|
||||
|
||||
private final PartTree tree;
|
||||
private final ElasticsearchConverter elasticsearchConverter;
|
||||
private final MappingContext<?, ElasticsearchPersistentProperty> mappingContext;
|
||||
|
||||
public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations) {
|
||||
super(method, elasticsearchOperations);
|
||||
this.tree = new PartTree(queryMethod.getName(), queryMethod.getResultProcessor().getReturnedType().getDomainType());
|
||||
this.elasticsearchConverter = elasticsearchOperations.getElasticsearchConverter();
|
||||
this.mappingContext = elasticsearchConverter.getMappingContext();
|
||||
}
|
||||
|
||||
@@ -65,103 +55,24 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType();
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
protected boolean isDeleteQuery() {
|
||||
return tree.isDelete();
|
||||
}
|
||||
|
||||
CriteriaQuery query = createQuery(accessor);
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return tree.isExistsProjection();
|
||||
}
|
||||
|
||||
Assert.notNull(query, "unsupported query");
|
||||
protected Query createQuery(ParametersParameterAccessor accessor) {
|
||||
|
||||
elasticsearchConverter.updateQuery(query, clazz);
|
||||
|
||||
if (queryMethod.hasAnnotatedHighlight()) {
|
||||
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
|
||||
}
|
||||
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
|
||||
|
||||
Object result = null;
|
||||
BaseQuery query = new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
|
||||
|
||||
if (tree.isLimiting()) {
|
||||
// noinspection ConstantConditions
|
||||
query.setMaxResults(tree.getMaxResults());
|
||||
}
|
||||
|
||||
if (tree.isDelete()) {
|
||||
result = countOrGetDocumentsForDelete(query, accessor);
|
||||
elasticsearchOperations.delete(query, clazz, index);
|
||||
elasticsearchOperations.indexOps(index).refresh();
|
||||
} else if (queryMethod.isPageQuery()) {
|
||||
query.setPageable(accessor.getPageable());
|
||||
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
|
||||
if (queryMethod.isSearchPageMethod()) {
|
||||
result = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
|
||||
} else {
|
||||
result = SearchHitSupport.unwrapSearchHits(SearchHitSupport.searchPageFor(searchHits, query.getPageable()));
|
||||
}
|
||||
} else if (queryMethod.isStreamQuery()) {
|
||||
if (accessor.getPageable().isUnpaged()) {
|
||||
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(query, clazz, index));
|
||||
} else if (queryMethod.isCollectionQuery()) {
|
||||
|
||||
if (accessor.getPageable().isUnpaged()) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, clazz, index);
|
||||
|
||||
if (itemCount == 0) {
|
||||
result = new SearchHitsImpl<>(0, TotalHitsRelation.EQUAL_TO, Float.NaN, null, Collections.emptyList(), null,
|
||||
null);
|
||||
} else {
|
||||
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
|
||||
}
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
result = elasticsearchOperations.search(query, clazz, index);
|
||||
}
|
||||
|
||||
} else if (tree.isCountProjection()) {
|
||||
result = elasticsearchOperations.count(query, clazz, index);
|
||||
} else {
|
||||
result = elasticsearchOperations.searchOne(query, clazz, index);
|
||||
}
|
||||
|
||||
return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod())
|
||||
? SearchHitSupport.unwrapSearchHits(result)
|
||||
: result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object countOrGetDocumentsForDelete(CriteriaQuery query, ParametersParameterAccessor accessor) {
|
||||
|
||||
Object result = null;
|
||||
Class<?> clazz = queryMethod.getEntityInformation().getJavaType();
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
|
||||
|
||||
if (queryMethod.isCollectionQuery()) {
|
||||
|
||||
if (accessor.getPageable().isUnpaged()) {
|
||||
int itemCount = (int) elasticsearchOperations.count(query, clazz, index);
|
||||
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
|
||||
} else {
|
||||
query.setPageable(accessor.getPageable());
|
||||
}
|
||||
result = elasticsearchOperations.search(query, clazz, index);
|
||||
}
|
||||
|
||||
if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
|
||||
result = elasticsearchOperations.count(query, clazz, index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
|
||||
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
+16
-55
@@ -15,16 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.repository.query;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHitSupport;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||
import org.springframework.data.elasticsearch.repository.support.StringQueryUtil;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.util.StreamUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -38,13 +33,13 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQuery {
|
||||
|
||||
private String query;
|
||||
private final String queryString;
|
||||
|
||||
public ElasticsearchStringQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations,
|
||||
String query) {
|
||||
String queryString) {
|
||||
super(queryMethod, elasticsearchOperations);
|
||||
Assert.notNull(query, "Query cannot be empty");
|
||||
this.query = query;
|
||||
Assert.notNull(queryString, "Query cannot be empty");
|
||||
this.queryString = queryString;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,54 +48,20 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(Object[] parameters) {
|
||||
|
||||
Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType();
|
||||
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
|
||||
|
||||
StringQuery stringQuery = createQuery(accessor);
|
||||
|
||||
Assert.notNull(stringQuery, "unsupported query");
|
||||
|
||||
if (queryMethod.hasAnnotatedHighlight()) {
|
||||
stringQuery.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
|
||||
}
|
||||
|
||||
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
|
||||
|
||||
Object result = null;
|
||||
|
||||
if (isCountQuery()) {
|
||||
result = elasticsearchOperations.count(stringQuery, clazz, index);
|
||||
} else if (queryMethod.isPageQuery()) {
|
||||
stringQuery.setPageable(accessor.getPageable());
|
||||
SearchHits<?> searchHits = elasticsearchOperations.search(stringQuery, clazz, index);
|
||||
if (queryMethod.isSearchPageMethod()) {
|
||||
result = SearchHitSupport.searchPageFor(searchHits, stringQuery.getPageable());
|
||||
} else {
|
||||
result = SearchHitSupport
|
||||
.unwrapSearchHits(SearchHitSupport.searchPageFor(searchHits, stringQuery.getPageable()));
|
||||
}
|
||||
} else if (queryMethod.isStreamQuery()) {
|
||||
stringQuery.setPageable(
|
||||
accessor.getPageable().isPaged() ? accessor.getPageable() : PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
|
||||
result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(stringQuery, clazz, index));
|
||||
} else if (queryMethod.isCollectionQuery()) {
|
||||
stringQuery.setPageable(accessor.getPageable().isPaged() ? accessor.getPageable() : Pageable.unpaged());
|
||||
result = elasticsearchOperations.search(stringQuery, clazz, index);
|
||||
} else {
|
||||
result = elasticsearchOperations.searchOne(stringQuery, clazz, index);
|
||||
}
|
||||
|
||||
return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod())
|
||||
? SearchHitSupport.unwrapSearchHits(result)
|
||||
: result;
|
||||
protected boolean isDeleteQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) {
|
||||
@Override
|
||||
protected boolean isExistsQuery() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Query createQuery(ParametersParameterAccessor parameterAccessor) {
|
||||
|
||||
String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService())
|
||||
.replacePlaceholders(this.query, parameterAccessor);
|
||||
.replacePlaceholders(this.queryString, parameterAccessor);
|
||||
|
||||
return new StringQuery(queryString);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -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,9 +60,7 @@ 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.4.2 (2021.2.2)
|
||||
Spring Data Elasticsearch 4.4.6 (2021.2.6)
|
||||
Copyright (c) [2013-2021] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
@@ -35,6 +35,10 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+3
-4
@@ -21,8 +21,8 @@ import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
|
||||
|
||||
/**
|
||||
@@ -36,12 +36,11 @@ public class ElasticsearchPartQueryELCIntegrationTests extends ElasticsearchPart
|
||||
static class Config {}
|
||||
|
||||
@Override
|
||||
protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) {
|
||||
protected String buildQueryString(Query query, Class<?> clazz) {
|
||||
|
||||
JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper();
|
||||
RequestConverter requestConverter = new RequestConverter(operations.getElasticsearchConverter(), jsonpMapper);
|
||||
SearchRequest request = requestConverter.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy"), false,
|
||||
false);
|
||||
SearchRequest request = requestConverter.searchRequest(query, clazz, IndexCoordinates.of("dummy"), false, false);
|
||||
|
||||
return JsonUtils.toJson(request, jsonpMapper);
|
||||
// return "{\"query\":" + JsonUtils.toJson(request.query(), jsonpMapper) + "}";
|
||||
|
||||
+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
|
||||
|
||||
+49
@@ -45,7 +45,9 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
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;
|
||||
@@ -2783,6 +2785,7 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
|
||||
assertThat(settings).doesNotContainKey("index.max_result_window");
|
||||
}
|
||||
|
||||
@DisabledIf(value = "newElasticsearchClient", disabledReason = "ES 7.17.6 returns a null storage type that the new client cannot handle")
|
||||
@Test // DATAES-709
|
||||
public void shouldIncludeDefaultsOnGetIndexSettings() {
|
||||
|
||||
@@ -3718,6 +3721,21 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
|
||||
}
|
||||
}
|
||||
|
||||
@Test // #2230
|
||||
@DisplayName("should work with readonly id")
|
||||
void shouldWorkWithReadonlyId() {
|
||||
|
||||
ReadonlyIdEntity entity = new ReadonlyIdEntity();
|
||||
entity.setPart1("foo");
|
||||
entity.setPart2("bar");
|
||||
operations.save(entity);
|
||||
|
||||
ReadonlyIdEntity readEntity = operations.get(entity.getId(), ReadonlyIdEntity.class);
|
||||
|
||||
assertThat(readEntity.getPart1()).isEqualTo(entity.getPart1());
|
||||
assertThat(readEntity.getPart2()).isEqualTo(entity.getPart2());
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
private static class SampleEntityUUIDKeyed {
|
||||
@Nullable
|
||||
@@ -4463,5 +4481,36 @@ public abstract class ElasticsearchIntegrationTests implements NewElasticsearchC
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id")
|
||||
static class ReadonlyIdEntity {
|
||||
@Field(type = FieldType.Keyword) private String part1;
|
||||
|
||||
@Field(type = FieldType.Keyword) private String part2;
|
||||
|
||||
@Id
|
||||
@ReadOnlyProperty
|
||||
@AccessType(AccessType.Type.PROPERTY)
|
||||
public String getId() {
|
||||
return part1 + '-' + part2;
|
||||
}
|
||||
|
||||
public String getPart1() {
|
||||
return part1;
|
||||
}
|
||||
|
||||
public void setPart1(String part1) {
|
||||
this.part1 = part1;
|
||||
}
|
||||
|
||||
public String getPart2() {
|
||||
return part2;
|
||||
}
|
||||
|
||||
public void setPart2(String part2) {
|
||||
this.part2 = part2;
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
+3
-3
@@ -19,8 +19,8 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@@ -38,9 +38,9 @@ public class ElasticsearchPartQueryERHLCIntegrationTests extends ElasticsearchPa
|
||||
@Import({ ElasticsearchRestTemplateConfiguration.class })
|
||||
static class Config {}
|
||||
|
||||
protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) {
|
||||
protected String buildQueryString(Query query, Class<?> clazz) {
|
||||
SearchSourceBuilder source = new RequestFactory(operations.getElasticsearchConverter())
|
||||
.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy")).source();
|
||||
.searchRequest(query, clazz, IndexCoordinates.of("dummy")).source();
|
||||
// remove defaultboost values
|
||||
return source.toString().replaceAll("(\\^\\d+\\.\\d+)", "");
|
||||
}
|
||||
|
||||
+3
-3
@@ -103,15 +103,15 @@ public class ReactiveElasticsearchELCIntegrationTests extends ReactiveElasticsea
|
||||
assertThat(bucketList.size()).isEqualTo(3);
|
||||
AtomicInteger count = new AtomicInteger();
|
||||
bucketList.forEach(stringTermsBucket -> {
|
||||
if ("message".equals(stringTermsBucket.key())) {
|
||||
if ("message".equals(stringTermsBucket.key().stringValue())) {
|
||||
count.getAndIncrement();
|
||||
assertThat(stringTermsBucket.docCount()).isEqualTo(3);
|
||||
}
|
||||
if ("some".equals(stringTermsBucket.key())) {
|
||||
if ("some".equals(stringTermsBucket.key().stringValue())) {
|
||||
count.getAndIncrement();
|
||||
assertThat(stringTermsBucket.docCount()).isEqualTo(2);
|
||||
}
|
||||
if ("other".equals(stringTermsBucket.key())) {
|
||||
if ("other".equals(stringTermsBucket.key().stringValue())) {
|
||||
count.getAndIncrement();
|
||||
assertThat(stringTermsBucket.docCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
+49
@@ -49,7 +49,9 @@ import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
@@ -1156,6 +1158,23 @@ public abstract class ReactiveElasticsearchIntegrationTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test // #2230
|
||||
@DisplayName("should work with readonly id")
|
||||
void shouldWorkWithReadonlyId() {
|
||||
|
||||
ReadonlyIdEntity entity = new ReadonlyIdEntity();
|
||||
entity.setPart1("foo");
|
||||
entity.setPart2("bar");
|
||||
|
||||
operations.save(entity).block();
|
||||
|
||||
operations.get(entity.getId(), ReadonlyIdEntity.class) //
|
||||
.as(StepVerifier::create) //
|
||||
.assertNext(readEntity -> { //
|
||||
assertThat(readEntity.getPart1()).isEqualTo(entity.getPart1()); //
|
||||
assertThat(readEntity.getPart2()).isEqualTo(entity.getPart2()); //
|
||||
}).verifyComplete();
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region Helper functions
|
||||
@@ -1489,5 +1508,35 @@ public abstract class ReactiveElasticsearchIntegrationTests {
|
||||
+ seqNoPrimaryTerm + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id")
|
||||
static class ReadonlyIdEntity {
|
||||
@Field(type = FieldType.Keyword) private String part1;
|
||||
|
||||
@Field(type = FieldType.Keyword) private String part2;
|
||||
|
||||
@Id
|
||||
@ReadOnlyProperty
|
||||
@AccessType(AccessType.Type.PROPERTY)
|
||||
public String getId() {
|
||||
return part1 + '-' + part2;
|
||||
}
|
||||
|
||||
public String getPart1() {
|
||||
return part1;
|
||||
}
|
||||
|
||||
public void setPart1(String part1) {
|
||||
this.part1 = part1;
|
||||
}
|
||||
|
||||
public String getPart2() {
|
||||
return part2;
|
||||
}
|
||||
|
||||
public void setPart2(String part2) {
|
||||
this.part2 = part2;
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
}
|
||||
|
||||
@@ -140,6 +140,18 @@ class RequestFactoryTests {
|
||||
assertThat(request.upsertRequest()).isNotNull();
|
||||
}
|
||||
|
||||
@Test // #2287
|
||||
@DisplayName("should create update query when script language is not set")
|
||||
void shouldCreateUpdateQueryWhenScriptTypeIsSetToNull() {
|
||||
|
||||
UpdateQuery updateQuery = UpdateQuery.builder("1") //
|
||||
.withScript("script").build();
|
||||
|
||||
UpdateRequest request = requestFactory.updateRequest(updateQuery, IndexCoordinates.of("index"));
|
||||
|
||||
assertThat(request).isNotNull();
|
||||
}
|
||||
|
||||
@Test // DATAES-693
|
||||
public void shouldReturnSourceWhenRequested() {
|
||||
// given
|
||||
|
||||
+506
-41
@@ -33,7 +33,10 @@ 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.intellij.lang.annotations.Language;
|
||||
import org.json.JSONException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
@@ -623,7 +626,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 +669,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 +700,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 +718,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertThat(document).isEqualTo(notificationAsMap);
|
||||
}
|
||||
|
||||
@Test // DATAES-763
|
||||
@Test
|
||||
// DATAES-763
|
||||
void readEntityWithMapDataType() {
|
||||
|
||||
Document document = Document.create();
|
||||
@@ -729,7 +736,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 +751,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 +770,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 +782,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 +792,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 +810,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, json, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-857
|
||||
@Test
|
||||
// DATAES-857
|
||||
void shouldWriteEntityWithListOfGeoPoints() throws JSONException {
|
||||
|
||||
GeoPointListEntity entity = new GeoPointListEntity();
|
||||
@@ -827,7 +840,8 @@ public class MappingElasticsearchConverterUnitTests {
|
||||
assertEquals(expected, json, false);
|
||||
}
|
||||
|
||||
@Test // DATAES-857
|
||||
@Test
|
||||
// DATAES-857
|
||||
void shouldReadEntityWithListOfGeoPoints() {
|
||||
|
||||
String json = "{\n" + //
|
||||
@@ -852,7 +866,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 +1524,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();
|
||||
@@ -1678,34 +1992,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;
|
||||
}
|
||||
|
||||
@@ -1792,15 +2118,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);
|
||||
}
|
||||
|
||||
@@ -1826,10 +2155,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;
|
||||
|
||||
@@ -1862,17 +2193,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);
|
||||
}
|
||||
|
||||
@@ -1903,10 +2238,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;
|
||||
|
||||
@@ -1953,17 +2290,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;
|
||||
}
|
||||
|
||||
@@ -1990,10 +2331,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;
|
||||
|
||||
@@ -2462,6 +2805,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) {
|
||||
|
||||
+1
-1
@@ -241,7 +241,7 @@ abstract class CallbackIntegrationTests {
|
||||
@Id private String id;
|
||||
@Nullable private String text;
|
||||
|
||||
@ReadOnlyProperty
|
||||
// @ReadOnlyProperty
|
||||
@Nullable private String className;
|
||||
|
||||
@Nullable
|
||||
|
||||
-2
@@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveIndexOperations;
|
||||
@@ -119,7 +118,6 @@ public abstract class ReactiveCallbackIntegrationTests {
|
||||
@Id private String id;
|
||||
private String text;
|
||||
|
||||
@ReadOnlyProperty
|
||||
@Nullable private String className;
|
||||
|
||||
public SampleEntity(String id, String text) {
|
||||
|
||||
+4
-6
@@ -36,7 +36,6 @@ import org.springframework.data.elasticsearch.repository.query.ElasticsearchPart
|
||||
import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
@@ -637,19 +636,18 @@ public abstract class ElasticsearchPartQueryIntegrationTests {
|
||||
new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(),
|
||||
operations.getElasticsearchConverter().getMappingContext());
|
||||
ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations);
|
||||
CriteriaQuery criteriaQuery = partQuery
|
||||
.createQuery(new ParametersParameterAccessor(queryMethod.getParameters(), parameters));
|
||||
return buildQueryString(criteriaQuery, Book.class);
|
||||
Query query = partQuery.createQuery(parameters);
|
||||
return buildQueryString(query, Book.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* builds the query String that would be sent to Elasticsearch
|
||||
*
|
||||
* @param criteriaQuery the {@link CriteriaQuery}
|
||||
* @param query the {@link Query}
|
||||
* @param clazz the entity class
|
||||
* @return the created query string
|
||||
*/
|
||||
abstract protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz);
|
||||
abstract protected String buildQueryString(Query query, Class<?> clazz);
|
||||
|
||||
@FunctionalInterface
|
||||
interface AssertFunction {
|
||||
|
||||
+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 {
|
||||
|
||||
|
||||
+13
@@ -310,6 +310,17 @@ abstract class QueryKeywordsIntegrationTests {
|
||||
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 = "#{@indexNameProvider.indexName()}")
|
||||
static class Product {
|
||||
@@ -452,6 +463,8 @@ abstract class QueryKeywordsIntegrationTests {
|
||||
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;
|
||||
@@ -121,6 +124,21 @@ public abstract 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();
|
||||
@@ -132,6 +150,8 @@ public abstract class ReactiveQueryKeywordsIntegrationTests {
|
||||
Flux<SearchHit<SampleEntity>> findByMessageIsNotEmpty();
|
||||
|
||||
Flux<SearchHit<SampleEntity>> findByMessageIsEmpty();
|
||||
|
||||
Mono<Boolean> existsByMessage(String message);
|
||||
}
|
||||
|
||||
private void loadEntities() {
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.0
|
||||
*/
|
||||
@ContextConfiguration(classes = { ReactiveValueConverterELCIntegrationTests.Config.class })
|
||||
public class ReactiveValueConverterELCIntegrationTests extends ReactiveValueConverterIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ ReactiveElasticsearchTemplateConfiguration.class })
|
||||
@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
@Bean
|
||||
IndexNameProvider indexNameProvider() {
|
||||
return new IndexNameProvider("reactive-valueconverter");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.0
|
||||
*/
|
||||
@ContextConfiguration(classes = { ReactiveValueConverterERHLCIntegrationTests.Config.class })
|
||||
public class ReactiveValueConverterERHLCIntegrationTests extends ReactiveValueConverterIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ ReactiveElasticsearchRestTemplateConfiguration.class })
|
||||
@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
@Bean
|
||||
IndexNameProvider indexNameProvider() {
|
||||
return new IndexNameProvider("reactive-valueconverter-es7");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.annotations.ValueConverter;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
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;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHit;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Integration tests to check that {@link org.springframework.data.elasticsearch.annotations.ValueConverter} annotated
|
||||
* properties are handle correctly (method name derived queries, for
|
||||
*
|
||||
* @{@link org.springframework.data.elasticsearch.core.query.Query} methods we don't know which parameters map to which
|
||||
* property.
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@SpringIntegrationTest
|
||||
public abstract class ReactiveValueConverterIntegrationTests {
|
||||
|
||||
@Autowired private IndexNameProvider indexNameProvider;
|
||||
@Autowired private ReactiveElasticsearchOperations operations;
|
||||
@Autowired private EntityRepository repository;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
indexNameProvider.increment();
|
||||
operations.indexOps(Entity.class).createWithMapping().block();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(java.lang.Integer.MAX_VALUE)
|
||||
void cleanup() {
|
||||
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete().block();
|
||||
}
|
||||
|
||||
|
||||
@Test // #2338
|
||||
@DisplayName("should apply ValueConverter")
|
||||
void shouldApplyValueConverter() {
|
||||
|
||||
ValueConverterIntegrationTests.Entity entity = new ValueConverterIntegrationTests.Entity();
|
||||
entity.setId("42");
|
||||
entity.setText("answer");
|
||||
operations.save(entity).block();
|
||||
|
||||
repository.queryByText("text-answer") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextCount(1) //
|
||||
.verifyComplete();
|
||||
|
||||
repository.findByText("answer") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextCount(1) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
interface EntityRepository extends ReactiveElasticsearchRepository<Entity, String> {
|
||||
Flux<SearchHit<Entity>> findByText(String text);
|
||||
|
||||
@Query("{ \"term\": { \"text\": \"?0\" } }")
|
||||
Flux<SearchHit<Entity>> queryByText(String text);
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
static class Entity {
|
||||
@Id
|
||||
@Nullable private String id;
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@ValueConverter(ValueConverterIntegrationTests.TextConverter.class)
|
||||
@Nullable private String text;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(@Nullable String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
static class TextConverter implements PropertyValueConverter {
|
||||
|
||||
public static final String PREFIX = "text-";
|
||||
|
||||
@Override
|
||||
public Object write(Object value) {
|
||||
return PREFIX + value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(Object value) {
|
||||
|
||||
String valueString = value.toString();
|
||||
|
||||
if (valueString.startsWith(PREFIX)) {
|
||||
return valueString.substring(PREFIX.length());
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* {@link ValueConverterIntegrationTests} using a Repository backed by an ElasticsearchTemplate.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.0
|
||||
*/
|
||||
@ContextConfiguration(classes = { ValueConverterELCIntegrationTests.Config.class })
|
||||
public class ValueConverterELCIntegrationTests extends ValueConverterIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ ElasticsearchTemplateConfiguration.class })
|
||||
@EnableElasticsearchRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
@Bean
|
||||
IndexNameProvider indexNameProvider() {
|
||||
return new IndexNameProvider("valueconverter");
|
||||
}
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
|
||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
/**
|
||||
* {@link ValueConverterIntegrationTests} using a Repository backed by an ElasticsearchTemplate.
|
||||
*
|
||||
* @author Peter-Josef Meisch
|
||||
* @since 5.0
|
||||
*/
|
||||
@ContextConfiguration(classes = { ValueConverterERHLCIntegrationTests.Config.class })
|
||||
public class ValueConverterERHLCIntegrationTests extends ValueConverterIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import({ ElasticsearchRestTemplateConfiguration.class })
|
||||
@EnableElasticsearchRepositories(considerNestedRepositories = true)
|
||||
static class Config {
|
||||
@Bean
|
||||
IndexNameProvider indexNameProvider() {
|
||||
return new IndexNameProvider("valueconverter-es7");
|
||||
}
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* 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.valueconverter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
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.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.FieldType;
|
||||
import org.springframework.data.elasticsearch.annotations.Query;
|
||||
import org.springframework.data.elasticsearch.annotations.ValueConverter;
|
||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||
import org.springframework.data.elasticsearch.core.SearchHits;
|
||||
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
|
||||
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
|
||||
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
|
||||
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
|
||||
import org.springframework.data.elasticsearch.utils.IndexNameProvider;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Integration tests to check that {@link org.springframework.data.elasticsearch.annotations.ValueConverter} annotated
|
||||
* properties are handle correctly (method name derived queries, for
|
||||
*
|
||||
* @{@link org.springframework.data.elasticsearch.core.query.Query} methods we don't know which parameters map to which
|
||||
* property.
|
||||
* @author Peter-Josef Meisch
|
||||
*/
|
||||
@SpringIntegrationTest
|
||||
abstract class ValueConverterIntegrationTests {
|
||||
|
||||
@Autowired private EntityRepository repository;
|
||||
@Autowired ElasticsearchOperations operations;
|
||||
@Autowired IndexNameProvider indexNameProvider;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
indexNameProvider.increment();
|
||||
operations.indexOps(Entity.class).createWithMapping();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(Integer.MAX_VALUE)
|
||||
void cleanup() {
|
||||
operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete();
|
||||
}
|
||||
|
||||
@Test // #2338
|
||||
@DisplayName("should apply ValueConverter")
|
||||
void shouldApplyValueConverter() {
|
||||
|
||||
Entity entity = new Entity();
|
||||
entity.setId("42");
|
||||
entity.setText("answer");
|
||||
operations.save(entity);
|
||||
|
||||
SearchHits<Entity> searchHits = repository.queryByText("text-answer");
|
||||
assertThat(searchHits.getTotalHits()).isEqualTo(1);
|
||||
|
||||
searchHits = repository.findByText("answer");
|
||||
assertThat(searchHits.getTotalHits()).isEqualTo(1);
|
||||
}
|
||||
|
||||
interface EntityRepository extends ElasticsearchRepository<Entity, String> {
|
||||
SearchHits<Entity> findByText(String text);
|
||||
|
||||
@Query("{ \"term\": { \"text\": \"?0\" } }")
|
||||
SearchHits<Entity> queryByText(String text);
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
static class Entity {
|
||||
@Id
|
||||
@Nullable private String id;
|
||||
|
||||
@Field(type = FieldType.Keyword)
|
||||
@ValueConverter(TextConverter.class)
|
||||
@Nullable private String text;
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(@Nullable String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setText(@Nullable String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
static class TextConverter implements PropertyValueConverter {
|
||||
|
||||
public static final String PREFIX = "text-";
|
||||
|
||||
@Override
|
||||
public Object write(Object value) {
|
||||
return PREFIX + value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object read(Object value) {
|
||||
|
||||
String valueString = value.toString();
|
||||
|
||||
if (valueString.startsWith(PREFIX)) {
|
||||
return valueString.substring(PREFIX.length());
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
#
|
||||
sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
|
||||
sde.testcontainers.image-version=7.17.4
|
||||
sde.testcontainers.image-version=7.17.7
|
||||
#
|
||||
#
|
||||
# needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13
|
||||
|
||||
Reference in New Issue
Block a user