Skip to content

Commit

Permalink
Merge pull request #4 from TarasYashchuk/dev
Browse files Browse the repository at this point in the history
implemented book search
  • Loading branch information
TarasYashchuk authored Jun 19, 2024
2 parents 7563600 + 18a0d31 commit 5f5be81
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/main/java/mate/academy/controller/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import lombok.RequiredArgsConstructor;
import mate.academy.dto.BookDto;
import mate.academy.dto.BookSearchParametersDto;
import mate.academy.dto.CreateBookRequestDto;
import mate.academy.dto.UpdateBookRequestDto;
import mate.academy.service.BookService;
Expand Down Expand Up @@ -49,4 +50,9 @@ public void delete(@PathVariable Long id) {
public BookDto updateBook(@PathVariable Long id, @RequestBody UpdateBookRequestDto requestDto) {
return bookService.updateBookDetails(id, requestDto);
}

@GetMapping("/search")
public List<BookDto> search(BookSearchParametersDto searchParameters) {
return bookService.search(searchParameters);
}
}
8 changes: 8 additions & 0 deletions src/main/java/mate/academy/dto/BookSearchParametersDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mate.academy.dto;

public record BookSearchParametersDto(
String title,
String author,
String isbn,
String price) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package mate.academy.repository;

import mate.academy.dto.BookSearchParametersDto;
import org.springframework.data.jpa.domain.Specification;

public interface SpecificationBuilder<T> {
Specification<T> build(BookSearchParametersDto searchParameters);
}
10 changes: 10 additions & 0 deletions src/main/java/mate/academy/repository/SpecificationProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package mate.academy.repository;

import mate.academy.model.Book;
import org.springframework.data.jpa.domain.Specification;

