Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.List;
import java.util.Optional;
import org.runimo.runimo.records.domain.RunningRecord;
import org.runimo.runimo.records.service.dto.DailyStat;
import org.runimo.runimo.records.service.dto.RecordStatDto;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.jpa.repository.JpaRepository;
Expand Down Expand Up @@ -33,14 +33,15 @@ Slice<RunningRecord> findFirstRunOfWeek(
@Query("select r from RunningRecord r where r.userId = :userId")
Slice<RunningRecord> findLatestByUserId(Long userId, Pageable pageRequest);

@Query("select new org.runimo.runimo.records.service.dto.DailyStat(" +
"cast(r.startedAt as localdate), " +
"sum(r.totalDistance.amount)) " +
@Query("select new org.runimo.runimo.records.service.dto.RecordStatDto(" +
"r.startedAt, " +
"r.endAt, " +
"r.totalDistance.amount) " +
"from RunningRecord r " +
"where r.userId = :userId " +
"and r.startedAt between :startOfWeek and :now " +
"group by function('date', r.startedAt)")
List<DailyStat> findDailyDistanceByUserIdAndThisWeek(Long userId, LocalDateTime startOfWeek,
"order by r.startedAt asc")
List<RecordStatDto> findRecordStatByUserIdAndBetween(Long userId, LocalDateTime startOfWeek,
LocalDateTime now);

List<RunningRecord> findRecordByUserIdOrderByStartedAtDesc(Long id, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package org.runimo.runimo.records.service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.runimo.runimo.records.domain.RunningRecord;
import org.runimo.runimo.records.repository.RecordRepository;
import org.runimo.runimo.records.service.dto.DailyStat;
import org.runimo.runimo.records.service.dto.RecordSimpleView;
import org.runimo.runimo.records.service.dto.RecordStatDto;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
Expand Down Expand Up @@ -54,7 +56,8 @@ public Optional<RunningRecord> findLatestRunningRecordByUserId(Long userId) {
@Transactional(readOnly = true)
public List<DailyStat> findDailyStatByUserIdBetween(Long id, LocalDateTime from,
LocalDateTime to) {
return recordRepository.findDailyDistanceByUserIdAndThisWeek(id, from, to);
return mapToDailyStatList(
recordRepository.findRecordStatByUserIdAndBetween(id, from, to));
}

@Transactional(readOnly = true)
Expand All @@ -66,4 +69,22 @@ public List<RecordSimpleView> findRecordSimpleViewByUserId(Long id, int page, in
.map(RecordSimpleView::from)
.toList();
}

private List<DailyStat> mapToDailyStatList(List<RecordStatDto> recordStatDtos) {
List<DailyStat> list = new ArrayList<>();
for (RecordStatDto recordStatDto : recordStatDtos) {
if (list.isEmpty() || list.getLast().getDate() != recordStatDto.getStartedAt()
.toLocalDate()) {
DailyStat dailyStat = DailyStat.empty(recordStatDto.getStartedAt().toLocalDate());
dailyStat.addData(recordStatDto);
list.add(dailyStat);
continue;
}
DailyStat last = list.getLast();
last.addData(recordStatDto);
}
return list;
}


}
32 changes: 28 additions & 4 deletions src/main/java/org/runimo/runimo/records/service/dto/DailyStat.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
package org.runimo.runimo.records.service.dto;


import com.fasterxml.jackson.annotation.JsonIgnore;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import lombok.Getter;

public record DailyStat(
LocalDate date,
Long distance
) {
@Getter
public class DailyStat {

private LocalDate date;
@JsonIgnore
private Long timeInSeconds;
@JsonIgnore
private Long runningCount;
private Long distanceInMeters;

Choose a reason for hiding this comment

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

The addData method modifies the state of the DailyStat object. Ensure that this behavior is intended and thread-safe if this object is used in a multi-threaded environment.

public DailyStat(LocalDate date, Long timeInSeconds, Long runningCount, Long distanceInMeters) {
this.date = date;
this.timeInSeconds = timeInSeconds;
this.runningCount = runningCount;
this.distanceInMeters = distanceInMeters;
}

public void addData(RecordStatDto recordStat) {
this.timeInSeconds += recordStat.getStartedAt().until(recordStat.getEndAt(), ChronoUnit.SECONDS);
this.runningCount += 1;
this.distanceInMeters += recordStat.getRunningDistanceInMeters();
}

public static DailyStat empty(LocalDate date) {
return new DailyStat(date, 0L, 0L, 0L);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.runimo.runimo.records.service.dto;

import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RecordStatDto {
private LocalDateTime startedAt;
private LocalDateTime endAt;
private Long runningDistanceInMeters;

public RecordStatDto(LocalDateTime startedAt, LocalDateTime endAt, Long runningDistanceInMeters) {
this.startedAt = startedAt;
this.endAt = endAt;
this.runningDistanceInMeters = runningDistanceInMeters;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.runimo.runimo.records.service.dto;

import java.util.List;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class SimpleStat {

Long totalTimeInSeconds;
Long totalRunningCount;
Long totalDistanceInMeters;

private SimpleStat(Long totalTimeInSeconds, Long totalRunningCount, Long totalDistanceInMeters) {
this.totalTimeInSeconds = totalTimeInSeconds;
this.totalRunningCount = totalRunningCount;
this.totalDistanceInMeters = totalDistanceInMeters;
}



public static SimpleStat from(List<DailyStat> dailyStats) {
SimpleStat simpleStat = new SimpleStat(0L, 0L, 0L);
for (DailyStat dailyStat : dailyStats) {
simpleStat.totalTimeInSeconds += dailyStat.getTimeInSeconds();
simpleStat.totalRunningCount += dailyStat.getRunningCount();
simpleStat.totalDistanceInMeters += dailyStat.getDistanceInMeters();
}
return simpleStat;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

@Schema(name = "주간 통계 응답")
public record WeeklyRecordStatResponse(
SimpleStat simpleStat,
List<DailyStat> dailyStats
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.runimo.runimo.records.service.dto.DailyStat;
import org.runimo.runimo.records.service.dto.RecordSimpleView;
import org.runimo.runimo.records.service.dto.RecordSimpleViewResponse;
import org.runimo.runimo.records.service.dto.SimpleStat;
import org.runimo.runimo.records.service.dto.WeeklyRecordStatResponse;
import org.runimo.runimo.records.service.dto.WeeklyStatQuery;
import org.runimo.runimo.records.service.usecases.dtos.MonthlyRecordStatResponse;
Expand All @@ -32,13 +33,15 @@ public RecordDetailViewResponse getRecordDetailView(Long recordId) {

@Override
public WeeklyRecordStatResponse getUserWeeklyRecordStat(WeeklyStatQuery query) {
// DB에서 일별로 이미 합산된 데이터 조회
List<DailyStat> dailyDistances = recordFinder.findDailyStatByUserIdBetween(
query.userId(),
query.startDate().atStartOfDay(),
query.endDate().atTime(23, 59, 59)
);
return new WeeklyRecordStatResponse(dailyDistances);

SimpleStat weeklyStat = SimpleStat.from(dailyDistances);

return new WeeklyRecordStatResponse(weeklyStat, dailyDistances);
}

@Override
Expand All @@ -50,7 +53,8 @@ public MonthlyRecordStatResponse getUserMonthlyRecordStat(MonthlyStatQuery query
from.atStartOfDay(),
to.atTime(23, 59, 59)
);
return new MonthlyRecordStatResponse(dailyDistances);
SimpleStat monthlyStat = SimpleStat.from(dailyDistances);
return new MonthlyRecordStatResponse(monthlyStat, dailyDistances);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import java.util.List;
import org.runimo.runimo.records.service.dto.DailyStat;
import org.runimo.runimo.records.service.dto.SimpleStat;

public record MonthlyRecordStatResponse(
SimpleStat simpleStat,
List<DailyStat> dailyStats
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,19 +159,19 @@ void tearDown() {
.body("code", equalTo("MY_PAGE_DATA_FETCHED"))
.body("payload.daily_stats.size()", equalTo(7))
.body("payload.daily_stats[0].date", equalTo("2025-03-31"))
.body("payload.daily_stats[0].distance", equalTo(1000))
.body("payload.daily_stats[0].distance_in_meters", equalTo(1000))
.body("payload.daily_stats[1].date", equalTo("2025-04-01"))
.body("payload.daily_stats[1].distance", equalTo(2000))
.body("payload.daily_stats[1].distance_in_meters", equalTo(2000))
.body("payload.daily_stats[2].date", equalTo("2025-04-02"))
.body("payload.daily_stats[2].distance", equalTo(3000))
.body("payload.daily_stats[2].distance_in_meters", equalTo(3000))
.body("payload.daily_stats[3].date", equalTo("2025-04-03"))
.body("payload.daily_stats[3].distance", equalTo(4000))
.body("payload.daily_stats[3].distance_in_meters", equalTo(4000))
.body("payload.daily_stats[4].date", equalTo("2025-04-04"))
.body("payload.daily_stats[4].distance", equalTo(5000))
.body("payload.daily_stats[4].distance_in_meters", equalTo(5000))
.body("payload.daily_stats[5].date", equalTo("2025-04-05"))
.body("payload.daily_stats[5].distance", equalTo(6000))
.body("payload.daily_stats[5].distance_in_meters", equalTo(6000))
.body("payload.daily_stats[6].date", equalTo("2025-04-06"))
.body("payload.daily_stats[6].distance", equalTo(7000));
.body("payload.daily_stats[6].distance_in_meters", equalTo(7000));
}

@Test
Expand All @@ -192,17 +192,21 @@ void tearDown() {
.log().ifValidationFails()
.statusCode(200)
.body("code", equalTo("MY_PAGE_DATA_FETCHED"))
.body("payload.simple_stat", notNullValue())
.body("payload.simple_stat.total_time_in_seconds", equalTo(18000))
.body("payload.simple_stat.total_running_count", equalTo(5))
.body("payload.simple_stat.total_distance_in_meters", equalTo(21000))
.body("payload.daily_stats.size()", equalTo(5))
.body("payload.daily_stats[0].date", equalTo("2025-03-31"))
.body("payload.daily_stats[0].distance", equalTo(1000))
.body("payload.daily_stats[0].distance_in_meters", equalTo(1000))
.body("payload.daily_stats[1].date", equalTo("2025-04-01"))
.body("payload.daily_stats[1].distance", equalTo(2000))
.body("payload.daily_stats[1].distance_in_meters", equalTo(2000))
.body("payload.daily_stats[2].date", equalTo("2025-04-04"))
.body("payload.daily_stats[2].distance", equalTo(5000))
.body("payload.daily_stats[2].distance_in_meters", equalTo(5000))
.body("payload.daily_stats[3].date", equalTo("2025-04-05"))
.body("payload.daily_stats[3].distance", equalTo(6000))
.body("payload.daily_stats[3].distance_in_meters", equalTo(6000))
.body("payload.daily_stats[4].date", equalTo("2025-04-06"))
.body("payload.daily_stats[4].distance", equalTo(7000));
.body("payload.daily_stats[4].distance_in_meters", equalTo(7000));
}

@Test
Expand All @@ -224,11 +228,15 @@ void tearDown() {
.log().all()
.statusCode(200)
.body("code", equalTo("MY_PAGE_DATA_FETCHED"))
.body("payload.simple_stat", notNullValue())
.body("payload.simple_stat.total_time_in_seconds", equalTo(21600))
.body("payload.simple_stat.total_running_count", equalTo(6))
.body("payload.simple_stat.total_distance_in_meters", equalTo(27000))
.body("payload.daily_stats.size()", equalTo(6))
.body("payload.daily_stats[0].date", equalTo("2025-04-01"))
.body("payload.daily_stats[0].distance", equalTo(2000))
.body("payload.daily_stats[0].distance_in_meters", equalTo(2000))
.body("payload.daily_stats[1].date", equalTo("2025-04-02"))
.body("payload.daily_stats[1].distance", equalTo(3000));
.body("payload.daily_stats[1].distance_in_meters", equalTo(3000));
}

@Test
Expand Down
Loading