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

[BE] feat: 상품 검색 기능 구현 #445

Merged
merged 6 commits into from
Aug 16, 2023
Merged

[BE] feat: 상품 검색 기능 구현 #445

merged 6 commits into from
Aug 16, 2023

Conversation

Go-Jaecheol
Copy link
Collaborator

Issue

✨ 구현한 기능

상품 검색 기능 구현

  • 공통 상품, PB 상품 같이 통합해서 검색하도록 구현
  • 자동 완성 API, 검색 결과 API 분리
    • 자동 완성의 경우에는 API 호출을 자주하고, 모든 상품 정보를 반환할 필요가 없음
    • 자동 완성 API : 상품 정보에서 id, name, categoryType만 반환
    • 검색 결과 API : 필요한 상품 정보 전부 반환
  • 페이징 처리 (size : 10, sort : X)

검색 관련 쿼리

SELECT *
FROM product
WHERE name LIKE '%망고%';
SELECT *
FROM product
WHERE name LIKE '%망고%'
ORDER BY CASE WHEN name LIKE '망고%' THEN 1 ELSE 2 END;

위 방식은 순서에 상관없이 '망고'라는 문자열이 포함된 상품명을 다 조회하기 때문에, 사용자의 의도에 맞는 정확한 검색과는 거리가 멀다.
=> '망고'라는 검색어로 시작하는 문자열이 먼저 출력될 수 있도록 ORDER BY + CASE WHEN ~ 사용
ex)
망고주스
망고푸딩
애플망고

📢 논의하고 싶은 내용

  • controller에서 PageRequest 재정의하고 service로 넘겨주는 이유
    • CustomPageableHandlerMethodArgumentResolver로 인해서 Pageable에 id로 정렬하는 sort 옵션이 기본으로 들어가있음
    • 따라서 ORDER BY 절을 포함시켜서 쿼리를 날리게 되는데, 위 ORDER BY 절과 중복돼서 에러 발생
      => controller에서 service로 Pageable 넘기기 전에 PageRequest.of()로 재정의

🎸 기타

  • 위 SQL문과 실제 구현한 JPQL 쿼리문이 다른 이유

⏰ 일정

  • 추정 시간 : 3h
  • 걸린 시간 : 6h

@github-actions
Copy link

github-actions bot commented Aug 14, 2023

Unit Test Results

159 tests   159 ✔️  15s ⏱️
  90 suites      0 💤
  90 files        0

Results for commit f98f02c.

♻️ This comment has been updated with latest results.

Copy link
Collaborator

@wugawuga wugawuga left a comment

Choose a reason for hiding this comment

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

controller에서 PageRequest 재정의하고 service로 넘겨주는 이유
CustomPageableHandlerMethodArgumentResolver로 인해서 Pageable에 id로 정렬하는 sort 옵션이 기본으로 들어가있음
따라서 ORDER BY 절을 포함시켜서 쿼리를 날리게 되는데, 위 ORDER BY 절과 중복돼서 에러 발생
=> controller에서 service로 Pageable 넘기기 전에 PageRequest.of()로 재정의

저는 괜찮다고 생각해요!

@@ -40,4 +44,18 @@ public ResponseEntity<RankingProductsResponse> getRankingProducts() {
final RankingProductsResponse response = productService.getTop3Products();
return ResponseEntity.ok(response);
}

@GetMapping("/search/products")
public ResponseEntity<SearchProductsResponse> searchProducts(@RequestParam final String query, @PageableDefault final Pageable pageable) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

제 인텔리제이에서 보니까 query 이후에 pageable 줄바꿈을 해주네요!!

}

@GetMapping("/search/products/results")
public ResponseEntity<SearchProductResultsResponse> getSearchResults(@RequestParam final String query, @PageableDefault final Pageable pageable) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

이부분도 줄바꿈을 해줘요!!

Comment on lines 52 to 55
@GetMapping
ResponseEntity<SearchProductsResponse> searchProducts(
@RequestParam final String query, @PageableDefault final Pageable pageable
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
@GetMapping
ResponseEntity<SearchProductsResponse> searchProducts(
@RequestParam final String query, @PageableDefault final Pageable pageable
);
@GetMapping
ResponseEntity<SearchProductsResponse> searchProducts(@RequestParam final String query, @PageableDefault final Pageable pageable
);

이렇게 정렬하는 건 어떨까요?

Copy link
Member

@70825 70825 left a comment

Choose a reason for hiding this comment

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

코드 완전 깔끔하네요 🥳

Comment on lines +39 to +54

@Query("SELECT p FROM Product p "
+ "WHERE p.name LIKE CONCAT('%', :name, '%') "
+ "ORDER BY CASE "
+ "WHEN p.name LIKE CONCAT(:name, '%') THEN 1 "
+ "ELSE 2 END")
Page<Product> findAllByNameContaining(@Param("name") final String name, final Pageable pageable);

@Query("SELECT new com.funeat.product.dto.ProductReviewCountDto(p, COUNT(r.id)) FROM Product p "
+ "LEFT JOIN Review r ON r.product.id = p.id "
+ "WHERE p.name LIKE CONCAT('%', :name, '%') "
+ "GROUP BY p.id "
+ "ORDER BY CASE "
+ "WHEN p.name LIKE CONCAT(:name, '%') THEN 1 "
+ "ELSE 2 END")
Page<ProductReviewCountDto> findAllWithReviewCountByNameContaining(@Param("name") final String name, final Pageable pageable);
Copy link
Member

Choose a reason for hiding this comment

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

👍👍👍👍👍👍👍

@@ -604,4 +726,23 @@ class getRankingProducts_성공_테스트 {
assertThat(actual).usingRecursiveComparison()
.isEqualTo(expected);
}

private <T> void 상품_자동_완성_검색_결과를_검증한다(final ExtractableResponse<Response> response, final List<T> products) {
Copy link
Member

Choose a reason for hiding this comment

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

이거 생각해보니까 나중에 다시 테스트 코드 리팩터링 할 때 상품_EMPTY_배열_생성() 같은걸로 관리하면 좋을 것 같아요

Copy link
Collaborator

@hanueleee hanueleee left a comment

Choose a reason for hiding this comment

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

상품 검색 수고하셨습니다~~
LGTM~

@Go-Jaecheol Go-Jaecheol merged commit 072bce4 into develop Aug 16, 2023
@Go-Jaecheol Go-Jaecheol deleted the feat/issue-402 branch August 16, 2023 04:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BE] 상품 검색 기능 구현
4 participants