public interface SpecificationProvider<T> {
Specification<Book> getSpecification(String param);

String getKey();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package mate.academy.repository;

public interface SpecificationProviderManager<T> {
SpecificationProvider<T> getSpecificationProvider(String key);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package mate.academy.repository;
package mate.academy.repository.book;

import mate.academy.model.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
public interface BookRepository extends JpaRepository<Book, Long>, JpaSpecificationExecutor<Book> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mate.academy.repository.book;

import lombok.RequiredArgsConstructor;
import mate.academy.dto.BookSearchParametersDto;
import mate.academy.model.Book;
import mate.academy.repository.SpecificationBuilder;
import mate.academy.repository.SpecificationProviderManager;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class BookSpecificationBuilder implements SpecificationBuilder<Book> {

private final SpecificationProviderManager<Book> bookSpecificationProviderManager;

@Override
public Specification<Book> build(BookSearchParametersDto searchParameters) {
Specification<Book> specification = Specification.where(null);

specification = addSpecification(specification,
BookSpecificationKeys.TITLE, searchParameters.title());
specification = addSpecification(specification,
BookSpecificationKeys.PRICE, searchParameters.price());
specification = addSpecification(specification,
BookSpecificationKeys.ISBN, searchParameters.isbn());
specification = addSpecification(specification,
BookSpecificationKeys.AUTHOR, searchParameters.author());

return specification;
}

private Specification<Book> addSpecification(Specification<Book> specification,
String key, String value) {
if (value != null && !value.isEmpty()) {
specification = specification
.and(bookSpecificationProviderManager.getSpecificationProvider(key)
.getSpecification(value));
}
return specification;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package mate.academy.repository.book;

public final class BookSpecificationKeys {
public static final String TITLE = "title";
public static final String PRICE = "price";
public static final String ISBN = "isbn";
public static final String AUTHOR = "author";

private BookSpecificationKeys() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package mate.academy.repository.book;

import java.util.List;
import lombok.RequiredArgsConstructor;
import mate.academy.model.Book;
import mate.academy.repository.SpecificationProvider;
import mate.academy.repository.SpecificationProviderManager;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class BookSpecificationProviderManager implements SpecificationProviderManager<Book> {

private final List<SpecificationProvider<Book>> bookSpecificationProviders;

@Override
public SpecificationProvider<Book> getSpecificationProvider(String key) {
return bookSpecificationProviders.stream()
.filter(p -> p.getKey().equals(key))
.findFirst()
.orElseThrow(
() -> new RuntimeException("Cant get specification with key: " + key));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package mate.academy.repository.book.spec;

import mate.academy.model.Book;
import mate.academy.repository.SpecificationProvider;
import mate.academy.repository.book.BookSpecificationKeys;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@Component
public class AuthorSpecificationProvider implements SpecificationProvider<Book> {

public Specification<Book> getSpecification(String param) {
return (root, query, criteriaBuilder) -> criteriaBuilder
.equal(root.get(BookSpecificationKeys.AUTHOR), param);
}

@Override
public String getKey() {
return BookSpecificationKeys.AUTHOR;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package mate.academy.repository.book.spec;

import mate.academy.model.Book;
import mate.academy.repository.SpecificationProvider;
import mate.academy.repository.book.BookSpecificationKeys;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@Component
public class IsbnSpecificationProvider implements SpecificationProvider<Book> {

public Specification<Book> getSpecification(String param) {
return (root, query, criteriaBuilder) -> criteriaBuilder
.equal(root.get(BookSpecificationKeys.ISBN), param);
}

@Override
public String getKey() {
return BookSpecificationKeys.ISBN;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mate.academy.repository.book.spec;

import mate.academy.model.Book;
import mate.academy.repository.SpecificationProvider;
import mate.academy.repository.book.BookSpecificationKeys;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@Component
public class PriceSpecificationProvider implements SpecificationProvider<Book> {
public Specification<Book> getSpecification(String param) {
return (root, query, criteriaBuilder) -> criteriaBuilder
.equal(root.get(BookSpecificationKeys.PRICE), param);
}

@Override
public String getKey() {
return BookSpecificationKeys.PRICE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package mate.academy.repository.book.spec;

import mate.academy.model.Book;
import mate.academy.repository.SpecificationProvider;
import mate.academy.repository.book.BookSpecificationKeys;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@Component
public class TitleSpecificationProvider implements SpecificationProvider<Book> {
public Specification<Book> getSpecification(String param) {
return (root, query, criteriaBuilder) -> criteriaBuilder
.equal(root.get(BookSpecificationKeys.TITLE), param);
}

@Override
public String getKey() {
return BookSpecificationKeys.TITLE;
}
}
15 changes: 14 additions & 1 deletion src/main/java/mate/academy/service/BookService.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package mate.academy.service;

import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import mate.academy.dto.BookDto;
import mate.academy.dto.BookSearchParametersDto;
import mate.academy.dto.CreateBookRequestDto;
import mate.academy.dto.UpdateBookRequestDto;
import mate.academy.exception.EntityNotFoundException;
import mate.academy.mapper.BookMapper;
import mate.academy.model.Book;
import mate.academy.repository.BookRepository;
import mate.academy.repository.book.BookRepository;
import mate.academy.repository.book.BookSpecificationBuilder;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
Expand All @@ -18,6 +22,8 @@ public class BookService {

private final BookMapper bookMapper;

private final BookSpecificationBuilder bookSpecificationBuilder;

public BookDto save(CreateBookRequestDto requestDto) {
Book book = bookMapper.toModel(requestDto);
return bookMapper.toDto(bookRepository.save(book));
Expand Down Expand Up @@ -46,4 +52,11 @@ public BookDto updateBookDetails(Long id, UpdateBookRequestDto requestDto) {
bookMapper.updateBookFromDto(requestDto,book);
return bookMapper.toDto(bookRepository.save(book));
}

public List<BookDto> search(BookSearchParametersDto params) {
Specification<Book> bookSpecification = bookSpecificationBuilder.build(params);
return bookRepository.findAll(bookSpecification).stream()
.map(bookMapper::toDto)
.collect(Collectors.toList());
}
}

0 comments on commit 5f5be81

Please sign in to comment.