initial commit

This commit is contained in:
2025-02-02 15:11:35 +01:00
commit 3640116dd5
39 changed files with 10298 additions and 0 deletions

40
internal/repo/repo.go Normal file
View 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
View 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
}

View 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 ;