diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/config/Initializer.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/config/Initializer.java index e6a350bc4..f3a92e61d 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/config/Initializer.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/config/Initializer.java @@ -21,7 +21,7 @@ public class Initializer implements CommandLineRunner { public void run(String... args) { log.info("Running Initializer....."); List actorList = - LongStream.rangeClosed(1, 30) + LongStream.rangeClosed(1, 50) .mapToObj( actorId -> { Actor actor = new Actor(); diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/ActorsFilter.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/ActorsFilter.java index 8edd63d14..6ce562226 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/ActorsFilter.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/ActorsFilter.java @@ -4,8 +4,10 @@ import java.util.ArrayList; import java.util.List; import lombok.Getter; +import lombok.Setter; @Getter +@Setter public class ActorsFilter { private Kind kind; @@ -14,14 +16,6 @@ public class ActorsFilter { public ActorsFilter() {} - public void setKind(Kind kind) { - this.kind = kind; - } - - public void setField(String field) { - this.field = field; - } - @JsonIgnore public String getValue() { return values.get(0); @@ -70,11 +64,7 @@ public void setHigh(String high) { values.set(1, high); } - public void setValues(List values) { - this.values = values; - } - - public static enum Kind { + public enum Kind { EQ, LT, GT, diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/FindActorsQuery.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/FindActorsQuery.java index 3b999d37a..86283afbd 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/FindActorsQuery.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/model/query/FindActorsQuery.java @@ -3,7 +3,6 @@ public record FindActorsQuery( int pageNo, int pageSize, - Integer firstResult, Integer maxResults, Long lowest, Long highest, diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/repositories/ActorRepository.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/repositories/ActorRepository.java index 571e57721..7654718db 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/repositories/ActorRepository.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/repositories/ActorRepository.java @@ -1,12 +1,14 @@ package com.example.keysetpagination.repositories; import com.blazebit.persistence.spring.data.repository.KeysetAwarePage; +import com.blazebit.persistence.spring.data.repository.KeysetPageable; import com.example.keysetpagination.entities.Actor; -import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.ListCrudRepository; -public interface ActorRepository extends JpaRepository { +public interface ActorRepository extends ListCrudRepository { - KeysetAwarePage findAll(Specification specification, Pageable pageable); + KeysetAwarePage findAll(Specification specification, KeysetPageable pageable); + + KeysetAwarePage findAll(KeysetPageable keysetPageable); } diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/services/ActorService.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/services/ActorService.java index 598d9d514..e2932c634 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/services/ActorService.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/services/ActorService.java @@ -31,7 +31,7 @@ import org.springframework.transaction.annotation.Transactional; @Service -@Transactional +@Transactional(readOnly = true) @RequiredArgsConstructor public class ActorService { @@ -42,8 +42,46 @@ public PagedResult findAll( ActorsFilter[] actorsFilter, FindActorsQuery findActorsQuery) { Specification specification = getSpecificationForFilter(actorsFilter); KeysetPageable keysetPageable = createPageable(findActorsQuery); - KeysetAwarePage keysetAwarePage = - actorRepository.findAll(specification, keysetPageable); + return getActorResponsePagedResult(actorRepository.findAll(specification, keysetPageable)); + } + + public PagedResult findAll(FindActorsQuery findActorsQuery) { + KeysetPageable keysetPageable = createPageable(findActorsQuery); + return getActorResponsePagedResult(actorRepository.findAll(keysetPageable)); + } + + public Optional findActorById(Long id) { + return actorRepository.findById(id).map(actorMapper::toResponse); + } + + @Transactional + public ActorResponse saveActor(ActorRequest actorRequest) { + Actor actor = actorMapper.toEntity(actorRequest); + Actor savedActor = actorRepository.save(actor); + return actorMapper.toResponse(savedActor); + } + + @Transactional + public ActorResponse updateActor(Long id, ActorRequest actorRequest) { + Actor actor = + actorRepository.findById(id).orElseThrow(() -> new ActorNotFoundException(id)); + + // Update the actor object with data from actorRequest + actorMapper.mapActorWithRequest(actor, actorRequest); + + // Save the updated actor object + Actor updatedActor = actorRepository.save(actor); + + return actorMapper.toResponse(updatedActor); + } + + @Transactional + public void deleteActorById(Long id) { + actorRepository.deleteById(id); + } + + private PagedResult getActorResponsePagedResult( + KeysetAwarePage keysetAwarePage) { List actorResponseList = actorMapper.toResponseList(keysetAwarePage.getContent()); return new PagedResult<>( @@ -71,7 +109,7 @@ private KeysetPageable createPageable(FindActorsQuery findActorsQuery) { : Sort.Order.desc(findActorsQuery.sortBy())); KeysetPage keysetPage = new DefaultKeysetPage( - findActorsQuery.firstResult() == null ? 0 : findActorsQuery.firstResult(), + findActorsQuery.pageNo() - 1, findActorsQuery.maxResults() == null ? findActorsQuery.pageSize() : findActorsQuery.maxResults(), @@ -81,146 +119,103 @@ private KeysetPageable createPageable(FindActorsQuery findActorsQuery) { keysetPage, PageRequest.of(pageNo, findActorsQuery.pageSize(), sort)); } - public Optional findActorById(Long id) { - return actorRepository.findById(id).map(actorMapper::toResponse); - } - - public ActorResponse saveActor(ActorRequest actorRequest) { - Actor actor = actorMapper.toEntity(actorRequest); - Actor savedActor = actorRepository.save(actor); - return actorMapper.toResponse(savedActor); - } - - public ActorResponse updateActor(Long id, ActorRequest actorRequest) { - Actor actor = - actorRepository.findById(id).orElseThrow(() -> new ActorNotFoundException(id)); - - // Update the actor object with data from actorRequest - actorMapper.mapActorWithRequest(actor, actorRequest); - - // Save the updated actor object - Actor updatedActor = actorRepository.save(actor); - - return actorMapper.toResponse(updatedActor); - } - - public void deleteActorById(Long id) { - actorRepository.deleteById(id); - } - private Specification getSpecificationForFilter(final ActorsFilter[] actorsFilter) { if (actorsFilter == null || actorsFilter.length == 0) { return null; } - return new Specification() { - @Override - public Predicate toPredicate( - Root root, - CriteriaQuery criteriaQuery, - CriteriaBuilder criteriaBuilder) { - List predicates = new ArrayList<>(); - ParserContext parserContext = new ParserContextImpl(); - try { - for (ActorsFilter f : actorsFilter) { - SerializableFormat format = FILTER_ATTRIBUTES.get(f.getField()); - if (format != null) { - String[] fieldParts = f.getField().split("\\."); - Path path = root.get(fieldParts[0]); - for (int i = 1; i < fieldParts.length; i++) { - path = path.get(fieldParts[i]); - } - switch (f.getKind()) { - case EQ: - predicates.add( - criteriaBuilder.equal( - path, - format.parse(f.getValue(), parserContext))); - break; - case GT: - predicates.add( - criteriaBuilder.greaterThan( - (Expression) path, - (Comparable) - format.parse( - f.getValue(), parserContext))); - break; - case LT: - predicates.add( - criteriaBuilder.lessThan( - (Expression) path, - (Comparable) - format.parse( - f.getValue(), parserContext))); - break; - case GTE: - predicates.add( - criteriaBuilder.greaterThanOrEqualTo( - (Expression) path, - (Comparable) - format.parse( - f.getValue(), parserContext))); - break; - case LTE: - predicates.add( - criteriaBuilder.lessThanOrEqualTo( - (Expression) path, - (Comparable) - format.parse( - f.getValue(), parserContext))); - break; - case IN: - List values = f.getValues(); - List filterValues = new ArrayList<>(values.size()); - for (String value : values) { - filterValues.add(format.parse(value, parserContext)); - } - predicates.add(path.in(filterValues)); - break; - case BETWEEN: - predicates.add( - criteriaBuilder.between( - (Expression) path, - (Comparable) - format.parse(f.getLow(), parserContext), - (Comparable) - format.parse( - f.getHigh(), parserContext))); - break; - case STARTS_WITH: - predicates.add( - criteriaBuilder.like( - (Expression) path, - format.parse(f.getValue(), parserContext) - + "%")); - break; - case ENDS_WITH: - predicates.add( - criteriaBuilder.like( - (Expression) path, - "%" - + format.parse( - f.getValue(), parserContext))); - break; - case CONTAINS: - predicates.add( - criteriaBuilder.like( - (Expression) path, - "%" - + format.parse( - f.getValue(), parserContext) - + "%")); - break; - default: - throw new UnsupportedOperationException( - "Unsupported kind: " + f.getKind()); - } + return (root, criteriaQuery, criteriaBuilder) -> { + List predicates = new ArrayList<>(); + ParserContext parserContext = new ParserContextImpl(); + try { + for (ActorsFilter f : actorsFilter) { + SerializableFormat format = FILTER_ATTRIBUTES.get(f.getField()); + if (format != null) { + String[] fieldParts = f.getField().split("\\."); + Path path = root.get(fieldParts[0]); + for (int i = 1; i < fieldParts.length; i++) { + path = path.get(fieldParts[i]); + } + switch (f.getKind()) { + case EQ: + predicates.add( + criteriaBuilder.equal( + path, format.parse(f.getValue(), parserContext))); + break; + case GT: + predicates.add( + criteriaBuilder.greaterThan( + (Expression) path, + (Comparable) + format.parse(f.getValue(), parserContext))); + break; + case LT: + predicates.add( + criteriaBuilder.lessThan( + (Expression) path, + (Comparable) + format.parse(f.getValue(), parserContext))); + break; + case GTE: + predicates.add( + criteriaBuilder.greaterThanOrEqualTo( + (Expression) path, + (Comparable) + format.parse(f.getValue(), parserContext))); + break; + case LTE: + predicates.add( + criteriaBuilder.lessThanOrEqualTo( + (Expression) path, + (Comparable) + format.parse(f.getValue(), parserContext))); + break; + case IN: + List values = f.getValues(); + List filterValues = new ArrayList<>(values.size()); + for (String value : values) { + filterValues.add(format.parse(value, parserContext)); + } + predicates.add(path.in(filterValues)); + break; + case BETWEEN: + predicates.add( + criteriaBuilder.between( + (Expression) path, + (Comparable) + format.parse(f.getLow(), parserContext), + (Comparable) + format.parse(f.getHigh(), parserContext))); + break; + case STARTS_WITH: + predicates.add( + criteriaBuilder.like( + (Expression) path, + format.parse(f.getValue(), parserContext) + "%")); + break; + case ENDS_WITH: + predicates.add( + criteriaBuilder.like( + (Expression) path, + "%" + format.parse(f.getValue(), parserContext))); + break; + case CONTAINS: + predicates.add( + criteriaBuilder.like( + (Expression) path, + "%" + + format.parse(f.getValue(), parserContext) + + "%")); + break; + default: + throw new UnsupportedOperationException( + "Unsupported kind: " + f.getKind()); } } - } catch (ParseException ex) { - throw new RuntimeException(ex); } - return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); + } catch (ParseException ex) { + throw new RuntimeException(ex); } + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; } @@ -228,7 +223,7 @@ private static class ParserContextImpl implements ParserContext { private final Map contextMap; private ParserContextImpl() { - this.contextMap = new HashMap(); + this.contextMap = new HashMap<>(); } public Object getAttribute(String name) { diff --git a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/web/controllers/ActorController.java b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/web/controllers/ActorController.java index 5885ea2a4..19920cce3 100644 --- a/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/web/controllers/ActorController.java +++ b/jpa/boot-data-keyset-pagination/src/main/java/com/example/keysetpagination/web/controllers/ActorController.java @@ -53,17 +53,51 @@ public PagedResult findAllActors( defaultValue = AppConstants.DEFAULT_SORT_DIRECTION, required = false) String sortDir, - @RequestParam(value = "prevPage", required = false) Integer prevPage, @RequestParam(value = "maxResults", required = false) Integer maxResults, @RequestParam(value = "lowest", required = false) Long lowest, + @RequestParam(value = "highest", required = false) Long highest) { + + FindActorsQuery findActorsQuery = + new FindActorsQuery(pageNo, pageSize, maxResults, lowest, highest, sortBy, sortDir); + + return actorService.findAll(findActorsQuery); + } + + @PostMapping("/search") + public PagedResult searchActors( + @RequestParam( + value = "pageNo", + defaultValue = AppConstants.DEFAULT_PAGE_NUMBER, + required = false) + int pageNo, + @RequestParam( + value = "pageSize", + defaultValue = AppConstants.DEFAULT_PAGE_SIZE, + required = false) + int pageSize, + @RequestParam( + value = "sortBy", + defaultValue = AppConstants.DEFAULT_SORT_BY, + required = false) + String sortBy, + @RequestParam( + value = "sortDir", + defaultValue = AppConstants.DEFAULT_SORT_DIRECTION, + required = false) + String sortDir, + @RequestParam( + value = "maxResults", + defaultValue = AppConstants.DEFAULT_PAGE_SIZE, + required = false) + Integer maxResults, + @RequestParam(value = "lowest", required = false) Long lowest, @RequestParam(value = "highest", required = false) Long highest, - @RequestParam(name = "filter", required = false) final ActorsFilter[] actorsFilter) { + @RequestBody ActorsFilter[] actorsFilters) { FindActorsQuery findActorsQuery = - new FindActorsQuery( - pageNo, pageSize, prevPage, maxResults, lowest, highest, sortBy, sortDir); + new FindActorsQuery(pageNo, pageSize, maxResults, lowest, highest, sortBy, sortDir); - return actorService.findAll(actorsFilter, findActorsQuery); + return actorService.findAll(actorsFilters, findActorsQuery); } @GetMapping("/{id}") diff --git a/jpa/boot-data-keyset-pagination/src/test/java/com/example/keysetpagination/web/controllers/ActorControllerIT.java b/jpa/boot-data-keyset-pagination/src/test/java/com/example/keysetpagination/web/controllers/ActorControllerIT.java index 77e89ff16..d28574c23 100644 --- a/jpa/boot-data-keyset-pagination/src/test/java/com/example/keysetpagination/web/controllers/ActorControllerIT.java +++ b/jpa/boot-data-keyset-pagination/src/test/java/com/example/keysetpagination/web/controllers/ActorControllerIT.java @@ -34,7 +34,7 @@ class ActorControllerIT extends AbstractIntegrationTest { @BeforeEach void setUp() { - actorRepository.deleteAllInBatch(); + actorRepository.deleteAll(); actorList = new ArrayList<>(); actorList.add(new Actor(null, "First Actor", LocalDate.now())); @@ -72,7 +72,6 @@ void shouldFetchAllActors() throws Exception { .param("pageNo", "2") .param("pageSize", "2") .param("sortDir", "desc") - .param("prevPage", String.valueOf(pagedResult.pageNumber())) .param("maxResults", "2") .param( "lowest",