Skip to content

Commit

Permalink
Merge pull request #1472 from woowacourse/feature/1461-로드맵_키워드_반환_기능_추가
Browse files Browse the repository at this point in the history
feat : 커리큘럼 ID로 키워드들 조회 API 구현
  • Loading branch information
java-saeng authored Aug 7, 2023
2 parents 8ff6c20 + 3877b7d commit ad9d2b3
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package wooteco.prolog.roadmap.application;

import static wooteco.prolog.common.exception.BadRequestCode.CURRICULUM_NOT_FOUND_EXCEPTION;

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 wooteco.prolog.common.exception.BadRequestException;
import wooteco.prolog.roadmap.application.dto.KeywordsResponse;
import wooteco.prolog.roadmap.domain.Curriculum;
import wooteco.prolog.roadmap.domain.Keyword;
import wooteco.prolog.roadmap.domain.repository.CurriculumRepository;
import wooteco.prolog.roadmap.domain.repository.KeywordRepository;
import wooteco.prolog.session.domain.Session;
import wooteco.prolog.session.domain.repository.SessionRepository;

@RequiredArgsConstructor
@Transactional
@Service
public class RoadMapService {

private final CurriculumRepository curriculumRepository;
private final SessionRepository sessionRepository;
private final KeywordRepository keywordRepository;

@Transactional(readOnly = true)
public KeywordsResponse findAllKeywords(final Long curriculumId) {
final Curriculum curriculum = curriculumRepository.findById(curriculumId)
.orElseThrow(() -> new BadRequestException(CURRICULUM_NOT_FOUND_EXCEPTION));

final Set<Long> sessionIds = sessionRepository.findAllByCurriculumId(curriculum.getId())
.stream()
.map(Session::getId)
.collect(Collectors.toSet());

final List<Keyword> keywords = keywordRepository.findBySessionIdIn(sessionIds);

return KeywordsResponse.createResponseWithChildren(keywords);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ public static KeywordsResponse createResponse(final List<Keyword> keywords) {
.collect(Collectors.toList());
return new KeywordsResponse(keywordsResponse);
}

public static KeywordsResponse createResponseWithChildren(final List<Keyword> keywords) {
List<KeywordResponse> keywordsResponse = keywords.stream()
.filter(Keyword::isRoot)
.map(KeywordResponse::createWithAllChildResponse)
.collect(Collectors.toList());
return new KeywordsResponse(keywordsResponse);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ private void validateKeywordParent(final Keyword parentKeyword) {
}
}

public boolean isRoot() {
return parent == null;
}

public Long getParentIdOrNull() {
if (parent == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package wooteco.prolog.roadmap.domain.repository;

import java.util.List;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
Expand All @@ -17,4 +18,6 @@ public interface KeywordRepository extends JpaRepository<Keyword, Long> {
@Query("SELECT k FROM Keyword k "
+ "WHERE k.sessionId = :sessionId AND k.parent IS NULL")
List<Keyword> findBySessionIdAndParentIsNull(@Param("sessionId") Long sessionId);

List<Keyword> findBySessionIdIn(final Set<Long> sessionIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package wooteco.prolog.roadmap.ui;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import wooteco.prolog.roadmap.application.RoadMapService;
import wooteco.prolog.roadmap.application.dto.KeywordsResponse;

@RequiredArgsConstructor
@RestController
public class RoadmapController {

private final RoadMapService roadMapService;

@GetMapping("/roadmaps")
public KeywordsResponse findRoadMapKeyword(@RequestParam final Long curriculumId) {
return roadMapService.findAllKeywords(curriculumId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package wooteco.prolog.roadmap.application;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import wooteco.prolog.roadmap.application.dto.KeywordsResponse;
import wooteco.prolog.roadmap.domain.Curriculum;
import wooteco.prolog.roadmap.domain.Keyword;
import wooteco.prolog.roadmap.domain.repository.CurriculumRepository;
import wooteco.prolog.roadmap.domain.repository.KeywordRepository;
import wooteco.prolog.session.domain.Session;
import wooteco.prolog.session.domain.repository.SessionRepository;

@ExtendWith(MockitoExtension.class)
class RoadMapServiceTest {

@Mock
private CurriculumRepository curriculumRepository;
@Mock
private SessionRepository sessionRepository;
@Mock
private KeywordRepository keywordRepository;
@InjectMocks
private RoadMapService roadMapService;

@Test
@DisplayName("curriculumId가 주어지면 해당 커리큘럼의 키워드들을 전부 조회할 수 있다.")
void findAllKeywords() {
//given
final Curriculum curriculum = new Curriculum(1L, "커리큘럼1");
final Session session = new Session(1L, curriculum.getId(), "세션1");
final List<Session> sessions = Arrays.asList(session);
final Keyword keyword = new Keyword(1L, "자바1", "자바 설명1", 1, 5, session.getId(),
null, Collections.emptySet());

when(curriculumRepository.findById(anyLong()))
.thenReturn(Optional.of(curriculum));

when(sessionRepository.findAllByCurriculumId(anyLong()))
.thenReturn(sessions);

when(keywordRepository.findBySessionIdIn(any()))
.thenReturn(Arrays.asList(keyword));

final KeywordsResponse expected = KeywordsResponse.createResponseWithChildren(Arrays.asList(keyword));

//when
final KeywordsResponse actual =
roadMapService.findAllKeywords(curriculum.getId());

//then
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import javax.persistence.EntityManager;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import wooteco.prolog.roadmap.domain.Curriculum;
import wooteco.prolog.roadmap.domain.Keyword;
import wooteco.prolog.roadmap.domain.repository.CurriculumRepository;
import wooteco.prolog.roadmap.domain.repository.KeywordRepository;
import wooteco.prolog.session.domain.Session;
import wooteco.prolog.session.domain.repository.SessionRepository;
Expand All @@ -23,6 +27,8 @@ class KeywordRepositoryTest {
private SessionRepository sessionRepository;
@Autowired
private EntityManager em;
@Autowired
private CurriculumRepository curriculumRepository;

@Test
void 부모_키워드와_1뎁스까지의_자식_키워드를_함께_조회할__있다() {
Expand Down Expand Up @@ -105,7 +111,54 @@ class KeywordRepositoryTest {
sessionId);

// then
Assertions.assertThat(extractParentKeyword.size()).isEqualTo(1);
assertThat(extractParentKeyword.size()).isEqualTo(1);
}

@Test
@DisplayName("세션 ID 리스트로 키워드 리스트를 조회한다")
void findBySessionIdIn() {
//given
final Curriculum curriculum = curriculumRepository.save(new Curriculum("커리큘럼1"));

final Session session1 = sessionRepository.save(new Session(curriculum.getId(), "세션1"));
final Session session2 = sessionRepository.save(new Session(curriculum.getId(), "세션2"));
final Session session3 = sessionRepository.save(new Session(curriculum.getId(), "세션3"));
final Session session4 = sessionRepository.save(new Session(curriculum.getId(), "세션4"));
final Session session5 = sessionRepository.save(new Session(curriculum.getId(), "세션5"));

final Keyword keyword1 = keywordRepository.save(
Keyword.createKeyword("자바1", "자바 설명1", 1, 5, session1.getId(), null));
final Keyword keyword2 = keywordRepository.save(
Keyword.createKeyword("자바2", "자바 설명2", 2, 5, session1.getId(), keyword1));
final Keyword keyword3 = keywordRepository.save(
Keyword.createKeyword("자바3", "자바 설명3", 3, 5, session1.getId(), null));
final Keyword keyword4 = keywordRepository.save(
Keyword.createKeyword("자바4", "자바 설명4", 4, 5, session1.getId(), keyword3));
keywordRepository.save(
Keyword.createKeyword("자바5", "자바 설명5", 5, 5, session2.getId(), null));
keywordRepository.save(
Keyword.createKeyword("자바6", "자바 설명6", 6, 5, session2.getId(), keyword1));
keywordRepository.save(
Keyword.createKeyword("자바7", "자바 설명7", 7, 5, session2.getId(), null));
keywordRepository.save(
Keyword.createKeyword("자바8", "자바 설명8", 8, 5, session3.getId(), keyword2));
final Keyword keyword9 = keywordRepository.save(
Keyword.createKeyword("자바9", "자바 설명9", 9, 5, session4.getId(), keyword2));
final Keyword keyword10 = keywordRepository.save(
Keyword.createKeyword("자바10", "자바 설명10", 10, 5, session5.getId(), null));

final HashSet<Long> sessionIds = new HashSet<>(
Arrays.asList(session1.getId(), session4.getId(), session5.getId())
);

//when
final List<Keyword> keywords = keywordRepository.findBySessionIdIn(sessionIds);

//then
assertThat(keywords)
.usingRecursiveComparison()
.ignoringFields("id", "parent.id")
.isEqualTo(Arrays.asList(keyword1, keyword2, keyword3, keyword4, keyword9, keyword10));
}

private Keyword createKeywordParent(final Keyword keyword) {
Expand Down

0 comments on commit ad9d2b3

Please sign in to comment.