vladmihalcea / hypersistence-utils

The Hypersistence Utils library (previously known as Hibernate Types) gives you Spring and Hibernate utilities that can help you get the most out of your data access layer.
Apache License 2.0
2.38k stars 366 forks source link

Add a findAll that takes a Pageable and returns a Slice instead of a Page #558

Open simasch opened 1 year ago

simasch commented 1 year ago

The PagingAndSortingRepositoryhas a Page<T> findAll(Pageable pageable) method.

The problem is that returning a Pagewill result in a count and a select statement.

The same problem is present in JpaSpecificationExecutor. So it would be awesome to have this covered as well.

vladmihalcea commented 1 year ago

So, should we define findAll that returns a Slice instead?

One option would be to avoid extending any base interface and create additional interfaces that provide this extra functionality:

simasch commented 1 year ago

+1 for the additional interfaces

josergdev commented 3 weeks ago

@vladmihalcea @simasch Can't this be achieved using JpaSpecificationExecutor::findBy method?

<S extends T, R> R findBy(Specification<T> spec, Function<FluentQuery.FetchableFluentQuery<S>, R> queryFunction);

I created this gist: https://gist.github.com/josergdev/06c82891a719eca4834410339885ad23

package dev.joserg.jpa;

import static org.springframework.data.domain.ScrollPosition.offset;

import java.util.function.Function;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;

public interface SliceSpecificationExecutor<T> extends JpaSpecificationExecutor<T> {

  default Window<T> findAllWindowed(Specification<T> spec, Sort sort, int limit, ScrollPosition scrollPosition) {
    return this.findBy(spec, toWindow(sort, limit, scrollPosition));
  }

  default Window<T> findAllWindowed(Specification<T> spec, Sort sort, ScrollPosition scrollPosition) {
    return this.findBy(spec, toWindow(sort, scrollPosition));
  }

  default Window<T> findAllWindowed(Specification<T> spec, ScrollPosition scrollPosition) {
    return this.findAllWindowed(spec, Sort.unsorted(), scrollPosition);
  }

  default Slice<T> findAllSliced(Specification<T> spec, Pageable pageable) {
    final var window = pageable.isUnpaged()
        ? this.findAllWindowed(spec, pageable.getSort(), offset())
        : this.findAllWindowed(spec, pageable.getSort(), pageable.getPageSize(), offset(pageable.getOffset()));
    return new SliceImpl<>(window.getContent(), pageable, window.hasNext());
  }

  private static <T> Function<FetchableFluentQuery<T>, Window<T>> toWindow(Sort sort, int limit, ScrollPosition scrollPosition) {
    return fetchableFluentQuery -> fetchableFluentQuery.sortBy(sort).limit(limit).scroll(scrollPosition);
  }

  private static <T> Function<FetchableFluentQuery<T>, Window<T>> toWindow(Sort sort, ScrollPosition scrollPosition) {
    return fetchableFluentQuery -> fetchableFluentQuery.sortBy(sort).scroll(scrollPosition);
  }

}
vladmihalcea commented 3 weeks ago

@josergdev Thanks for the tip.

abuzar-aftab commented 3 weeks ago

Is this done?

vladmihalcea commented 2 weeks ago

@abuzar-aftab Be the change you want to see in this world and provide a Pull Request with the fix.