feat(multiplayer): expose active ranked season

This commit is contained in:
Josh Creek
2026-09-01 21:34:57 +01:00
parent 3151e54ab3
commit eb3b685af0
7 changed files with 53 additions and 13 deletions
+20
View File
@@ -1275,6 +1275,26 @@ func TestPostgreSQLEmptyRankedSeasonIsMarkedRolledOver(t *testing.T) {
}
}
func TestPostgreSQLRankedProfileProjectsActiveSeason(t *testing.T) {
db := openIntegrationPostgres(t)
applyIntegrationMigrations(t, db)
now := time.Now().UTC().Truncate(time.Microsecond)
ctx := context.Background()
if _, err := db.ExecContext(ctx, `INSERT INTO identities (player_id, steam_id) VALUES ('profile-season-player', 'profile-season-steam')`); err != nil {
t.Fatal(err)
}
if _, err := db.ExecContext(ctx, `INSERT INTO ratings (player_id, rating, deviation, volatility, ranked_games) VALUES ('profile-season-player', 1600, 200, 0.06, 10)`); err != nil {
t.Fatal(err)
}
if _, err := db.ExecContext(ctx, `INSERT INTO seasons (season_id, playlist, starts_at, ends_at) VALUES ('profile-season-current', 'ranked', $1, $2)`, now.Add(-time.Hour), now.Add(time.Hour)); err != nil {
t.Fatal(err)
}
profile, found, err := (PostgresRankedProfiles{DB: db}).Get(ctx, "profile-season-player")
if err != nil || !found || profile.CurrentSeasonID != "profile-season-current" {
t.Fatalf("profile=%+v found=%t err=%v", profile, found, err)
}
}
func TestPostgreSQLMigrationsAreForwardExecutable(t *testing.T) {
db := openIntegrationPostgres(t)
applyIntegrationMigrations(t, db)
+9 -7
View File
@@ -8,7 +8,10 @@ import (
"github.com/cosmic-clash/cosmic-clash/server/domain"
)
const RankedProfileSelectSQL = `SELECT rating, deviation, volatility, ranked_games, updated_at
const RankedProfileSelectSQL = `SELECT rating, deviation, volatility, ranked_games, updated_at,
COALESCE((SELECT season_id FROM seasons
WHERE playlist = 'ranked' AND starts_at <= CURRENT_TIMESTAMP AND ends_at > CURRENT_TIMESTAMP
ORDER BY starts_at DESC, season_id DESC LIMIT 1), '')
FROM ratings
WHERE player_id = $1`
@@ -19,11 +22,10 @@ WHERE player_id = $1`
// the same way the in-memory RankedProfiles map api.Service still falls
// back to already did: (zero value, false, nil).
//
// LastSeasonID and SeasonHistory are deliberately left at their zero values.
// The ratings table has no "current season" column, and reconstructing
// season history means a second query against ranked_season_rollovers with
// its own display semantics to settle -- a real, separate piece of work,
// not bundled into this read path speculatively.
// LastSeasonID and SeasonHistory remain zero-valued because they describe
// rollover history, while CurrentSeasonID is derived from the active ranked
// season row. Keeping those concepts separate prevents the profile endpoint
// from making a current season look already rolled over to maintenance.
type PostgresRankedProfiles struct{ DB *sql.DB }
func (p PostgresRankedProfiles) Get(ctx context.Context, playerID string) (domain.RankedProfile, bool, error) {
@@ -32,7 +34,7 @@ func (p PostgresRankedProfiles) Get(ctx context.Context, playerID string) (domai
}
var profile domain.RankedProfile
err := p.DB.QueryRowContext(ctx, RankedProfileSelectSQL, playerID).
Scan(&profile.Value, &profile.RD, &profile.Volatility, &profile.RankedGames, &profile.LastRatedAt)
Scan(&profile.Value, &profile.RD, &profile.Volatility, &profile.RankedGames, &profile.LastRatedAt, &profile.CurrentSeasonID)
if err == sql.ErrNoRows {
return domain.RankedProfile{}, false, nil
}
+11
View File
@@ -0,0 +1,11 @@
package store
import "testing"
func TestRankedProfileQueryProjectsOnlyTheActiveRankedSeason(t *testing.T) {
for _, fragment := range []string{"playlist = 'ranked'", "starts_at <= CURRENT_TIMESTAMP", "ends_at > CURRENT_TIMESTAMP", "ORDER BY starts_at DESC", "LIMIT 1"} {
if !contains(RankedProfileSelectSQL, fragment) {
t.Fatalf("ranked profile query missing %q", fragment)
}
}
}