┌─ GO ───────────────────────────────────────────────────────────────────────┐
│ package generator │
│ │
│ import ( │
│ "database/sql" │
│ "fmt" │
│ "ookstats/internal/writer" │
│ "path/filepath" │
│ "time" │
│ ) │
│ │
│ // SearchEntry represents a player in the search index │
│ type SearchEntry struct { │
│ ID int64 `json:"id"` │
│ Name string `json:"name"` │
│ Region string `json:"region"` │
│ RealmSlug string `json:"realm_slug"` │
│ RealmName string `json:"realm_name"` │
│ ClassName string `json:"class_name,omitempty"` │
│ GlobalRanking *int `json:"global_ranking,omitempty"` │
│ GlobalBracket string `json:"global_ranking_bracket,omitempty"` │
│ } │
│ │
│ // GenerateSearchIndex generates sharded JSON files for the player search index │
│ func GenerateSearchIndex(db *sql.DB, out string, shardSize int) error { │
│ if shardSize <= 0 { │
│ shardSize = 5000 │
│ } │
│ if err := writer.EnsureDir(out); err != nil { │
│ return err │
│ } │
│ │
│ // count first so the shard loop never holds a row iterator across a second query │
│ var totalPlayers int │
│ if err := db.QueryRow(` │
│ SELECT COUNT(*) │
│ FROM players p │
│ JOIN ( │
│ SELECT player_id, MAX(season_id) as max_season_id │
│ FROM player_profiles │
│ WHERE has_complete_coverage = 1 │
│ GROUP BY player_id │
│ ) latest ON p.id = latest.player_id │
│ JOIN player_profiles pp ON pp.player_id = latest.player_id │
│ AND pp.season_id = latest.max_season_id │
│ JOIN realms r ON p.realm_id = r.id │
│ `).Scan(&totalPlayers); err != nil { │
│ return err │
│ } │
│ │
│ rows, err := db.Query(` │
│ SELECT p.id, p.name, r.region, r.slug, r.name, │
│ COALESCE(pp.class_name, ''), pp.global_ranking, COALESCE(pp.global_ │
│ ranking_bracket,'') │
│ FROM players p │
│ JOIN ( │
│ SELECT player_id, MAX(season_id) as max_season_id │
│ FROM player_profiles │
│ WHERE has_complete_coverage = 1 │
│ GROUP BY player_id │
│ ) latest ON p.id = latest.player_id │
│ JOIN player_profiles pp ON pp.player_id = latest.player_id │
│ AND pp.season_id = latest.max_season_id │
│ JOIN realms r ON p.realm_id = r.id │
│ ORDER BY pp.global_ranking ASC, p.name ASC │
│ `) │
│ if err != nil { │
│ return err │
│ } │
│ defer rows.Close() │
│ │
│ shard := 0 │
│ count := 0 │
│ buf := []SearchEntry{} │
│ │
│ flush := func() error { │
│ if len(buf) == 0 { │
│ return nil │
│ } │
│ path := filepath.Join(out, fmt.Sprintf("players-%03d.json", shard)) │
│ meta := map[string]any{ │
│ "total_players": totalPlayers, │
│ "returned_players": len(buf), │
│ "offset": shard * shardSize, │
│ "limit": shardSize, │
│ "last_updated": time.Now().Format(time.RFC3339), │
│ } │
│ if err := writer.WriteJSONFileCompact(path, map[string]any{"players": buf, "meta │
│ data": meta}); err != nil { │
│ return err │
│ } │
│ shard++ │
│ buf = buf[:0] │
│ return nil │
│ } │
│ │
│ for rows.Next() { │
│ var e SearchEntry │
│ var className sql.NullString │
│ var gr sql.NullInt64 │
│ var gb string │
│ if err := rows.Scan(&e.ID, &e.Name, &e.Region, &e.RealmSlug, &e.RealmName, &clas │
│ sName, &gr, &gb); err != nil { │
│ return err │
│ } │
│ e.ClassName = className.String │
│ e.GlobalBracket = gb │
│ if gr.Valid { │
│ v := int(gr.Int64) │
│ e.GlobalRanking = &v │
│ } │
│ buf = append(buf, e) │
│ count++ │
│ if len(buf) >= shardSize { │
│ if err := flush(); err != nil { │
│ return err │
│ } │
│ } │
│ } │
│ │
│ if err := rows.Err(); err != nil { │
│ return err │
│ } │
│ if err := flush(); err != nil { │
│ return err │
│ } │
│ │
│ fmt.Printf("[OK] Generated search index: %d players in %d shards\n", count, shard │
│ ) │
│ return nil │
│ } │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ GO ─────────────────────────────────┐
│ package generator │
│ │
│ import ( │
│ "database/sql" │
│ "fmt" │
│ "ookstats/internal/writer" │
│ "path/filepath" │
│ "time" │
│ ) │
│ │
│ // SearchEntry represents a player in the se │
│ arch index │
│ type SearchEntry struct { │
│ ID int64 `json:"id"` │
│ Name string `json:"name"` │
│ Region string `json:"region"` │
│ RealmSlug string `json:"realm_slug"` │
│ RealmName string `json:"realm_name"` │
│ ClassName string `json:"class_name,omit │
│ empty"` │
│ GlobalRanking *int `json:"global_ranking, │
│ omitempty"` │
│ GlobalBracket string `json:"global_ranking_ │
│ bracket,omitempty"` │
│ } │
│ │
│ // GenerateSearchIndex generates sharded JSO │
│ N files for the player search index │
│ func GenerateSearchIndex(db *sql.DB, out str │
│ ing, shardSize int) error { │
│ if shardSize <= 0 { │
│ shardSize = 5000 │
│ } │
│ if err := writer.EnsureDir(out); err != nil │
│ { │
│ return err │
│ } │
│ │
│ // count first so the shard loop never hold │
│ s a row iterator across a second query │
│ var totalPlayers int │
│ if err := db.QueryRow(` │
│ SELECT COUNT(*) │
│ FROM players p │
│ JOIN ( │
│ SELECT player_id, MAX(season_id) a │
│ s max_season_id │
│ FROM player_profiles │
│ WHERE has_complete_coverage = 1 │
│ GROUP BY player_id │
│ ) latest ON p.id = latest.player_id │
│ JOIN player_profiles pp ON pp.player_i │
│ d = latest.player_id │
│ AND pp.season_ │
│ id = latest.max_season_id │
│ JOIN realms r ON p.realm_id = r.id │
│ `).Scan(&totalPlayers); err != nil { │
│ return err │
│ } │
│ │
│ rows, err := db.Query(` │
│ SELECT p.id, p.name, r.region, r.slu │
│ g, r.name, │
│ COALESCE(pp.class_name, ''), │
│ pp.global_ranking, COALESCE(pp.global_rankin │
│ g_bracket,'') │
│ FROM players p │
│ JOIN ( │
│ SELECT player_id, MAX(season_id) │
│ as max_season_id │
│ FROM player_profiles │
│ WHERE has_complete_coverage = 1 │
│ GROUP BY player_id │
│ ) latest ON p.id = latest.player_id │
│ JOIN player_profiles pp ON pp.player │
│ _id = latest.player_id │
│ AND pp.seaso │
│ n_id = latest.max_season_id │
│ JOIN realms r ON p.realm_id = r.id │
│ ORDER BY pp.global_ranking ASC, p.na │
│ me ASC │
│ `) │
│ if err != nil { │
│ return err │
│ } │
│ defer rows.Close() │
│ │
│ shard := 0 │
│ count := 0 │
│ buf := []SearchEntry{} │
│ │
│ flush := func() error { │
│ if len(buf) == 0 { │
│ return nil │
│ } │
│ path := filepath.Join(out, fmt.Sprintf("pl │
│ ayers-%03d.json", shard)) │
│ meta := map[string]any{ │
│ "total_players": totalPlayers, │
│ "returned_players": len(buf), │
│ "offset": shard * shardSize, │
│ "limit": shardSize, │
│ "last_updated": time.Now().Format(tim │
│ e.RFC3339), │
│ } │
│ if err := writer.WriteJSONFileCompact(path │
│ , map[string]any{"players": buf, "metadata": │
│ meta}); err != nil { │
│ return err │
│ } │
│ shard++ │
│ buf = buf[:0] │
│ return nil │
│ } │
│ │
│ for rows.Next() { │
│ var e SearchEntry │
│ var className sql.NullString │
│ var gr sql.NullInt64 │
│ var gb string │
│ if err := rows.Scan(&e.ID, &e.Name, &e.Reg │
│ ion, &e.RealmSlug, &e.RealmName, &className, │
│ &gr, &gb); err != nil { │
│ return err │
│ } │
│ e.ClassName = className.String │
│ e.GlobalBracket = gb │
│ if gr.Valid { │
│ v := int(gr.Int64) │
│ e.GlobalRanking = &v │
│ } │
│ buf = append(buf, e) │
│ count++ │
│ if len(buf) >= shardSize { │
│ if err := flush(); err != nil { │
│ return err │
│ } │
│ } │
│ } │
│ │
│ if err := rows.Err(); err != nil { │
│ return err │
│ } │
│ if err := flush(); err != nil { │
│ return err │
│ } │
│ │
│ fmt.Printf("[OK] Generated search index: %d │
│ players in %d shards\n", count, shard) │
│ return nil │
│ } │
└──────────────────────────────────────────────┘