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

태그 목록 검색 기능 리팩터링 #637

Merged
merged 7 commits into from
Oct 11, 2023
Original file line number Diff line number Diff line change
@@ -1,25 +1,12 @@
package touch.baton.domain.tag.command.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import touch.baton.domain.common.vo.TagName;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;

import java.util.List;
import java.util.Optional;

public interface TagCommandRepository extends JpaRepository<Tag, Long> {

Optional<Tag> findByTagName(final TagName tagName);

@Query("""
select t
from Tag t
where t.tagReducedName like :tagReducedName%
order by t.tagReducedName asc
limit 10
""")
List<Tag> readTagsByReducedName(@Param("tagReducedName") TagReducedName tagReducedName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import touch.baton.domain.tag.query.controller.response.TagSearchResponse;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;
import touch.baton.domain.tag.query.controller.response.TagSearchResponses;
import touch.baton.domain.tag.query.service.TagQueryService;

import java.util.Collections;
import java.util.List;

@RequiredArgsConstructor
Expand All @@ -23,14 +23,9 @@ public class TagQueryController {

@GetMapping("/search")
public ResponseEntity<TagSearchResponses.Detail> readTagsByTagName(@Nullable @RequestParam(required = false) final String tagName) {
if (tagName == null || tagName.isBlank()) {
return ResponseEntity.ok().body(TagSearchResponses.Detail.from(Collections.emptyList()));
}
final TagReducedName tagReducedName = TagReducedName.nullableInstance(tagName);
final List<Tag> foundTags = tagQueryService.readTagsByReducedName(tagReducedName, 10);

final List<TagSearchResponse.TagResponse> tagSearchResponses = tagQueryService.readTagsByReducedName(tagName).stream()
.map(TagSearchResponse.TagResponse::from)
.toList();

return ResponseEntity.ok(TagSearchResponses.Detail.from(tagSearchResponses));
return ResponseEntity.ok(TagSearchResponses.Detail.from(foundTags));
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package touch.baton.domain.tag.query.controller.response;

import touch.baton.domain.tag.command.Tag;

import java.util.List;

public record TagSearchResponses() {

public record Detail(List<TagSearchResponse.TagResponse> data) {
public static Detail from(final List<TagSearchResponse.TagResponse> data) {
return new Detail(data);

public static Detail from(final List<Tag> tags) {
final List<TagSearchResponse.TagResponse> response = tags.stream()
.map(TagSearchResponse.TagResponse::from)
.toList();

return new Detail(response);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package touch.baton.domain.tag.query.repository;

import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;

import java.util.Collections;
import java.util.List;

import static touch.baton.domain.tag.command.QTag.tag;

@RequiredArgsConstructor
@Repository
public class TagQuerydslRepository {

private final JPAQueryFactory queryFactory;

public List<Tag> findByTagReducedName(@Nullable final TagReducedName tagReducedName, final int limit) {
if (isTagReducedNameIsNullOrBlank(tagReducedName)) {
return Collections.emptyList();
}

return queryFactory.selectFrom(tag)
.where(tag.tagReducedName.value.startsWith(tagReducedName.getValue()))
.orderBy(tag.tagReducedName.value.asc(), tag.tagName.value.desc())
.limit(limit)
.fetch();
}

private boolean isTagReducedNameIsNullOrBlank(@Nullable final TagReducedName tagReducedName) {
return tagReducedName == null || tagReducedName.getValue().isBlank();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package touch.baton.domain.tag.query.service;

import jakarta.annotation.Nullable;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;
import touch.baton.domain.tag.query.repository.TagQueryRepository;
import touch.baton.domain.tag.query.repository.TagQuerydslRepository;

import java.util.List;

Expand All @@ -14,9 +15,9 @@
@Service
public class TagQueryService {

private final TagQueryRepository tagQueryRepository;
private final TagQuerydslRepository tagQuerydslRepository;

public List<Tag> readTagsByReducedName(final String tagName) {
return tagQueryRepository.readTagsByReducedName(TagReducedName.from(tagName));
public List<Tag> readTagsByReducedName(@Nullable final TagReducedName tagReducedName, final int limit) {
return tagQuerydslRepository.findByTagReducedName(tagReducedName, limit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import touch.baton.domain.member.query.repository.SupporterRunnerPostQueryRepository;

@Profile("test")

public interface TestSupporterRunnerPostQueryRepository extends SupporterRunnerPostQueryRepository {

default Long getApplicantCountByRunnerPostId(final Long runnerPostId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
package touch.baton.assure.repository;

import touch.baton.domain.tag.query.repository.TagQueryRepository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;

public interface TestTagQueryRepository extends TagQueryRepository {
import java.util.List;

public interface TestTagQueryRepository extends JpaRepository<Tag, Long> {

@Query("""
select t
from Tag t
where t.tagReducedName like :tagReducedName%
order by t.tagReducedName asc
limit 10
""")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

limit!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도한건가요?

List<Tag> findTagsByReducedName(@Param("tagReducedName") final TagReducedName tagReducedName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,56 @@

import org.junit.jupiter.api.Test;
import touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport;
import touch.baton.assure.tag.support.query.TagAssuredSupport;
import touch.baton.assure.tag.support.query.TagQuerySupport;
import touch.baton.config.AssuredTestConfig;
import touch.baton.config.infra.auth.oauth.authcode.FakeAuthCodes;
import touch.baton.domain.tag.command.Tag;
import touch.baton.domain.tag.command.vo.TagReducedName;
import touch.baton.domain.tag.query.controller.response.TagSearchResponses;

import java.time.LocalDateTime;
import java.util.List;

import static touch.baton.assure.runnerpost.support.command.RunnerPostCreateSupport.러너_게시글_생성_요청;
import static touch.baton.assure.tag.support.query.TagAssuredSupport.태그_검색_Detail_응답;


@SuppressWarnings("NonAsciiCharacters")
class TagReadAssuredTest extends AssuredTestConfig {

@Test
void 태그_검색에_성공한다() {
void 입력된_문자열로_태그_목록_검색에_성공한다() {
// given
final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode());
러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(헤나_액세스_토큰, List.of("java", "javascript", "script"));
final TagReducedName reducedName = TagReducedName.from("ja");
final List<Tag> 검색된_태그_목록 = tagRepository.readTagsByReducedName(reducedName);
러너_게시글과_태그를_생성한다(헤나_액세스_토큰, List.of("java", "javascript", "script"));

final TagReducedName 요청할_태그_이름 = TagReducedName.nullableInstance("ja");

// when, then
TagAssuredSupport
final List<Tag> 검색된_태그_목록 = tagQueryRepository.findTagsByReducedName(요청할_태그_이름);

TagQuerySupport
.클라이언트_요청()
.액세스_토큰으로_로그인한다(헤나_액세스_토큰)
.태그_이름을_오름차순으로_10개_검색한다("ja")
.입력된_문자열로_태그_목록을_검색한다(요청할_태그_이름)

.서버_응답()
.태그_검색_성공을_검증한다(
태그_검색_Detail_응답(검색된_태그_목록)
.입력된_문자열로_태그_목록_검색_성공을_검증한다(
TagSearchResponses.Detail.from(검색된_태그_목록)
);
}

private void 러너_게시글_생성을_성공하고_러너_게시글_식별자값을_반환한다(final String 헤나_액세스_토큰, final List<String> 태그_목록) {
private void 러너_게시글과_태그를_생성한다(final String 액세스_토큰, final List<String> 태그_목록) {
RunnerPostCreateSupport
.클라이언트_요청()
.액세스_토큰으로_로그인한다(헤나_액세스_토큰)
.러너_게시글_등록_요청한다(
러너_게시글_생성_요청(
"테스트용_러너_게시글_제목",
태그_목록,
"https://test-pull-request.com",
LocalDateTime.now().plusHours(100),
"테스트용_러너_게시글_구현_내용",
"테스트용_러너_게시글_궁금한_내용",
"테스트용_러너_게시글_참고_사항"
)
)
.액세스_토큰으로_로그인한다(액세스_토큰)
.러너_게시글_등록_요청한다(러너_게시글_생성_요청(
"테스트용_러너_게시글_제목",
태그_목록,
"https://test-pull-request.com",
LocalDateTime.now().plusHours(100),
"테스트용_러너_게시글_구현_내용",
"테스트용_러너_게시글_궁금한_내용",
"테스트용_러너_게시글_참고_사항"
))

.서버_응답()
.러너_게시글_생성_성공을_검증한다();
Expand Down

This file was deleted.

Loading