Skip to content

Instantly share code, notes, and snippets.

@josergdev
Last active August 24, 2024 12:00
Show Gist options
  • Save josergdev/2d70f4975cd33140e1b9659ccc426917 to your computer and use it in GitHub Desktop.
Save josergdev/2d70f4975cd33140e1b9659ccc426917 to your computer and use it in GitHub Desktop.
SimpleJpaRepository extension to find All Slice by Specification
package dev.joserg.jpa;
import jakarta.persistence.EntityManager;
import org.jetbrains.annotations.Nullable;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
public class SliceJpaRepositoryImpl<T, I> extends SimpleJpaRepository<T, I> {
public BaseJpaRepositoryImpl(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
super(entityInformation, entityManager);
}
@Override
public Slice<T> findAllSliced(@Nullable final Specification<T> spec, final Pageable pageable) {
final var query = this.getQuery(spec, pageable.getSort());
query.setFirstResult((int) pageable.getOffset());
final var extraSize = pageable.getPageSize() + 1;
query.setMaxResults(extraSize);
final var result = query.getResultList();
final var hasNext = result.size() == extraSize;
if (hasNext) {
result.remove(extraSize - 1);
}
return new SliceImpl<>(result, pageable, hasNext);
}
}
package dev.joserg.jpa;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.CrudMethodMetadata;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.MutableQueryHints;
@ExtendWith(MockitoExtension.class)
class SliceJpaRepositoryImplTest {
private SliceJpaRepositoryImpl<ExampleEntity, Integer> repo;
@Mock
EntityManager em;
@Mock
CriteriaBuilder builder;
@Mock
CriteriaQuery<ExampleEntity> criteriaQuery;
@Mock
TypedQuery<ExampleEntity> query;
@Mock
JpaEntityInformation<ExampleEntity, UUID> information;
@Mock
CrudMethodMetadata metadata;
@BeforeEach
void setUp() {
when(this.em.getDelegate()).thenReturn(this.em);
when(this.information.getJavaType()).thenReturn(ExampleEntity.class);
when(this.em.getCriteriaBuilder()).thenReturn(this.builder);
when(this.builder.createQuery(ExampleEntity.class)).thenReturn(this.criteriaQuery);
when(this.em.createQuery(this.criteriaQuery)).thenReturn(this.query);
when(this.metadata.getQueryHints()).thenReturn(new MutableQueryHints());
this.repo = new BaseJpaRepositoryImpl<>(this.information, this.em);
this.repo.setRepositoryMethodMetadata(this.metadata);
}
@Test
void should_find_all_sliced_that_has_next() {
final var pageRequest = PageRequest.of(0, 1);
final var resultList = new ArrayList<>(List.of(mock(ExampleEntity.class), mock(ExampleEntity.class)));
when(this.query.getResultList()).thenReturn(resultList);
final var actual = this.repo.findAllSliced(Specification.where(null), pageRequest);
final var expected = new SliceImpl<>(resultList, pageRequest, true);
assertThat(actual.getContent()).hasSize(1);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}
@Test
void should_find_all_sliced_that_has_not_next() {
final var pageRequest = PageRequest.of(0, 2);
final var resultList = new ArrayList<>(List.of(mock(ExampleEntity.class), mock(ExampleEntity.class)));
when(this.query.getResultList()).thenReturn(resultList);
final var actual = this.repo.findAllSliced(Specification.where(null), pageRequest);
final var expected = new SliceImpl<>(resultList, pageRequest, false);
assertThat(actual.getContent()).hasSize(2);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment