Skip to content

Commit d67a09e

Browse files
authored
feat: 공연 목록 종료 공연 필터링 (#453)
1 parent 0a5a695 commit d67a09e

3 files changed

Lines changed: 246 additions & 46 deletions

File tree

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.b2st.domain.performance.repository;
22

3+
import java.time.LocalDateTime;
34
import java.util.List;
45
import java.util.Optional;
56

@@ -27,14 +28,14 @@ public interface PerformanceRepository extends JpaRepository<Performance, Long>
2728

2829
@EntityGraph(attributePaths = "venue")
2930
@Query("""
30-
select p
31-
from Performance p
32-
where p.status = :status
33-
and (
34-
lower(p.title) like lower(concat('%', :keyword, '%'))
35-
or lower(p.category) like lower(concat('%', :keyword, '%'))
36-
)
37-
""")
31+
select p
32+
from Performance p
33+
where p.status = :status
34+
and (
35+
lower(p.title) like lower(concat('%', :keyword, '%'))
36+
or lower(p.category) like lower(concat('%', :keyword, '%'))
37+
)
38+
""")
3839
Page<Performance> searchActive(
3940
@Param("status") PerformanceStatus status,
4041
@Param("keyword") String keyword,
@@ -54,11 +55,11 @@ Page<Performance> searchActive(
5455

5556
@EntityGraph(attributePaths = "venue")
5657
@Query("""
57-
select p
58-
from Performance p
59-
where lower(p.title) like lower(concat('%', :keyword, '%'))
60-
or lower(p.category) like lower(concat('%', :keyword, '%'))
61-
""")
58+
select p
59+
from Performance p
60+
where lower(p.title) like lower(concat('%', :keyword, '%'))
61+
or lower(p.category) like lower(concat('%', :keyword, '%'))
62+
""")
6263
Page<Performance> searchAll(@Param("keyword") String keyword, Pageable pageable);
6364

6465
/* =========================
@@ -71,32 +72,36 @@ or lower(p.category) like lower(concat('%', :keyword, '%'))
7172
/* 사용자용 (ACTIVE만) - Cursor */
7273
@EntityGraph(attributePaths = "venue")
7374
@Query("""
74-
select p
75-
from Performance p
76-
where p.status = :status
77-
and (:cursor is null or p.performanceId < :cursor)
78-
order by p.performanceId desc
79-
""")
75+
select p
76+
from Performance p
77+
where p.status = :status
78+
and p.endDate >= :todayStart
79+
and (:cursor is null or p.performanceId < :cursor)
80+
order by p.performanceId desc
81+
""")
8082
List<Performance> findByStatusWithCursor(
8183
@Param("status") PerformanceStatus status,
84+
@Param("todayStart") LocalDateTime todayStart,
8285
@Param("cursor") Long cursor,
8386
Pageable pageable
8487
);
8588

8689
@EntityGraph(attributePaths = "venue")
8790
@Query("""
88-
select p
89-
from Performance p
90-
where p.status = :status
91-
and (:cursor is null or p.performanceId < :cursor)
92-
and (
93-
lower(p.title) like lower(concat('%', :keyword, '%'))
94-
or lower(p.category) like lower(concat('%', :keyword, '%'))
95-
)
96-
order by p.performanceId desc
97-
""")
91+
select p
92+
from Performance p
93+
where p.status = :status
94+
and p.endDate >= :todayStart
95+
and (:cursor is null or p.performanceId < :cursor)
96+
and (
97+
lower(p.title) like lower(concat('%', :keyword, '%'))
98+
or lower(p.category) like lower(concat('%', :keyword, '%'))
99+
)
100+
order by p.performanceId desc
101+
""")
98102
List<Performance> searchActiveWithCursor(
99103
@Param("status") PerformanceStatus status,
104+
@Param("todayStart") LocalDateTime todayStart,
100105
@Param("keyword") String keyword,
101106
@Param("cursor") Long cursor,
102107
Pageable pageable
@@ -105,30 +110,30 @@ List<Performance> searchActiveWithCursor(
105110
/* 관리자용 (상태 무관) - Cursor */
106111
@EntityGraph(attributePaths = "venue")
107112
@Query("""
108-
select p
109-
from Performance p
110-
where (:cursor is null or p.performanceId < :cursor)
111-
order by p.performanceId desc
112-
""")
113+
select p
114+
from Performance p
115+
where (:cursor is null or p.performanceId < :cursor)
116+
order by p.performanceId desc
117+
""")
113118
List<Performance> findAllWithCursor(
114119
@Param("cursor") Long cursor,
115120
Pageable pageable
116121
);
117122

118123
@EntityGraph(attributePaths = "venue")
119124
@Query("""
120-
select p
121-
from Performance p
122-
where (:cursor is null or p.performanceId < :cursor)
123-
and (
124-
lower(p.title) like lower(concat('%', :keyword, '%'))
125-
or lower(p.category) like lower(concat('%', :keyword, '%'))
126-
)
127-
order by p.performanceId desc
128-
""")
125+
select p
126+
from Performance p
127+
where (:cursor is null or p.performanceId < :cursor)
128+
and (
129+
lower(p.title) like lower(concat('%', :keyword, '%'))
130+
or lower(p.category) like lower(concat('%', :keyword, '%'))
131+
)
132+
order by p.performanceId desc
133+
""")
129134
List<Performance> searchAllWithCursor(
130135
@Param("keyword") String keyword,
131136
@Param("cursor") Long cursor,
132137
Pageable pageable
133138
);
134-
}
139+
}

