-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1613 from woowacourse/refactor/1609-roadmap
로드맵 서비스 로직 가독성 개선
- Loading branch information
Showing
12 changed files
with
396 additions
and
278 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
115 changes: 20 additions & 95 deletions
115
backend/src/main/java/wooteco/prolog/roadmap/application/RoadMapService.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 |
---|---|---|
@@ -1,122 +1,47 @@ | ||
package wooteco.prolog.roadmap.application; | ||
|
||
import java.util.Comparator; | ||
import java.util.HashSet; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import wooteco.prolog.common.exception.BadRequestException; | ||
import wooteco.prolog.roadmap.application.dto.KeywordResponse; | ||
import wooteco.prolog.roadmap.application.dto.KeywordsResponse; | ||
import wooteco.prolog.roadmap.application.dto.RecommendedPostResponse; | ||
import wooteco.prolog.roadmap.domain.Curriculum; | ||
import wooteco.prolog.roadmap.domain.EssayAnswer; | ||
import wooteco.prolog.roadmap.domain.Keyword; | ||
import wooteco.prolog.roadmap.domain.Quiz; | ||
import wooteco.prolog.roadmap.domain.repository.CurriculumRepository; | ||
import wooteco.prolog.roadmap.domain.repository.EssayAnswerRepository; | ||
import wooteco.prolog.roadmap.domain.repository.KeywordRepository; | ||
import wooteco.prolog.roadmap.domain.repository.QuizRepository; | ||
import wooteco.prolog.session.domain.Session; | ||
import wooteco.prolog.session.domain.repository.SessionRepository; | ||
import wooteco.prolog.roadmap.domain.repository.dto.KeywordIdAndAnsweredQuizCount; | ||
import wooteco.prolog.roadmap.domain.repository.dto.KeywordIdAndTotalQuizCount; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import static java.util.stream.Collectors.groupingBy; | ||
import static java.util.stream.Collectors.toList; | ||
import static java.util.stream.Collectors.toSet; | ||
import static wooteco.prolog.common.exception.BadRequestCode.CURRICULUM_NOT_FOUND_EXCEPTION; | ||
import static java.util.stream.Collectors.toMap; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional | ||
@Transactional(readOnly = true) | ||
@Service | ||
public class RoadMapService { | ||
|
||
private final CurriculumRepository curriculumRepository; | ||
private final SessionRepository sessionRepository; | ||
private final KeywordRepository keywordRepository; | ||
private final QuizRepository quizRepository; | ||
private final EssayAnswerRepository essayAnswerRepository; | ||
|
||
@Transactional(readOnly = true) | ||
public KeywordsResponse findAllKeywordsWithProgress(final Long curriculumId, final Long memberId) { | ||
final Curriculum curriculum = curriculumRepository.findById(curriculumId) | ||
.orElseThrow(() -> new BadRequestException(CURRICULUM_NOT_FOUND_EXCEPTION)); | ||
final List<Keyword> keywords = keywordRepository.findAllByCurriculumId(curriculumId); | ||
final Map<Long, Integer> totalQuizCounts = getTotalQuizCounts(); | ||
final Map<Long, Integer> answeredQuizCounts = getAnsweredQuizCounts(memberId); | ||
|
||
final List<Keyword> keywordsInCurriculum = getKeywordsInCurriculum(curriculum); | ||
|
||
final Map<Keyword, Set<Quiz>> quizzesInKeywords = quizRepository.findAll().stream() | ||
.collect(groupingBy(Quiz::getKeyword, toSet())); | ||
|
||
return createResponsesWithProgress(keywordsInCurriculum, quizzesInKeywords, getDoneQuizzes(memberId)); | ||
} | ||
|
||
private Set<Quiz> getDoneQuizzes(final Long memberId) { | ||
return essayAnswerRepository.findAllByMemberId(memberId).stream() | ||
.map(EssayAnswer::getQuiz) | ||
.collect(toSet()); | ||
} | ||
|
||
private List<Keyword> getKeywordsInCurriculum(final Curriculum curriculum) { | ||
final Set<Long> sessionIds = sessionRepository.findAllByCurriculumId(curriculum.getId()) | ||
.stream() | ||
.map(Session::getId) | ||
.collect(toSet()); | ||
|
||
return keywordRepository.findBySessionIdIn(sessionIds); | ||
} | ||
|
||
private KeywordsResponse createResponsesWithProgress(final List<Keyword> keywords, | ||
final Map<Keyword, Set<Quiz>> quizzesPerKeyword, | ||
final Set<Quiz> doneQuizzes) { | ||
final List<KeywordResponse> keywordResponses = keywords.stream() | ||
.filter(Keyword::isRoot) | ||
.map(keyword -> createResponseWithProgress(keyword, quizzesPerKeyword, doneQuizzes)) | ||
.sorted(Comparator.comparing(KeywordResponse::getKeywordId)) | ||
.collect(toList()); | ||
|
||
return new KeywordsResponse(keywordResponses); | ||
} | ||
|
||
private KeywordResponse createResponseWithProgress(final Keyword keyword, | ||
final Map<Keyword, Set<Quiz>> quizzesPerKeyword, | ||
final Set<Quiz> doneQuizzes) { | ||
final int totalQuizCount = quizzesPerKeyword.getOrDefault(keyword, new HashSet<>()).size(); | ||
final int doneQuizCount = getDoneQuizCount( | ||
quizzesPerKeyword.getOrDefault(keyword, new HashSet<>()), doneQuizzes); | ||
|
||
final List<RecommendedPostResponse> recommendedPostResponses = keyword.getRecommendedPosts().stream() | ||
.map(RecommendedPostResponse::from) | ||
.collect(toList()); | ||
|
||
return new KeywordResponse( | ||
keyword.getId(), | ||
keyword.getName(), | ||
keyword.getDescription(), | ||
keyword.getSeq(), | ||
keyword.getImportance(), | ||
totalQuizCount, | ||
doneQuizCount, | ||
keyword.getParentIdOrNull(), | ||
recommendedPostResponses, | ||
createChildrenWithProgress(keyword.getChildren(), quizzesPerKeyword, doneQuizzes) | ||
); | ||
return KeywordsResponse.of(keywords, totalQuizCounts, answeredQuizCounts); | ||
} | ||
|
||
private int getDoneQuizCount(final Set<Quiz> quizzes, final Set<Quiz> doneQuizzes) { | ||
quizzes.retainAll(doneQuizzes); | ||
return quizzes.size(); | ||
private Map<Long, Integer> getTotalQuizCounts() { | ||
return keywordRepository.findTotalQuizCount().stream() | ||
.collect( | ||
toMap( | ||
KeywordIdAndTotalQuizCount::getKeywordId, | ||
KeywordIdAndTotalQuizCount::getTotalQuizCount)); | ||
} | ||
|
||
private List<KeywordResponse> createChildrenWithProgress(final Set<Keyword> children, | ||
final Map<Keyword, Set<Quiz>> quizzesPerKeyword, | ||
final Set<Quiz> userAnswers) { | ||
return children.stream() | ||
.map(child -> createResponseWithProgress(child, quizzesPerKeyword, userAnswers)) | ||
.sorted(Comparator.comparing(KeywordResponse::getKeywordId)) | ||
.collect(Collectors.toList()); | ||
private Map<Long, Integer> getAnsweredQuizCounts(final Long memberId) { | ||
return keywordRepository.findAnsweredQuizCountByMemberId(memberId).stream() | ||
.collect( | ||
toMap( | ||
KeywordIdAndAnsweredQuizCount::getKeywordId, | ||
KeywordIdAndAnsweredQuizCount::getAnsweredQuizCount)); | ||
} | ||
} |
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
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
Oops, something went wrong.