HASH ff2a75cd54b0
DATE 2025-11-14
SUBJECT web: connected realms player profile header
FILES 9 CHANGED
HASH ff2a75cd54b0
DATE 2025-11-14
SUBJECT web: connected realms player profile
header
FILES 9 CHANGED
┌─ nix/pkgs/ookstats/src/internal/database/client.go ────────────────────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/database/client.go b/nix/pkgs/ookstats │
│ /src/internal/database/client.go │
│ index 010b398..cb9dcbd 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/database/client.go │
│ +++ b/nix/pkgs/ookstats/src/internal/database/client.go │
│ @@ -1,12 +1,12 @@ │
│ package database │
│ │
│ import ( │
│ - "database/sql" │
│ - "fmt" │
│ - "os" │
│ - "strings" │
│ + "database/sql" │
│ + "fmt" │
│ + "os" │
│ + "strings" │
│ │
│ - _ "github.com/tursodatabase/go-libsql" │
│ + _ "github.com/tursodatabase/go-libsql" │
│ ) │
│ │
│ // connect creates a local libSQL database connection │
│ @@ -14,66 +14,66 @@ var dbPathOverride string │
│ │
│ // SetDBPath allows callers (CLI) to override the local SQLite filename │
│ func SetDBPath(path string) { │
│ - dbPathOverride = path │
│ + dbPathOverride = path │
│ } │
│ │
│ // DBConnString returns the libsql connection string for the local SQLite file │
│ func DBConnString() string { │
│ - // Priority: explicit override -> env vars -> default │
│ - if dbPathOverride != "" { │
│ - if strings.HasPrefix(dbPathOverride, "file:") { │
│ - return dbPathOverride │
│ - } │
│ - return "file:" + dbPathOverride │
│ - } │
│ - if v := os.Getenv("OOKSTATS_DB"); v != "" { │
│ - if strings.HasPrefix(v, "file:") { │
│ - return v │
│ - } │
│ - return "file:" + v │
│ - } │
│ - if v := os.Getenv("ASTRO_DATABASE_FILE"); v != "" { │
│ - if strings.HasPrefix(v, "file:") { │
│ - return v │
│ - } │
│ - return "file:" + v │
│ - } │
│ - return "file:local.db" │
│ + // Priority: explicit override -> env vars -> default │
│ + if dbPathOverride != "" { │
│ + if strings.HasPrefix(dbPathOverride, "file:") { │
│ + return dbPathOverride │
│ + } │
│ + return "file:" + dbPathOverride │
│ + } │
│ + if v := os.Getenv("OOKSTATS_DB"); v != "" { │
│ + if strings.HasPrefix(v, "file:") { │
│ + return v │
│ + } │
│ + return "file:" + v │
│ + } │
│ + if v := os.Getenv("ASTRO_DATABASE_FILE"); v != "" { │
│ + if strings.HasPrefix(v, "file:") { │
│ + return v │
│ + } │
│ + return "file:" + v │
│ + } │
│ + return "file:local.db" │
│ } │
│ │
│ // DBFilePath returns the plain filesystem path for the local DB (without file: p │
│ refix) │
│ func DBFilePath() string { │
│ - conn := DBConnString() │
│ - if strings.HasPrefix(conn, "file:") { │
│ - return strings.TrimPrefix(conn, "file:") │
│ - } │
│ - return conn │
│ + conn := DBConnString() │
│ + if strings.HasPrefix(conn, "file:") { │
│ + return strings.TrimPrefix(conn, "file:") │
│ + } │
│ + return conn │
│ } │
│ │
│ func Connect() (*sql.DB, error) { │
│ - dsn := DBConnString() │
│ - fmt.Printf("Using local SQLite database: %s\n", dsn) │
│ - fmt.Printf("Opening database connection...\n") │
│ - │
│ - db, err := sql.Open("libsql", dsn) │
│ - if err != nil { │
│ - return nil, fmt.Errorf("failed to open database: %w", err) │
│ - } │
│ - │
│ - fmt.Printf("Testing database connection...\n") │
│ - if err := db.Ping(); err != nil { │
│ - db.Close() │
│ - return nil, fmt.Errorf("failed to ping database: %w", err) │
│ - } │
│ - │
│ - // configure database for optimal performance │
│ - if err := configureDatabaseSettings(db, dsn); err != nil { │
│ - db.Close() │
│ - return nil, fmt.Errorf("failed to configure database: %w", err) │
│ - } │
│ - │
│ - fmt.Printf("[OK] Local SQLite database connected\n") │
│ - return db, nil │
│ + dsn := DBConnString() │
│ + fmt.Printf("Using local SQLite database: %s\n", dsn) │
│ + fmt.Printf("Opening database connection...\n") │
│ + │
│ + db, err := sql.Open("libsql", dsn) │
│ + if err != nil { │
│ + return nil, fmt.Errorf("failed to open database: %w", err) │
│ + } │
│ + │
│ + fmt.Printf("Testing database connection...\n") │
│ + if err := db.Ping(); err != nil { │
│ + db.Close() │
│ + return nil, fmt.Errorf("failed to ping database: %w", err) │
│ + } │
│ + │
│ + // configure database for optimal performance │
│ + if err := configureDatabaseSettings(db, dsn); err != nil { │
│ + db.Close() │
│ + return nil, fmt.Errorf("failed to configure database: %w", err) │
│ + } │
│ + │
│ + fmt.Printf("[OK] Local SQLite database connected\n") │
│ + return db, nil │
│ } │
│ │
│ func getEnvOrFail(key string) string { │
│ @@ -105,10 +105,10 @@ func QuerySQL(db *sql.DB, query string, args ...any) (*sql.R │
│ ows, error) { │
│ │
│ // configureDatabaseSettings optimizes database for performance │
│ func configureDatabaseSettings(db *sql.DB, dsn string) error { │
│ - // apply modest cache size for local SQLite file │
│ - if _, err := db.Exec("PRAGMA cache_size = -64000"); err != nil { │
│ - // ignore if not supported │
│ - } │
│ + // apply modest cache size for local SQLite file │
│ + if _, err := db.Exec("PRAGMA cache_size = -64000"); err != nil { │
│ + // ignore if not supported │
│ + } │
│ │
│ // check journal mode │
│ var journalMode string │
│ @@ -124,7 +124,7 @@ func configureDatabaseSettings(db *sql.DB, dsn string) error { │
│ // EnsureCompleteSchema creates all required tables and indexes for the ookstats │
│ database │
│ func EnsureCompleteSchema(db *sql.DB) error { │
│ fmt.Printf("Ensuring complete database schema...\n") │
│ - │
│ + │
│ // Create all tables first │
│ tables := []string{ │
│ // Reference tables │
│ @@ -135,16 +135,22 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ map_id INTEGER, │
│ map_challenge_mode_id INTEGER UNIQUE │
│ )`, │
│ - │
│ - `CREATE TABLE IF NOT EXISTS realms ( │
│ + │
│ + `CREATE TABLE IF NOT EXISTS realms ( │
│ id INTEGER PRIMARY KEY, │
│ slug TEXT, │
│ name TEXT, │
│ region TEXT, │
│ connected_realm_id INTEGER UNIQUE │
│ )`, │
│ - │
│ + │
│ + `CREATE TABLE IF NOT EXISTS realm_groups ( │
│ + child_realm_id INTEGER PRIMARY KEY, │
│ + parent_realm_id INTEGER NOT NULL │
│ + )`, │
│ + │
│ // Core leaderboard data │
│ + │
│ `CREATE TABLE IF NOT EXISTS challenge_runs ( │
│ id INTEGER PRIMARY KEY, │
│ duration INTEGER, │
│ @@ -157,21 +163,21 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ period_end_timestamp INTEGER, │
│ team_signature TEXT │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS players ( │
│ id INTEGER PRIMARY KEY, │
│ name TEXT, │
│ name_lower TEXT, │
│ realm_id INTEGER │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS run_members ( │
│ run_id INTEGER, │
│ player_id INTEGER, │
│ spec_id INTEGER, │
│ faction TEXT │
│ )`, │
│ - │
│ + │
│ // Player aggregation and rankings (season-scoped) │
│ `CREATE TABLE IF NOT EXISTS player_profiles ( │
│ player_id INTEGER, │
│ @@ -193,7 +199,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ last_updated INTEGER, │
│ PRIMARY KEY (player_id, season_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_best_runs ( │
│ player_id INTEGER, │
│ dungeon_id INTEGER, │
│ @@ -213,7 +219,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ completed_timestamp INTEGER, │
│ PRIMARY KEY (player_id, dungeon_id, season_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_rankings ( │
│ player_id INTEGER, │
│ ranking_type TEXT, │
│ @@ -237,7 +243,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ last_updated INTEGER, │
│ PRIMARY KEY (player_id, season_id) │
│ )`, │
│ - │
│ + │
│ // Extended player information │
│ `CREATE TABLE IF NOT EXISTS player_details ( │
│ player_id INTEGER PRIMARY KEY, │
│ @@ -256,7 +262,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ last_login_timestamp INTEGER, │
│ last_updated INTEGER │
│ )`, │
│ - │
│ + │
│ // Equipment system │
│ `CREATE TABLE IF NOT EXISTS player_equipment ( │
│ id INTEGER PRIMARY KEY, │
│ @@ -268,7 +274,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ item_name TEXT, │
│ snapshot_timestamp INTEGER │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_equipment_enchantments ( │
│ id INTEGER PRIMARY KEY, │
│ equipment_id INTEGER, │
│ @@ -280,7 +286,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ source_item_name TEXT, │
│ spell_id INTEGER │
│ )`, │
│ - │
│ + │
│ // Computed rankings │
│ `CREATE TABLE IF NOT EXISTS run_rankings ( │
│ run_id INTEGER, │
│ @@ -293,7 +299,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ computed_at INTEGER, │
│ PRIMARY KEY (run_id, ranking_type, ranking_scope, season_id) │
│ )`, │
│ - │
│ + │
│ // Metadata and items │
│ `CREATE TABLE IF NOT EXISTS api_fetch_metadata ( │
│ id INTEGER PRIMARY KEY, │
│ @@ -311,7 +317,7 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ last_completed_ts INTEGER NOT NULL DEFAULT 0, │
│ PRIMARY KEY (realm_slug, dungeon_id, period_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS items ( │
│ id INTEGER PRIMARY KEY, │
│ name TEXT, │
│ @@ -338,75 +344,77 @@ func EnsureCompleteSchema(db *sql.DB) error { │
│ PRIMARY KEY (period_id, season_id) │
│ )`, │
│ } │
│ - │
│ + │
│ for _, table := range tables { │
│ if _, err := db.Exec(table); err != nil { │
│ return fmt.Errorf("failed to create table: %w", err) │
│ } │
│ } │
│ - │
│ -fmt.Printf("[OK] All tables created\n") │
│ - │
│ - // Migrate realms schema if needed (ensure (region, slug) composite uniquenes │
│ s) │
│ - if err := migrateRealmsCompositeSlug(db); err != nil { │
│ - return err │
│ - } │
│ - │
│ - // Create indexes │
│ - return ensureRecommendedIndexes(db) │
│ + │
│ + fmt.Printf("[OK] All tables created\n") │
│ + │
│ + // Migrate realms schema if needed (ensure (region, slug) composite uniqueness) │
│ + if err := migrateRealmsCompositeSlug(db); err != nil { │
│ + return err │
│ + } │
│ + │
│ + // Create indexes │
│ + return ensureRecommendedIndexes(db) │
│ } │
│ │
│ // ensureRecommendedIndexes creates indexes used by hot paths if missing │
│ func ensureRecommendedIndexes(db *sql.DB) error { │
│ - stmts := []string{ │
│ - // Ensure composite uniqueness for realms │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slug ON realms(regio │
│ n, slug)", │
│ - // Fast path for high-water checks │
│ - "CREATE INDEX IF NOT EXISTS idx_runs_realm_dungeon_ct ON challenge_runs(r │
│ ealm_id, dungeon_id, completed_timestamp)", │
│ - // Uniqueness key to avoid duplicates │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_unique ON challenge_runs(comp │
│ leted_timestamp, dungeon_id, duration, realm_id, team_signature)", │
│ - // Lookups used elsewhere │
│ - "CREATE INDEX IF NOT EXISTS idx_players_name_lower ON players(name_lower) │
│ ", │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS idx_run_members_pair ON run_members(ru │
│ n_id, player_id)", │
│ - // Speed up canonical run selection: partition/order by team per dungeon │
│ - "CREATE INDEX IF NOT EXISTS idx_runs_dungeon_team_duration ON challenge_r │
│ uns(dungeon_id, team_signature, duration, completed_timestamp, id)", │
│ - // Additional indexes for performance │
│ - "CREATE INDEX IF NOT EXISTS idx_run_members_player_id ON run_members(play │
│ er_id)", │
│ - "CREATE INDEX IF NOT EXISTS idx_challenge_runs_dungeon_duration ON challe │
│ nge_runs(dungeon_id, duration)", │
│ - // Season-related indexes │
│ - "CREATE INDEX IF NOT EXISTS idx_run_rankings_season ON run_rankings(seaso │
│ n_id, ranking_type, ranking_scope, dungeon_id)", │
│ - "CREATE INDEX IF NOT EXISTS idx_player_best_runs_season ON player_best_ru │
│ ns(season_id, player_id)", │
│ - "CREATE INDEX IF NOT EXISTS idx_player_profiles_season ON player_profiles │
│ (season_id, global_ranking)", │
│ - "CREATE INDEX IF NOT EXISTS idx_player_profiles_season_coverage ON player │
│ _profiles(season_id, has_complete_coverage, combined_best_time)", │
│ - } │
│ - for _, s := range stmts { │
│ - if _, err := db.Exec(s); err != nil { │
│ - // don't fail the connection on index creation errors │
│ - fmt.Printf("Warning: index creation failed: %v\n", err) │
│ - } │
│ - } │
│ - │
│ - fmt.Printf("[OK] All indexes ensured\n") │
│ - return nil │
│ + stmts := []string{ │
│ + // Ensure composite uniqueness for realms │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slug ON realms(region, slu │
│ g)", │
│ + // Fast path for high-water checks │
│ + "CREATE INDEX IF NOT EXISTS idx_runs_realm_dungeon_ct ON challenge_runs(realm_i │
│ d, dungeon_id, completed_timestamp)", │
│ + // Uniqueness key to avoid duplicates │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_unique ON challenge_runs(completed_ │
│ timestamp, dungeon_id, duration, realm_id, team_signature)", │
│ + // Lookups used elsewhere │
│ + "CREATE INDEX IF NOT EXISTS idx_players_name_lower ON players(name_lower)", │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_run_members_pair ON run_members(run_id, │
│ player_id)", │
│ + // Speed up canonical run selection: partition/order by team per dungeon │
│ + "CREATE INDEX IF NOT EXISTS idx_runs_dungeon_team_duration ON challenge_runs(du │
│ ngeon_id, team_signature, duration, completed_timestamp, id)", │
│ + // Additional indexes for performance │
│ + "CREATE INDEX IF NOT EXISTS idx_run_members_player_id ON run_members(player_id) │
│ ", │
│ + "CREATE INDEX IF NOT EXISTS idx_challenge_runs_dungeon_duration ON challenge_ru │
│ ns(dungeon_id, duration)", │
│ + // Season-related indexes │
│ + "CREATE INDEX IF NOT EXISTS idx_run_rankings_season ON run_rankings(season_id, │
│ ranking_type, ranking_scope, dungeon_id)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_best_runs_season ON player_best_runs(sea │
│ son_id, player_id)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_profiles_season ON player_profiles(seaso │
│ n_id, global_ranking)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_profiles_season_coverage ON player_profi │
│ les(season_id, has_complete_coverage, combined_best_time)", │
│ + } │
│ + for _, s := range stmts { │
│ + if _, err := db.Exec(s); err != nil { │
│ + // don't fail the connection on index creation errors │
│ + fmt.Printf("Warning: index creation failed: %v\n", err) │
│ + } │
│ + } │
│ + │
│ + fmt.Printf("[OK] All indexes ensured\n") │
│ + return nil │
│ } │
│ │
│ // migrateRealmsCompositeSlug upgrades the realms table from slug-unique to (regi │
│ on,slug)-unique if necessary. │
│ func migrateRealmsCompositeSlug(db *sql.DB) error { │
│ - // Inspect table SQL │
│ - var createSQL string │
│ - _ = db.QueryRow(`SELECT sql FROM sqlite_master WHERE type='table' AND name='r │
│ ealms'`).Scan(&createSQL) │
│ - // If table already created without UNIQUE on slug, nothing to do │
│ - if !strings.Contains(strings.ToLower(createSQL), "slug text unique") { │
│ - return nil │
│ - } │
│ - │
│ - fmt.Printf("[MIGRATE] Upgrading realms table to composite (region,slug) uniqu │
│ eness...\n") │
│ - tx, err := db.Begin() │
│ - if err != nil { return err } │
│ - defer tx.Rollback() │
│ - │
│ - // Create new table without UNIQUE on slug │
│ - if _, err := tx.Exec(` │
│ + // Inspect table SQL │
│ + var createSQL string │
│ + _ = db.QueryRow(`SELECT sql FROM sqlite_master WHERE type='table' AND name='real │
│ ms'`).Scan(&createSQL) │
│ + // If table already created without UNIQUE on slug, nothing to do │
│ + if !strings.Contains(strings.ToLower(createSQL), "slug text unique") { │
│ + return nil │
│ + } │
│ + │
│ + fmt.Printf("[MIGRATE] Upgrading realms table to composite (region,slug) uniquene │
│ ss...\n") │
│ + tx, err := db.Begin() │
│ + if err != nil { │
│ + return err │
│ + } │
│ + defer tx.Rollback() │
│ + │
│ + // Create new table without UNIQUE on slug │
│ + if _, err := tx.Exec(` │
│ CREATE TABLE IF NOT EXISTS realms_new ( │
│ id INTEGER PRIMARY KEY, │
│ slug TEXT, │
│ @@ -414,27 +422,37 @@ func migrateRealmsCompositeSlug(db *sql.DB) error { │
│ region TEXT, │
│ connected_realm_id INTEGER UNIQUE │
│ ) │
│ - `); err != nil { return fmt.Errorf("create realms_new: %w", err) } │
│ + `); err != nil { │
│ + return fmt.Errorf("create realms_new: %w", err) │
│ + } │
│ │
│ - // Copy data │
│ - if _, err := tx.Exec(`INSERT INTO realms_new (id, slug, name, region, connect │
│ ed_realm_id) │
│ + // Copy data │
│ + if _, err := tx.Exec(`INSERT INTO realms_new (id, slug, name, region, connected_ │
│ realm_id) │
│ SELECT id, slug, name, region, connected_realm_id FROM │
│ realms`); err != nil { │
│ - return fmt.Errorf("copy realms: %w", err) │
│ - } │
│ + return fmt.Errorf("copy realms: %w", err) │
│ + } │
│ │
│ - // Rename old and new │
│ - if _, err := tx.Exec(`ALTER TABLE realms RENAME TO realms_old`); err != nil { │
│ return fmt.Errorf("rename old: %w", err) } │
│ - if _, err := tx.Exec(`ALTER TABLE realms_new RENAME TO realms`); err != nil { │
│ return fmt.Errorf("rename new: %w", err) } │
│ + // Rename old and new │
│ + if _, err := tx.Exec(`ALTER TABLE realms RENAME TO realms_old`); err != nil { │
│ + return fmt.Errorf("rename old: %w", err) │
│ + } │
│ + if _, err := tx.Exec(`ALTER TABLE realms_new RENAME TO realms`); err != nil { │
│ + return fmt.Errorf("rename new: %w", err) │
│ + } │
│ │
│ - // Drop old │
│ - if _, err := tx.Exec(`DROP TABLE realms_old`); err != nil { return fmt.Errorf │
│ ("drop old: %w", err) } │
│ + // Drop old │
│ + if _, err := tx.Exec(`DROP TABLE realms_old`); err != nil { │
│ + return fmt.Errorf("drop old: %w", err) │
│ + } │
│ │
│ - // Ensure composite unique index │
│ - if _, err := tx.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slu │
│ g ON realms(region, slug)`); err != nil { │
│ - return fmt.Errorf("create composite unique index: %w", err) │
│ - } │
│ + // Ensure composite unique index │
│ + if _, err := tx.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_realms_region_slug O │
│ N realms(region, slug)`); err != nil { │
│ + return fmt.Errorf("create composite unique index: %w", err) │
│ + } │
│ │
│ - if err := tx.Commit(); err != nil { return err } │
│ - fmt.Printf("[OK] Realms table migrated\n") │
│ - return nil │
│ + if err := tx.Commit(); err != nil { │
│ + return err │
│ + } │
│ + fmt.Printf("[OK] Realms table migrated\n") │
│ + return nil │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...c/internal/database/client.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ database/client.go b/nix/pkgs/ookstats/src/i │
│ nternal/database/client.go │
│ index 010b398..cb9dcbd 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/databas │
│ e/client.go │
│ +++ b/nix/pkgs/ookstats/src/internal/databas │
│ e/client.go │
│ @@ -1,12 +1,12 @@ │
│ package database │
│ │
│ import ( │
│ - "database/sql" │
│ - "fmt" │
│ - "os" │
│ - "strings" │
│ + "database/sql" │
│ + "fmt" │
│ + "os" │
│ + "strings" │
│ │
│ - _ "github.com/tursodatabase/go-libsql" │
│ + _ "github.com/tursodatabase/go-libsql" │
│ ) │
│ │
│ // connect creates a local libSQL database │
│ connection │
│ @@ -14,66 +14,66 @@ var dbPathOverride strin │
│ g │
│ │
│ // SetDBPath allows callers (CLI) to overri │
│ de the local SQLite filename │
│ func SetDBPath(path string) { │
│ - dbPathOverride = path │
│ + dbPathOverride = path │
│ } │
│ │
│ // DBConnString returns the libsql connecti │
│ on string for the local SQLite file │
│ func DBConnString() string { │
│ - // Priority: explicit override -> env v │
│ ars -> default │
│ - if dbPathOverride != "" { │
│ - if strings.HasPrefix(dbPathOverride │
│ , "file:") { │
│ - return dbPathOverride │
│ - } │
│ - return "file:" + dbPathOverride │
│ - } │
│ - if v := os.Getenv("OOKSTATS_DB"); v != │
│ "" { │
│ - if strings.HasPrefix(v, "file:") { │
│ - return v │
│ - } │
│ - return "file:" + v │
│ - } │
│ - if v := os.Getenv("ASTRO_DATABASE_FILE" │
│ ); v != "" { │
│ - if strings.HasPrefix(v, "file:") { │
│ - return v │
│ - } │
│ - return "file:" + v │
│ - } │
│ - return "file:local.db" │
│ + // Priority: explicit override -> env vars │
│ -> default │
│ + if dbPathOverride != "" { │
│ + if strings.HasPrefix(dbPathOverride, "fil │
│ e:") { │
│ + return dbPathOverride │
│ + } │
│ + return "file:" + dbPathOverride │
│ + } │
│ + if v := os.Getenv("OOKSTATS_DB"); v != "" │
│ { │
│ + if strings.HasPrefix(v, "file:") { │
│ + return v │
│ + } │
│ + return "file:" + v │
│ + } │
│ + if v := os.Getenv("ASTRO_DATABASE_FILE"); │
│ v != "" { │
│ + if strings.HasPrefix(v, "file:") { │
│ + return v │
│ + } │
│ + return "file:" + v │
│ + } │
│ + return "file:local.db" │
│ } │
│ │
│ // DBFilePath returns the plain filesystem │
│ path for the local DB (without file: prefix) │
│ func DBFilePath() string { │
│ - conn := DBConnString() │
│ - if strings.HasPrefix(conn, "file:") { │
│ - return strings.TrimPrefix(conn, "fi │
│ le:") │
│ - } │
│ - return conn │
│ + conn := DBConnString() │
│ + if strings.HasPrefix(conn, "file:") { │
│ + return strings.TrimPrefix(conn, "file:") │
│ + } │
│ + return conn │
│ } │
│ │
│ func Connect() (*sql.DB, error) { │
│ - dsn := DBConnString() │
│ - fmt.Printf("Using local SQLite database │
│ : %s\n", dsn) │
│ - fmt.Printf("Opening database connection │
│ ...\n") │
│ - │
│ - db, err := sql.Open("libsql", dsn) │
│ - if err != nil { │
│ - return nil, fmt.Errorf("failed to o │
│ pen database: %w", err) │
│ - } │
│ - │
│ - fmt.Printf("Testing database connection │
│ ...\n") │
│ - if err := db.Ping(); err != nil { │
│ - db.Close() │
│ - return nil, fmt.Errorf("failed to p │
│ ing database: %w", err) │
│ - } │
│ - │
│ - // configure database for optimal perfo │
│ rmance │
│ - if err := configureDatabaseSettings(db, │
│ dsn); err != nil { │
│ - db.Close() │
│ - return nil, fmt.Errorf("failed to c │
│ onfigure database: %w", err) │
│ - } │
│ - │
│ - fmt.Printf("[OK] Local SQLite database │
│ connected\n") │
│ - return db, nil │
│ + dsn := DBConnString() │
│ + fmt.Printf("Using local SQLite database: % │
│ s\n", dsn) │
│ + fmt.Printf("Opening database connection... │
│ \n") │
│ + │
│ + db, err := sql.Open("libsql", dsn) │
│ + if err != nil { │
│ + return nil, fmt.Errorf("failed to open da │
│ tabase: %w", err) │
│ + } │
│ + │
│ + fmt.Printf("Testing database connection... │
│ \n") │
│ + if err := db.Ping(); err != nil { │
│ + db.Close() │
│ + return nil, fmt.Errorf("failed to ping da │
│ tabase: %w", err) │
│ + } │
│ + │
│ + // configure database for optimal performa │
│ nce │
│ + if err := configureDatabaseSettings(db, ds │
│ n); err != nil { │
│ + db.Close() │
│ + return nil, fmt.Errorf("failed to configu │
│ re database: %w", err) │
│ + } │
│ + │
│ + fmt.Printf("[OK] Local SQLite database con │
│ nected\n") │
│ + return db, nil │
│ } │
│ │
│ func getEnvOrFail(key string) string { │
│ @@ -105,10 +105,10 @@ func QuerySQL(db *sql. │
│ DB, query string, args ...any) (*sql.Rows, e │
│ rror) { │
│ │
│ // configureDatabaseSettings optimizes data │
│ base for performance │
│ func configureDatabaseSettings(db *sql.DB, │
│ dsn string) error { │
│ - // apply modest cache size for local SQ │
│ Lite file │
│ - if _, err := db.Exec("PRAGMA cache_size │
│ = -64000"); err != nil { │
│ - // ignore if not supported │
│ - } │
│ + // apply modest cache size for local SQLit │
│ e file │
│ + if _, err := db.Exec("PRAGMA cache_size = │
│ -64000"); err != nil { │
│ + // ignore if not supported │
│ + } │
│ │
│ // check journal mode │
│ var journalMode string │
│ @@ -124,7 +124,7 @@ func configureDatabaseSe │
│ ttings(db *sql.DB, dsn string) error { │
│ // EnsureCompleteSchema creates all require │
│ d tables and indexes for the ookstats databa │
│ se │
│ func EnsureCompleteSchema(db *sql.DB) error │
│ { │
│ fmt.Printf("Ensuring complete database sch │
│ ema...\n") │
│ - │
│ + │
│ // Create all tables first │
│ tables := []string{ │
│ // Reference tables │
│ @@ -135,16 +135,22 @@ func EnsureCompleteSch │
│ ema(db *sql.DB) error { │
│ map_id INTEGER, │
│ map_challenge_mode_id INTEGER UNIQUE │
│ )`, │
│ - │
│ - `CREATE TABLE IF NOT EXISTS realms │
│ ( │
│ + │
│ + `CREATE TABLE IF NOT EXISTS realms ( │
│ id INTEGER PRIMARY KEY, │
│ slug TEXT, │
│ name TEXT, │
│ region TEXT, │
│ connected_realm_id INTEGER UNIQ │
│ UE │
│ )`, │
│ - │
│ + │
│ + `CREATE TABLE IF NOT EXISTS realm_groups │
│ ( │
│ + child_realm_id INTEGER PRIMARY │
│ KEY, │
│ + parent_realm_id INTEGER NOT NUL │
│ L │
│ + )`, │
│ + │
│ // Core leaderboard data │
│ + │
│ `CREATE TABLE IF NOT EXISTS challenge_run │
│ s ( │
│ id INTEGER PRIMARY KEY, │
│ duration INTEGER, │
│ @@ -157,21 +163,21 @@ func EnsureCompleteSch │
│ ema(db *sql.DB) error { │
│ period_end_timestamp INTEGER, │
│ team_signature TEXT │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS players ( │
│ id INTEGER PRIMARY KEY, │
│ name TEXT, │
│ name_lower TEXT, │
│ realm_id INTEGER │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS run_members ( │
│ run_id INTEGER, │
│ player_id INTEGER, │
│ spec_id INTEGER, │
│ faction TEXT │
│ )`, │
│ - │
│ + │
│ // Player aggregation and rankings (seaso │
│ n-scoped) │
│ `CREATE TABLE IF NOT EXISTS player_profil │
│ es ( │
│ player_id INTEGER, │
│ @@ -193,7 +199,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ last_updated INTEGER, │
│ PRIMARY KEY (player_id, season_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_best_r │
│ uns ( │
│ player_id INTEGER, │
│ dungeon_id INTEGER, │
│ @@ -213,7 +219,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ completed_timestamp INTEGER, │
│ PRIMARY KEY (player_id, dungeon_id, seas │
│ on_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_rankin │
│ gs ( │
│ player_id INTEGER, │
│ ranking_type TEXT, │
│ @@ -237,7 +243,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ last_updated INTEGER, │
│ PRIMARY KEY (player_id, season_id) │
│ )`, │
│ - │
│ + │
│ // Extended player information │
│ `CREATE TABLE IF NOT EXISTS player_detail │
│ s ( │
│ player_id INTEGER PRIMARY KEY, │
│ @@ -256,7 +262,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ last_login_timestamp INTEGER, │
│ last_updated INTEGER │
│ )`, │
│ - │
│ + │
│ // Equipment system │
│ `CREATE TABLE IF NOT EXISTS player_equipm │
│ ent ( │
│ id INTEGER PRIMARY KEY, │
│ @@ -268,7 +274,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ item_name TEXT, │
│ snapshot_timestamp INTEGER │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS player_equipm │
│ ent_enchantments ( │
│ id INTEGER PRIMARY KEY, │
│ equipment_id INTEGER, │
│ @@ -280,7 +286,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ source_item_name TEXT, │
│ spell_id INTEGER │
│ )`, │
│ - │
│ + │
│ // Computed rankings │
│ `CREATE TABLE IF NOT EXISTS run_rankings │
│ ( │
│ run_id INTEGER, │
│ @@ -293,7 +299,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ computed_at INTEGER, │
│ PRIMARY KEY (run_id, ranking_type, ranki │
│ ng_scope, season_id) │
│ )`, │
│ - │
│ + │
│ // Metadata and items │
│ `CREATE TABLE IF NOT EXISTS api_fetch_met │
│ adata ( │
│ id INTEGER PRIMARY KEY, │
│ @@ -311,7 +317,7 @@ func EnsureCompleteSchem │
│ a(db *sql.DB) error { │
│ last_completed_ts INTEGER NOT NULL DEFAU │
│ LT 0, │
│ PRIMARY KEY (realm_slug, dungeon_id, per │
│ iod_id) │
│ )`, │
│ - │
│ + │
│ `CREATE TABLE IF NOT EXISTS items ( │
│ id INTEGER PRIMARY KEY, │
│ name TEXT, │
│ @@ -338,75 +344,77 @@ func EnsureCompleteSch │
│ ema(db *sql.DB) error { │
│ PRIMARY KEY (period_id, season_id) │
│ )`, │
│ } │
│ - │
│ + │
│ for _, table := range tables { │
│ if _, err := db.Exec(table); err != nil { │
│ return fmt.Errorf("failed to create tabl │
│ e: %w", err) │
│ } │
│ } │
│ - │
│ -fmt.Printf("[OK] All tables created\n") │
│ - │
│ - // Migrate realms schema if needed (ens │
│ ure (region, slug) composite uniqueness) │
│ - if err := migrateRealmsCompositeSlug(db │
│ ); err != nil { │
│ - return err │
│ - } │
│ - │
│ - // Create indexes │
│ - return ensureRecommendedIndexes(db) │
│ + │
│ + fmt.Printf("[OK] All tables created\n") │
│ + │
│ + // Migrate realms schema if needed (ensure │
│ (region, slug) composite uniqueness) │
│ + if err := migrateRealmsCompositeSlug(db); │
│ err != nil { │
│ + return err │
│ + } │
│ + │
│ + // Create indexes │
│ + return ensureRecommendedIndexes(db) │
│ } │
│ │
│ // ensureRecommendedIndexes creates indexes │
│ used by hot paths if missing │
│ func ensureRecommendedIndexes(db *sql.DB) e │
│ rror { │
│ - stmts := []string{ │
│ - // Ensure composite uniqueness for │
│ realms │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS │
│ idx_realms_region_slug ON realms(region, slu │
│ g)", │
│ - // Fast path for high-water checks │
│ - "CREATE INDEX IF NOT EXISTS idx_run │
│ s_realm_dungeon_ct ON challenge_runs(realm_i │
│ d, dungeon_id, completed_timestamp)", │
│ - // Uniqueness key to avoid duplicat │
│ es │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS │
│ idx_runs_unique ON challenge_runs(completed_ │
│ timestamp, dungeon_id, duration, realm_id, t │
│ eam_signature)", │
│ - // Lookups used elsewhere │
│ - "CREATE INDEX IF NOT EXISTS idx_pla │
│ yers_name_lower ON players(name_lower)", │
│ - "CREATE UNIQUE INDEX IF NOT EXISTS │
│ idx_run_members_pair ON run_members(run_id, │
│ player_id)", │
│ - // Speed up canonical run selection │
│ : partition/order by team per dungeon │
│ - "CREATE INDEX IF NOT EXISTS idx_run │
│ s_dungeon_team_duration ON challenge_runs(du │
│ ngeon_id, team_signature, duration, complete │
│ d_timestamp, id)", │
│ - // Additional indexes for performan │
│ ce │
│ - "CREATE INDEX IF NOT EXISTS idx_run │
│ _members_player_id ON run_members(player_id) │
│ ", │
│ - "CREATE INDEX IF NOT EXISTS idx_cha │
│ llenge_runs_dungeon_duration ON challenge_ru │
│ ns(dungeon_id, duration)", │
│ - // Season-related indexes │
│ - "CREATE INDEX IF NOT EXISTS idx_run │
│ _rankings_season ON run_rankings(season_id, │
│ ranking_type, ranking_scope, dungeon_id)", │
│ - "CREATE INDEX IF NOT EXISTS idx_pla │
│ yer_best_runs_season ON player_best_runs(sea │
│ son_id, player_id)", │
│ - "CREATE INDEX IF NOT EXISTS idx_pla │
│ yer_profiles_season ON player_profiles(seaso │
│ n_id, global_ranking)", │
│ - "CREATE INDEX IF NOT EXISTS idx_pla │
│ yer_profiles_season_coverage ON player_profi │
│ les(season_id, has_complete_coverage, combin │
│ ed_best_time)", │
│ - } │
│ - for _, s := range stmts { │
│ - if _, err := db.Exec(s); err != nil │
│ { │
│ - // don't fail the connection on │
│ index creation errors │
│ - fmt.Printf("Warning: index crea │
│ tion failed: %v\n", err) │
│ - } │
│ - } │
│ - │
│ - fmt.Printf("[OK] All indexes ensured\n" │
│ ) │
│ - return nil │
│ + stmts := []string{ │
│ + // Ensure composite uniqueness for realms │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_re │
│ alms_region_slug ON realms(region, slug)", │
│ + // Fast path for high-water checks │
│ + "CREATE INDEX IF NOT EXISTS idx_runs_real │
│ m_dungeon_ct ON challenge_runs(realm_id, dun │
│ geon_id, completed_timestamp)", │
│ + // Uniqueness key to avoid duplicates │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_ru │
│ ns_unique ON challenge_runs(completed_timest │
│ amp, dungeon_id, duration, realm_id, team_si │
│ gnature)", │
│ + // Lookups used elsewhere │
│ + "CREATE INDEX IF NOT EXISTS idx_players_n │
│ ame_lower ON players(name_lower)", │
│ + "CREATE UNIQUE INDEX IF NOT EXISTS idx_ru │
│ n_members_pair ON run_members(run_id, player │
│ _id)", │
│ + // Speed up canonical run selection: part │
│ ition/order by team per dungeon │
│ + "CREATE INDEX IF NOT EXISTS idx_runs_dung │
│ eon_team_duration ON challenge_runs(dungeon_ │
│ id, team_signature, duration, completed_time │
│ stamp, id)", │
│ + // Additional indexes for performance │
│ + "CREATE INDEX IF NOT EXISTS idx_run_membe │
│ rs_player_id ON run_members(player_id)", │
│ + "CREATE INDEX IF NOT EXISTS idx_challenge │
│ _runs_dungeon_duration ON challenge_runs(dun │
│ geon_id, duration)", │
│ + // Season-related indexes │
│ + "CREATE INDEX IF NOT EXISTS idx_run_ranki │
│ ngs_season ON run_rankings(season_id, rankin │
│ g_type, ranking_scope, dungeon_id)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_be │
│ st_runs_season ON player_best_runs(season_id │
│ , player_id)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_pr │
│ ofiles_season ON player_profiles(season_id, │
│ global_ranking)", │
│ + "CREATE INDEX IF NOT EXISTS idx_player_pr │
│ ofiles_season_coverage ON player_profiles(se │
│ ason_id, has_complete_coverage, combined_bes │
│ t_time)", │
│ + } │
│ + for _, s := range stmts { │
│ + if _, err := db.Exec(s); err != nil { │
│ + // don't fail the connection on index cr │
│ eation errors │
│ + fmt.Printf("Warning: index creation fail │
│ ed: %v\n", err) │
│ + } │
│ + } │
│ + │
│ + fmt.Printf("[OK] All indexes ensured\n") │
│ + return nil │
│ } │
│ │
│ // migrateRealmsCompositeSlug upgrades the │
│ realms table from slug-unique to (region,slu │
│ g)-unique if necessary. │
│ func migrateRealmsCompositeSlug(db *sql.DB) │
│ error { │
│ - // Inspect table SQL │
│ - var createSQL string │
│ - _ = db.QueryRow(`SELECT sql FROM sqlite │
│ _master WHERE type='table' AND name='realms' │
│ `).Scan(&createSQL) │
│ - // If table already created without UNI │
│ QUE on slug, nothing to do │
│ - if !strings.Contains(strings.ToLower(cr │
│ eateSQL), "slug text unique") { │
│ - return nil │
│ - } │
│ - │
│ - fmt.Printf("[MIGRATE] Upgrading realms │
│ table to composite (region,slug) uniqueness. │
│ ..\n") │
│ - tx, err := db.Begin() │
│ - if err != nil { return err } │
│ - defer tx.Rollback() │
│ - │
│ - // Create new table without UNIQUE on s │
│ lug │
│ - if _, err := tx.Exec(` │
│ + // Inspect table SQL │
│ + var createSQL string │
│ + _ = db.QueryRow(`SELECT sql FROM sqlite_ma │
│ ster WHERE type='table' AND name='realms'`). │
│ Scan(&createSQL) │
│ + // If table already created without UNIQUE │
│ on slug, nothing to do │
│ + if !strings.Contains(strings.ToLower(creat │
│ eSQL), "slug text unique") { │
│ + return nil │
│ + } │
│ + │
│ + fmt.Printf("[MIGRATE] Upgrading realms tab │
│ le to composite (region,slug) uniqueness...\ │
│ n") │
│ + tx, err := db.Begin() │
│ + if err != nil { │
│ + return err │
│ + } │
│ + defer tx.Rollback() │
│ + │
│ + // Create new table without UNIQUE on slug │
│ + if _, err := tx.Exec(` │
│ CREATE TABLE IF NOT EXISTS realms_n │
│ ew ( │
│ id INTEGER PRIMARY KEY, │
│ slug TEXT, │
│ @@ -414,27 +422,37 @@ func migrateRealmsComp │
│ ositeSlug(db *sql.DB) error { │
│ region TEXT, │
│ connected_realm_id INTEGER UNIQ │
│ UE │
│ ) │
│ - `); err != nil { return fmt.Errorf("cre │
│ ate realms_new: %w", err) } │
│ + `); err != nil { │
│ + return fmt.Errorf("create realms_new: %w" │
│ , err) │
│ + } │
│ │
│ - // Copy data │
│ - if _, err := tx.Exec(`INSERT INTO realm │
│ s_new (id, slug, name, region, connected_rea │
│ lm_id) │
│ + // Copy data │
│ + if _, err := tx.Exec(`INSERT INTO realms_n │
│ ew (id, slug, name, region, connected_realm_ │
│ id) │
│ SELECT id, slug, │
│ name, region, connected_realm_id FROM realms │
│ `); err != nil { │
│ - return fmt.Errorf("copy realms: %w" │
│ , err) │
│ - } │
│ + return fmt.Errorf("copy realms: %w", err) │
│ + } │
│ │
│ - // Rename old and new │
│ - if _, err := tx.Exec(`ALTER TABLE realm │
│ s RENAME TO realms_old`); err != nil { retur │
│ n fmt.Errorf("rename old: %w", err) } │
│ - if _, err := tx.Exec(`ALTER TABLE realm │
│ s_new RENAME TO realms`); err != nil { retur │
│ n fmt.Errorf("rename new: %w", err) } │
│ + // Rename old and new │
│ + if _, err := tx.Exec(`ALTER TABLE realms R │
│ ENAME TO realms_old`); err != nil { │
│ + return fmt.Errorf("rename old: %w", err) │
│ + } │
│ + if _, err := tx.Exec(`ALTER TABLE realms_n │
│ ew RENAME TO realms`); err != nil { │
│ + return fmt.Errorf("rename new: %w", err) │
│ + } │
│ │
│ - // Drop old │
│ - if _, err := tx.Exec(`DROP TABLE realms │
│ _old`); err != nil { return fmt.Errorf("drop │
│ old: %w", err) } │
│ + // Drop old │
│ + if _, err := tx.Exec(`DROP TABLE realms_ol │
│ d`); err != nil { │
│ + return fmt.Errorf("drop old: %w", err) │
│ + } │
│ │
│ - // Ensure composite unique index │
│ - if _, err := tx.Exec(`CREATE UNIQUE IND │
│ EX IF NOT EXISTS idx_realms_region_slug ON r │
│ ealms(region, slug)`); err != nil { │
│ - return fmt.Errorf("create composite │
│ unique index: %w", err) │
│ - } │
│ + // Ensure composite unique index │
│ + if _, err := tx.Exec(`CREATE UNIQUE INDEX │
│ IF NOT EXISTS idx_realms_region_slug ON real │
│ ms(region, slug)`); err != nil { │
│ + return fmt.Errorf("create composite uniqu │
│ e index: %w", err) │
│ + } │
│ │
│ - if err := tx.Commit(); err != nil { ret │
│ urn err } │
│ - fmt.Printf("[OK] Realms table migrated\ │
│ n") │
│ - return nil │
│ + if err := tx.Commit(); err != nil { │
│ + return err │
│ + } │
│ + fmt.Printf("[OK] Realms table migrated\n") │
│ + return nil │
│ } │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/ookstats/src/internal/generator/player_leaderboards.go ──────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/generator/player_leaderboards.go b/nix │
│ /pkgs/ookstats/src/internal/generator/player_leaderboards.go │
│ index 7b0b576..557b859 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generator/player_leaderboards.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generator/player_leaderboards.go │
│ @@ -3,11 +3,12 @@ package generator │
│ import ( │
│ "database/sql" │
│ "fmt" │
│ - "ookstats/internal/utils" │
│ + "ookstats/internal/realms" │
│ "ookstats/internal/wow" │
│ "ookstats/internal/writer" │
│ "os" │
│ "path/filepath" │
│ + "sort" │
│ "strings" │
│ "time" │
│ ) │
│ @@ -179,61 +180,65 @@ func generateRealmPlayerLeaderboards(db *sql.DB, out, region │
│ string, pageSize in │
│ } │
│ defer rrows.Close() │
│ │
│ - var slugs []string │
│ + parentSet := make(map[string]struct{}) │
│ for rrows.Next() { │
│ - var s string │
│ - if err := rrows.Scan(&s); err != nil { │
│ + var slug string │
│ + if err := rrows.Scan(&slug); err != nil { │
│ return err │
│ } │
│ - slugs = append(slugs, s) │
│ + parent := realms.EffectiveSlug(region, slug) │
│ + if parent == "" { │
│ + parent = slug │
│ + } │
│ + parentSet[parent] = struct{}{} │
│ } │
│ │
│ - groups := groupRealmSlugs(region, slugs) │
│ - if len(groups) == 0 { │
│ + var parents []string │
│ + for slug := range parentSet { │
│ + parents = append(parents, slug) │
│ + } │
│ + if len(parents) == 0 { │
│ return nil │
│ } │
│ + // keep deterministic order │
│ + sort.Strings(parents) │
│ │
│ - for _, group := range groups { │
│ - if len(group.Slugs) == 0 { │
│ - continue │
│ - } │
│ - dir := filepath.Join(out, "players", "realm", region, group.Parent) │
│ + for _, parentSlug := range parents { │
│ + dir := filepath.Join(out, "players", "realm", region, parentSlug) │
│ if err := os.MkdirAll(dir, 0o755); err != nil { │
│ return err │
│ } │
│ │
│ - placeholder := makeSQLPlaceholders(len(group.Slugs)) │
│ - baseArgs := append([]interface{}{seasonID, region}, stringSliceToInterface(grou │
│ p.Slugs)...) │
│ - │
│ var total int │
│ - countQuery := fmt.Sprintf(` │
│ + if err := db.QueryRow(` │
│ SELECT COUNT(*) │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ - WHERE pp.season_id = ? AND r.region = ? AND r.slug IN (%s) AND pp.has_complete │
│ _coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ - `, placeholder) │
│ - if err := db.QueryRow(countQuery, baseArgs...).Scan(&total); err != nil { │
│ + JOIN realms parent ON pp.realm_id = parent.id │
│ + WHERE pp.season_id = ? AND parent.region = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ + `, seasonID, region, parentSlug).Scan(&total); err != nil { │
│ return fmt.Errorf("players total (realm, season %d): %w", seasonID, err) │
│ } │
│ │
│ pages := (total + pageSize - 1) / pageSize │
│ for p := 1; p <= pages; p++ { │
│ offset := (p - 1) * pageSize │
│ - dataArgs := append(append([]interface{}{}, baseArgs...), pageSize, offset) │
│ - rows, err := db.Query(fmt.Sprintf(` │
│ + rows, err := db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.region, │
│ COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_ │
│ spec_id, │
│ pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ COALESCE(pp.realm_ranking_bracket, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ + JOIN realms parent ON pp.realm_id = parent.id │
│ LEFT JOIN player_details pd ON p.id = pd.player_id │
│ - WHERE pp.season_id = ? AND r.region = ? AND r.slug IN (%s) AND pp.has_complet │
│ e_coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ + WHERE pp.season_id = ? AND parent.region = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.name ASC │
│ LIMIT ? OFFSET ? │
│ - `, placeholder), dataArgs...) │
│ + `, seasonID, region, parentSlug, pageSize, offset) │
│ if err != nil { │
│ return err │
│ } │
│ @@ -243,15 +248,15 @@ func generateRealmPlayerLeaderboards(db *sql.DB, out, region │
│ string, pageSize in │
│ return err │
│ } │
│ │
│ - applyPercentileBrackets(list, offset, total) │
│ + title := strings.ToUpper(region) + "/" + parentSlug + " Player Rankings" │
│ │
│ - title := strings.ToUpper(region) + "/" + group.Parent + " Player Rankings" │
│ page := buildPlayerLeaderboardPage(list, title, total, pages, p, pageSize) │
│ if err := writer.WriteJSONFile(filepath.Join(dir, fmt.Sprintf("%d.json", p)), │
│ page); err != nil { │
│ return err │
│ } │
│ } │
│ } │
│ + │
│ return nil │
│ } │
│ │
│ @@ -287,7 +292,7 @@ func generateClassPlayerLeaderboards(db *sql.DB, out, classKey │
│ string, pageSize │
│ │
│ seenParents := make(map[string]struct{}) │
│ for _, rslug := range slugs { │
│ - parentSlug := effectiveRealmSlug(reg, rslug) │
│ + parentSlug := realms.EffectiveSlug(reg, rslug) │
│ if parentSlug == "" { │
│ parentSlug = rslug │
│ } │
│ @@ -312,7 +317,7 @@ func generateClassScope(db *sql.DB, out, scope, region, realmS │
│ lug, classKey stri │
│ } else if scope == "regional" { │
│ dir = filepath.Join(out, "players", "class", classKey, "regional", region) │
│ } else { │
│ - effectiveSlug := effectiveRealmSlug(region, realmSlug) │
│ + effectiveSlug := realms.EffectiveSlug(region, realmSlug) │
│ if effectiveSlug == "" { │
│ effectiveSlug = realmSlug │
│ } │
│ @@ -326,58 +331,49 @@ func generateClassScope(db *sql.DB, out, scope, region, real │
│ mSlug, classKey stri │
│ // Fetch ALL players for this season, then filter by class in Go (to handle fall │
│ back logic) │
│ var rows *sql.Rows │
│ var err error │
│ - var bracketColumn string │
│ if scope == "global" { │
│ - bracketColumn = "pp.global_ranking_bracket" │
│ rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.region, │
│ - COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_spec │
│ _id, │
│ - pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ - COALESCE(pp.global_ranking_bracket, '') │
│ + COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_s │
│ pec_id, │
│ + pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ + COALESCE(pp.global_ranking_bracket, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ LEFT JOIN player_details pd ON p.id = pd.player_id │
│ WHERE pp.season_id = ? AND pp.has_complete_coverage = 1 AND pp.combined_best_t │
│ ime IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.name ASC │
│ `, seasonID) │
│ } else if scope == "regional" { │
│ - bracketColumn = "pp.regional_ranking_bracket" │
│ rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.region, │
│ - COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_spec │
│ _id, │
│ - pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ - COALESCE(pp.regional_ranking_bracket, '') │
│ + COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_s │
│ pec_id, │
│ + pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ + COALESCE(pp.regional_ranking_bracket, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ LEFT JOIN player_details pd ON p.id = pd.player_id │
│ WHERE pp.season_id = ? AND r.region = ? AND pp.has_complete_coverage = 1 AND p │
│ p.combined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.name ASC │
│ `, seasonID, region) │
│ } else { │
│ - bracketColumn = "pp.realm_ranking_bracket" │
│ - realmSlugs := realmGroupSlugs(region, realmSlug) │
│ - if len(realmSlugs) == 0 { │
│ - realmSlugs = []string{realmSlug} │
│ - } │
│ - placeholder := makeSQLPlaceholders(len(realmSlugs)) │
│ - args := append([]interface{}{seasonID, region}, stringSliceToInterface(realmSlu │
│ gs)...) │
│ - rows, err = db.Query(fmt.Sprintf(` │
│ + rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.region, │
│ COALESCE(pd.class_name,''), COALESCE(pd.active_spec_name,''), pp.main_s │
│ pec_id, │
│ pp.combined_best_time, pp.dungeons_completed, pp.total_runs, │
│ COALESCE(pp.realm_ranking_bracket, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.player_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ + JOIN realms parent ON pp.realm_id = parent.id │
│ LEFT JOIN player_details pd ON p.id = pd.player_id │
│ - WHERE pp.season_id = ? AND r.region = ? AND r.slug IN (%s) AND pp.has_complete │
│ _coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ + WHERE pp.season_id = ? AND parent.region = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND pp.combined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.name ASC │
│ - `, placeholder), args...) │
│ + `, seasonID, region, realmSlug) │
│ } │
│ │
│ - _ = bracketColumn // unused for now, but documents intent │
│ if err != nil { │
│ return err │
│ } │
│ @@ -459,10 +455,6 @@ func generateClassScope(db *sql.DB, out, scope, region, realm │
│ Slug, classKey stri │
│ list = append(list, obj) │
│ } │
│ │
│ - if scope == "realm" { │
│ - applyPercentileBrackets(list, offset, total) │
│ - } │
│ - │
│ title := "Global Player Rankings" │
│ if scope == "regional" { │
│ title = strings.ToUpper(region) + " Player Rankings" │
│ @@ -553,20 +545,11 @@ func buildPlayerLeaderboardPage(leaderboard []map[string]any │
│ , title string, tota │
│ } │
│ } │
│ │
│ +// applyPercentileBrackets is left in place for compatibility with older builds t │
│ hat expect │
│ +// client-side recalculation. The new pipeline already emits normalized brackets, │
│ so this │
│ +// helper is effectively a no-op; it simply preserves any existing value on the e │
│ ntry. │
│ func applyPercentileBrackets(entries []map[string]any, offset int, total int) { │
│ - if total <= 0 { │
│ - return │
│ - } │
│ - for i, entry := range entries { │
│ - rank := offset + i + 1 │
│ - if rank <= 0 { │
│ - continue │
│ - } │
│ - bracket := utils.CalculatePercentileBracket(rank, total) │
│ - if bracket == "" { │
│ - delete(entry, "ranking_percentile") │
│ - } else { │
│ - entry["ranking_percentile"] = bracket │
│ - } │
│ - } │
│ + _ = offset │
│ + _ = total │
│ + // nothing to do; the database is already normalized │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...erator/player_leaderboards.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ generator/player_leaderboards.go b/nix/pkgs/ │
│ ookstats/src/internal/generator/player_leade │
│ rboards.go │
│ index 7b0b576..557b859 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generat │
│ or/player_leaderboards.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generat │
│ or/player_leaderboards.go │
│ @@ -3,11 +3,12 @@ package generator │
│ import ( │
│ "database/sql" │
│ "fmt" │
│ - "ookstats/internal/utils" │
│ + "ookstats/internal/realms" │
│ "ookstats/internal/wow" │
│ "ookstats/internal/writer" │
│ "os" │
│ "path/filepath" │
│ + "sort" │
│ "strings" │
│ "time" │
│ ) │
│ @@ -179,61 +180,65 @@ func generateRealmPlay │
│ erLeaderboards(db *sql.DB, out, region strin │
│ g, pageSize in │
│ } │
│ defer rrows.Close() │
│ │
│ - var slugs []string │
│ + parentSet := make(map[string]struct{}) │
│ for rrows.Next() { │
│ - var s string │
│ - if err := rrows.Scan(&s); err != nil { │
│ + var slug string │
│ + if err := rrows.Scan(&slug); err != nil { │
│ return err │
│ } │
│ - slugs = append(slugs, s) │
│ + parent := realms.EffectiveSlug(region, sl │
│ ug) │
│ + if parent == "" { │
│ + parent = slug │
│ + } │
│ + parentSet[parent] = struct{}{} │
│ } │
│ │
│ - groups := groupRealmSlugs(region, slugs) │
│ - if len(groups) == 0 { │
│ + var parents []string │
│ + for slug := range parentSet { │
│ + parents = append(parents, slug) │
│ + } │
│ + if len(parents) == 0 { │
│ return nil │
│ } │
│ + // keep deterministic order │
│ + sort.Strings(parents) │
│ │
│ - for _, group := range groups { │
│ - if len(group.Slugs) == 0 { │
│ - continue │
│ - } │
│ - dir := filepath.Join(out, "players", "rea │
│ lm", region, group.Parent) │
│ + for _, parentSlug := range parents { │
│ + dir := filepath.Join(out, "players", "rea │
│ lm", region, parentSlug) │
│ if err := os.MkdirAll(dir, 0o755); err != │
│ nil { │
│ return err │
│ } │
│ │
│ - placeholder := makeSQLPlaceholders(len(gr │
│ oup.Slugs)) │
│ - baseArgs := append([]interface{}{seasonID │
│ , region}, stringSliceToInterface(group.Slug │
│ s)...) │
│ - │
│ var total int │
│ - countQuery := fmt.Sprintf(` │
│ + if err := db.QueryRow(` │
│ SELECT COUNT(*) │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.pla │
│ yer_id │
│ - WHERE pp.season_id = ? AND r.region = ? │
│ AND r.slug IN (%s) AND pp.has_complete_cover │
│ age = 1 AND pp.combined_best_time IS NOT NUL │
│ L │
│ - `, placeholder) │
│ - if err := db.QueryRow(countQuery, baseArg │
│ s...).Scan(&total); err != nil { │
│ + JOIN realms parent ON pp.realm_id = pare │
│ nt.id │
│ + WHERE pp.season_id = ? AND parent.region │
│ = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND p │
│ p.combined_best_time IS NOT NULL │
│ + `, seasonID, region, parentSlug).Scan(&to │
│ tal); err != nil { │
│ return fmt.Errorf("players total (realm, │
│ season %d): %w", seasonID, err) │
│ } │
│ │
│ pages := (total + pageSize - 1) / pageSiz │
│ e │
│ for p := 1; p <= pages; p++ { │
│ offset := (p - 1) * pageSize │
│ - dataArgs := append(append([]interface{}{ │
│ }, baseArgs...), pageSize, offset) │
│ - rows, err := db.Query(fmt.Sprintf(` │
│ + rows, err := db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r. │
│ region, │
│ COALESCE(pd.class_name,''), COAL │
│ ESCE(pd.active_spec_name,''), pp.main_spec_i │
│ d, │
│ pp.combined_best_time, pp.dungeo │
│ ns_completed, pp.total_runs, │
│ COALESCE(pp.realm_ranking_bracke │
│ t, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.pl │
│ ayer_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ + JOIN realms parent ON pp.realm_id = par │
│ ent.id │
│ LEFT JOIN player_details pd ON p.id = p │
│ d.player_id │
│ - WHERE pp.season_id = ? AND r.region = ? │
│ AND r.slug IN (%s) AND pp.has_complete_cove │
│ rage = 1 AND pp.combined_best_time IS NOT NU │
│ LL │
│ + WHERE pp.season_id = ? AND parent.regio │
│ n = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND │
│ pp.combined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.n │
│ ame ASC │
│ LIMIT ? OFFSET ? │
│ - `, placeholder), dataArgs...) │
│ + `, seasonID, region, parentSlug, pageSiz │
│ e, offset) │
│ if err != nil { │
│ return err │
│ } │
│ @@ -243,15 +248,15 @@ func generateRealmPlay │
│ erLeaderboards(db *sql.DB, out, region strin │
│ g, pageSize in │
│ return err │
│ } │
│ │
│ - applyPercentileBrackets(list, offset, to │
│ tal) │
│ + title := strings.ToUpper(region) + "/" + │
│ parentSlug + " Player Rankings" │
│ │
│ - title := strings.ToUpper(region) + "/" + │
│ group.Parent + " Player Rankings" │
│ page := buildPlayerLeaderboardPage(list, │
│ title, total, pages, p, pageSize) │
│ if err := writer.WriteJSONFile(filepath. │
│ Join(dir, fmt.Sprintf("%d.json", p)), page); │
│ err != nil { │
│ return err │
│ } │
│ } │
│ } │
│ + │
│ return nil │
│ } │
│ │
│ @@ -287,7 +292,7 @@ func generateClassPlayer │
│ Leaderboards(db *sql.DB, out, classKey strin │
│ g, pageSize │
│ │
│ seenParents := make(map[string]struct{}) │
│ for _, rslug := range slugs { │
│ - parentSlug := effectiveRealmSlug(reg, rs │
│ lug) │
│ + parentSlug := realms.EffectiveSlug(reg, │
│ rslug) │
│ if parentSlug == "" { │
│ parentSlug = rslug │
│ } │
│ @@ -312,7 +317,7 @@ func generateClassScope( │
│ db *sql.DB, out, scope, region, realmSlug, c │
│ lassKey stri │
│ } else if scope == "regional" { │
│ dir = filepath.Join(out, "players", "clas │
│ s", classKey, "regional", region) │
│ } else { │
│ - effectiveSlug := effectiveRealmSlug(regio │
│ n, realmSlug) │
│ + effectiveSlug := realms.EffectiveSlug(reg │
│ ion, realmSlug) │
│ if effectiveSlug == "" { │
│ effectiveSlug = realmSlug │
│ } │
│ @@ -326,58 +331,49 @@ func generateClassScop │
│ e(db *sql.DB, out, scope, region, realmSlug, │
│ classKey stri │
│ // Fetch ALL players for this season, then │
│ filter by class in Go (to handle fallback l │
│ ogic) │
│ var rows *sql.Rows │
│ var err error │
│ - var bracketColumn string │
│ if scope == "global" { │
│ - bracketColumn = "pp.global_ranking_bracke │
│ t" │
│ rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.r │
│ egion, │
│ - COALESCE(pd.class_name,''), COALESCE │
│ (pd.active_spec_name,''), pp.main_spec_id, │
│ - pp.combined_best_time, pp.dungeons_c │
│ ompleted, pp.total_runs, │
│ - COALESCE(pp.global_ranking_bracket, │
│ '') │
│ + COALESCE(pd.class_name,''), COALE │
│ SCE(pd.active_spec_name,''), pp.main_spec_id │
│ , │
│ + pp.combined_best_time, pp.dungeon │
│ s_completed, pp.total_runs, │
│ + COALESCE(pp.global_ranking_bracke │
│ t, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.pla │
│ yer_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ LEFT JOIN player_details pd ON p.id = pd │
│ .player_id │
│ WHERE pp.season_id = ? AND pp.has_comple │
│ te_coverage = 1 AND pp.combined_best_time IS │
│ NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.na │
│ me ASC │
│ `, seasonID) │
│ } else if scope == "regional" { │
│ - bracketColumn = "pp.regional_ranking_brac │
│ ket" │
│ rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.r │
│ egion, │
│ - COALESCE(pd.class_name,''), COALESCE │
│ (pd.active_spec_name,''), pp.main_spec_id, │
│ - pp.combined_best_time, pp.dungeons_c │
│ ompleted, pp.total_runs, │
│ - COALESCE(pp.regional_ranking_bracket │
│ , '') │
│ + COALESCE(pd.class_name,''), COALE │
│ SCE(pd.active_spec_name,''), pp.main_spec_id │
│ , │
│ + pp.combined_best_time, pp.dungeon │
│ s_completed, pp.total_runs, │
│ + COALESCE(pp.regional_ranking_brac │
│ ket, '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.pla │
│ yer_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ LEFT JOIN player_details pd ON p.id = pd │
│ .player_id │
│ WHERE pp.season_id = ? AND r.region = ? │
│ AND pp.has_complete_coverage = 1 AND pp.comb │
│ ined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.na │
│ me ASC │
│ `, seasonID, region) │
│ } else { │
│ - bracketColumn = "pp.realm_ranking_bracket │
│ " │
│ - realmSlugs := realmGroupSlugs(region, rea │
│ lmSlug) │
│ - if len(realmSlugs) == 0 { │
│ - realmSlugs = []string{realmSlug} │
│ - } │
│ - placeholder := makeSQLPlaceholders(len(re │
│ almSlugs)) │
│ - args := append([]interface{}{seasonID, re │
│ gion}, stringSliceToInterface(realmSlugs)... │
│ ) │
│ - rows, err = db.Query(fmt.Sprintf(` │
│ + rows, err = db.Query(` │
│ SELECT p.id, p.name, r.slug, r.name, r.r │
│ egion, │
│ COALESCE(pd.class_name,''), COALE │
│ SCE(pd.active_spec_name,''), pp.main_spec_id │
│ , │
│ pp.combined_best_time, pp.dungeon │
│ s_completed, pp.total_runs, │
│ COALESCE(pp.realm_ranking_bracket │
│ , '') │
│ FROM players p │
│ - JOIN realms r ON p.realm_id = r.id │
│ JOIN player_profiles pp ON p.id = pp.pla │
│ yer_id │
│ + JOIN realms r ON p.realm_id = r.id │
│ + JOIN realms parent ON pp.realm_id = pare │
│ nt.id │
│ LEFT JOIN player_details pd ON p.id = pd │
│ .player_id │
│ - WHERE pp.season_id = ? AND r.region = ? │
│ AND r.slug IN (%s) AND pp.has_complete_cover │
│ age = 1 AND pp.combined_best_time IS NOT NUL │
│ L │
│ + WHERE pp.season_id = ? AND parent.region │
│ = ? AND parent.slug = ? │
│ + AND pp.has_complete_coverage = 1 AND p │
│ p.combined_best_time IS NOT NULL │
│ ORDER BY pp.combined_best_time ASC, p.na │
│ me ASC │
│ - `, placeholder), args...) │
│ + `, seasonID, region, realmSlug) │
│ } │
│ │
│ - _ = bracketColumn // unused for now, but d │
│ ocuments intent │
│ if err != nil { │
│ return err │
│ } │
│ @@ -459,10 +455,6 @@ func generateClassScope │
│ (db *sql.DB, out, scope, region, realmSlug, │
│ classKey stri │
│ list = append(list, obj) │
│ } │
│ │
│ - if scope == "realm" { │
│ - applyPercentileBrackets(list, offset, to │
│ tal) │
│ - } │
│ - │
│ title := "Global Player Rankings" │
│ if scope == "regional" { │
│ title = strings.ToUpper(region) + " Play │
│ er Rankings" │
│ @@ -553,20 +545,11 @@ func buildPlayerLeader │
│ boardPage(leaderboard []map[string]any, titl │
│ e string, tota │
│ } │
│ } │
│ │
│ +// applyPercentileBrackets is left in place │
│ for compatibility with older builds that ex │
│ pect │
│ +// client-side recalculation. The new pipel │
│ ine already emits normalized brackets, so th │
│ is │
│ +// helper is effectively a no-op; it simply │
│ preserves any existing value on the entry. │
│ func applyPercentileBrackets(entries []map[ │
│ string]any, offset int, total int) { │
│ - if total <= 0 { │
│ - return │
│ - } │
│ - for i, entry := range entries { │
│ - rank := offset + i + 1 │
│ - if rank <= 0 { │
│ - continue │
│ - } │
│ - bracket := utils.CalculatePercentileBrack │
│ et(rank, total) │
│ - if bracket == "" { │
│ - delete(entry, "ranking_percentile") │
│ - } else { │
│ - entry["ranking_percentile"] = bracket │
│ - } │
│ - } │
│ + _ = offset │
│ + _ = total │
│ + // nothing to do; the database is already │
│ normalized │
│ } │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/ookstats/src/internal/generator/realm_aliases.go ────────────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/generator/realm_aliases.go b/nix/pkgs/ │
│ ookstats/src/internal/generator/realm_aliases.go │
│ index 1bd4ac8..cc1b290 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generator/realm_aliases.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generator/realm_aliases.go │
│ @@ -1,151 +1 @@ │
│ package generator │
│ - │
│ -import "strings" │
│ - │
│ -// mergedRealmParents maps child realm slugs to their parent leaderboard realm pe │
│ r region. │
│ -var mergedRealmParents = map[string]map[string]string{ │
│ - "us": { │
│ - "nazgrim": "pagle", │
│ - "galakras": "pagle", │
│ - "raden": "pagle", │
│ - "ra-den": "pagle", │
│ - "lei-shen": "pagle", │
│ - "leishen": "pagle", │
│ - "immerseus": "pagle", │
│ - }, │
│ - "eu": { │
│ - "shekzeer": "mirage-raceway", │
│ - "garalon": "mirage-raceway", │
│ - "norushen": "mirage-raceway", │
│ - "hoptallus": "mirage-raceway", │
│ - "hotallus": "mirage-raceway", │
│ - "ook-ook": "everlook", │
│ - "ookook": "everlook", │
│ - }, │
│ -} │
│ - │
│ -type realmGroup struct { │
│ - Parent string │
│ - Slugs []string │
│ -} │
│ - │
│ -func normalizeSlug(slug string) string { │
│ - return strings.ToLower(strings.TrimSpace(slug)) │
│ -} │
│ - │
│ -func normalizeRegion(region string) string { │
│ - return strings.ToLower(strings.TrimSpace(region)) │
│ -} │
│ - │
│ -// effectiveRealmSlug returns the parent leaderboard slug for a given region/real │
│ m slug. │
│ -func effectiveRealmSlug(region, slug string) string { │
│ - normalizedRegion := normalizeRegion(region) │
│ - normalizedSlug := normalizeSlug(slug) │
│ - if normalizedSlug == "" { │
│ - return "" │
│ - } │
│ - │
│ - if parents, ok := mergedRealmParents[normalizedRegion]; ok { │
│ - if parent, ok := parents[normalizedSlug]; ok { │
│ - return parent │
│ - } │
│ - } │
│ - return normalizedSlug │
│ -} │
│ - │
│ -// realmGroupSlugs returns all realm slugs (parent + children) that belong to the │
│ same leaderboard group. │
│ -func realmGroupSlugs(region, slug string) []string { │
│ - normalizedRegion := normalizeRegion(region) │
│ - parent := effectiveRealmSlug(region, slug) │
│ - if parent == "" { │
│ - if s := normalizeSlug(slug); s != "" { │
│ - return []string{s} │
│ - } │
│ - return nil │
│ - } │
│ - │
│ - unique := make(map[string]struct{}) │
│ - ordered := make([]string, 0, 4) │
│ - add := func(value string) { │
│ - if value == "" { │
│ - return │
│ - } │
│ - if _, exists := unique[value]; exists { │
│ - return │
│ - } │
│ - unique[value] = struct{}{} │
│ - ordered = append(ordered, value) │
│ - } │
│ - │
│ - add(parent) │
│ - if parents, ok := mergedRealmParents[normalizedRegion]; ok { │
│ - for child, p := range parents { │
│ - if p == parent { │
│ - add(child) │
│ - } │
│ - } │
│ - } │
│ - add(normalizeSlug(slug)) │
│ - │
│ - return ordered │
│ -} │
│ - │
│ -// groupRealmSlugs groups a list of realm slugs by their effective leaderboard pa │
│ rent. │
│ -func groupRealmSlugs(region string, slugs []string) []realmGroup { │
│ - normalizedRegion := normalizeRegion(region) │
│ - index := make(map[string]int) │
│ - var groups []realmGroup │
│ - │
│ - for _, slug := range slugs { │
│ - parent := effectiveRealmSlug(normalizedRegion, slug) │
│ - if parent == "" { │
│ - continue │
│ - } │
│ - if idx, ok := index[parent]; ok { │
│ - groups[idx].Slugs = appendUnique(groups[idx].Slugs, normalizeSlug(slug)) │
│ - } else { │
│ - groups = append(groups, realmGroup{ │
│ - Parent: parent, │
│ - Slugs: []string{normalizeSlug(slug)}, │
│ - }) │
│ - index[parent] = len(groups) - 1 │
│ - } │
│ - } │
│ - │
│ - for i := range groups { │
│ - groups[i].Slugs = appendUnique(groups[i].Slugs, groups[i].Parent) │
│ - } │
│ - │
│ - return groups │
│ -} │
│ - │
│ -func appendUnique(list []string, value string) []string { │
│ - if value == "" { │
│ - return list │
│ - } │
│ - for _, existing := range list { │
│ - if existing == value { │
│ - return list │
│ - } │
│ - } │
│ - return append(list, value) │
│ -} │
│ - │
│ -func makeSQLPlaceholders(n int) string { │
│ - if n <= 0 { │
│ - return "" │
│ - } │
│ - parts := make([]string, n) │
│ - for i := range parts { │
│ - parts[i] = "?" │
│ - } │
│ - return strings.Join(parts, ",") │
│ -} │
│ - │
│ -func stringSliceToInterface(values []string) []interface{} { │
│ - out := make([]interface{}, len(values)) │
│ - for i, v := range values { │
│ - out[i] = v │
│ - } │
│ - return out │
│ -} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...al/generator/realm_aliases.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ generator/realm_aliases.go b/nix/pkgs/ooksta │
│ ts/src/internal/generator/realm_aliases.go │
│ index 1bd4ac8..cc1b290 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/generat │
│ or/realm_aliases.go │
│ +++ b/nix/pkgs/ookstats/src/internal/generat │
│ or/realm_aliases.go │
│ @@ -1,151 +1 @@ │
│ package generator │
│ - │
│ -import "strings" │
│ - │
│ -// mergedRealmParents maps child realm slug │
│ s to their parent leaderboard realm per regi │
│ on. │
│ -var mergedRealmParents = map[string]map[str │
│ ing]string{ │
│ - "us": { │
│ - "nazgrim": "pagle", │
│ - "galakras": "pagle", │
│ - "raden": "pagle", │
│ - "ra-den": "pagle", │
│ - "lei-shen": "pagle", │
│ - "leishen": "pagle", │
│ - "immerseus": "pagle", │
│ - }, │
│ - "eu": { │
│ - "shekzeer": "mirage-raceway", │
│ - "garalon": "mirage-raceway", │
│ - "norushen": "mirage-raceway", │
│ - "hoptallus": "mirage-raceway", │
│ - "hotallus": "mirage-raceway", │
│ - "ook-ook": "everlook", │
│ - "ookook": "everlook", │
│ - }, │
│ -} │
│ - │
│ -type realmGroup struct { │
│ - Parent string │
│ - Slugs []string │
│ -} │
│ - │
│ -func normalizeSlug(slug string) string { │
│ - return strings.ToLower(strings.TrimSpace(s │
│ lug)) │
│ -} │
│ - │
│ -func normalizeRegion(region string) string │
│ { │
│ - return strings.ToLower(strings.TrimSpace(r │
│ egion)) │
│ -} │
│ - │
│ -// effectiveRealmSlug returns the parent le │
│ aderboard slug for a given region/realm slug │
│ . │
│ -func effectiveRealmSlug(region, slug string │
│ ) string { │
│ - normalizedRegion := normalizeRegion(region │
│ ) │
│ - normalizedSlug := normalizeSlug(slug) │
│ - if normalizedSlug == "" { │
│ - return "" │
│ - } │
│ - │
│ - if parents, ok := mergedRealmParents[norma │
│ lizedRegion]; ok { │
│ - if parent, ok := parents[normalizedSlug]; │
│ ok { │
│ - return parent │
│ - } │
│ - } │
│ - return normalizedSlug │
│ -} │
│ - │
│ -// realmGroupSlugs returns all realm slugs │
│ (parent + children) that belong to the same │
│ leaderboard group. │
│ -func realmGroupSlugs(region, slug string) [ │
│ ]string { │
│ - normalizedRegion := normalizeRegion(region │
│ ) │
│ - parent := effectiveRealmSlug(region, slug) │
│ - if parent == "" { │
│ - if s := normalizeSlug(slug); s != "" { │
│ - return []string{s} │
│ - } │
│ - return nil │
│ - } │
│ - │
│ - unique := make(map[string]struct{}) │
│ - ordered := make([]string, 0, 4) │
│ - add := func(value string) { │
│ - if value == "" { │
│ - return │
│ - } │
│ - if _, exists := unique[value]; exists { │
│ - return │
│ - } │
│ - unique[value] = struct{}{} │
│ - ordered = append(ordered, value) │
│ - } │
│ - │
│ - add(parent) │
│ - if parents, ok := mergedRealmParents[norma │
│ lizedRegion]; ok { │
│ - for child, p := range parents { │
│ - if p == parent { │
│ - add(child) │
│ - } │
│ - } │
│ - } │
│ - add(normalizeSlug(slug)) │
│ - │
│ - return ordered │
│ -} │
│ - │
│ -// groupRealmSlugs groups a list of realm s │
│ lugs by their effective leaderboard parent. │
│ -func groupRealmSlugs(region string, slugs [ │
│ ]string) []realmGroup { │
│ - normalizedRegion := normalizeRegion(region │
│ ) │
│ - index := make(map[string]int) │
│ - var groups []realmGroup │
│ - │
│ - for _, slug := range slugs { │
│ - parent := effectiveRealmSlug(normalizedRe │
│ gion, slug) │
│ - if parent == "" { │
│ - continue │
│ - } │
│ - if idx, ok := index[parent]; ok { │
│ - groups[idx].Slugs = appendUnique(groups[ │
│ idx].Slugs, normalizeSlug(slug)) │
│ - } else { │
│ - groups = append(groups, realmGroup{ │
│ - Parent: parent, │
│ - Slugs: []string{normalizeSlug(slug)}, │
│ - }) │
│ - index[parent] = len(groups) - 1 │
│ - } │
│ - } │
│ - │
│ - for i := range groups { │
│ - groups[i].Slugs = appendUnique(groups[i]. │
│ Slugs, groups[i].Parent) │
│ - } │
│ - │
│ - return groups │
│ -} │
│ - │
│ -func appendUnique(list []string, value stri │
│ ng) []string { │
│ - if value == "" { │
│ - return list │
│ - } │
│ - for _, existing := range list { │
│ - if existing == value { │
│ - return list │
│ - } │
│ - } │
│ - return append(list, value) │
│ -} │
│ - │
│ -func makeSQLPlaceholders(n int) string { │
│ - if n <= 0 { │
│ - return "" │
│ - } │
│ - parts := make([]string, n) │
│ - for i := range parts { │
│ - parts[i] = "?" │
│ - } │
│ - return strings.Join(parts, ",") │
│ -} │
│ - │
│ -func stringSliceToInterface(values []string │
│ ) []interface{} { │
│ - out := make([]interface{}, len(values)) │
│ - for i, v := range values { │
│ - out[i] = v │
│ - } │
│ - return out │
│ -} │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/ookstats/src/internal/pipeline/process.go ───────────────────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/pipeline/process.go b/nix/pkgs/ookstat │
│ s/src/internal/pipeline/process.go │
│ index 544e5d7..4acc707 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/pipeline/process.go │
│ +++ b/nix/pkgs/ookstats/src/internal/pipeline/process.go │
│ @@ -4,6 +4,8 @@ import ( │
│ "database/sql" │
│ "fmt" │
│ "time" │
│ + │
│ + "ookstats/internal/realms" │
│ ) │
│ │
│ // ProcessPlayersOptions contains options for player processing │
│ @@ -43,6 +45,10 @@ func ProcessPlayers(db *sql.DB, opts ProcessPlayersOptions) (pr │
│ ofilesCreated int │
│ fmt.Printf("Found %d seasons configured\n", seasonCount) │
│ } │
│ │
│ + if err := realms.SyncRealmGroups(tx); err != nil { │
│ + return 0, 0, fmt.Errorf("failed to sync realm groups: %w", err) │
│ + } │
│ + │
│ // step 1: create player aggregations (season-aware if seasons exist) │
│ fmt.Println("\n1. Creating player aggregations...") │
│ profilesCreated, err = createPlayerAggregations(tx) │
│ @@ -211,7 +217,7 @@ func createPlayerAggregations(tx *sql.Tx) (int, error) { │
│ p.id as player_id, │
│ pbr.season_id, │
│ p.name, │
│ - p.realm_id, │
│ + COALESCE(rg.parent_realm_id, p.realm_id) as realm_id, │
│ COUNT(pbr.dungeon_id) as dungeons_completed, │
│ season_runs.run_count as total_runs, │
│ COALESCE(SUM(pbr.duration), 0) as combined_best_time, │
│ @@ -223,6 +229,7 @@ func createPlayerAggregations(tx *sql.Tx) (int, error) { │
│ CASE WHEN COUNT(pbr.dungeon_id) = (SELECT COUNT(*) FROM dungeons) THEN 1 ELSE │
│ 0 END as has_complete_coverage, │
│ ? as last_updated │
│ FROM players p │
│ + LEFT JOIN realm_groups rg ON rg.child_realm_id = p.realm_id │
│ INNER JOIN player_best_runs pbr ON p.id = pbr.player_id │
│ INNER JOIN ( │
│ SELECT rm.player_id, COALESCE(ps.season_id, 1) as season_id, COUNT(*) as run_c │
│ ount │
│ @@ -231,7 +238,7 @@ func createPlayerAggregations(tx *sql.Tx) (int, error) { │
│ LEFT JOIN period_seasons ps ON cr.period_id = ps.period_id │
│ GROUP BY rm.player_id, COALESCE(ps.season_id, 1) │
│ ) season_runs ON p.id = season_runs.player_id AND pbr.season_id = season_runs.s │
│ eason_id │
│ - GROUP BY p.id, pbr.season_id, p.name, p.realm_id, season_runs.run_count │
│ + GROUP BY p.id, pbr.season_id, p.name, COALESCE(rg.parent_realm_id, p.realm_id), │
│ season_runs.run_count │
│ `, currentTime) │
│ if err != nil { │
│ return 0, err │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ .../internal/pipeline/process.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ pipeline/process.go b/nix/pkgs/ookstats/src/ │
│ internal/pipeline/process.go │
│ index 544e5d7..4acc707 100644 │
│ --- a/nix/pkgs/ookstats/src/internal/pipelin │
│ e/process.go │
│ +++ b/nix/pkgs/ookstats/src/internal/pipelin │
│ e/process.go │
│ @@ -4,6 +4,8 @@ import ( │
│ "database/sql" │
│ "fmt" │
│ "time" │
│ + │
│ + "ookstats/internal/realms" │
│ ) │
│ │
│ // ProcessPlayersOptions contains options f │
│ or player processing │
│ @@ -43,6 +45,10 @@ func ProcessPlayers(db *s │
│ ql.DB, opts ProcessPlayersOptions) (profiles │
│ Created int │
│ fmt.Printf("Found %d seasons configured\n │
│ ", seasonCount) │
│ } │
│ │
│ + if err := realms.SyncRealmGroups(tx); err │
│ != nil { │
│ + return 0, 0, fmt.Errorf("failed to sync r │
│ ealm groups: %w", err) │
│ + } │
│ + │
│ // step 1: create player aggregations (sea │
│ son-aware if seasons exist) │
│ fmt.Println("\n1. Creating player aggregat │
│ ions...") │
│ profilesCreated, err = createPlayerAggrega │
│ tions(tx) │
│ @@ -211,7 +217,7 @@ func createPlayerAggrega │
│ tions(tx *sql.Tx) (int, error) { │
│ p.id as player_id, │
│ pbr.season_id, │
│ p.name, │
│ - p.realm_id, │
│ + COALESCE(rg.parent_realm_id, p.realm_id) │
│ as realm_id, │
│ COUNT(pbr.dungeon_id) as dungeons_comple │
│ ted, │
│ season_runs.run_count as total_runs, │
│ COALESCE(SUM(pbr.duration), 0) as combin │
│ ed_best_time, │
│ @@ -223,6 +229,7 @@ func createPlayerAggrega │
│ tions(tx *sql.Tx) (int, error) { │
│ CASE WHEN COUNT(pbr.dungeon_id) = (SELEC │
│ T COUNT(*) FROM dungeons) THEN 1 ELSE 0 END │
│ as has_complete_coverage, │
│ ? as last_updated │
│ FROM players p │
│ + LEFT JOIN realm_groups rg ON rg.child_rea │
│ lm_id = p.realm_id │
│ INNER JOIN player_best_runs pbr ON p.id = │
│ pbr.player_id │
│ INNER JOIN ( │
│ SELECT rm.player_id, COALESCE(ps.season_ │
│ id, 1) as season_id, COUNT(*) as run_count │
│ @@ -231,7 +238,7 @@ func createPlayerAggrega │
│ tions(tx *sql.Tx) (int, error) { │
│ LEFT JOIN period_seasons ps ON cr.period │
│ _id = ps.period_id │
│ GROUP BY rm.player_id, COALESCE(ps.seaso │
│ n_id, 1) │
│ ) season_runs ON p.id = season_runs.playe │
│ r_id AND pbr.season_id = season_runs.season_ │
│ id │
│ - GROUP BY p.id, pbr.season_id, p.name, p.r │
│ ealm_id, season_runs.run_count │
│ + GROUP BY p.id, pbr.season_id, p.name, COA │
│ LESCE(rg.parent_realm_id, p.realm_id), seaso │
│ n_runs.run_count │
│ `, currentTime) │
│ if err != nil { │
│ return 0, err │
└──────────────────────────────────────────────┘
┌─ nix/pkgs/ookstats/src/internal/realms/aliases.go ─────────────────────────┐
│ diff --git a/nix/pkgs/ookstats/src/internal/realms/aliases.go b/nix/pkgs/ookstats/ │
│ src/internal/realms/aliases.go │
│ new file mode 100644 │
│ index 0000000..a475779 │
│ --- /dev/null │
│ +++ b/nix/pkgs/ookstats/src/internal/realms/aliases.go │
│ @@ -0,0 +1,101 @@ │
│ +package realms │
│ + │
│ +import ( │
│ + "database/sql" │
│ + "fmt" │
│ + "strings" │
│ +) │
│ + │
│ +// ParentSlugByRegion defines merged realm mappings keyed by region and child slu │
│ g │
│ +var ParentSlugByRegion = map[string]map[string]string{ │
│ + "us": { │
│ + "nazgrim": "pagle", │
│ + "galakras": "pagle", │
│ + "raden": "pagle", │
│ + "ra-den": "pagle", │
│ + "lei-shen": "pagle", │
│ + "leishen": "pagle", │
│ + "immerseus": "pagle", │
│ + }, │
│ + "eu": { │
│ + "shekzeer": "mirage-raceway", │
│ + "garalon": "mirage-raceway", │
│ + "norushen": "mirage-raceway", │
│ + "hoptallus": "mirage-raceway", │
│ + "hotallus": "mirage-raceway", │
│ + "ook-ook": "everlook", │
│ + "ookook": "everlook", │
│ + }, │
│ +} │
│ + │
│ +func normalize(value string) string { │
│ + return strings.ToLower(strings.TrimSpace(value)) │
│ +} │
│ + │
│ +// EffectiveSlug returns the leaderboard slug (parent) for the given region+slug │
│ pair. │
│ +func EffectiveSlug(region, slug string) string { │
│ + normalizedRegion := normalize(region) │
│ + normalizedSlug := normalize(slug) │
│ + if normalizedSlug == "" { │
│ + return "" │
│ + } │
│ + │
│ + if regionMap, ok := ParentSlugByRegion[normalizedRegion]; ok { │
│ + if parent, ok := regionMap[normalizedSlug]; ok { │
│ + return parent │
│ + } │
│ + } │
│ + return normalizedSlug │
│ +} │
│ + │
│ +// SyncRealmGroups populates the realm_groups table so child -> parent mappings a │
│ re available in SQL. │
│ +func SyncRealmGroups(tx *sql.Tx) error { │
│ + if _, err := tx.Exec(`DELETE FROM realm_groups`); err != nil { │
│ + return fmt.Errorf("failed clearing realm_groups: %w", err) │
│ + } │
│ + │
│ + rows, err := tx.Query(`SELECT id, slug, region FROM realms`) │
│ + if err != nil { │
│ + return fmt.Errorf("failed loading realms for mapping: %w", err) │
│ + } │
│ + defer rows.Close() │
│ + │
│ + type realmRow struct { │
│ + id int64 │
│ + slug string │
│ + region string │
│ + } │
│ + │
│ + realmIndex := make(map[string]map[string]int64) │
│ + for rows.Next() { │
│ + var rr realmRow │
│ + if err := rows.Scan(&rr.id, &rr.slug, &rr.region); err != nil { │
│ + return err │
│ + } │
│ + regionKey := normalize(rr.region) │
│ + slugKey := normalize(rr.slug) │
│ + if _, ok := realmIndex[regionKey]; !ok { │
│ + realmIndex[regionKey] = make(map[string]int64) │
│ + } │
│ + realmIndex[regionKey][slugKey] = rr.id │
│ + } │
│ + │
│ + for region, children := range ParentSlugByRegion { │
│ + known := realmIndex[region] │
│ + if known == nil { │
│ + continue │
│ + } │
│ + for childSlug, parentSlug := range children { │
│ + childID := known[childSlug] │
│ + parentID := known[parentSlug] │
│ + if childID == 0 || parentID == 0 { │
│ + continue │
│ + } │
│ + if _, err := tx.Exec(`INSERT INTO realm_groups (child_realm_id, parent_realm_i │
│ d) VALUES (?, ?)`, childID, parentID); err != nil { │
│ + return fmt.Errorf("failed inserting realm group for %s -> %s: %w", childSlug, │
│ parentSlug, err) │
│ + } │
│ + } │
│ + } │
│ + │
│ + return nil │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...rc/internal/realms/aliases.go ───┐
│ diff --git a/nix/pkgs/ookstats/src/internal/ │
│ realms/aliases.go b/nix/pkgs/ookstats/src/in │
│ ternal/realms/aliases.go │
│ new file mode 100644 │
│ index 0000000..a475779 │
│ --- /dev/null │
│ +++ b/nix/pkgs/ookstats/src/internal/realms/ │
│ aliases.go │
│ @@ -0,0 +1,101 @@ │
│ +package realms │
│ + │
│ +import ( │
│ + "database/sql" │
│ + "fmt" │
│ + "strings" │
│ +) │
│ + │
│ +// ParentSlugByRegion defines merged realm │
│ mappings keyed by region and child slug │
│ +var ParentSlugByRegion = map[string]map[str │
│ ing]string{ │
│ + "us": { │
│ + "nazgrim": "pagle", │
│ + "galakras": "pagle", │
│ + "raden": "pagle", │
│ + "ra-den": "pagle", │
│ + "lei-shen": "pagle", │
│ + "leishen": "pagle", │
│ + "immerseus": "pagle", │
│ + }, │
│ + "eu": { │
│ + "shekzeer": "mirage-raceway", │
│ + "garalon": "mirage-raceway", │
│ + "norushen": "mirage-raceway", │
│ + "hoptallus": "mirage-raceway", │
│ + "hotallus": "mirage-raceway", │
│ + "ook-ook": "everlook", │
│ + "ookook": "everlook", │
│ + }, │
│ +} │
│ + │
│ +func normalize(value string) string { │
│ + return strings.ToLower(strings.TrimSpace(v │
│ alue)) │
│ +} │
│ + │
│ +// EffectiveSlug returns the leaderboard sl │
│ ug (parent) for the given region+slug pair. │
│ +func EffectiveSlug(region, slug string) str │
│ ing { │
│ + normalizedRegion := normalize(region) │
│ + normalizedSlug := normalize(slug) │
│ + if normalizedSlug == "" { │
│ + return "" │
│ + } │
│ + │
│ + if regionMap, ok := ParentSlugByRegion[nor │
│ malizedRegion]; ok { │
│ + if parent, ok := regionMap[normalizedSlug │
│ ]; ok { │
│ + return parent │
│ + } │
│ + } │
│ + return normalizedSlug │
│ +} │
│ + │
│ +// SyncRealmGroups populates the realm_grou │
│ ps table so child -> parent mappings are ava │
│ ilable in SQL. │
│ +func SyncRealmGroups(tx *sql.Tx) error { │
│ + if _, err := tx.Exec(`DELETE FROM realm_gr │
│ oups`); err != nil { │
│ + return fmt.Errorf("failed clearing realm_ │
│ groups: %w", err) │
│ + } │
│ + │
│ + rows, err := tx.Query(`SELECT id, slug, re │
│ gion FROM realms`) │
│ + if err != nil { │
│ + return fmt.Errorf("failed loading realms │
│ for mapping: %w", err) │
│ + } │
│ + defer rows.Close() │
│ + │
│ + type realmRow struct { │
│ + id int64 │
│ + slug string │
│ + region string │
│ + } │
│ + │
│ + realmIndex := make(map[string]map[string]i │
│ nt64) │
│ + for rows.Next() { │
│ + var rr realmRow │
│ + if err := rows.Scan(&rr.id, &rr.slug, &rr │
│ .region); err != nil { │
│ + return err │
│ + } │
│ + regionKey := normalize(rr.region) │
│ + slugKey := normalize(rr.slug) │
│ + if _, ok := realmIndex[regionKey]; !ok { │
│ + realmIndex[regionKey] = make(map[string] │
│ int64) │
│ + } │
│ + realmIndex[regionKey][slugKey] = rr.id │
│ + } │
│ + │
│ + for region, children := range ParentSlugBy │
│ Region { │
│ + known := realmIndex[region] │
│ + if known == nil { │
│ + continue │
│ + } │
│ + for childSlug, parentSlug := range childr │
│ en { │
│ + childID := known[childSlug] │
│ + parentID := known[parentSlug] │
│ + if childID == 0 || parentID == 0 { │
│ + continue │
│ + } │
│ + if _, err := tx.Exec(`INSERT INTO realm_ │
│ groups (child_realm_id, parent_realm_id) VAL │
│ UES (?, ?)`, childID, parentID); err != nil │
│ { │
│ + return fmt.Errorf("failed inserting rea │
│ lm group for %s -> %s: %w", childSlug, paren │
│ tSlug, err) │
│ + } │
│ + } │
│ + } │
│ + │
│ + return nil │
│ +} │
└──────────────────────────────────────────────┘
┌─ web/.astro/data-store.json ───────────────────────────────────────────────┐
│ diff --git a/web/.astro/data-store.json b/web/.astro/data-store.json │
│ index 0606cf9..ea0aeae 100644 │
│ --- a/web/.astro/data-store.json │
│ +++ b/web/.astro/data-store.json │
│ @@ -1 +1 @@ │
│ -[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config- │
│ digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{} │
│ ,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail │
│ ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\", │
│ \"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr │
│ o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto │
│ \",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":17631,\"s │
│ treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r │
│ oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\" │
│ config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de │
│ vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\ │
│ ",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th │
│ eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl │
│ ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t │
│ rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\ │
│ ":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false │
│ ,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\ │
│ ":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}" │
│ ] │
│ \ No newline at end of file │
│ +[["Map",1,2],"meta::meta",["Map",3,4,5,6],"astro-version","5.12.0","astro-config- │
│ digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{} │
│ ,\"site\":\"https://wowsimstats.com\",\"compressHTML\":true,\"base\":\"/\",\"trail │
│ ingSlash\":\"ignore\",\"output\":\"server\",\"scopedStyleStrategy\":\"attribute\", │
│ \"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astr │
│ o\",\"serverEntry\":\"entry.mjs\",\"redirects\":false,\"inlineStylesheets\":\"auto │
│ \",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":37831,\"s │
│ treaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"r │
│ oute\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\" │
│ config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"de │
│ vToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":{\"type\":\"shiki\ │
│ ",\"excludeLangs\":[\"math\"]},\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"th │
│ eme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPl │
│ ugins\":[],\"rehypePlugins\":[],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":t │
│ rue},\"security\":{\"checkOrigin\":true},\"env\":{\"schema\":{},\"validateSecrets\ │
│ ":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false │
│ ,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\ │
│ ":false,\"csp\":false,\"rawEnvValues\":false},\"legacy\":{\"collections\":false}}" │
│ ] │
│ \ No newline at end of file │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/.astro/data-store.json ─────────┐
│ diff --git a/web/.astro/data-store.json b/we │
│ b/.astro/data-store.json │
│ index 0606cf9..ea0aeae 100644 │
│ --- a/web/.astro/data-store.json │
│ +++ b/web/.astro/data-store.json │
│ @@ -1 +1 @@ │
│ -[["Map",1,2],"meta::meta",["Map",3,4,5,6]," │
│ astro-version","5.12.0","astro-config-digest │
│ ","{\"root\":{},\"srcDir\":{},\"publicDir\": │
│ {},\"outDir\":{},\"cacheDir\":{},\"site\":\" │
│ https://wowsimstats.com\",\"compressHTML\":t │
│ rue,\"base\":\"/\",\"trailingSlash\":\"ignor │
│ e\",\"output\":\"server\",\"scopedStyleStrat │
│ egy\":\"attribute\",\"build\":{\"format\":\" │
│ directory\",\"client\":{},\"server\":{},\"as │
│ sets\":\"_astro\",\"serverEntry\":\"entry.mj │
│ s\",\"redirects\":false,\"inlineStylesheets\ │
│ ":\"auto\",\"concurrency\":1},\"server\":{\" │
│ open\":false,\"host\":false,\"port\":17631,\ │
│ "streaming\":true,\"allowedHosts\":[]},\"red │
│ irects\":{},\"image\":{\"endpoint\":{\"route │
│ \":\"/_image\"},\"service\":{\"entrypoint\": │
│ \"astro/assets/services/sharp\",\"config\":{ │
│ }},\"domains\":[],\"remotePatterns\":[],\"re │
│ sponsiveStyles\":false},\"devToolbar\":{\"en │
│ abled\":true},\"markdown\":{\"syntaxHighligh │
│ t\":{\"type\":\"shiki\",\"excludeLangs\":[\" │
│ math\"]},\"shikiConfig\":{\"langs\":[],\"lan │
│ gAlias\":{},\"theme\":\"github-dark\",\"them │
│ es\":{},\"wrap\":false,\"transformers\":[]}, │
│ \"remarkPlugins\":[],\"rehypePlugins\":[],\" │
│ remarkRehype\":{},\"gfm\":true,\"smartypants │
│ \":true},\"security\":{\"checkOrigin\":true} │
│ ,\"env\":{\"schema\":{},\"validateSecrets\": │
│ false},\"experimental\":{\"clientPrerender\" │
│ :false,\"contentIntellisense\":false,\"headi │
│ ngIdCompat\":false,\"preserveScriptOrder\":f │
│ alse,\"liveContentCollections\":false,\"csp\ │
│ ":false,\"rawEnvValues\":false},\"legacy\":{ │
│ \"collections\":false}}"] │
│ \ No newline at end of file │
│ +[["Map",1,2],"meta::meta",["Map",3,4,5,6]," │
│ astro-version","5.12.0","astro-config-digest │
│ ","{\"root\":{},\"srcDir\":{},\"publicDir\": │
│ {},\"outDir\":{},\"cacheDir\":{},\"site\":\" │
│ https://wowsimstats.com\",\"compressHTML\":t │
│ rue,\"base\":\"/\",\"trailingSlash\":\"ignor │
│ e\",\"output\":\"server\",\"scopedStyleStrat │
│ egy\":\"attribute\",\"build\":{\"format\":\" │
│ directory\",\"client\":{},\"server\":{},\"as │
│ sets\":\"_astro\",\"serverEntry\":\"entry.mj │
│ s\",\"redirects\":false,\"inlineStylesheets\ │
│ ":\"auto\",\"concurrency\":1},\"server\":{\" │
│ open\":false,\"host\":false,\"port\":37831,\ │
│ "streaming\":true,\"allowedHosts\":[]},\"red │
│ irects\":{},\"image\":{\"endpoint\":{\"route │
│ \":\"/_image\"},\"service\":{\"entrypoint\": │
│ \"astro/assets/services/sharp\",\"config\":{ │
│ }},\"domains\":[],\"remotePatterns\":[],\"re │
│ sponsiveStyles\":false},\"devToolbar\":{\"en │
│ abled\":true},\"markdown\":{\"syntaxHighligh │
│ t\":{\"type\":\"shiki\",\"excludeLangs\":[\" │
│ math\"]},\"shikiConfig\":{\"langs\":[],\"lan │
│ gAlias\":{},\"theme\":\"github-dark\",\"them │
│ es\":{},\"wrap\":false,\"transformers\":[]}, │
│ \"remarkPlugins\":[],\"rehypePlugins\":[],\" │
│ remarkRehype\":{},\"gfm\":true,\"smartypants │
│ \":true},\"security\":{\"checkOrigin\":true} │
│ ,\"env\":{\"schema\":{},\"validateSecrets\": │
│ false},\"experimental\":{\"clientPrerender\" │
│ :false,\"contentIntellisense\":false,\"headi │
│ ngIdCompat\":false,\"preserveScriptOrder\":f │
│ alse,\"liveContentCollections\":false,\"csp\ │
│ ":false,\"rawEnvValues\":false},\"legacy\":{ │
│ \"collections\":false}}"] │
│ \ No newline at end of file │
└──────────────────────────────────────────────┘
┌─ web/src/components/PlayerProfile/PlayerBestRuns/PlayerBestRuns.astro ─────┐
│ diff --git a/web/src/components/PlayerProfile/PlayerBestRuns/PlayerBestRuns.astro │
│ b/web/src/components/PlayerProfile/PlayerBestRuns/PlayerBestRuns.astro │
│ index a4440df..50bc417 100644 │
│ --- a/web/src/components/PlayerProfile/PlayerBestRuns/PlayerBestRuns.astro │
│ +++ b/web/src/components/PlayerProfile/PlayerBestRuns/PlayerBestRuns.astro │
│ @@ -7,6 +7,7 @@ import TeamComposition from "../../Leaderboard/TeamComposition/Tea │
│ mComposition.a │
│ import { formatDurationMMSS, buildLeaderboardURL } from "../../../lib/utils"; │
│ import { formatRankingWithBracket } from "../../../lib/ranking-utils"; │
│ import { getDungeonIconUrl } from "../../../lib/dungeonIcons"; │
│ +import { getEffectiveRealmSlug } from "../../../lib/realms"; │
│ import "./PlayerBestRuns.scss"; │
│ │
│ interface Props { │
│ @@ -32,6 +33,8 @@ const { │
│ const runsArray = bestRuns ? Object.values(bestRuns) : []; │
│ const seasonNumber = seasonId ? Number(seasonId) : undefined; │
│ const leaderboardUrlOpts = seasonNumber ? { season: seasonNumber } : undefined; │
│ +const leaderboardRealmSlug = │
│ + getEffectiveRealmSlug(playerRegion, playerRealmSlug) || playerRealmSlug || ""; │
│ │
│ const formatTime = (ms: number) => formatDurationMMSS(ms); │
│ │
│ @@ -122,16 +125,17 @@ const formatDate = (timestamp: number) => { │
│ ) │
│ : "#"; │
│ const realmURL = │
│ - playerRegion && playerRealmSlug │
│ + playerRegion && leaderboardRealmSlug │
│ ? buildLeaderboardURL( │
│ playerRegion, │
│ - playerRealmSlug, │
│ + leaderboardRealmSlug, │
│ dungeonSlug, │
│ undefined, │
│ leaderboardUrlOpts, │
│ ) │
│ : "#"; │
│ │
│ + │
│ const members = (run as any).all_members || (run as any).team_membe │
│ rs || []; │
│ │
│ return ( │
│ @@ -276,16 +280,17 @@ const formatDate = (timestamp: number) => { │
│ ) │
│ : "#"; │
│ const realmURL = │
│ - playerRegion && playerRealmSlug │
│ + playerRegion && leaderboardRealmSlug │
│ ? buildLeaderboardURL( │
│ playerRegion, │
│ - playerRealmSlug, │
│ + leaderboardRealmSlug, │
│ dungeonSlug, │
│ undefined, │
│ leaderboardUrlOpts, │
│ ) │
│ : "#"; │
│ │
│ + │
│ const members = (run as any).all_members || (run as any).team_members │
│ || []; │
│ │
│ return ( │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...BestRuns/PlayerBestRuns.astro ───┐
│ diff --git a/web/src/components/PlayerProfil │
│ e/PlayerBestRuns/PlayerBestRuns.astro b/web/ │
│ src/components/PlayerProfile/PlayerBestRuns/ │
│ PlayerBestRuns.astro │
│ index a4440df..50bc417 100644 │
│ --- a/web/src/components/PlayerProfile/Playe │
│ rBestRuns/PlayerBestRuns.astro │
│ +++ b/web/src/components/PlayerProfile/Playe │
│ rBestRuns/PlayerBestRuns.astro │
│ @@ -7,6 +7,7 @@ import TeamComposition from │
│ "../../Leaderboard/TeamComposition/TeamCompo │
│ sition.a │
│ import { formatDurationMMSS, buildLeaderboa │
│ rdURL } from "../../../lib/utils"; │
│ import { formatRankingWithBracket } from ". │
│ ./../../lib/ranking-utils"; │
│ import { getDungeonIconUrl } from "../../.. │
│ /lib/dungeonIcons"; │
│ +import { getEffectiveRealmSlug } from "../. │
│ ./../lib/realms"; │
│ import "./PlayerBestRuns.scss"; │
│ │
│ interface Props { │
│ @@ -32,6 +33,8 @@ const { │
│ const runsArray = bestRuns ? Object.values( │
│ bestRuns) : []; │
│ const seasonNumber = seasonId ? Number(seas │
│ onId) : undefined; │
│ const leaderboardUrlOpts = seasonNumber ? { │
│ season: seasonNumber } : undefined; │
│ +const leaderboardRealmSlug = │
│ + getEffectiveRealmSlug(playerRegion, playe │
│ rRealmSlug) || playerRealmSlug || ""; │
│ │
│ const formatTime = (ms: number) => formatDu │
│ rationMMSS(ms); │
│ │
│ @@ -122,16 +125,17 @@ const formatDate = (ti │
│ mestamp: number) => { │
│ ) │
│ : "#"; │
│ const realmURL = │
│ - playerRegion && playerRealm │
│ Slug │
│ + playerRegion && leaderboard │
│ RealmSlug │
│ ? buildLeaderboardURL( │
│ playerRegion, │
│ - playerRealmSlug, │
│ + leaderboardRealmSlug, │
│ dungeonSlug, │
│ undefined, │
│ leaderboardUrlOpts, │
│ ) │
│ : "#"; │
│ │
│ + │
│ const members = (run as any). │
│ all_members || (run as any).team_members || │
│ []; │
│ │
│ return ( │
│ @@ -276,16 +280,17 @@ const formatDate = (ti │
│ mestamp: number) => { │
│ ) │
│ : "#"; │
│ const realmURL = │
│ - playerRegion && playerRealmSl │
│ ug │
│ + playerRegion && leaderboardRe │
│ almSlug │
│ ? buildLeaderboardURL( │
│ playerRegion, │
│ - playerRealmSlug, │
│ + leaderboardRealmSlug, │
│ dungeonSlug, │
│ undefined, │
│ leaderboardUrlOpts, │
│ ) │
│ : "#"; │
│ │
│ + │
│ const members = (run as any).al │
│ l_members || (run as any).team_members || [] │
│ ; │
│ │
│ return ( │
└──────────────────────────────────────────────┘
┌─ web/src/components/PlayerProfile/PlayerHeader/PlayerHeader.astro ─────────┐
│ diff --git a/web/src/components/PlayerProfile/PlayerHeader/PlayerHeader.astro b/we │
│ b/src/components/PlayerProfile/PlayerHeader/PlayerHeader.astro │
│ index 4700433..ab7d353 100644 │
│ --- a/web/src/components/PlayerProfile/PlayerHeader/PlayerHeader.astro │
│ +++ b/web/src/components/PlayerProfile/PlayerHeader/PlayerHeader.astro │
│ @@ -2,6 +2,7 @@ │
│ import { formatDurationMMSS } from "../../../lib/utils"; │
│ import { formatRankingWithBracket } from "../../../lib/ranking-utils"; │
│ import { getClassTextClass } from "../../../lib/wow-constants"; │
│ +import { getEffectiveRealmSlug, getRealmDisplayName } from "../../../lib/realms"; │
│ import "./PlayerHeader.scss"; │
│ │
│ interface SeasonData { │
│ @@ -40,6 +41,13 @@ interface Props { │
│ │
│ const { player, seasonData } = Astro.props; │
│ │
│ +const leaderboardRealmSlug = │
│ + getEffectiveRealmSlug(player.region, player.realm_slug) || player.realm_slug; │
│ +const leaderboardRealmLabel = getRealmDisplayName( │
│ + player.region, │
│ + leaderboardRealmSlug, │
│ +); │
│ + │
│ function getRaceId(raceName: string): number { │
│ const raceIds: Record<string, number> = { │
│ Human: 1, │
│ @@ -128,7 +136,7 @@ const avatarUrl = player.avatar_url │
│ </div> │
│ │
│ <div class="ranking-column"> │
│ - <div class="stat-label">{player.realm_name || player.realm_slug} Rank</div> │
│ + <div class="stat-label">{leaderboardRealmLabel || player.realm_name || player │
│ .realm_slug} Rank</div> │
│ <div │
│ class="stat-value" │
│ set:html={formatRankingWithBracket( │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...ayerHeader/PlayerHeader.astro ───┐
│ diff --git a/web/src/components/PlayerProfil │
│ e/PlayerHeader/PlayerHeader.astro b/web/src/ │
│ components/PlayerProfile/PlayerHeader/Player │
│ Header.astro │
│ index 4700433..ab7d353 100644 │
│ --- a/web/src/components/PlayerProfile/Playe │
│ rHeader/PlayerHeader.astro │
│ +++ b/web/src/components/PlayerProfile/Playe │
│ rHeader/PlayerHeader.astro │
│ @@ -2,6 +2,7 @@ │
│ import { formatDurationMMSS } from "../../. │
│ ./lib/utils"; │
│ import { formatRankingWithBracket } from ". │
│ ./../../lib/ranking-utils"; │
│ import { getClassTextClass } from "../../.. │
│ /lib/wow-constants"; │
│ +import { getEffectiveRealmSlug, getRealmDis │
│ playName } from "../../../lib/realms"; │
│ import "./PlayerHeader.scss"; │
│ │
│ interface SeasonData { │
│ @@ -40,6 +41,13 @@ interface Props { │
│ │
│ const { player, seasonData } = Astro.props; │
│ │
│ +const leaderboardRealmSlug = │
│ + getEffectiveRealmSlug(player.region, play │
│ er.realm_slug) || player.realm_slug; │
│ +const leaderboardRealmLabel = getRealmDispl │
│ ayName( │
│ + player.region, │
│ + leaderboardRealmSlug, │
│ +); │
│ + │
│ function getRaceId(raceName: string): numbe │
│ r { │
│ const raceIds: Record<string, number> = { │
│ Human: 1, │
│ @@ -128,7 +136,7 @@ const avatarUrl = player │
│ .avatar_url │
│ </div> │
│ │
│ <div class="ranking-column"> │
│ - <div class="stat-label">{player.realm_n │
│ ame || player.realm_slug} Rank</div> │
│ + <div class="stat-label">{leaderboardRea │
│ lmLabel || player.realm_name || player.realm │
│ _slug} Rank</div> │
│ <div │
│ class="stat-value" │
│ set:html={formatRankingWithBracket( │
└──────────────────────────────────────────────┘
┌─ web/src/lib/realms.ts ────────────────────────────────────────────────────┐
│ diff --git a/web/src/lib/realms.ts b/web/src/lib/realms.ts │
│ index 1e1bfe9..1e3c65b 100644 │
│ --- a/web/src/lib/realms.ts │
│ +++ b/web/src/lib/realms.ts │
│ @@ -146,3 +146,25 @@ export function areRealmsEquivalent( │
│ } │
│ return effectiveA === effectiveB; │
│ } │
│ + │
│ +export function getRealmDisplayName( │
│ + region?: string | null, │
│ + realmSlug?: string | null, │
│ +): string { │
│ + const normalizedRegion = normalizeRegion(region); │
│ + const normalizedSlug = normalizeSlug(realmSlug); │
│ + if (!normalizedSlug) { │
│ + return realmSlug || ""; │
│ + } │
│ + │
│ + if (normalizedRegion && REALM_DATA[normalizedRegion]) { │
│ + const regionRealms = REALM_DATA[normalizedRegion]; │
│ + const displayName = │
│ + regionRealms[normalizedSlug as keyof typeof regionRealms]; │
│ + if (displayName) { │
│ + return displayName; │
│ + } │
│ + } │
│ + │
│ + return realmSlug || normalizedSlug; │
│ +} │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ web/src/lib/realms.ts ──────────────┐
│ diff --git a/web/src/lib/realms.ts b/web/src │
│ /lib/realms.ts │
│ index 1e1bfe9..1e3c65b 100644 │
│ --- a/web/src/lib/realms.ts │
│ +++ b/web/src/lib/realms.ts │
│ @@ -146,3 +146,25 @@ export function areReal │
│ msEquivalent( │
│ } │
│ return effectiveA === effectiveB; │
│ } │
│ + │
│ +export function getRealmDisplayName( │
│ + region?: string | null, │
│ + realmSlug?: string | null, │
│ +): string { │
│ + const normalizedRegion = normalizeRegion( │
│ region); │
│ + const normalizedSlug = normalizeSlug(real │
│ mSlug); │
│ + if (!normalizedSlug) { │
│ + return realmSlug || ""; │
│ + } │
│ + │
│ + if (normalizedRegion && REALM_DATA[normal │
│ izedRegion]) { │
│ + const regionRealms = REALM_DATA[normali │
│ zedRegion]; │
│ + const displayName = │
│ + regionRealms[normalizedSlug as keyof │
│ typeof regionRealms]; │
│ + if (displayName) { │
│ + return displayName; │
│ + } │
│ + } │
│ + │
│ + return realmSlug || normalizedSlug; │
│ +} │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET