Skip to content

Commit

Permalink
Fix repository methods value converting.
Browse files Browse the repository at this point in the history
Original Pull Request #2339
Closes #2338

(cherry picked from commit e67150a)
  • Loading branch information
sothawo committed Oct 19, 2022
1 parent edac49c commit 933ebab
Show file tree
Hide file tree
Showing 15 changed files with 667 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
Expand Down Expand Up @@ -1156,6 +1157,13 @@ public void updateQuery(Query query, @Nullable Class<?> domainClass) {

Assert.notNull(query, "query must not be null");

if (query instanceof BaseQuery) {

if (((BaseQuery) query).queryIsUpdatedByConverter()) {
return;
}
}

if (domainClass == null) {
return;
}
Expand All @@ -1165,6 +1173,10 @@ public void updateQuery(Query query, @Nullable Class<?> domainClass) {
if (query instanceof CriteriaQuery) {
updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass);
}

if (query instanceof BaseQuery) {
((BaseQuery) query).setQueryIsUpdatedByConverter(true);
}
}

private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public class BaseQuery implements Query {
protected final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected List<IndexBoost> indicesBoost;

private boolean queryIsUpdatedByConverter = false;

public BaseQuery() {}

public <Q extends BaseQuery, B extends BaseQueryBuilder<Q, B>> BaseQuery(BaseQueryBuilder<Q, B> builder) {
Expand Down Expand Up @@ -440,4 +442,23 @@ public List<RuntimeField> getRuntimeFields() {
public List<IndexBoost> getIndicesBoost() {
return indicesBoost;
}

/**
* used internally. Not considered part of the API.
*
* @since 5.0
*/
public boolean queryIsUpdatedByConverter() {
return queryIsUpdatedByConverter;
}

/**
* used internally. Not considered part of the API.
*
* @since 5.0
*/
public void setQueryIsUpdatedByConverter(boolean queryIsUpdatedByConverter) {
this.queryIsUpdatedByConverter = queryIsUpdatedByConverter;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,24 @@
*/
package org.springframework.data.elasticsearch.repository.query;

import java.util.Collections;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchHitsImpl;
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
* AbstractElasticsearchRepositoryQuery
Expand All @@ -32,11 +47,13 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
protected static final int DEFAULT_STREAM_BATCH_SIZE = 500;
protected ElasticsearchQueryMethod queryMethod;
protected ElasticsearchOperations elasticsearchOperations;
protected final ElasticsearchConverter elasticsearchConverter;

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

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

protected abstract boolean isDeleteQuery();

protected abstract boolean isExistsQuery();

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

ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
Class<?> clazz = getResultClass();
Query query = createQuery(parameters);

IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);

Object result = null;

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

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

if (itemCount == 0) {
result = new SearchHitsImpl<>(0, TotalHitsRelation.EQUAL_TO, Float.NaN, null, Collections.emptyList(), null,
null);
} else {
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
}
} else {
query.setPageable(parameterAccessor.getPageable());
}

if (result == null) {
result = elasticsearchOperations.search(query, clazz, index);
}

} else {
result = elasticsearchOperations.searchOne(query, clazz, index);
}

return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod())
? SearchHitSupport.unwrapSearchHits(result)
: result;
}

public Query createQuery(Object[] parameters) {

Class<?> clazz = getResultClass();
ParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
Query query = createQuery(parameterAccessor);

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

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

return query;
}

private Class<?> getResultClass() {
return queryMethod.getResultProcessor().getReturnedType().getDomainType();
}

private ParametersParameterAccessor getParameterAccessor(Object[] parameters) {
return new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
}

@Nullable
private Object countOrGetDocumentsForDelete(Query query, ParametersParameterAccessor accessor) {

Object result = null;
Class<?> entityClass = queryMethod.getEntityInformation().getJavaType();
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(entityClass);

if (queryMethod.isCollectionQuery()) {

if (accessor.getPageable().isUnpaged()) {
int itemCount = (int) elasticsearchOperations.count(query, entityClass, index);
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
} else {
query.setPageable(accessor.getPageable());
}
result = elasticsearchOperations.search(query, entityClass, index);
}

if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
result = elasticsearchOperations.count(query, entityClass, index);
}

return result;
}

protected abstract Query createQuery(ParametersParameterAccessor accessor);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,18 @@
*/
package org.springframework.data.elasticsearch.repository.query;

import java.util.Collections;

import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchHitsImpl;
import org.springframework.data.elasticsearch.core.TotalHitsRelation;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;

/**
* ElasticsearchPartQuery
Expand All @@ -49,13 +41,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 @@ -65,106 +55,24 @@ public boolean isCountQuery() {
}

@Override
public Object execute(Object[] parameters) {
Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType();
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);

CriteriaQuery query = createQuery(accessor);

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

elasticsearchConverter.updateQuery(query, clazz);
protected boolean isDeleteQuery() {
return tree.isDelete();
}

if (queryMethod.hasAnnotatedHighlight()) {
query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery());
}
@Override
protected boolean isExistsQuery() {
return tree.isExistsProjection();
}

IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);
protected Query createQuery(ParametersParameterAccessor accessor) {

Object result = null;
BaseQuery query = new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();

if (tree.isLimiting()) {
// noinspection ConstantConditions
query.setMaxResults(tree.getMaxResults());
}

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

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

if (itemCount == 0) {
result = new SearchHitsImpl<>(0, TotalHitsRelation.EQUAL_TO, Float.NaN, null, Collections.emptyList(), null,
null);
} else {
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
}
} else {
query.setPageable(accessor.getPageable());
}

if (result == null) {
result = elasticsearchOperations.search(query, clazz, index);
}

} else if (tree.isCountProjection()) {
result = elasticsearchOperations.count(query, clazz, index);
} else if (tree.isExistsProjection()) {
long count = elasticsearchOperations.count(query, clazz, index);
result = count > 0;
} else {
result = elasticsearchOperations.searchOne(query, clazz, index);
}

return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod())
? SearchHitSupport.unwrapSearchHits(result)
: result;
}

@Nullable
private Object countOrGetDocumentsForDelete(CriteriaQuery query, ParametersParameterAccessor accessor) {

Object result = null;
Class<?> clazz = queryMethod.getEntityInformation().getJavaType();
IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz);

if (queryMethod.isCollectionQuery()) {

if (accessor.getPageable().isUnpaged()) {
int itemCount = (int) elasticsearchOperations.count(query, clazz, index);
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
} else {
query.setPageable(accessor.getPageable());
}
result = elasticsearchOperations.search(query, clazz, index);
}

if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
result = elasticsearchOperations.count(query, clazz, index);
}
return result;
}

public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
return query;
}
}
Loading

0 comments on commit 933ebab

Please sign in to comment.