Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.rutledgepaulv.qbuilders.visitors.PredicateVisitor Maven / Gradle / Ivy
/*
*
* * com.github.rutledgepaulv.qbuilders.visitors.PredicateVisitor
* * *
* * * Copyright (C) 2016 Paul Rutledge
* * *
* * * This software may be modified and distributed under the terms
* * * of the MIT license. See the LICENSE file for details.
* *
*
*/
package com.github.rutledgepaulv.qbuilders.visitors;
import com.github.rutledgepaulv.qbuilders.nodes.AndNode;
import com.github.rutledgepaulv.qbuilders.nodes.ComparisonNode;
import com.github.rutledgepaulv.qbuilders.nodes.OrNode;
import com.github.rutledgepaulv.qbuilders.operators.ComparisonOperator;
import org.apache.commons.lang3.reflect.FieldUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import static java.util.Arrays.stream;
@SuppressWarnings("WeakerAccess")
public class PredicateVisitor extends AbstractVoidContextNodeVisitor> {
@Override
protected Predicate visit(AndNode node) {
return (t) -> node.getChildren().stream().map(this::visitAny).allMatch(p -> p.test(t));
}
@Override
protected Predicate visit(OrNode node) {
return (t) -> node.getChildren().stream().map(this::visitAny).anyMatch(p -> p.test(t));
}
@Override
protected Predicate visit(ComparisonNode node) {
ComparisonOperator operator = node.getOperator();
if(ComparisonOperator.EQ.equals(operator)) {
return single(node, this::equality);
} else if(ComparisonOperator.NE.equals(operator)) {
return single(node, this::inequality);
} else if (ComparisonOperator.EX.equals(operator)) {
return ((Boolean)node.getValues().iterator().next()) ? exists(node) : doesNotExist(node);
} else if (ComparisonOperator.GT.equals(operator)) {
return single(node, this::greaterThan);
} else if (ComparisonOperator.LT.equals(operator)) {
return single(node, this::lessThan);
} else if (ComparisonOperator.GTE.equals(operator)) {
return single(node, this::greaterThanOrEqualTo);
} else if (ComparisonOperator.LTE.equals(operator)) {
return single(node, this::lessThanOrEqualTo);
} else if (ComparisonOperator.IN.equals(operator)) {
return multi(node, this::in);
} else if (ComparisonOperator.NIN.equals(operator)) {
return multi(node, this::nin);
} else if (ComparisonOperator.RE.equals(operator)) {
return single(node, this::regex);
} else if (ComparisonOperator.SUB_CONDITION_ANY.equals(operator)) {
Predicate test = condition(node);
// subquery condition is ignored because a predicate has already been built.
return single(node, (fieldValue, subQueryCondition) -> this.subquery(fieldValue, test));
}
throw new UnsupportedOperationException("This visitor does not support the operator " + operator + ".");
}
protected boolean subquery(Object actual, Predicate func) {
if (actual != null && actual.getClass().isArray()) {
Object[] values = (Object[]) actual;
return stream(values).anyMatch(func);
} else if (actual != null && Collection.class.isAssignableFrom(actual.getClass())) {
Collection> values = (Collection>) actual;
return values.stream().anyMatch(func);
} else {
throw new IllegalArgumentException("You cannot do a subquery against a single element.");
}
}
protected boolean regex(Object actual, Object query) {
Predicate test;
if (query instanceof String) {
String queryRegex = (String) query;
test = Pattern.compile(queryRegex).asPredicate();
} else {
return false;
}
if (actual.getClass().isArray()) {
String[] values = (String[]) actual;
return Arrays.stream(values).anyMatch(test);
} else if (Collection.class.isAssignableFrom(actual.getClass())) {
Collection values = (Collection) actual;
return values.stream().anyMatch(test);
} else if (actual instanceof String) {
return test.test((String) actual);
}
return false;
}
protected boolean equality(Object actual, Object query) {
if(actual != null && actual.getClass().isArray()) {
Object[] values = (Object[]) actual;
return stream(values).anyMatch(query::equals);
} else if (actual != null && Collection.class.isAssignableFrom(actual.getClass())) {
Collection> values = (Collection>)actual;
return values.stream().anyMatch(query::equals);
} else {
return query.equals(actual);
}
}
protected boolean inequality(Object actual, Object query) {
if(actual != null && actual.getClass().isArray()) {
Object[] values = (Object[]) actual;
return stream(values).noneMatch(query::equals);
} else if (actual != null && Collection.class.isAssignableFrom(actual.getClass())) {
Collection> values = (Collection>)actual;
return values.stream().noneMatch(query::equals);
} else {
return !query.equals(actual);
}
}
protected boolean nin(Object actual, Collection> queries) {
if(actual != null && actual.getClass().isArray()) {
Object[] values = (Object[]) actual;
return stream(values).noneMatch(queries::contains);
} else if (actual != null && Collection.class.isAssignableFrom(actual.getClass())) {
Collection> values = (Collection>)actual;
return values.stream().noneMatch(queries::contains);
} else {
return !queries.contains(actual);
}
}
protected boolean in(Object actual, Collection> queries) {
if(actual != null && actual.getClass().isArray()) {
Object[] values = (Object[]) actual;
return stream(values).anyMatch(queries::contains);
} else if (actual != null && Collection.class.isAssignableFrom(actual.getClass())) {
Collection> values = (Collection>)actual;
return values.stream().anyMatch(queries::contains);
} else {
return queries.contains(actual);
}
}
protected boolean greaterThan(Object actual, Object query) {
if(query instanceof Number && actual instanceof Number) {
return ((Number)actual).doubleValue() > ((Number) query).doubleValue();
} else if (query instanceof String && actual instanceof String) {
return ((String)actual).compareTo((String)query) > 0;
} else {
throw new UnsupportedOperationException("Incompatible types provided.");
}
}
protected boolean greaterThanOrEqualTo(Object actual, Object query) {
if(query instanceof Number && actual instanceof Number) {
return ((Number)actual).doubleValue() >= ((Number) query).doubleValue();
} else if (query instanceof String && actual instanceof String) {
return ((String)actual).compareTo((String)query) >= 0;
} else {
throw new UnsupportedOperationException("Incompatible types provided.");
}
}
protected boolean lessThan(Object actual, Object query) {
if(query instanceof Number && actual instanceof Number) {
return ((Number)actual).doubleValue() < ((Number) query).doubleValue();
} else if (query instanceof String && actual instanceof String) {
return ((String)actual).compareTo((String)query) < 0;
} else {
throw new UnsupportedOperationException("Incompatible types provided.");
}
}
protected boolean lessThanOrEqualTo(Object actual, Object query) {
if(query instanceof Number && actual instanceof Number) {
return ((Number)actual).doubleValue() <= ((Number) query).doubleValue();
} else if (query instanceof String && actual instanceof String) {
return ((String)actual).compareTo((String)query) <= 0;
} else {
throw new UnsupportedOperationException("Incompatible types provided.");
}
}
private Predicate doesNotExist(ComparisonNode node) {
return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.isNull(one));
}
private Predicate exists(ComparisonNode node) {
return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.nonNull(one));
}
private Predicate single(ComparisonNode node, BiPredicate func) {
return t -> resolveSingleField(t, node.getField().asKey(), node, func);
}
private Predicate multi(ComparisonNode node, BiPredicate> func) {
return t -> resolveMultiField(t, node.getField().asKey(), node, func);
}
private boolean resolveSingleField(Object root, String field, ComparisonNode node, BiPredicate func) {
if(root == null || node.getField() == null) {
return func.test(null, node.getValues().iterator().next());
} else {
String[] splitField = field.split("\\.", 2);
Object currentField = getFieldValueFromString(root, splitField[0]);
if(splitField.length == 1) {
return func.test(currentField, node.getValues().iterator().next());
} else {
return recurseSingle(currentField, splitField[1], node, func);
}
}
}
private boolean recurseSingle(Object root, String field, ComparisonNode node, BiPredicate func) {
if(root.getClass().isArray()) {
return Arrays.stream((Object[])root).anyMatch(t -> resolveSingleField(t, field, node, func));
}
if(root instanceof Collection) {
return ((Collection)root).stream().anyMatch(t -> resolveSingleField(t, field, node, func));
}
return resolveSingleField(root, field, node, func);
}
private boolean resolveMultiField(Object root, String field, ComparisonNode node, BiPredicate> func) {
if(root == null || node.getField() == null) {
return func.test(null, node.getValues());
} else {
String[] splitField = field.split("\\.", 2);
Object currentField = getFieldValueFromString(root, splitField[0]);
if(splitField.length == 1) {
return func.test(currentField, node.getValues());
} else {
return recurseMulti(currentField, splitField[1], node, func);
}
}
}
private boolean recurseMulti(Object root, String field, ComparisonNode node, BiPredicate> func) {
if(root.getClass().isArray()) {
return Arrays.stream((Object[])root).anyMatch(t -> resolveMultiField(t, field, node, func));
}
if(root instanceof Collection) {
return ((Collection)root).stream().anyMatch(t -> resolveMultiField(t, field, node, func));
}
return resolveMultiField(root, field, node, func);
}
private Object getFieldValueFromString(Object o, String s) {
if(o == null) {
return null;
}
try {
return FieldUtils.readField(o, s, true);
} catch (IllegalAccessException e) {
return null;
}
}
}