diff --git a/src/main/java/com/bookstore/controller/BookController.java b/src/main/java/com/bookstore/controller/BookController.java index efe6dee..0ef3e7f 100644 --- a/src/main/java/com/bookstore/controller/BookController.java +++ b/src/main/java/com/bookstore/controller/BookController.java @@ -9,6 +9,7 @@ import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.security.access.prepost.PreAuthorize; @@ -46,7 +47,7 @@ public BookDto getBookById(@PathVariable Long id) { @GetMapping("/search") @PreAuthorize("hasRole('USER')") @Operation(summary = "Search books", description = "Search book by specific search parameters") - public List searchBooks(BookSearchParametersDto searchParameters) { + public Page searchBooks(BookSearchParametersDto searchParameters) { return bookService.searchBooks(searchParameters); } diff --git a/src/main/java/com/bookstore/controller/ShoppingCartController.java b/src/main/java/com/bookstore/controller/ShoppingCartController.java new file mode 100644 index 0000000..96139c3 --- /dev/null +++ b/src/main/java/com/bookstore/controller/ShoppingCartController.java @@ -0,0 +1,79 @@ +package com.bookstore.controller; + +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemUpdateDto; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import com.bookstore.model.User; +import com.bookstore.service.ShoppingCartService; +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 org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +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; + +@Tag(name = "Shopping cart management", description = "Endpoints for managing shopping carts") +@RequiredArgsConstructor +@RestController +@RequestMapping(value = "/api/cart") +public class ShoppingCartController { + private final ShoppingCartService shoppingCartService; + + @GetMapping(value = "/all") + @PreAuthorize("hasRole('ADMIN')") + @Operation(summary = "Get all shopping carts", + description = "Get all shopping carts only for admins") + public List getAll(Pageable pageable) { + return shoppingCartService.findAll(pageable); + } + + @GetMapping + @PreAuthorize("hasRole('USER')") + @Operation(summary = "Retrieve user's shopping cart", + description = "Retrieve user's shopping cart") + public ShoppingCartDto getShoppingCartByUser(Authentication authentication) { + User user = (User) authentication.getPrincipal(); + return shoppingCartService.getByUserId(user.getId()); + } + + @PostMapping + @PreAuthorize("hasRole('USER')") + @Operation(summary = "Add book to the shopping cart", + description = "Add book to the shopping cart") + public ShoppingCartDto addBookToTheCart(Authentication authentication, + @RequestBody @Valid + CartItemCreateDto cartItemCreateDto) { + User user = (User) authentication.getPrincipal(); + return shoppingCartService.saveBookToTheCart(user.getId(), cartItemCreateDto); + } + + @PutMapping(value = "/cart-items/{cartItemId}") + @PreAuthorize("hasRole('USER')") + @Operation(summary = "Update quantity of a book in the shopping cart", + description = "Update quantity of a book in the shopping cart") + public ShoppingCartDto updateBookInTheCart(Authentication authentication, + @PathVariable Long cartItemId, + @RequestBody @Valid + CartItemUpdateDto cartItemUpdateDto) { + User user = (User) authentication.getPrincipal(); + return shoppingCartService.update(user.getId(), cartItemId, cartItemUpdateDto); + } + + @DeleteMapping(value = "/cart-items/{cartItemId}") + @PreAuthorize("hasRole('USER')") + @Operation(summary = "Remove a book from the shopping cart", + description = "Remove a book from the shopping cart") + public void removeBookFromTheCart(@PathVariable Long cartItemId) { + shoppingCartService.deleteCartItemFromTheCart(cartItemId); + } +} diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java new file mode 100644 index 0000000..49be3c2 --- /dev/null +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java @@ -0,0 +1,14 @@ +package com.bookstore.dto.cartitem; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class CartItemCreateDto { + @NotNull + private Long bookId; + @NotNull + @Min(1) + private int quantity; +} diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java new file mode 100644 index 0000000..0714f6b --- /dev/null +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java @@ -0,0 +1,11 @@ +package com.bookstore.dto.cartitem; + +import lombok.Data; + +@Data +public class CartItemResponseDto { + private Long id; + private Long bookId; + private String bookTitle; + private int quantity; +} diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java new file mode 100644 index 0000000..71d0130 --- /dev/null +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java @@ -0,0 +1,12 @@ +package com.bookstore.dto.cartitem; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class CartItemUpdateDto { + @NotNull + @Min(1) + private int quantity; +} diff --git a/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java b/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java new file mode 100644 index 0000000..1861f9f --- /dev/null +++ b/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java @@ -0,0 +1,11 @@ +package com.bookstore.dto.shoppingcart; + +import com.bookstore.dto.cartitem.CartItemResponseDto; +import java.util.Set; +import lombok.Data; + +@Data +public class ShoppingCartDto { + private Long userId; + private Set cartItemsDto; +} diff --git a/src/main/java/com/bookstore/mapper/CartItemMapper.java b/src/main/java/com/bookstore/mapper/CartItemMapper.java new file mode 100644 index 0000000..8b311da --- /dev/null +++ b/src/main/java/com/bookstore/mapper/CartItemMapper.java @@ -0,0 +1,22 @@ +package com.bookstore.mapper; + +import com.bookstore.config.MapperConfig; +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemResponseDto; +import com.bookstore.model.Book; +import com.bookstore.model.CartItem; +import com.bookstore.model.ShoppingCart; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class) +public interface CartItemMapper { + @Mapping(target = "id", ignore = true) + CartItem toEntity(CartItemCreateDto cartItemCreateDto, + Book book, + ShoppingCart shoppingCart); + + @Mapping(source = "cartItem.book.id", target = "bookId") + @Mapping(source = "cartItem.book.title", target = "bookTitle") + CartItemResponseDto toDto(CartItem cartItem); +} diff --git a/src/main/java/com/bookstore/mapper/ShoppingCartMapper.java b/src/main/java/com/bookstore/mapper/ShoppingCartMapper.java new file mode 100644 index 0000000..166b143 --- /dev/null +++ b/src/main/java/com/bookstore/mapper/ShoppingCartMapper.java @@ -0,0 +1,14 @@ +package com.bookstore.mapper; + +import com.bookstore.config.MapperConfig; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import com.bookstore.model.ShoppingCart; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapperConfig.class, uses = CartItemMapper.class) +public interface ShoppingCartMapper { + @Mapping(source = "user.id", target = "userId") + @Mapping(source = "cartItems", target = "cartItemsDto") + ShoppingCartDto toDto(ShoppingCart shoppingCart); +} diff --git a/src/main/java/com/bookstore/model/CartItem.java b/src/main/java/com/bookstore/model/CartItem.java new file mode 100644 index 0000000..e7fc6d1 --- /dev/null +++ b/src/main/java/com/bookstore/model/CartItem.java @@ -0,0 +1,32 @@ +package com.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.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@EqualsAndHashCode +@Entity +@Table(name = "cart_items") +public class CartItem { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @ManyToOne + @JoinColumn(name = "shopping_cart_id", nullable = false) + private ShoppingCart shoppingCart; + @ManyToOne + @JoinColumn(name = "book_id", nullable = false) + private Book book; + @Column(nullable = false) + private int quantity; +} diff --git a/src/main/java/com/bookstore/model/ShoppingCart.java b/src/main/java/com/bookstore/model/ShoppingCart.java new file mode 100644 index 0000000..e593662 --- /dev/null +++ b/src/main/java/com/bookstore/model/ShoppingCart.java @@ -0,0 +1,40 @@ +package com.bookstore.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.Table; +import java.util.Set; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.hibernate.annotations.SQLDelete; + +@Getter +@Setter +@EqualsAndHashCode +@Entity +@SQLDelete(sql = "UPDATE shopping_carts SET is_deleted=true WHERE id=?") +@Table(name = "shopping_carts") +public class ShoppingCart { + @Id + private Long id; + @OneToOne + @MapsId + @PrimaryKeyJoinColumn(name = "user_id") + private User user; + @ToString.Exclude + @EqualsAndHashCode.Exclude + @OneToMany(mappedBy = "shoppingCart", cascade = CascadeType.ALL, orphanRemoval = true) + private Set cartItems; + + public void addCartItemToSet(CartItem cartItem) { + cartItems.add(cartItem); + cartItem.setShoppingCart(this); + } +} diff --git a/src/main/java/com/bookstore/repository/cartitem/CartItemRepository.java b/src/main/java/com/bookstore/repository/cartitem/CartItemRepository.java new file mode 100644 index 0000000..6f20f9c --- /dev/null +++ b/src/main/java/com/bookstore/repository/cartitem/CartItemRepository.java @@ -0,0 +1,7 @@ +package com.bookstore.repository.cartitem; + +import com.bookstore.model.CartItem; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CartItemRepository extends JpaRepository { +} diff --git a/src/main/java/com/bookstore/repository/shoppingcart/ShoppingCartRepository.java b/src/main/java/com/bookstore/repository/shoppingcart/ShoppingCartRepository.java new file mode 100644 index 0000000..5fd0119 --- /dev/null +++ b/src/main/java/com/bookstore/repository/shoppingcart/ShoppingCartRepository.java @@ -0,0 +1,17 @@ +package com.bookstore.repository.shoppingcart; + +import com.bookstore.model.ShoppingCart; +import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ShoppingCartRepository extends JpaRepository { + + @EntityGraph(attributePaths = {"cartItems", "cartItems.book"}) + Page findAll(Pageable pageable); + + @EntityGraph(attributePaths = {"cartItems", "cartItems.book"}) + Optional findByUserId(Long id); +} diff --git a/src/main/java/com/bookstore/service/BookService.java b/src/main/java/com/bookstore/service/BookService.java index 5321645..95147d4 100644 --- a/src/main/java/com/bookstore/service/BookService.java +++ b/src/main/java/com/bookstore/service/BookService.java @@ -5,6 +5,7 @@ import com.bookstore.dto.book.BookSearchParametersDto; import com.bookstore.dto.book.CreateBookRequestDto; import java.util.List; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface BookService { @@ -18,7 +19,7 @@ public interface BookService { void deleteBookById(Long id); - List searchBooks(BookSearchParametersDto searchParameters); + Page searchBooks(BookSearchParametersDto searchParameters); List findAllByCategoryId(Long categoryId, Pageable pageable); } diff --git a/src/main/java/com/bookstore/service/ShoppingCartService.java b/src/main/java/com/bookstore/service/ShoppingCartService.java new file mode 100644 index 0000000..56277cf --- /dev/null +++ b/src/main/java/com/bookstore/service/ShoppingCartService.java @@ -0,0 +1,19 @@ +package com.bookstore.service; + +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemUpdateDto; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import java.util.List; +import org.springframework.data.domain.Pageable; + +public interface ShoppingCartService { + List findAll(Pageable pageable); + + ShoppingCartDto getByUserId(Long id); + + ShoppingCartDto saveBookToTheCart(Long id, CartItemCreateDto cartItemCreateDto); + + ShoppingCartDto update(Long id, Long cartItemId, CartItemUpdateDto cartItemUpdateDto); + + void deleteCartItemFromTheCart(Long id); +} diff --git a/src/main/java/com/bookstore/service/impl/BookServiceImpl.java b/src/main/java/com/bookstore/service/impl/BookServiceImpl.java index adf8f5a..82a1563 100644 --- a/src/main/java/com/bookstore/service/impl/BookServiceImpl.java +++ b/src/main/java/com/bookstore/service/impl/BookServiceImpl.java @@ -15,6 +15,8 @@ import java.util.List; import java.util.Set; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; @@ -73,12 +75,13 @@ public void deleteBookById(Long id) { } @Override - public List searchBooks(BookSearchParametersDto searchParameters) { + public Page searchBooks(BookSearchParametersDto searchParameters) { Specification bookSpecification = bookSpecificationBuilder.build(searchParameters); - return bookRepository.findAll(bookSpecification) + List bookDtos = bookRepository.findAll(bookSpecification) .stream() .map(bookMapper::toDto) .toList(); + return new PageImpl<>(bookDtos, Pageable.ofSize(10), bookDtos.size()); } @Override diff --git a/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java b/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java new file mode 100644 index 0000000..b100872 --- /dev/null +++ b/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java @@ -0,0 +1,88 @@ +package com.bookstore.service.impl; + +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemUpdateDto; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import com.bookstore.exception.EntityNotFoundException; +import com.bookstore.mapper.CartItemMapper; +import com.bookstore.mapper.ShoppingCartMapper; +import com.bookstore.model.Book; +import com.bookstore.model.CartItem; +import com.bookstore.model.ShoppingCart; +import com.bookstore.model.User; +import com.bookstore.repository.book.BookRepository; +import com.bookstore.repository.cartitem.CartItemRepository; +import com.bookstore.repository.shoppingcart.ShoppingCartRepository; +import com.bookstore.repository.user.UserRepository; +import com.bookstore.service.ShoppingCartService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class ShoppingCartServiceImpl implements ShoppingCartService { + private final ShoppingCartRepository shoppingCartRepository; + private final ShoppingCartMapper shoppingCartMapper; + private final UserRepository userRepository; + private final CartItemMapper cartItemMapper; + private final CartItemRepository cartItemRepository; + private final BookRepository bookRepository; + + @Override + public List findAll(Pageable pageable) { + return shoppingCartRepository.findAll(pageable) + .stream() + .map(shoppingCartMapper::toDto) + .toList(); + } + + @Override + public ShoppingCartDto getByUserId(Long id) { + return shoppingCartMapper.toDto(getShoppingCartByUserId(id)); + } + + @Override + public ShoppingCartDto saveBookToTheCart(Long userId, CartItemCreateDto cartItemCreateDto) { + ShoppingCart shoppingCart = getShoppingCartByUserId(userId); + Book book = bookRepository.findById(cartItemCreateDto.getBookId()).orElseThrow(() -> + new EntityNotFoundException( + "Can't find a book in DB by id: " + cartItemCreateDto.getBookId() + )); + CartItem cartItem = cartItemMapper.toEntity(cartItemCreateDto, book, shoppingCart); + cartItemRepository.save(cartItem); + shoppingCart.addCartItemToSet(cartItem); + return shoppingCartMapper.toDto(getShoppingCartByUserId(userId)); + } + + @Override + public ShoppingCartDto update(Long userId, + Long cartItemId, + CartItemUpdateDto cartItemUpdateDto) { + CartItem cartItem = cartItemRepository.findById(cartItemId) + .orElseThrow(() -> + new EntityNotFoundException( + "Can't find a cart item in DB by id: " + cartItemId + )); + cartItem.setQuantity(cartItemUpdateDto.getQuantity()); + cartItemRepository.save(cartItem); + return shoppingCartMapper.toDto(getShoppingCartByUserId(userId)); + } + + @Override + public void deleteCartItemFromTheCart(Long id) { + cartItemRepository.deleteById(id); + } + + private ShoppingCart getShoppingCartByUserId(Long id) { + User user = userRepository.findById(id) + .orElseThrow(() -> + new EntityNotFoundException("Can't find user in DB by id: " + id)); + return shoppingCartRepository.findByUserId(user.getId()) + .orElseThrow(() -> + new EntityNotFoundException( + "Can't find a shopping cart by id: " + user.getId() + )); + } +} diff --git a/src/main/java/com/bookstore/service/impl/UserServiceImpl.java b/src/main/java/com/bookstore/service/impl/UserServiceImpl.java index 83e4f5c..d932eb2 100644 --- a/src/main/java/com/bookstore/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bookstore/service/impl/UserServiceImpl.java @@ -5,8 +5,10 @@ import com.bookstore.exception.RegistrationException; import com.bookstore.mapper.UserMapper; import com.bookstore.model.Role; +import com.bookstore.model.ShoppingCart; import com.bookstore.model.User; import com.bookstore.repository.role.RoleRepository; +import com.bookstore.repository.shoppingcart.ShoppingCartRepository; import com.bookstore.repository.user.UserRepository; import com.bookstore.service.UserService; import java.util.HashSet; @@ -22,6 +24,7 @@ public class UserServiceImpl implements UserService { private final RoleRepository roleRepository; private final PasswordEncoder passwordEncoder; private final UserMapper userMapper; + private final ShoppingCartRepository shoppingCartRepository; @Override public UserResponseDto register(UserRegistrationRequestDto requestDto) @@ -42,6 +45,9 @@ public UserResponseDto register(UserRegistrationRequestDto requestDto) Set roles = new HashSet<>(); roles.add(userRole); user.setRoles(roles); + ShoppingCart shoppingCart = new ShoppingCart(); + shoppingCart.setUser(user); + shoppingCartRepository.save(shoppingCart); return userMapper.toUserResponse(userRepository.save(user)); } } diff --git a/src/main/resources/db/changelog/changes/09-create-shopping_carts-table.yaml b/src/main/resources/db/changelog/changes/09-create-shopping_carts-table.yaml new file mode 100644 index 0000000..f841dad --- /dev/null +++ b/src/main/resources/db/changelog/changes/09-create-shopping_carts-table.yaml @@ -0,0 +1,17 @@ +databaseChangeLog: + - changeSet: + id: create-shopping_carts-table + author: fmIst0 + changes: + - createTable: + tableName: shopping_carts + columns: + - column: + name: user_id + type: bigint + constraints: + foreignKeyName: fk_shopping_carts_users + referencedTableName: users + referencedColumnNames: id + nullable: false + primaryKey: true \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/10-create-cart-items-table.yaml b/src/main/resources/db/changelog/changes/10-create-cart-items-table.yaml new file mode 100644 index 0000000..129e596 --- /dev/null +++ b/src/main/resources/db/changelog/changes/10-create-cart-items-table.yaml @@ -0,0 +1,42 @@ +databaseChangeLog: + - changeSet: + id: create-cart_items-table + author: fmIst0 + changes: + - createTable: + tableName: cart_items + columns: + - column: + name: id + type: bigint + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: shopping_cart_id + type: bigint + constraints: + nullable: false + foreignKeyName: fk_cart_items_shopping_carts + referencedTableName: shopping_carts + referencedColumnNames: user_id + - column: + name: book_id + type: bigint + constraints: + nullable: false + foreignKeyName: fk_cart_items_books + referencedTableName: books + referencedColumnNames: id + - column: + name: quantity + type: integer + constraints: + nullable: false + - column: + name: is_deleted + type: boolean + defaultValueBoolean: false + constraints: + nullable: false \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/11-drop-column-is_deleted-in-cart_items-table.yaml b/src/main/resources/db/changelog/changes/11-drop-column-is_deleted-in-cart_items-table.yaml new file mode 100644 index 0000000..22435ed --- /dev/null +++ b/src/main/resources/db/changelog/changes/11-drop-column-is_deleted-in-cart_items-table.yaml @@ -0,0 +1,8 @@ +databaseChangeLog: + - changeSet: + id: drop-column-is_deleted-in-cart_items-table + author: fmIst0 + changes: + - dropColumn: + tableName: cart_items + columnName: is_deleted \ No newline at end of file diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 8f3ad47..538a54f 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -14,4 +14,10 @@ databaseChangeLog: - include: file: db/changelog/changes/07-create-categories-table.yaml - include: - file: db/changelog/changes/08-create-books-categories-table.yaml \ No newline at end of file + file: db/changelog/changes/08-create-books-categories-table.yaml + - include: + file: db/changelog/changes/09-create-shopping_carts-table.yaml + - include: + file: db/changelog/changes/10-create-cart-items-table.yaml + - include: + file: db/changelog/changes/11-drop-column-is_deleted-in-cart_items-table.yaml \ No newline at end of file