- Replace Create+Get+Update with UpsertGame/UpsertSnakeGame queries - Extract free functions (saveGame, loadGame, etc.) from duplicated receiver methods on Store and Instance types - Remove duplicate generateID from snake package, reuse game.GenerateID - Throttle snake game DB writes to every 2s instead of every tick - Fix double-lock in c4game chat handler - Update all code for sqlc pointer types (*string instead of sql.NullString)
110 lines
2.5 KiB
Go
110 lines
2.5 KiB
Go
package game
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ryanhamamura/c4/db/repository"
|
|
)
|
|
|
|
// 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 {
|
|
player := &Player{
|
|
Nickname: row.Nickname,
|
|
Color: int(row.Color),
|
|
}
|
|
|
|
if row.UserID != nil {
|
|
player.UserID = row.UserID
|
|
player.ID = PlayerID(*row.UserID)
|
|
} else if row.GuestPlayerID != nil {
|
|
player.ID = PlayerID(*row.GuestPlayerID)
|
|
}
|
|
|
|
players = append(players, player)
|
|
}
|
|
return players
|
|
}
|