package kickr.db.dao;
import kickr.db.entity.PlayerStatistics;
import kickr.db.entity.Score;
import io.dropwizard.hibernate.AbstractDAO;
import java.time.Instant;
import java.time.Period;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import kickr.db.entity.Player;
import kickr.db.entity.ScoreChange;
import kickr.db.entity.ScoreWithChanges;
import org.hibernate.SessionFactory;
/**
*
* @author nikku
*/
public class ScoreDAO extends AbstractDAO<Score> {
public ScoreDAO(SessionFactory sessionFactory) {
super(sessionFactory);
}
public Score getOrCreateScore(Player player) {
Score score = uniqueResult(namedQuery("Score.byPlayer").setParameter("player", player));
if (score == null) {
score = new Score(player, 0);
persist(score);
}
return score;
}
public List<PlayerStatistics> getStatistics(int firstResult, int maxResults) {
Date latestDate = Date.from(Instant.now().minus(Period.ofDays(7)));
List<Object[]> results = (List<Object[]>) currentSession()
.createQuery("SELECT p, SUM(c.value) FROM ScoreChange c JOIN c.player p WHERE c.created > :latestDate GROUP BY p.id, c.match.id")
.setDate("latestDate", latestDate)
.list();
Map<Player, List<Object[]>> gameValues = results.stream().collect(Collectors.groupingBy(r -> (Player) r[0]));
List<PlayerStatistics> playerStatistics = new ArrayList<>();
gameValues.forEach((player, rows) -> {
long games = rows.size();
long score = 0;
for (Object[] r: rows) {
score += (Long) r[1];
}
playerStatistics.add(new PlayerStatistics(player, score, games));
});
return playerStatistics.stream().sorted((s1, s2) -> {
return -1 * Double.compare(s1.getRating(), s2.getRating());
}).skip(firstResult)
.limit(maxResults)
.collect(Collectors.toList());
}
public List<ScoreWithChanges> getScoresWithChanges(int firstResult, int maxResults) {
List<Score> scores = list(currentSession()
.createQuery("SELECT s FROM Score s ORDER BY s.value DESC")
.setFirstResult(firstResult)
.setMaxResults(maxResults));
if (scores.isEmpty()) {
return Collections.emptyList();
}
Date latestDate = Date.from(Instant.now().minus(Period.ofDays(7)));
List<ScoreChange> changes = currentSession()
.createQuery(
"SELECT c FROM ScoreChange c " +
"JOIN FETCH c.match " +
"JOIN FETCH c.score " +
"JOIN FETCH c.score.player " +
"WHERE c.created > :latestDate AND c.score IN :scores")
.setDate("latestDate", latestDate)
.setParameterList("scores", scores)
.list();
Map<Score, List<ScoreChange>> changesByScore = changes.stream()
.collect(Collectors.groupingBy(ScoreChange::getScore));
return scores.stream()
.map(s -> new ScoreWithChanges(s, changesByScore.getOrDefault(s, Collections.emptyList())))
.collect(Collectors.toList());
}
public void createChanges(ScoreChange update) {
currentSession().persist(update);
}
}