Skip to content

Commit de51a9b

Browse files
committed
fix: solve period issue into comparison
1 parent e690232 commit de51a9b

1 file changed

Lines changed: 111 additions & 74 deletions

File tree

app/modules/analytics/controllers/team_comparison_controller.rb

Lines changed: 111 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def index
1818
private
1919

2020
def fetch_roster_players
21-
organization_scoped(Player).includes(:organization).where(status: %w[active benched trial])
21+
organization_scoped(Player).includes(:organization).where.not(status: 'removed')
2222
end
2323

2424
def build_matches_query
@@ -60,59 +60,81 @@ def build_comparison_data(players, matches)
6060
end
6161

6262
# Single GROUP BY query replaces one query per player (N+1 → 1)
63+
# Players with no stats in the period appear with zero values
6364
def build_player_comparisons(players, matches)
6465
player_ids = players.pluck(:id)
65-
match_ids = matches.pluck(:id)
66-
return [] if player_ids.empty? || match_ids.empty?
67-
68-
agg_rows = PlayerMatchStat
69-
.where(player_id: player_ids, match_id: match_ids)
70-
.group(:player_id)
71-
.select(
72-
'player_id',
73-
'COUNT(*) AS games_played',
74-
'SUM(kills) AS total_kills',
75-
'SUM(deaths) AS total_deaths',
76-
'SUM(assists) AS total_assists',
77-
'AVG(damage_dealt_total) AS avg_damage',
78-
'AVG(gold_earned) AS avg_gold',
79-
'AVG(cs) AS avg_cs',
80-
'AVG(vision_score) AS avg_vision_score',
81-
'AVG(performance_score) AS avg_performance_score',
82-
'SUM(double_kills) AS double_kills',
83-
'SUM(triple_kills) AS triple_kills',
84-
'SUM(quadra_kills) AS quadra_kills',
85-
'SUM(penta_kills) AS penta_kills'
86-
)
87-
88-
players_by_id = players.index_by(&:id)
89-
90-
agg_rows.filter_map do |agg|
91-
player = players_by_id[agg.player_id]
92-
next unless player
93-
94-
deaths = agg.total_deaths.to_i.zero? ? 1 : agg.total_deaths.to_i
95-
kda = ((agg.total_kills.to_i + agg.total_assists.to_i).to_f / deaths).round(2)
96-
97-
{
98-
player: PlayerSerializer.render_as_hash(player),
99-
games_played: agg.games_played.to_i,
100-
kda: kda,
101-
avg_damage: agg.avg_damage.to_f.round(0),
102-
avg_gold: agg.avg_gold.to_f.round(0),
103-
avg_cs: agg.avg_cs.to_f.round(1),
104-
avg_vision_score: agg.avg_vision_score.to_f.round(1),
105-
avg_performance_score: agg.avg_performance_score.to_f.round(1),
106-
multikills: {
107-
double: agg.double_kills.to_i,
108-
triple: agg.triple_kills.to_i,
109-
quadra: agg.quadra_kills.to_i,
110-
penta: agg.penta_kills.to_i
111-
}
112-
}
66+
return [] if player_ids.empty?
67+
68+
match_ids = matches.pluck(:id)
69+
70+
agg_by_player_id = if match_ids.empty?
71+
{}
72+
else
73+
PlayerMatchStat
74+
.where(player_id: player_ids, match_id: match_ids)
75+
.group(:player_id)
76+
.select(
77+
'player_id',
78+
'COUNT(*) AS games_played',
79+
'SUM(kills) AS total_kills',
80+
'SUM(deaths) AS total_deaths',
81+
'SUM(assists) AS total_assists',
82+
'AVG(damage_dealt_total) AS avg_damage',
83+
'AVG(gold_earned) AS avg_gold',
84+
'AVG(cs) AS avg_cs',
85+
'AVG(vision_score) AS avg_vision_score',
86+
'AVG(performance_score) AS avg_performance_score',
87+
'SUM(double_kills) AS double_kills',
88+
'SUM(triple_kills) AS triple_kills',
89+
'SUM(quadra_kills) AS quadra_kills',
90+
'SUM(penta_kills) AS penta_kills'
91+
).index_by(&:player_id)
92+
end
93+
94+
players.map do |player|
95+
agg = agg_by_player_id[player.id]
96+
build_player_entry(player, agg)
11397
end.sort_by { |p| -p[:avg_performance_score] }
11498
end
11599

