Skip to content

Commit

Permalink
[Feature] - 여행기 나라 관련 리팩토링 (#586)
Browse files Browse the repository at this point in the history
* refactor: CountryCode 내부로 검증 로직 이동

* refactor: 통일성을 위해 SearchType 의 from 메소드 수정

* feat: TravelogueCountry 검증 로직 추가

* style: 통일성을 위해 "나라"를 "국가" 로 변경

* feat: 여행기 장소 생성시 국가 코드가 NONE 인지 검증하는 로직 추가

* feat: 여행기 생성 시 국가 코드가 NONE 인 여행기 장소가 생성되지 않는 기능 구현

* feat: 태그 생성 기능 삭제

* sytle: 통일성을 위해 괄호 수정

Co-authored-by: eunjungL <[email protected]>

* feat: TravelogueCountry 에 NONE 국가 코드 허용

* feat: 존재하지 않는 국가로 검색 시 빈 여행기 목록을 반환하는 기능 구현

* refactor: 비즈니스 로직을 facade 가 아닌 서비스에서 수행하도록 변경

* test: 존재하지 않는 국가 검색 테스트 코드 추가

---------

Co-authored-by: eunjungL <[email protected]>
  • Loading branch information
nak-honest and eunjungL authored Oct 24, 2024
1 parent d574795 commit 425166a
Show file tree
Hide file tree
Showing 27 changed files with 374 additions and 232 deletions.
27 changes: 0 additions & 27 deletions backend/src/main/java/kr/touroot/tag/controller/TagController.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
package kr.touroot.tag.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.net.URI;
import java.util.List;
import kr.touroot.global.exception.dto.ExceptionResponse;
import kr.touroot.tag.dto.TagCreateRequest;
import kr.touroot.tag.dto.TagResponse;
import kr.touroot.tag.service.TagService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -29,25 +21,6 @@ public class TagController {

private final TagService tagService;

@Operation(summary = "태그 생성")
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
description = "태그가 생성이 정상적으로 성공했을 때"
),
@ApiResponse(
responseCode = "400",
description = "Body에 유효하지 않은 값이 존재하거나 중복된 태그가 존재할 때",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
)
})
@PostMapping
public ResponseEntity<TagResponse> createTag(@Valid @RequestBody TagCreateRequest request) {
TagResponse data = tagService.createTag(request);
return ResponseEntity.created(URI.create("/api/v1/tags/" + data.id()))
.body(data);
}

