package game import ( "context" "github.com/ryanhamamura/c4/db/repository" "github.com/ryanhamamura/c4/player" "github.com/rs/zerolog/log" ) func (gi *GameInstance) save() error { err := saveGame(gi.queries, gi.game) if err != nil { log.Error().Err(err).Str("game_id", gi.game.ID).Msg("failed to save game") } return err } func (gi *GameInstance) savePlayer(player *Player, slot int) error { err := saveGamePlayer(gi.queries, gi.game.ID, player, slot) if err != nil { log.Error().Err(err).Str("game_id", gi.game.ID).Int("slot", slot).Msg("failed to save game player") } return err } // saveGame persists the game state via upsert. func saveGame(queries *repository.Queries, g *Game) error { var winnerUserID *string if g.Winner != nil && g.Winner.UserID != nil { winnerUserID = g.Winner.UserID } var winningCells *string if wc := g.WinningCellsToJSON(); wc != "" { winningCells = &wc } return queries.UpsertGame(context.Background(), repository.UpsertGameParams{ ID: g.ID, Board: g.BoardToJSON(), CurrentTurn: int64(g.CurrentTurn), Status: int64(g.Status), WinnerUserID: winnerUserID, WinningCells: winningCells, RematchGameID: g.RematchGameID, }) } func saveGamePlayer(queries *repository.Queries, gameID string, player *Player, slot int) error { var userID, guestPlayerID *string if player.UserID != nil { userID = player.UserID } else { id := string(player.ID) guestPlayerID = &id } return queries.CreateGamePlayer(context.Background(), repository.CreateGamePlayerParams{ GameID: gameID, UserID: userID, GuestPlayerID: guestPlayerID, Nickname: player.Nickname, Color: int64(player.Color), Slot: int64(slot), }) } func loadGame(queries *repository.Queries, id string) (*Game, error) { row, err := queries.GetGame(context.Background(), id) if err != nil { return nil, err } return gameFromRow(row) } func loadGamePlayers(queries *repository.Queries, id string) ([]*Player, error) { rows, err := queries.GetGamePlayers(context.Background(), id) if err != nil { return nil, err } return playersFromRows(rows), nil } // Domain ↔ DB mapping helpers. func gameFromRow(row *repository.Game) (*Game, error) { g := &Game{ ID: row.ID, CurrentTurn: int(row.CurrentTurn), Status: GameStatus(row.Status), } if err := g.BoardFromJSON(row.Board); err != nil { return nil, err } if row.WinningCells != nil { _ = g.WinningCellsFromJSON(*row.WinningCells) } if row.RematchGameID != nil { g.RematchGameID = row.RematchGameID } return g, nil } func playersFromRows(rows []*repository.GamePlayer) []*Player { players := make([]*Player, 0, len(rows)) for _, row := range rows { p := &Player{ Nickname: row.Nickname, Color: int(row.Color), } if row.UserID != nil { p.UserID = row.UserID p.ID = player.ID(*row.UserID) } else if row.GuestPlayerID != nil { p.ID = player.ID(*row.GuestPlayerID) } players = append(players, p) } return players }