Skip to content

Commit 1bd7554

Browse files
feat: 통계 조회 시 기간 필터 기능 추가 (#253)
시작일과 종료일을 입력받아 해당 기간에 해당하는 통계 데이터를 조회할 수 있도록 개선. 기간 형식 검증 로직 추가로 안전성 확보.
1 parent 8cfdbda commit 1bd7554

3 files changed

Lines changed: 69 additions & 8 deletions

File tree

src/main/java/org/devkor/apu/saerok_server/domain/stat/api/AdminStatController.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@ public class AdminStatController {
4646
}
4747
)
4848
public StatSeriesResponse getSeries(
49-
@Parameter(description = "반복 지정 가능") @RequestParam List<String> metric
49+
@Parameter(description = "반복 지정 가능") @RequestParam List<String> metric,
50+
@Parameter(description = "조회 기간 (시작일,종료일)", example = "2024-01-01,2024-01-31")
51+
@RequestParam(required = false) String period
5052
) {
5153
List<StatMetric> metrics = metric.stream()
5254
.map(s -> EnumParser.fromString(StatMetric.class, s))
5355
.toList();
54-
return queryService.getSeries(metrics);
56+
return queryService.getSeries(metrics, period);
5557
}
5658

5759
@PostMapping("/aggregate-yesterday")

src/main/java/org/devkor/apu/saerok_server/domain/stat/application/StatQueryService.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import org.devkor.apu.saerok_server.domain.stat.core.entity.DailyStat;
66
import org.devkor.apu.saerok_server.domain.stat.core.entity.StatMetric;
77
import org.devkor.apu.saerok_server.domain.stat.core.repository.DailyStatRepository;
8+
import org.devkor.apu.saerok_server.global.shared.exception.BadRequestException;
89
import org.springframework.stereotype.Service;
910
import org.springframework.transaction.annotation.Transactional;
1011

12+
import java.time.LocalDate;
13+
import java.time.format.DateTimeParseException;
1114
import java.util.*;
1215

1316
@Service
@@ -17,12 +20,13 @@ public class StatQueryService {
1720

1821
private final DailyStatRepository dailyRepo;
1922

20-
public StatSeriesResponse getSeries(List<StatMetric> metrics) {
23+
public StatSeriesResponse getSeries(List<StatMetric> metrics, String period) {
2124
if (metrics == null || metrics.isEmpty()) return StatSeriesResponse.empty();
2225

26+
LocalDateRange range = parsePeriod(period);
2327
List<StatSeriesResponse.Series> out = new ArrayList<>();
2428
for (StatMetric m : metrics) {
25-
List<DailyStat> rows = dailyRepo.findSeriesByMetric(m);
29+
List<DailyStat> rows = dailyRepo.findSeriesByMetric(m, range.startDate(), range.endDate());
2630

2731
if (m == StatMetric.BIRD_ID_RESOLUTION_STATS_28D) {
2832
var minSeries = new StatSeriesResponse.ComponentSeries(
@@ -60,4 +64,41 @@ public StatSeriesResponse getSeries(List<StatMetric> metrics) {
6064
private static Number numberOrNull(Object o) {
6165
return (o instanceof Number n) ? n : null;
6266
}
67+
68+
private LocalDateRange parsePeriod(String period) {
69+
if (period == null || period.isBlank()) {
70+
return LocalDateRange.empty();
71+
}
72+
73+
String[] tokens = period.split(",");
74+
if (tokens.length != 2) {
75+
throw new BadRequestException("period 파라미터는 '시작일,종료일' 형식이어야 합니다.");
76+
}
77+
78+
LocalDate start = parseDate(tokens[0].trim(), "시작일");
79+
LocalDate end = parseDate(tokens[1].trim(), "종료일");
80+
81+
if (start != null && end != null && end.isBefore(start)) {
82+
throw new BadRequestException("period 파라미터는 종료일이 시작일보다 빠를 수 없습니다.");
83+
}
84+
85+
return new LocalDateRange(start, end);
86+
}
87+
88+
private LocalDate parseDate(String value, String label) {
89+
if (value == null || value.isBlank()) {
90+
return null;
91+
}
92+
try {
93+
return LocalDate.parse(value);
94+
} catch (DateTimeParseException e) {
95+
throw new BadRequestException(label + "은 yyyy-MM-dd 형식이어야 합니다.");
96+
}
97+
}
98+
99+
private record LocalDateRange(LocalDate startDate, LocalDate endDate) {
100+
private static LocalDateRange empty() {
101+
return new LocalDateRange(null, null);
102+
}
103+
}
63104
}

src/main/java/org/devkor/apu/saerok_server/domain/stat/core/repository/DailyStatRepository.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,28 @@ public void upsertValue(StatMetric metric, LocalDate date, Number value) {
4545
}
4646
}
4747

48-
public List<DailyStat> findSeriesByMetric(StatMetric metric) {
49-
return em.createQuery("SELECT s FROM DailyStat s WHERE s.metric = :m ORDER BY s.date", DailyStat.class)
50-
.setParameter("m", metric)
51-
.getResultList();
48+
public List<DailyStat> findSeriesByMetric(StatMetric metric, LocalDate startDate, LocalDate endDate) {
49+
StringBuilder jpql = new StringBuilder("SELECT s FROM DailyStat s WHERE s.metric = :m");
50+
51+
if (startDate != null) {
52+
jpql.append(" AND s.date >= :start");
53+
}
54+
if (endDate != null) {
55+
jpql.append(" AND s.date <= :end");
56+
}
57+
jpql.append(" ORDER BY s.date");
58+
59+
var query = em.createQuery(jpql.toString(), DailyStat.class)
60+
.setParameter("m", metric);
61+
62+
if (startDate != null) {
63+
query.setParameter("start", startDate);
64+
}
65+
if (endDate != null) {
66+
query.setParameter("end", endDate);
67+
}
68+
69+
return query.getResultList();
5270
}
5371

5472
public Optional<LocalDate> findLastDateOf(StatMetric metric) {

0 commit comments

Comments
 (0)