package repo import ( "database/sql" "fmt" "time" "git.kapelle.org/niklas/beerpong-elo/internal/model" _ "github.com/go-sql-driver/mysql" ) type SQLRepo struct { db *sql.DB } func NewSQLRepo(host, username, password, dbName string) (Repo, error) { db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true", username, password, host, dbName)) if err != nil { return nil, err } db.SetConnMaxLifetime(time.Minute * 3) db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) return &SQLRepo{ db: db, }, nil } func (s *SQLRepo) AddGame(game model.Game) (model.GameID, error) { stmt, err := s.db.Prepare("INSERT INTO Games(added,score,overtime,author,team0player0,team0player1,team1player0,team1player1) VALUES (?,?,?,?,?,?,?,?)") if err != nil { return "", err } res, err := stmt.Exec(game.Added, game.Score, game.Overtime, game.Author, game.Team0Player0, game.Team0Player1, game.Team1Player0, game.Team1Player1) if err != nil { return "", err } id, err := res.LastInsertId() if err != nil { return "", err } var gameID model.GameID gameID.Scan(id) return gameID, nil } func (s *SQLRepo) AddGameResult(gameResult model.GameResult) (model.GameResultID, error) { stms, err := s.db.Prepare("INSERT INTO GameResults(game,player,startElo,endElo) VALUES (?,?,?,?)") if err != nil { return "", err } res, err := stms.Exec(gameResult.Game, gameResult.Player, gameResult.StartElo, gameResult.EndElo) if err != nil { return "", err } id, err := res.LastInsertId() if err != nil { return "", err } var gameResultID model.GameResultID gameResultID.Scan(id) return gameResultID, nil } func (s *SQLRepo) GetGame(id model.GameID) (*model.Game, error) { rows := s.db.QueryRow("SELECT id,added, score,overtime,author,team0player0,team0player1,team1player0,team1player1 FROM Games WHERE id = ? ", id) var game model.Game if err := rows.Scan(&game.ID, &game.Added, &game.Score, &game.Overtime, &game.Author, &game.Team0Player0, &game.Team0Player1, &game.Team1Player0, &game.Team1Player1); err != nil { if err == sql.ErrNoRows { return nil, nil } return nil, err } return &game, nil } func (s *SQLRepo) GetGameResult(id model.GameResultID) (*model.GameResult, error) { rows := s.db.QueryRow("SELECT game,player,startElo,endElo FROM GameResults WHERE id = ? ", id) var gameResult model.GameResult gameResult.ID = id if err := rows.Scan(&gameResult.Game, &gameResult.Player, &gameResult.StartElo, &gameResult.EndElo); err != nil { if err == sql.ErrNoRows { return nil, nil } return nil, err } return &gameResult, nil } func (s *SQLRepo) playerWithNameExists(name string) (*model.PlayerID, error) { rows := s.db.QueryRow("SELECT id FROM Players WHERE name = ?", name) var id model.PlayerID if err := rows.Scan(&id); err != nil { if err == sql.ErrNoRows { return nil, nil } return nil, err } return &id, nil } func (s *SQLRepo) GetOrCreatePlayerID(name string) (model.PlayerID, error) { foundID, err := s.playerWithNameExists(name) if err != nil { return "", err } if foundID != nil { return *foundID, nil } stmt, err := s.db.Prepare("INSERT INTO Players(name,elo) VALUES (?,?)") if err != nil { return "", err } newPlayer := model.NewPlayer(name) res, err := stmt.Exec(newPlayer.Name, newPlayer.Elo) if err != nil { return "", err } id, err := res.LastInsertId() if err != nil { return "", err } var playerID model.PlayerID playerID.Scan(id) return playerID, nil } func (s *SQLRepo) GetPlayer(id model.PlayerID) (*model.Player, error) { rows := s.db.QueryRow("SELECT name,elo from Players WHERE id = ?", id) var player model.Player player.ID = id if err := rows.Scan(&player.Name, &player.Elo); err != nil { if err == sql.ErrNoRows { return nil, nil } return nil, err } return &player, nil } func (s *SQLRepo) GetGamesForPlayer(id model.PlayerID) ([]*model.Game, error) { rows, err := s.db.Query(` SELECT id,added, score,overtime,author,team0player0,team0player1,team1player0,team1player1 FROM Games WHERE team0player0 = ? OR team0player1 = ? OR team1player0 = ? OR team1player1 = ? `, id, id, id, id) if err != nil { return nil, err } defer rows.Close() rtn := []*model.Game{} for rows.Next() { var game model.Game err = rows.Scan(&game.ID, &game.Added, &game.Score, &game.Overtime, &game.Author, &game.Team0Player0, &game.Team0Player1, &game.Team1Player0, &game.Team1Player1) if err != nil { return nil, err } rtn = append(rtn, &game) } return rtn, nil } func (s *SQLRepo) GetGameResultForPlayerAndGame(gameID model.GameID, playerID model.PlayerID) (*model.GameResult, error) { rows := s.db.QueryRow("SELECT id,game,player,startElo,endElo FROM GameResults WHERE game = ? AND player = ? ", gameID, playerID) var gameResult model.GameResult if err := rows.Scan(&gameResult.ID, &gameResult.Game, &gameResult.Player, &gameResult.StartElo, &gameResult.EndElo); err != nil { if err == sql.ErrNoRows { return nil, nil } return nil, err } return &gameResult, nil } func (s *SQLRepo) GetGameResultsForPlayer(id model.PlayerID) ([]*model.GameResult, error) { rows, err := s.db.Query("SELECT id,game,player,startElo,endElo FROM GameResults WHERE player = ? ", id) if err != nil { return nil, err } rtn := []*model.GameResult{} for rows.Next() { var gameResult model.GameResult err = rows.Scan(&gameResult.ID, &gameResult.Game, &gameResult.Player, &gameResult.StartElo, &gameResult.EndElo) if err != nil { return nil, err } rtn = append(rtn, &gameResult) } return rtn, nil } func (s *SQLRepo) GetPlayers() ([]*model.Player, error) { rows, err := s.db.Query("SELECT id, name, elo FROM Players") if err != nil { return nil, err } rtn := []*model.Player{} for rows.Next() { var player model.Player err = rows.Scan(&player.ID, &player.Name, &player.Elo) if err != nil { return nil, err } rtn = append(rtn, &player) } return rtn, nil } func (s *SQLRepo) GetGames() ([]*model.Game, error) { rows, err := s.db.Query("SELECT id,added, score,overtime,author,team0player0,team0player1,team1player0,team1player1 FROM Games") if err != nil { return nil, err } rtn := []*model.Game{} for rows.Next() { var game model.Game err = rows.Scan(&game.ID, &game.Added, &game.Score, &game.Overtime, &game.Author, &game.Team0Player0, &game.Team0Player1, &game.Team1Player0, &game.Team1Player1) if err != nil { return nil, err } rtn = append(rtn, &game) } return rtn, nil }