Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PopulationStatistic의 DashboareType에 따라 DashboareComponent 생성 #115

Open
wants to merge 5 commits into
base: refactor/#104
Choose a base branch
from
Open
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 @@ -63,6 +63,7 @@ public enum ApplicationErrorType {
QUESTION_ANSWER_COUNT_NOT_EQUAL(HttpStatus.INTERNAL_SERVER_ERROR, "문항과 답변의 개수가 일치하지 않습니다."),

INVALID_BORROWING_LIMIT(HttpStatus.BAD_REQUEST, "빌릴 수 있는 돈은 0 이상 10억 이하입니다."),
INVALID_TYPE_CAST(HttpStatus.CONFLICT, "타입 캐스팅에 실패하였습니다."),

/**
* Filter Error Type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
import com.dnd.namuiwiki.domain.dashboard.model.DashboardComponent;
import com.dnd.namuiwiki.domain.dashboard.model.dto.DashboardDto;
import com.dnd.namuiwiki.domain.dashboard.model.entity.Dashboard;
import com.dnd.namuiwiki.domain.dashboard.type.DashboardType;
import com.dnd.namuiwiki.domain.jwt.dto.TokenUserInfoDto;
import com.dnd.namuiwiki.domain.question.type.QuestionName;
import com.dnd.namuiwiki.domain.statistic.StatisticsService;
import com.dnd.namuiwiki.domain.statistic.model.entity.PopulationStatistic;
import com.dnd.namuiwiki.domain.survey.model.entity.Answer;
Expand Down Expand Up @@ -40,12 +38,12 @@ public DashboardDto getDashboard(TokenUserInfoDto tokenUserInfoDto, Period perio
}
Dashboard dashboard = optionalDashboard.get();

List<PopulationStatistic> populationStatistics = statisticsService.getPopulationStatistics(period, relation);
List<DashboardComponent> populationDashboards = dashboard.getPopulationDashboards(populationStatistics);
List<DashboardComponent> userDashboards = dashboard.getUserDashboards();
PopulationStatistic populationStatistic = statisticsService.getPopulationStatistic(period, relation, QuestionName.BORROWING_LIMIT);
DashboardComponent populationDashboard = dashboard.getPopulationDashboard(populationStatistic, DashboardType.MONEY);

List<DashboardComponent> components = new ArrayList<>(userDashboards);
components.add(populationDashboard);
components.addAll(populationDashboards);

return new DashboardDto(components);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ protected static RatioStatistic create(Question question) {
public void updateStatistic(Answer answer) {
increaseTotalCount();

if (answer.getType().isOption()) {
increaseOptionCount(answer);
}
}

private void increaseOptionCount(Answer answer) {
Question question = answer.getQuestion();
String optionId = answer.getAnswer().toString();
Legend legend = getLegend(optionId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,14 @@ public List<DashboardComponent> getUserDashboards() {
.toList();
}

public DashboardComponent getPopulationDashboard(PopulationStatistic populationStatistic, DashboardType dashboardType) {
List<Statistic> statisticsByDashboardType = statistics.getStatisticsByDashboardType(dashboardType);

return DashboardFactory.create(dashboardType, statisticsByDashboardType, populationStatistic);
public List<DashboardComponent> getPopulationDashboards(List<PopulationStatistic> populationStatistics) {
return populationStatistics.stream()
.map(populationStatistic -> {
DashboardType dashboardType = populationStatistic.getDashboardType();
List<Statistic> statisticsByDashboardType = statistics.getStatisticsByDashboardType(dashboardType);
return DashboardFactory.create(dashboardType, statisticsByDashboardType, populationStatistic);
})
.toList();
}

public static Dashboard createNew(User owner, Period period, Relation relation, List<Answer> answers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
import com.dnd.namuiwiki.domain.survey.type.Relation;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;
import java.util.Optional;

public interface StatisticsRepository extends MongoRepository<PopulationStatistic, String> {
Optional<PopulationStatistic> findByPeriodAndRelationAndQuestionName(Period period, Relation relation, QuestionName name);

List<PopulationStatistic> findAllByPeriodAndRelation(Period period, Relation relation);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package com.dnd.namuiwiki.domain.statistic;

import com.dnd.namuiwiki.common.exception.ApplicationErrorException;
import com.dnd.namuiwiki.common.exception.ApplicationErrorType;
import com.dnd.namuiwiki.domain.option.entity.Option;
import com.dnd.namuiwiki.domain.question.type.QuestionName;
import com.dnd.namuiwiki.domain.statistic.model.AverageEntireStatistic;
import com.dnd.namuiwiki.domain.question.entity.Question;
import com.dnd.namuiwiki.domain.statistic.model.entity.PopulationStatistic;
import com.dnd.namuiwiki.domain.survey.model.entity.Answer;
import com.dnd.namuiwiki.domain.survey.model.entity.Survey;
import com.dnd.namuiwiki.domain.survey.type.Period;
import com.dnd.namuiwiki.domain.survey.type.Relation;
Expand All @@ -24,52 +19,37 @@ public void updateStatistics(Survey survey) {
Period period = survey.getPeriod();
Relation relation = survey.getRelation();

var statisticalAnswers = survey.getAnswers().stream()
.filter(answer -> answer.getQuestion().getDashboardType().getStatisticsCalculationType().isNotNone())
.toList();

updateBorrowingLimitStatistic(period, relation, statisticalAnswers);
survey.getAnswers().stream()
.filter(answer -> answer.getQuestion().getDashboardType().getAnalysisType().isPopulation())
.forEach(answer -> {
Question question = answer.getQuestion();
var calculationType = question.getDashboardType().getStatisticsCalculationType();
if (calculationType.isAverage()) {
updateAverageStatistic(question, period, relation, answer.getAnswer(Long.class));
}
});
}

public PopulationStatistic getPopulationStatistic(Period period, Relation relation, QuestionName questionName) {
return statisticsRepository
.findByPeriodAndRelationAndQuestionName(period, relation, questionName)
.orElseGet(() -> PopulationStatistic.builder()
.statistic(new AverageEntireStatistic(0L, 0L))
.period(period)
.questionName(questionName)
.relation(relation)
.build());
private void updateAverageStatistic(Question question, Period period, Relation relation, long newValue) {
updateAverageStatisticByCategory(question, null, null, newValue);
updateAverageStatisticByCategory(question, period, null, newValue);
updateAverageStatisticByCategory(question, null, relation, newValue);
}

private void updateBorrowingLimitStatistic(Period period, Relation relation, List<Answer> answers) {
Answer borroingLimitAnswer = answers.stream()
.filter(answer -> answer.getQuestion().getName() == QuestionName.BORROWING_LIMIT)
.findFirst()
.orElseThrow(() -> new ApplicationErrorException(ApplicationErrorType.INVALID_DATA_ARGUMENT));

long borrowingLimit;
if (borroingLimitAnswer.getType().isOption()) {
Option option = borroingLimitAnswer.getQuestion().getOptions().get(borroingLimitAnswer.getAnswer().toString());
borrowingLimit = (long) option.getValue();
} else {
borrowingLimit = (long) borroingLimitAnswer.getAnswer();
}
private void updateAverageStatisticByCategory(Question question, Period period, Relation relation, long newValue) {
PopulationStatistic populationStatistic = getPopulationStatistic(question, period, relation);
populationStatistic.updateStatistic(String.valueOf(newValue));

updateBorrowingLimitStatisticByCategory(null, null, borrowingLimit);
updateBorrowingLimitStatisticByCategory(period, null, borrowingLimit);
updateBorrowingLimitStatisticByCategory(null, relation, borrowingLimit);
statisticsRepository.save(populationStatistic);
}

private void updateBorrowingLimitStatisticByCategory(Period period, Relation relation, long borrowingLimit) {
PopulationStatistic populationStatistic = getPopulationStatistic(period, relation, QuestionName.BORROWING_LIMIT);

AverageEntireStatistic statistic = (AverageEntireStatistic) populationStatistic.getStatistic();
statistic.updateStatistic(String.valueOf(borrowingLimit));

populationStatistic.setStatistic(statistic);
private PopulationStatistic getPopulationStatistic(Question question, Period period, Relation relation) {
return statisticsRepository.findByPeriodAndRelationAndQuestionName(period, relation, question.getName())
.orElseGet(() -> PopulationStatistic.from(period, relation, question.getName(), question.getDashboardType()));
}

statisticsRepository.save(populationStatistic);
public List<PopulationStatistic> getPopulationStatistics(Period period, Relation relation) {
return statisticsRepository.findAllByPeriodAndRelation(period, relation);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

@Getter
@AllArgsConstructor
public class AverageEntireStatistic implements EntireStatistic {
public class AverageEntireStatistic extends EntireStatistic {

private long entireAverage;
private long peopleCount;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package com.dnd.namuiwiki.domain.statistic.model;

public interface EntireStatistic {
void updateStatistic(String... arguments);
import com.dnd.namuiwiki.domain.statistic.type.StatisticsCalculationType;

public abstract class EntireStatistic {
public abstract void updateStatistic(String... arguments);

public static EntireStatistic createEmpty(StatisticsCalculationType type) {
switch (type) {
case AVERAGE:
return new AverageEntireStatistic(0L, 0L);
default:
throw new IllegalArgumentException("Not supported type: " + type);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package com.dnd.namuiwiki.domain.statistic.model.entity;

import com.dnd.namuiwiki.domain.dashboard.type.DashboardType;
import com.dnd.namuiwiki.domain.question.type.QuestionName;
import com.dnd.namuiwiki.domain.statistic.model.EntireStatistic;
import com.dnd.namuiwiki.domain.survey.type.Period;
import com.dnd.namuiwiki.domain.survey.type.Relation;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Getter
@Setter
@Builder
@Document("statistics")
public class PopulationStatistic {
Expand All @@ -25,6 +24,22 @@ public class PopulationStatistic {

private QuestionName questionName;

private DashboardType dashboardType;

private EntireStatistic statistic;

public void updateStatistic(String... args) {
statistic.updateStatistic(args);
}

public static PopulationStatistic from(Period period, Relation relation, QuestionName questionName, DashboardType dashboardType) {
return PopulationStatistic.builder()
.statistic(EntireStatistic.createEmpty(dashboardType.getStatisticsCalculationType()))
.dashboardType(dashboardType)
.period(period)
.questionName(questionName)
.relation(relation)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@ public boolean isNotNone() {
return this != NONE;
}

public boolean isRatio() {
return this == RATIO;
}

public boolean isAverage() {
return this == AVERAGE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import com.dnd.namuiwiki.common.exception.ApplicationErrorException;
import com.dnd.namuiwiki.common.exception.ApplicationErrorType;
import com.dnd.namuiwiki.domain.option.entity.Option;
import com.dnd.namuiwiki.domain.question.entity.Question;
import com.dnd.namuiwiki.domain.question.type.QuestionType;
import com.dnd.namuiwiki.domain.survey.type.AnswerType;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.mapping.DocumentReference;

@Slf4j
@Getter
@Builder
@NoArgsConstructor
public class Answer {

Expand Down Expand Up @@ -42,6 +43,33 @@ public Answer(Question question, AnswerType type, Object answer, String reason)
this.reason = reason;
}

public <T> T getAnswer(Class<T> returnType) {
Object value;

if (type.isOption()) {
Option option = question.getOptions().get(answer.toString());
value = option.getValue();
} else {
value = answer;
}

if (value == null) {
throw new ApplicationErrorException(ApplicationErrorType.INTERNAL_ERROR);
}

try {
return returnType.cast(value);
} catch (ClassCastException e) {
log.error("Answer.getAnswer value: {}, valueType: {}, returnType: {}", value, value.getClass(), returnType, e);
throw new ApplicationErrorException(ApplicationErrorType.INVALID_TYPE_CAST);
}

}

private boolean isNumericAnswerNeeded() {
return question.getType().isNumericType() && type.isManual();
}

private void validateBorrowingLimit(long longAnswer) {
if (!(0 <= longAnswer && longAnswer <= 1_000_000_000)) {
throw new ApplicationErrorException(ApplicationErrorType.INVALID_BORROWING_LIMIT);
Expand Down