diff --git a/migrations/001_initial_schema.up.sql b/migrations/001_initial_schema.up.sql index 95deb1c..9bd3f79 100644 --- a/migrations/001_initial_schema.up.sql +++ b/migrations/001_initial_schema.up.sql @@ -86,3 +86,20 @@ CREATE TABLE journal( FOREIGN KEY (username) REFERENCES players(username) ON DELETE CASCADE, FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE ); + +CREATE TABLE player_stats ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + player_username TEXT NOT NULL UNIQUE, + games_played INTEGER NOT NULL DEFAULT 0, + games_won INTEGER NOT NULL DEFAULT 0, + games_lost INTEGER NOT NULL DEFAULT 0, + opened_opposite_words INTEGER NOT NULL DEFAULT 0, + opened_white_words INTEGER NOT NULL DEFAULT 0, + opened_black_words INTEGER NOT NULL DEFAULT 0, + mime_winrate REAL NOT NULL DEFAULT 0.0, + guesser_winrate REAL NOT NULL DEFAULT 0.0, + played_as_mime INTEGER NOT NULL DEFAULT 0, + played_as_guesser INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY (player_username) REFERENCES players(username) ON DELETE CASCADE +); + diff --git a/models/main.go b/models/main.go index 8d79035..1e7aa8f 100644 --- a/models/main.go +++ b/models/main.go @@ -138,6 +138,22 @@ type Journal struct { CreatedAt time.Time `db:"created_at"` } +type PlayerStats struct { + ID uint32 `db:"id"` + PlayerUsername string `db:"player_username"` + GamesPlayed int `db:"games_played"` + GamesWon int `db:"games_won"` + GamesLost int `db:"games_lost"` + OpenedOppositeWords int `db:"opened_opposite_words"` + OpenedWhiteWords int `db:"opened_white_words"` + OpenedBlackWords int `db:"opened_black_words"` + MimeWinrate float64 `db:"mime_winrate"` + GuesserWinrate float64 `db:"guesser_winrate"` + PlayedAsMime int `db:"played_as_mime"` + PlayedAsGuesser int `db:"played_as_guesser"` +} + + type Room struct { ID string `json:"id" db:"id"` CreatedAt time.Time `json:"created_at" db:"created_at"` diff --git a/repos/main.go b/repos/main.go index 36d9e9a..13d2b0d 100644 --- a/repos/main.go +++ b/repos/main.go @@ -2,7 +2,6 @@ package repos import ( "context" - "gralias/config" "log/slog" "os" "sync" @@ -20,6 +19,7 @@ type AllRepos interface { WordCardsRepo SettingsRepo CardMarksRepo + PlayerStatsRepo InitTx(ctx context.Context) (context.Context, *sqlx.Tx, error) Close() } @@ -32,12 +32,7 @@ type RepoProvider struct { var RP AllRepos -func init() { - cfg := config.LoadConfigOrDefault("") - // sqlite3 has lock on write, so we need to have only one connection per whole app - // https://github.com/mattn/go-sqlite3/issues/274#issuecomment-232942571 - RP = NewRepoProvider(cfg.DBPath) -} + func NewRepoProvider(pathToDB string) *RepoProvider { db, err := sqlx.Connect("sqlite3", pathToDB) diff --git a/repos/player_stats.go b/repos/player_stats.go new file mode 100644 index 0000000..4ee5d1f --- /dev/null +++ b/repos/player_stats.go @@ -0,0 +1,42 @@ +package repos + +import ( + "context" + "gralias/models" + + "github.com/jmoiron/sqlx" +) + +type PlayerStatsRepo interface { + GetPlayerStats(ctx context.Context, username string) (*models.PlayerStats, error) + UpdatePlayerStats(ctx context.Context, stats *models.PlayerStats) error + CreatePlayerStats(ctx context.Context, username string) error +} + +func (p *RepoProvider) GetPlayerStats(ctx context.Context, username string) (*models.PlayerStats, error) { + stats := &models.PlayerStats{} + err := sqlx.GetContext(ctx, p.DB, stats, "SELECT * FROM player_stats WHERE player_username = ?", username) + return stats, err +} + +func (p *RepoProvider) UpdatePlayerStats(ctx context.Context, stats *models.PlayerStats) error { + _, err := p.DB.NamedExecContext(ctx, `UPDATE player_stats SET + games_played = :games_played, + games_won = :games_won, + games_lost = :games_lost, + opened_opposite_words = :opened_opposite_words, + opened_white_words = :opened_white_words, + opened_black_words = :opened_black_words, + mime_winrate = :mime_winrate, + guesser_winrate = :guesser_winrate, + played_as_mime = :played_as_mime, + played_as_guesser = :played_as_guesser + WHERE player_username = :player_username`, stats) + return err +} + +func (p *RepoProvider) CreatePlayerStats(ctx context.Context, username string) error { + db := getDB(ctx, p.DB) + _, err := db.ExecContext(ctx, "INSERT INTO player_stats (player_username) VALUES (?)", username) + return err +}