Polishing.

This commit is contained in:
Peter-Josef Meisch 2023-12-12 18:58:34 +01:00
parent 1d6a1b0f2f
commit fb9ccf7b44
No known key found for this signature in database
GPG Key ID: DE108246970C7708

View File

@ -15,8 +15,6 @@
*/ */
package org.springframework.data.elasticsearch.repository.query.parser; package org.springframework.data.elasticsearch.repository.query.parser;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.geo.GeoBox; import org.springframework.data.elasticsearch.core.geo.GeoBox;
@ -35,6 +33,9 @@ import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree; import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import java.util.Collection;
import java.util.Iterator;
/** /**
* ElasticsearchQueryCreator * ElasticsearchQueryCreator
* *
@ -47,159 +48,159 @@ import org.springframework.lang.Nullable;
*/ */
public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery, CriteriaQuery> { public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery, CriteriaQuery> {
private final MappingContext<?, ElasticsearchPersistentProperty> context; private final MappingContext<?, ElasticsearchPersistentProperty> context;
public ElasticsearchQueryCreator(PartTree tree, ParameterAccessor parameters, public ElasticsearchQueryCreator(PartTree tree, ParameterAccessor parameters,
MappingContext<?, ElasticsearchPersistentProperty> context) { MappingContext<?, ElasticsearchPersistentProperty> context) {
super(tree, parameters); super(tree, parameters);
this.context = context; this.context = context;
} }
public ElasticsearchQueryCreator(PartTree tree, MappingContext<?, ElasticsearchPersistentProperty> context) { public ElasticsearchQueryCreator(PartTree tree, MappingContext<?, ElasticsearchPersistentProperty> context) {
super(tree); super(tree);
this.context = context; this.context = context;
} }
@Override @Override
protected CriteriaQuery create(Part part, Iterator<Object> iterator) { protected CriteriaQuery create(Part part, Iterator<Object> iterator) {
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath( PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(
part.getProperty()); part.getProperty());
return new CriteriaQuery(from(part, return new CriteriaQuery(from(part,
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.QueryPropertyToFieldNameConverter.INSTANCE)), new Criteria(path.toDotPath(ElasticsearchPersistentProperty.QueryPropertyToFieldNameConverter.INSTANCE)),
iterator)); iterator));
} }
@Override @Override
protected CriteriaQuery and(Part part, CriteriaQuery base, Iterator<Object> iterator) { protected CriteriaQuery and(Part part, CriteriaQuery base, Iterator<Object> iterator) {
if (base == null) { if (base == null) {
return create(part, iterator); return create(part, iterator);
} }
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath( PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(
part.getProperty()); part.getProperty());
return base.addCriteria(from(part, return base.addCriteria(from(part,
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.QueryPropertyToFieldNameConverter.INSTANCE)), new Criteria(path.toDotPath(ElasticsearchPersistentProperty.QueryPropertyToFieldNameConverter.INSTANCE)),
iterator)); iterator));
} }
@Override @Override
protected CriteriaQuery or(CriteriaQuery base, CriteriaQuery query) { protected CriteriaQuery or(CriteriaQuery base, CriteriaQuery query) {
return new CriteriaQuery(base.getCriteria().or(query.getCriteria())); return new CriteriaQuery(base.getCriteria().or(query.getCriteria()));
} }
@Override @Override
protected CriteriaQuery complete(@Nullable CriteriaQuery query, Sort sort) { protected CriteriaQuery complete(@Nullable CriteriaQuery query, Sort sort) {
if (query == null) { if (query == null) {
// this is the case in a findAllByOrderByField method, add empty criteria // this is the case in a findAllByOrderByField method, add empty criteria
query = new CriteriaQuery(new Criteria()); query = new CriteriaQuery(new Criteria());
} }
return query.addSort(sort); return query.addSort(sort);
} }
private Criteria from(Part part, Criteria criteria, Iterator<?> parameters) { private Criteria from(Part part, Criteria criteria, Iterator<?> parameters) {
Part.Type type = part.getType(); Part.Type type = part.getType();
return switch (type) { return switch (type) {
case TRUE -> criteria.is(true); case TRUE -> criteria.is(true);
case FALSE -> criteria.is(false); case FALSE -> criteria.is(false);
case NEGATING_SIMPLE_PROPERTY -> criteria.is(parameters.next()).not(); case NEGATING_SIMPLE_PROPERTY -> criteria.is(parameters.next()).not();
case REGEX -> criteria.expression(parameters.next().toString()); case REGEX -> criteria.expression(parameters.next().toString());
case LIKE, STARTING_WITH -> criteria.startsWith(parameters.next().toString()); case LIKE, STARTING_WITH -> criteria.startsWith(parameters.next().toString());
case ENDING_WITH -> criteria.endsWith(parameters.next().toString()); case ENDING_WITH -> criteria.endsWith(parameters.next().toString());
case CONTAINING -> criteria.contains(parameters.next().toString()); case CONTAINING -> criteria.contains(parameters.next().toString());
case GREATER_THAN -> criteria.greaterThan(parameters.next()); case GREATER_THAN -> criteria.greaterThan(parameters.next());
case AFTER, GREATER_THAN_EQUAL -> criteria.greaterThanEqual(parameters.next()); case AFTER, GREATER_THAN_EQUAL -> criteria.greaterThanEqual(parameters.next());
case LESS_THAN -> criteria.lessThan(parameters.next()); case LESS_THAN -> criteria.lessThan(parameters.next());
case BEFORE, LESS_THAN_EQUAL -> criteria.lessThanEqual(parameters.next()); case BEFORE, LESS_THAN_EQUAL -> criteria.lessThanEqual(parameters.next());
case BETWEEN -> criteria.between(parameters.next(), parameters.next()); case BETWEEN -> criteria.between(parameters.next(), parameters.next());
case IN -> criteria.in(asArray(parameters.next())); case IN -> criteria.in(asArray(parameters.next()));
case NOT_IN -> criteria.notIn(asArray(parameters.next())); case NOT_IN -> criteria.notIn(asArray(parameters.next()));
case SIMPLE_PROPERTY, WITHIN -> this.within(part, criteria, parameters); case SIMPLE_PROPERTY, WITHIN -> within(part, criteria, parameters);
case NEAR -> this.near(criteria, parameters); case NEAR -> near(criteria, parameters);
case EXISTS, IS_NOT_NULL -> criteria.exists(); case EXISTS, IS_NOT_NULL -> criteria.exists();
case IS_NULL -> criteria.not().exists(); case IS_NULL -> criteria.not().exists();
case IS_EMPTY -> criteria.empty(); case IS_EMPTY -> criteria.empty();
case IS_NOT_EMPTY -> criteria.notEmpty(); case IS_NOT_EMPTY -> criteria.notEmpty();
default -> throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'."); default -> throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'.");
}; };
} }
private Criteria within(Part part, Criteria criteria, Iterator<?> parameters) { private Criteria within(Part part, Criteria criteria, Iterator<?> parameters) {
Object firstParameter = parameters.next(); Object firstParameter = parameters.next();
Object secondParameter; Object secondParameter;
if (part.getType() == Part.Type.SIMPLE_PROPERTY) { if (part.getType() == Part.Type.SIMPLE_PROPERTY) {
if (part.getProperty().getType() != GeoPoint.class) { if (part.getProperty().getType() != GeoPoint.class) {
if (firstParameter != null) { if (firstParameter != null) {
return criteria.is(firstParameter); return criteria.is(firstParameter);
} else { } else {
// searching for null is a must_not (exists) // searching for null is a must_not (exists)
return criteria.exists().not(); return criteria.exists().not();
} }
} else { } else {
// it means it's a simple find with exact geopoint matching (e.g. findByLocation) // it means it's a simple find with exact geopoint matching (e.g. findByLocation)
// and because Elasticsearch does not have any kind of query with just a geopoint // and because Elasticsearch does not have any kind of query with just a geopoint
// as argument we use a "geo distance" query with a distance of one meter. // as argument we use a "geo distance" query with a distance of one meter.
secondParameter = ".001km"; secondParameter = ".001km";
} }
} else { } else {
secondParameter = parameters.next(); secondParameter = parameters.next();
} }
return doWithinIfPossible(criteria, firstParameter, secondParameter); return doWithinIfPossible(criteria, firstParameter, secondParameter);
} }
private Criteria near(Criteria criteria, Iterator<?> parameters) { private Criteria near(Criteria criteria, Iterator<?> parameters) {
Object firstParameter = parameters.next(); Object firstParameter = parameters.next();
if (firstParameter instanceof GeoBox geoBox) { if (firstParameter instanceof GeoBox geoBox) {
return criteria.boundedBy(geoBox); return criteria.boundedBy(geoBox);
} }
if (firstParameter instanceof Box box) { if (firstParameter instanceof Box box) {
return criteria.boundedBy(GeoBox.fromBox(box)); return criteria.boundedBy(GeoBox.fromBox(box));
} }
Object secondParameter = parameters.next(); Object secondParameter = parameters.next();
return doWithinIfPossible(criteria, firstParameter, secondParameter); return doWithinIfPossible(criteria, firstParameter, secondParameter);
} }
/** /**
* Do a within query if possible, otherwise return the criteria unchanged. * Do a within query if possible, otherwise return the criteria unchanged.
* *
* @param criteria must not be {@literal null} * @param criteria must not be {@literal null}
* @param firstParameter must not be {@literal null} * @param firstParameter must not be {@literal null}
* @param secondParameter must not be {@literal null} * @param secondParameter must not be {@literal null}
* @return the criteria with the within query applied if possible. * @return the criteria with the within query applied if possible.
* @author Junghoon Ban * @author Junghoon Ban
*/ */
private Criteria doWithinIfPossible(Criteria criteria, Object firstParameter, Object secondParameter) { private Criteria doWithinIfPossible(Criteria criteria, Object firstParameter, Object secondParameter) {
if (firstParameter instanceof GeoPoint geoPoint && secondParameter instanceof String string) { if (firstParameter instanceof GeoPoint geoPoint && secondParameter instanceof String string) {
return criteria.within(geoPoint, string); return criteria.within(geoPoint, string);
} }
if (firstParameter instanceof Point point && secondParameter instanceof Distance distance) { if (firstParameter instanceof Point point && secondParameter instanceof Distance distance) {
return criteria.within(point, distance); return criteria.within(point, distance);
} }
if (firstParameter instanceof String firstString && secondParameter instanceof String secondString) { if (firstParameter instanceof String firstString && secondParameter instanceof String secondString) {
return criteria.within(firstString, secondString); return criteria.within(firstString, secondString);
} }
return criteria; return criteria;
} }
private Object[] asArray(Object o) { private Object[] asArray(Object o) {
if (o instanceof Collection) { if (o instanceof Collection) {
return ((Collection<?>) o).toArray(); return ((Collection<?>) o).toArray();
} else if (o.getClass().isArray()) { } else if (o.getClass().isArray()) {
return (Object[]) o; return (Object[]) o;
} }
return new Object[] { o }; return new Object[]{o};
} }
} }