Following the official documentation, adding @EnableSpringDataWebSupport
annotation to my Spring configuration allows to automatically inject a Predicate
class in query:
@RequestMapping(method = RequestMethod.GET, path="/find")
public ResponseEntity<PagedResources<FooResource>> find(Pageable pageable, PagedResourcesAssembler<Foo> assembler, @QuerydslPredicate(root = Foo.class) Predicate predicate) {
Page<Foo> foos = fooRepository.findAll(predicate, pageable)
final ResourceAssemblerSupport<Foo, FooResource> fooResourceAssembler = new ....;
final PagedResources<FooResource> pagedResources = assembler.toResource(foos, fooResourceAssembler);
return new ResponseEntity<>(pagedResources, HttpStatus.OK);
}
Then I can easily search when performing the GET request:
GET /foo/name?=bob&name=alice&age=20
This works fine. However I was wondering how to achieve more advanced search criteria:
>
<
>=
<=
Typically I would like to apply these operators to numeric and date fields in my data models. These sorts of criterion are supported in Querydsl.
I tried adding > (%3E)
in my query parameters but it fails parsing (for example for numeric field like age it complains it cannot parse >10
as a number.
Is it possible to use this operator directly in the query?
(In case it matters I'm using Spring Data Mongodb)
Custom Query DSL binding - greater than comparison
What you can do is define your own QueryDSL Binding in your repository, by extending QueryDslPredicateExecutor
and QuerydslBinderCustomizer
:
public interface FooRepository
extends CrudRepository<Foo, Integer>, QueryDslPredicateExecutor<Foo>, QuerydslBinderCustomizer<QFoo> {
default void customize(final QuerydslBindings bindings, final QFoo foo) {
SingleValueBinding<NumberPath<Integer>, Integer> singleBinding = new SingleValueBinding<NumberPath<Integer>,Integer>(){
@Override
public Predicate bind(NumberPath<Integer> path, Integer ageValue) {
return path.gt(ageValue);
}
};
bindings.bind(foo.age).first(singleBinding);
}
}
I'm no Query DSL expert, but my understanding is the following:
a binding defines how a specific field is to be compared to its database column.
The same binding with java 8 lambda: (path, ageValue) -> path.gt(ageValue)
. You have to read the code in customize method from the url parameter's perspective:
fetch the Foos for which the age provided as parameter is greater than the database's value.
Custom Query DSL binding - between comparison
Another option is to provide lower and upper bound for your parameter, like this: ?age=10&age=30
. Then, define the following binding:
default void customize(final QuerydslBindings bindings, final QFoo foo) {
bindings.bind(foo.age).all((path, values) -> {
Iterator<? extends Long> it = values.iterator();
return path.between(it.next(), it.next());
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With