-
Notifications
You must be signed in to change notification settings - Fork 7
/
GetCalorieCalorieAnalysisService.java
105 lines (94 loc) · 4.52 KB
/
GetCalorieCalorieAnalysisService.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.gaebaljip.exceed.application.service.nutritionist;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.gaebaljip.exceed.adapter.out.jpa.nutritionist.MonthlyMealPort;
import com.gaebaljip.exceed.application.domain.meal.DailyMeal;
import com.gaebaljip.exceed.application.domain.meal.Meal;
import com.gaebaljip.exceed.application.domain.member.Member;
import com.gaebaljip.exceed.application.domain.nutritionist.CalorieAnalyzer;
import com.gaebaljip.exceed.application.domain.nutritionist.CalorieAnalyzerFactory;
import com.gaebaljip.exceed.application.port.in.nutritionist.GetCalorieAnalysisUsecase;
import com.gaebaljip.exceed.application.port.out.member.MemberPort;
import com.gaebaljip.exceed.common.annotation.Timer;
import com.gaebaljip.exceed.common.dto.CalorieAnalysisDTO;
import com.gaebaljip.exceed.common.dto.MonthlyMealDTO;
import com.gaebaljip.exceed.adapter.in.nutritionist.request.GetCalorieAnalysisRequest;
import com.gaebaljip.exceed.adapter.in.nutritionist.response.GetCalorieAnalysisResponse;
import lombok.RequiredArgsConstructor;
/**
* 한달치 칼로리 달성도를 날짜별로 측정하여 반환한다.
*
* @author hwangdaesun
* @version 1.0
*/
@Service
@RequiredArgsConstructor
public class GetCalorieCalorieAnalysisService implements GetCalorieAnalysisUsecase {
public static final int FIRST_DAY = 1;
private final MonthlyMealPort monthlyMealPort;
private final MemberPort memberPort;
/**
* CalorieAnalyzer 도메인이 특정 날짜에 목표 칼로리를 달성했는 지를 판단하여 달성했을 경우 true를 반환
*
* @param request : 회원 PK와 날짜
* @return GetAnalysisResponse : 날짜별 칼로리 달성 여부
*/
@Override
@Timer
@Transactional(readOnly = true)
public GetCalorieAnalysisResponse execute(GetCalorieAnalysisRequest request) {
List<Meal> meals =
monthlyMealPort.query(new MonthlyMealDTO(request.memberId(), request.date()));
Map<LocalDate, DailyMeal> dailyMealMap = groupByDate(meals);
Member member = memberPort.query(request.memberId(), request.date());
List<CalorieAnalysisDTO> analyses =
getStartDate(request)
.datesUntil(getLastDate(request).plusDays(1))
.map(date -> createAnalysisForDay(date, dailyMealMap, member))
.toList();
return new GetCalorieAnalysisResponse(analyses);
}
@Timer
private Map<LocalDate, DailyMeal> groupByDate(List<Meal> meals) {
return meals.stream()
.collect(
Collectors.groupingBy(
meal -> meal.getMealDateTime().toLocalDate(),
Collectors.collectingAndThen(Collectors.toList(), DailyMeal::new)));
}
private LocalDate getStartDate(GetCalorieAnalysisRequest request) {
return LocalDate.from(request.date().withDayOfMonth(FIRST_DAY));
}
private LocalDate getLastDate(GetCalorieAnalysisRequest request) {
LocalDate date = request.date().toLocalDate(); // LocalDateTime을 LocalDate로 변환
return date.withDayOfMonth(date.lengthOfMonth()); // 그 달의 마지막 날짜를 설정
}
@Timer
private CalorieAnalysisDTO createAnalysisForDay(
LocalDate day, Map<LocalDate, DailyMeal> dailyMealMap, Member member) {
return Optional.ofNullable(dailyMealMap.get(day))
.map(
dailyMeal -> {
CalorieAnalyzer calorieAnalyzer =
CalorieAnalyzerFactory.getInstance()
.createAnalyzer(dailyMeal, member);
return CalorieAnalysisDTO.builder()
.date(day)
.isVisited(true)
.isCalorieAchieved(calorieAnalyzer.analyze())
.build();
})
.orElseGet(
() ->
CalorieAnalysisDTO.builder()
.date(day)
.isVisited(false)
.isCalorieAchieved(false)
.build());
}
}