Skip to content

Commit

Permalink
Implement SourceFilters annotation.
Browse files Browse the repository at this point in the history
Original Pull Request #2254
Closes #1280
Closes #2062
Closes #2146
Closes #2147
Closes #2151
  • Loading branch information
sothawo committed Aug 6, 2022
1 parent 954d8b0 commit cf135f4
Show file tree
Hide file tree
Showing 9 changed files with 595 additions and 130 deletions.
Expand Up @@ -15,8 +15,14 @@
*/
package org.springframework.data.elasticsearch.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.data.annotation.QueryAnnotation;
import java.lang.annotation.*;

/**
* Query
Expand All @@ -34,10 +40,18 @@
public @interface Query {

/**
* @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0
* @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0. Alias for query.
*/
@AliasFor("query")
String value() default "";

/**
* @return Elasticsearch query to be used when executing query. May contain placeholders eg. ?0. Alias for value
* @since 5.0
*/
@AliasFor("value")
String query() default "";

/**
* Named Query Named looked up by repository.
*
Expand Down
@@ -0,0 +1,73 @@
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.data.elasticsearch.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* This annotation can be placed on repository methods to define the properties that should be requested from
* Elasticsearch when the method is run.
*
* @author Alexander Torres
* @author Peter-Josef Meisch
* @since 5.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Documented
public @interface SourceFilters {

/**
* Properties to be requested from Elasticsearch to be included in the response. These can be passed in as literals
* like
*
* <pre>
* {@code @SourceFilters(includes = {"property1", "property2"})}
* </pre>
*
* or as a parameterized value
*
* <pre>
* {@code @SourceFilters(includes = "?0")}
* </pre>
*
* when the list of properties is passed as a function parameter.
*/
String[] includes() default "";

/**
* Properties to be requested from Elasticsearch to be excluded in the response. These can be passed in as literals
* like
*
* <pre>
* {@code @SourceFilters(excludes = {"property1", "property2"})}
* </pre>
*
* or as a parameterized value
*
* <pre>
* {@code @SourceFilters(excludes = "?0")}
* </pre>
*
* when the list of properties is passed as a function parameter.
*/
String[] excludes() default "";
}
Expand Up @@ -16,6 +16,9 @@
package org.springframework.data.elasticsearch.repository.query;

import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;

Expand All @@ -31,12 +34,14 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository

protected static final int DEFAULT_STREAM_BATCH_SIZE = 500;
protected ElasticsearchQueryMethod queryMethod;
protected ElasticsearchOperations elasticsearchOperations;
protected final ElasticsearchOperations elasticsearchOperations;
protected final ElasticsearchConverter elasticsearchConverter;

public AbstractElasticsearchRepositoryQuery(ElasticsearchQueryMethod queryMethod,
ElasticsearchOperations elasticsearchOperations) {
this.queryMethod = queryMethod;
this.elasticsearchOperations = elasticsearchOperations;
this.elasticsearchConverter = elasticsearchOperations.getElasticsearchConverter();
}

@Override
Expand All @@ -49,4 +54,19 @@ public QueryMethod getQueryMethod() {
* @since 4.2
*/
public abstract boolean isCountQuery();

protected void prepareQuery(Query query, Class<?> clazz, ParameterAccessor parameterAccessor) {

elasticsearchConverter.updateQuery(query, clazz);

if (queryMethod.hasAnnotatedHighlight()) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
}

var sourceFilter = queryMethod.getSourceFilter(parameterAccessor,
elasticsearchOperations.getElasticsearchConverter());
if (sourceFilter != null) {
query.addSourceFilter(sourceFilter);
}
}
}
Expand Up @@ -27,6 +27,7 @@
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.ByQueryResponse;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.SourceFilter;
import org.springframework.data.elasticsearch.repository.query.ReactiveElasticsearchQueryExecution.ResultProcessingConverter;
import org.springframework.data.elasticsearch.repository.query.ReactiveElasticsearchQueryExecution.ResultProcessingExecution;
import org.springframework.data.mapping.context.MappingContext;
Expand Down Expand Up @@ -88,6 +89,12 @@ private Object execute(ElasticsearchParameterAccessor parameterAccessor) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
}

var sourceFilter = queryMethod.getSourceFilter(parameterAccessor,
elasticsearchOperations.getElasticsearchConverter());
if (sourceFilter != null) {
query.addSourceFilter(sourceFilter);
}

Class<?> targetType = processor.getReturnedType().getTypeToRead();
String indexName = queryMethod.getEntityInformation().getIndexName();
IndexCoordinates index = IndexCoordinates.of(indexName);
Expand Down
Expand Up @@ -23,7 +23,6 @@
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchHitsImpl;
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
Expand All @@ -49,13 +48,11 @@
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery {

private final PartTree tree;
private final ElasticsearchConverter elasticsearchConverter;
private final MappingContext<?, ElasticsearchPersistentProperty> mappingContext;

public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations) {
super(method, elasticsearchOperations);
this.tree = new PartTree(queryMethod.getName(), queryMethod.getResultProcessor().getReturnedType().getDomainType());
this.elasticsearchConverter = elasticsearchOperations.getElasticsearchConverter();
this.mappingContext = elasticsearchConverter.getMappingContext();
}

Expand All @@ -66,18 +63,16 @@ public boolean isCountQuery() {

@Override
public Object execute(Object[] parameters) {

Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType();
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(queryMethod.getParameters(),
parameters);

CriteriaQuery query = createQuery(accessor);
CriteriaQuery query = createQuery(parameterAccessor);

Assert.notNull(query, "unsupported query");

elasticsearchConverter.updateQuery(query, clazz);

if (queryMethod.hasAnnotatedHighlight()) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
}
prepareQuery(query, clazz, parameterAccessor);

IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);

Expand All @@ -89,27 +84,27 @@ public Object execute(Object[] parameters) {
}

if (tree.isDelete()) {
result = countOrGetDocumentsForDelete(query, accessor);
result = countOrGetDocumentsForDelete(query, parameterAccessor);
elasticsearchOperations.delete(query, clazz, index);
elasticsearchOperations.indexOps(index).refresh();
} else if (queryMethod.isPageQuery()) {
query.setPageable(accessor.getPageable());
query.setPageable(parameterAccessor.getPageable());
SearchHits<?> searchHits = elasticsearchOperations.search(query, clazz, index);
if (queryMethod.isSearchPageMethod()) {
result = SearchHitSupport.searchPageFor(searchHits, query.getPageable());
} else {
result = SearchHitSupport.unwrapSearchHits(SearchHitSupport.searchPageFor(searchHits, query.getPageable()));
}
} else if (queryMethod.isStreamQuery()) {
if (accessor.getPageable().isUnpaged()) {
if (parameterAccessor.getPageable().isUnpaged()) {
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
} else {
query.setPageable(accessor.getPageable());
query.setPageable(parameterAccessor.getPageable());
}
result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(query, clazz, index));
} else if (queryMethod.isCollectionQuery()) {

if (accessor.getPageable().isUnpaged()) {
if (parameterAccessor.getPageable().isUnpaged()) {
int itemCount = (int) elasticsearchOperations.count(query, clazz, index);

if (itemCount == 0) {
Expand All @@ -119,7 +114,7 @@ public Object execute(Object[] parameters) {
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
}
} else {
query.setPageable(accessor.getPageable());
query.setPageable(parameterAccessor.getPageable());
}

if (result == null) {
Expand Down

0 comments on commit cf135f4

Please sign in to comment.