From 1b6eb81abd9f58e6bf3789ddf75f9d7aedbb1fb3 Mon Sep 17 00:00:00 2001 From: Invidam Date: Sun, 7 Jan 2024 17:31:42 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EB=A9=94=EB=89=B4=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shop/controller/ShopController.java | 7 +++ .../shop/dto/MenuCategoriesResponse.java | 25 ++++++++ .../repository/MenuCategoryRepository.java | 11 ++++ .../koin/domain/shop/service/ShopService.java | 11 +++- .../koin/acceptance/ShopApiTest.java | 62 +++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java create mode 100644 src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java diff --git a/src/main/java/in/koreatech/koin/domain/shop/controller/ShopController.java b/src/main/java/in/koreatech/koin/domain/shop/controller/ShopController.java index efb4520ef..fd6a99000 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/controller/ShopController.java +++ b/src/main/java/in/koreatech/koin/domain/shop/controller/ShopController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import in.koreatech.koin.domain.shop.dto.MenuCategoriesResponse; import in.koreatech.koin.domain.shop.dto.ShopMenuResponse; import in.koreatech.koin.domain.shop.service.ShopService; import lombok.RequiredArgsConstructor; @@ -20,4 +21,10 @@ public ResponseEntity findMenu(@PathVariable Long shopId, @Pat ShopMenuResponse shopMenu = shopService.findMenu(menuId); return ResponseEntity.ok(shopMenu); } + + @GetMapping("/shops/{shopId}/menus/categories") + public ResponseEntity findMenuCategories(@PathVariable Long shopId) { + MenuCategoriesResponse menuCategories = shopService.getMenuCategories(shopId); + return ResponseEntity.ok(menuCategories); + } } diff --git a/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java new file mode 100644 index 000000000..636c2751d --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java @@ -0,0 +1,25 @@ +package in.koreatech.koin.domain.shop.dto; + +import java.util.List; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; +import com.fasterxml.jackson.databind.annotation.JsonNaming; + +import in.koreatech.koin.domain.shop.model.MenuCategory; + +@JsonNaming(value = SnakeCaseStrategy.class) +public record MenuCategoriesResponse(Long count, List menuCategories) { + public static MenuCategoriesResponse of(Long count, List menuCategories) { + List categories = menuCategories.stream() + .map(menuCategory -> MenuCategoryResponse.of(menuCategory.getId(), menuCategory.getName())) + .toList(); + + return new MenuCategoriesResponse(count, categories); + } + + private record MenuCategoryResponse(Long id, String name) { + public static MenuCategoryResponse of(Long id, String name) { + return new MenuCategoryResponse(id, name); + } + } +} diff --git a/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java b/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java new file mode 100644 index 000000000..2fb36ea6e --- /dev/null +++ b/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java @@ -0,0 +1,11 @@ +package in.koreatech.koin.domain.shop.repository; + +import java.util.List; + +import org.springframework.data.repository.Repository; + +import in.koreatech.koin.domain.shop.model.MenuCategory; + +public interface MenuCategoryRepository extends Repository { + List findAllByShopId(Long shopId); +} diff --git a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java index 9d2ee55b2..b4988479a 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java +++ b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java @@ -5,10 +5,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import in.koreatech.koin.domain.shop.dto.MenuCategoriesResponse; +import in.koreatech.koin.domain.shop.dto.ShopMenuResponse; import in.koreatech.koin.domain.shop.model.Menu; import in.koreatech.koin.domain.shop.model.MenuCategory; import in.koreatech.koin.domain.shop.model.MenuCategoryMap; -import in.koreatech.koin.domain.shop.dto.ShopMenuResponse; +import in.koreatech.koin.domain.shop.repository.MenuCategoryRepository; import in.koreatech.koin.domain.shop.repository.MenuRepository; import lombok.RequiredArgsConstructor; @@ -18,6 +20,7 @@ public class ShopService { private final MenuRepository menuRepository; + private final MenuCategoryRepository menuCategoryRepository; public ShopMenuResponse findMenu(Long menuId) { Menu menu = menuRepository.findById(menuId) @@ -37,4 +40,10 @@ private ShopMenuResponse createShopMenuResponse(Menu menu, List me } return ShopMenuResponse.createForSingleOption(menu, menuCategories); } + + public MenuCategoriesResponse getMenuCategories(Long shopId) { + //TODO 존재하는 상점인지 검증하고, 없다면 401를 반환하여야 한다. 작업시점: 상점 도메인 조회 기능 추가시 + List menuCategories = menuCategoryRepository.findAllByShopId(shopId); + return MenuCategoriesResponse.of((long)menuCategories.size(), menuCategories); + } } diff --git a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java index 72acf9604..615392d66 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java @@ -177,4 +177,66 @@ void findMenuMultipleOption() { } ); } + + @Test + @DisplayName("상점의 메뉴 카테고리들을 조회한다.") + void findShopMenuCategories() { + // given + final long SHOP_ID = 1L; + + Menu menu = Menu.builder() + .shopId(SHOP_ID) + .name("짜장면") + .description("맛있는 짜장면") + .build(); + + MenuCategory menuCategory1 = MenuCategory.builder() + .shopId(SHOP_ID) + .name("이벤트 메뉴") + .build(); + + MenuCategory menuCategory2 = MenuCategory.builder() + .shopId(SHOP_ID) + .name("메인 메뉴") + .build(); + + MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); + MenuCategoryMap menuCategoryMap2 = MenuCategoryMap.create(); + + // when then + menuCategoryMap1.map(menu, menuCategory1); + menuCategoryMap2.map(menu, menuCategory2); + + menuRepository.save(menu); + + ExtractableResponse response = RestAssured + .given() + .log().all() + .when() + .log().all() + .get("/shops/{shopId}/menus/categories", menu.getShopId()) + .then() + .log().all() + .statusCode(HttpStatus.OK.value()) + .extract(); + + SoftAssertions.assertSoftly( + softly -> { + softly.assertThat(response.body().jsonPath().getLong("count")).isEqualTo(2); + + softly.assertThat(response.body().jsonPath().getList("menu_categories")) + .hasSize(2); + + softly.assertThat(response.body().jsonPath().getLong("menu_categories[0].id")) + .isEqualTo(menuCategory1.getId()); + softly.assertThat(response.body().jsonPath().getString("menu_categories[0].name")) + .isEqualTo(menuCategory1.getName()); + + softly.assertThat(response.body().jsonPath().getLong("menu_categories[1].id")) + .isEqualTo(menuCategory2.getId()); + softly.assertThat(response.body().jsonPath().getString("menu_categories[1].name")) + .isEqualTo(menuCategory2.getName()); + } + ); + } } From 1625ff7f79c8c9a84fc5feaf93fc590988190342 Mon Sep 17 00:00:00 2001 From: Invidam Date: Sun, 7 Jan 2024 17:33:54 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20=EC=9D=91=EB=8B=B5=20DTO=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../koin/domain/shop/dto/MenuCategoriesResponse.java | 4 ++-- .../in/koreatech/koin/domain/shop/service/ShopService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java index 636c2751d..c8fec73bb 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java +++ b/src/main/java/in/koreatech/koin/domain/shop/dto/MenuCategoriesResponse.java @@ -9,12 +9,12 @@ @JsonNaming(value = SnakeCaseStrategy.class) public record MenuCategoriesResponse(Long count, List menuCategories) { - public static MenuCategoriesResponse of(Long count, List menuCategories) { + public static MenuCategoriesResponse from(List menuCategories) { List categories = menuCategories.stream() .map(menuCategory -> MenuCategoryResponse.of(menuCategory.getId(), menuCategory.getName())) .toList(); - return new MenuCategoriesResponse(count, categories); + return new MenuCategoriesResponse((long)categories.size(), categories); } private record MenuCategoryResponse(Long id, String name) { diff --git a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java index b4988479a..89e4d0dea 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java +++ b/src/main/java/in/koreatech/koin/domain/shop/service/ShopService.java @@ -44,6 +44,6 @@ private ShopMenuResponse createShopMenuResponse(Menu menu, List me public MenuCategoriesResponse getMenuCategories(Long shopId) { //TODO 존재하는 상점인지 검증하고, 없다면 401를 반환하여야 한다. 작업시점: 상점 도메인 조회 기능 추가시 List menuCategories = menuCategoryRepository.findAllByShopId(shopId); - return MenuCategoriesResponse.of((long)menuCategories.size(), menuCategories); + return MenuCategoriesResponse.from(menuCategories); } } From 5e822f990aca578422d8734700b9f33414293d14 Mon Sep 17 00:00:00 2001 From: Invidam Date: Sun, 7 Jan 2024 18:11:58 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20cascade=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refactor: cascade 처리 방식 변경 --- .../koreatech/koin/domain/shop/model/MenuCategoryMap.java | 3 +-- .../domain/shop/repository/MenuCategoryRepository.java | 2 ++ .../java/in/koreatech/koin/acceptance/ShopApiTest.java | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategoryMap.java b/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategoryMap.java index b5417e86f..9765179f1 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategoryMap.java +++ b/src/main/java/in/koreatech/koin/domain/shop/model/MenuCategoryMap.java @@ -1,6 +1,5 @@ package in.koreatech.koin.domain.shop.model; -import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -29,7 +28,7 @@ public class MenuCategoryMap { @JoinColumn(name = "shop_menu_id") private Menu menu; - @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "shop_menu_category_id") private MenuCategory menuCategory; diff --git a/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java b/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java index 2fb36ea6e..8fa21336e 100644 --- a/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java +++ b/src/main/java/in/koreatech/koin/domain/shop/repository/MenuCategoryRepository.java @@ -8,4 +8,6 @@ public interface MenuCategoryRepository extends Repository { List findAllByShopId(Long shopId); + + MenuCategory save(MenuCategory menuCategory); } diff --git a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java index 615392d66..629a3a641 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java @@ -12,6 +12,7 @@ import in.koreatech.koin.domain.shop.model.MenuCategoryMap; import in.koreatech.koin.domain.shop.model.MenuImage; import in.koreatech.koin.domain.shop.model.MenuOption; +import in.koreatech.koin.domain.shop.repository.MenuCategoryRepository; import in.koreatech.koin.domain.shop.repository.MenuRepository; import io.restassured.RestAssured; import io.restassured.response.ExtractableResponse; @@ -22,6 +23,9 @@ class ShopApiTest extends AcceptanceTest { @Autowired private MenuRepository menuRepository; + @Autowired + private MenuCategoryRepository menuCategoryRepository; + @Test @DisplayName("옵션이 하나 있는 상점의 메뉴를 조회한다.") void findMenuSingleOption() { @@ -54,6 +58,7 @@ void findMenuSingleOption() { menuCategoryMap.map(menu, menuCategory); + menuCategoryRepository.save(menuCategory); menuRepository.save(menu); ExtractableResponse response = RestAssured @@ -133,6 +138,7 @@ void findMenuMultipleOption() { menuCategoryMap.map(menu, menuCategory); + menuCategoryRepository.save(menuCategory); menuRepository.save(menu); ExtractableResponse response = RestAssured @@ -207,6 +213,8 @@ void findShopMenuCategories() { menuCategoryMap1.map(menu, menuCategory1); menuCategoryMap2.map(menu, menuCategory2); + menuCategoryRepository.save(menuCategory1); + menuCategoryRepository.save(menuCategory2); menuRepository.save(menu); ExtractableResponse response = RestAssured From 6ff904d38eb17ec243fa9e38233e51e1291c343f Mon Sep 17 00:00:00 2001 From: Invidam Date: Mon, 15 Jan 2024 23:48:11 +0900 Subject: [PATCH 4/4] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=AC=B8=EB=A7=A5=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/koreatech/koin/acceptance/ShopApiTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java index 629a3a641..8aa830bbe 100644 --- a/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java +++ b/src/test/java/in/koreatech/koin/acceptance/ShopApiTest.java @@ -49,16 +49,15 @@ void findMenuSingleOption() { .shopId(1L) .name("중식") .build(); + menuCategoryRepository.save(menuCategory); MenuCategoryMap menuCategoryMap = MenuCategoryMap.create(); - // when then menuOption.setMenu(menu); menuImage.setMenu(menu); + // when then menuCategoryMap.map(menu, menuCategory); - - menuCategoryRepository.save(menuCategory); menuRepository.save(menu); ExtractableResponse response = RestAssured @@ -129,6 +128,7 @@ void findMenuMultipleOption() { .build(); MenuCategoryMap menuCategoryMap = MenuCategoryMap.create(); + menuCategoryRepository.save(menuCategory); // when then menuOption1.setMenu(menu); @@ -138,7 +138,6 @@ void findMenuMultipleOption() { menuCategoryMap.map(menu, menuCategory); - menuCategoryRepository.save(menuCategory); menuRepository.save(menu); ExtractableResponse response = RestAssured @@ -205,6 +204,9 @@ void findShopMenuCategories() { .shopId(SHOP_ID) .name("메인 메뉴") .build(); + + menuCategoryRepository.save(menuCategory1); + menuCategoryRepository.save(menuCategory2); MenuCategoryMap menuCategoryMap1 = MenuCategoryMap.create(); MenuCategoryMap menuCategoryMap2 = MenuCategoryMap.create(); @@ -213,8 +215,6 @@ void findShopMenuCategories() { menuCategoryMap1.map(menu, menuCategory1); menuCategoryMap2.map(menu, menuCategory2); - menuCategoryRepository.save(menuCategory1); - menuCategoryRepository.save(menuCategory2); menuRepository.save(menu); ExtractableResponse response = RestAssured