From 4ecac08b4834bfa7b25a1067a7637069b1367714 Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 28 Aug 2025 16:00:48 +0300 Subject: [PATCH 1/9] create statistics service skeleton and overall stats logic --- .../api/service/WarriorStatisticsService.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java new file mode 100644 index 0000000..68e53c1 --- /dev/null +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -0,0 +1,59 @@ +package com.mayadem.battlearena.api.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.mayadem.battlearena.api.dto.OverallStatsDto; +import com.mayadem.battlearena.api.dto.enums.StreakType; +import com.mayadem.battlearena.api.entity.Warrior; +import com.mayadem.battlearena.api.repository.BattleParticipantRepository; +import com.mayadem.battlearena.api.repository.projection.OverallStatsProjection; + +@Service +public class WarriorStatisticsService { + + private final BattleParticipantRepository battleParticipantRepository; + + public WarriorStatisticsService(BattleParticipantRepository battleParticipantRepository) { + this.battleParticipantRepository = battleParticipantRepository; + } + + public void getDetailedStatsForWarrior(Warrior warrior) { + + } + + + @Transactional(readOnly = true) + private OverallStatsDto buildOverallStats(Warrior warrior) { + + OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior) + .orElse(new OverallStatsProjection(0, 0, 0, 0, 0.0, 0, 0.0, 0L)); + + + Object[] streakInfo = battleParticipantRepository.findStreakInfoByWarrior(warrior.getId()); + + int currentStreak = 0; + StreakType streakType = StreakType.NONE; + int longestWinStreak = 0; + + if (streakInfo != null && streakInfo.length > 0 && streakInfo[0] != null) { + currentStreak = ((Number) streakInfo[0]).intValue(); + streakType = StreakType.valueOf((String) streakInfo[1]); + longestWinStreak = ((Number) streakInfo[2]).intValue(); + } + + return new OverallStatsDto( + (int) stats.totalBattles(), + (int) stats.victories(), + (int) stats.defeats(), + (int) stats.draws(), + stats.winRate() != null ? stats.winRate() : 0.0, + stats.bestScore() != null ? stats.bestScore() : 0, + stats.averageScore() != null ? stats.averageScore() : 0.0, + stats.totalRankPointsGained() != null ? stats.totalRankPointsGained().intValue() : 0, + currentStreak, + streakType, + longestWinStreak + ); + } +} \ No newline at end of file From bd25286cc1d4b8bf8521571d570560e346663a5a Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 28 Aug 2025 16:04:41 +0300 Subject: [PATCH 2/9] add recent performance and trend calculation logic --- .../api/service/WarriorStatisticsService.java | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index 68e53c1..f9c781d 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -1,13 +1,20 @@ package com.mayadem.battlearena.api.service; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Collections; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.mayadem.battlearena.api.dto.OverallStatsDto; +import com.mayadem.battlearena.api.dto.RecentPerformanceDto; +import com.mayadem.battlearena.api.dto.enums.PerformanceTrend; import com.mayadem.battlearena.api.dto.enums.StreakType; import com.mayadem.battlearena.api.entity.Warrior; import com.mayadem.battlearena.api.repository.BattleParticipantRepository; import com.mayadem.battlearena.api.repository.projection.OverallStatsProjection; +import com.mayadem.battlearena.api.repository.projection.RecentPerformanceProjection; @Service public class WarriorStatisticsService { @@ -19,19 +26,17 @@ public WarriorStatisticsService(BattleParticipantRepository battleParticipantRep } public void getDetailedStatsForWarrior(Warrior warrior) { - - } + } @Transactional(readOnly = true) private OverallStatsDto buildOverallStats(Warrior warrior) { - + OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior) .orElse(new OverallStatsProjection(0, 0, 0, 0, 0.0, 0, 0.0, 0L)); - Object[] streakInfo = battleParticipantRepository.findStreakInfoByWarrior(warrior.getId()); - + int currentStreak = 0; StreakType streakType = StreakType.NONE; int longestWinStreak = 0; @@ -53,7 +58,41 @@ private OverallStatsDto buildOverallStats(Warrior warrior) { stats.totalRankPointsGained() != null ? stats.totalRankPointsGained().intValue() : 0, currentStreak, streakType, - longestWinStreak - ); + longestWinStreak); + } + + @Transactional(readOnly = true) + private RecentPerformanceDto buildRecentPerformance(Warrior warrior, double overallWinRate) { + + Instant since = Instant.now().minus(30, ChronoUnit.DAYS); + + RecentPerformanceProjection recentStats = battleParticipantRepository.findRecentStats(warrior, since) + .orElse(new RecentPerformanceProjection(0, 0, 0L)); + + long battles = recentStats.battles(); + long victories = recentStats.victories(); + long rankPointsChange = recentStats.rankPointsChange() != null ? recentStats.rankPointsChange() : 0L; + + double winRateLast30Days = (battles > 0) ? ((double) victories / battles) * 100.0 : 0.0; + PerformanceTrend trend; + double difference = winRateLast30Days - overallWinRate; + + if (battles < 10) { + trend = PerformanceTrend.STEADY; + } else if (difference > 5) { + trend = PerformanceTrend.IMPROVING; + } else if (difference < -5) { + trend = PerformanceTrend.DECLINING; + } else { + trend = PerformanceTrend.STEADY; + } + + return new RecentPerformanceDto( + (int) battles, + (int) victories, + Math.round(winRateLast30Days * 100.0) / 100.0, + (int) rankPointsChange, + trend, + Collections.emptyMap()); } } \ No newline at end of file From 5a58ded2af9d70c3e92800a01f2e4ebabf44a2b7 Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 28 Aug 2025 19:25:27 +0300 Subject: [PATCH 3/9] complete statistics service by assembling all DTOs --- .../api/service/WarriorStatisticsService.java | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index f9c781d..d6728e6 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -3,15 +3,22 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Collections; +import java.util.List; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import com.mayadem.battlearena.api.dto.BattleTypeStatsDto; +import com.mayadem.battlearena.api.dto.GlobalComparisonDto; +import com.mayadem.battlearena.api.dto.LeaderboardStatsDto; import com.mayadem.battlearena.api.dto.OverallStatsDto; import com.mayadem.battlearena.api.dto.RecentPerformanceDto; +import com.mayadem.battlearena.api.dto.WarriorDetailedStatsDto; import com.mayadem.battlearena.api.dto.enums.PerformanceTrend; import com.mayadem.battlearena.api.dto.enums.StreakType; +import com.mayadem.battlearena.api.entity.ArenaLeaderboard; import com.mayadem.battlearena.api.entity.Warrior; +import com.mayadem.battlearena.api.repository.ArenaLeaderboardRepository; import com.mayadem.battlearena.api.repository.BattleParticipantRepository; import com.mayadem.battlearena.api.repository.projection.OverallStatsProjection; import com.mayadem.battlearena.api.repository.projection.RecentPerformanceProjection; @@ -20,13 +27,47 @@ public class WarriorStatisticsService { private final BattleParticipantRepository battleParticipantRepository; + private final ArenaLeaderboardRepository arenaLeaderboardRepository; - public WarriorStatisticsService(BattleParticipantRepository battleParticipantRepository) { + public WarriorStatisticsService(BattleParticipantRepository battleParticipantRepository, + ArenaLeaderboardRepository arenaLeaderboardRepository) { this.battleParticipantRepository = battleParticipantRepository; + this.arenaLeaderboardRepository = arenaLeaderboardRepository; } - public void getDetailedStatsForWarrior(Warrior warrior) { + @Transactional(readOnly = true) + public WarriorDetailedStatsDto getDetailedStatsForWarrior(Warrior warrior) { + + OverallStatsDto overallStats = buildOverallStats(warrior); + + RecentPerformanceDto recentPerformance = buildRecentPerformance(warrior, overallStats.winRate()); + + List statsByType = battleParticipantRepository.findStatsByBattleType(warrior); + + Integer currentRank = arenaLeaderboardRepository.findWarriorPosition(warrior.getId()) + .map(ArenaLeaderboard::getRankPosition) + .orElse(null); + + GlobalComparisonDto globalComparison = buildGlobalComparison(); + + return new WarriorDetailedStatsDto( + warrior.getUsername(), + warrior.getDisplayName(), + warrior.getRankPoints(), + currentRank, + overallStats, + statsByType, + recentPerformance, + globalComparison); + } + private GlobalComparisonDto buildGlobalComparison() { + LeaderboardStatsDto globalStats = arenaLeaderboardRepository.findGlobalStats(); + return new GlobalComparisonDto( + globalStats.getAverageRankPoints() != null ? globalStats.getAverageRankPoints() : 0.0, + 0.0, + globalStats.getTotalActiveWarriors() != null ? globalStats.getTotalActiveWarriors().intValue() : 0 + ); } @Transactional(readOnly = true) From e6cebe77499a0e064a01a07813352a2a51704367 Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 28 Aug 2025 19:33:34 +0300 Subject: [PATCH 4/9] solve sonar problem --- .../api/repository/BattleParticipantRepository.java | 3 +++ .../battlearena/api/service/WarriorStatisticsService.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mayadem/battlearena/api/repository/BattleParticipantRepository.java b/src/main/java/com/mayadem/battlearena/api/repository/BattleParticipantRepository.java index c5d84c8..e9e88e7 100644 --- a/src/main/java/com/mayadem/battlearena/api/repository/BattleParticipantRepository.java +++ b/src/main/java/com/mayadem/battlearena/api/repository/BattleParticipantRepository.java @@ -70,6 +70,9 @@ public interface BattleParticipantRepository extends JpaRepository 0 THEN + (SUM(CASE WHEN bp.result = com.mayadem.battlearena.api.entity.enums.BattleResult.WIN THEN 1.0 ELSE 0.0 END) / COUNT(bp)) * 100.0 + ELSE 0.0 END, MAX(bp.finalScore), AVG(bp.finalScore), SUM(bp.rankPointsChange) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index d6728e6..472547e 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -82,7 +82,7 @@ private OverallStatsDto buildOverallStats(Warrior warrior) { StreakType streakType = StreakType.NONE; int longestWinStreak = 0; - if (streakInfo != null && streakInfo.length > 0 && streakInfo[0] != null) { + if (streakInfo != null && streakInfo.length > 0 && streakInfo[0] != null && streakInfo[1] != null) { currentStreak = ((Number) streakInfo[0]).intValue(); streakType = StreakType.valueOf((String) streakInfo[1]); longestWinStreak = ((Number) streakInfo[2]).intValue(); From 0b7346578cdf9e67fc3b5824e08725e5b8543cd7 Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 28 Aug 2025 19:41:09 +0300 Subject: [PATCH 5/9] solve sonar problem --- .../battlearena/api/service/WarriorStatisticsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index 472547e..8df0a54 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -70,7 +70,7 @@ private GlobalComparisonDto buildGlobalComparison() { ); } - @Transactional(readOnly = true) + private OverallStatsDto buildOverallStats(Warrior warrior) { OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior) @@ -102,7 +102,7 @@ private OverallStatsDto buildOverallStats(Warrior warrior) { longestWinStreak); } - @Transactional(readOnly = true) + private RecentPerformanceDto buildRecentPerformance(Warrior warrior, double overallWinRate) { Instant since = Instant.now().minus(30, ChronoUnit.DAYS); From 199f5d869c569e5e7f1a93300b73b68a480f72c8 Mon Sep 17 00:00:00 2001 From: Eren Date: Tue, 2 Sep 2025 23:08:19 +0300 Subject: [PATCH 6/9] update --- .../api/service/WarriorStatisticsService.java | 77 +++++++++++++------ 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index 8df0a54..b92a588 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -4,7 +4,8 @@ import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.List; - +import java.util.stream.Collectors; +import java.util.Map; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,8 +21,10 @@ import com.mayadem.battlearena.api.entity.Warrior; import com.mayadem.battlearena.api.repository.ArenaLeaderboardRepository; import com.mayadem.battlearena.api.repository.BattleParticipantRepository; +import com.mayadem.battlearena.api.repository.projection.DailyStatsProjection; import com.mayadem.battlearena.api.repository.projection.OverallStatsProjection; import com.mayadem.battlearena.api.repository.projection.RecentPerformanceProjection; +import com.mayadem.battlearena.api.repository.projection.StreakProjection; @Service public class WarriorStatisticsService { @@ -61,31 +64,52 @@ public WarriorDetailedStatsDto getDetailedStatsForWarrior(Warrior warrior) { globalComparison); } + @Transactional(readOnly = true) + public OverallStatsDto getOverallStats(Warrior warrior) { + return buildOverallStats(warrior); + } + + @Transactional(readOnly = true) + public RecentPerformanceDto getRecentPerformance(Warrior warrior) { + OverallStatsDto overallStats = buildOverallStats(warrior); + return buildRecentPerformance(warrior, overallStats.winRate()); + } + private GlobalComparisonDto buildGlobalComparison() { LeaderboardStatsDto globalStats = arenaLeaderboardRepository.findGlobalStats(); return new GlobalComparisonDto( - globalStats.getAverageRankPoints() != null ? globalStats.getAverageRankPoints() : 0.0, - 0.0, - globalStats.getTotalActiveWarriors() != null ? globalStats.getTotalActiveWarriors().intValue() : 0 - ); + globalStats.getAverageRankPoints() != null ? globalStats.getAverageRankPoints() : 0.0, + 0.0, + globalStats.getTotalActiveWarriors() != null ? globalStats.getTotalActiveWarriors().intValue() : 0); } - private OverallStatsDto buildOverallStats(Warrior warrior) { - OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior) .orElse(new OverallStatsProjection(0, 0, 0, 0, 0.0, 0, 0.0, 0L)); - Object[] streakInfo = battleParticipantRepository.findStreakInfoByWarrior(warrior.getId()); - - int currentStreak = 0; - StreakType streakType = StreakType.NONE; - int longestWinStreak = 0; - - if (streakInfo != null && streakInfo.length > 0 && streakInfo[0] != null && streakInfo[1] != null) { - currentStreak = ((Number) streakInfo[0]).intValue(); - streakType = StreakType.valueOf((String) streakInfo[1]); - longestWinStreak = ((Number) streakInfo[2]).intValue(); + List streakResults = battleParticipantRepository.findStreakInfoByWarrior(warrior.getId()); + + StreakProjection streakProjection; + if (streakResults != null && !streakResults.isEmpty()) { + Object[] streakResult = streakResults.get(0); + if (streakResult != null && streakResult.length > 0 && streakResult[0] != null) { + int currentStreak = ((Number) streakResult[0]).intValue(); + String streakTypeStr = (String) streakResult[1]; + int longestWinStreak = ((Number) streakResult[2]).intValue(); + + StreakType streakType = StreakType.NONE; + if ("WIN".equalsIgnoreCase(streakTypeStr)) { + streakType = StreakType.WIN; + } else if ("LOSS".equalsIgnoreCase(streakTypeStr)) { + streakType = StreakType.LOSS; + } + + streakProjection = new StreakProjection(currentStreak, streakType, longestWinStreak); + } else { + streakProjection = new StreakProjection(0, StreakType.NONE, 0); + } + } else { + streakProjection = new StreakProjection(0, StreakType.NONE, 0); } return new OverallStatsDto( @@ -97,12 +121,11 @@ private OverallStatsDto buildOverallStats(Warrior warrior) { stats.bestScore() != null ? stats.bestScore() : 0, stats.averageScore() != null ? stats.averageScore() : 0.0, stats.totalRankPointsGained() != null ? stats.totalRankPointsGained().intValue() : 0, - currentStreak, - streakType, - longestWinStreak); + streakProjection.currentStreak(), + streakProjection.streakType(), + streakProjection.longestWinStreak()); } - private RecentPerformanceDto buildRecentPerformance(Warrior warrior, double overallWinRate) { Instant since = Instant.now().minus(30, ChronoUnit.DAYS); @@ -110,6 +133,16 @@ private RecentPerformanceDto buildRecentPerformance(Warrior warrior, double over RecentPerformanceProjection recentStats = battleParticipantRepository.findRecentStats(warrior, since) .orElse(new RecentPerformanceProjection(0, 0, 0L)); + List dailyCounts = battleParticipantRepository.findDailyBattleCounts(warrior.getId(), + since); + + Map dailyStatsMap = dailyCounts.stream() + .collect(Collectors.toMap( + + projection -> projection.getBattleDate().toString(), + + DailyStatsProjection::getBattleCount)); + long battles = recentStats.battles(); long victories = recentStats.victories(); long rankPointsChange = recentStats.rankPointsChange() != null ? recentStats.rankPointsChange() : 0L; @@ -134,6 +167,6 @@ private RecentPerformanceDto buildRecentPerformance(Warrior warrior, double over Math.round(winRateLast30Days * 100.0) / 100.0, (int) rankPointsChange, trend, - Collections.emptyMap()); + dailyStatsMap); } } \ No newline at end of file From c02bff87bdd67f0e35b609654ae0cfd7f0639340 Mon Sep 17 00:00:00 2001 From: Eren Date: Tue, 2 Sep 2025 23:11:16 +0300 Subject: [PATCH 7/9] solve sonar importIssue --- .../battlearena/api/service/WarriorStatisticsService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index b92a588..97df66b 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -2,7 +2,6 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.Map; From f54e368169d166bc9179f8742773e3a27dc7a0f3 Mon Sep 17 00:00:00 2001 From: Eren Date: Wed, 10 Sep 2025 01:19:39 +0300 Subject: [PATCH 8/9] change method because of change in arenaleaderboardrepository --- .../api/service/WarriorStatisticsService.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index 97df66b..54057ea 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -3,14 +3,14 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.List; -import java.util.stream.Collectors; import java.util.Map; +import java.util.stream.Collectors; + import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.mayadem.battlearena.api.dto.BattleTypeStatsDto; import com.mayadem.battlearena.api.dto.GlobalComparisonDto; -import com.mayadem.battlearena.api.dto.LeaderboardStatsDto; import com.mayadem.battlearena.api.dto.OverallStatsDto; import com.mayadem.battlearena.api.dto.RecentPerformanceDto; import com.mayadem.battlearena.api.dto.WarriorDetailedStatsDto; @@ -75,12 +75,13 @@ public RecentPerformanceDto getRecentPerformance(Warrior warrior) { } private GlobalComparisonDto buildGlobalComparison() { - LeaderboardStatsDto globalStats = arenaLeaderboardRepository.findGlobalStats(); - return new GlobalComparisonDto( - globalStats.getAverageRankPoints() != null ? globalStats.getAverageRankPoints() : 0.0, - 0.0, - globalStats.getTotalActiveWarriors() != null ? globalStats.getTotalActiveWarriors().intValue() : 0); - } + ArenaLeaderboardRepository.LeaderboardStatsProjection projection = arenaLeaderboardRepository.findGlobalStatsProjection(); + return new GlobalComparisonDto( + projection.getAverageRankPoints() != null ? projection.getAverageRankPoints() : 0.0, + 0.0, + projection.getTotalActiveWarriors() != null ? projection.getTotalActiveWarriors().intValue() : 0 + ); +} private OverallStatsDto buildOverallStats(Warrior warrior) { OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior) From 337b3ee9e6edd23659958745f2bdc19c4a157e9e Mon Sep 17 00:00:00 2001 From: Eren Date: Thu, 11 Sep 2025 19:17:12 +0300 Subject: [PATCH 9/9] updates --- .../ArenaLeaderboardRepository.java | 65 ++++++++++--------- .../api/service/WarriorStatisticsService.java | 15 +++-- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/mayadem/battlearena/api/repository/ArenaLeaderboardRepository.java b/src/main/java/com/mayadem/battlearena/api/repository/ArenaLeaderboardRepository.java index cae82ab..efc6888 100644 --- a/src/main/java/com/mayadem/battlearena/api/repository/ArenaLeaderboardRepository.java +++ b/src/main/java/com/mayadem/battlearena/api/repository/ArenaLeaderboardRepository.java @@ -1,48 +1,55 @@ package com.mayadem.battlearena.api.repository; -import com.mayadem.battlearena.api.entity.ArenaLeaderboard; +import java.util.List; +import java.util.Optional; + import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; -import java.util.Optional; +import com.mayadem.battlearena.api.entity.ArenaLeaderboard; public interface ArenaLeaderboardRepository extends JpaRepository { - interface LeaderboardStatsProjection { - Long getTotalActiveWarriors(); + interface LeaderboardStatsProjection { + Long getTotalActiveWarriors(); + + Double getAverageWinRate(); + + Double getAverageScore(); - Double getAverageRankPoints(); + Double getAverageRankPoints(); - Integer getHighestRankPoints(); + Integer getHighestRankPoints(); - String getTopWarriorUsername(); - } + String getTopWarriorUsername(); + } // En iyi 100 oyuncu (JPQL'de LIMIT yok → Pageable kullanılmalı) @Query("SELECT a FROM ArenaLeaderboard a ORDER BY a.rankPoints DESC") List findTopPlayers(Pageable pageable); - // Belirli oyuncunun pozisyonu - @Query("SELECT a FROM ArenaLeaderboard a WHERE a.id = :warriorId") - Optional findWarriorPosition(@Param("warriorId") Long warriorId); - - // Global istatistikler - @Query(value = """ - SELECT COUNT(*) AS total_active_warriors, - AVG(rank_points) AS average_rank_points, - MAX(rank_points) AS highest_rank_points, - (SELECT username FROM arena_leaderboard ORDER BY rank_points DESC LIMIT 1) AS top_warrior_username - FROM arena_leaderboard - """, nativeQuery = true) - LeaderboardStatsProjection findGlobalStatsProjection(); - - // Rank aralığındaki oyuncular - @Query("SELECT a FROM ArenaLeaderboard a " + - "WHERE a.rankPosition BETWEEN :startRank AND :endRank " + - "ORDER BY a.rankPosition ASC") - List findWarriorsAroundRank(@Param("startRank") int startRank, - @Param("endRank") int endRank); + // Belirli oyuncunun pozisyonu + @Query("SELECT a FROM ArenaLeaderboard a WHERE a.id = :warriorId") + Optional findWarriorPosition(@Param("warriorId") Long warriorId); + + // Global istatistikler + @Query(value = """ + SELECT COUNT(*) AS total_active_warriors, + AVG(rank_points) AS average_rank_points, + AVG(win_rate) AS average_win_rate, + AVG(best_score) AS average_score, + MAX(rank_points) AS highest_rank_points, + (SELECT username FROM arena_leaderboard ORDER BY rank_points DESC LIMIT 1) AS top_warrior_username + FROM arena_leaderboard + """, nativeQuery = true) + LeaderboardStatsProjection findGlobalStatsProjection(); + + // Rank aralığındaki oyuncular + @Query("SELECT a FROM ArenaLeaderboard a " + + "WHERE a.rankPosition BETWEEN :startRank AND :endRank " + + "ORDER BY a.rankPosition ASC") + List findWarriorsAroundRank(@Param("startRank") int startRank, + @Param("endRank") int endRank); } diff --git a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java index 54057ea..55999a2 100644 --- a/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java +++ b/src/main/java/com/mayadem/battlearena/api/service/WarriorStatisticsService.java @@ -75,13 +75,14 @@ public RecentPerformanceDto getRecentPerformance(Warrior warrior) { } private GlobalComparisonDto buildGlobalComparison() { - ArenaLeaderboardRepository.LeaderboardStatsProjection projection = arenaLeaderboardRepository.findGlobalStatsProjection(); - return new GlobalComparisonDto( - projection.getAverageRankPoints() != null ? projection.getAverageRankPoints() : 0.0, - 0.0, - projection.getTotalActiveWarriors() != null ? projection.getTotalActiveWarriors().intValue() : 0 - ); -} + ArenaLeaderboardRepository.LeaderboardStatsProjection projection = arenaLeaderboardRepository + .findGlobalStatsProjection(); + + return new GlobalComparisonDto( + projection.getAverageWinRate() != null ? projection.getAverageWinRate() : 0.0, + projection.getAverageScore() != null ? projection.getAverageScore() : 0.0, + projection.getTotalActiveWarriors() != null ? projection.getTotalActiveWarriors().intValue() : 0); + } private OverallStatsDto buildOverallStats(Warrior warrior) { OverallStatsProjection stats = battleParticipantRepository.findOverallStatsByWarrior(warrior)