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.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; | ||||
| @ -1186,6 +1187,13 @@ public class MappingElasticsearchConverter | ||||
| 
 | ||||
| 		Assert.notNull(query, "query must not be null"); | ||||
| 
 | ||||
| 		if (query instanceof BaseQuery) { | ||||
| 
 | ||||
| 			if (((BaseQuery) query).queryIsUpdatedByConverter()) { | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (domainClass == null) { | ||||
| 			return; | ||||
| 		} | ||||
| @ -1195,6 +1203,10 @@ public class MappingElasticsearchConverter | ||||
| 		if (query instanceof CriteriaQuery) { | ||||
| 			updatePropertiesInCriteriaQuery((CriteriaQuery) query, domainClass); | ||||
| 		} | ||||
| 
 | ||||
| 		if (query instanceof BaseQuery) { | ||||
| 			((BaseQuery) query).setQueryIsUpdatedByConverter(true); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private void updatePropertiesInFieldsAndSourceFilter(Query query, Class<?> domainClass) { | ||||
|  | ||||
| @ -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) { | ||||
| @ -466,4 +468,20 @@ public class BaseQuery implements Query { | ||||
| 	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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| @ -55,8 +67,76 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository | ||||
| 	 */ | ||||
| 	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()); | ||||
| @ -68,6 +148,44 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository | ||||
| 			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; | ||||
| 
 | ||||
| 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 | ||||
| @ -62,104 +51,24 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Object execute(Object[] parameters) { | ||||
| 	protected boolean isDeleteQuery() { | ||||
| 		return tree.isDelete(); | ||||
| 	} | ||||
| 
 | ||||
| 		Class<?> clazz = queryMethod.getResultProcessor().getReturnedType().getDomainType(); | ||||
| 		ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(queryMethod.getParameters(), | ||||
| 				parameters); | ||||
| 	@Override | ||||
| 	protected boolean isExistsQuery() { | ||||
| 		return tree.isExistsProjection(); | ||||
| 	} | ||||
| 
 | ||||
| 		CriteriaQuery query = createQuery(parameterAccessor); | ||||
| 	protected Query createQuery(ParametersParameterAccessor accessor) { | ||||
| 
 | ||||
| 		Assert.notNull(query, "unsupported query"); | ||||
| 
 | ||||
| 		prepareQuery(query, clazz, parameterAccessor); | ||||
| 
 | ||||
| 		IndexCoordinates index = elasticsearchOperations.getIndexCoordinatesFor(clazz); | ||||
| 
 | ||||
| 		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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -15,17 +15,11 @@ | ||||
|  */ | ||||
| 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.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.StringQuery; | ||||
| import org.springframework.data.elasticsearch.repository.support.StringQueryUtil; | ||||
| import org.springframework.data.repository.query.ParametersParameterAccessor; | ||||
| import org.springframework.data.util.StreamUtils; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| /** | ||||
| @ -54,56 +48,20 @@ public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQue | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public Object execute(Object[] parameters) { | ||||
| 
 | ||||
| 		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()); | ||||
| 	protected boolean isDeleteQuery() { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 		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); | ||||
| 	@Override | ||||
| 	protected boolean isExistsQuery() { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 		return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod()) | ||||
| 				? SearchHitSupport.unwrapSearchHits(result) | ||||
| 				: result; | ||||
| 	} | ||||
| 	protected Query createQuery(ParametersParameterAccessor parameterAccessor) { | ||||
| 
 | ||||
| 	protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) { | ||||
| 		String queryString = new StringQueryUtil(elasticsearchOperations.getElasticsearchConverter().getConversionService()) | ||||
| 				.replacePlaceholders(this.queryString, parameterAccessor); | ||||
| 
 | ||||
| 		return new StringQuery(queryString); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -61,7 +61,6 @@ final public class StringQueryUtil { | ||||
| 		String parameterValue = "null"; | ||||
| 
 | ||||
| 		if (parameter != null) { | ||||
| 
 | ||||
| 			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.Import; | ||||
| 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.Query; | ||||
| import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; | ||||
| 
 | ||||
| /** | ||||
| @ -36,12 +36,11 @@ public class ElasticsearchPartQueryELCIntegrationTests extends ElasticsearchPart | ||||
| 	static class Config {} | ||||
| 
 | ||||
| 	@Override | ||||
| 	protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) { | ||||
| 	protected String buildQueryString(Query query, Class<?> clazz) { | ||||
| 
 | ||||
| 		JacksonJsonpMapper jsonpMapper = new JacksonJsonpMapper(); | ||||
| 		RequestConverter requestConverter = new RequestConverter(operations.getElasticsearchConverter(), jsonpMapper); | ||||
| 		SearchRequest request = requestConverter.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy"), false, | ||||
| 				false); | ||||
| 		SearchRequest request = requestConverter.searchRequest(query, clazz, IndexCoordinates.of("dummy"), false, false); | ||||
| 
 | ||||
| 		return JsonUtils.toJson(request, 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.Import; | ||||
| 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.Query; | ||||
| import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration; | ||||
| import org.springframework.test.context.ContextConfiguration; | ||||
| 
 | ||||
| @ -38,9 +38,9 @@ public class ElasticsearchPartQueryERHLCIntegrationTests extends ElasticsearchPa | ||||
| 	@Import({ ElasticsearchRestTemplateConfiguration.class }) | ||||
| 	static class Config {} | ||||
| 
 | ||||
| 	protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz) { | ||||
| 	protected String buildQueryString(Query query, Class<?> clazz) { | ||||
| 		SearchSourceBuilder source = new RequestFactory(operations.getElasticsearchConverter()) | ||||
| 				.searchRequest(criteriaQuery, clazz, IndexCoordinates.of("dummy")).source(); | ||||
| 				.searchRequest(query, clazz, IndexCoordinates.of("dummy")).source(); | ||||
| 		// remove defaultboost values | ||||
| 		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.projection.SpelAwareProxyProjectionFactory; | ||||
| import org.springframework.data.repository.core.support.DefaultRepositoryMetadata; | ||||
| import org.springframework.data.repository.query.ParametersParameterAccessor; | ||||
| import org.springframework.lang.Nullable; | ||||
| 
 | ||||
| /** | ||||
| @ -649,19 +648,18 @@ public abstract class ElasticsearchPartQueryIntegrationTests { | ||||
| 				new DefaultRepositoryMetadata(SampleRepository.class), new SpelAwareProxyProjectionFactory(), | ||||
| 				operations.getElasticsearchConverter().getMappingContext()); | ||||
| 		ElasticsearchPartQuery partQuery = new ElasticsearchPartQuery(queryMethod, operations); | ||||
| 		CriteriaQuery criteriaQuery = partQuery | ||||
| 				.createQuery(new ParametersParameterAccessor(queryMethod.getParameters(), parameters)); | ||||
| 		return buildQueryString(criteriaQuery, Book.class); | ||||
| 		Query query = partQuery.createQuery(parameters); | ||||
| 		return buildQueryString(query, Book.class); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * 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 | ||||
| 	 * @return the created query string | ||||
| 	 */ | ||||
| 	abstract protected String buildQueryString(CriteriaQuery criteriaQuery, Class<?> clazz); | ||||
| 	abstract protected String buildQueryString(Query query, Class<?> clazz); | ||||
| 
 | ||||
| 	@FunctionalInterface | ||||
| 	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