Skip to content

Commit

Permalink
feat: use datalist with existing players when creating new game
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarow committed Dec 28, 2023
1 parent feff38c commit e84143f
Show file tree
Hide file tree
Showing 9 changed files with 421 additions and 359 deletions.
7 changes: 6 additions & 1 deletion internal/api/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,12 @@ func (h Handler) EditGame(c echo.Context) error {
}

func (h Handler) GetCreateGameForm(c echo.Context) error {
form := component.CreateGameForm()
players, err := h.service.ListPlayers()
if err != nil {
c.Logger().Error(err)
return err
}
form := component.CreateGameForm(players)
return render(c, http.StatusOK, form)
}

Expand Down
234 changes: 234 additions & 0 deletions internal/skat/game.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package skat

import (
"slices"

"github.com/go-jet/jet/v2/sqlite"
"github.com/tarow/skat-counter/internal/skat/gen/model"
"github.com/tarow/skat-counter/internal/skat/gen/table"
)

func (s Service) List() ([]Game, error) {
stmt := sqlite.SELECT(
table.Game.AllColumns,
table.Player.AllColumns,
table.Round.AllColumns,
table.RoundOpponent.PlayerID.AS("opponent.id"),
).FROM(table.Game.
INNER_JOIN(table.GamePlayer, table.Game.ID.EQ(table.GamePlayer.GameID)).
INNER_JOIN(table.Player, table.Player.ID.EQ(table.GamePlayer.PlayerID)).
LEFT_JOIN(table.Round, table.Round.GameID.EQ(table.Game.ID)).
LEFT_JOIN(table.RoundOpponent, table.RoundOpponent.RoundID.EQ(table.Round.ID).AND(
table.RoundOpponent.PlayerID.EQ(table.Player.ID),
)),
).ORDER_BY(table.Game.CreatedAt.DESC(), table.GamePlayer.Rank.ASC(), table.Round.CreatedAt.ASC())

games := make([]Game, 0)
err := stmt.Query(s.db, &games)
if err != nil {
return []Game{}, err
}

return games, nil
}

func (s Service) Find(gameId int32) (*Game, error) {
stmt := sqlite.SELECT(
table.Game.AllColumns,
table.Player.AllColumns,
table.Round.AllColumns,
table.RoundOpponent.PlayerID.AS("opponent.id"),
).FROM(table.Game.
INNER_JOIN(table.GamePlayer, table.Game.ID.EQ(table.GamePlayer.GameID)).
INNER_JOIN(table.Player, table.Player.ID.EQ(table.GamePlayer.PlayerID)).
LEFT_JOIN(table.Round, table.Round.GameID.EQ(table.Game.ID)).
LEFT_JOIN(table.RoundOpponent, table.RoundOpponent.RoundID.EQ(table.Round.ID).AND(
table.RoundOpponent.PlayerID.EQ(table.Player.ID),
)),
).WHERE(table.Game.ID.EQ(sqlite.Int32(gameId))).
ORDER_BY(table.GamePlayer.Rank.ASC(), table.Round.CreatedAt.ASC())

game := Game{}
err := stmt.Query(s.db, &game)
if err != nil {
return &Game{}, err
}

return &game, nil
}

func (s Service) Create(g Game) (Game, error) {
tx, err := s.db.Begin()
if err != nil {
return Game{}, err
}

defer tx.Rollback()

// Create players if they dont exist
stmt := table.Player.
INSERT(table.Player.Name).
MODELS(g.Players).
ON_CONFLICT().DO_NOTHING().RETURNING(table.Player.AllColumns)

_, err = stmt.Exec(tx)
if err != nil {

return Game{}, err
}

// Insert game
stmt = table.Game.INSERT(
table.Game.Online,
table.Game.Stake,
table.Game.CreatedAt,
).MODEL(g)

res, err := stmt.Exec(tx)
if err != nil {
return Game{}, err
}

gameId, err := res.LastInsertId()
if err != nil {
return Game{}, err
}

playerNames := []sqlite.Expression{}
playerNamesStr := []string{}
for _, p := range g.Players {
playerNames = append(playerNames, sqlite.String(p.Name))
playerNamesStr = append(playerNamesStr, p.Name)
}

// Link players to game
selectPlayers := table.Player.SELECT(table.Player.AllColumns).
FROM(table.Player).
WHERE(table.Player.Name.IN(playerNames...))

players := make([]model.Player, 0)
err = selectPlayers.Query(tx, &players)
if err != nil {
return Game{}, err
}

gamePlayers := []model.GamePlayer{}
for _, p := range players {
gamePlayers = append(gamePlayers, model.GamePlayer{
GameID: int32(gameId),
PlayerID: p.ID,
Rank: int32(slices.Index(playerNamesStr, p.Name)),
})
}
stmt = table.GamePlayer.INSERT(table.GamePlayer.AllColumns).
MODELS(gamePlayers)
_, err = stmt.Exec(tx)
if err != nil {
return Game{}, err
}

err = tx.Commit()
if err != nil {
return Game{}, err
}

g.ID = int32(gameId)
return g, nil
}

func (s Service) UpdateGame(g Game) (Game, error) {
tx, err := s.db.Begin()
if err != nil {
return Game{}, err
}
defer tx.Rollback()

stmt := table.Game.UPDATE(table.Game.Stake, table.Game.Online).
MODEL(g).
WHERE(table.Game.ID.EQ(sqlite.Int32(g.ID)))

_, err = stmt.Exec(tx)
if err != nil {
return Game{}, err
}

for rank, player := range g.Players {
stmt := table.GamePlayer.UPDATE(table.GamePlayer.Rank).
MODEL(model.GamePlayer{
GameID: g.ID,
PlayerID: player.ID,
Rank: int32(rank),
}).
WHERE(table.GamePlayer.GameID.EQ(sqlite.Int32(g.ID)).
AND(table.GamePlayer.PlayerID.EQ(sqlite.Int32(player.ID))))
_, err = stmt.Exec(tx)
if err != nil {
return Game{}, err
}
}

err = tx.Commit()
if err != nil {
return Game{}, err
}

return g, nil
}

