initial commit
This commit is contained in:
40
internal/repo/repo.go
Normal file
40
internal/repo/repo.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
model "git.kapelle.org/niklas/beerpong-elo/internal/model"
|
||||
)
|
||||
|
||||
type Repo interface {
|
||||
// Add a new game to the repo. ID needs to be nil on argument. PlayerID are fetched beforehand.
|
||||
AddGame(model.Game) (model.GameID, error)
|
||||
|
||||
// Get a game by ID. Returns nil if not found.
|
||||
GetGame(model.GameID) (*model.Game, error)
|
||||
|
||||
// Get ID of a player. Creates one if not found.
|
||||
GetOrCreatePlayerID(string) (model.PlayerID, error)
|
||||
|
||||
// Get player by id. Returns nil if not found.
|
||||
GetPlayer(model.PlayerID) (*model.Player, error)
|
||||
|
||||
// Adds a game result. ID needs to be nil on argument.
|
||||
AddGameResult(model.GameResult) (model.GameResultID, error)
|
||||
|
||||
// Get a game result by ID. Returns nil if not found.
|
||||
GetGameResult(model.GameResultID) (*model.GameResult, error)
|
||||
|
||||
// Get a game result for a player in a game
|
||||
GetGameResultForPlayerAndGame(model.GameID, model.PlayerID) (*model.GameResult, error)
|
||||
|
||||
// Get all game results for a player
|
||||
GetGameResultsForPlayer(model.PlayerID) ([]*model.GameResult, error)
|
||||
|
||||
// Get games for a player
|
||||
GetGamesForPlayer(model.PlayerID) ([]*model.Game, error)
|
||||
|
||||
// Get all players
|
||||
GetPlayers() ([]*model.Player, error)
|
||||
|
||||
// Get all games
|
||||
GetGames() ([]*model.Game, error)
|
||||
}
|
||||
279
internal/repo/sqlRepo.go
Normal file
279
internal/repo/sqlRepo.go
Normal file
@@ -0,0 +1,279 @@
|
||||
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
|
||||
}
|
||||
44
internal/repo/sqlSchema.sql
Normal file
44
internal/repo/sqlSchema.sql
Normal file
@@ -0,0 +1,44 @@
|
||||
CREATE TABLE Players (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
elo INT
|
||||
);
|
||||
|
||||
CREATE TABLE Games (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
added DATETIME NOT NULL,
|
||||
score INT NOT NULL,
|
||||
overtime BOOL NOT NULL,
|
||||
author INT,
|
||||
team0player0 INT,
|
||||
team0player1 INT,
|
||||
team1player0 INT,
|
||||
team1player1 INT,
|
||||
FOREIGN KEY (author) REFERENCES Players(id) on DELETE SET NULL,
|
||||
FOREIGN KEY (team0player0) REFERENCES Players(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (team0player1) REFERENCES Players(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (team1player0) REFERENCES Players(id) ON DELETE SET NULL,
|
||||
FOREIGN KEY (team1player1) REFERENCES Players(id) ON DELETE SET NULL
|
||||
);
|
||||
|
||||
CREATE TABLE GameResults (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
game INT,
|
||||
player INT,
|
||||
startElo INT,
|
||||
endElo INT,
|
||||
FOREIGN KEY (game) REFERENCES Games(id) on DELETE SET NULL,
|
||||
FOREIGN KEY (player) REFERENCES Players(id) on DELETE SET NULL
|
||||
)
|
||||
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER UpdateCurrentELO
|
||||
AFTER INSERT ON GameResults
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE Players
|
||||
SET elo = NEW.endElo
|
||||
WHERE id = NEW.player;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
Reference in New Issue
Block a user