Skip to content

Commit

Permalink
Merge pull request #96 from ShyPolarBear/refactor/quiz_dto_conversion
Browse files Browse the repository at this point in the history
refactor: Quiz dto의 타입 캐스팅 책임 이동
  • Loading branch information
wonslee authored Jan 27, 2024
2 parents 224265a + e949f21 commit b1e247a
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 86 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package com.shy_polarbear.server.domain.quiz.dto.response;

import com.shy_polarbear.server.domain.quiz.dto.QuizType;
import com.shy_polarbear.server.domain.quiz.model.MultipleChoiceQuiz;
import com.shy_polarbear.server.domain.quiz.model.OXQuiz;
import com.shy_polarbear.server.global.common.constants.BusinessLogicConstants;
import lombok.Builder;

import com.shy_polarbear.server.domain.quiz.model.Quiz;
import java.util.List;
import lombok.Builder;

@Builder
public record QuizCardResponse(
Expand All @@ -16,23 +13,25 @@ public record QuizCardResponse(
int time,
List<MultipleChoiceResponse> choices // nullable
) {
public static QuizCardResponse of(MultipleChoiceQuiz quiz) {
public static QuizCardResponse from(Quiz quiz) {
return QuizCardResponse.builder()
.quizId(quiz.getId())
.type(QuizType.MULTIPLE_CHOICE.getValue())
.type(quiz.getType().getValue())
.question(quiz.getQuestion())
.time(BusinessLogicConstants.MULTIPLE_CHOICE_QUIZ_TIME_LIMIT)
.choices(quiz.getMultipleChoiceList().stream().map(MultipleChoiceResponse::of).toList())
.time(quiz.getTimeLimit())
.choices(resolveChoicesFromDynamicQuizType(quiz))
.build();
}

public static QuizCardResponse of(OXQuiz quiz) {
return QuizCardResponse.builder()
.quizId(quiz.getId())
.type(QuizType.OX.getValue())
.question(quiz.getQuestion())
.time(BusinessLogicConstants.OX_QUIZ_TIME_LIMIT)
.build();
private static List<MultipleChoiceResponse> resolveChoicesFromDynamicQuizType(Quiz quiz) {
if (quiz.getClass().equals(MultipleChoiceQuiz.class)) {
return ((MultipleChoiceQuiz) quiz).getMultipleChoiceList().stream()
.map(MultipleChoiceResponse::of)
.toList();
}

return null;
}

}

Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
package com.shy_polarbear.server.domain.quiz.model;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Getter
@Entity
@DiscriminatorValue("M")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MultipleChoiceQuiz extends Quiz {
@OneToMany(mappedBy = "multipleChoiceQuiz", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MultipleChoice> multipleChoiceList = new ArrayList<>();
private final List<MultipleChoice> multipleChoiceList = new ArrayList<>();

@Builder
public MultipleChoiceQuiz(String question, String explanation) {
super(question, explanation);
super(QuizType.MULTIPLE_CHOICE, question, explanation);
}

}
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
package com.shy_polarbear.server.domain.quiz.model;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;

// TODO: Getter, constructor, builder은 어디서 만드는게 좋지? 자식쪽에서 하는게 맞을듯. Quiz에서 만들고 다 적용되면 좋긴한데.
@Getter
@Entity
@DiscriminatorValue("OX")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OXQuiz extends Quiz {

@Enumerated(EnumType.STRING)
private OXChoice answer;

@Builder
public OXQuiz(String question, String explanation, OXChoice answer) {
super(question, explanation);
super(QuizType.OX, question, explanation);
this.answer = answer;
}

}
25 changes: 21 additions & 4 deletions src/main/java/com/shy_polarbear/server/domain/quiz/model/Quiz.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

import com.shy_polarbear.server.global.common.model.BaseEntity;
import com.shy_polarbear.server.global.common.util.profiles.CustomProfileUtils;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Getter
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class Quiz extends BaseEntity {
@Id
Expand All @@ -25,11 +31,22 @@ public abstract class Quiz extends BaseEntity {
@Column(nullable = false, length = 1000)
private String explanation;

protected Quiz(String question, String explanation) {
@Column(nullable = false, name = "quiz_type")
@Enumerated(EnumType.STRING)
private QuizType type;

protected Quiz(QuizType type, String question, String explanation) {
this.type = type;
this.question = question;
this.explanation = explanation;
}

public int getTimeLimit() {
return this.type.getTimeLimit();
}


// TODO refactor: Mockito spy 대체
// test
public void setIdForMockTest(Long mockId) {
CustomProfileUtils.validateIsProfileNullOrTest();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,36 @@
package com.shy_polarbear.server.domain.quiz.model;

import com.shy_polarbear.server.domain.quiz.exception.QuizException;
import com.shy_polarbear.server.global.common.util.EnumModel;
import com.shy_polarbear.server.global.exception.ExceptionStatus;
import java.util.Arrays;
import lombok.AllArgsConstructor;

public enum QuizType {
@AllArgsConstructor
public enum QuizType implements EnumModel<String> {
OX("OX", 17), MULTIPLE_CHOICE("MULTIPLE_CHOICE", 17);

// OX, 객관식
TRUE_FALSE, MULTIPLE_CHOICE
private final String value;
private final int timeLimit;

public static QuizType of(String param) {
return Arrays.stream(QuizType.values())
.filter(v -> v.getValue().equals(param.toUpperCase()))
.findFirst()
.orElseThrow(() -> new QuizException(ExceptionStatus.CLIENT_ERROR));
}

@Override
public String getKey() {
return this.name();
}

@Override
public String getValue() {
return this.value;
}

public int getTimeLimit() {
return this.timeLimit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ public QuizCardResponse getDailyQuiz(Long currentUserId) {
Quiz quiz = quizRepository.findRecentQuizNotYetSolvedByUser(currentUserId)
.orElseThrow(() -> new QuizException(ExceptionStatus.NO_MORE_DAILY_QUIZ));

return buildQuizCardResponseFromQuiz(quiz);
return QuizCardResponse.from(quiz);
}

// 복습 퀴즈 조회 : 랜덤으로 5개
public PageResponse<QuizCardResponse> getRandomReviewQuizzes(Long currentUserId, int limit) {
Slice<QuizCardResponse> result = quizRepository
.findRandomQuizzesAlreadySolvedByUser(currentUserId, limit)
.map(this::buildQuizCardResponseFromQuiz);
.map(QuizCardResponse::from);

Long count = quizRepository.countAllQuizzesAlreadySolvedByUser(currentUserId);
return PageResponse.of(result, count);
Expand All @@ -63,6 +63,7 @@ public WhetherDailyQuizSolvedResponse getWhetherDailyQuizSolved(Long currentUser
LocalDate today = LocalDate.now();
Optional<UserQuiz> optionalUserQuiz = userQuizRepository.findFirstSubmittedDailyQuizByUser(today.toString(), currentUserId);

// TODO refactor: UserQuiz 책임 이동
boolean isSubmitted = optionalUserQuiz.isPresent(); // 레코드 존재 여부
Long quizId = isSubmitted ? optionalUserQuiz.get().getQuiz().getId() : null; // 존재 여부에 따라 id값 할당
boolean isSolved = isSubmitted && optionalUserQuiz.get().isCorrect();
Expand All @@ -83,6 +84,7 @@ public OXQuizScoreResponse scoreOXQuizSubmission(Long currentUserId, long quizId
} else if (Objects.isNull(request.getAnswer())) { // 시간초과되지 않았는데 선택지가 null: 클라이언트 에러
throw new QuizException(ExceptionStatus.QUIZ_SUBMISSION_NULL_CLIENT_ERROR);
} else {
// TODO refactor: OXChoice 책임 이동
OXChoice submittedChoice = OXChoice.toEnum(request.getAnswer());
boolean isCorrect = submittedChoice.equals(oxQuiz.getAnswer()); // 제출된 답안과 실제 답 비교

Expand Down Expand Up @@ -111,6 +113,7 @@ public MultipleChoiceQuizScoreResponse scoreMultipleQuizSubmission(Long currentU
} else if (Objects.isNull(request.getAnswerId())) { // 시간초과되지 않았는데 선택지가 null: 클라이언트 에러
throw new QuizException(ExceptionStatus.QUIZ_SUBMISSION_NULL_CLIENT_ERROR);
} else {
// TODO refactor: MultipleChoiceQuiz 책임 이동
MultipleChoice submittedChoice = multipleChoiceList.stream().filter(it -> it.getId().equals(request.getAnswerId())).findFirst()
.orElseThrow(() -> new QuizException(ExceptionStatus.NOT_FOUND_CHOICE));

Expand All @@ -122,12 +125,4 @@ public MultipleChoiceQuizScoreResponse scoreMultipleQuizSubmission(Long currentU
}
}

// 퀴즈 유형에 따른 분기처리
private QuizCardResponse buildQuizCardResponseFromQuiz(Quiz quiz) {
if (quiz.getClass().equals(OXQuiz.class)) {
return QuizCardResponse.of((OXQuiz) quiz);
} else {
return QuizCardResponse.of((MultipleChoiceQuiz) quiz);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.shy_polarbear.server.global.common.constants;

public abstract class BusinessLogicConstants {
public abstract class BusinessLogicConstants { // TODO refactor: 각 객체로 책임 이동

/**
* 퀴즈
*/
public static final int OX_QUIZ_TIME_LIMIT = 17;
public static final int MULTIPLE_CHOICE_QUIZ_TIME_LIMIT = 17;

public static final String REVIEW_QUIZ_LIMIT_PARAM_DEFAULT_VALUE = "5";

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.shy_polarbear.server.domain.point.model.PointType;
import com.shy_polarbear.server.domain.point.service.PointService;
import com.shy_polarbear.server.domain.quiz.dto.QuizType;
import com.shy_polarbear.server.domain.quiz.model.QuizType;
import com.shy_polarbear.server.domain.quiz.dto.request.MultipleChoiceQuizScoreRequest;
import com.shy_polarbear.server.domain.quiz.dto.request.OXQuizScoreRequest;
import com.shy_polarbear.server.domain.quiz.dto.response.MultipleChoiceQuizScoreResponse;
Expand All @@ -16,7 +16,6 @@
import com.shy_polarbear.server.domain.user.model.User;
import com.shy_polarbear.server.domain.user.service.UserService;
import com.shy_polarbear.server.domain.user.template.UserTemplate;
import com.shy_polarbear.server.global.common.constants.BusinessLogicConstants;
import com.shy_polarbear.server.global.common.dto.PageResponse;
import com.shy_polarbear.server.global.exception.ExceptionStatus;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -81,7 +80,7 @@ public void getDailyQuizSuccess() {
// then
assertThat(response.quizId()).isEqualTo(mockOXQuiz.getId());
assertThat(response.type()).isEqualTo(QuizType.OX.getValue());
assertThat(response.time()).isEqualTo(BusinessLogicConstants.OX_QUIZ_TIME_LIMIT);
assertThat(response.time()).isEqualTo(QuizType.OX.getTimeLimit());
assertThat(response.question()).isEqualTo(mockOXQuiz.getQuestion());
assertThat(response.choices()).isNull();
}
Expand Down Expand Up @@ -110,7 +109,7 @@ public void getRandomReviewQuizzesSuccess() {
PageResponse<QuizCardResponse> response = quizService.getRandomReviewQuizzes(UserTemplate.ID, limit);

// then
List<QuizCardResponse> mockResponse = mockOXQuizList.stream().map(it -> QuizCardResponse.of((OXQuiz) it)).toList();
List<QuizCardResponse> mockResponse = mockOXQuizList.stream().map(it -> QuizCardResponse.from((OXQuiz) it)).toList();
assertThat(response.getContent()).isEqualTo(mockResponse);
}

Expand Down

0 comments on commit b1e247a

Please sign in to comment.