diff --git a/src/main/java/com/developer/wiki/question/command/domain/QuestionSearchRepository.java b/src/main/java/com/developer/wiki/question/command/domain/QuestionSearchRepository.java index 7b9b37b..ac24560 100644 --- a/src/main/java/com/developer/wiki/question/command/domain/QuestionSearchRepository.java +++ b/src/main/java/com/developer/wiki/question/command/domain/QuestionSearchRepository.java @@ -1,12 +1,11 @@ package com.developer.wiki.question.command.domain; import com.developer.wiki.question.query.application.SummaryQuestionResponse; +import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; -import java.util.List; - public interface QuestionSearchRepository { Page findPageByUserId(Pageable pageable, String mainCategory, List subCategory, @@ -16,4 +15,6 @@ Page findBookmarkByUserId(Pageable pageable, String mai Long userId); Slice findRandomBy(Pageable pageable, String mainCategory, List subCategory); + + Page findPageByUserIdAndKeyword(Pageable pageable, Long userId, String keyword); } diff --git a/src/main/java/com/developer/wiki/question/infra/QuestionSearchRepositoryImpl.java b/src/main/java/com/developer/wiki/question/infra/QuestionSearchRepositoryImpl.java index ab14cab..375dd1f 100644 --- a/src/main/java/com/developer/wiki/question/infra/QuestionSearchRepositoryImpl.java +++ b/src/main/java/com/developer/wiki/question/infra/QuestionSearchRepositoryImpl.java @@ -86,6 +86,23 @@ public Slice findRandomBy(Pageable pageable, String mainCategory, return new SliceImpl<>(courses, pageable, hasNext); } + @Override + public Page findPageByUserIdAndKeyword(Pageable pageable, Long userId, + String keyword) { + List questions = jpaQueryFactory.select(question).from(question) + .leftJoin(question.bookmarks) + .where(keywordListContains(keyword), question.isApproved.isTrue()) + .orderBy(question.id.asc()).offset(pageable.getOffset()).limit(pageable.getPageSize()) + .distinct().fetch(); + List summaryQuestionResponses = questions.stream().map(question -> { + Boolean isBookmarked = exist(question.getId(), userId); + return new SummaryQuestionResponse(question.getId(), question.getTitle(), + question.getMainCategory(), question.getSubCategory(), question.getViewCount(), + question.getCommentCount(), question.getCreatedAt(), isBookmarked); + }).collect(Collectors.toList()); + return new PageImpl<>(summaryQuestionResponses, pageable, questions.size()); + } + private BooleanExpression mainCategoryEq(String mainCategory) { return ObjectUtils.isEmpty(mainCategory) ? null : question.mainCategory.eq(MainCategory.of(mainCategory)); @@ -112,7 +129,7 @@ private BooleanExpression userIdEq(Long userId) { return Objects.isNull(userId) ? null : bookmark.userId.eq(userId); } - public Boolean exist(Long questionId, Long userId) { + private Boolean exist(Long questionId, Long userId) { if (userId == null) { userId = 0L; } @@ -123,4 +140,17 @@ public Boolean exist(Long questionId, Long userId) { } + private BooleanBuilder keywordListContains(String keyword) { + if (ObjectUtils.isEmpty(keyword)) { + return null; + } + BooleanBuilder builder = new BooleanBuilder(); + String[] splitedKeyword = keyword.split(" "); + for (String value : splitedKeyword) { + builder.or(question.title.contains(value)); + builder.or(question.tailQuestions.any().tailQuestion.contains(value)); + } + return builder; + } + } diff --git a/src/main/java/com/developer/wiki/question/presentation/question/QuestionSearchController.java b/src/main/java/com/developer/wiki/question/presentation/question/QuestionSearchController.java new file mode 100644 index 0000000..fecd740 --- /dev/null +++ b/src/main/java/com/developer/wiki/question/presentation/question/QuestionSearchController.java @@ -0,0 +1,30 @@ +package com.developer.wiki.question.presentation.question; + +import com.developer.wiki.oauth.User; +import com.developer.wiki.question.query.application.QuestionSearchService; +import com.developer.wiki.question.query.application.SummaryQuestionResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/questions") +@RequiredArgsConstructor +public class QuestionSearchController { + + private final QuestionSearchService questionSearchService; + + @GetMapping("/search") + public ResponseEntity> getSlice( + @AuthenticationPrincipal User currentUser, @RequestParam String keyword, Pageable pageable) { + Slice summarySlice = questionSearchService.findPage(pageable, + currentUser, keyword); + return ResponseEntity.ok(summarySlice); + } +} diff --git a/src/main/java/com/developer/wiki/question/query/application/QuestionSearchService.java b/src/main/java/com/developer/wiki/question/query/application/QuestionSearchService.java new file mode 100644 index 0000000..be0bab2 --- /dev/null +++ b/src/main/java/com/developer/wiki/question/query/application/QuestionSearchService.java @@ -0,0 +1,24 @@ +package com.developer.wiki.question.query.application; + +import com.developer.wiki.oauth.User; +import com.developer.wiki.question.command.domain.QuestionSearchRepository; +import java.util.Objects; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class QuestionSearchService { + + private final QuestionSearchRepository questionSearchRepository; + + public Slice findPage(Pageable pageable, + User currentUser, String keyword) { + Long userId = Objects.isNull(currentUser) ? null : currentUser.getId(); + return questionSearchRepository.findPageByUserIdAndKeyword(pageable, userId, keyword); + } +}