100+
def build_player_entry(player, agg)
101+
return zero_stats_entry(player) unless agg
102+
103+
deaths = agg.total_deaths.to_i.zero? ? 1 : agg.total_deaths.to_i
104+
kda = ((agg.total_kills.to_i + agg.total_assists.to_i).to_f / deaths).round(2)
105+
106+
{
107+
player: PlayerSerializer.render_as_hash(player),
108+
games_played: agg.games_played.to_i,
109+
kda: kda,
110+
avg_damage: agg.avg_damage.to_f.round(0),
111+
avg_gold: agg.avg_gold.to_f.round(0),
112+
avg_cs: agg.avg_cs.to_f.round(1),
113+
avg_vision_score: agg.avg_vision_score.to_f.round(1),
114+
avg_performance_score: agg.avg_performance_score.to_f.round(1),
115+
multikills: {
116+
double: agg.double_kills.to_i,
117+
triple: agg.triple_kills.to_i,
118+
quadra: agg.quadra_kills.to_i,
119+
penta: agg.penta_kills.to_i
120+
}
121+
}
122+
end
123+
124+
def zero_stats_entry(player)
125+
{
126+
player: PlayerSerializer.render_as_hash(player),
127+
games_played: 0,
128+
kda: 0.0,
129+
avg_damage: 0,
130+
avg_gold: 0,
131+
avg_cs: 0.0,
132+
avg_vision_score: 0.0,
133+
avg_performance_score: 0.0,
134+
multikills: { double: 0, triple: 0, quadra: 0, penta: 0 }
135+
}
136+
end
137+
116138
def calculate_average(stats, column, precision)
117139
stats.average(column)&.round(precision) || 0
118140
end
@@ -148,35 +170,50 @@ def calculate_team_averages(matches)
148170
end
149171

150172
# Single GROUP BY across all roles — replaces 3N per-player queries
173+
# Players with no stats appear in their role slot with 0 games
151174
def calculate_role_rankings(players, matches)
152175
player_ids = players.pluck(:id)
153-
match_ids = matches.pluck(:id)
154-
155-
rankings = { 'top' => [], 'jungle' => [], 'mid' => [], 'adc' => [], 'support' => [] }
156-
return rankings if player_ids.empty? || match_ids.empty?
157-
158-
agg_rows = PlayerMatchStat
159-
.joins(:player)
160-
.where(player_id: player_ids, match_id: match_ids)
161-
.group('player_id, players.role, players.summoner_name')
162-
.select(
163-
'player_id',
164-
'players.role AS role',
165-
'players.summoner_name AS summoner_name',
166-
'COUNT(*) AS games',
167-
'AVG(performance_score) AS avg_performance'
168-
)
169-
170-
agg_rows.each do |agg|
171-
role = agg.role
176+
rankings = { 'top' => [], 'jungle' => [], 'mid' => [], 'adc' => [], 'support' => [] }
177+
return rankings if player_ids.empty?
178+
179+
match_ids = matches.pluck(:id)
180+
181+
agg_by_player_id = if match_ids.empty?
182+
{}
183+
else
184+
PlayerMatchStat
185+
.joins(:player)
186+
.where(player_id: player_ids, match_id: match_ids)
187+
.group('player_id, players.role, players.summoner_name')
188+
.select(
189+
'player_id',
190+
'players.role AS role',
191+
'players.summoner_name AS summoner_name',
192+
'COUNT(*) AS games',
193+
'AVG(performance_score) AS avg_performance'
194+
).index_by(&:player_id)
195+
end
196+
197+
players.each do |player|
198+
role = player.role
172199
next unless rankings.key?(role)
173200

174-
rankings[role] << {
175-
player_id: agg.player_id,
176-
summoner_name: agg.summoner_name,
177-
avg_performance: agg.avg_performance.to_f.round(1),
178-
games: agg.games.to_i
179-
}
201+
agg = agg_by_player_id[player.id]
202+
rankings[role] << if agg
203+
{
204+
player_id: player.id,
205+
summoner_name: player.summoner_name,
206+
avg_performance: agg.avg_performance.to_f.round(1),
207+
games: agg.games.to_i
208+
}
209+
else
210+
{
211+
player_id: player.id,
212+
summoner_name: player.summoner_name,
213+
avg_performance: 0.0,
214+
games: 0
215+
}
216+
end
180217
end
181218

182219
rankings.transform_values { |list| list.sort_by { |p| -p[:avg_performance] } }

0 commit comments

Comments
 (0)