|
case ENDING_WITH: |
|
case LIKE: |
|
case NOT_LIKE: |
|
return fromLikeVariant(type, ignoreCase, property, iterator); |
|
case TRUE: |
|
case FALSE: |
|
return fromBooleanVariant(type, property); |
|
case SIMPLE_PROPERTY: |
|
case NEGATING_SIMPLE_PROPERTY: |
|
return fromEqualityVariant(type, ignoreCase, property, iterator); |
|
case REGEX: |
|
return Predicates.regex(property, iterator.next().toString()); |
|
case IS_EMPTY: |
|
case IS_NOT_EMPTY: |
|
return fromEmptyVariant(type, property); |
|
/* case EXISTS:*/ |
|
case NEAR: |
|
case WITHIN: |
|
return fromGeoVariant(type, property, iterator); |
|
|
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Unsupported type '%s'", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromBooleanVariant(Type type, String property) { |
|
switch (type) { |
|
case TRUE: |
|
return Predicates.equal(property, true); |
|
case FALSE: |
|
return Predicates.equal(property, false); |
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromCollectionVariant(Type type, String property, Iterator<Comparable<?>> iterator) { |
|
switch (type) { |
|
case IN: |
|
return Predicates.in(property, collectToArray(type, iterator)); |
|
case NOT_IN: |
|
return Predicates.not(Predicates.in(property, collectToArray(type, iterator))); |
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromInequalityVariant(Type type, String property, Iterator<Comparable<?>> iterator) { |
|
switch (type) { |
|
case AFTER: |
|
case GREATER_THAN: |
|
return Predicates.greaterThan(property, iterator.next()); |
|
case GREATER_THAN_EQUAL: |
|
return Predicates.greaterEqual(property, iterator.next()); |
|
case BEFORE: |
|
case LESS_THAN: |
|
return Predicates.lessThan(property, iterator.next()); |
|
case LESS_THAN_EQUAL: |
|
return Predicates.lessEqual(property, iterator.next()); |
|
case BETWEEN: |
|
Comparable<?> first = iterator.next(); |
|
Comparable<?> second = iterator.next(); |
|
return Predicates.between(property, first, second); |
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromNullVariant(Type type, String property) { |
|
switch (type) { |
|
case IS_NULL: |
|
return Predicates.equal(property, null); |
|
case IS_NOT_NULL: |
|
return Predicates.notEqual(property, null); |
|
|
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromEqualityVariant(Type type, boolean ignoreCase, String property, |
|
Iterator<Comparable<?>> iterator) { |
|
switch (type) { |
|
case SIMPLE_PROPERTY: |
|
if (ignoreCase) { |
|
return Predicates.ilike(property, iterator.next().toString()); |
|
} else { |
|
return Predicates.equal(property, iterator.next()); |
|
} |
|
case NEGATING_SIMPLE_PROPERTY: |
|
if (ignoreCase) { |
|
return Predicates.not(Predicates.ilike(property, iterator.next().toString())); |
|
} else { |
|
return Predicates.notEqual(property, iterator.next()); |
|
} |
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromLikeVariant(Type type, boolean ignoreCase, String property, Iterator<Comparable<?>> iterator) { |
|
String likeExpression = iterator.next().toString(); |
|
switch (type) { |
|
case CONTAINING: |
|
case NOT_CONTAINING: |
|
likeExpression = String.join("", "%", likeExpression, "%"); |
|
break; |
|
case STARTING_WITH: |
|
likeExpression = String.join("", likeExpression, "%"); |
|
break; |
|
case ENDING_WITH: |
|
likeExpression = String.join("", "%", likeExpression); |
|
break; |
|
case LIKE: |
|
case NOT_LIKE: |
|
break; |
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("'%s' is not supported for LIKE style query", type)); |
|
} |
|
|
|
Predicate likePredicate = ignoreCase ? Predicates.ilike(property, likeExpression) : Predicates |
|
.like(property, likeExpression); |
|
return type.equals(NOT_LIKE) || type.equals(NOT_CONTAINING) ? Predicates.not(likePredicate) : likePredicate; |
|
} |
|
|
|
private boolean ifIgnoreCase(Part part) { |
|
switch (part.shouldIgnoreCase()) { |
|
case ALWAYS: |
|
Assert.state(canUpperCase(part.getProperty()), |
|
String.format("Unable to ignore case of %s types, the property '%s' must reference a String", |
|
part.getProperty().getType().getName(), part.getProperty().getSegment())); |
|
return true; |
|
case WHEN_POSSIBLE: |
|
return canUpperCase(part.getProperty()); |
|
case NEVER: |
|
default: |
|
return false; |
|
} |
|
} |
|
|
|
private boolean canUpperCase(PropertyPath path) { |
|
return String.class.equals(path.getType()); |
|
} |
|
|
|
private boolean isCollection(Object item) { |
|
return Collection.class.isAssignableFrom(item.getClass()); |
|
} |
|
|
|
private Comparable<?>[] collectToArray(Type type, Iterator<Comparable<?>> iterator) { |
|
Object item = iterator.next(); |
|
Assert.state(isCollection(item), String.format("%s requires collection of values", type)); |
|
Collection<Comparable<?>> itemcol = (Collection<Comparable<?>>) item; |
|
return itemcol.toArray(new Comparable<?>[0]); |
|
} |
|
|
|
private Predicate<?, ?> fromEmptyVariant(Type type, String property) { |
|
switch (type) { |
|
case IS_EMPTY: |
|
return Predicates.equal(property, ""); |
|
case IS_NOT_EMPTY: |
|
return Predicates.notEqual(property, ""); |
|
|
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
|
|
|
private Predicate<?, ?> fromGeoVariant(Type type, String property, Iterator<Comparable<?>> iterator) { |
|
final Object item = iterator.next(); |
|
Point point; |
|
Distance distance; |
|
if (item instanceof Point) { |
|
point = (Point) item; |
|
if (!iterator.hasNext()) { |
|
throw new InvalidDataAccessApiUsageException( |
|
"Expected to find distance value for geo query. Are you missing a parameter?"); |
|
} |
|
|
|
Object distObject = iterator.next(); |
|
if (distObject instanceof Distance) { |
|
distance = (Distance) distObject; |
|
} else if (distObject instanceof Number) { |
|
distance = new Distance(((Number) distObject).doubleValue(), Metrics.KILOMETERS); |
|
} else { |
|
throw new InvalidDataAccessApiUsageException(String |
|
.format("Expected to find Distance or Numeric value for geo query but was %s.", |
|
distObject.getClass())); |
|
} |
|
} else if (item instanceof Circle) { |
|
point = ((Circle) item).getCenter(); |
|
distance = ((Circle) item).getRadius(); |
|
} else { |
|
throw new InvalidDataAccessApiUsageException( |
|
String.format("Expected to find a Circle or Point/Distance for geo query but was %s.", item.getClass())); |
|
} |
|
|
|
switch (type) { |
|
case WITHIN: |
|
case NEAR: |
|
return new GeoPredicate<>(property, point, distance); |
|
|
|
default: |
|
throw new InvalidDataAccessApiUsageException(String.format("Logic error for '%s' in query", type)); |
|
} |
|
} |
Once SQL support is production-ready, we should remove our custom querying infrastructure and reuse what's already in Hazelcast
spring-data-hazelcast/src/main/java/org/springframework/data/hazelcast/repository/query/HazelcastQueryCreator.java
Lines 171 to 375 in 3db5278