Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ implement recipe steps retrieval #83

Merged
merged 5 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import java.util.List;
import lombok.RequiredArgsConstructor;
import net.pengcook.recipe.dto.MainRecipeRequest;
import net.pengcook.recipe.dto.MainRecipeResponse;
import net.pengcook.recipe.dto.RecipeStepResponse;
import net.pengcook.recipe.service.RecipeService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
Expand All @@ -18,7 +19,12 @@ public class RecipeController {
private final RecipeService recipeService;

@GetMapping
public List<MainRecipeResponse> readRecipes(@RequestBody MainRecipeRequest request) {
return recipeService.readRecipes(request);
public List<MainRecipeResponse> readRecipes(@RequestParam int pageNumber, @RequestParam int pageSize) {
return recipeService.readRecipes(pageNumber, pageSize);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 MainRecipeRequest를 살리고 싶으시면

@ModelAttribute 를 고려해봐도 좋을것 같아요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ModelAttribute를 사용하면 param을 모두 기재할 필요없이 하나의 객체처럼 받아올 수도 있네요 👍🏻
상황에 따라 적용하는것도 고려해봐야겠어요.


@GetMapping("/{id}/steps")
public List<RecipeStepResponse> readRecipeSteps(@PathVariable long id) {
return recipeService.readRecipeSteps(id);
}
}
3 changes: 2 additions & 1 deletion backend/src/main/java/net/pengcook/recipe/domain/Recipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import net.pengcook.user.domain.User;

@Entity
@NoArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
public class Recipe {
Expand Down
37 changes: 37 additions & 0 deletions backend/src/main/java/net/pengcook/recipe/domain/RecipeStep.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package net.pengcook.recipe.domain;

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 lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class RecipeStep {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@ManyToOne
@JoinColumn(name = "recipe_id")
private Recipe recipe;

private String image;

private String description;

private int sequence;

public long recipeId() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getRecipeId() 는 RecipeStep의 다른 필드의 getter와 구분하기 위한 네이밍 인가요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RecipeStepRepository에서 RecipeId로 조회하는 메서드를 작성하기 위해 사용되는 메서드입니다.

recipeId를 가져오는 메서드가 없으면 Repository에서 findAllByRecipeId()로 검색했을 때 에러가 발생했습니다. 에러를 해결하려면 메서드 명에 findAllByRecipe_Id() 와 같이 실제 매핑되는 컬럼명을 적어주어야했어요.
getRecipeId()처럼 일반 getter와 같은 형태로 메서드 명을 작성해도 동작하지 않아서 recipeId()를 명시적으로 표시해두었습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋네요! 레벨2에서 slot_startAt 이런식으로 쓴적있는데 그때 알려주시지.. 왜 지금 알려주시죠

return recipe.getId();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package net.pengcook.recipe.dto;

import net.pengcook.recipe.domain.RecipeStep;

public record RecipeStepResponse(long id, long recipeId, String image, String description, int sequence) {

public RecipeStepResponse(RecipeStep recipeStep) {
this(
recipeStep.getId(),
recipeStep.recipeId(),
recipeStep.getImage(),
recipeStep.getDescription(),
recipeStep.getSequence()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.pengcook.recipe.repository;

import java.util.List;
import net.pengcook.recipe.domain.RecipeStep;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RecipeStepRepository extends JpaRepository<RecipeStep, Long> {

List<RecipeStep> findAllByRecipeIdOrderBySequence(long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import net.pengcook.recipe.domain.RecipeStep;
import net.pengcook.recipe.dto.AuthorResponse;
import net.pengcook.recipe.dto.CategoryResponse;
import net.pengcook.recipe.dto.IngredientResponse;
import net.pengcook.recipe.dto.MainRecipeRequest;
import net.pengcook.recipe.dto.MainRecipeResponse;
import net.pengcook.recipe.dto.RecipeDataResponse;
import net.pengcook.recipe.dto.RecipeStepResponse;
import net.pengcook.recipe.repository.RecipeRepository;
import net.pengcook.recipe.repository.RecipeStepRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
Expand All @@ -21,15 +23,27 @@
public class RecipeService {

private final RecipeRepository recipeRepository;
private final RecipeStepRepository recipeStepRepository;

public List<MainRecipeResponse> readRecipes(MainRecipeRequest request) {
Pageable pageable = PageRequest.of(request.pageNumber(), request.pageSize());
public List<MainRecipeResponse> readRecipes(int pageNumber, int pageSize) {
Pageable pageable = PageRequest.of(pageNumber, pageSize);
List<Long> recipeIds = recipeRepository.findRecipeIds(pageable);

List<RecipeDataResponse> recipeDataResponses = recipeRepository.findRecipeData(recipeIds);
return convertToMainRecipeResponses(recipeDataResponses);
}

public List<RecipeStepResponse> readRecipeSteps(long id) {
List<RecipeStep> recipeSteps = recipeStepRepository.findAllByRecipeIdOrderBySequence(id);
return convertToRecipeStepResponses(recipeSteps);
}

private List<RecipeStepResponse> convertToRecipeStepResponses(List<RecipeStep> recipeSteps) {
return recipeSteps.stream()
.map(RecipeStepResponse::new)
.toList();
}

public List<MainRecipeResponse> convertToMainRecipeResponses(List<RecipeDataResponse> recipeDataResponses) {
Collection<List<RecipeDataResponse>> groupedRecipeData = recipeDataResponses.stream()
.collect(Collectors.groupingBy(RecipeDataResponse::recipeId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.pengcook.recipe.dto.MainRecipeRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand All @@ -28,13 +27,21 @@ void setUp() {
@Test
@DisplayName("레시피 개요 목록을 조회한다.")
void readRecipes() {
MainRecipeRequest request = new MainRecipeRequest(0, 3);
RestAssured.given().log().all()
.contentType(ContentType.JSON)
.when()
.get("/api/recipes?pageNumber=0&pageSize=3")
.then().log().all()
.body("size()", is(3));
}

@Test
@DisplayName("레시피 상세 스텝을 조회한다.")
void readRecipeSteps() {
RestAssured.given().log().all()
.contentType(ContentType.JSON)
.body(request)
.when()
.get("/api/recipes")
.get("/api/recipes/1/steps")
.then().log().all()
.body("size()", is(3));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.List;
import net.pengcook.recipe.dto.MainRecipeRequest;
import net.pengcook.recipe.dto.MainRecipeResponse;
import net.pengcook.recipe.dto.RecipeStepResponse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -25,10 +27,23 @@ class RecipeServiceTest {
@CsvSource(value = {"0,2,4", "1,2,2", "1,3,1"})
@DisplayName("요청받은 페이지의 레시피 개요 목록을 조회한다.")
void readRecipes(int pageNumber, int pageSize, int expectedFirstRecipeId) {
MainRecipeRequest request = new MainRecipeRequest(pageNumber, pageSize);

List<MainRecipeResponse> mainRecipeResponses = recipeService.readRecipes(request);
List<MainRecipeResponse> mainRecipeResponses = recipeService.readRecipes(pageNumber, pageSize);

assertThat(mainRecipeResponses.getFirst().recipeId()).isEqualTo(expectedFirstRecipeId);
}

@Test
@DisplayName("특정 레시피의 스텝을 sequence 순서로 조회한다.")
void readRecipeSteps() {
long recipeId = 1L;
List<RecipeStepResponse> expectedRecipeStepResponses = Arrays.asList(
new RecipeStepResponse(1L, 1, "레시피1 설명1 이미지", "레시피1 설명1", 1),
new RecipeStepResponse(3L, 1, "레시피1 설명2 이미지", "레시피1 설명2", 2),
new RecipeStepResponse(2L, 1, "레시피1 설명3 이미지", "레시피1 설명3", 3)
);

List<RecipeStepResponse> recipeStepResponses = recipeService.readRecipeSteps(recipeId);

assertThat(recipeStepResponses).isEqualTo(expectedRecipeStepResponses);
}
}
8 changes: 8 additions & 0 deletions backend/src/test/resources/data/recipe.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ ALTER TABLE category_recipe ALTER COLUMN id RESTART;
TRUNCATE TABLE ingredient_recipe;
ALTER TABLE ingredient_recipe ALTER COLUMN id RESTART;

TRUNCATE TABLE recipe_step;
ALTER TABLE recipe_step ALTER COLUMN id RESTART;

SET REFERENTIAL_INTEGRITY TRUE;

INSERT INTO users (email, username, nickname, image, birth, region)
Expand Down Expand Up @@ -76,3 +79,8 @@ VALUES (1, 1, 'REQUIRED'),
(3, 3, 'REQUIRED'),
(7, 3, 'REQUIRED'),
(2, 4, 'REQUIRED');

INSERT INTO recipe_step (recipe_id, image, description, sequence)
VALUES (1, '레시피1 설명1 이미지', '레시피1 설명1', 1),
(1, '레시피1 설명3 이미지', '레시피1 설명3', 3),
(1, '레시피1 설명2 이미지', '레시피1 설명2', 2);
Loading