Can Spring Data REST's QueryDSL integration be used to perform more complex queries?

I think you should be able to get this to work using the following customization:

bindings.bind(user.dateOfBirth).all((path, value) -> {

  Iterator<? extends LocalDate> it = value.iterator();
  return path.between(it.next(), it.next());
});

The key here is to use ?dateOfBirth=…&dateOfBirth= (use the property twice) and the ….all(…) binding which will give you access to all values provided.

Make sure you add the @DateTimeFormat annotation to the dateOfBirth-property of User so that Spring is able to convert the incoming Strings into LocalDate instances correctly.

The lambda currently gets a Collection<? extends T> which makes untangling the individual elements a bit more pain that it needs to be, but I think we can change this in a future release to rather expose a List.


As it was posted in some comment I also had the need to have different behaviour according to the field name creationDateFrom and creationDateTo. In order to make it work I did the following:

First I added the @QueryEntity annotation and two more fields to my entity class. The fields were annotated with:

  • @Transient so the fields are not persisted
  • @Getter(value = AccessLevel.PRIVATE) as we are using Lombok, the annotation hides the field from the response body
  • @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) takes care of the format for parsing the date on the url query parameter

@QueryEntity
@Entity
public class MyEntity implements Serializable {
  ...

  @Column(updatable = false)
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
  private Date creationDate;

  @Transient
  @Getter(value = AccessLevel.PRIVATE)
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
  private Date creationDateTo;

  @Transient
  @Getter(value = AccessLevel.PRIVATE)
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
  private Date creationDateFrom;

  ...
}  

Then I changed the way of generating the querydsl classes from JPAAnnotationProcessor to QuerydslAnnotationProcessor. This way fields annotated with @Transient are still generated on QMyEntity but are not persisted. Plugin configuration in pom:

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <phase>generate-sources</phase>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/annotations</outputDirectory>
                <processor>com.querydsl.apt.QuerydslAnnotationProcessor</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

Finally I extended the QuerydslBinderCustomizer and customized the bindings related with the creationDateFrom and creationDateTo but applying the right logic over creationDate

@Override
default void customize(QuerydslBindings bindings, QMyEntity root) {
    bindings.bind(root.creationDateFrom).first((path, value) -> 
                                                root.creationDate.after(value));
    bindings.bind(root.creationDateTo).first((path, value) ->
                                               root.creationDate.before(value));
}

With all of this you can do date range queries using one, both or none of the criterias:

http://localhost:8080/myentities?creation_date_to=2017-05-08
http://localhost:8080/myentities?creation_date_from=2017-01-01
http://localhost:8080/myentities?creation_date_from=2017-01-01&creation_date_to=2017-05-08