src/main/java/com/back/b2st/domain/performance/service/PerformanceService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,10 @@ public Page<PerformanceListRes> searchActivePerformances(String keyword, Pageabl
244244

245245
public PerformanceCursorPageRes getActivePerformancesWithCursor(Long cursor, int size) {
246246
Pageable pageable = PageRequest.of(0, size + 1);
247+
LocalDateTime todayStart = LocalDateTime.now().toLocalDate().atStartOfDay();
247248

248249
List<Performance> performances = performanceRepository
249-
.findByStatusWithCursor(PerformanceStatus.ACTIVE, cursor, pageable);
250+
.findByStatusWithCursor(PerformanceStatus.ACTIVE, todayStart, cursor, pageable);
250251

251252
return mapToCursorRes(performances, size);
252253
}
@@ -257,8 +258,10 @@ public PerformanceCursorPageRes searchActivePerformancesWithCursor(Long cursor,
257258
}
258259

259260
Pageable pageable = PageRequest.of(0, size + 1);
261+
LocalDateTime todayStart = LocalDateTime.now().toLocalDate().atStartOfDay();
262+
260263
List<Performance> performances = performanceRepository
261-
.searchActiveWithCursor(PerformanceStatus.ACTIVE, keyword.trim(), cursor, pageable);
264+
.searchActiveWithCursor(PerformanceStatus.ACTIVE, todayStart, keyword.trim(), cursor, pageable);
262265

263266
return mapToCursorRes(performances, size);
264267
}
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package com.back.b2st.domain.performance.service;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
import static org.mockito.BDDMockito.*;
5+
6+
import java.time.LocalDate;
7+
import java.time.LocalDateTime;
8+
import java.util.List;
9+
10+
import org.junit.jupiter.api.DisplayName;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.mockito.ArgumentCaptor;
14+
import org.mockito.InjectMocks;
15+
import org.mockito.Mock;
16+
import org.mockito.junit.jupiter.MockitoExtension;
17+
import org.springframework.data.domain.PageRequest;
18+
import org.springframework.data.domain.Pageable;
19+
20+
import com.back.b2st.domain.performance.dto.response.PerformanceCursorPageRes;
21+
import com.back.b2st.domain.performance.entity.Performance;
22+
import com.back.b2st.domain.performance.entity.PerformanceStatus;
23+
import com.back.b2st.domain.performance.mapper.PerformanceMapper;
24+
import com.back.b2st.domain.performance.repository.PerformanceRepository;
25+
26+
@ExtendWith(MockitoExtension.class)
27+
class PerformanceServiceTest {
28+
29+
@Mock
30+
private PerformanceRepository performanceRepository;
31+
32+
@Mock
33+
private PerformanceMapper performanceMapper;
34+
35+
@InjectMocks
36+
private PerformanceService performanceService;
37+
38+
@Test
39+
@DisplayName("getActivePerformancesWithCursor(): 종료된 공연을 필터링한다")
40+
void getActivePerformancesWithCursor_filtersEndedPerformances() {
41+
// given
42+
Long cursor = 100L;
43+
int size = 10;
44+
LocalDate today = LocalDate.now();
45+
LocalDateTime todayStart = today.atStartOfDay();
46+
47+
given(performanceRepository.findByStatusWithCursor(
48+
eq(PerformanceStatus.ACTIVE),
49+
any(LocalDateTime.class),
50+
eq(cursor),
51+
any(Pageable.class)
52+
)).willReturn(List.of());
53+
54+
// when
55+
performanceService.getActivePerformancesWithCursor(cursor, size);
56+
57+
// then
58+
ArgumentCaptor<LocalDateTime> dateCaptor = ArgumentCaptor.forClass(LocalDateTime.class);
59+
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
60+
61+
verify(performanceRepository).findByStatusWithCursor(
62+
eq(PerformanceStatus.ACTIVE),
63+
dateCaptor.capture(),
64+
eq(cursor),
65+
pageableCaptor.capture()
66+
);
67+
68+
// todayStart가 오늘 00:00:00인지 확인
69+
LocalDateTime capturedDate = dateCaptor.getValue();
70+
assertThat(capturedDate).isEqualTo(todayStart);
71+
assertThat(capturedDate.toLocalDate()).isEqualTo(today);
72+
assertThat(capturedDate.getHour()).isEqualTo(0);
73+
assertThat(capturedDate.getMinute()).isEqualTo(0);
74+
assertThat(capturedDate.getSecond()).isEqualTo(0);
75+
76+
// Pageable이 size+1로 설정되었는지 확인
77+
Pageable capturedPageable = pageableCaptor.getValue();
78+
assertThat(capturedPageable.getPageSize()).isEqualTo(size + 1);
79+
}
80+
81+
@Test
82+
@DisplayName("searchActivePerformancesWithCursor(): 종료된 공연을 필터링한다")
83+
void searchActivePerformancesWithCursor_filtersEndedPerformances() {
84+
// given
85+
Long cursor = 200L;
86+
String keyword = "콘서트";
87+
int size = 20;
88+
LocalDate today = LocalDate.now();
89+
LocalDateTime todayStart = today.atStartOfDay();
90+
91+
given(performanceRepository.searchActiveWithCursor(
92+
eq(PerformanceStatus.ACTIVE),
93+
any(LocalDateTime.class),
94+
eq(keyword),
95+
eq(cursor),
96+
any(Pageable.class)
97+
)).willReturn(List.of());
98+
99+
// when
100+
performanceService.searchActivePerformancesWithCursor(cursor, keyword, size);
101+
102+
// then
103+
ArgumentCaptor<LocalDateTime> dateCaptor = ArgumentCaptor.forClass(LocalDateTime.class);
104+
ArgumentCaptor<Pageable> pageableCaptor = ArgumentCaptor.forClass(Pageable.class);
105+
106+
verify(performanceRepository).searchActiveWithCursor(
107+
eq(PerformanceStatus.ACTIVE),
108+
dateCaptor.capture(),
109+
eq(keyword),
110+
eq(cursor),
111+
pageableCaptor.capture()
112+
);
113+
114+
// todayStart가 오늘 00:00:00인지 확인
115+
LocalDateTime capturedDate = dateCaptor.getValue();
116+
assertThat(capturedDate).isEqualTo(todayStart);
117+
assertThat(capturedDate.toLocalDate()).isEqualTo(today);
118+
assertThat(capturedDate.getHour()).isEqualTo(0);
119+
assertThat(capturedDate.getMinute()).isEqualTo(0);
120+
assertThat(capturedDate.getSecond()).isEqualTo(0);
121+
122+
// Pageable이 size+1로 설정되었는지 확인
123+
Pageable capturedPageable = pageableCaptor.getValue();
124+
assertThat(capturedPageable.getPageSize()).isEqualTo(size + 1);
125+
}
126+
127+
@Test
128+
@DisplayName("searchActivePerformancesWithCursor(): 키워드가 null이면 일반 목록 조회로 위임")
129+
void searchActivePerformancesWithCursor_nullKeyword_delegatesToGetActivePerformances() {
130+
// given
131+
Long cursor = 300L;
132+
int size = 15;
133+
134+
given(performanceRepository.findByStatusWithCursor(
135+
eq(PerformanceStatus.ACTIVE),
136+
any(LocalDateTime.class),
137+
eq(cursor),
138+
any(Pageable.class)
139+
)).willReturn(List.of());
140+
141+
// when
142+
performanceService.searchActivePerformancesWithCursor(cursor, null, size);
143+
144+
// then
145+
verify(performanceRepository).findByStatusWithCursor(
146+
eq(PerformanceStatus.ACTIVE),
147+
any(LocalDateTime.class),
148+
eq(cursor),
149+
any(Pageable.class)
150+
);
151+
verify(performanceRepository, never()).searchActiveWithCursor(
152+
any(),
153+
any(),
154+
any(),
155+
any(),
156+
any()
157+
);
158+
}
159+
160+
@Test
161+
@DisplayName("searchActivePerformancesWithCursor(): 키워드가 빈 문자열이면 일반 목록 조회로 위임")
162+
void searchActivePerformancesWithCursor_emptyKeyword_delegatesToGetActivePerformances() {
163+
// given
164+
Long cursor = 400L;
165+
int size = 25;
166+
167+
given(performanceRepository.findByStatusWithCursor(
168+
eq(PerformanceStatus.ACTIVE),
169+
any(LocalDateTime.class),
170+
eq(cursor),
171+
any(Pageable.class)
172+
)).willReturn(List.of());
173+
174+
// when
175+
performanceService.searchActivePerformancesWithCursor(cursor, " ", size);
176+
177+
// then
178+
verify(performanceRepository).findByStatusWithCursor(
179+
eq(PerformanceStatus.ACTIVE),
180+
any(LocalDateTime.class),
181+
eq(cursor),
182+
any(Pageable.class)
183+
);
184+
verify(performanceRepository, never()).searchActiveWithCursor(
185+
any(),
186+
any(),
187+
any(),
188+
any(),
189+
any()
190+
);
191+
}
192+
}

0 commit comments

Comments
 (0)