@Operation(summary = "모든 태그 조회")
@ApiResponses(value = {
@ApiResponse(
Expand Down
15 changes: 0 additions & 15 deletions backend/src/main/java/kr/touroot/tag/dto/TagCreateRequest.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@
import org.springframework.data.jpa.repository.JpaRepository;

public interface TagRepository extends JpaRepository<Tag, Long> {

boolean existsByTag(String tag);
}
17 changes: 0 additions & 17 deletions backend/src/main/java/kr/touroot/tag/service/TagService.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package kr.touroot.tag.service;

import java.util.List;
import kr.touroot.global.exception.BadRequestException;
import kr.touroot.tag.domain.Tag;
import kr.touroot.tag.dto.TagCreateRequest;
import kr.touroot.tag.dto.TagResponse;
import kr.touroot.tag.repository.TagRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -19,20 +16,6 @@ public class TagService {

private final TagRepository tagRepository;

@Transactional
public TagResponse createTag(TagCreateRequest tagCreateRequest) {
validateDuplicated(tagCreateRequest);
Tag savedTag = tagRepository.save(tagCreateRequest.toTag());

return TagResponse.from(savedTag);
}

private void validateDuplicated(TagCreateRequest tagCreateRequest) {
if (tagRepository.existsByTag(tagCreateRequest.tag())) {
throw new BadRequestException("이미 존재하는 태그입니다.");
}
}

@Cacheable(cacheNames = "tag")
@Transactional(readOnly = true)
public List<TagResponse> readTags() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import kr.touroot.global.exception.BadRequestException;
import kr.touroot.travelogue.domain.search.CountryCode;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand All @@ -24,6 +25,8 @@
@Entity
public class TravelogueCountry {

private static final int MIN_COUNT = 1;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Expand All @@ -40,8 +43,27 @@ public class TravelogueCountry {
private Integer count;

public TravelogueCountry(Travelogue travelogue, CountryCode countryCode, Integer count) {
validate(travelogue, countryCode, count);
this.travelogue = travelogue;
this.countryCode = countryCode;
this.count = count;
}


private void validate(Travelogue travelogue, CountryCode countryCode, Integer count) {
validateNotNull(travelogue, countryCode, count);
validateCount(count);
}

private void validateNotNull(Travelogue travelogue, CountryCode countryCode, Integer count) {
if (travelogue == null || countryCode == null || count == null) {
throw new BadRequestException("여행기와 국가 코드, 국가 코드의 count 는 null 일 수 없습니다.");
}
}

private void validateCount(Integer count) {
if (count < MIN_COUNT) {
throw new BadRequestException(String.format("국가 코드의 개수는 %d 보다 커야합니다.", MIN_COUNT));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public TraveloguePlace(
this.name = name;
this.position = position;
this.travelogueDay = travelogueDay;
this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
this.countryCode = CountryCode.from(countryCode);
}

public TraveloguePlace(
Expand Down Expand Up @@ -147,11 +147,7 @@ private void validatePlaceNameLength(String placeName) {
}

private void validateCountryCode(String countryCode) {
try {
CountryCode.valueOfIgnoreCase(countryCode);
} catch (IllegalArgumentException e) {
throw new BadRequestException("존재하지 않는 국가 코드입니다");
}
CountryCode.from(countryCode);
}

public void addPhoto(TraveloguePhoto photo) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Arrays;
import java.util.Set;
import kr.touroot.global.exception.BadRequestException;

public enum CountryCode {

Expand Down Expand Up @@ -259,7 +260,11 @@ public static CountryCode findByName(String name) {
.orElse(NONE);
}

public static CountryCode valueOfIgnoreCase(String name) {
return CountryCode.valueOf(name.toUpperCase());
public static CountryCode from(String code) {
try {
return CountryCode.valueOf(code.toUpperCase());
} catch (IllegalArgumentException exception) {
throw new BadRequestException("존재하지 않는 국가 코드입니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ public SearchCondition(String keyword, SearchType searchType) {
public boolean isEmptyCondition() {
return keyword == null && searchType == null;
}

public boolean isNoneCountry() {
return searchType == SearchType.COUNTRY && CountryCode.findByName(keyword) == CountryCode.NONE;
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package kr.touroot.travelogue.domain.search;

import java.util.Arrays;
import kr.touroot.global.exception.BadRequestException;

public enum SearchType {
TITLE, AUTHOR, COUNTRY;

public static SearchType from(String searchType) {
return Arrays.stream(SearchType.values())
.filter(type -> searchType.equalsIgnoreCase(type.name()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 검색 키워드 종류입니다."));
try {
return SearchType.valueOf(searchType.toUpperCase());
} catch (IllegalArgumentException exception) {
throw new BadRequestException("존재하지 않는 검색 키워드 종류입니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,34 @@ public class TravelogueCountryService {

private final TravelogueCountryRepository travelogueCountryRepository;

@Transactional(readOnly = true)
public List<TravelogueCountry> readCountryByTravelogue(Travelogue travelogue) {
return travelogueCountryRepository.findAllByTravelogue(travelogue);
}

@Transactional
public void createTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
public List<TravelogueCountry> createTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
Map<CountryCode, Long> countryCounts = countCountries(request);

countryCounts.forEach((countryCode, count) -> travelogueCountryRepository.save(
new TravelogueCountry(travelogue, countryCode, count.intValue())));
return countryCounts.entrySet().stream()
.map(entry -> travelogueCountryRepository.save(
new TravelogueCountry(travelogue, entry.getKey(), entry.getValue().intValue()))
)
.toList();
}

private Map<CountryCode, Long> countCountries(TravelogueRequest request) {
return request.days().stream()
.flatMap(day -> day.places().stream())
.map(place -> CountryCode.valueOf(place.countryCode()))
.filter(countryCode -> countryCode != CountryCode.NONE)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

@Transactional(readOnly = true)
public List<TravelogueCountry> getTravelogueCountryByTravelogue(Travelogue travelogue) {
return travelogueCountryRepository.findAllByTravelogue(travelogue);
}

@Transactional
public void updateTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
public List<TravelogueCountry> updateTravelogueCountries(Travelogue travelogue, TravelogueRequest request) {
deleteAllByTravelogue(travelogue);
createTravelogueCountries(travelogue, request);
return createTravelogueCountries(travelogue, request);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public Page<TravelogueSimpleResponse> findSimpleTravelogues(
) {
TravelogueFilterCondition filter = filterRequest.toFilterCondition();
SearchCondition searchCondition = searchRequest.toSearchCondition();

Page<Travelogue> travelogues = travelogueService.findAll(searchCondition, filter, pageable);

return travelogues.map(this::getTravelogueSimpleResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ public Page<Travelogue> findAllByMember(Member member, Pageable pageable) {
public Page<Travelogue> findByKeyword(TravelogueSearchRequest request, Pageable pageable) {
SearchType searchType = SearchType.from(request.searchType());
SearchCondition searchCondition = new SearchCondition(request.keyword(), searchType);
if (searchCondition.isNoneCountry()) {
return Page.empty();
}

return travelogueQueryRepository.findAllBySearchCondition(searchCondition, pageable);
}
Expand All @@ -55,6 +58,10 @@ public Page<Travelogue> findAll(
TravelogueFilterCondition filter,
Pageable pageable
) {
if (searchCondition.isNoneCountry()) {
return Page.empty();
}

if (filter.isEmptyCondition() && searchCondition.isEmptyCondition()) {
return travelogueRepository.findAll(pageable);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public TravelPlanPlace(Long id, Integer order, TravelPlanDay day, String name, P
this.day = day;
this.name = name;
this.position = position;
this.countryCode = CountryCode.valueOfIgnoreCase(countryCode);
this.countryCode = CountryCode.from(countryCode);
}

public TravelPlanPlace(Integer order, TravelPlanDay day, String name, String latitude, String longitude,
Expand Down Expand Up @@ -115,7 +115,7 @@ private void validatePlaceNameLength(String placeName) {

private void validateCountryCode(String countryCode) {
try {
CountryCode.valueOfIgnoreCase(countryCode);
CountryCode.from(countryCode);
} catch (IllegalArgumentException e) {
throw new BadRequestException("존재하지 않는 국가 코드입니다");
}
Expand Down
56 changes: 0 additions & 56 deletions backend/src/test/java/kr/touroot/tag/TagControllerTest.java

This file was deleted.

5 changes: 0 additions & 5 deletions backend/src/test/java/kr/touroot/tag/fixture/TagFixture.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package kr.touroot.tag.fixture;

import kr.touroot.tag.domain.Tag;
import kr.touroot.tag.dto.TagCreateRequest;
import kr.touroot.tag.dto.TagResponse;

public enum TagFixture {
Expand All @@ -21,10 +20,6 @@ public Tag get() {
return new Tag(tag);
}

public TagCreateRequest getCreateRequest() {
return new TagCreateRequest(tag);
}

public TagResponse getResponse(Long id) {
return new TagResponse(id, tag);
}
Expand Down
Loading

0 comments on commit 425166a

Please sign in to comment.