mirror of
				https://github.com/spring-projects/spring-data-elasticsearch.git
				synced 2025-10-31 06:38:44 +00:00 
			
		
		
		
	Fix repository methods value converting.
Original Pull Request #2339 Closes #2338
This commit is contained in:
		
							parent
							
								
									f21285d33c
								
							
						
					
					
						commit
						e67150a55b
					
				| @ -41,6 +41,7 @@ import org.springframework.data.elasticsearch.core.document.SearchDocument; | |||||||
| import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; | import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; | ||||||
| import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; | import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; | ||||||
| import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter; | 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.Criteria; | ||||||
| import org.springframework.data.elasticsearch.core.query.CriteriaQuery; | import org.springframework.data.elasticsearch.core.query.CriteriaQuery; | ||||||
| import org.springframework.data.elasticsearch.core.query.FetchSourceFilter; | import org.springframework.data.elasticsearch.core.query.FetchSourceFilter; | ||||||
| @ -1186,6 +1187,13 @@ public class MappingElasticsearchConverter | |||||||
| 
 | 
 | ||||||
| 		Assert.notNull(query, "query must not be null"); | 		Assert.notNull(query, "query must not be null"); | ||||||
| 
 | 
 | ||||||
|  | 		if (query instanceof BaseQuery) { | ||||||
|  | 
 | ||||||
|  | 			if (((BaseQuery) query).queryIsUpdatedByConverter()) { | ||||||
|  | 				return; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		if (domainClass == null) { | 		if (domainClass == null) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| @ -1195,6 +1203,10 @@ public class MappingElasticsearchConverter | |||||||
| 		if (query instanceof CriteriaQuery) { | 		if (query instanceof CriteriaQuery) { | ||||||
| 			updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass); | 			updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (query instanceof BaseQuery) { | ||||||
|  | 			((BaseQuery) query).setQueryIsUpdatedByConverter(true); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) { | 	private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) { | ||||||
|  | |||||||
| @ -74,6 +74,8 @@ public class BaseQuery implements Query { | |||||||
| 	protected final List<RuntimeField> runtimeFields = new ArrayList<>(); | 	protected final List<RuntimeField> runtimeFields = new ArrayList<>(); | ||||||
| 	@Nullable protected PointInTime pointInTime; | 	@Nullable protected PointInTime pointInTime; | ||||||
| 
 | 
 | ||||||
|  | 	private boolean queryIsUpdatedByConverter = false; | ||||||
|  | 
 | ||||||
| 	public BaseQuery() {} | 	public BaseQuery() {} | ||||||
| 
 | 
 | ||||||
| 	public <Q extends BaseQuery, B extends BaseQueryBuilder<Q, B>> BaseQuery(BaseQueryBuilder<Q, B> builder) { | 	public <Q extends BaseQuery, B extends BaseQueryBuilder<Q, B>> BaseQuery(BaseQueryBuilder<Q, B> builder) { | ||||||
| @ -466,4 +468,20 @@ public class BaseQuery implements Query { | |||||||
| 	public void setPointInTime(@Nullable PointInTime pointInTime) { | 	public void setPointInTime(@Nullable PointInTime pointInTime) { | ||||||
| 		this.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; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,12 +15,24 @@ | |||||||
|  */ |  */ | ||||||
| package org.springframework.data.elasticsearch.repository.query; | 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.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.convert.ElasticsearchConverter; | ||||||
|  | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | ||||||
| import org.springframework.data.elasticsearch.core.query.Query; | 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.QueryMethod; | ||||||
| import org.springframework.data.repository.query.RepositoryQuery; | 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 |  * AbstractElasticsearchRepositoryQuery | ||||||
| @ -55,8 +67,76 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository | |||||||
| 	 */ | 	 */ | ||||||
| 	public abstract boolean isCountQuery(); | 	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()) { | 		if (queryMethod.hasAnnotatedHighlight()) { | ||||||
| 			query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery()); | 			query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery()); | ||||||
| @ -68,6 +148,44 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository | |||||||
| 			query.addSourceFilter(sourceFilter); | 			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); | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,25 +15,14 @@ | |||||||
|  */ |  */ | ||||||
| package org.springframework.data.elasticsearch.repository.query; | 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.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.ElasticsearchPersistentProperty; | ||||||
| import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | import org.springframework.data.elasticsearch.core.query.BaseQuery; | ||||||
| import org.springframework.data.elasticsearch.core.query.CriteriaQuery; | import org.springframework.data.elasticsearch.core.query.Query; | ||||||
| import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator; | import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator; | ||||||
| import org.springframework.data.mapping.context.MappingContext; | import org.springframework.data.mapping.context.MappingContext; | ||||||
| import org.springframework.data.repository.query.ParametersParameterAccessor; | import org.springframework.data.repository.query.ParametersParameterAccessor; | ||||||
| import org.springframework.data.repository.query.parser.PartTree; | 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 |  * ElasticsearchPartQuery | ||||||
| @ -62,104 +51,24 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public Object execute(Object[] parameters) { | 	protected boolean isDeleteQuery() { | ||||||
|  | 		return tree.isDelete(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 		Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType(); | 	@Override | ||||||
| 		ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(queryMethod.getParameters(), | 	protected boolean isExistsQuery() { | ||||||
| 				parameters); | 		return tree.isExistsProjection(); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 		CriteriaQuery query = createQuery(parameterAccessor); | 	protected Query createQuery(ParametersParameterAccessor accessor) { | ||||||
| 
 | 
 | ||||||
| 		Assert.notNull(query, "unsupported query"); | 		BaseQuery query = new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery(); | ||||||
| 
 |  | ||||||
| 		prepareQuery(query, clazz, parameterAccessor); |  | ||||||
| 
 |  | ||||||
| 		IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz); |  | ||||||
| 
 |  | ||||||
| 		Object result = null; |  | ||||||
| 
 | 
 | ||||||
| 		if (tree.isLimiting()) { | 		if (tree.isLimiting()) { | ||||||
| 			// noinspection ConstantConditions | 			// noinspection ConstantConditions | ||||||
| 			query.setMaxResults(tree.getMaxResults()); | 			query.setMaxResults(tree.getMaxResults()); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (tree.isDelete()) { | 		return query; | ||||||
| 			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(); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,17 +15,11 @@ | |||||||
|  */ |  */ | ||||||
| package org.springframework.data.elasticsearch.repository.query; | package org.springframework.data.elasticsearch.repository.query; | ||||||
| 
 | 
 | ||||||
| import org.springframework.data.domain.PageRequest; |  | ||||||
| import org.springframework.data.domain.Pageable; |  | ||||||
| import org.springframework.data.elasticsearch.core.ElasticsearchOperations; | 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.mapping.IndexCoordinates; |  | ||||||
| import org.springframework.data.elasticsearch.core.query.Query; | import org.springframework.data.elasticsearch.core.query.Query; | ||||||
| import org.springframework.data.elasticsearch.core.query.StringQuery; | import org.springframework.data.elasticsearch.core.query.StringQuery; | ||||||
| import org.springframework.data.elasticsearch.repository.support.StringQueryUtil; | import org.springframework.data.elasticsearch.repository.support.StringQueryUtil; | ||||||
| import org.springframework.data.repository.query.ParametersParameterAccessor; | import org.springframework.data.repository.query.ParametersParameterAccessor; | ||||||
| import org.springframework.data.util.StreamUtils; |  | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -54,56 +48,20 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	public Object execute(Object[] parameters) { | 	protected boolean isDeleteQuery() { | ||||||
| 
 | 		return false; | ||||||
| 		Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType(); |  | ||||||
| 		ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(queryMethod.getParameters(), |  | ||||||
| 				parameters); |  | ||||||
| 
 |  | ||||||
| 		Query query = createQuery(parameterAccessor); |  | ||||||
| 		Assert.notNull(query, "unsupported query"); |  | ||||||
| 
 |  | ||||||
| 		if (queryMethod.hasAnnotatedHighlight()) { |  | ||||||
| 			query.setHighlightQuery(queryMethod.getAnnotatedHighlightQuery()); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		prepareQuery(query, clazz, parameterAccessor); |  | ||||||
| 
 |  | ||||||
| 		IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz); |  | ||||||
| 
 |  | ||||||
| 		Object result; |  | ||||||
| 
 |  | ||||||
| 		if (isCountQuery()) { |  | ||||||
| 			result = elasticsearchOperations.count(query, clazz, index); |  | ||||||
| 		} 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()) { |  | ||||||
| 			query.setPageable( |  | ||||||
| 					parameterAccessor.getPageable().isPaged() ? parameterAccessor.getPageable() : Pageable.unpaged()); |  | ||||||
| 			result = elasticsearchOperations.search(query, clazz, index); |  | ||||||
| 		} else { |  | ||||||
| 			result = elasticsearchOperations.searchOne(query, clazz, index); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod()) |  | ||||||
| 				? SearchHitSupport.unwrapSearchHits(result) |  | ||||||
| 				: result; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) { | 	@Override | ||||||
|  | 	protected boolean isExistsQuery() { | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protected Query createQuery(ParametersParameterAccessor parameterAccessor) { | ||||||
|  | 
 | ||||||
| 		String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService()) | 		String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService()) | ||||||
| 				.replacePlaceholders(this.queryString, parameterAccessor); | 				.replacePlaceholders(this.queryString, parameterAccessor); | ||||||
|  | 
 | ||||||
| 		return new StringQuery(queryString); | 		return new StringQuery(queryString); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -61,7 +61,6 @@ final public class StringQueryUtil { | |||||||
| 		String parameterValue = "null"; | 		String parameterValue = "null"; | ||||||
| 
 | 
 | ||||||
| 		if (parameter != null) { | 		if (parameter != null) { | ||||||
| 
 |  | ||||||
| 			parameterValue = convert(parameter); | 			parameterValue = convert(parameter); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -21,8 +21,8 @@ import co.elastic.clients.json.jackson.JacksonJsonpMapper; | |||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.context.annotation.Import; | import org.springframework.context.annotation.Import; | ||||||
| import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | ||||||
| import org.springframework.data.elasticsearch.core.query.CriteriaQuery; |  | ||||||
| import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests; | import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests; | ||||||
|  | import org.springframework.data.elasticsearch.core.query.Query; | ||||||
| import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; | import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -36,12 +36,11 @@ public class ElasticsearchPartQueryELCIntegrationTests extends ElasticsearchPart | |||||||
| 	static class Config {} | 	static class Config {} | ||||||
| 
 | 
 | ||||||
| 	@Override | 	@Override | ||||||
| 	protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) { | 	protected String buildQueryString(Query query, Class<?> clazz) { | ||||||
| 
 | 
 | ||||||
| 		JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper(); | 		JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper(); | ||||||
| 		RequestConverter requestConverter = new RequestConverter(operations.getElasticsearchConverter(), jsonpMapper); | 		RequestConverter requestConverter = new RequestConverter(operations.getElasticsearchConverter(), jsonpMapper); | ||||||
| 		SearchRequest request = requestConverter.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy"), false, | 		SearchRequest request = requestConverter.searchRequest(query, clazz, IndexCoordinates.of("dummy"), false, false); | ||||||
| 				false); |  | ||||||
| 
 | 
 | ||||||
| 		return JsonUtils.toJson(request, jsonpMapper); | 		return JsonUtils.toJson(request, jsonpMapper); | ||||||
| 		// return "{\"query\":" + JsonUtils.toJson(request.query(), jsonpMapper) + "}"; | 		// return "{\"query\":" + JsonUtils.toJson(request.query(), jsonpMapper) + "}"; | ||||||
|  | |||||||
| @ -19,8 +19,8 @@ import org.elasticsearch.search.builder.SearchSourceBuilder; | |||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
| import org.springframework.context.annotation.Import; | import org.springframework.context.annotation.Import; | ||||||
| import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | ||||||
| import org.springframework.data.elasticsearch.core.query.CriteriaQuery; |  | ||||||
| import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests; | import org.springframework.data.elasticsearch.core.query.ElasticsearchPartQueryIntegrationTests; | ||||||
|  | import org.springframework.data.elasticsearch.core.query.Query; | ||||||
| import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; | import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; | ||||||
| import org.springframework.test.context.ContextConfiguration; | import org.springframework.test.context.ContextConfiguration; | ||||||
| 
 | 
 | ||||||
| @ -38,9 +38,9 @@ public class ElasticsearchPartQueryERHLCIntegrationTests extends ElasticsearchPa | |||||||
| 	@Import({ ElasticsearchRestTemplateConfiguration.class }) | 	@Import({ ElasticsearchRestTemplateConfiguration.class }) | ||||||
| 	static class Config {} | 	static class Config {} | ||||||
| 
 | 
 | ||||||
| 	protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) { | 	protected String buildQueryString(Query query, Class<?> clazz) { | ||||||
| 		SearchSourceBuilder source = new RequestFactory(operations.getElasticsearchConverter()) | 		SearchSourceBuilder source = new RequestFactory(operations.getElasticsearchConverter()) | ||||||
| 				.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy")).source(); | 				.searchRequest(query, clazz, IndexCoordinates.of("dummy")).source(); | ||||||
| 		// remove defaultboost values | 		// remove defaultboost values | ||||||
| 		return source.toString().replaceAll("(\\^\\d+\\.\\d+)", ""); | 		return source.toString().replaceAll("(\\^\\d+\\.\\d+)", ""); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -36,7 +36,6 @@ import org.springframework.data.elasticsearch.repository.query.ElasticsearchPart | |||||||
| import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod; | import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod; | ||||||
| import org.springframework.data.projection.SpelAwareProxyProjectionFactory; | import org.springframework.data.projection.SpelAwareProxyProjectionFactory; | ||||||
| import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; | import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; | ||||||
| import org.springframework.data.repository.query.ParametersParameterAccessor; |  | ||||||
| import org.springframework.lang.Nullable; | import org.springframework.lang.Nullable; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -649,19 +648,18 @@ public abstract class ElasticsearchPartQueryIntegrationTests { | |||||||
| 				new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(), | 				new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(), | ||||||
| 				operations.getElasticsearchConverter().getMappingContext()); | 				operations.getElasticsearchConverter().getMappingContext()); | ||||||
| 		ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations); | 		ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations); | ||||||
| 		CriteriaQuery criteriaQuery = partQuery | 		Query query = partQuery.createQuery(parameters); | ||||||
| 				.createQuery(new ParametersParameterAccessor(queryMethod.getParameters(), parameters)); | 		return buildQueryString(query, Book.class); | ||||||
| 		return buildQueryString(criteriaQuery, Book.class); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * builds the query String that would be sent to Elasticsearch | 	 * builds the query String that would be sent to Elasticsearch | ||||||
| 	 * | 	 * | ||||||
| 	 * @param criteriaQuery the {@link CriteriaQuery} | 	 * @param query the {@link Query} | ||||||
| 	 * @param clazz the entity class | 	 * @param clazz the entity class | ||||||
| 	 * @return the created query string | 	 * @return the created query string | ||||||
| 	 */ | 	 */ | ||||||
| 	abstract protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz); | 	abstract protected String buildQueryString(Query query, Class<?> clazz); | ||||||
| 
 | 
 | ||||||
| 	@FunctionalInterface | 	@FunctionalInterface | ||||||
| 	interface AssertFunction { | 	interface AssertFunction { | ||||||
|  | |||||||
| @ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchTemplateConfiguration; | ||||||
|  | import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | @ContextConfiguration(classes = { ReactiveValueConverterELCIntegrationTests.Config.class }) | ||||||
|  | public class ReactiveValueConverterELCIntegrationTests extends ReactiveValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Configuration | ||||||
|  | 	@Import({ ReactiveElasticsearchTemplateConfiguration.class }) | ||||||
|  | 	@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true) | ||||||
|  | 	static class Config { | ||||||
|  | 		@Bean | ||||||
|  | 		IndexNameProvider indexNameProvider() { | ||||||
|  | 			return new IndexNameProvider("reactive-valueconverter"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,43 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration; | ||||||
|  | import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | @ContextConfiguration(classes = { ReactiveValueConverterERHLCIntegrationTests.Config.class }) | ||||||
|  | public class ReactiveValueConverterERHLCIntegrationTests extends ReactiveValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Configuration | ||||||
|  | 	@Import({ ReactiveElasticsearchRestTemplateConfiguration.class }) | ||||||
|  | 	@EnableReactiveElasticsearchRepositories(considerNestedRepositories = true) | ||||||
|  | 	static class Config { | ||||||
|  | 		@Bean | ||||||
|  | 		IndexNameProvider indexNameProvider() { | ||||||
|  | 			return new IndexNameProvider("reactive-valueconverter-es7"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,153 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import static org.assertj.core.api.Assertions.*; | ||||||
|  | import static org.springframework.data.elasticsearch.annotations.FieldType.*; | ||||||
|  | 
 | ||||||
|  | import org.springframework.data.elasticsearch.annotations.FieldType; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Query; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.ValueConverter; | ||||||
|  | import org.springframework.data.elasticsearch.core.SearchHits; | ||||||
|  | import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter; | ||||||
|  | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; | ||||||
|  | import reactor.core.publisher.Flux; | ||||||
|  | import reactor.core.publisher.Mono; | ||||||
|  | import reactor.test.StepVerifier; | ||||||
|  | 
 | ||||||
|  | import java.lang.Boolean; | ||||||
|  | 
 | ||||||
|  | import org.junit.jupiter.api.BeforeEach; | ||||||
|  | import org.junit.jupiter.api.DisplayName; | ||||||
|  | import org.junit.jupiter.api.Order; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.data.annotation.Id; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Document; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Field; | ||||||
|  | import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; | ||||||
|  | import org.springframework.data.elasticsearch.core.SearchHit; | ||||||
|  | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; | ||||||
|  | import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.lang.Nullable; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integration tests to check that {@link org.springframework.data.elasticsearch.annotations.ValueConverter} annotated | ||||||
|  |  * properties are handle correctly (method name derived queries, for | ||||||
|  |  * | ||||||
|  |  * @{@link org.springframework.data.elasticsearch.core.query.Query} methods we don't know which parameters map to which | ||||||
|  |  *         property. | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  */ | ||||||
|  | @SpringIntegrationTest | ||||||
|  | public abstract class ReactiveValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Autowired private IndexNameProvider indexNameProvider; | ||||||
|  | 	@Autowired private ReactiveElasticsearchOperations operations; | ||||||
|  | 	@Autowired private EntityRepository repository; | ||||||
|  | 
 | ||||||
|  | 	@BeforeEach | ||||||
|  | 	void setUp() { | ||||||
|  | 		indexNameProvider.increment(); | ||||||
|  | 		operations.indexOps(Entity.class).createWithMapping().block(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	@Order(java.lang.Integer.MAX_VALUE) | ||||||
|  | 	void cleanup() { | ||||||
|  | 		operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete().block(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	@Test // #2338 | ||||||
|  | 	@DisplayName("should apply ValueConverter") | ||||||
|  | 	void shouldApplyValueConverter() { | ||||||
|  | 
 | ||||||
|  | 		ValueConverterIntegrationTests.Entity entity = new ValueConverterIntegrationTests.Entity(); | ||||||
|  | 		entity.setId("42"); | ||||||
|  | 		entity.setText("answer"); | ||||||
|  | 		operations.save(entity).block(); | ||||||
|  | 
 | ||||||
|  | 		repository.queryByText("text-answer") // | ||||||
|  | 			.as(StepVerifier::create) // | ||||||
|  | 			.expectNextCount(1) // | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 
 | ||||||
|  | 		repository.findByText("answer") // | ||||||
|  | 			.as(StepVerifier::create) // | ||||||
|  | 			.expectNextCount(1) // | ||||||
|  | 			.verifyComplete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	interface EntityRepository extends ReactiveElasticsearchRepository<Entity, String> { | ||||||
|  | 		Flux<SearchHit<Entity>> findByText(String text); | ||||||
|  | 
 | ||||||
|  | 		@Query("{ \"term\": { \"text\": \"?0\" } }") | ||||||
|  | 		Flux<SearchHit<Entity>> queryByText(String text); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Document(indexName = "#{@indexNameProvider.indexName()}") | ||||||
|  | 	static class Entity { | ||||||
|  | 		@Id | ||||||
|  | 		@Nullable private String id; | ||||||
|  | 
 | ||||||
|  | 		@Field(type = FieldType.Keyword) | ||||||
|  | 		@ValueConverter(ValueConverterIntegrationTests.TextConverter.class) | ||||||
|  | 		@Nullable private String text; | ||||||
|  | 
 | ||||||
|  | 		@Nullable | ||||||
|  | 		public String getId() { | ||||||
|  | 			return id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public void setId(@Nullable String id) { | ||||||
|  | 			this.id = id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Nullable | ||||||
|  | 		public String getText() { | ||||||
|  | 			return text; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public void setText(@Nullable String text) { | ||||||
|  | 			this.text = text; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static class TextConverter implements PropertyValueConverter { | ||||||
|  | 
 | ||||||
|  | 		public static final String PREFIX = "text-"; | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public Object write(Object value) { | ||||||
|  | 			return PREFIX + value.toString(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public Object read(Object value) { | ||||||
|  | 
 | ||||||
|  | 			String valueString = value.toString(); | ||||||
|  | 
 | ||||||
|  | 			if (valueString.startsWith(PREFIX)) { | ||||||
|  | 				return valueString.substring(PREFIX.length()); | ||||||
|  | 			} else { | ||||||
|  | 				return value; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,44 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; | ||||||
|  | import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * {@link ValueConverterIntegrationTests} using a Repository backed by an ElasticsearchTemplate. | ||||||
|  |  * | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | @ContextConfiguration(classes = { ValueConverterELCIntegrationTests.Config.class }) | ||||||
|  | public class ValueConverterELCIntegrationTests extends ValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Configuration | ||||||
|  | 	@Import({ ElasticsearchTemplateConfiguration.class }) | ||||||
|  | 	@EnableElasticsearchRepositories(considerNestedRepositories = true) | ||||||
|  | 	static class Config { | ||||||
|  | 		@Bean | ||||||
|  | 		IndexNameProvider indexNameProvider() { | ||||||
|  | 			return new IndexNameProvider("valueconverter"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,44 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.context.annotation.Configuration; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; | ||||||
|  | import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * {@link ValueConverterIntegrationTests} using a Repository backed by an ElasticsearchTemplate. | ||||||
|  |  * | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  * @since 5.0 | ||||||
|  |  */ | ||||||
|  | @ContextConfiguration(classes = { ValueConverterERHLCIntegrationTests.Config.class }) | ||||||
|  | public class ValueConverterERHLCIntegrationTests extends ValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Configuration | ||||||
|  | 	@Import({ ElasticsearchRestTemplateConfiguration.class }) | ||||||
|  | 	@EnableElasticsearchRepositories(considerNestedRepositories = true) | ||||||
|  | 	static class Config { | ||||||
|  | 		@Bean | ||||||
|  | 		IndexNameProvider indexNameProvider() { | ||||||
|  | 			return new IndexNameProvider("valueconverter-es7"); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -0,0 +1,140 @@ | |||||||
|  | /* | ||||||
|  |  * 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.repository.query.valueconverter; | ||||||
|  | 
 | ||||||
|  | import static org.assertj.core.api.Assertions.*; | ||||||
|  | 
 | ||||||
|  | import org.junit.jupiter.api.BeforeEach; | ||||||
|  | import org.junit.jupiter.api.DisplayName; | ||||||
|  | import org.junit.jupiter.api.Order; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.data.annotation.Id; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Document; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Field; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.FieldType; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.Query; | ||||||
|  | import org.springframework.data.elasticsearch.annotations.ValueConverter; | ||||||
|  | import org.springframework.data.elasticsearch.core.ElasticsearchOperations; | ||||||
|  | import org.springframework.data.elasticsearch.core.SearchHits; | ||||||
|  | import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; | ||||||
|  | import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter; | ||||||
|  | import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; | ||||||
|  | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; | ||||||
|  | import org.springframework.data.elasticsearch.utils.IndexNameProvider; | ||||||
|  | import org.springframework.lang.Nullable; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Integration tests to check that {@link org.springframework.data.elasticsearch.annotations.ValueConverter} annotated | ||||||
|  |  * properties are handle correctly (method name derived queries, for | ||||||
|  |  * | ||||||
|  |  * @{@link org.springframework.data.elasticsearch.core.query.Query} methods we don't know which parameters map to which | ||||||
|  |  *         property. | ||||||
|  |  * @author Peter-Josef Meisch | ||||||
|  |  */ | ||||||
|  | @SpringIntegrationTest | ||||||
|  | abstract class ValueConverterIntegrationTests { | ||||||
|  | 
 | ||||||
|  | 	@Autowired private EntityRepository repository; | ||||||
|  | 	@Autowired ElasticsearchOperations operations; | ||||||
|  | 	@Autowired IndexNameProvider indexNameProvider; | ||||||
|  | 
 | ||||||
|  | 	@BeforeEach | ||||||
|  | 	public void before() { | ||||||
|  | 		indexNameProvider.increment(); | ||||||
|  | 		operations.indexOps(Entity.class).createWithMapping(); | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	@Order(Integer.MAX_VALUE) | ||||||
|  | 	void cleanup() { | ||||||
|  | 		operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + '*')).delete(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test // #2338 | ||||||
|  | 	@DisplayName("should apply ValueConverter") | ||||||
|  | 	void shouldApplyValueConverter() { | ||||||
|  | 
 | ||||||
|  | 		Entity entity = new Entity(); | ||||||
|  | 		entity.setId("42"); | ||||||
|  | 		entity.setText("answer"); | ||||||
|  | 		operations.save(entity); | ||||||
|  | 
 | ||||||
|  | 		SearchHits<Entity> searchHits = repository.queryByText("text-answer"); | ||||||
|  | 		assertThat(searchHits.getTotalHits()).isEqualTo(1); | ||||||
|  | 
 | ||||||
|  | 		searchHits = repository.findByText("answer"); | ||||||
|  | 		assertThat(searchHits.getTotalHits()).isEqualTo(1); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	interface EntityRepository extends ElasticsearchRepository<Entity, String> { | ||||||
|  | 		SearchHits<Entity> findByText(String text); | ||||||
|  | 
 | ||||||
|  | 		@Query("{ \"term\": { \"text\": \"?0\" } }") | ||||||
|  | 		SearchHits<Entity> queryByText(String text); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Document(indexName = "#{@indexNameProvider.indexName()}") | ||||||
|  | 	static class Entity { | ||||||
|  | 		@Id | ||||||
|  | 		@Nullable private String id; | ||||||
|  | 
 | ||||||
|  | 		@Field(type = FieldType.Keyword) | ||||||
|  | 		@ValueConverter(TextConverter.class) | ||||||
|  | 		@Nullable private String text; | ||||||
|  | 
 | ||||||
|  | 		@Nullable | ||||||
|  | 		public String getId() { | ||||||
|  | 			return id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public void setId(@Nullable String id) { | ||||||
|  | 			this.id = id; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Nullable | ||||||
|  | 		public String getText() { | ||||||
|  | 			return text; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public void setText(@Nullable String text) { | ||||||
|  | 			this.text = text; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	static class TextConverter implements PropertyValueConverter { | ||||||
|  | 
 | ||||||
|  | 		public static final String PREFIX = "text-"; | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public Object write(Object value) { | ||||||
|  | 			return PREFIX + value.toString(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public Object read(Object value) { | ||||||
|  | 
 | ||||||
|  | 			String valueString = value.toString(); | ||||||
|  | 
 | ||||||
|  | 			if (valueString.startsWith(PREFIX)) { | ||||||
|  | 				return valueString.substring(PREFIX.length()); | ||||||
|  | 			} else { | ||||||
|  | 				return value; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user