-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* [feat] 조회하고자 하는 카트가 없을 때 발생시킬 예외 구현 * [feat] 구매자의 카트를 조회하는 Dao * [feat] 카트 조회 앤드포인트 * [feat] 카트를 조회할 수 있는 Dao를 Redis를 이용해서 구현 (#135) * [test] menu 더미를 저장하고 반환하는 메서드 추가 및 상점을 24시간 열려있도록 수정 * [feat] getter 및 생성자 추가 * [feat] redis용 dao를 임시로 inMemoryCartRepository를 이용해서 구현 * [test] RedisCartDao 테스트코드 추가 * [feat] CartItemInfo에도 getter 추가 * [fix] 테스트 이후 데이터를 롤백시키기 위해 @transactional 추가 * [fix] CartResponse의 amount를 Integer로 수정 * [feat] Jpa를 이용한 카트 조회 dao --------- Co-authored-by: 김현욱 <43038815+Hyeon-Uk@users.noreply.github.com>
- Loading branch information
Showing
9 changed files
with
358 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
src/main/java/camp/woowak/lab/cart/exception/NotFoundCartException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package camp.woowak.lab.cart.exception; | ||
|
||
import camp.woowak.lab.common.exception.BadRequestException; | ||
|
||
public class NotFoundCartException extends BadRequestException { | ||
public NotFoundCartException(String message) { | ||
super(CartErrorCode.NOT_FOUND, message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package camp.woowak.lab.web.dao.cart; | ||
|
||
import java.util.UUID; | ||
|
||
import camp.woowak.lab.web.dto.response.CartResponse; | ||
|
||
public interface CartDao { | ||
/** | ||
* @throws camp.woowak.lab.cart.exception.NotFoundCartException | ||
*/ | ||
CartResponse findByCustomerId(UUID customerId); | ||
} |
57 changes: 57 additions & 0 deletions
57
src/main/java/camp/woowak/lab/web/dao/cart/JpaCartDao.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package camp.woowak.lab.web.dao.cart; | ||
|
||
import static camp.woowak.lab.cart.persistence.jpa.entity.QCartEntity.*; | ||
import static camp.woowak.lab.cart.persistence.jpa.entity.QCartItemEntity.*; | ||
import static camp.woowak.lab.menu.domain.QMenu.*; | ||
import static camp.woowak.lab.store.domain.QStore.*; | ||
|
||
import java.util.UUID; | ||
|
||
import org.springframework.stereotype.Repository; | ||
|
||
import com.querydsl.core.types.Projections; | ||
import com.querydsl.core.types.dsl.BooleanExpression; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
|
||
import camp.woowak.lab.web.dto.response.CartResponse; | ||
|
||
@Repository | ||
public class JpaCartDao implements CartDao { | ||
private final JPAQueryFactory queryFactory; | ||
|
||
public JpaCartDao(JPAQueryFactory queryFactory) { | ||
this.queryFactory = queryFactory; | ||
} | ||
|
||
@Override | ||
public CartResponse findByCustomerId(UUID customerId) { | ||
CartResponse cartResponse = queryFactory | ||
.select(Projections.constructor(CartResponse.class, | ||
store.id, | ||
store.name, | ||
store.minOrderPrice, | ||
Projections.list( | ||
Projections.constructor(CartResponse.CartItemInfo.class, | ||
menu.id, | ||
menu.name, | ||
menu.price, | ||
cartItemEntity.amount, | ||
menu.stockCount | ||
) | ||
) | ||
)) | ||
.from(cartEntity) | ||
.leftJoin(cartEntity.cartItems, cartItemEntity) | ||
.join(menu).on(menu.id.eq(cartItemEntity.menuId)) | ||
.join(store).on(store.id.eq(cartItemEntity.storeId)) | ||
.where( | ||
eqCustomerId(customerId) | ||
) | ||
.fetchOne(); | ||
return cartResponse; | ||
} | ||
|
||
private BooleanExpression eqCustomerId(UUID customerId) { | ||
return cartEntity.customerId.eq(customerId); | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
src/main/java/camp/woowak/lab/web/dao/cart/RedisCartDao.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package camp.woowak.lab.web.dao.cart; | ||
|
||
import static camp.woowak.lab.menu.domain.QMenu.*; | ||
import static camp.woowak.lab.store.domain.QStore.*; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.UUID; | ||
import java.util.stream.Collectors; | ||
|
||
import org.springframework.beans.factory.annotation.Qualifier; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import com.querydsl.core.Tuple; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
|
||
import camp.woowak.lab.cart.domain.Cart; | ||
import camp.woowak.lab.cart.repository.CartRepository; | ||
import camp.woowak.lab.web.dto.response.CartResponse; | ||
|
||
@Repository | ||
public class RedisCartDao implements CartDao { | ||
private final CartRepository cartRepository; | ||
private final JPAQueryFactory queryFactory; | ||
|
||
public RedisCartDao(@Qualifier("inMemoryCartRepository") CartRepository cartRepository, | ||
JPAQueryFactory queryFactory) { | ||
this.cartRepository = cartRepository; | ||
this.queryFactory = queryFactory; | ||
} | ||
|
||
@Override | ||
public CartResponse findByCustomerId(UUID customerId) { | ||
Optional<Cart> optionalCart = cartRepository.findByCustomerId(customerId.toString()); | ||
if (optionalCart.isEmpty()) { | ||
return new CartResponse(); | ||
} | ||
Cart cart = optionalCart.get(); | ||
|
||
if (cart.getCartItems().isEmpty()) { | ||
return new CartResponse(); | ||
} | ||
|
||
Long sId = cart.getCartItems().stream().findAny().get().getStoreId(); | ||
Map<Long, Integer> menuIdsCount = new HashMap<>(); | ||
Set<Long> menuIds = cart.getCartItems().stream() | ||
.map((cartItem) -> { | ||
int amount = cartItem.getAmount(); | ||
menuIdsCount.put(cartItem.getMenuId(), amount); | ||
return cartItem.getMenuId(); | ||
}) | ||
.collect(Collectors.toSet()); | ||
|
||
List<Tuple> results = queryFactory | ||
.select( | ||
store.id, | ||
store.name, | ||
store.minOrderPrice, | ||
menu.id, | ||
menu.name, | ||
menu.price, | ||
menu.stockCount | ||
) | ||
.from(store) | ||
.join(menu).on(menu.store.id.eq(store.id)) | ||
.where(store.id.eq(sId).and(menu.id.in(menuIds))) | ||
.fetch(); | ||
|
||
if (results.isEmpty()) { | ||
return null; // 또는 적절한 예외 처리 | ||
} | ||
|
||
Tuple firstResult = results.get(0); | ||
Long storeId = firstResult.get(store.id); | ||
String storeName = firstResult.get(store.name); | ||
Integer minOrderPrice = firstResult.get(store.minOrderPrice); | ||
|
||
List<CartResponse.CartItemInfo> menuList = results.stream() | ||
.map(tuple -> new CartResponse.CartItemInfo( | ||
tuple.get(menu.id), | ||
tuple.get(menu.name), | ||
tuple.get(menu.price), | ||
menuIdsCount.get(tuple.get(menu.id)), // amount 대신 stockCount 사용 | ||
tuple.get(menu.stockCount) | ||
)) | ||
.collect(Collectors.toList()); | ||
|
||
return new CartResponse(storeId, storeName, minOrderPrice, menuList); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/main/java/camp/woowak/lab/web/dto/response/CartResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package camp.woowak.lab.web.dto.response; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import lombok.Getter; | ||
|
||
@Getter | ||
public class CartResponse { | ||
private Long storeId; | ||
private String storeName; | ||
private Integer minOrderPrice; | ||
private List<CartItemInfo> menus = new ArrayList<>(); | ||
|
||
public CartResponse() { | ||
} | ||
|
||
public CartResponse(Long storId, String storeName, Integer minOrderPrice, List<CartItemInfo> menus) { | ||
this.storeId = storId; | ||
this.storeName = storeName; | ||
this.minOrderPrice = minOrderPrice; | ||
this.menus = menus; | ||
} | ||
|
||
@Getter | ||
public static class CartItemInfo { | ||
private Long menuId; | ||
private String menuName; | ||
private Long menuPrice; | ||
private Integer amount; | ||
private Long leftAmount; | ||
|
||
public CartItemInfo(Long menuId, String menuName, Long menuPrice, Integer amount, Long leftAmount) { | ||
this.menuId = menuId; | ||
this.menuName = menuName; | ||
this.menuPrice = menuPrice; | ||
this.amount = amount; | ||
this.leftAmount = leftAmount; | ||
} | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
src/test/java/camp/woowak/lab/web/dao/cart/RedisCartDaoTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package camp.woowak.lab.web.dao.cart; | ||
|
||
import static org.assertj.core.api.Assertions.*; | ||
|
||
import java.util.List; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import camp.woowak.lab.cart.domain.Cart; | ||
import camp.woowak.lab.cart.repository.CartRepository; | ||
import camp.woowak.lab.customer.domain.Customer; | ||
import camp.woowak.lab.customer.repository.CustomerRepository; | ||
import camp.woowak.lab.menu.domain.Menu; | ||
import camp.woowak.lab.menu.domain.MenuCategory; | ||
import camp.woowak.lab.menu.repository.MenuCategoryRepository; | ||
import camp.woowak.lab.menu.repository.MenuRepository; | ||
import camp.woowak.lab.order.repository.OrderRepository; | ||
import camp.woowak.lab.payaccount.repository.PayAccountRepository; | ||
import camp.woowak.lab.store.domain.Store; | ||
import camp.woowak.lab.store.repository.StoreCategoryRepository; | ||
import camp.woowak.lab.store.repository.StoreRepository; | ||
import camp.woowak.lab.vendor.repository.VendorRepository; | ||
import camp.woowak.lab.web.dao.store.StoreDummiesFixture; | ||
import camp.woowak.lab.web.dto.response.CartResponse; | ||
|
||
@SpringBootTest | ||
@Transactional | ||
class RedisCartDaoTest extends StoreDummiesFixture { | ||
private final CartRepository cartRepository; | ||
@Autowired | ||
private RedisCartDao redisCartDao; | ||
|
||
@Autowired | ||
public RedisCartDaoTest(StoreRepository storeRepository, | ||
StoreCategoryRepository storeCategoryRepository, | ||
VendorRepository vendorRepository, | ||
PayAccountRepository payAccountRepository, | ||
OrderRepository orderRepository, | ||
CustomerRepository customerRepository, | ||
MenuRepository menuRepository, | ||
MenuCategoryRepository menuCategoryRepository, | ||
CartRepository cartRepository) { | ||
super(storeRepository, storeCategoryRepository, vendorRepository, payAccountRepository, orderRepository, | ||
customerRepository, menuRepository, menuCategoryRepository); | ||
this.cartRepository = cartRepository; | ||
} | ||
|
||
private Customer customer; | ||
private Store store; | ||
private MenuCategory menuCategory; | ||
private List<Menu> menus; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
customer = createDummyCustomers(1).get(0); | ||
store = createDummyStores(1).get(0); | ||
menuCategory = createDummyMenuCategories(store,1).get(0); | ||
menus = createDummyMenus(store,menuCategory,5); | ||
} | ||
|
||
@Test | ||
@DisplayName("findByCustomerId 메서드는 장바구니에 담긴 메뉴의 아이템을 가져온다.") | ||
void findByCustomerIdTest(){ | ||
//given | ||
Cart cart = new Cart(customer.getId().toString()); | ||
cartRepository.save(cart); | ||
menus.stream() | ||
.forEach(cart::addMenu); | ||
Cart save = cartRepository.save(cart); | ||
|
||
//when | ||
CartResponse response = redisCartDao.findByCustomerId(customer.getId()); | ||
|
||
//then | ||
assertThat(response.getStoreId()).isEqualTo(store.getId()); | ||
assertThat(response.getStoreName()).isEqualTo(store.getName()); | ||
assertThat(response.getMinOrderPrice()).isEqualTo(store.getMinOrderPrice()); | ||
} | ||
} |
Oops, something went wrong.