Search code examples
javaspringspring-data-jpaquerydsl

How to use bitwise operators in QueryDSL?


Hi,

In my project, I have a bit field flag (int), and i need to query the database using several criteria, one of them is the flag field, and in my Entity I have a field flag which is an enum, the same field could hold multiple values by adding them to each other, and then extract the result I need using & operator. For example: In database flag = 4 + 128 = 132 I need to check if the flag is holding the value of 128 by applying AND operator, so applying the query: SELECT * from rate where (flag & 128) > 0 so what I need is to send a bitwise_AND using Querydsl and spring data jpa.

I tried using QuerydslBinderCustomizer but couldn't find any method which apply any bitwise operator to integers. I also tried to create a custom BooleanExpression to return it to the bindings.bind which apply the bitwise operator manually, but also it didn't work.

This is an example of what I need:

public interface RateRepository extends CrudRepository<Rate,RatePK>, QueryDslPredicateExecutor<Rate>, QuerydslBinderCustomizer<QRate> {

@Override
default void customize(QuerydslBindings bindings, QRate qRate) {
    bindings.bind(qRate.rateId).first(
            (path, value) -> {
                return (path & value > 0) //Something like this, or a function like:
                //return (bitwise_AND(path, value) > 0);
            });
}

}

I also tried using com.querydsl.core.types.dsl.Expressions and com.querydsl.core.types.Predicate as below:

bindings.bind(qRate.rateFlag).first(
            (path, value) -> {
                Expression<Integer> intPath = Expressions.asNumber(path);
                Expression<Integer> rateFlag = Expressions.asNumber(value);
                Expression<Integer> zeroValue = Expressions.asNumber(0);
                Expression<Integer> integerExpression = Expressions.numberOperation(Integer.class, Ops.AND, intPath, rateFlag);
                Predicate predicate  = Expressions.predicate(Ops.GT, integerExpression, zeroValue);
                return predicate;
            });

But i got an invalid operator AND error.

How could this be done?

Thank you.


Solution

  • first you need to extend hibernate dialect to support bit operation as below

    public class MySQLDialect extends org.hibernate.dialect.MySQLDialect {
    
        public MySQLDialect() {
            super();
            registerFunction("bitand", new SQLFunctionTemplate(IntegerType.INSTANCE, "(?1 & ?2)"));
        }
    }
    

    then you can reference this function from querydsl or spring repository

    bindings.bind(qRate.rateFlag).first(
                (path, value) -> {
                    Expression<Integer> zeroValue = Expressions.asNumber(0);
                    NumberTemplate<Integer> numberTemplate = Expressions.numberTemplate(Integer.class, "function('bitand', {0}, {1})", path, value);
                    return numberTemplate.gt(0);
                });