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

[BE] refactor: 리뷰 작성 시 네이티브 쿼리를 사용 #308

Merged
merged 4 commits into from
Aug 12, 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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package reviewme.review.repository;

import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import reviewme.question.domain.Question2;
import reviewme.question.domain.exception.QuestionNotFoundException;

public interface QuestionRepository2 extends JpaRepository<Question2, Long> {

Expand All @@ -15,4 +17,18 @@ public interface QuestionRepository2 extends JpaRepository<Question2, Long> {
ORDER BY q.position ASC
""", nativeQuery = true)
List<Question2> findAllBySectionId(long sectionId);

@Query(value = """
SELECT q.* FROM question2 q
LEFT JOIN section_question sq
ON sq.question_id = q.id
LEFT JOIN template_section ts
ON sq.section_id = ts.section_id
WHERE ts.template_id = :templateId
""", nativeQuery = true)
Set<Long> findAllQuestionIdByTemplateId(long templateId);

default Question2 getQuestionById(long id) {
return findById(id).orElseThrow(() -> new QuestionNotFoundException(id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import reviewme.question.domain.Question2;
import reviewme.question.repository.OptionGroupRepository;
import reviewme.question.repository.OptionItemRepository;
import reviewme.question.repository.Question2Repository;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.service.exception.CheckBoxAnswerIncludedNotProvidedOptionItemException;
import reviewme.review.service.exception.CheckBoxAnswerIncludedTextException;
import reviewme.review.service.exception.MissingRequiredQuestionAnswerException;
Expand All @@ -21,13 +21,13 @@
@RequiredArgsConstructor
public class CreateCheckBoxAnswerRequestValidator {

private final Question2Repository question2Repository;
private final QuestionRepository2 questionRepository;
private final OptionGroupRepository optionGroupRepository;
private final OptionItemRepository optionItemRepository;

public void validate(CreateReviewAnswerRequest request) {
validateNotContainingText(request);
Question2 question = question2Repository.getQuestionById(request.questionId());
Question2 question = questionRepository.getQuestionById(request.questionId());
OptionGroup optionGroup = optionGroupRepository.findByQuestionId(question.getId())
.orElseThrow(() -> new OptionGroupNotFoundByQuestionIdException(question.getId()));
validateRequiredQuestion(request, question);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
package reviewme.review.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reviewme.question.domain.Question2;
import reviewme.question.domain.QuestionType;
import reviewme.question.repository.Question2Repository;
import reviewme.review.domain.CheckboxAnswer;
import reviewme.review.domain.Review2;
import reviewme.review.domain.TextAnswer;
import reviewme.review.domain.exception.ReviewGroupNotFoundByRequestReviewCodeException;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.dto.request.create.CreateReviewRequest;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.repository.Review2Repository;
import reviewme.review.service.exception.SubmittedQuestionAndProvidedQuestionMismatchException;
import reviewme.reviewgroup.domain.ReviewGroup;
import reviewme.reviewgroup.repository.ReviewGroupRepository;
import reviewme.template.domain.SectionQuestion;
import reviewme.template.domain.Template;
import reviewme.template.repository.SectionRepository;
import reviewme.template.repository.TemplateRepository;

Expand All @@ -29,7 +28,7 @@
public class CreateReviewService {

private final Review2Repository review2Repository;
private final Question2Repository question2Repository;
private final QuestionRepository2 questionRepository;
private final ReviewGroupRepository reviewGroupRepository;
private final TemplateRepository templateRepository;
private final SectionRepository sectionRepository;
Expand All @@ -39,8 +38,7 @@ public class CreateReviewService {
@Transactional
public long createReview(CreateReviewRequest request) {
ReviewGroup reviewGroup = validateReviewGroupByRequestCode(request.reviewRequestCode());
Template template = templateRepository.getTemplateById(reviewGroup.getTemplateId());
validateSubmittedQuestionAndProvidedQuestionMatch(request, template);
validateSubmittedQuestionsContainingInTemplate(reviewGroup.getTemplateId(), request);
return saveReview(request, reviewGroup);
}

Expand All @@ -49,18 +47,13 @@ private ReviewGroup validateReviewGroupByRequestCode(String reviewRequestCode) {
.orElseThrow(() -> new ReviewGroupNotFoundByRequestReviewCodeException(reviewRequestCode));
}

private void validateSubmittedQuestionAndProvidedQuestionMatch(CreateReviewRequest request, Template template) {
List<Long> providedQuestionIds = template.getSectionIds()
.stream()
.map(templateSection -> sectionRepository.getSectionById(templateSection.getSectionId()))
.flatMap(section -> section.getQuestionIds().stream().map(SectionQuestion::getQuestionId))
.toList();
List<Long> submittedQuestionIds = request.answers()
private void validateSubmittedQuestionsContainingInTemplate(long templateId, CreateReviewRequest request) {
Set<Long> providedQuestionIds = questionRepository.findAllQuestionIdByTemplateId(templateId);
Set<Long> submittedQuestionIds = request.answers()
.stream()
.map(CreateReviewAnswerRequest::questionId)
.toList();

if (!new HashSet<>(providedQuestionIds).containsAll(submittedQuestionIds)) {
.collect(Collectors.toSet());
if (!providedQuestionIds.containsAll(submittedQuestionIds)) {
throw new SubmittedQuestionAndProvidedQuestionMismatchException(submittedQuestionIds, providedQuestionIds);
}
}
Expand All @@ -69,7 +62,7 @@ private Long saveReview(CreateReviewRequest request, ReviewGroup reviewGroup) {
List<TextAnswer> textAnswers = new ArrayList<>();
List<CheckboxAnswer> checkboxAnswers = new ArrayList<>();
for (CreateReviewAnswerRequest answerRequests : request.answers()) {
Question2 question = question2Repository.getQuestionById(answerRequests.questionId());
Question2 question = questionRepository.getQuestionById(answerRequests.questionId());
QuestionType questionType = question.getQuestionType();
if (questionType == QuestionType.TEXT) {
createTextAnswerRequestValidator.validate(answerRequests);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import reviewme.question.domain.Question2;
import reviewme.question.repository.Question2Repository;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.service.exception.MissingRequiredQuestionAnswerException;
import reviewme.review.service.exception.TextAnswerInculdedOptionException;

@Component
@RequiredArgsConstructor
public class CreateTextAnswerRequestValidator {

private final Question2Repository question2Repository;
private final QuestionRepository2 questionRepository;

public void validate(CreateReviewAnswerRequest request) {
validateNotIncludingOptions(request);
Expand All @@ -28,7 +28,7 @@ private void validateNotIncludingOptions(CreateReviewAnswerRequest request) {

private Question2 validateQuestionExists(CreateReviewAnswerRequest request) {
long questionId = request.questionId();
return question2Repository.getQuestionById(questionId);
return questionRepository.getQuestionById(questionId);
}

private void validateQuestionRequired(Question2 question, CreateReviewAnswerRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
import reviewme.review.domain.Review2;
import reviewme.review.domain.TextAnswer;
import reviewme.review.domain.TextAnswers;
import reviewme.review.domain.exception.ReviewGroupNotFoundByGroupAccessCodeException;
import reviewme.review.domain.exception.InvalidReviewAccessByReviewGroupException;
import reviewme.review.domain.exception.ReviewGroupNotFoundByGroupAccessCodeException;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.repository.ReviewRepository2;
import reviewme.review.service.dto.response.detail.OptionGroupAnswerResponse;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package reviewme.review.service.exception;

import java.util.List;
import java.util.Collection;
import lombok.extern.slf4j.Slf4j;
import reviewme.global.exception.BadRequestException;

@Slf4j
public class SubmittedQuestionAndProvidedQuestionMismatchException extends BadRequestException {

public SubmittedQuestionAndProvidedQuestionMismatchException(List<Long> submittedQuestionIds,
List<Long> providedQuestionIds) {
public SubmittedQuestionAndProvidedQuestionMismatchException(Collection<Long> submittedQuestionIds,
Collection<Long> providedQuestionIds) {
super("제출된 응답이 제공된 질문과 매칭되지 않아요.");
log.info(
"Submitted questions mismatch with provided questions - submittedQuestionIds: {}, providedQuestionIds: {}",
submittedQuestionIds, providedQuestionIds);
"Submitted questions and provided questions mismatch. submittedQuestionIds: {}, providedQuestionIds: {}",
submittedQuestionIds, providedQuestionIds
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public interface ReviewGroupApi {
String APPLICATION_JSON = "application/json";

@Operation(summary = "리뷰 그룹 생성", description = "리뷰 그룹 정보를 받아 리뷰 그룹을 생성한다.")
@ApiResponses(value ={
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "응답 성공 : 리뷰 그룹 생성",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package reviewme.template.domain;

import jakarta.persistence.Column;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import reviewme.question.domain.exception.MissingOptionItemsInOptionGroupException;
import reviewme.question.repository.OptionGroupRepository;
import reviewme.question.repository.OptionItemRepository;
import reviewme.question.repository.Question2Repository;
import reviewme.review.repository.QuestionRepository2;
import reviewme.reviewgroup.domain.ReviewGroup;
import reviewme.template.domain.Section;
import reviewme.template.domain.SectionQuestion;
Expand All @@ -27,7 +27,7 @@
public class TemplateMapper {

private final SectionRepository sectionRepository;
private final Question2Repository questionRepository;
private final QuestionRepository2 questionRepository;
private final OptionGroupRepository optionGroupRepository;
private final OptionItemRepository optionItemRepository;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import reviewme.question.domain.Question2;
import reviewme.question.domain.QuestionType;
import reviewme.template.domain.Section;
import reviewme.template.domain.Template;
import reviewme.template.domain.VisibleType;
import reviewme.template.repository.SectionRepository;
import reviewme.template.repository.TemplateRepository;

@DataJpaTest
class QuestionRepository2Test {
Expand All @@ -21,6 +24,9 @@ class QuestionRepository2Test {
@Autowired
private SectionRepository sectionRepository;

@Autowired
private TemplateRepository templateRepository;

@Test
void 섹션_아이디로_질문_목록을_순서대로_가져온다() {
// given
Expand All @@ -39,4 +45,26 @@ class QuestionRepository2Test {
assertThat(actual).extracting(Question2::getId)
.containsExactly(question1.getId(), question2.getId(), question3.getId());
}

@Test
void 템플릿_아이디로_질문_목록을_모두_가져온다() {
// given
Question2 question1 = questionRepository.save(new Question2(true, QuestionType.TEXT, "질문1", null, 1));
Question2 question2 = questionRepository.save(new Question2(true, QuestionType.TEXT, "질문2", null, 2));
Question2 question3 = questionRepository.save(new Question2(true, QuestionType.TEXT, "질문3", null, 1));
Question2 question4 = questionRepository.save(new Question2(true, QuestionType.TEXT, "질문4", null, 2));

List<Long> sectionQuestion1 = List.of(question1.getId(), question2.getId());
List<Long> sectionQuestion2 = List.of(question3.getId(), question4.getId());
Section section1 = sectionRepository.save(new Section(VisibleType.ALWAYS, sectionQuestion1, null, "header", 0));
sectionRepository.save(new Section(VisibleType.ALWAYS, sectionQuestion2, null, "header", 0));
List<Long> sectionIds = List.of(section1.getId());
Template template = templateRepository.save(new Template(sectionIds));

// when
Set<Long> actual = questionRepository.findAllQuestionIdByTemplateId(template.getId());

// then
assertThat(actual).containsExactlyInAnyOrder(question1.getId(), question2.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import reviewme.question.domain.exception.QuestionNotFoundException;
import reviewme.question.repository.OptionGroupRepository;
import reviewme.question.repository.OptionItemRepository;
import reviewme.question.repository.Question2Repository;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.service.exception.CheckBoxAnswerIncludedNotProvidedOptionItemException;
import reviewme.review.service.exception.CheckBoxAnswerIncludedTextException;
import reviewme.review.service.exception.MissingRequiredQuestionAnswerException;
Expand All @@ -30,7 +30,7 @@ class CreateCheckBoxAnswerRequestValidatorTest {
private CreateCheckBoxAnswerRequestValidator createCheckBoxAnswerRequestValidator;

@Autowired
private Question2Repository question2Repository;
private QuestionRepository2 questionRepository;

@Autowired
private OptionGroupRepository optionGroupRepository;
Expand All @@ -42,7 +42,7 @@ class CreateCheckBoxAnswerRequestValidatorTest {

@BeforeEach
void setUp() {
savedQuestion = question2Repository.save(new Question2(true, QuestionType.CHECKBOX, "질문", null, 1));
savedQuestion = questionRepository.save(new Question2(true, QuestionType.CHECKBOX, "질문", null, 1));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
import reviewme.question.domain.QuestionType;
import reviewme.question.repository.OptionGroupRepository;
import reviewme.question.repository.OptionItemRepository;
import reviewme.question.repository.Question2Repository;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.dto.request.create.CreateReviewRequest;
import reviewme.review.repository.CheckboxAnswerRepository;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.repository.Review2Repository;
import reviewme.review.repository.TextAnswerRepository;
import reviewme.reviewgroup.domain.ReviewGroup;
Expand All @@ -35,7 +35,7 @@ class CreateReviewServiceTest {
private CreateReviewService createReviewService;

@Autowired
private Question2Repository questionRepository;
private QuestionRepository2 questionRepository;

@Autowired
private OptionGroupRepository optionGroupRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import reviewme.question.domain.Question2;
import reviewme.question.domain.QuestionType;
import reviewme.question.domain.exception.QuestionNotFoundException;
import reviewme.question.repository.Question2Repository;
import reviewme.review.dto.request.create.CreateReviewAnswerRequest;
import reviewme.review.repository.QuestionRepository2;
import reviewme.review.service.exception.MissingRequiredQuestionAnswerException;
import reviewme.review.service.exception.TextAnswerInculdedOptionException;
import reviewme.support.ServiceTest;
Expand All @@ -21,7 +21,7 @@ class CreateTextAnswerRequestValidatorTest {
private CreateTextAnswerRequestValidator createTextAnswerRequestValidator;

@Autowired
private Question2Repository question2Repository;
private QuestionRepository2 questionRepository;

@Test
void 저장되지_않은_질문에_대한_대답이면_예외가_발생한다() {
Expand All @@ -37,7 +37,7 @@ class CreateTextAnswerRequestValidatorTest {
void 텍스트형_질문에_선택형_응답을_하면_예외가_발생한다() {
// given
Question2 savedQuestion
= question2Repository.save(new Question2(true, QuestionType.TEXT, "질문", "가이드라인", 1));
= questionRepository.save(new Question2(true, QuestionType.TEXT, "질문", "가이드라인", 1));
CreateReviewAnswerRequest request = new CreateReviewAnswerRequest(savedQuestion.getId(), List.of(1L), "응답");

// when, then
Expand All @@ -49,7 +49,7 @@ class CreateTextAnswerRequestValidatorTest {
void 필수_텍스트형_질문에_응답을_하지_않으면_예외가_발생한다() {
// given
Question2 savedQuestion
= question2Repository.save(new Question2(true, QuestionType.TEXT, "질문", "가이드라인", 1));
= questionRepository.save(new Question2(true, QuestionType.TEXT, "질문", "가이드라인", 1));
CreateReviewAnswerRequest request = new CreateReviewAnswerRequest(savedQuestion.getId(), null, null);

// when, then
Expand Down
Loading