Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
simasch opened this issue Jan 26, 2023 · 6 comments
Open

Comments

@simasch
Copy link

simasch commented Jan 26, 2023

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

The problem is that returning a Page will 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.

@simasch simasch changed the title Add a findAll that takes a Pageable returns a Slice instead of a Page Add a findAll that takes a Pageable and returns a Slice instead of a Page Jan 26, 2023
@vladmihalcea
Copy link
Owner

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:

  • PagingBaseJpaRepository
  • SlicingBaseJpaRepository

@simasch
Copy link
Author

simasch commented Jan 26, 2023

+1 for the additional interfaces

@josergdev
Copy link

josergdev commented Sep 4, 2024

@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(), this.getInclusiveStartingOffset(pageable));
    return new SliceImpl<>(window.getContent(), pageable, window.hasNext());
  }

  private ScrollPosition getInclusiveStartingOffset(Pageable pageable) {
    return pageable.getOffset() == 0
        ? ScrollPosition.offset()
        : offset(pageable.getOffset() - 1);
  }

  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);
  }

}

EDIT:
Since Spring Data 3.3.3, OffsetScrollPosition is exclusive starting point.
https://github.com/spring-projects/spring-data-commons/wiki/Spring-Data-2024.0-Release-Notes#behavior-changes-in-offset-based-scrolling

Behavior Changes in Offset-based Scrolling
Scrolling behavior using offsets has been aligned with keyset-based scrolling. Both implementations now treat a given ScrollPosition as an exclusive starting point. It is important to start scrolling with the initial position ScrollPosition.offset() or ScrollPosition.keyset() to ensure the first element is included in the result. Scrolling from ScrollPosition.offset(0) will resume scrolling after the first element.

@vladmihalcea
Copy link
Owner

@josergdev Thanks for the tip.

@abuzar-aftab
Copy link

Is this done?

@vladmihalcea
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants