diff --git a/src/main/java/org/springframework/data/elasticsearch/core/document/Document.java b/src/main/java/org/springframework/data/elasticsearch/core/document/Document.java
index d365e9cb2..b1ddccbf8 100644
--- a/src/main/java/org/springframework/data/elasticsearch/core/document/Document.java
+++ b/src/main/java/org/springframework/data/elasticsearch/core/document/Document.java
@@ -30,12 +30,12 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
- * A representation of a Elasticsearch document as extended {@link StringObjectMap Map}. All iterators preserve original
+ * A representation of an Elasticsearch document as extended {@link StringObjectMap Map}. All iterators preserve original
* insertion order.
*
* Document does not allow {@code null} keys. It allows {@literal null} values.
*
- * Implementing classes can bei either mutable or immutable. In case a subclass is immutable, its methods may throw
+ * Implementing classes can be either mutable or immutable. In case a subclass is immutable, its methods may throw
* {@link UnsupportedOperationException} when calling modifying methods.
*
* @author Mark Paluch
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java
index 80848540b..c42e1a034 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java
@@ -25,6 +25,7 @@ import org.springframework.data.elasticsearch.core.query.BaseQuery;
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.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.util.StreamUtils;
@@ -47,12 +48,15 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
protected ElasticsearchQueryMethod queryMethod;
protected final ElasticsearchOperations elasticsearchOperations;
protected final ElasticsearchConverter elasticsearchConverter;
+ protected final QueryMethodEvaluationContextProvider evaluationContextProvider;
public AbstractElasticsearchRepositoryQuery(ElasticsearchQueryMethod queryMethod,
- ElasticsearchOperations elasticsearchOperations) {
+ ElasticsearchOperations elasticsearchOperations,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
this.queryMethod = queryMethod;
this.elasticsearchOperations = elasticsearchOperations;
this.elasticsearchConverter = elasticsearchOperations.getElasticsearchConverter();
+ this.evaluationContextProvider = evaluationContextProvider;
}
@Override
@@ -128,7 +132,8 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
var query = createQuery(parameterAccessor);
Assert.notNull(query, "unsupported query");
- queryMethod.addMethodParameter(query, parameterAccessor, elasticsearchOperations.getElasticsearchConverter());
+ queryMethod.addMethodParameter(query, parameterAccessor, elasticsearchOperations.getElasticsearchConverter(),
+ evaluationContextProvider);
return query;
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractReactiveElasticsearchRepositoryQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractReactiveElasticsearchRepositoryQuery.java
index 02826cbe5..8544b7648 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractReactiveElasticsearchRepositoryQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractReactiveElasticsearchRepositoryQuery.java
@@ -34,6 +34,7 @@ import org.springframework.data.elasticsearch.repository.query.ReactiveElasticse
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.util.Assert;
@@ -50,12 +51,15 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
protected final ReactiveElasticsearchQueryMethod queryMethod;
private final ReactiveElasticsearchOperations elasticsearchOperations;
+ protected final QueryMethodEvaluationContextProvider evaluationContextProvider;
AbstractReactiveElasticsearchRepositoryQuery(ReactiveElasticsearchQueryMethod queryMethod,
- ReactiveElasticsearchOperations elasticsearchOperations) {
+ ReactiveElasticsearchOperations elasticsearchOperations,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
this.queryMethod = queryMethod;
this.elasticsearchOperations = elasticsearchOperations;
+ this.evaluationContextProvider = evaluationContextProvider;
}
/*
@@ -96,7 +100,8 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
var query = createQuery(parameterAccessor);
Assert.notNull(query, "unsupported query");
- queryMethod.addMethodParameter(query, parameterAccessor, elasticsearchOperations.getElasticsearchConverter());
+ queryMethod.addMethodParameter(query, parameterAccessor, elasticsearchOperations.getElasticsearchConverter(),
+ evaluationContextProvider);
String indexName = queryMethod.getEntityInformation().getIndexName();
IndexCoordinates index = IndexCoordinates.of(indexName);
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java
index 3c5303ad8..cee8e00d2 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java
@@ -18,11 +18,9 @@ package org.springframework.data.elasticsearch.repository.query;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
-import org.springframework.data.elasticsearch.core.query.Query;
-import org.springframework.data.elasticsearch.core.query.RuntimeField;
-import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
import org.springframework.data.mapping.context.MappingContext;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.parser.PartTree;
/**
@@ -34,14 +32,16 @@ import org.springframework.data.repository.query.parser.PartTree;
* @author Mark Paluch
* @author Rasmus Faber-Espensen
* @author Peter-Josef Meisch
+ * @author Haibo Liu
*/
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery {
private final PartTree tree;
private final MappingContext, ElasticsearchPersistentProperty> mappingContext;
- public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations) {
- super(method, elasticsearchOperations);
+ public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ super(method, elasticsearchOperations, evaluationContextProvider);
this.tree = new PartTree(queryMethod.getName(), queryMethod.getResultProcessor().getReturnedType().getDomainType());
this.mappingContext = elasticsearchConverter.getMappingContext();
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchQueryMethod.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchQueryMethod.java
index 2f98e8276..64b272d44 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchQueryMethod.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchQueryMethod.java
@@ -24,6 +24,7 @@ import java.util.List;
import java.util.stream.Stream;
import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.core.convert.ConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.Query;
@@ -41,13 +42,13 @@ import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.RuntimeField;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.data.elasticsearch.core.query.SourceFilter;
-import org.springframework.data.elasticsearch.repository.support.StringQueryUtil;
+import org.springframework.data.elasticsearch.repository.support.QueryStringProcessor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.core.RepositoryMetadata;
-import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryMethod;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrapperConverters;
import org.springframework.data.util.TypeInformation;
@@ -146,9 +147,7 @@ public class ElasticsearchQueryMethod extends QueryMethod {
Assert.isTrue(hasAnnotatedHighlight(), "no Highlight annotation present on " + getName());
Assert.notNull(highlightAnnotation, "highlightAnnotation must not be null");
- return new HighlightQuery(
- highlightConverter.convert(highlightAnnotation),
- getDomainClass());
+ return new HighlightQuery(highlightConverter.convert(highlightAnnotation), getDomainClass());
}
/**
@@ -288,42 +287,46 @@ public class ElasticsearchQueryMethod extends QueryMethod {
* @param parameterAccessor the accessor with the query method parameter details
* @param converter {@link ElasticsearchConverter} needed to convert entity property names to the Elasticsearch field
* names and for parameter conversion when the includes or excludes are defined as parameters
+ * @param evaluationContextProvider to provide an evaluation context for SpEL evaluation
* @return source filter with includes and excludes for a query, {@literal null} when no {@link SourceFilters}
* annotation was set on the method.
* @since 5.0
*/
@Nullable
- SourceFilter getSourceFilter(ParameterAccessor parameterAccessor, ElasticsearchConverter converter) {
+ SourceFilter getSourceFilter(ElasticsearchParametersParameterAccessor parameterAccessor,
+ ElasticsearchConverter converter,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
if (sourceFilters == null || (sourceFilters.includes().length == 0 && sourceFilters.excludes().length == 0)) {
return null;
}
- StringQueryUtil stringQueryUtil = new StringQueryUtil(converter.getConversionService());
+ ConversionService conversionService = converter.getConversionService();
FetchSourceFilterBuilder fetchSourceFilterBuilder = new FetchSourceFilterBuilder();
if (sourceFilters.includes().length > 0) {
- fetchSourceFilterBuilder
- .withIncludes(mapParameters(sourceFilters.includes(), parameterAccessor, stringQueryUtil));
+ fetchSourceFilterBuilder.withIncludes(mapParameters(sourceFilters.includes(), parameterAccessor,
+ conversionService, evaluationContextProvider));
}
if (sourceFilters.excludes().length > 0) {
- fetchSourceFilterBuilder
- .withExcludes(mapParameters(sourceFilters.excludes(), parameterAccessor, stringQueryUtil));
+ fetchSourceFilterBuilder.withExcludes(mapParameters(sourceFilters.excludes(), parameterAccessor,
+ conversionService, evaluationContextProvider));
}
return fetchSourceFilterBuilder.build();
}
- private String[] mapParameters(String[] source, ParameterAccessor parameterAccessor,
- StringQueryUtil stringQueryUtil) {
+ private String[] mapParameters(String[] source, ElasticsearchParametersParameterAccessor parameterAccessor,
+ ConversionService conversionService, QueryMethodEvaluationContextProvider evaluationContextProvider) {
List fieldNames = new ArrayList<>();
for (String s : source) {
if (!s.isBlank()) {
- String fieldName = stringQueryUtil.replacePlaceholders(s, parameterAccessor);
+ String fieldName = new QueryStringProcessor(s, this, conversionService, evaluationContextProvider)
+ .createQuery(parameterAccessor);
// this could be "[\"foo\",\"bar\"]", must be split
if (fieldName.startsWith("[") && fieldName.endsWith("]")) {
// noinspection RegExpRedundantEscape
@@ -367,14 +370,16 @@ public class ElasticsearchQueryMethod extends QueryMethod {
}
void addMethodParameter(BaseQuery query, ElasticsearchParametersParameterAccessor parameterAccessor,
- ElasticsearchConverter elasticsearchConverter) {
+ ElasticsearchConverter elasticsearchConverter,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
if (hasAnnotatedHighlight()) {
- query.setHighlightQuery(
- getAnnotatedHighlightQuery(new HighlightConverter(parameterAccessor, elasticsearchConverter)));
+ var highlightQuery = getAnnotatedHighlightQuery(new HighlightConverter(parameterAccessor,
+ elasticsearchConverter.getConversionService(), evaluationContextProvider, this));
+ query.setHighlightQuery(highlightQuery);
}
- var sourceFilter = getSourceFilter(parameterAccessor, elasticsearchConverter);
+ var sourceFilter = getSourceFilter(parameterAccessor, elasticsearchConverter, evaluationContextProvider);
if (sourceFilter != null) {
query.addSourceFilter(sourceFilter);
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQuery.java
index b558dacb4..1ba765a00 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchStringQuery.java
@@ -19,8 +19,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.StringQuery;
-import org.springframework.data.elasticsearch.repository.support.StringQueryUtil;
-import org.springframework.data.elasticsearch.repository.support.spel.QueryStringSpELEvaluator;
+import org.springframework.data.elasticsearch.repository.support.QueryStringProcessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.util.Assert;
@@ -37,17 +36,15 @@ import org.springframework.util.Assert;
public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQuery {
private final String queryString;
- private final QueryMethodEvaluationContextProvider evaluationContextProvider;
public ElasticsearchStringQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations,
String queryString, QueryMethodEvaluationContextProvider evaluationContextProvider) {
- super(queryMethod, elasticsearchOperations);
+ super(queryMethod, elasticsearchOperations, evaluationContextProvider);
Assert.notNull(queryString, "Query cannot be empty");
Assert.notNull(evaluationContextProvider, "ExpressionEvaluationContextProvider must not be null");
this.queryString = queryString;
- this.evaluationContextProvider = evaluationContextProvider;
}
@Override
@@ -66,15 +63,12 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue
}
protected BaseQuery createQuery(ElasticsearchParametersParameterAccessor parameterAccessor) {
-
ConversionService conversionService = elasticsearchOperations.getElasticsearchConverter().getConversionService();
- var replacedString = new StringQueryUtil(conversionService).replacePlaceholders(this.queryString,
- parameterAccessor);
- var evaluator = new QueryStringSpELEvaluator(replacedString, parameterAccessor, queryMethod,
- evaluationContextProvider, conversionService);
- var query = new StringQuery(evaluator.evaluate());
- query.addSort(parameterAccessor.getSort());
- return query;
+ var processed = new QueryStringProcessor(queryString, queryMethod, conversionService, evaluationContextProvider)
+ .createQuery(parameterAccessor);
+
+ return new StringQuery(processed)
+ .addSort(parameterAccessor.getSort());
}
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/HighlightConverter.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/HighlightConverter.java
index 6486607aa..8e74b0a30 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/HighlightConverter.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/HighlightConverter.java
@@ -18,13 +18,15 @@ package org.springframework.data.elasticsearch.repository.query;
import java.util.Arrays;
import java.util.List;
-import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
+import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightField;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightParameters;
-import org.springframework.data.elasticsearch.repository.support.StringQueryUtil;
+import org.springframework.data.elasticsearch.repository.support.QueryStringProcessor;
+import org.springframework.data.repository.query.QueryMethod;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.util.Assert;
/**
@@ -35,12 +37,24 @@ import org.springframework.util.Assert;
public class HighlightConverter {
private final ElasticsearchParametersParameterAccessor parameterAccessor;
- private final ElasticsearchConverter elasticsearchConverter;
+ private final ConversionService conversionService;
+ private final QueryMethodEvaluationContextProvider evaluationContextProvider;
+ private final QueryMethod queryMethod;
HighlightConverter(ElasticsearchParametersParameterAccessor parameterAccessor,
- ElasticsearchConverter elasticsearchConverter) {
+ ConversionService conversionService,
+ QueryMethodEvaluationContextProvider evaluationContextProvider,
+ QueryMethod queryMethod) {
+
+ Assert.notNull(parameterAccessor, "parameterAccessor must not be null");
+ Assert.notNull(conversionService, "conversionService must not be null");
+ Assert.notNull(evaluationContextProvider, "evaluationContextProvider must not be null");
+ Assert.notNull(queryMethod, "queryMethod must not be null");
+
this.parameterAccessor = parameterAccessor;
- this.elasticsearchConverter = elasticsearchConverter;
+ this.conversionService = conversionService;
+ this.evaluationContextProvider = evaluationContextProvider;
+ this.queryMethod = queryMethod;
}
/**
@@ -58,10 +72,10 @@ public class HighlightConverter {
// replace placeholders in highlight query with actual parameters
Query highlightQuery = null;
if (!parameters.highlightQuery().value().isEmpty()) {
- String rawString = parameters.highlightQuery().value();
- String queryString = new StringQueryUtil(elasticsearchConverter.getConversionService())
- .replacePlaceholders(rawString, parameterAccessor);
- highlightQuery = new StringQuery(queryString);
+ String rawQuery = parameters.highlightQuery().value();
+ String query = new QueryStringProcessor(rawQuery, queryMethod, conversionService, evaluationContextProvider)
+ .createQuery(parameterAccessor);
+ highlightQuery = new StringQuery(query);
}
HighlightParameters highlightParameters = HighlightParameters.builder() //
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQuery.java
index 368577c47..c15b4dfb2 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQuery.java
@@ -19,10 +19,8 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.StringQuery;
-import org.springframework.data.elasticsearch.repository.support.StringQueryUtil;
-import org.springframework.data.elasticsearch.repository.support.spel.QueryStringSpELEvaluator;
+import org.springframework.data.elasticsearch.repository.support.QueryStringProcessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
/**
@@ -37,16 +35,14 @@ public class ReactiveElasticsearchStringQuery extends AbstractReactiveElasticsea
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
public ReactiveElasticsearchStringQuery(ReactiveElasticsearchQueryMethod queryMethod,
- ReactiveElasticsearchOperations operations, SpelExpressionParser expressionParser,
- QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ ReactiveElasticsearchOperations operations, QueryMethodEvaluationContextProvider evaluationContextProvider) {
- this(queryMethod.getAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider);
+ this(queryMethod.getAnnotatedQuery(), queryMethod, operations, evaluationContextProvider);
}
public ReactiveElasticsearchStringQuery(String query, ReactiveElasticsearchQueryMethod queryMethod,
- ReactiveElasticsearchOperations operations, SpelExpressionParser expressionParser,
- QueryMethodEvaluationContextProvider evaluationContextProvider) {
- super(queryMethod, operations);
+ ReactiveElasticsearchOperations operations, QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ super(queryMethod, operations, evaluationContextProvider);
Assert.notNull(query, "query must not be null");
Assert.notNull(evaluationContextProvider, "evaluationContextProvider must not be null");
@@ -57,15 +53,11 @@ public class ReactiveElasticsearchStringQuery extends AbstractReactiveElasticsea
@Override
protected BaseQuery createQuery(ElasticsearchParametersParameterAccessor parameterAccessor) {
- String queryString = new StringQueryUtil(
- getElasticsearchOperations().getElasticsearchConverter().getConversionService())
- .replacePlaceholders(this.query, parameterAccessor);
-
ConversionService conversionService = getElasticsearchOperations().getElasticsearchConverter()
.getConversionService();
- QueryStringSpELEvaluator evaluator = new QueryStringSpELEvaluator(queryString, parameterAccessor, queryMethod,
- evaluationContextProvider, conversionService);
- return new StringQuery(evaluator.evaluate());
+ String processed = new QueryStringProcessor(query, queryMethod, conversionService, evaluationContextProvider)
+ .createQuery(parameterAccessor);
+ return new StringQuery(processed);
}
@Override
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactivePartTreeElasticsearchQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactivePartTreeElasticsearchQuery.java
index 1fd7f1308..1da8c29a6 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactivePartTreeElasticsearchQuery.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/ReactivePartTreeElasticsearchQuery.java
@@ -19,12 +19,14 @@ import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperatio
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.parser.PartTree;
/**
* @author Christoph Strobl
* @author Peter-Josef Meisch
+ * @author Haibo Liu
* @since 3.2
*/
public class ReactivePartTreeElasticsearchQuery extends AbstractReactiveElasticsearchRepositoryQuery {
@@ -32,8 +34,9 @@ public class ReactivePartTreeElasticsearchQuery extends AbstractReactiveElastics
private final PartTree tree;
public ReactivePartTreeElasticsearchQuery(ReactiveElasticsearchQueryMethod queryMethod,
- ReactiveElasticsearchOperations elasticsearchOperations) {
- super(queryMethod, elasticsearchOperations);
+ ReactiveElasticsearchOperations elasticsearchOperations,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
+ super(queryMethod, elasticsearchOperations, evaluationContextProvider);
ResultProcessor processor = queryMethod.getResultProcessor();
this.tree = new PartTree(queryMethod.getName(), processor.getReturnedType().getDomainType());
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java
index 698183a43..b7c5f29ec 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchRepositoryFactory.java
@@ -128,7 +128,7 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
return new ElasticsearchStringQuery(queryMethod, elasticsearchOperations, queryMethod.getAnnotatedQuery(),
evaluationContextProvider);
}
- return new ElasticsearchPartQuery(queryMethod, elasticsearchOperations);
+ return new ElasticsearchPartQuery(queryMethod, elasticsearchOperations, evaluationContextProvider);
}
}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/StringQueryUtil.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringPlaceholderReplacer.java
similarity index 87%
rename from src/main/java/org/springframework/data/elasticsearch/repository/support/StringQueryUtil.java
rename to src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringPlaceholderReplacer.java
index ff429a26d..7d93623cd 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/support/StringQueryUtil.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringPlaceholderReplacer.java
@@ -26,23 +26,32 @@ import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
/**
+ * To replace the placeholders like `?0`, `?1, `?2` of the query string.
+ *
* @author Peter-Josef Meisch
* @author Niklas Herder
* @author Haibo Liu
*/
-final public class StringQueryUtil {
+final public class QueryStringPlaceholderReplacer {
private static final Pattern PARAMETER_PLACEHOLDER = Pattern.compile("\\?(\\d+)");
private final ConversionService conversionService;
- public StringQueryUtil(ConversionService conversionService) {
+ public QueryStringPlaceholderReplacer(ConversionService conversionService) {
Assert.notNull(conversionService, "conversionService must not be null");
this.conversionService = ElasticsearchQueryValueConversionService.getInstance(conversionService);
}
+ /**
+ * Replace the placeholders of the query string.
+ *
+ * @param input raw query string
+ * @param accessor parameter info
+ * @return a plain string with placeholders replaced
+ */
public String replacePlaceholders(String input, ParameterAccessor accessor) {
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringProcessor.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringProcessor.java
new file mode 100644
index 000000000..8ac45acb7
--- /dev/null
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/QueryStringProcessor.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2024 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.support;
+
+import org.springframework.core.convert.ConversionService;
+import org.springframework.data.elasticsearch.repository.query.ElasticsearchParametersParameterAccessor;
+import org.springframework.data.elasticsearch.repository.support.spel.QueryStringSpELEvaluator;
+import org.springframework.data.repository.query.QueryMethod;
+import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
+import org.springframework.util.Assert;
+
+/**
+ * To process query strings with placeholder replacement and SpEL evaluation by {@link QueryStringPlaceholderReplacer}
+ * and {@link QueryStringSpELEvaluator}.
+ *
+ * @since 5.3
+ * @author Haibo Liu
+ */
+public class QueryStringProcessor {
+
+ private final String query;
+ private final QueryMethod queryMethod;
+ private final ConversionService conversionService;
+ private final QueryMethodEvaluationContextProvider evaluationContextProvider;
+
+ public QueryStringProcessor(String query, QueryMethod queryMethod, ConversionService conversionService,
+ QueryMethodEvaluationContextProvider evaluationContextProvider) {
+
+ Assert.notNull(query, "query must not be null");
+ Assert.notNull(queryMethod, "queryMethod must not be null");
+ Assert.notNull(conversionService, "conversionService must not be null");
+ Assert.notNull(evaluationContextProvider, "evaluationContextProvider must not be null");
+
+ this.query = query;
+ this.queryMethod = queryMethod;
+ this.conversionService = conversionService;
+ this.evaluationContextProvider = evaluationContextProvider;
+ }
+
+ /**
+ * Process the query string with placeholder replacement and SpEL evaluation.
+ *
+ * @param parameterAccessor parameter info
+ * @return processed string
+ */
+ public String createQuery(ElasticsearchParametersParameterAccessor parameterAccessor) {
+ String queryString = new QueryStringPlaceholderReplacer(conversionService)
+ .replacePlaceholders(query, parameterAccessor);
+
+ QueryStringSpELEvaluator evaluator = new QueryStringSpELEvaluator(queryString, parameterAccessor, queryMethod,
+ evaluationContextProvider, conversionService);
+ return evaluator.evaluate();
+ }
+}
diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java
index e3f31093c..d4f65a7aa 100644
--- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java
+++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ReactiveElasticsearchRepositoryFactory.java
@@ -39,7 +39,6 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
import org.springframework.data.repository.query.RepositoryQuery;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -50,12 +49,11 @@ import org.springframework.util.Assert;
* @author Christoph Strobl
* @author Ivan Greene
* @author Ezequiel AntĂșnez Camacho
+ * @author Haibo Liu
* @since 3.2
*/
public class ReactiveElasticsearchRepositoryFactory extends ReactiveRepositoryFactorySupport {
- private static final SpelExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
-
private final ReactiveElasticsearchOperations operations;
private final MappingContext extends ElasticsearchPersistentEntity>, ElasticsearchPersistentProperty> mappingContext;
@@ -163,13 +161,12 @@ public class ReactiveElasticsearchRepositoryFactory extends ReactiveRepositoryFa
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
- return new ReactiveElasticsearchStringQuery(namedQuery, queryMethod, operations, EXPRESSION_PARSER,
+ return new ReactiveElasticsearchStringQuery(namedQuery, queryMethod, operations,
evaluationContextProvider);
} else if (queryMethod.hasAnnotatedQuery()) {
- return new ReactiveElasticsearchStringQuery(queryMethod, operations, EXPRESSION_PARSER,
- evaluationContextProvider);
+ return new ReactiveElasticsearchStringQuery(queryMethod, operations, evaluationContextProvider);
} else {
- return new ReactivePartTreeElasticsearchQuery(queryMethod, operations);
+ return new ReactivePartTreeElasticsearchQuery(queryMethod, operations, evaluationContextProvider);
}
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java
index b41eee474..42ffa5f39 100644
--- a/src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/core/query/ElasticsearchPartQueryIntegrationTests.java
@@ -36,6 +36,7 @@ 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.QueryMethodEvaluationContextProvider;
import org.springframework.lang.Nullable;
/**
@@ -44,6 +45,7 @@ import org.springframework.lang.Nullable;
* kept package private.
*
* @author Peter-Josef Meisch
+ * @author Haibo Liu
*/
@SpringIntegrationTest
public abstract class ElasticsearchPartQueryIntegrationTests {
@@ -647,7 +649,8 @@ public abstract class ElasticsearchPartQueryIntegrationTests {
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method,
new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(),
operations.getElasticsearchConverter().getMappingContext());
- ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations);
+ ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations,
+ QueryMethodEvaluationContextProvider.DEFAULT);
Query query = partQuery.createQuery(parameters);
return buildQueryString(query, Book.class);
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/custommethod/CustomMethodRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/repositories/custommethod/CustomMethodRepositoryIntegrationTests.java
index 078cdb684..730c55116 100644
--- a/src/test/java/org/springframework/data/elasticsearch/repositories/custommethod/CustomMethodRepositoryIntegrationTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/repositories/custommethod/CustomMethodRepositoryIntegrationTests.java
@@ -1740,6 +1740,26 @@ public abstract class CustomMethodRepositoryIntegrationTests {
assertThat(highlightXyzHit.getHighlightField("type")).hasSize(1).contains("abc xyz");
}
+ @Test
+ void shouldReturnDifferentHighlightsOnAnnotatedStringQueryMethodSpEL() {
+ List entities = createSampleEntities("abc xyz", 2);
+ repository.saveAll(entities);
+
+ // when
+ SearchHits highlightAbcHits = repository.queryByStringWithSeparateHighlightSpEL("abc", "abc");
+
+ assertThat(highlightAbcHits.getTotalHits()).isEqualTo(2);
+ SearchHit highlightAbcHit = highlightAbcHits.getSearchHit(0);
+ assertThat(highlightAbcHit.getHighlightField("type")).hasSize(1).contains("abc xyz");
+
+ // when
+ SearchHits highlightXyzHits = repository.queryByStringWithSeparateHighlightSpEL("abc", "xyz");
+
+ assertThat(highlightXyzHits.getTotalHits()).isEqualTo(2);
+ SearchHit highlightXyzHit = highlightXyzHits.getSearchHit(0);
+ assertThat(highlightXyzHit.getHighlightField("type")).hasSize(1).contains("abc xyz");
+ }
+
@Test // DATAES-734
void shouldUseGeoSortParameter() {
GeoPoint munich = new GeoPoint(48.137154, 11.5761247);
@@ -1938,6 +1958,28 @@ public abstract class CustomMethodRepositoryIntegrationTests {
assertThat(foundEntity.getKeyword()).isNull();
}
+ @Test
+ @DisplayName("should use sourceIncludes from parameter SpEL")
+ void shouldUseSourceIncludesFromParameterSpEL() {
+
+ SampleEntity entity = new SampleEntity();
+ entity.setId("42");
+ entity.setMessage("message");
+ entity.setCustomFieldNameMessage("customFieldNameMessage");
+ entity.setType("type");
+ entity.setKeyword("keyword");
+ repository.save(entity);
+
+ var searchHits = repository.queryBy(List.of("message", "customFieldNameMessage"));
+
+ assertThat(searchHits.hasSearchHits()).isTrue();
+ var foundEntity = searchHits.getSearchHit(0).getContent();
+ assertThat(foundEntity.getMessage()).isEqualTo("message");
+ assertThat(foundEntity.getCustomFieldNameMessage()).isEqualTo("customFieldNameMessage");
+ assertThat(foundEntity.getType()).isNull();
+ assertThat(foundEntity.getKeyword()).isNull();
+ }
+
@Test // #2146
@DisplayName("should use sourceExcludes from annotation")
void shouldUseSourceExcludesFromAnnotation() {
@@ -1982,6 +2024,28 @@ public abstract class CustomMethodRepositoryIntegrationTests {
assertThat(foundEntity.getKeyword()).isNull();
}
+ @Test
+ @DisplayName("should use source excludes from parameter SpEL")
+ void shouldUseSourceExcludesFromParameterSpEL() {
+
+ SampleEntity entity = new SampleEntity();
+ entity.setId("42");
+ entity.setMessage("message");
+ entity.setCustomFieldNameMessage("customFieldNameMessage");
+ entity.setType("type");
+ entity.setKeyword("keyword");
+ repository.save(entity);
+
+ var searchHits = repository.getBy(List.of("type", "keyword"));
+
+ assertThat(searchHits.hasSearchHits()).isTrue();
+ var foundEntity = searchHits.getSearchHit(0).getContent();
+ assertThat(foundEntity.getMessage()).isEqualTo("message");
+ assertThat(foundEntity.getCustomFieldNameMessage()).isEqualTo("customFieldNameMessage");
+ assertThat(foundEntity.getType()).isNull();
+ assertThat(foundEntity.getKeyword()).isNull();
+ }
+
private List createSampleEntities(String type, int numberOfEntities) {
List entities = new ArrayList<>();
@@ -2276,6 +2340,37 @@ public abstract class CustomMethodRepositoryIntegrationTests {
""")))
SearchHits queryByStringWithSeparateHighlight(String type, String highlight);
+ @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "type":"#{#type}"
+ }
+ }
+ ]
+ }
+ }
+ """)
+ @Highlight(
+ fields = { @HighlightField(name = "type") },
+ parameters = @HighlightParameters(
+ highlightQuery = @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "type":"#{#highlight}"
+ }
+ }
+ ]
+ }
+ }
+ """)))
+ SearchHits queryByStringWithSeparateHighlightSpEL(String type, String highlight);
+
List> queryByMessage(String message);
Stream> readByMessage(String message);
@@ -2307,6 +2402,9 @@ public abstract class CustomMethodRepositoryIntegrationTests {
@SourceFilters(includes = "?0")
SearchHits searchBy(Collection sourceIncludes);
+ @SourceFilters(includes = "#{#sourceIncludes}")
+ SearchHits queryBy(Collection sourceIncludes);
+
@Query("""
{
"match_all": {}
@@ -2317,6 +2415,9 @@ public abstract class CustomMethodRepositoryIntegrationTests {
@SourceFilters(excludes = "?0")
SearchHits findBy(Collection sourceExcludes);
+
+ @SourceFilters(excludes = "#{#sourceExcludes}")
+ SearchHits getBy(Collection sourceExcludes);
}
public interface SampleStreamingCustomMethodRepository extends ElasticsearchRepository {
diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQueryUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQueryUnitTests.java
index e649fe792..e51674ab8 100644
--- a/src/test/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQueryUnitTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/repository/query/ReactiveElasticsearchStringQueryUnitTests.java
@@ -52,7 +52,6 @@ import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
-import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
/**
@@ -63,8 +62,6 @@ import org.springframework.lang.Nullable;
@ExtendWith(MockitoExtension.class)
public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStringQueryUnitTestBase {
- SpelExpressionParser PARSER = new SpelExpressionParser();
-
@Mock ReactiveElasticsearchOperations operations;
@BeforeEach
@@ -377,7 +374,7 @@ public class ReactiveElasticsearchStringQueryUnitTests extends ElasticsearchStri
}
private ReactiveElasticsearchStringQuery queryForMethod(ReactiveElasticsearchQueryMethod queryMethod) {
- return new ReactiveElasticsearchStringQuery(queryMethod, operations, PARSER,
+ return new ReactiveElasticsearchStringQuery(queryMethod, operations,
QueryMethodEvaluationContextProvider.DEFAULT);
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepositoryIntegrationTests.java
index a516d48c6..2ade46a6d 100644
--- a/src/test/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepositoryIntegrationTests.java
+++ b/src/test/java/org/springframework/data/elasticsearch/repository/support/SimpleReactiveElasticsearchRepositoryIntegrationTests.java
@@ -51,6 +51,7 @@ import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.Highlight;
import org.springframework.data.elasticsearch.annotations.HighlightField;
+import org.springframework.data.elasticsearch.annotations.HighlightParameters;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.annotations.SourceFilters;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
@@ -436,6 +437,60 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
.verifyComplete();
}
+ @Test
+ void shouldReturnDifferentHighlightsOnAnnotatedStringQueryMethod() {
+
+ bulkIndex(new SampleEntity("id-one", "abc xyz"), //
+ new SampleEntity("id-two", "abc xyz"), //
+ new SampleEntity("id-three", "abc xyz")) //
+ .block();
+
+ repository.queryByMessageWithSeparateHighlight("abc", "abc") //
+ .as(StepVerifier::create) //
+ .expectNextMatches(searchHit -> {
+ List hitHighlightField = searchHit.getHighlightField("message");
+ return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc xyz");
+ }) //
+ .expectNextCount(2) //
+ .verifyComplete();
+
+ repository.queryByMessageWithSeparateHighlight("abc", "xyz") //
+ .as(StepVerifier::create) //
+ .expectNextMatches(searchHit -> {
+ List hitHighlightField = searchHit.getHighlightField("message");
+ return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc xyz");
+ }) //
+ .expectNextCount(2) //
+ .verifyComplete();
+ }
+
+ @Test
+ void shouldReturnDifferentHighlightsOnAnnotatedStringQueryMethodSpEL() {
+
+ bulkIndex(new SampleEntity("id-one", "abc xyz"), //
+ new SampleEntity("id-two", "abc xyz"), //
+ new SampleEntity("id-three", "abc xyz")) //
+ .block();
+
+ repository.queryByMessageWithSeparateHighlightSpEL("abc", "abc") //
+ .as(StepVerifier::create) //
+ .expectNextMatches(searchHit -> {
+ List hitHighlightField = searchHit.getHighlightField("message");
+ return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc xyz");
+ }) //
+ .expectNextCount(2) //
+ .verifyComplete();
+
+ repository.queryByMessageWithSeparateHighlightSpEL("abc", "xyz") //
+ .as(StepVerifier::create) //
+ .expectNextMatches(searchHit -> {
+ List hitHighlightField = searchHit.getHighlightField("message");
+ return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc xyz");
+ }) //
+ .expectNextCount(2) //
+ .verifyComplete();
+ }
+
@Test // DATAES-519, DATAES-767, DATAES-822
void countShouldErrorWhenIndexDoesNotExist() {
@@ -860,6 +915,29 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
.verifyComplete();
}
+ @Test
+ @DisplayName("should use sourceIncludes from parameter SpEL")
+ void shouldUseSourceIncludesFromParameterSpEL() {
+
+ var entity = new SampleEntity();
+ entity.setId("42");
+ entity.setMessage("message");
+ entity.setCustomFieldNameMessage("customFieldNameMessage");
+ entity.setType("type");
+ entity.setKeyword("keyword");
+ repository.save(entity).block();
+
+ repository.queryBy(List.of("message", "customFieldNameMessage")) //
+ .as(StepVerifier::create) //
+ .consumeNextWith(foundEntity -> { //
+ assertThat(foundEntity.getMessage()).isEqualTo("message"); //
+ assertThat(foundEntity.getCustomFieldNameMessage()).isEqualTo("customFieldNameMessage"); //
+ assertThat(foundEntity.getType()).isNull(); //
+ assertThat(foundEntity.getKeyword()).isNull(); //
+ }) //
+ .verifyComplete();
+ }
+
@Test // #2146
@DisplayName("should use sourceExcludes from annotation")
void shouldUseSourceExcludesFromAnnotation() {
@@ -906,6 +984,29 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
.verifyComplete();
}
+ @Test
+ @DisplayName("should use source excludes from parameter SpEL")
+ void shouldUseSourceExcludesFromParameterSpEL() {
+
+ var entity = new SampleEntity();
+ entity.setId("42");
+ entity.setMessage("message");
+ entity.setCustomFieldNameMessage("customFieldNameMessage");
+ entity.setType("type");
+ entity.setKeyword("keyword");
+ repository.save(entity).block();
+
+ repository.getBy(List.of("type", "keyword")) //
+ .as(StepVerifier::create) //
+ .consumeNextWith(foundEntity -> { //
+ assertThat(foundEntity.getMessage()).isEqualTo("message"); //
+ assertThat(foundEntity.getCustomFieldNameMessage()).isEqualTo("customFieldNameMessage"); //
+ assertThat(foundEntity.getType()).isNull(); //
+ assertThat(foundEntity.getKeyword()).isNull(); //
+ }) //
+ .verifyComplete();
+ }
+
@Test // #2496
@DisplayName("should save data from Flux and return saved data in a flux")
void shouldSaveDataFromFluxAndReturnSavedDataInAFlux() {
@@ -947,6 +1048,68 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
@Highlight(fields = { @HighlightField(name = "message") })
Flux> queryByMessageWithString(String message);
+ @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "message":"?0"
+ }
+ }
+ ]
+ }
+ }
+ """)
+ @Highlight(
+ fields = { @HighlightField(name = "message") },
+ parameters = @HighlightParameters(
+ highlightQuery = @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "message":"?1"
+ }
+ }
+ ]
+ }
+ }
+ """)))
+ Flux> queryByMessageWithSeparateHighlight(String message, String highlight);
+
+ @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "message":"#{#message}"
+ }
+ }
+ ]
+ }
+ }
+ """)
+ @Highlight(
+ fields = { @HighlightField(name = "message") },
+ parameters = @HighlightParameters(
+ highlightQuery = @Query("""
+ {
+ "bool":{
+ "must":[
+ {
+ "match":{
+ "message":"#{#highlight}"
+ }
+ }
+ ]
+ }
+ }
+ """)))
+ Flux> queryByMessageWithSeparateHighlightSpEL(String message, String highlight);
+
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"message\" : \"?0\" } } } }")
Flux findAllViaAnnotatedQueryByMessageLike(String message);
@@ -1083,6 +1246,9 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
@SourceFilters(includes = "?0")
Flux searchBy(Collection sourceIncludes);
+ @SourceFilters(includes = "#{#sourceIncludes}")
+ Flux queryBy(Collection sourceIncludes);
+
@Query("""
{
"match_all": {}
@@ -1093,6 +1259,9 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
@SourceFilters(excludes = "?0")
Flux findBy(Collection sourceExcludes);
+
+ @SourceFilters(excludes = "#{#sourceExcludes}")
+ Flux getBy(Collection sourceExcludes);
}
@Document(indexName = "#{@indexNameProvider.indexName()}")