diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-21 10:29:21 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-21 10:29:21 +0900 |
| commit | e8db174d3e464a5764a9f4bfd82172261bd50519 (patch) | |
| tree | 68cb8f0713fcc1f960a650d879232cb4c20ca6cd /backend/api/convert.go | |
| parent | 1be106ac53caa019a8912af932a43570fa8c052d (diff) | |
| download | phperkaigi-2026-albatross-e8db174d3e464a5764a9f4bfd82172261bd50519.tar.gz phperkaigi-2026-albatross-e8db174d3e464a5764a9f4bfd82172261bd50519.tar.zst phperkaigi-2026-albatross-e8db174d3e464a5764a9f4bfd82172261bd50519.zip | |
refactor(api): separate business logic into game, tournament, session packages
Extract business logic from api/handler.go into dedicated service packages:
- session: context helpers (resolves admin → api import dependency)
- game: game state, code submission, ranking, watch logic
- tournament: bracket construction and seed ordering
- api/convert.go: domain → API type conversion functions
api/handler.go is now a thin adapter that delegates to services and
maps domain errors to HTTP status codes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'backend/api/convert.go')
| -rw-r--r-- | backend/api/convert.go | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/backend/api/convert.go b/backend/api/convert.go new file mode 100644 index 0000000..f05f3bf --- /dev/null +++ b/backend/api/convert.go @@ -0,0 +1,160 @@ +package api + +import ( + "github.com/oapi-codegen/nullable" + + "albatross-2026-backend/game" + "albatross-2026-backend/tournament" +) + +func toAPIUser(p game.Player) User { + return User{ + UserID: p.UserID, + Username: p.Username, + DisplayName: p.DisplayName, + IconPath: p.IconPath, + IsAdmin: p.IsAdmin, + Label: toNullable(p.Label), + } +} + +func toAPIGame(g game.GameDetail) Game { + var startedAt *int64 + if g.StartedAt != nil { + ts := g.StartedAt.Unix() + startedAt = &ts + } + mainPlayers := make([]User, len(g.MainPlayers)) + for i, p := range g.MainPlayers { + mainPlayers[i] = toAPIUser(p) + } + return Game{ + GameID: g.GameID, + GameType: GameType(g.GameType), + IsPublic: g.IsPublic, + DisplayName: g.DisplayName, + DurationSeconds: g.DurationSeconds, + StartedAt: startedAt, + Problem: Problem{ + ProblemID: g.Problem.ProblemID, + Title: g.Problem.Title, + Description: g.Problem.Description, + Language: ProblemLanguage(g.Problem.Language), + SampleCode: g.Problem.SampleCode, + }, + MainPlayers: mainPlayers, + } +} + +func toAPILatestState(s game.LatestState) LatestGameState { + var score nullable.Nullable[int] + if s.Score != nil { + score = nullable.NewNullableWithValue(*s.Score) + } else { + score = nullable.NewNullNullable[int]() + } + var submittedAt nullable.Nullable[int64] + if s.BestScoreSubmittedAt != nil { + submittedAt = nullable.NewNullableWithValue(*s.BestScoreSubmittedAt) + } else { + submittedAt = nullable.NewNullNullable[int64]() + } + return LatestGameState{ + Code: s.Code, + Score: score, + BestScoreSubmittedAt: submittedAt, + Status: ExecutionStatus(s.Status), + } +} + +func toAPIRankingEntry(r game.RankingEntry) RankingEntry { + var code nullable.Nullable[string] + if r.Code != nil { + code = nullable.NewNullableWithValue(*r.Code) + } else { + code = nullable.NewNullNullable[string]() + } + return RankingEntry{ + Player: toAPIUser(r.Player), + Score: r.Score, + SubmittedAt: r.SubmittedAt, + Code: code, + } +} + +func toAPISubmission(s game.SubmissionDetail) Submission { + return Submission{ + SubmissionID: s.SubmissionID, + GameID: s.GameID, + Code: s.Code, + CodeSize: s.CodeSize, + Status: ExecutionStatus(s.Status), + CreatedAt: s.CreatedAt, + } +} + +func toAPITournamentUser(p tournament.Player) User { + return User{ + UserID: p.UserID, + Username: p.Username, + DisplayName: p.DisplayName, + IconPath: p.IconPath, + IsAdmin: p.IsAdmin, + Label: toNullable(p.Label), + } +} + +func toAPITournamentPlayerPtr(p *tournament.Player) *User { + if p == nil { + return nil + } + u := toAPITournamentUser(*p) + return &u +} + +func toAPITournament(t tournament.TournamentBracket) Tournament { + entries := make([]TournamentEntry, len(t.Entries)) + for i, e := range t.Entries { + entries[i] = TournamentEntry{ + User: toAPITournamentUser(e.User), + Seed: e.Seed, + } + } + matches := make([]TournamentMatch, len(t.Matches)) + for i, m := range t.Matches { + matches[i] = TournamentMatch{ + TournamentMatchID: m.TournamentMatchID, + Round: m.Round, + Position: m.Position, + GameID: m.GameID, + Player1: toAPITournamentPlayerPtr(m.Player1), + Player2: toAPITournamentPlayerPtr(m.Player2), + Player1Score: m.Player1Score, + Player2Score: m.Player2Score, + WinnerUserID: m.WinnerUserID, + IsBye: m.IsBye, + } + } + return Tournament{ + TournamentID: t.TournamentID, + DisplayName: t.DisplayName, + BracketSize: t.BracketSize, + NumRounds: t.NumRounds, + Entries: entries, + Matches: matches, + } +} + +func toNullable[T any](p *T) nullable.Nullable[T] { + if p == nil { + return nullable.NewNullNullable[T]() + } + return nullable.NewNullableWithValue(*p) +} + +func toNullableWith[T, U any](p *T, f func(T) U) nullable.Nullable[U] { + if p == nil { + return nullable.NewNullNullable[U]() + } + return nullable.NewNullableWithValue(f(*p)) +} |
