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
  • Loading branch information
sothawo committed Oct 19, 2022
1 parent f21285d commit e67150a
Show file tree
Hide file tree
Showing 15 changed files with 649 additions and 171 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,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 @@ -1186,6 +1187,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 @@ -1195,6 +1203,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 @@ -74,6 +74,8 @@ public class BaseQuery implements Query {
protected final List<RuntimeField> runtimeFields = new ArrayList<>();
@Nullable protected PointInTime pointInTime;

private boolean queryIsUpdatedByConverter = false;

public BaseQuery() {}

public <Q extends BaseQuery, B extends BaseQueryBuilder<Q, B>> BaseQuery(BaseQueryBuilder<Q, B> builder) {
Expand Down Expand Up @@ -466,4 +468,20 @@ public PointInTime getPointInTime() {
public void setPointInTime(@Nullable PointInTime pointInTime) {
this.pointInTime = pointInTime;
}

/**
* 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,12 +15,24 @@
*/
package org.springframework.data.elasticsearch.repository.query;

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.ParameterAccessor;
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;

import java.util.Collections;

/**
* AbstractElasticsearchRepositoryQuery
Expand Down Expand Up @@ -55,8 +67,76 @@ public QueryMethod getQueryMethod() {
*/
public abstract boolean isCountQuery();

protected void prepareQuery(Query query, Class<?> clazz, ParameterAccessor parameterAccessor) {
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,
query.getPointInTime() != null ? query.getPointInTime().id() : 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());
Expand All @@ -68,6 +148,44 @@ protected void prepareQuery(Query query, Class<?> clazz, ParameterAccessor param
query.addSourceFilter(sourceFilter);
}

elasticsearchConverter.updateQuery(query, clazz);
// todo #2338 remove that call, this should be done when the real request is built
// elasticsearchConverter.updateQuery(query, clazz);

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,25 +15,14 @@
*/
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.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 Down Expand Up @@ -62,104 +51,24 @@ public boolean isCountQuery() {
}

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

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

CriteriaQuery query = createQuery(parameterAccessor);

Assert.notNull(query, "unsupported query");
protected boolean isDeleteQuery() {
return tree.isDelete();
}

prepareQuery(query, clazz, parameterAccessor);
@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, parameterAccessor);
elasticsearchOperations.delete(query, clazz, index);
elasticsearchOperations.indexOps(index).refresh();
} 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()) {
if (parameterAccessor.getPageable().isUnpaged()) {
query.setPageable(PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE));
} else {
query.setPageable(parameterAccessor.getPageable());
}
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,
query.getPointInTime() != null ? query.getPointInTime().id() : 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 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 e67150a

Please sign in to comment.