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 extends JpaSpecificationExecutor { default Window findAllWindowed(Specification spec, Sort sort, int limit, ScrollPosition scrollPosition) { return this.findBy(spec, toWindow(sort, limit, scrollPosition)); } default Window findAllWindowed(Specification spec, Sort sort, ScrollPosition scrollPosition) { return this.findBy(spec, toWindow(sort, scrollPosition)); } default Window findAllWindowed(Specification spec, ScrollPosition scrollPosition) { return this.findAllWindowed(spec, Sort.unsorted(), scrollPosition); } default Slice findAllSliced(Specification 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 Function, Window> toWindow(Sort sort, int limit, ScrollPosition scrollPosition) { return fetchableFluentQuery -> fetchableFluentQuery.sortBy(sort).limit(limit).scroll(scrollPosition); } private static Function, Window> toWindow(Sort sort, ScrollPosition scrollPosition) { return fetchableFluentQuery -> fetchableFluentQuery.sortBy(sort).scroll(scrollPosition); } }