redis / redis-om-spring

Spring Data Redis extensions for better search, documents models, and more
MIT License
604 stars 93 forks source link

constructor of predicate #342

Open HengCC opened 1 year ago

HengCC commented 1 year ago

How can I construct combinations of predicates of different types, such as 'and' and 'or'? Currently, writing something like this results in a generic type incompatibility error. Do I need to specify the generic type within these constructs

xxx$.NAME_SPACE.eq(NameSpaceEnum.PERSONAL.name())
                .and(xxx$.RELATE_ID.eq(user.getId()))

At compile time, I'm getting the following error

Required type: Predicate <? super String,

Provided: EqualPredicate <xxx,java.lang.Long>
HengCC commented 1 year ago

In Java 8, predicates naturally come with generic constraints. However, in real-world queries, combining conditions of two different types should be a normal business scenario, as in the example above. It can be written as (@nameSpace:{space}) (@relateId:{id}).

HengCC commented 1 year ago

If 'and' and 'or' don't return Predicate types but instead assemble into a string query expression like the following, is it feasible?

public interface QueryCondition {
    String get();

    default QueryCondition and(QueryCondition otherCondition) {
        return () -> {
            return this.get() + "  " + otherCondition.get();
        };
    }

    default QueryCondition or(QueryCondition otherCondition) {
        return () -> {
            return "(" + this.get() + ")" + "| " + "(" + otherCondition.get() + ")";
        };
    }
}

then use it,

 QueryCondition queryCondition = () -> xxx$.CONTENT.containing(keyword).apply(QueryBuilders.union(new Node[0])).toString(Node.Parenthesize.NEVER);
        queryCondition = queryCondition.or(() -> xxx$.NAME.startsWith(keyword).apply(QueryBuilders.union(new Node[0])).toString(Node.Parenthesize.NEVER))
                .or(() -> xxx$.NAME.endsWith(keyword).apply(QueryBuilders.union(new Node[0])).toString(Node.Parenthesize.NEVER))
                .or(() -> xxx$.NAME.containing(keyword).apply(QueryBuilders.union(new Node[0])).toString(Node.Parenthesize.NEVER))
.and(() -> xxx$.NAME_SPACE.eq("namespace").apply(QueryBuilders.union(new Node[0])).toString(Node.Parenthesize.NEVER));
        long total = entityStream.of(xxx.class).filter(predicate).count();
        List<xxx> collect = entityStream.of(xxx.class)
                //.filter("(@name:" + keyword + ")|(@content:" + keyword + ")")
                .filter(queryCondition.get())
                //.filter(predicate)
                .skip(pageable.getOffset())
                .limit(pageable.getPageSize())
                .collect(Collectors.toList());
bsbodden commented 6 months ago

@HengCC sorry, this one slipped by... Would you be interested in working in a PR with us?