diff --git a/src/main/java/mate/academy/bookstore/controller/BookController.java b/src/main/java/mate/academy/bookstore/controller/BookController.java index 85bd8b1..74033ba 100644 --- a/src/main/java/mate/academy/bookstore/controller/BookController.java +++ b/src/main/java/mate/academy/bookstore/controller/BookController.java @@ -6,8 +6,8 @@ import java.util.List; import lombok.RequiredArgsConstructor; import mate.academy.bookstore.dto.book.BookDto; -import mate.academy.bookstore.dto.book.BookRequestDto; import mate.academy.bookstore.dto.book.BookSearchParametersDto; +import mate.academy.bookstore.dto.book.CreateBookRequestDto; import mate.academy.bookstore.service.BookService; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; @@ -29,6 +29,7 @@ public class BookController { private final BookService bookService; + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @GetMapping @ResponseStatus(HttpStatus.OK) @Operation(summary = "Get all books", description = "Get a list of all available books") @@ -36,6 +37,7 @@ public List getAll(Pageable pageable) { return bookService.findAll(pageable); } + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @GetMapping("/{id}") @ResponseStatus(HttpStatus.OK) @Operation(summary = "Get a book by ID", description = "Get a book by ID, if there is one") @@ -47,7 +49,7 @@ public BookDto getBookById(@PathVariable Long id) { @PostMapping @ResponseStatus(HttpStatus.CREATED) @Operation(summary = "Create a new book", description = "Create a new book with generated ID") - public BookDto createBook(@RequestBody @Valid BookRequestDto requestDto) { + public BookDto createBook(@RequestBody @Valid CreateBookRequestDto requestDto) { return bookService.save(requestDto); } @@ -56,7 +58,7 @@ public BookDto createBook(@RequestBody @Valid BookRequestDto requestDto) { @ResponseStatus(HttpStatus.ACCEPTED) @Operation(summary = "Update a book by ID", description = "Update a book by its ID, if exists") public BookDto updateBook(@PathVariable Long id, - @RequestBody @Valid BookRequestDto requestDto) { + @RequestBody @Valid CreateBookRequestDto requestDto) { return bookService.updateById(id, requestDto); } @@ -68,6 +70,7 @@ public void deleteBook(@PathVariable Long id) { bookService.delete(id); } + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") @GetMapping("/search") @ResponseStatus(HttpStatus.OK) @Operation(summary = "Get a list of books by search parameters", diff --git a/src/main/java/mate/academy/bookstore/controller/CategoryController.java b/src/main/java/mate/academy/bookstore/controller/CategoryController.java new file mode 100644 index 0000000..6e35c92 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/controller/CategoryController.java @@ -0,0 +1,77 @@ +package mate.academy.bookstore.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import mate.academy.bookstore.dto.book.BookDtoWithoutCategoryIds; +import mate.academy.bookstore.dto.category.CategoryDto; +import mate.academy.bookstore.service.BookService; +import mate.academy.bookstore.service.CategoryService; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RestController +@Tag(name = "Category management", description = "Endpoints for category management") +@RequestMapping(value = "/categories") +public class CategoryController { + private final CategoryService categoryService; + private final BookService bookService; + + @PreAuthorize("hasRole('ADMIN')") + @PostMapping + @Operation(summary = "Create new category", description = "Create category with generated ID") + public CategoryDto createCategory(@RequestBody @Valid CategoryDto categoryDto) { + return categoryService.save(categoryDto); + } + + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + @GetMapping + @Operation(summary = "Get all categories", description = "Get a list of existing categories") + public List getAll(Pageable pageable) { + return categoryService.findAll(pageable); + } + + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + @GetMapping("/{id}") + @Operation(summary = "Get category by ID", description = "Get category by ID, if there is one") + public CategoryDto getCategoryById(@PathVariable Long id) { + return categoryService.getById(id); + } + + @PreAuthorize("hasRole('ADMIN')") + @PutMapping("/{id}") + @Operation(summary = "Update category by ID", description = "Update category by ID, if exists") + public CategoryDto updateCategory(@PathVariable Long id, + @RequestBody @Valid CategoryDto categoryDto) { + return categoryService.update(id, categoryDto); + } + + @PreAuthorize("hasRole('ADMIN')") + @DeleteMapping("/{id}") + @Operation(summary = "Delete category by ID", description = "Delete category by ID, if exists") + public void deleteCategory(@PathVariable Long id) { + categoryService.delete(id); + } + + @PreAuthorize("hasAnyRole('USER', 'ADMIN')") + @GetMapping("/{id}/books") + @Operation(summary = "Get books by category ID", + description = "Get a list of books by category ID") + public List getBooksByCategoryId( + @PathVariable Long id, + Pageable pageable + ) { + return bookService.getAllBookByCategoryId(id, pageable); + } +} diff --git a/src/main/java/mate/academy/bookstore/dto/book/BookDto.java b/src/main/java/mate/academy/bookstore/dto/book/BookDto.java index 95dae1b..947b650 100644 --- a/src/main/java/mate/academy/bookstore/dto/book/BookDto.java +++ b/src/main/java/mate/academy/bookstore/dto/book/BookDto.java @@ -1,6 +1,7 @@ package mate.academy.bookstore.dto.book; import java.math.BigDecimal; +import java.util.Set; import lombok.Data; @Data @@ -12,4 +13,5 @@ public class BookDto { private BigDecimal price; private String description; private String coverImage; + private Set categories; } diff --git a/src/main/java/mate/academy/bookstore/dto/book/BookDtoWithoutCategoryIds.java b/src/main/java/mate/academy/bookstore/dto/book/BookDtoWithoutCategoryIds.java new file mode 100644 index 0000000..cc2c15c --- /dev/null +++ b/src/main/java/mate/academy/bookstore/dto/book/BookDtoWithoutCategoryIds.java @@ -0,0 +1,15 @@ +package mate.academy.bookstore.dto.book; + +import java.math.BigDecimal; +import lombok.Data; + +@Data +public class BookDtoWithoutCategoryIds { + private Long id; + private String title; + private String author; + private String isbn; + private BigDecimal price; + private String description; + private String coverImage; +} diff --git a/src/main/java/mate/academy/bookstore/dto/book/BookRequestDto.java b/src/main/java/mate/academy/bookstore/dto/book/CreateBookRequestDto.java similarity index 93% rename from src/main/java/mate/academy/bookstore/dto/book/BookRequestDto.java rename to src/main/java/mate/academy/bookstore/dto/book/CreateBookRequestDto.java index ca2b1a6..d123fe1 100644 --- a/src/main/java/mate/academy/bookstore/dto/book/BookRequestDto.java +++ b/src/main/java/mate/academy/bookstore/dto/book/CreateBookRequestDto.java @@ -8,7 +8,7 @@ import org.hibernate.validator.constraints.ISBN; @Data -public class BookRequestDto { +public class CreateBookRequestDto { @NotBlank private String title; @NotBlank diff --git a/src/main/java/mate/academy/bookstore/dto/category/CategoryDto.java b/src/main/java/mate/academy/bookstore/dto/category/CategoryDto.java new file mode 100644 index 0000000..55a44d5 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/dto/category/CategoryDto.java @@ -0,0 +1,13 @@ +package mate.academy.bookstore.dto.category; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; + +public record CategoryDto( + Long id, + @NotBlank + @Size(min = 4, max = 24, message = "Category name must be 4 to 24 characters long") + String name, + String description +) { +} diff --git a/src/main/java/mate/academy/bookstore/exception/DuplicateEntityException.java b/src/main/java/mate/academy/bookstore/exception/DuplicateEntityException.java new file mode 100644 index 0000000..1129682 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/exception/DuplicateEntityException.java @@ -0,0 +1,7 @@ +package mate.academy.bookstore.exception; + +public class DuplicateEntityException extends RuntimeException { + public DuplicateEntityException(String message) { + super(message); + } +} diff --git a/src/main/java/mate/academy/bookstore/exception/GlobalExceptionHandler.java b/src/main/java/mate/academy/bookstore/exception/GlobalExceptionHandler.java index 77ebcc3..ecc64bb 100644 --- a/src/main/java/mate/academy/bookstore/exception/GlobalExceptionHandler.java +++ b/src/main/java/mate/academy/bookstore/exception/GlobalExceptionHandler.java @@ -38,6 +38,11 @@ protected ResponseEntity handleMethodRepository(DuplicateIsbnException e return getResponseEntity(HttpStatus.BAD_REQUEST, ex.getMessage()); } + @ExceptionHandler(DuplicateEntityException.class) + protected ResponseEntity handleMethodRepository(DuplicateEntityException ex) { + return getResponseEntity(HttpStatus.BAD_REQUEST, ex.getMessage()); + } + @ExceptionHandler(EntityNotFoundException.class) protected ResponseEntity handleMethodNotFound(EntityNotFoundException ex) { return getResponseEntity(HttpStatus.NOT_FOUND, ex.getMessage()); diff --git a/src/main/java/mate/academy/bookstore/mapper/BookMapper.java b/src/main/java/mate/academy/bookstore/mapper/BookMapper.java index b58036c..6ff1a92 100644 --- a/src/main/java/mate/academy/bookstore/mapper/BookMapper.java +++ b/src/main/java/mate/academy/bookstore/mapper/BookMapper.java @@ -1,17 +1,36 @@ package mate.academy.bookstore.mapper; +import java.util.Collections; +import java.util.stream.Collectors; import mate.academy.bookstore.config.MapperConfig; import mate.academy.bookstore.dto.book.BookDto; -import mate.academy.bookstore.dto.book.BookRequestDto; +import mate.academy.bookstore.dto.book.BookDtoWithoutCategoryIds; +import mate.academy.bookstore.dto.book.CreateBookRequestDto; import mate.academy.bookstore.model.Book; +import mate.academy.bookstore.model.Category; +import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; @Mapper(config = MapperConfig.class) public interface BookMapper { + @Mapping(target = "categories", ignore = true) BookDto toDto(Book book); @Mapping(target = "id", ignore = true) @Mapping(target = "deleted", ignore = true) - Book toModel(BookRequestDto requestDto); + Book toEntity(CreateBookRequestDto requestDto); + + BookDtoWithoutCategoryIds toDtoWithoutCategories(Book book); + + @AfterMapping + default void setCategoryIds(@MappingTarget BookDto bookDto, Book book) { + if (book.getCategories() == null) { + bookDto.setCategories(Collections.emptySet()); + } + bookDto.setCategories(book.getCategories().stream() + .map(Category::getId) + .collect(Collectors.toSet())); + } } diff --git a/src/main/java/mate/academy/bookstore/mapper/CategoryMapper.java b/src/main/java/mate/academy/bookstore/mapper/CategoryMapper.java new file mode 100644 index 0000000..cd17b75 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/mapper/CategoryMapper.java @@ -0,0 +1,13 @@ +package mate.academy.bookstore.mapper; + +import mate.academy.bookstore.config.MapperConfig; +import mate.academy.bookstore.dto.category.CategoryDto; +import mate.academy.bookstore.model.Category; +import org.mapstruct.Mapper; + +@Mapper(config = MapperConfig.class) +public interface CategoryMapper { + CategoryDto toDto(Category category); + + Category toEntity(CategoryDto categoryDto); +} diff --git a/src/main/java/mate/academy/bookstore/model/Book.java b/src/main/java/mate/academy/bookstore/model/Book.java index 86061a9..346ee69 100644 --- a/src/main/java/mate/academy/bookstore/model/Book.java +++ b/src/main/java/mate/academy/bookstore/model/Book.java @@ -2,11 +2,17 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -15,7 +21,7 @@ @Getter @Setter -@EqualsAndHashCode(of = {"id", "title", "author", "isbn"}) +@EqualsAndHashCode(of = {"id", "title", "author", "isbn", "categories"}) @Entity @SQLDelete(sql = "UPDATE books SET is_deleted = true WHERE id=?") @SQLRestriction(value = "is_deleted=false") @@ -40,6 +46,13 @@ public class Book { private String description; private String coverImage; + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "books_categories", + joinColumns = @JoinColumn(name = "book_id"), + inverseJoinColumns = @JoinColumn(name = "category_id") + ) + private Set categories = new HashSet<>(); @Column(nullable = false) private boolean isDeleted; diff --git a/src/main/java/mate/academy/bookstore/model/Category.java b/src/main/java/mate/academy/bookstore/model/Category.java new file mode 100644 index 0000000..c15dd4c --- /dev/null +++ b/src/main/java/mate/academy/bookstore/model/Category.java @@ -0,0 +1,25 @@ +package mate.academy.bookstore.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.SoftDelete; + +@Getter +@Setter +@Entity +@SoftDelete +@Table(name = "categories") +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(nullable = false, unique = true) + private String name; + private String description; +} diff --git a/src/main/java/mate/academy/bookstore/repository/book/BookRepository.java b/src/main/java/mate/academy/bookstore/repository/book/BookRepository.java index bd16ab7..665cb7a 100644 --- a/src/main/java/mate/academy/bookstore/repository/book/BookRepository.java +++ b/src/main/java/mate/academy/bookstore/repository/book/BookRepository.java @@ -1,9 +1,18 @@ package mate.academy.bookstore.repository.book; +import java.util.List; import mate.academy.bookstore.model.Book; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface BookRepository extends JpaRepository, JpaSpecificationExecutor { + @EntityGraph(attributePaths = {"categories"}) Book findBookByIsbn(String isbn); + + @Query("SELECT b FROM Book b LEFT JOIN FETCH b.categories c WHERE c.id = :categoryId") + List findAllBooksByCategoryId(@Param("categoryId") Long categoryId, Pageable pageable); } diff --git a/src/main/java/mate/academy/bookstore/repository/category/CategoryRepository.java b/src/main/java/mate/academy/bookstore/repository/category/CategoryRepository.java new file mode 100644 index 0000000..38b9454 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/repository/category/CategoryRepository.java @@ -0,0 +1,9 @@ +package mate.academy.bookstore.repository.category; + +import mate.academy.bookstore.model.Category; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CategoryRepository extends JpaRepository { + + Category findByName(String categoryName); +} diff --git a/src/main/java/mate/academy/bookstore/service/BookService.java b/src/main/java/mate/academy/bookstore/service/BookService.java index 63e0a47..6841aa3 100644 --- a/src/main/java/mate/academy/bookstore/service/BookService.java +++ b/src/main/java/mate/academy/bookstore/service/BookService.java @@ -2,12 +2,13 @@ import java.util.List; import mate.academy.bookstore.dto.book.BookDto; -import mate.academy.bookstore.dto.book.BookRequestDto; +import mate.academy.bookstore.dto.book.BookDtoWithoutCategoryIds; import mate.academy.bookstore.dto.book.BookSearchParametersDto; +import mate.academy.bookstore.dto.book.CreateBookRequestDto; import org.springframework.data.domain.Pageable; public interface BookService { - BookDto save(BookRequestDto requestDto); + BookDto save(CreateBookRequestDto requestDto); List findAll(Pageable pageable); @@ -15,7 +16,9 @@ public interface BookService { List search(BookSearchParametersDto parametersDto, Pageable pageable); - BookDto updateById(Long id, BookRequestDto requestDto); + BookDto updateById(Long id, CreateBookRequestDto requestDto); void delete(Long id); + + List getAllBookByCategoryId(Long id, Pageable pageable); } diff --git a/src/main/java/mate/academy/bookstore/service/CategoryService.java b/src/main/java/mate/academy/bookstore/service/CategoryService.java new file mode 100644 index 0000000..0754ba6 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/service/CategoryService.java @@ -0,0 +1,17 @@ +package mate.academy.bookstore.service; + +import java.util.List; +import mate.academy.bookstore.dto.category.CategoryDto; +import org.springframework.data.domain.Pageable; + +public interface CategoryService { + List findAll(Pageable pageable); + + CategoryDto getById(Long id); + + CategoryDto save(CategoryDto categoryDto); + + CategoryDto update(Long id, CategoryDto categoryDto); + + void delete(Long id); +} diff --git a/src/main/java/mate/academy/bookstore/service/impl/BookServiceImpl.java b/src/main/java/mate/academy/bookstore/service/impl/BookServiceImpl.java index 304af9c..6cb73cc 100644 --- a/src/main/java/mate/academy/bookstore/service/impl/BookServiceImpl.java +++ b/src/main/java/mate/academy/bookstore/service/impl/BookServiceImpl.java @@ -3,8 +3,9 @@ import java.util.List; import java.util.Objects; import mate.academy.bookstore.dto.book.BookDto; -import mate.academy.bookstore.dto.book.BookRequestDto; +import mate.academy.bookstore.dto.book.BookDtoWithoutCategoryIds; import mate.academy.bookstore.dto.book.BookSearchParametersDto; +import mate.academy.bookstore.dto.book.CreateBookRequestDto; import mate.academy.bookstore.exception.DuplicateIsbnException; import mate.academy.bookstore.exception.EntityNotFoundException; import mate.academy.bookstore.mapper.BookMapper; @@ -15,9 +16,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; -@Component +@Service public class BookServiceImpl implements BookService { private final BookRepository bookRepository; private final BookMapper bookMapper; @@ -32,13 +33,13 @@ public BookServiceImpl(BookRepository bookRepository, BookMapper bookMapper, } @Override - public BookDto save(BookRequestDto requestDto) { + public BookDto save(CreateBookRequestDto requestDto) { String isbn = requestDto.getIsbn(); if (bookRepository.findBookByIsbn(isbn) != null) { throw new DuplicateIsbnException("Book with ISBN " + isbn + " already exists"); } - Book book = bookMapper.toModel(requestDto); + Book book = bookMapper.toEntity(requestDto); Book savedBook = bookRepository.save(book); return bookMapper.toDto(savedBook); } @@ -56,7 +57,7 @@ public BookDto findById(Long id) { return bookMapper.toDto(book); } - public BookDto updateById(Long id, BookRequestDto requestDto) { + public BookDto updateById(Long id, CreateBookRequestDto requestDto) { Book existingBook = bookRepository.findById(id).orElseThrow( () -> new EntityNotFoundException("Book not found by id " + id)); @@ -66,7 +67,7 @@ public BookDto updateById(Long id, BookRequestDto requestDto) { throw new DuplicateIsbnException("Book with ISBN " + requestIsbn + " already exists"); } - Book book = bookMapper.toModel(requestDto); + Book book = bookMapper.toEntity(requestDto); book.setId(id); Book savedBook = bookRepository.save(book); return bookMapper.toDto(savedBook); @@ -85,4 +86,11 @@ public List search(BookSearchParametersDto params, Pageable pageable) { .map(bookMapper::toDto) .toList(); } + + @Override + public List getAllBookByCategoryId(Long id, Pageable pageable) { + return bookRepository.findAllBooksByCategoryId(id, pageable).stream() + .map(bookMapper::toDtoWithoutCategories) + .toList(); + } } diff --git a/src/main/java/mate/academy/bookstore/service/impl/CategoryServiceImpl.java b/src/main/java/mate/academy/bookstore/service/impl/CategoryServiceImpl.java new file mode 100644 index 0000000..a1c4b10 --- /dev/null +++ b/src/main/java/mate/academy/bookstore/service/impl/CategoryServiceImpl.java @@ -0,0 +1,74 @@ +package mate.academy.bookstore.service.impl; + +import java.util.List; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import mate.academy.bookstore.dto.category.CategoryDto; +import mate.academy.bookstore.exception.DuplicateEntityException; +import mate.academy.bookstore.exception.EntityNotFoundException; +import mate.academy.bookstore.mapper.CategoryMapper; +import mate.academy.bookstore.model.Category; +import mate.academy.bookstore.repository.category.CategoryRepository; +import mate.academy.bookstore.service.CategoryService; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +@RequiredArgsConstructor +@Service +public class CategoryServiceImpl implements CategoryService { + private final CategoryRepository categoryRepository; + private final CategoryMapper categoryMapper; + + @Override + public List findAll(Pageable pageable) { + return categoryRepository.findAll(pageable).stream() + .map(categoryMapper::toDto) + .toList(); + } + + @Override + public CategoryDto getById(Long id) { + Category category = findCategoryByIdOrElseThrow(id); + return categoryMapper.toDto(category); + } + + @Override + public CategoryDto save(CategoryDto categoryDto) { + String name = categoryDto.name(); + if (categoryRepository.findByName(name) != null) { + throw new DuplicateEntityException("Category with name " + name + " already exists"); + } + + Category category = categoryMapper.toEntity(categoryDto); + Category savedCategory = categoryRepository.save(category); + return categoryMapper.toDto(savedCategory); + } + + @Override + public CategoryDto update(Long id, CategoryDto categoryDto) { + Category existingCategory = findCategoryByIdOrElseThrow(id); + + String categoryName = categoryDto.name(); + if (!Objects.equals(existingCategory.getName(), categoryName) + && categoryRepository.findByName(categoryName) != null) { + throw new DuplicateEntityException( + "Category with name " + categoryName + " already exists"); + } + + Category category = categoryMapper.toEntity(categoryDto); + category.setId(id); + Category savedCategory = categoryRepository.save(category); + return categoryMapper.toDto(savedCategory); + } + + @Override + public void delete(Long id) { + findCategoryByIdOrElseThrow(id); + categoryRepository.deleteById(id); + } + + private Category findCategoryByIdOrElseThrow(Long id) { + return categoryRepository.findById(id).orElseThrow( + () -> new EntityNotFoundException("Category not found by id " + id)); + } +} diff --git a/src/main/java/mate/academy/bookstore/service/impl/UserServiceImpl.java b/src/main/java/mate/academy/bookstore/service/impl/UserServiceImpl.java index dc9f322..9ed5b70 100644 --- a/src/main/java/mate/academy/bookstore/service/impl/UserServiceImpl.java +++ b/src/main/java/mate/academy/bookstore/service/impl/UserServiceImpl.java @@ -12,10 +12,10 @@ import mate.academy.bookstore.repository.user.UserRepository; import mate.academy.bookstore.service.UserService; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; @RequiredArgsConstructor -@Component +@Service public class UserServiceImpl implements UserService { private final UserRepository userRepository; private final UserMapper userMapper; diff --git a/src/main/resources/db/changelog/changes/08-create-category-table.yaml b/src/main/resources/db/changelog/changes/08-create-category-table.yaml new file mode 100644 index 0000000..29c5974 --- /dev/null +++ b/src/main/resources/db/changelog/changes/08-create-category-table.yaml @@ -0,0 +1,31 @@ +databaseChangeLog: + - changeSet: + id: create-categories-table + author: nklimovych + changes: + - createTable: + tableName: categories + columns: + - column: + name: id + type: bigint + autoIncrement: true + constraints: + primaryKey: true + - column: + name: name + type: varchar(64) + constraints: + nullable: false + unique: true + - column: + name: description + type: varchar(255) + constraints: + nullable: true + - column: + name: deleted + type: bit + defaultValueBoolean: false + constraints: + nullable: false diff --git a/src/main/resources/db/changelog/changes/09-create-books-categories-table.yaml b/src/main/resources/db/changelog/changes/09-create-books-categories-table.yaml new file mode 100644 index 0000000..9bb6648 --- /dev/null +++ b/src/main/resources/db/changelog/changes/09-create-books-categories-table.yaml @@ -0,0 +1,22 @@ +databaseChangeLog: + - changeSet: + id: create-books-categories-table + author: nklimovych + changes: + - createTable: + tableName: books_categories + columns: + - column: + name: book_id + type: bigint + constraints: + nullable: false + references: books(id) + foreignKeyName: fk_books_category_id + - column: + name: category_id + type: bigint + constraints: + nullable: false + references: categories(id) + foreignKeyName: fk_categories_book_id diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 9794f55..9fb74f6 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -13,3 +13,7 @@ databaseChangeLog: file: db/changelog/changes/06-insert-admin-user-into-database.yaml - include: file: db/changelog/changes/07-assign-admin-user-to-role-admin.yaml + - include: + file: db/changelog/changes/08-create-category-table.yaml + - include: + file: db/changelog/changes/09-create-books-categories-table.yaml