// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/AndNode.java
// public final class AndNode extends LogicalNode {
// 
//     public AndNode() {}
// 
//     public AndNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public AndNode(LogicalNode parent, List<AbstractNode> children) {
//         super(parent, children);
//     }
// 
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/ComparisonNode.java
// public final class ComparisonNode extends AbstractNode {
// 
//     private FieldPath path;
//     private ComparisonOperator operator;
//     private Collection<?> values;
// 
//     public ComparisonNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public FieldPath getField() {
//         return path;
//     }
// 
//     public void setField(FieldPath field) {
//         this.path = field;
//     }
// 
//     public ComparisonOperator getOperator() {
//         return operator;
//     }
// 
//     public void setOperator(ComparisonOperator operator) {
//         this.operator = operator;
//     }
// 
//     public Collection<?> getValues() {
//         return values;
//     }
// 
//     public void setValues(Collection<?> values) {
//         this.values = values;
//     }
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/OrNode.java
// public final class OrNode extends LogicalNode {
// 
//     public OrNode() {}
// 
//     public OrNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public OrNode(LogicalNode parent, List<AbstractNode> children) {
//         super(parent, children);
//     }
// 
// 
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/operators/ComparisonOperator.java
// public final class ComparisonOperator {
// 
//     private String representation;
// 
//     public ComparisonOperator(String representation) {
//         this.representation = representation;
//     }
// 
//     public static final ComparisonOperator EQ = new ComparisonOperator("EQ");
//     public static final ComparisonOperator NE = new ComparisonOperator("NE");
//     public static final ComparisonOperator GT = new ComparisonOperator("GT");
//     public static final ComparisonOperator LT = new ComparisonOperator("LT");
//     public static final ComparisonOperator GTE = new ComparisonOperator("GTE");
//     public static final ComparisonOperator LTE = new ComparisonOperator("LTE");
//     public static final ComparisonOperator IN = new ComparisonOperator("IN");
//     public static final ComparisonOperator NIN = new ComparisonOperator("NIN");
//     public static final ComparisonOperator EX = new ComparisonOperator("EX");
//     public static final ComparisonOperator RE = new ComparisonOperator("RE");
//     public static final ComparisonOperator SUB_CONDITION_ANY = new ComparisonOperator("SUB_CONDITION_ANY");
// 
//     @Override
//     public final boolean equals(Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (o == null || getClass() != o.getClass()) {
//             return false;
//         }
//         ComparisonOperator that = (ComparisonOperator) o;
//         return Objects.equals(representation, that.representation);
//     }
// 
//     @Override
//     public final int hashCode() {
//         return Objects.hash(representation);
//     }
// }


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;
            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<T> doesNotExist(ComparisonNode node) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.isNull(one));
    }

    private Predicate<T> exists(ComparisonNode node) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.nonNull(one));
    }

    private Predicate<T> single(ComparisonNode node, BiPredicate<Object, Object> func) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, func);
    }

    private Predicate<T> multi(ComparisonNode node, BiPredicate<Object, Collection<?>> func) {
        return t -> resolveMultiField(t, node.getField().asKey(), node, func);
    }

// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/AndNode.java
// public final class AndNode extends LogicalNode {
// 
//     public AndNode() {}
// 
//     public AndNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public AndNode(LogicalNode parent, List<AbstractNode> children) {
//         super(parent, children);
//     }
// 
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/ComparisonNode.java
// public final class ComparisonNode extends AbstractNode {
// 
//     private FieldPath path;
//     private ComparisonOperator operator;
//     private Collection<?> values;
// 
//     public ComparisonNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public FieldPath getField() {
//         return path;
//     }
// 
//     public void setField(FieldPath field) {
//         this.path = field;
//     }
// 
//     public ComparisonOperator getOperator() {
//         return operator;
//     }
// 
//     public void setOperator(ComparisonOperator operator) {
//         this.operator = operator;
//     }
// 
//     public Collection<?> getValues() {
//         return values;
//     }
// 
//     public void setValues(Collection<?> values) {
//         this.values = values;
//     }
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/nodes/OrNode.java
// public final class OrNode extends LogicalNode {
// 
//     public OrNode() {}
// 
//     public OrNode(LogicalNode parent) {
//         super(parent);
//     }
// 
//     public OrNode(LogicalNode parent, List<AbstractNode> children) {
//         super(parent, children);
//     }
// 
// 
// }
// 
// Path: src/main/java/com/github/rutledgepaulv/qbuilders/operators/ComparisonOperator.java
// public final class ComparisonOperator {
// 
//     private String representation;
// 
//     public ComparisonOperator(String representation) {
//         this.representation = representation;
//     }
// 
//     public static final ComparisonOperator EQ = new ComparisonOperator("EQ");
//     public static final ComparisonOperator NE = new ComparisonOperator("NE");
//     public static final ComparisonOperator GT = new ComparisonOperator("GT");
//     public static final ComparisonOperator LT = new ComparisonOperator("LT");
//     public static final ComparisonOperator GTE = new ComparisonOperator("GTE");
//     public static final ComparisonOperator LTE = new ComparisonOperator("LTE");
//     public static final ComparisonOperator IN = new ComparisonOperator("IN");
//     public static final ComparisonOperator NIN = new ComparisonOperator("NIN");
//     public static final ComparisonOperator EX = new ComparisonOperator("EX");
//     public static final ComparisonOperator RE = new ComparisonOperator("RE");
//     public static final ComparisonOperator SUB_CONDITION_ANY = new ComparisonOperator("SUB_CONDITION_ANY");
// 
//     @Override
//     public final boolean equals(Object o) {
//         if (this == o) {
//             return true;
//         }
//         if (o == null || getClass() != o.getClass()) {
//             return false;
//         }
//         ComparisonOperator that = (ComparisonOperator) o;
//         return Objects.equals(representation, that.representation);
//     }
// 
//     @Override
//     public final int hashCode() {
//         return Objects.hash(representation);
//     }
// }


// Path: src/main/java/com/github/rutledgepaulv/qbuilders/visitors/PredicateVisitor.java
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;

            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<T> doesNotExist(ComparisonNode node) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.isNull(one));
    }

    private Predicate<T> exists(ComparisonNode node) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, (one, two) -> Objects.nonNull(one));
    }

    private Predicate<T> single(ComparisonNode node, BiPredicate<Object, Object> func) {
        return t -> resolveSingleField(t, node.getField().asKey(), node, func);
    }

    private Predicate<T> multi(ComparisonNode node, BiPredicate<Object, Collection<?>> func) {
        return t -> resolveMultiField(t, node.getField().asKey(), node, func);
    }

    private boolean resolveSingleField(Object root, String field, ComparisonNode node, BiPredicate<Object, Object> func) {