added team overview

This commit is contained in:
2026-03-06 18:53:58 +11:00
parent baa15f03fa
commit c53fbac281
8 changed files with 535 additions and 10 deletions

View File

@@ -2,6 +2,7 @@ package db
import (
"context"
"sort"
"github.com/pkg/errors"
"github.com/uptrace/bun"
@@ -72,3 +73,149 @@ func (t *Team) InSeason(seasonID int) bool {
}
return false
}
// TeamSeasonInfo holds information about a team's participation in a specific season+league.
type TeamSeasonInfo struct {
Season *Season
League *League
Record *TeamRecord
TotalTeams int
Position int
}
// GetTeamSeasonParticipation returns all season+league combos the team participated in,
// with computed records, positions, and total team counts.
func GetTeamSeasonParticipation(
ctx context.Context,
tx bun.Tx,
teamID int,
) ([]*TeamSeasonInfo, error) {
if teamID == 0 {
return nil, errors.New("teamID not provided")
}
// Get all participations for this team
var participations []*TeamParticipation
err := tx.NewSelect().
Model(&participations).
Where("team_id = ?", teamID).
Relation("Season", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Relation("Leagues")
}).
Relation("League").
Scan(ctx)
if err != nil {
return nil, errors.Wrap(err, "tx.NewSelect participations")
}
var results []*TeamSeasonInfo
for _, p := range participations {
// Get all teams in this season+league for position calculation
var teams []*Team
err := tx.NewSelect().
Model(&teams).
Join("INNER JOIN team_participations AS tp ON tp.team_id = t.id").
Where("tp.season_id = ? AND tp.league_id = ?", p.SeasonID, p.LeagueID).
Scan(ctx)
if err != nil {
return nil, errors.Wrap(err, "tx.NewSelect teams")
}
// Get all fixtures for this season+league
fixtures, err := GetAllocatedFixtures(ctx, tx, p.SeasonID, p.LeagueID)
if err != nil {
return nil, errors.Wrap(err, "GetAllocatedFixtures")
}
fixtureIDs := make([]int, len(fixtures))
for i, f := range fixtures {
fixtureIDs[i] = f.ID
}
resultMap, err := GetFinalizedResultsForFixtures(ctx, tx, fixtureIDs)
if err != nil {
return nil, errors.Wrap(err, "GetFinalizedResultsForFixtures")
}
// Compute leaderboard to get position
leaderboard := ComputeLeaderboard(teams, fixtures, resultMap)
var position int
var record *TeamRecord
for _, entry := range leaderboard {
if entry.Team.ID == teamID {
position = entry.Position
record = entry.Record
break
}
}
if record == nil {
record = &TeamRecord{}
}
results = append(results, &TeamSeasonInfo{
Season: p.Season,
League: p.League,
Record: record,
TotalTeams: len(teams),
Position: position,
})
}
// Sort by season start date descending (newest first)
sort.Slice(results, func(i, j int) bool {
return results[i].Season.StartDate.After(results[j].Season.StartDate)
})
return results, nil
}
// TeamAllTimePlayerStats holds aggregated all-time stats for a player on a team.
type TeamAllTimePlayerStats struct {
PlayerID int `bun:"player_id"`
PlayerName string `bun:"player_name"`
SeasonsPlayed int `bun:"seasons_played"`
PeriodsPlayed int `bun:"total_periods_played"`
Goals int `bun:"total_goals"`
Assists int `bun:"total_assists"`
Saves int `bun:"total_saves"`
}
// GetTeamAllTimePlayerStats returns aggregated all-time stats for all players
// who have ever played for a given team across all seasons.
func GetTeamAllTimePlayerStats(
ctx context.Context,
tx bun.Tx,
teamID int,
) ([]*TeamAllTimePlayerStats, error) {
if teamID == 0 {
return nil, errors.New("teamID not provided")
}
var stats []*TeamAllTimePlayerStats
err := tx.NewRaw(`
SELECT
frps.player_id AS player_id,
COALESCE(p.name, frps.player_username) AS player_name,
COUNT(DISTINCT s.id) AS seasons_played,
COALESCE(SUM(frps.periods_played), 0) AS total_periods_played,
COALESCE(SUM(frps.goals), 0) AS total_goals,
COALESCE(SUM(frps.assists), 0) AS total_assists,
COALESCE(SUM(frps.saves), 0) AS total_saves
FROM fixture_result_player_stats frps
JOIN fixture_results fr ON fr.id = frps.fixture_result_id
JOIN fixtures f ON f.id = fr.fixture_id
JOIN seasons s ON s.id = f.season_id
LEFT JOIN players p ON p.id = frps.player_id
WHERE fr.finalized = true
AND frps.team_id = ?
AND frps.period_num = 3
AND frps.player_id IS NOT NULL
GROUP BY frps.player_id, COALESCE(p.name, frps.player_username)
`, teamID).Scan(ctx, &stats)
if err != nil {
return nil, errors.Wrap(err, "tx.NewRaw")
}
return stats, nil
}