func (s Service) DeleteGame(gameId int32) error {
tx, err := s.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()

// Delete round opponents
stmt := table.RoundOpponent.DELETE().WHERE(
table.RoundOpponent.RoundID.IN(
table.Round.SELECT(table.Round.ID).FROM(table.Round).WHERE(
table.Round.GameID.EQ(sqlite.Int32(gameId)),
),
))

_, err = stmt.Exec(tx)
if err != nil {
return err
}

//Delete rounds
stmt = table.Round.DELETE().WHERE(table.Round.GameID.EQ(sqlite.Int32(gameId)))
_, err = stmt.Exec(tx)
if err != nil {
return err
}

//Delete game players references
stmt = table.GamePlayer.DELETE().WHERE(table.GamePlayer.GameID.EQ(sqlite.Int32(gameId)))
_, err = stmt.Exec(tx)
if err != nil {
return err
}

//Delete game
stmt = table.Game.DELETE().WHERE(table.Game.ID.EQ(sqlite.Int32(gameId)))
_, err = stmt.Exec(tx)
if err != nil {
return err
}

// Delete orphan players that arent refenced in any game
stmt = table.Player.DELETE().WHERE(table.Player.ID.NOT_IN(
table.GamePlayer.SELECT(table.GamePlayer.PlayerID),
))
_, err = stmt.Exec(tx)
if err != nil {
return err
}

err = tx.Commit()
if err != nil {
return err
}

return nil
}
15 changes: 15 additions & 0 deletions internal/skat/player.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package skat

import (
"github.com/tarow/skat-counter/internal/skat/gen/model"
"github.com/tarow/skat-counter/internal/skat/gen/table"
)

func (s Service) ListPlayers() ([]model.Player, error) {
stmt := table.Player.SELECT(table.Player.AllColumns).FROM(table.Player)

var result []model.Player
err := stmt.Query(s.db, &result)

return result, err
}
127 changes: 127 additions & 0 deletions internal/skat/round.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package skat

import (
"github.com/go-jet/jet/v2/sqlite"
"github.com/tarow/skat-counter/internal/skat/gen/model"
"github.com/tarow/skat-counter/internal/skat/gen/table"
)

func (s Service) AddRound(round Round) (Round, error) {
opponents := round.Opponents

tx, err := s.db.Begin()
if err != nil {
return Round{}, err
}
defer tx.Rollback()

// Insert round
stmt := table.Round.INSERT(
table.Round.AllColumns.Except(table.Round.ID),
).MODEL(round).RETURNING(table.Round.AllColumns)

err = stmt.Query(tx, &round)
if err != nil {
return Round{}, err
}
round.Opponents = opponents

roundOpponents := make([]model.RoundOpponent, 0)
for _, opponentId := range opponents {
roundOpponents = append(roundOpponents, model.RoundOpponent{
RoundID: round.ID,
PlayerID: opponentId,
})
}
stmt = table.RoundOpponent.INSERT(
table.RoundOpponent.AllColumns,
).MODELS(roundOpponents)

_, err = stmt.Exec(tx)
if err != nil {
return Round{}, err
}

err = tx.Commit()
if err != nil {
return Round{}, err
}

return round, nil
}

func (s Service) UpdateRound(round Round) (Round, error) {
tx, err := s.db.Begin()
if err != nil {
return Round{}, err
}
defer tx.Rollback()

// Delete old opponents
deleteOpponents := table.RoundOpponent.DELETE().
WHERE(table.RoundOpponent.RoundID.EQ(sqlite.Int32(round.ID)))
_, err = deleteOpponents.Exec(tx)
if err != nil {
return Round{}, err
}

// Update round
updateRound := table.Round.UPDATE(
table.Round.AllColumns.Except(table.Round.ID, table.Round.CreatedAt),
).WHERE(table.Round.ID.EQ(sqlite.Int32(round.ID))).
MODEL(round)
_, err = updateRound.Exec(tx)
if err != nil {
return Round{}, err
}

// Insert new round opponents
roundOpponents := make([]model.RoundOpponent, 0)
for _, opponentId := range round.Opponents {
roundOpponents = append(roundOpponents, model.RoundOpponent{
RoundID: round.ID,
PlayerID: opponentId,
})
}
insertOpponents := table.RoundOpponent.INSERT(
table.RoundOpponent.AllColumns,
).MODELS(roundOpponents)

_, err = insertOpponents.Exec(tx)
if err != nil {
return Round{}, err
}

err = tx.Commit()
if err != nil {
return Round{}, err
}

return round, nil
}

func (s Service) DeleteRound(roundId int32) error {
tx, err := s.db.Begin()
if err != nil {
return err
}
defer tx.Rollback()

// Delete opponents
deleteOpponents := table.RoundOpponent.DELETE().
WHERE(table.RoundOpponent.RoundID.EQ(sqlite.Int32(roundId)))
_, err = deleteOpponents.Exec(tx)
if err != nil {
return err
}

// Delete round
deleteRound := table.Round.DELETE().
WHERE(table.Round.ID.EQ(sqlite.Int32(roundId)))
_, err = deleteRound.Exec(tx)
if err != nil {
return err
}

return tx.Commit()
}
Loading

0 comments on commit e84143f

Please sign in to comment.