Enha: sqlx instead of pgx
This commit is contained in:
13
go.mod
13
go.mod
@ -4,15 +4,14 @@ go 1.24
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.5.0
|
github.com/BurntSushi/toml v1.5.0
|
||||||
github.com/jackc/pgx/v5 v5.7.5
|
github.com/jmoiron/sqlx v1.4.0
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.28
|
||||||
github.com/rs/xid v1.6.0
|
github.com/rs/xid v1.6.0
|
||||||
|
github.com/stretchr/testify v1.10.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
golang.org/x/crypto v0.37.0 // indirect
|
|
||||||
golang.org/x/sync v0.13.0 // indirect
|
|
||||||
golang.org/x/text v0.24.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
35
go.sum
35
go.sum
@ -1,32 +1,25 @@
|
|||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||||
github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.28/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||||
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
|
||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
BIN
gralias.db
BIN
gralias.db
Binary file not shown.
@ -72,6 +72,10 @@ func getStateByCtx(ctx context.Context) (*models.UserState, error) {
|
|||||||
return us, nil
|
return us, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func dbCreate(fi *models.FullInfo) error{
|
||||||
|
// repo.CreateRoom()
|
||||||
|
// }
|
||||||
|
|
||||||
func saveFullInfo(fi *models.FullInfo) error {
|
func saveFullInfo(fi *models.FullInfo) error {
|
||||||
// INFO: no transactions; so case is possible where first object is updated but the second is not
|
// INFO: no transactions; so case is possible where first object is updated but the second is not
|
||||||
if err := saveState(fi.State.Username, fi.State); err != nil {
|
if err := saveState(fi.State.Username, fi.State); err != nil {
|
||||||
|
@ -43,6 +43,10 @@ func HandleCreateRoom(w http.ResponseWriter, r *http.Request) {
|
|||||||
fi.State.RoomID = room.ID
|
fi.State.RoomID = room.ID
|
||||||
fi.Room = room
|
fi.Room = room
|
||||||
fi.Room.IsPublic = true // hardcode for local test; move to form
|
fi.Room.IsPublic = true // hardcode for local test; move to form
|
||||||
|
if err := repo.CreateRoom(r.Context(), room); err != nil {
|
||||||
|
abortWithError(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := saveFullInfo(fi); err != nil {
|
if err := saveFullInfo(fi); err != nil {
|
||||||
msg := "failed to set current room to session"
|
msg := "failed to set current room to session"
|
||||||
log.Error(msg, "error", err)
|
log.Error(msg, "error", err)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"gralias/config"
|
"gralias/config"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
"gralias/pkg/cache"
|
"gralias/pkg/cache"
|
||||||
|
"gralias/repos"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -17,6 +18,7 @@ var (
|
|||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
memcache cache.Cache
|
memcache cache.Cache
|
||||||
Notifier *broker.Broker
|
Notifier *broker.Broker
|
||||||
|
repo repos.AllRepos
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -30,6 +32,7 @@ func init() {
|
|||||||
cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval
|
cache.MemCache.StartBackupRoutine(15 * time.Second) // Reduced backup interval
|
||||||
// bot loader
|
// bot loader
|
||||||
// check the rooms if it has bot_{digits} in them, create bots if have
|
// check the rooms if it has bot_{digits} in them, create bots if have
|
||||||
|
repo = repos.NewRepoProvider("sqlite3://../gralias.db")
|
||||||
recoverBots()
|
recoverBots()
|
||||||
// if player has a roomID, but no team and role, try to recover
|
// if player has a roomID, but no team and role, try to recover
|
||||||
recoverPlayers()
|
recoverPlayers()
|
||||||
@ -57,7 +60,11 @@ func HandleHome(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fi != nil && fi.Room == nil {
|
if fi != nil && fi.Room == nil {
|
||||||
fi.List = listRooms(false)
|
rooms, err := repo.ListRooms(r.Context())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("failed to list rooms;", "error", err)
|
||||||
|
}
|
||||||
|
fi.List = rooms
|
||||||
}
|
}
|
||||||
if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil {
|
if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil {
|
||||||
log.Error("failed to exec templ;", "error", err, "templ", "base")
|
log.Error("failed to exec templ;", "error", err, "templ", "base")
|
||||||
|
0
handlers/sqlite:gralias.db
Normal file
0
handlers/sqlite:gralias.db
Normal file
@ -54,9 +54,9 @@ func StartTurnTimer(roomID string, duration time.Duration) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
room.Settings.TurnSecondsLeft--
|
room.Settings.TurnSecondsLeft--
|
||||||
if err := saveRoom(room); err != nil {
|
// if err := saveRoom(room); err != nil {
|
||||||
log.Error("failed to save room", "error", err)
|
// log.Error("failed to save room", "error", err)
|
||||||
}
|
// }
|
||||||
notify(models.NotifyRoomUpdatePrefix+room.ID, "")
|
notify(models.NotifyRoomUpdatePrefix+room.ID, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,8 @@ type Action struct {
|
|||||||
Word string `json:"word" db:"word"`
|
Word string `json:"word" db:"word"`
|
||||||
WordColor string `json:"word_color" db:"word_color"`
|
WordColor string `json:"word_color" db:"word_color"`
|
||||||
Number string `json:"number_associated" db:"number_associated"`
|
Number string `json:"number_associated" db:"number_associated"`
|
||||||
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
CreatedAt time.Time `json:"created_at" db:"-"`
|
||||||
|
CreatedAtUnix int64 `db:"created_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
|
@ -3,8 +3,7 @@ package repos
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
|
"time"
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ActionsRepo interface {
|
type ActionsRepo interface {
|
||||||
@ -15,32 +14,33 @@ type ActionsRepo interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) ListActions(ctx context.Context, roomID string) ([]models.Action, error) {
|
func (p *RepoProvider) ListActions(ctx context.Context, roomID string) ([]models.Action, error) {
|
||||||
rows, err := p.DB.Query(ctx, `SELECT actor, actor_color, action_type, word, word_color, number_associated FROM actions WHERE room_id = $1 ORDER BY created_at ASC`, roomID)
|
actions := []models.Action{}
|
||||||
|
err := p.DB.SelectContext(ctx, &actions, `SELECT actor, actor_color, action_type, word, word_color, number_associated, created_at FROM actions WHERE room_id = ? ORDER BY created_at ASC`, roomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return pgx.CollectRows(rows, pgx.RowToStructByName[models.Action])
|
for i := range actions {
|
||||||
|
actions[i].CreatedAt = time.Unix(0, actions[i].CreatedAtUnix)
|
||||||
|
}
|
||||||
|
return actions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) CreateAction(ctx context.Context, roomID string, a *models.Action) error {
|
func (p *RepoProvider) CreateAction(ctx context.Context, roomID string, a *models.Action) error {
|
||||||
_, err := p.DB.Exec(ctx, `INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated) VALUES ($1, $2, $3, $4, $5, $6, $7)`,
|
_, err := p.DB.ExecContext(ctx, `INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, a.Actor, a.ActorColor, a.Action, a.Word, a.WordColor, a.Number, a.CreatedAt.UnixNano())
|
||||||
roomID, a.Actor, a.ActorColor, a.Action, a.Word, a.WordColor, a.Number)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) GetLastClue(ctx context.Context, roomID string) (*models.Action, error) {
|
func (p *RepoProvider) GetLastClue(ctx context.Context, roomID string) (*models.Action, error) {
|
||||||
rows, err := p.DB.Query(ctx, `SELECT actor, actor_color, action_type, word, word_color, number_associated FROM actions WHERE room_id = $1 AND action_type = 'gave_clue' ORDER BY created_at DESC LIMIT 1`, roomID)
|
action := &models.Action{}
|
||||||
|
err := p.DB.GetContext(ctx, action, `SELECT actor, actor_color, action_type, word, word_color, number_associated, created_at FROM actions WHERE room_id = ? AND action_type = 'gave_clue' ORDER BY created_at DESC LIMIT 1`, roomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
action, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[models.Action])
|
action.CreatedAt = time.Unix(0, action.CreatedAtUnix)
|
||||||
if err != nil {
|
return action, nil
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &action, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) DeleteActionsByRoomID(ctx context.Context, roomID string) error {
|
func (p *RepoProvider) DeleteActionsByRoomID(ctx context.Context, roomID string) error {
|
||||||
_, err := p.DB.Exec(ctx, `DELETE FROM actions WHERE room_id = $1`, roomID)
|
_, err := p.DB.ExecContext(ctx, `DELETE FROM actions WHERE room_id = ?`, roomID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
177
repos/actions_test.go
Normal file
177
repos/actions_test.go
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
package repos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"gralias/models"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupActionsTestDB(t *testing.T) (*sqlx.DB, func()) {
|
||||||
|
db, err := sqlx.Connect("sqlite3", ":memory:")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS actions (
|
||||||
|
room_id TEXT,
|
||||||
|
actor TEXT,
|
||||||
|
actor_color TEXT,
|
||||||
|
action_type TEXT,
|
||||||
|
word TEXT,
|
||||||
|
word_color TEXT,
|
||||||
|
number_associated TEXT,
|
||||||
|
created_at INTEGER
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
return db, func() {
|
||||||
|
db.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActionsRepo_CreateAction(t *testing.T) {
|
||||||
|
db, teardown := setupActionsTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
roomID := "test_room_actions_1"
|
||||||
|
action := &models.Action{
|
||||||
|
Actor: "player1",
|
||||||
|
ActorColor: "blue",
|
||||||
|
Action: "gave_clue",
|
||||||
|
Word: "apple",
|
||||||
|
WordColor: "red",
|
||||||
|
Number: "3",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := repo.CreateAction(context.Background(), roomID, action)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var retrievedAction models.Action
|
||||||
|
err = db.Get(&retrievedAction, "SELECT * FROM actions WHERE room_id = ? AND actor = ?", roomID, action.Actor)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, action.Word, retrievedAction.Word)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActionsRepo_ListActions(t *testing.T) {
|
||||||
|
db, teardown := setupActionsTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
roomID := "test_room_actions_2"
|
||||||
|
action1 := &models.Action{
|
||||||
|
Actor: "player1",
|
||||||
|
ActorColor: "blue",
|
||||||
|
Action: "gave_clue",
|
||||||
|
Word: "apple",
|
||||||
|
WordColor: "red",
|
||||||
|
Number: "3",
|
||||||
|
CreatedAt: time.Now().Add(-2 * time.Second),
|
||||||
|
}
|
||||||
|
action2 := &models.Action{
|
||||||
|
Actor: "player2",
|
||||||
|
ActorColor: "red",
|
||||||
|
Action: "guessed",
|
||||||
|
Word: "banana",
|
||||||
|
WordColor: "blue",
|
||||||
|
Number: "0",
|
||||||
|
CreatedAt: time.Now().Add(-1 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action1.Actor, action1.ActorColor, action1.Action, action1.Word, action1.WordColor, action1.Number, action1.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action2.Actor, action2.ActorColor, action2.Action, action2.Word, action2.WordColor, action2.Number, action2.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
actions, err := repo.ListActions(context.Background(), roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, actions, 2)
|
||||||
|
assert.Equal(t, action1.Word, actions[0].Word)
|
||||||
|
assert.Equal(t, action2.Word, actions[1].Word)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActionsRepo_GetLastClue(t *testing.T) {
|
||||||
|
db, teardown := setupActionsTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
roomID := "test_room_actions_3"
|
||||||
|
action1 := &models.Action{
|
||||||
|
Actor: "player1",
|
||||||
|
ActorColor: "blue",
|
||||||
|
Action: "gave_clue",
|
||||||
|
Word: "apple",
|
||||||
|
WordColor: "red",
|
||||||
|
Number: "3",
|
||||||
|
CreatedAt: time.Now().Add(-3 * time.Second),
|
||||||
|
}
|
||||||
|
action2 := &models.Action{
|
||||||
|
Actor: "player2",
|
||||||
|
ActorColor: "red",
|
||||||
|
Action: "gave_clue",
|
||||||
|
Word: "banana",
|
||||||
|
WordColor: "blue",
|
||||||
|
Number: "2",
|
||||||
|
CreatedAt: time.Now().Add(-2 * time.Second),
|
||||||
|
}
|
||||||
|
// Non-clue action
|
||||||
|
action3 := &models.Action{
|
||||||
|
Actor: "player3",
|
||||||
|
ActorColor: "blue",
|
||||||
|
Action: "guessed",
|
||||||
|
Word: "orange",
|
||||||
|
WordColor: "blue",
|
||||||
|
Number: "0",
|
||||||
|
CreatedAt: time.Now().Add(-1 * time.Second),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action1.Actor, action1.ActorColor, action1.Action, action1.Word, action1.WordColor, action1.Number, action1.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action2.Actor, action2.ActorColor, action2.Action, action2.Word, action2.WordColor, action2.Number, action2.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action3.Actor, action3.ActorColor, action3.Action, action3.Word, action3.WordColor, action3.Number, action3.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
lastClue, err := repo.GetLastClue(context.Background(), roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, lastClue)
|
||||||
|
assert.Equal(t, action2.Word, lastClue.Word)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestActionsRepo_DeleteActionsByRoomID(t *testing.T) {
|
||||||
|
db, teardown := setupActionsTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
roomID := "test_room_actions_4"
|
||||||
|
action1 := &models.Action{
|
||||||
|
Actor: "player1",
|
||||||
|
ActorColor: "blue",
|
||||||
|
Action: "gave_clue",
|
||||||
|
Word: "apple",
|
||||||
|
WordColor: "red",
|
||||||
|
Number: "3",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
_, err := db.Exec(`INSERT INTO actions (room_id, actor, actor_color, action_type, word, word_color, number_associated, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, roomID, action1.Actor, action1.ActorColor, action1.Action, action1.Word, action1.WordColor, action1.Number, action1.CreatedAt.UnixNano())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = repo.DeleteActionsByRoomID(context.Background(), roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM actions WHERE room_id = ?", roomID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
@ -1,11 +1,11 @@
|
|||||||
package repos
|
package repos
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jmoiron/sqlx"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AllRepos interface {
|
type AllRepos interface {
|
||||||
@ -15,17 +15,17 @@ type AllRepos interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RepoProvider struct {
|
type RepoProvider struct {
|
||||||
DB *pgxpool.Pool
|
DB *sqlx.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRepoProvider(pathToDB string) *RepoProvider {
|
func NewRepoProvider(pathToDB string) *RepoProvider {
|
||||||
dbpool, err := pgxpool.New(context.Background(), pathToDB)
|
db, err := sqlx.Connect("sqlite3", pathToDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Unable to connect to database", "error", err)
|
slog.Error("Unable to connect to database", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
slog.Info("Successfully connected to database")
|
slog.Info("Successfully connected to database")
|
||||||
return &RepoProvider{
|
return &RepoProvider{
|
||||||
DB: dbpool,
|
DB: db,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
repos/main_test.go
Normal file
24
repos/main_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package repos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewRepoProvider(t *testing.T) {
|
||||||
|
// Create a temporary SQLite database file for testing
|
||||||
|
tmpDBFile := "./test_gralias.db"
|
||||||
|
defer os.Remove(tmpDBFile) // Clean up the temporary file after the test
|
||||||
|
|
||||||
|
// Initialize a new RepoProvider
|
||||||
|
repoProvider := NewRepoProvider(tmpDBFile)
|
||||||
|
|
||||||
|
// Assert that the DB connection is not nil
|
||||||
|
assert.NotNil(t, repoProvider.DB, "DB connection should not be nil")
|
||||||
|
|
||||||
|
// Close the database connection
|
||||||
|
err := repoProvider.DB.Close()
|
||||||
|
assert.NoError(t, err, "Error closing database connection")
|
||||||
|
}
|
@ -13,7 +13,7 @@ type PlayersRepo interface {
|
|||||||
|
|
||||||
func (p *RepoProvider) GetPlayer(roomID, username string) (*models.Player, error) {
|
func (p *RepoProvider) GetPlayer(roomID, username string) (*models.Player, error) {
|
||||||
var player models.Player
|
var player models.Player
|
||||||
err := p.DB.QueryRow(context.Background(), "SELECT id, room_id, username, team, role, is_bot FROM players WHERE room_id = $1 AND username = $2", roomID, username).Scan(&player.ID, &player.RoomID, &player.Username, &player.Team, &player.Role, &player.IsBot)
|
err := p.DB.GetContext(context.Background(), &player, "SELECT id, room_id, username, team, role, is_bot FROM players WHERE room_id = ? AND username = ?", roomID, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -21,11 +21,11 @@ func (p *RepoProvider) GetPlayer(roomID, username string) (*models.Player, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) AddPlayer(player *models.Player) error {
|
func (p *RepoProvider) AddPlayer(player *models.Player) error {
|
||||||
_, err := p.DB.Exec(context.Background(), "INSERT INTO players (room_id, username, team, role, is_bot) VALUES ($1, $2, $3, $4, $5)", player.RoomID, player.Username, player.Team, player.Role, player.IsBot)
|
_, err := p.DB.ExecContext(context.Background(), "INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)", player.RoomID, player.Username, player.Team, player.Role, player.IsBot)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) DeletePlayer(roomID, username string) error {
|
func (p *RepoProvider) DeletePlayer(roomID, username string) error {
|
||||||
_, err := p.DB.Exec(context.Background(), "DELETE FROM players WHERE room_id = $1 AND username = $2", roomID, username)
|
_, err := p.DB.ExecContext(context.Background(), "DELETE FROM players WHERE room_id = ? AND username = ?", roomID, username)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
104
repos/players_test.go
Normal file
104
repos/players_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package repos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gralias/models"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupPlayersTestDB(t *testing.T) (*sqlx.DB, func()) {
|
||||||
|
db, err := sqlx.Connect("sqlite3", ":memory:")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS players (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
room_id TEXT,
|
||||||
|
username TEXT,
|
||||||
|
team TEXT,
|
||||||
|
role TEXT,
|
||||||
|
is_bot BOOLEAN
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
return db, func() {
|
||||||
|
db.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlayersRepo_AddPlayer(t *testing.T) {
|
||||||
|
db, teardown := setupPlayersTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
player := &models.Player{
|
||||||
|
RoomID: "test_room_player_1",
|
||||||
|
Username: "test_player_1",
|
||||||
|
Team: "blue",
|
||||||
|
Role: "player",
|
||||||
|
IsBot: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := repo.AddPlayer(player)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var retrievedPlayer models.Player
|
||||||
|
err = db.Get(&retrievedPlayer, "SELECT * FROM players WHERE room_id = ? AND username = ?", player.RoomID, player.Username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, player.Username, retrievedPlayer.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlayersRepo_GetPlayer(t *testing.T) {
|
||||||
|
db, teardown := setupPlayersTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
player := &models.Player{
|
||||||
|
RoomID: "test_room_player_2",
|
||||||
|
Username: "test_player_2",
|
||||||
|
Team: "red",
|
||||||
|
Role: "player",
|
||||||
|
IsBot: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)`, player.RoomID, player.Username, player.Team, player.Role, player.IsBot)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
retrievedPlayer, err := repo.GetPlayer(player.RoomID, player.Username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, retrievedPlayer)
|
||||||
|
assert.Equal(t, player.Username, retrievedPlayer.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlayersRepo_DeletePlayer(t *testing.T) {
|
||||||
|
db, teardown := setupPlayersTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
player := &models.Player{
|
||||||
|
RoomID: "test_room_player_3",
|
||||||
|
Username: "test_player_3",
|
||||||
|
Team: "blue",
|
||||||
|
Role: "player",
|
||||||
|
IsBot: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO players (room_id, username, team, role, is_bot) VALUES (?, ?, ?, ?, ?)`, player.RoomID, player.Username, player.Team, player.Role, player.IsBot)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = repo.DeletePlayer(player.RoomID, player.Username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM players WHERE room_id = ? AND username = ?", player.RoomID, player.Username)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
@ -3,24 +3,19 @@ package repos
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"gralias/models"
|
"gralias/models"
|
||||||
|
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type RoomsRepo interface {
|
type RoomsRepo interface {
|
||||||
ListRooms(ctx context.Context) ([]models.Room, error)
|
ListRooms(ctx context.Context) ([]*models.Room, error)
|
||||||
GetRoomByID(ctx context.Context, id string) (*models.Room, error)
|
GetRoomByID(ctx context.Context, id string) (*models.Room, error)
|
||||||
CreateRoom(ctx context.Context, room *models.Room) error
|
CreateRoom(ctx context.Context, room *models.Room) error
|
||||||
DeleteRoomByID(ctx context.Context, id string) error
|
DeleteRoomByID(ctx context.Context, id string) error
|
||||||
UpdateRoom(ctx context.Context, room *models.Room) error
|
UpdateRoom(ctx context.Context, room *models.Room) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) ListRooms(ctx context.Context) ([]models.Room, error) {
|
func (p *RepoProvider) ListRooms(ctx context.Context) ([]*models.Room, error) {
|
||||||
rows, err := p.DB.Query(ctx, `SELECT * FROM rooms`)
|
rooms := []*models.Room{}
|
||||||
if err != nil {
|
err := p.DB.SelectContext(ctx, &rooms, `SELECT * FROM rooms`)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rooms, err := pgx.CollectRows(rows, pgx.RowToStructByName[models.Room])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -28,28 +23,25 @@ func (p *RepoProvider) ListRooms(ctx context.Context) ([]models.Room, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) GetRoomByID(ctx context.Context, id string) (*models.Room, error) {
|
func (p *RepoProvider) GetRoomByID(ctx context.Context, id string) (*models.Room, error) {
|
||||||
rows, err := p.DB.Query(ctx, `SELECT * FROM rooms WHERE id = $1`, id)
|
room := &models.Room{}
|
||||||
|
err := p.DB.GetContext(ctx, room, `SELECT * FROM rooms WHERE id = ?`, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
room, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[models.Room])
|
return room, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &room, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) CreateRoom(ctx context.Context, r *models.Room) error {
|
func (p *RepoProvider) CreateRoom(ctx context.Context, r *models.Room) error {
|
||||||
_, err := p.DB.Exec(ctx, `INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`, r.ID, r.CreatedAt, r.CreatorName, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsPublic, r.IsRunning, r.Language, r.RoundTime, r.IsOver, r.TeamWon, r.Settings.RoomPass)
|
_, err := p.DB.ExecContext(ctx, `INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, r.ID, r.CreatedAt, r.CreatorName, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsPublic, r.IsRunning, r.Language, r.RoundTime, r.IsOver, r.TeamWon, r.RoomPass)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) DeleteRoomByID(ctx context.Context, id string) error {
|
func (p *RepoProvider) DeleteRoomByID(ctx context.Context, id string) error {
|
||||||
_, err := p.DB.Exec(ctx, `DELETE FROM rooms WHERE id = $1`, id)
|
_, err := p.DB.ExecContext(ctx, `DELETE FROM rooms WHERE id = ?`, id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *RepoProvider) UpdateRoom(ctx context.Context, r *models.Room) error {
|
func (p *RepoProvider) UpdateRoom(ctx context.Context, r *models.Room) error {
|
||||||
_, err := p.DB.Exec(ctx, `UPDATE rooms SET team_turn = $1, this_turn_limit = $2, opened_this_turn = $3, blue_counter = $4, red_counter = $5, red_turn = $6, mime_done = $7, is_public = $8, is_running = $9, language = $10, round_time = $11, is_over = $12, team_won = $13, room_pass = $14 WHERE id = $15`, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsPublic, r.IsRunning, r.Language, r.RoundTime, r.IsOver, r.TeamWon, r.Settings.RoomPass, r.ID)
|
_, err := p.DB.ExecContext(ctx, `UPDATE rooms SET team_turn = ?, this_turn_limit = ?, opened_this_turn = ?, blue_counter = ?, red_counter = ?, red_turn = ?, mime_done = ?, is_public = ?, is_running = ?, language = ?, round_time = ?, is_over = ?, team_won = ?, room_pass = ? WHERE id = ?`, r.TeamTurn, r.ThisTurnLimit, r.OpenedThisTurn, r.BlueCounter, r.RedCounter, r.RedTurn, r.MimeDone, r.IsPublic, r.IsRunning, r.Language, r.RoundTime, r.IsOver, r.TeamWon, r.RoomPass, r.ID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
254
repos/rooms_test.go
Normal file
254
repos/rooms_test.go
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package repos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"gralias/models"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupTestDB(t *testing.T) (*sqlx.DB, func()) {
|
||||||
|
db, err := sqlx.Connect("sqlite3", ":memory:")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
schema := `
|
||||||
|
CREATE TABLE IF NOT EXISTS rooms (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
created_at DATETIME,
|
||||||
|
creator_name TEXT,
|
||||||
|
team_turn TEXT,
|
||||||
|
this_turn_limit INTEGER,
|
||||||
|
opened_this_turn INTEGER,
|
||||||
|
blue_counter INTEGER,
|
||||||
|
red_counter INTEGER,
|
||||||
|
red_turn BOOLEAN,
|
||||||
|
mime_done BOOLEAN,
|
||||||
|
is_public BOOLEAN,
|
||||||
|
is_running BOOLEAN,
|
||||||
|
language TEXT,
|
||||||
|
round_time INTEGER,
|
||||||
|
is_over BOOLEAN,
|
||||||
|
team_won TEXT,
|
||||||
|
room_pass TEXT
|
||||||
|
);
|
||||||
|
`
|
||||||
|
_, err = db.Exec(schema)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
return db, func() {
|
||||||
|
db.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoomsRepo_CreateRoom(t *testing.T) {
|
||||||
|
db, teardown := setupTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
room := &models.Room{
|
||||||
|
ID: "test_room_1",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "test_creator",
|
||||||
|
TeamTurn: "blue",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: false,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := repo.CreateRoom(context.Background(), room)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify the room was created
|
||||||
|
var retrievedRoom models.Room
|
||||||
|
err = db.Get(&retrievedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, room.ID, retrievedRoom.ID)
|
||||||
|
assert.Equal(t, room.CreatorName, retrievedRoom.CreatorName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoomsRepo_GetRoomByID(t *testing.T) {
|
||||||
|
db, teardown := setupTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
room := &models.Room{
|
||||||
|
ID: "test_room_2",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "test_creator_2",
|
||||||
|
TeamTurn: "red",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: true,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert a room directly into the database for testing GetRoomByID
|
||||||
|
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsPublic, room.IsRunning, room.Language, room.RoundTime, room.IsOver, room.TeamWon, room.RoomPass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
retrievedRoom, err := repo.GetRoomByID(context.Background(), room.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, retrievedRoom)
|
||||||
|
assert.Equal(t, room.ID, retrievedRoom.ID)
|
||||||
|
assert.Equal(t, room.CreatorName, retrievedRoom.CreatorName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoomsRepo_ListRooms(t *testing.T) {
|
||||||
|
db, teardown := setupTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
room1 := &models.Room{
|
||||||
|
ID: "list_room_1",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "list_creator_1",
|
||||||
|
TeamTurn: "blue",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: false,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
room2 := &models.Room{
|
||||||
|
ID: "list_room_2",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "list_creator_2",
|
||||||
|
TeamTurn: "red",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: true,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room1.ID, room1.CreatedAt, room1.CreatorName, room1.TeamTurn, room1.ThisTurnLimit, room1.OpenedThisTurn, room1.BlueCounter, room1.RedCounter, room1.RedTurn, room1.MimeDone, room1.IsPublic, room1.IsRunning, room1.Language, room1.RoundTime, room1.IsOver, room1.TeamWon, room1.RoomPass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room2.ID, room2.CreatedAt, room2.CreatorName, room2.TeamTurn, room2.ThisTurnLimit, room2.OpenedThisTurn, room2.BlueCounter, room2.RedCounter, room2.RedTurn, room2.MimeDone, room2.IsPublic, room2.IsRunning, room2.Language, room2.RoundTime, room2.IsOver, room2.TeamWon, room2.RoomPass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
rooms, err := repo.ListRooms(context.Background())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, rooms, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoomsRepo_DeleteRoomByID(t *testing.T) {
|
||||||
|
db, teardown := setupTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
room := &models.Room{
|
||||||
|
ID: "delete_room_1",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "delete_creator_1",
|
||||||
|
TeamTurn: "blue",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: false,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsPublic, room.IsRunning, room.Language, room.RoundTime, room.IsOver, room.TeamWon, room.RoomPass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = repo.DeleteRoomByID(context.Background(), room.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var count int
|
||||||
|
err = db.Get(&count, "SELECT COUNT(*) FROM rooms WHERE id = ?", room.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRoomsRepo_UpdateRoom(t *testing.T) {
|
||||||
|
db, teardown := setupTestDB(t)
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
repo := &RepoProvider{DB: db}
|
||||||
|
|
||||||
|
room := &models.Room{
|
||||||
|
ID: "update_room_1",
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
CreatorName: "update_creator_1",
|
||||||
|
TeamTurn: "blue",
|
||||||
|
ThisTurnLimit: 5,
|
||||||
|
OpenedThisTurn: 0,
|
||||||
|
BlueCounter: 0,
|
||||||
|
RedCounter: 0,
|
||||||
|
RedTurn: false,
|
||||||
|
MimeDone: false,
|
||||||
|
IsPublic: true,
|
||||||
|
IsRunning: false,
|
||||||
|
Language: "en",
|
||||||
|
RoundTime: 60,
|
||||||
|
IsOver: false,
|
||||||
|
TeamWon: "",
|
||||||
|
RoomPass: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := db.Exec(`INSERT INTO rooms (id, created_at, creator_name, team_turn, this_turn_limit, opened_this_turn, blue_counter, red_counter, red_turn, mime_done, is_public, is_running, language, round_time, is_over, team_won, room_pass) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, room.ID, room.CreatedAt, room.CreatorName, room.TeamTurn, room.ThisTurnLimit, room.OpenedThisTurn, room.BlueCounter, room.RedCounter, room.RedTurn, room.MimeDone, room.IsPublic, room.IsRunning, room.Language, room.RoundTime, room.IsOver, room.TeamWon, room.RoomPass)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
room.TeamTurn = "red"
|
||||||
|
room.BlueCounter = 10
|
||||||
|
|
||||||
|
err = repo.UpdateRoom(context.Background(), room)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
var updatedRoom models.Room
|
||||||
|
err = db.Get(&updatedRoom, "SELECT * FROM rooms WHERE id = ?", room.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, models.UserTeam("red"), updatedRoom.TeamTurn)
|
||||||
|
assert.Equal(t, uint8(10), updatedRoom.BlueCounter)
|
||||||
|
}
|
0
sqlite:gralias.db
Normal file
0
sqlite:gralias.db
Normal file
Reference in New Issue
Block a user