Skip to content

Commit 2c979e3

Browse files
committed
feat: 검색을 동적쿼리로 변경한다
1 parent 08d9006 commit 2c979e3

File tree

5 files changed

+72
-10
lines changed

5 files changed

+72
-10
lines changed

src/main/java/spring/memewikibe/application/MemeLookUpServiceImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public List<CategoryResponse> getAllCategories() {
4848
@Override
4949
public PageResponse<Cursor, MemeDetailResponse> getMemesByCategory(Long id, Long next, int limit) {
5050
int validatedLimit = Math.min(Math.max(limit, 1), 30);
51-
51+
5252
Category category = getCategoryBy(id);
5353
List<Meme> foundMemes = fetchMemesByCategory(category, next, validatedLimit);
5454

@@ -59,12 +59,12 @@ public PageResponse<Cursor, MemeDetailResponse> getMemesByCategory(Long id, Long
5959
@Override
6060
public PageResponse<Cursor, MemeDetailResponse> getMemesByQuery(String query, Long next, int limit) {
6161
int validatedLimit = Math.min(Math.max(limit, 1), 30);
62-
62+
6363
if (next == null) {
64-
List<Meme> foundMemes = memeRepository.findByTitleContainingOrderByIdDesc(query, Limit.of(validatedLimit + 1));
64+
List<Meme> foundMemes = memeRepository.findByTitleDynamicContainingOrderByIdDesc(query, Limit.of(validatedLimit + 1));
6565
return createPageResponseBy(foundMemes, validatedLimit);
6666
}
67-
List<Meme> foundMemes = memeRepository.findByTitleContainingAndIdLessThanOrderByIdDesc(query, next, Limit.of(validatedLimit + 1));
67+
List<Meme> foundMemes = memeRepository.findByTitleDynamicContainingAndIdLessThanOrderByIdDesc(query, next, Limit.of(validatedLimit + 1));
6868
return createPageResponseBy(foundMemes, validatedLimit);
6969
}
7070

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package spring.memewikibe.infrastructure;
22

3+
import org.springframework.data.domain.Limit;
4+
import spring.memewikibe.domain.meme.Meme;
35
import spring.memewikibe.domain.meme.MemeAggregationResult;
46

57
import java.time.Duration;
68
import java.util.List;
79

810
public interface MemeAggregationRepository {
911
List<MemeAggregationResult> findTopRatedMemesBy(Duration duration, int limit);
12+
13+
List<Meme> findByTitleDynamicContainingOrderByIdDesc(String title, Limit limit);
14+
15+
List<Meme> findByTitleDynamicContainingAndIdLessThanOrderByIdDesc(String title, Long lastId, Limit limit);
1016
}

src/main/java/spring/memewikibe/infrastructure/MemeAggregationRepositoryImpl.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package spring.memewikibe.infrastructure;
22

33
import com.querydsl.core.types.Projections;
4+
import com.querydsl.core.types.dsl.BooleanExpression;
45
import com.querydsl.core.types.dsl.Expressions;
56
import com.querydsl.core.types.dsl.NumberTemplate;
67
import com.querydsl.jpa.JPAExpressions;
78
import com.querydsl.jpa.JPQLSubQuery;
89
import com.querydsl.jpa.impl.JPAQueryFactory;
10+
import org.springframework.data.domain.Limit;
911
import org.springframework.stereotype.Repository;
12+
import spring.memewikibe.domain.meme.Meme;
1013
import spring.memewikibe.domain.meme.MemeAggregationResult;
1114

1215
import java.time.Duration;
@@ -77,4 +80,28 @@ public List<MemeAggregationResult> findTopRatedMemesBy(Duration duration, int li
7780
.limit(limit)
7881
.fetch();
7982
}
83+
84+
@Override
85+
public List<Meme> findByTitleDynamicContainingOrderByIdDesc(String title, Limit limit) {
86+
return queryFactory
87+
.selectFrom(meme)
88+
.where(titleContains(title))
89+
.orderBy(meme.id.desc())
90+
.limit(limit.max())
91+
.fetch();
92+
}
93+
94+
@Override
95+
public List<Meme> findByTitleDynamicContainingAndIdLessThanOrderByIdDesc(String title, Long lastId, Limit limit) {
96+
return queryFactory
97+
.selectFrom(meme)
98+
.where(titleContains(title), meme.id.lt(lastId))
99+
.orderBy(meme.id.desc())
100+
.limit(limit.max())
101+
.fetch();
102+
}
103+
104+
private BooleanExpression titleContains(String title) {
105+
return title != null && !title.trim().isEmpty() ? meme.title.containsIgnoreCase(title) : null;
106+
}
80107
}
Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package spring.memewikibe.infrastructure;
22

3-
import org.springframework.data.domain.Limit;
43
import org.springframework.data.jpa.repository.JpaRepository;
54
import spring.memewikibe.domain.meme.Meme;
65

7-
import java.util.List;
8-
96
public interface MemeRepository extends JpaRepository<Meme, Long>, MemeAggregationRepository {
10-
List<Meme> findByTitleContainingOrderByIdDesc(String title, Limit limit);
11-
12-
List<Meme> findByTitleContainingAndIdLessThanOrderByIdDesc(String title, Long id, Limit limit);
137
}

src/test/java/spring/memewikibe/application/MemeLookUpServiceImplTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,41 @@ void tearDown() {
161161
.containsExactlyInAnyOrder("테스트 밈");
162162
}
163163

164+
@Test
165+
void 검색어가_널값이면_전부_조회된다() {
166+
Meme 나만_아니면_돼 = Meme.builder()
167+
.title("나만 아니면 돼")
168+
.origin("KBS 2TV '1박 2일'의 복불복 게임에서 벌칙에 걸리지 않은 멤버들이 외치던 말에서 유래했습니다. 초창기 멤버 노홍철이 처음 사용했으며, 이후 강호동이 과장된 표정과 액션으로 외치며 짤방으로 널리 퍼졌습니다. 무한도전의 '무한이기주의'와 비교되며 승리자의 자축을 넘어 타인의 불행을 조롱하는 의미로 변모했습니다.")
169+
.usageContext("원래는 복불복에서 살아남은 자의 자축이었으나, 시간이 지나며 타인의 불행을 보고 자신은 괜찮다며 조롱하는 용법으로 사용됩니다. 인터넷 커뮤니티에서 고소 사건, 단체 손해, 가해자 특정, 지탄받는 대상의 천벌 등 남의 불행에 연루되지 않은 사람들이 이를 비웃을 때 쓰입니다. 2020년대 이후 '알빠노' 등 극단적 이기주의 밈의 시초격으로 인식됩니다.")
170+
.trendPeriod("2020")
171+
.hashtags("\"[\"\"1박2일\"\", \"\"복불복\"\", \"\"노홍철\"\", \"\"강호동\"\", \"\"이기주의\"\", \"\"남의불행\"\", \"\"짤방\"\", \"\"인터넷밈\"\", \"\"알빠노\"\"]\"")
172+
.build();
173+
Meme 원영적_사고 = Meme.builder()
174+
.title("원영적 사고")
175+
.origin("장원영의 평소 초긍정적 사고방식이 팬들 사이에서 알려져 있었으나, 2024년 3월 15일 팬 계정의 프메 패러디 트윗이 SNS에 퍼지며 대중화되었습니다. 이후 기업 세미나에 등장하며 확산되었고, 그녀의 긍정적 태도가 악플 속에서도 빛나며 큰 공감을 얻었습니다. '럭키비키'는 핵심 문구입니다.")
176+
.usageContext("자신에게 일어나는 모든 일이 결국 긍정적인 결과로 이어질 것이라는 초월적인 낙관주의를 표현할 때 사용됩니다. 부정적인 상황을 단순히 외면하는 것이 아니라, 현재의 어려움도 결국 자신을 성장시키는 과정으로 받아들이며 긍정적으로 치환하는 사고방식입니다. \"\"완전 럭키비키잖아~\"\"와 함께 쓰입니다.")
177+
.trendPeriod("2024")
178+
.hashtags("\"[\"\"장원영\"\", \"\"원영적사고\"\", \"\"럭키비키\"\", \"\"초긍정\"\", \"\"긍정적사고\"\", \"\"인터넷밈\"\", \"\"아이브\"\"]\"")
179+
.build();
180+
Meme 무야호 = Meme.builder()
181+
.title("무야호")
182+
.origin("2010년 MBC 예능 프로그램 '무한도전' 알래스카 특집에서 유재석, 정형돈, 노홍철이 현지 교민 최규재 할아버지에게 '무한~도전!' 구호를 요청하자, 할아버지가 당황하며 '무야~ 호~!'라고 외친 장면에서 유래했습니다. 방영 당시에는 큰 주목을 받지 못했으나, 2018년 이후 유튜브 알고리즘과 팬 페이지를 통해 재발견되며 폭발적인 인기를 얻었습니다.")
183+
.usageContext("예상치 못한 상황에서 터져 나오는 순수한 기쁨, 환희, 또는 놀라움을 표현할 때 사용됩니다. 때로는 상황이 다소 어이없거나 엉뚱할 때의 유쾌함을 나타내기도 합니다. 특정 인물이나 상황에 대한 비난 또는 칭찬의 맥락에서도 사용될 수 있으며, 전반적으로 긍정적이고 유쾌한 분위기를 조성하는 데 활용됩니다.")
184+
.trendPeriod("2018")
185+
.hashtags("\"[\"\"무한도전\"\", \"\"무야호\"\", \"\"최규재\"\", \"\"알래스카\"\", \"\"인터넷밈\"\", \"\"유행어\"\", \"\"환희\"\", \"\"기쁨\"\", \"\"감탄사\"\"]\"")
186+
.build();
187+
188+
memeRepository.saveAll(List.of(나만_아니면_돼, 원영적_사고, 무야호));
189+
190+
// when
191+
PageResponse<Cursor, MemeDetailResponse> response = memeLookUpService.getMemesByQuery(null, null, 10);
192+
193+
// then
194+
then(response.getResults()).hasSize(3)
195+
.extracting(MemeDetailResponse::title)
196+
.containsExactlyInAnyOrder("나만 아니면 돼", "원영적 사고", "무야호");
197+
}
198+
164199
@Test
165200
void 쿼리로_밈을_검색한다_결과_없음() {
166201
// given

0 commit comments

Comments
 (0)