mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-06-23 04:22:12 +00:00
Add SpEL support for highlight query and source filter.
Original Pull Request #2853 Closes #2852
This commit is contained in:
parent
96185f94ef
commit
6af099ea34
@ -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.
|
||||
* <p>
|
||||
* Document does not allow {@code null} keys. It allows {@literal null} values.
|
||||
* <p>
|
||||
* 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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<String> 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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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() //
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1740,6 +1740,26 @@ public abstract class CustomMethodRepositoryIntegrationTests {
|
||||
assertThat(highlightXyzHit.getHighlightField("type")).hasSize(1).contains("abc <em>xyz</em>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnDifferentHighlightsOnAnnotatedStringQueryMethodSpEL() {
|
||||
List<SampleEntity> entities = createSampleEntities("abc xyz", 2);
|
||||
repository.saveAll(entities);
|
||||
|
||||
// when
|
||||
SearchHits<SampleEntity> highlightAbcHits = repository.queryByStringWithSeparateHighlightSpEL("abc", "abc");
|
||||
|
||||
assertThat(highlightAbcHits.getTotalHits()).isEqualTo(2);
|
||||
SearchHit<SampleEntity> highlightAbcHit = highlightAbcHits.getSearchHit(0);
|
||||
assertThat(highlightAbcHit.getHighlightField("type")).hasSize(1).contains("<em>abc</em> xyz");
|
||||
|
||||
// when
|
||||
SearchHits<SampleEntity> highlightXyzHits = repository.queryByStringWithSeparateHighlightSpEL("abc", "xyz");
|
||||
|
||||
assertThat(highlightXyzHits.getTotalHits()).isEqualTo(2);
|
||||
SearchHit<SampleEntity> highlightXyzHit = highlightXyzHits.getSearchHit(0);
|
||||
assertThat(highlightXyzHit.getHighlightField("type")).hasSize(1).contains("abc <em>xyz</em>");
|
||||
}
|
||||
|
||||
@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<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
|
||||
|
||||
List<SampleEntity> entities = new ArrayList<>();
|
||||
@ -2276,6 +2340,37 @@ public abstract class CustomMethodRepositoryIntegrationTests {
|
||||
""")))
|
||||
SearchHits<SampleEntity> 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<SampleEntity> queryByStringWithSeparateHighlightSpEL(String type, String highlight);
|
||||
|
||||
List<SearchHit<SampleEntity>> queryByMessage(String message);
|
||||
|
||||
Stream<SearchHit<SampleEntity>> readByMessage(String message);
|
||||
@ -2307,6 +2402,9 @@ public abstract class CustomMethodRepositoryIntegrationTests {
|
||||
@SourceFilters(includes = "?0")
|
||||
SearchHits<SampleEntity> searchBy(Collection<String> sourceIncludes);
|
||||
|
||||
@SourceFilters(includes = "#{#sourceIncludes}")
|
||||
SearchHits<SampleEntity> queryBy(Collection<String> sourceIncludes);
|
||||
|
||||
@Query("""
|
||||
{
|
||||
"match_all": {}
|
||||
@ -2317,6 +2415,9 @@ public abstract class CustomMethodRepositoryIntegrationTests {
|
||||
|
||||
@SourceFilters(excludes = "?0")
|
||||
SearchHits<SampleEntity> findBy(Collection<String> sourceExcludes);
|
||||
|
||||
@SourceFilters(excludes = "#{#sourceExcludes}")
|
||||
SearchHits<SampleEntity> getBy(Collection<String> sourceExcludes);
|
||||
}
|
||||
|
||||
public interface SampleStreamingCustomMethodRepository extends ElasticsearchRepository<SampleEntity, String> {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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<String> hitHighlightField = searchHit.getHighlightField("message");
|
||||
return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("<em>abc</em> xyz");
|
||||
}) //
|
||||
.expectNextCount(2) //
|
||||
.verifyComplete();
|
||||
|
||||
repository.queryByMessageWithSeparateHighlight("abc", "xyz") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextMatches(searchHit -> {
|
||||
List<String> hitHighlightField = searchHit.getHighlightField("message");
|
||||
return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc <em>xyz</em>");
|
||||
}) //
|
||||
.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<String> hitHighlightField = searchHit.getHighlightField("message");
|
||||
return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("<em>abc</em> xyz");
|
||||
}) //
|
||||
.expectNextCount(2) //
|
||||
.verifyComplete();
|
||||
|
||||
repository.queryByMessageWithSeparateHighlightSpEL("abc", "xyz") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNextMatches(searchHit -> {
|
||||
List<String> hitHighlightField = searchHit.getHighlightField("message");
|
||||
return hitHighlightField.size() == 1 && hitHighlightField.get(0).equals("abc <em>xyz</em>");
|
||||
}) //
|
||||
.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<SearchHit<SampleEntity>> queryByMessageWithString(String message);
|
||||
|
||||
@Query("""
|
||||
{
|
||||
"bool":{
|
||||
"must":[
|
||||
{
|
||||
"match":{
|
||||
"message":"?0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""")
|
||||
@Highlight(
|
||||
fields = { @HighlightField(name = "message") },
|
||||
parameters = @HighlightParameters(
|
||||
highlightQuery = @Query("""
|
||||
{
|
||||
"bool":{
|
||||
"must":[
|
||||
{
|
||||
"match":{
|
||||
"message":"?1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
""")))
|
||||
Flux<SearchHit<SampleEntity>> 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<SearchHit<SampleEntity>> queryByMessageWithSeparateHighlightSpEL(String message, String highlight);
|
||||
|
||||
@Query("{ \"bool\" : { \"must\" : { \"term\" : { \"message\" : \"?0\" } } } }")
|
||||
Flux<SampleEntity> findAllViaAnnotatedQueryByMessageLike(String message);
|
||||
|
||||
@ -1083,6 +1246,9 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
|
||||
@SourceFilters(includes = "?0")
|
||||
Flux<SampleEntity> searchBy(Collection<String> sourceIncludes);
|
||||
|
||||
@SourceFilters(includes = "#{#sourceIncludes}")
|
||||
Flux<SampleEntity> queryBy(Collection<String> sourceIncludes);
|
||||
|
||||
@Query("""
|
||||
{
|
||||
"match_all": {}
|
||||
@ -1093,6 +1259,9 @@ abstract class SimpleReactiveElasticsearchRepositoryIntegrationTests {
|
||||
|
||||
@SourceFilters(excludes = "?0")
|
||||
Flux<SampleEntity> findBy(Collection<String> sourceExcludes);
|
||||
|
||||
@SourceFilters(excludes = "#{#sourceExcludes}")
|
||||
Flux<SampleEntity> getBy(Collection<String> sourceExcludes);
|
||||
}
|
||||
|
||||
@Document(indexName = "#{@indexNameProvider.indexName()}")
|
||||
|
Loading…
x
Reference in New Issue
Block a user