diff --git a/go.mod b/go.mod index 7f8ba14..eca8b06 100644 --- a/go.mod +++ b/go.mod @@ -4,5 +4,15 @@ go 1.24 require ( github.com/BurntSushi/toml v1.5.0 + github.com/jackc/pgx/v5 v5.7.5 github.com/rs/xid v1.6.0 ) + +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // 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 +) diff --git a/go.sum b/go.sum index 6cdd3ff..2d701d0 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,32 @@ 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/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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs= +github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +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/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= 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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +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/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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/models/main.go b/models/main.go index 9346c3b..1c36398 100644 --- a/models/main.go +++ b/models/main.go @@ -70,33 +70,33 @@ type CardMark struct { type Room struct { ID string `json:"id" db:"id"` - CreatedAt time.Time `json:"created_at" db:"created_at"` // limit? - RoomLink string - CreatorName string `json:"creator_name"` - ActionHistory []Action - TeamTurn UserTeam - RedTeam Team - BlueTeam Team - Cards []WordCard - ThisTurnLimit uint8 // how many cards guessers can open this turn - OpenedThisTurn uint8 // how many cards have been opened this turn - WCMap map[string]WordColor - BotMap map[string]BotPlayer // key is bot name - BlueCounter uint8 - RedCounter uint8 - RedTurn bool // false is blue turn - MimeDone bool - IsPublic bool - IsRunning bool `json:"is_running"` - Language string `json:"language" example:"en" form:"language"` - RoundTime int32 `json:"round_time"` - IsOver bool - TeamWon UserTeam // blue | red - // - Mark CardMark // card is marked - // needed for debug - LogJournal []string - Settings GameSettings + CreatedAt time.Time `json:"created_at" db:"created_at"` + CreatorName string `json:"creator_name" db:"creator_name"` + TeamTurn UserTeam `db:"team_turn"` + ThisTurnLimit uint8 `db:"this_turn_limit"` + OpenedThisTurn uint8 `db:"opened_this_turn"` + BlueCounter uint8 `db:"blue_counter"` + RedCounter uint8 `db:"red_counter"` + RedTurn bool `db:"red_turn"` + MimeDone bool `db:"mime_done"` + IsPublic bool `db:"is_public"` + IsRunning bool `json:"is_running" db:"is_running"` + Language string `json:"language" example:"en" form:"language" db:"language"` + RoundTime uint32 `json:"round_time" db:"round_time"` + IsOver bool `db:"is_over"` + TeamWon UserTeam `db:"team_won"` + RoomPass string `json:"room_pass" db:"room_pass"` + // fields not in db + RoomLink string `db:"-"` + ActionHistory []Action `db:"-"` + RedTeam Team `db:"-"` + BlueTeam Team `db:"-"` + Cards []WordCard `db:"-"` + WCMap map[string]WordColor `db:"-"` + BotMap map[string]BotPlayer `db:"-"` + Mark CardMark `db:"-"` + LogJournal []string `db:"-"` + Settings GameSettings `db:"-"` } func (r *Room) ClearMarks() { @@ -325,10 +325,10 @@ type WordCard struct { } type GameSettings struct { - Language string `json:"language" example:"en" form:"language"` - RoomPass string `json:"room_pass"` - TurnSecondsLeft uint32 - RoundTime uint32 + Language string `json:"language" example:"en" form:"language" db:"language"` + RoomPass string `json:"room_pass" db:"room_pass"` + TurnSecondsLeft uint32 `db:"-"` + RoundTime uint32 `json:"round_time" db:"round_time"` } // ===== @@ -343,19 +343,14 @@ type RoomReq struct { func (rr *RoomReq) CreateRoom(creator string) *Room { roomID := xid.New().String() - settings := GameSettings{ - Language: rr.Language, - RoomPass: rr.RoomPass, - RoundTime: rr.RoundTime, - } return &Room{ - // RoomName: , - ID: roomID, - CreatedAt: time.Now(), - // PlayerList: []string{creator}, + ID: roomID, + CreatedAt: time.Now(), CreatorName: creator, + Language: rr.Language, + RoundTime: rr.RoundTime, + RoomPass: rr.RoomPass, BotMap: make(map[string]BotPlayer), - Settings: settings, } } diff --git a/repos/actions.go b/repos/actions.go new file mode 100644 index 0000000..f2fa1ed --- /dev/null +++ b/repos/actions.go @@ -0,0 +1,46 @@ +package repos + +import ( + "context" + "gralias/models" + + "github.com/jackc/pgx/v5" +) + +type ActionsRepo interface { + ListActions(ctx context.Context, roomID string) ([]models.Action, error) + CreateAction(ctx context.Context, roomID string, action *models.Action) error + GetLastClue(ctx context.Context, roomID string) (*models.Action, error) + DeleteActionsByRoomID(ctx context.Context, roomID string) 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) + if err != nil { + return nil, err + } + return pgx.CollectRows(rows, pgx.RowToStructByName[models.Action]) +} + +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)`, + roomID, a.Actor, a.ActorColor, a.Action, a.Word, a.WordColor, a.Number) + return err +} + +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) + if err != nil { + return nil, err + } + action, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[models.Action]) + if err != nil { + return nil, err + } + return &action, nil +} + +func (p *RepoProvider) DeleteActionsByRoomID(ctx context.Context, roomID string) error { + _, err := p.DB.Exec(ctx, `DELETE FROM actions WHERE room_id = $1`, roomID) + return err +} \ No newline at end of file diff --git a/repos/main.go b/repos/main.go index 87106ff..1b8b8c8 100644 --- a/repos/main.go +++ b/repos/main.go @@ -1,9 +1,11 @@ package repos +import "github.com/jackc/pgx/v5/pgxpool" + type AllRepos interface { RoomsRepo } type RepoProvider struct { - // db connection + DB *pgxpool.Pool } diff --git a/repos/rooms.go b/repos/rooms.go index f0ae01b..0daa377 100644 --- a/repos/rooms.go +++ b/repos/rooms.go @@ -1,15 +1,55 @@ package repos -import "gralias/models" +import ( + "context" + "gralias/models" + + "github.com/jackc/pgx/v5" +) type RoomsRepo interface { - ListRooms() ([]models.Room, error) - GetRoomByID(id string) (*models.Room, error) - CreateRoom(room *models.Room) error - DeleteRoomByID(id string) error + ListRooms(ctx context.Context) ([]models.Room, error) + GetRoomByID(ctx context.Context, id string) (*models.Room, error) + CreateRoom(ctx context.Context, room *models.Room) error + DeleteRoomByID(ctx context.Context, id string) error + UpdateRoom(ctx context.Context, room *models.Room) error } -// provider implementation -func (p RepoProvider) ListRooms() ([]models.Room, error) { - return nil, nil +func (p *RepoProvider) ListRooms(ctx context.Context) ([]models.Room, error) { + rows, err := p.DB.Query(ctx, `SELECT * FROM rooms`) + if err != nil { + return nil, err + } + rooms, err := pgx.CollectRows(rows, pgx.RowToStructByName[models.Room]) + if err != nil { + return nil, err + } + return rooms, nil +} + +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) + if err != nil { + return nil, err + } + room, err := pgx.CollectOneRow(rows, pgx.RowToStructByName[models.Room]) + if err != nil { + return nil, err + } + return &room, nil +} + +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) + return err +} + +func (p *RepoProvider) DeleteRoomByID(ctx context.Context, id string) error { + _, err := p.DB.Exec(ctx, `DELETE FROM rooms WHERE id = $1`, id) + return err +} + +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) + return err }