11package com .jajaja .domain .search .service ;
22
3+ import com .jajaja .domain .member .entity .Member ;
4+ import com .jajaja .domain .member .repository .MemberRepository ;
35import com .jajaja .domain .product .converter .ProductConverter ;
46import com .jajaja .domain .product .dto .response .ProductListResponseDto ;
57import com .jajaja .domain .product .entity .Product ;
68import com .jajaja .domain .product .repository .ProductSalesRepository ;
79import com .jajaja .domain .search .dto .PopularSearchKeywordsResponseDto ;
10+ import com .jajaja .domain .search .dto .RecentSearchKeywordResponseDto ;
11+ import com .jajaja .domain .search .entity .MemberSearchHistory ;
812import com .jajaja .domain .search .entity .Search ;
913import com .jajaja .domain .search .entity .enums .SearchSort ;
14+ import com .jajaja .domain .search .repository .MemberSearchHistoryRepository ;
1015import com .jajaja .domain .search .repository .SearchRepository ;
1116import com .jajaja .global .apiPayload .code .status .ErrorStatus ;
1217import com .jajaja .global .apiPayload .exception .custom .BadRequestException ;
@@ -26,23 +31,32 @@ public class SearchServiceImpl implements SearchService {
2631 private final SearchRepository searchRepository ;
2732 private final ProductConverter productConverter ;
2833 private final ProductSalesRepository productSalesRepository ;
34+ private final MemberRepository memberRepository ;
35+ private final MemberSearchHistoryRepository memberSearchHistoryRepository ;
2936
3037 /**
3138 * 키워드 기반 상품 검색
3239 *
40+ * @param memberId 로그인한 회원 ID (null 허용)
3341 * @param keyword 검색어
3442 * @param sort 정렬 기준 (POPULAR, NEW, LOW_PRICE, REVIEW)
3543 * @return 상품 리스트 DTO
3644 */
3745 @ Override
3846 @ Transactional
39- public List <ProductListResponseDto > searchProductsByKeyword (String keyword , SearchSort sort ) {
47+ public List <ProductListResponseDto > searchProductsByKeyword (Long memberId , String keyword , SearchSort sort ) {
4048 if (keyword == null || keyword .isBlank ()) {
4149 throw new BadRequestException (ErrorStatus .INVALID_KEYWORD );
4250 }
4351
4452 saveOrIncrementKeyword (keyword );
4553
54+ if (memberId != null ) {
55+ Member member = memberRepository .findById (memberId )
56+ .orElseThrow (() -> new BadRequestException (ErrorStatus .MEMBER_NOT_FOUND ));
57+ saveMemberSearchKeyword (member , keyword );
58+ }
59+
4660 List <Product > products = searchRepository .findProductsByKeyword (keyword );
4761 if (products .isEmpty ()) {
4862 return Collections .emptyList ();
@@ -79,6 +93,45 @@ protected void saveOrIncrementKeyword(String keyword) {
7993 );
8094 }
8195
96+ @ Transactional
97+ public void saveMemberSearchKeyword (Member member , String keyword ) {
98+ memberSearchHistoryRepository .findByMemberAndKeyword (member , keyword )
99+ .ifPresent (memberSearchHistoryRepository ::delete );
100+
101+ memberSearchHistoryRepository .save (MemberSearchHistory .builder ()
102+ .member (member )
103+ .keyword (keyword )
104+ .build ());
105+
106+ List <MemberSearchHistory > histories = memberSearchHistoryRepository .findByMemberOrderByCreatedAtDesc (member );
107+ if (histories .size () > 10 ) {
108+ memberSearchHistoryRepository .deleteAll (histories .subList (10 , histories .size ()));
109+ }
110+ }
111+
112+ @ Override
113+ public List <RecentSearchKeywordResponseDto > getRecentSearchKeywords (Long memberId ) {
114+ Member member = memberRepository .findById (memberId )
115+ .orElseThrow (() -> new BadRequestException (ErrorStatus .MEMBER_NOT_FOUND ));
116+
117+ return memberSearchHistoryRepository .findTop10ByMemberOrderByCreatedAtDesc (member )
118+ .stream ()
119+ .map (h -> RecentSearchKeywordResponseDto .of (h .getId (), h .getKeyword ()))
120+ .toList ();
121+ }
122+
123+ @ Override
124+ @ Transactional
125+ public void deleteSearchKeywordById (Long memberId , Long keywordId ) {
126+ Member member = memberRepository .findById (memberId )
127+ .orElseThrow (() -> new BadRequestException (ErrorStatus .MEMBER_NOT_FOUND ));
128+
129+ memberSearchHistoryRepository .findByMemberAndId (member , keywordId )
130+ .ifPresent (memberSearchHistoryRepository ::delete );
131+ }
132+
133+
134+
82135 private void sortProducts (List <Product > products , SearchSort sort ) {
83136 switch (sort ) {
84137 case NEW :
@@ -120,4 +173,5 @@ private void sortByTotalSales(List<Product> products) {
120173 products .sort ((p1 , p2 ) -> salesMap .getOrDefault (p2 .getId (), 0L )
121174 .compareTo (salesMap .getOrDefault (p1 .getId (), 0L )));
122175 }
176+
123177}
0 commit comments