package snake import ( "context" "github.com/ryanhamamura/c4/db/repository" "github.com/ryanhamamura/c4/player" "github.com/rs/zerolog/log" ) func (si *SnakeGameInstance) save() error { err := saveSnakeGame(si.queries, si.game) if err != nil { log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake game") } return err } func (si *SnakeGameInstance) savePlayer(player *Player) error { err := saveSnakePlayer(si.queries, si.game.ID, player) if err != nil { log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake player") } return err } // saveSnakeGame persists the snake game state via upsert. func saveSnakeGame(queries *repository.Queries, sg *SnakeGame) error { boardJSON := "{}" var gridWidth, gridHeight *int64 if sg.State != nil { boardJSON = sg.State.ToJSON() w, h := int64(sg.State.Width), int64(sg.State.Height) gridWidth, gridHeight = &w, &h } var winnerUserID *string if sg.Winner != nil && sg.Winner.UserID != nil { winnerUserID = sg.Winner.UserID } return queries.UpsertSnakeGame(context.Background(), repository.UpsertSnakeGameParams{ ID: sg.ID, Board: boardJSON, Status: int64(sg.Status), GridWidth: gridWidth, GridHeight: gridHeight, GameMode: int64(sg.Mode), SnakeSpeed: int64(sg.Speed), WinnerUserID: winnerUserID, RematchGameID: sg.RematchGameID, Score: int64(sg.Score), }) } func saveSnakePlayer(queries *repository.Queries, gameID string, player *Player) error { var userID, guestPlayerID *string if player.UserID != nil { userID = player.UserID } else { id := string(player.ID) guestPlayerID = &id } return queries.CreateSnakePlayer(context.Background(), repository.CreateSnakePlayerParams{ GameID: gameID, UserID: userID, GuestPlayerID: guestPlayerID, Nickname: player.Nickname, Color: int64(player.Slot + 1), Slot: int64(player.Slot), }) } func loadSnakeGame(queries *repository.Queries, id string) (*SnakeGame, error) { row, err := queries.GetSnakeGame(context.Background(), id) if err != nil { return nil, err } return snakeGameFromRow(row) } func loadSnakePlayers(queries *repository.Queries, id string) ([]*Player, error) { rows, err := queries.GetSnakePlayers(context.Background(), id) if err != nil { return nil, err } return snakePlayersFromRows(rows), nil } // Domain ↔ DB mapping helpers. func snakeGameFromRow(row *repository.Game) (*SnakeGame, error) { state, err := GameStateFromJSON(row.Board) if err != nil { state = &GameState{} } if row.GridWidth != nil { state.Width = int(*row.GridWidth) } if row.GridHeight != nil { state.Height = int(*row.GridHeight) } sg := &SnakeGame{ ID: row.ID, State: state, Players: make([]*Player, 8), Status: Status(row.Status), Mode: GameMode(row.GameMode), Score: int(row.Score), Speed: int(row.SnakeSpeed), } if row.RematchGameID != nil { sg.RematchGameID = row.RematchGameID } return sg, nil } func snakePlayersFromRows(rows []*repository.GamePlayer) []*Player { players := make([]*Player, 0, len(rows)) for _, row := range rows { p := &Player{ Nickname: row.Nickname, Slot: int(row.Slot), } 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 }