// Path: rsql-querydsl-parent/rsql-querydsl-filter/src/main/java/com/github/vineey/rql/querydsl/filter/converter/PathConverterContext.java
// public final class PathConverterContext {
//     private static final StringPathConverter STRING_PATH_CONVERTER = new StringPathConverter();
//     private static final EnumPathConverter ENUM_PATH_CONVERTER = new EnumPathConverter();
//     private static final NumberPathConverter NUMBER_PATH_CONVERTER = new NumberPathConverter();
//     private static final BooleanPathConverter BOOLEAN_PATH_CONVERTER = new BooleanPathConverter();
//     private static final TimePathConverter TIME_PATH_CONVERTER = new TimePathConverter();
//     private static final DateTimePathConverter DATE_TIME_PATH_CONVERTER = new DateTimePathConverter();
//     private static final DatePathConverter DATE_PATH_CONVERTER = new DatePathConverter();
//     private static final DefaultCollectionPathConverter<Object, SimpleExpression<? super Object>,
//             Collection<Object>, CollectionPathBase<Collection<Object>,
//             Object,
//             SimpleExpression<? super Object>>> DEFAULT_COLLECTION_PATH_CONVERTER = new DefaultCollectionPathConverter<>();
//     private final static ImmutableMap<Class<? extends Path>, PathConverter> map = ImmutableMap.<Class<? extends Path>, PathConverter>builder()
//             .put(StringPath.class, STRING_PATH_CONVERTER)
//             .put(EnumPath.class, ENUM_PATH_CONVERTER)
//             .put(NumberPath.class, NUMBER_PATH_CONVERTER)
//             .put(BooleanPath.class, BOOLEAN_PATH_CONVERTER)
//             .put(TimePath.class, TIME_PATH_CONVERTER)
//             .put(DateTimePath.class, DATE_TIME_PATH_CONVERTER)
//             .put(DatePath.class, DATE_PATH_CONVERTER)
//             .put(ListPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .put(SetPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .put(CollectionPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .build();
// 
//     public static PathConverter getOperator(Path path) {
//         return map.get(path.getClass());
//     }
// }


import com.github.vineey.rql.querydsl.filter.converter.PathConverterContext;
import com.google.common.collect.Lists;
import com.querydsl.core.types.Ops;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import cz.jirutka.rsql.parser.ast.*;
import java.util.List;

        List<Node> children = Lists.newArrayList(node.getChildren());
        Node firstNode = children.remove(0);
        BooleanExpression predicate = (BooleanExpression) firstNode.accept(this, param);
        for (Node subNode : children) {
            BooleanExpression subPredicate = (BooleanExpression) subNode.accept(this, param);
            predicate = combineByLogicalExpression(logicalOperator, predicate, subPredicate);
        }
        return predicate;
    }

    private BooleanExpression combineByLogicalExpression(Ops logicalOperator, BooleanExpression predicate, Predicate subPredicate) {
        BooleanExpression combinedPredicate = predicate;
        if (Ops.AND.equals(logicalOperator)) {
            combinedPredicate = predicate.and(subPredicate);
        } else if (Ops.OR.equals(logicalOperator)) {
            combinedPredicate = predicate.or(subPredicate);
        }
        return combinedPredicate;
    }

    @Override
    public Predicate visit(OrNode node, QuerydslFilterParam param) {
        return evaluateLogicalExpression(node, param, Ops.OR);
    }

    @Override
    public Predicate visit(ComparisonNode node, QuerydslFilterParam param) {
        String selector = node.getSelector();
        Path path = param.getMapping().get(selector);
// Path: rsql-querydsl-parent/rsql-querydsl-filter/src/main/java/com/github/vineey/rql/querydsl/filter/converter/PathConverterContext.java
// public final class PathConverterContext {
//     private static final StringPathConverter STRING_PATH_CONVERTER = new StringPathConverter();
//     private static final EnumPathConverter ENUM_PATH_CONVERTER = new EnumPathConverter();
//     private static final NumberPathConverter NUMBER_PATH_CONVERTER = new NumberPathConverter();
//     private static final BooleanPathConverter BOOLEAN_PATH_CONVERTER = new BooleanPathConverter();
//     private static final TimePathConverter TIME_PATH_CONVERTER = new TimePathConverter();
//     private static final DateTimePathConverter DATE_TIME_PATH_CONVERTER = new DateTimePathConverter();
//     private static final DatePathConverter DATE_PATH_CONVERTER = new DatePathConverter();
//     private static final DefaultCollectionPathConverter<Object, SimpleExpression<? super Object>,
//             Collection<Object>, CollectionPathBase<Collection<Object>,
//             Object,
//             SimpleExpression<? super Object>>> DEFAULT_COLLECTION_PATH_CONVERTER = new DefaultCollectionPathConverter<>();
//     private final static ImmutableMap<Class<? extends Path>, PathConverter> map = ImmutableMap.<Class<? extends Path>, PathConverter>builder()
//             .put(StringPath.class, STRING_PATH_CONVERTER)
//             .put(EnumPath.class, ENUM_PATH_CONVERTER)
//             .put(NumberPath.class, NUMBER_PATH_CONVERTER)
//             .put(BooleanPath.class, BOOLEAN_PATH_CONVERTER)
//             .put(TimePath.class, TIME_PATH_CONVERTER)
//             .put(DateTimePath.class, DATE_TIME_PATH_CONVERTER)
//             .put(DatePath.class, DATE_PATH_CONVERTER)
//             .put(ListPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .put(SetPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .put(CollectionPath.class, DEFAULT_COLLECTION_PATH_CONVERTER)
//             .build();
// 
//     public static PathConverter getOperator(Path path) {
//         return map.get(path.getClass());
//     }
// }


// Path: rsql-querydsl-parent/rsql-querydsl-filter/src/main/java/com/github/vineey/rql/querydsl/filter/QuerydslRsqlVisitor.java
import com.github.vineey.rql.querydsl.filter.converter.PathConverterContext;
import com.google.common.collect.Lists;
import com.querydsl.core.types.Ops;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import cz.jirutka.rsql.parser.ast.*;
import java.util.List;


        List<Node> children = Lists.newArrayList(node.getChildren());
        Node firstNode = children.remove(0);
        BooleanExpression predicate = (BooleanExpression) firstNode.accept(this, param);
        for (Node subNode : children) {
            BooleanExpression subPredicate = (BooleanExpression) subNode.accept(this, param);
            predicate = combineByLogicalExpression(logicalOperator, predicate, subPredicate);
        }
        return predicate;
    }

    private BooleanExpression combineByLogicalExpression(Ops logicalOperator, BooleanExpression predicate, Predicate subPredicate) {
        BooleanExpression combinedPredicate = predicate;
        if (Ops.AND.equals(logicalOperator)) {
            combinedPredicate = predicate.and(subPredicate);
        } else if (Ops.OR.equals(logicalOperator)) {
            combinedPredicate = predicate.or(subPredicate);
        }
        return combinedPredicate;
    }

    @Override
    public Predicate visit(OrNode node, QuerydslFilterParam param) {
        return evaluateLogicalExpression(node, param, Ops.OR);
    }

    @Override
    public Predicate visit(ComparisonNode node, QuerydslFilterParam param) {
        String selector = node.getSelector();
        Path path = param.getMapping().get(selector);
        return PathConverterContext.getOperator(path).evaluate(path, node);