This commit is contained in:
2026-03-07 03:57:45 +07:00
parent c3e5654ab4
commit 9e0a19d25a
10 changed files with 6 additions and 6 deletions
+28
View File
@@ -0,0 +1,28 @@
//go:generate mockgen -source=interface.go -destination=mocks/mock.go -package=mocks
package db
import (
"context"
"evening_detective/internal/models"
)
type IDBService interface {
Close()
GetTeams(ctx context.Context) ([]*models.Team, error)
GetTeam(ctx context.Context, teamId any, password any) (*models.Team, error)
AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error)
DeleteAllTeams(ctx context.Context) error
GetActions(ctx context.Context, teamId int64) ([]*models.Action, error)
AddActions(ctx context.Context, teamId int64, actions []*models.Action) error
GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error)
GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error)
AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error
GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error
GetGame(ctx context.Context) (*models.Game, error)
UpdateGameState(ctx context.Context, state string) error
}
+223
View File
@@ -0,0 +1,223 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: interface.go
// Package mocks is a generated GoMock package.
package mocks
import (
context "context"
models "evening_detective/internal/models"
reflect "reflect"
gomock "github.com/golang/mock/gomock"
)
// MockIDBService is a mock of IDBService interface.
type MockIDBService struct {
ctrl *gomock.Controller
recorder *MockIDBServiceMockRecorder
}
// MockIDBServiceMockRecorder is the mock recorder for MockIDBService.
type MockIDBServiceMockRecorder struct {
mock *MockIDBService
}
// NewMockIDBService creates a new mock instance.
func NewMockIDBService(ctrl *gomock.Controller) *MockIDBService {
mock := &MockIDBService{ctrl: ctrl}
mock.recorder = &MockIDBServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockIDBService) EXPECT() *MockIDBServiceMockRecorder {
return m.recorder
}
// AddActions mocks base method.
func (m *MockIDBService) AddActions(ctx context.Context, teamId int64, actions []*models.Action) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddActions", ctx, teamId, actions)
ret0, _ := ret[0].(error)
return ret0
}
// AddActions indicates an expected call of AddActions.
func (mr *MockIDBServiceMockRecorder) AddActions(ctx, teamId, actions interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddActions", reflect.TypeOf((*MockIDBService)(nil).AddActions), ctx, teamId, actions)
}
// AddApplications mocks base method.
func (m *MockIDBService) AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddApplications", ctx, teamId, applications)
ret0, _ := ret[0].(error)
return ret0
}
// AddApplications indicates an expected call of AddApplications.
func (mr *MockIDBServiceMockRecorder) AddApplications(ctx, teamId, applications interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddApplications", reflect.TypeOf((*MockIDBService)(nil).AddApplications), ctx, teamId, applications)
}
// AddTeams mocks base method.
func (m *MockIDBService) AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddTeams", ctx, teams)
ret0, _ := ret[0].([]*models.Team)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AddTeams indicates an expected call of AddTeams.
func (mr *MockIDBServiceMockRecorder) AddTeams(ctx, teams interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTeams", reflect.TypeOf((*MockIDBService)(nil).AddTeams), ctx, teams)
}
// Close mocks base method.
func (m *MockIDBService) Close() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Close")
}
// Close indicates an expected call of Close.
func (mr *MockIDBServiceMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIDBService)(nil).Close))
}
// DeleteAllTeams mocks base method.
func (m *MockIDBService) DeleteAllTeams(ctx context.Context) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteAllTeams", ctx)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteAllTeams indicates an expected call of DeleteAllTeams.
func (mr *MockIDBServiceMockRecorder) DeleteAllTeams(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAllTeams", reflect.TypeOf((*MockIDBService)(nil).DeleteAllTeams), ctx)
}
// GetActions mocks base method.
func (m *MockIDBService) GetActions(ctx context.Context, teamId int64) ([]*models.Action, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetActions", ctx, teamId)
ret0, _ := ret[0].([]*models.Action)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetActions indicates an expected call of GetActions.
func (mr *MockIDBServiceMockRecorder) GetActions(ctx, teamId interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActions", reflect.TypeOf((*MockIDBService)(nil).GetActions), ctx, teamId)
}
// GetApplications mocks base method.
func (m *MockIDBService) GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetApplications", ctx, teamId)
ret0, _ := ret[0].([]*models.Application)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetApplications indicates an expected call of GetApplications.
func (mr *MockIDBServiceMockRecorder) GetApplications(ctx, teamId interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplications", reflect.TypeOf((*MockIDBService)(nil).GetApplications), ctx, teamId)
}
// GetApplicationsByState mocks base method.
func (m *MockIDBService) GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetApplicationsByState", ctx, teamId, state)
ret0, _ := ret[0].([]*models.Application)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetApplicationsByState indicates an expected call of GetApplicationsByState.
func (mr *MockIDBServiceMockRecorder) GetApplicationsByState(ctx, teamId, state interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplicationsByState", reflect.TypeOf((*MockIDBService)(nil).GetApplicationsByState), ctx, teamId, state)
}
// GetGame mocks base method.
func (m *MockIDBService) GetGame(ctx context.Context) (*models.Game, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetGame", ctx)
ret0, _ := ret[0].(*models.Game)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetGame indicates an expected call of GetGame.
func (mr *MockIDBServiceMockRecorder) GetGame(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGame", reflect.TypeOf((*MockIDBService)(nil).GetGame), ctx)
}
// GetTeam mocks base method.
func (m *MockIDBService) GetTeam(ctx context.Context, teamId, password any) (*models.Team, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTeam", ctx, teamId, password)
ret0, _ := ret[0].(*models.Team)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTeam indicates an expected call of GetTeam.
func (mr *MockIDBServiceMockRecorder) GetTeam(ctx, teamId, password interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeam", reflect.TypeOf((*MockIDBService)(nil).GetTeam), ctx, teamId, password)
}
// GetTeams mocks base method.
func (m *MockIDBService) GetTeams(ctx context.Context) ([]*models.Team, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTeams", ctx)
ret0, _ := ret[0].([]*models.Team)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTeams indicates an expected call of GetTeams.
func (mr *MockIDBServiceMockRecorder) GetTeams(ctx interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeams", reflect.TypeOf((*MockIDBService)(nil).GetTeams), ctx)
}
// GiveApplications mocks base method.
func (m *MockIDBService) GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GiveApplications", ctx, teamId, applications)
ret0, _ := ret[0].(error)
return ret0
}
// GiveApplications indicates an expected call of GiveApplications.
func (mr *MockIDBServiceMockRecorder) GiveApplications(ctx, teamId, applications interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GiveApplications", reflect.TypeOf((*MockIDBService)(nil).GiveApplications), ctx, teamId, applications)
}
// UpdateGameState mocks base method.
func (m *MockIDBService) UpdateGameState(ctx context.Context, state string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateGameState", ctx, state)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateGameState indicates an expected call of UpdateGameState.
func (mr *MockIDBServiceMockRecorder) UpdateGameState(ctx, state interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGameState", reflect.TypeOf((*MockIDBService)(nil).UpdateGameState), ctx, state)
}
+236
View File
@@ -0,0 +1,236 @@
package db
import (
"context"
"database/sql"
"errors"
"evening_detective/internal/models"
"log"
_ "github.com/mattn/go-sqlite3"
)
type service struct {
db *sql.DB
}
func NewDBService(filepath string) (IDBService, error) {
db, err := sql.Open("sqlite3", filepath)
if err != nil {
return nil, err
}
log.Printf("load db from: %s", filepath)
_, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL CHECK(length(trim(name)) > 0), password TEXT);")
if err != nil {
return nil, err
}
_, err = db.Exec("CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY AUTOINCREMENT, place TEXT, teamId INTEGER, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
if err != nil {
return nil, err
}
_, err = db.Exec("CREATE TABLE IF NOT EXISTS applications (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, teamId INTEGER, state TEXT, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
if err != nil {
return nil, err
}
_, err = db.Exec("CREATE TABLE IF NOT EXISTS games (id INTEGER PRIMARY KEY AUTOINCREMENT, state TEXT, startAt TEXT, endAt TEXT);")
if err != nil {
return nil, err
}
return &service{db: db}, nil
}
func (s *service) Close() {
s.db.Close()
}
func (s *service) GetTeams(ctx context.Context) ([]*models.Team, error) {
rows, err := s.db.Query("select id, name, password from teams")
if err != nil {
return nil, err
}
defer rows.Close()
teams := []*models.Team{}
for rows.Next() {
item := &models.Team{}
err := rows.Scan(&item.ID, &item.Name, &item.Password)
if err != nil {
return nil, err
}
teams = append(teams, item)
}
return teams, nil
}
func (s *service) GetTeam(ctx context.Context, teamId any, password any) (*models.Team, error) {
rows, err := s.db.Query("select id, name from teams where LOWER(name) = LOWER($1) and password = $2", teamId, password)
if err != nil {
return nil, err
}
defer rows.Close()
teams := []*models.Team{}
for rows.Next() {
item := &models.Team{}
err := rows.Scan(&item.ID, &item.Name)
if err != nil {
return nil, err
}
teams = append(teams, item)
}
if len(teams) != 1 {
return nil, errors.New("bad result")
}
return teams[0], nil
}
func (s *service) AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error) {
for _, team := range teams {
result, err := s.db.Exec("insert into teams (name, password) values ($1, $2)", team.Name, team.Password)
if err != nil {
return nil, err
}
team.ID, err = result.LastInsertId()
if err != nil {
return nil, err
}
}
return teams, nil
}
func (s *service) DeleteAllTeams(ctx context.Context) error {
_, err := s.db.Exec("delete from teams where 1")
return err
}
func (s *service) GetActions(ctx context.Context, teamId int64) ([]*models.Action, error) {
rows, err := s.db.Query("select id, place from actions where teamId = $1", teamId)
if err != nil {
return nil, err
}
defer rows.Close()
actions := []*models.Action{}
for rows.Next() {
item := &models.Action{}
err := rows.Scan(&item.ID, &item.Place)
if err != nil {
return nil, err
}
actions = append(actions, item)
}
return actions, nil
}
func (s *service) AddActions(ctx context.Context, teamId int64, actions []*models.Action) error {
for _, action := range actions {
_, err := s.db.Exec("insert into actions (place, teamId) values ($1, $2)", action.Place, teamId)
if err != nil {
return err
}
}
return nil
}
func (s *service) GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error) {
rows, err := s.db.Query("select id, name from applications where teamId = $1", teamId)
if err != nil {
return nil, err
}
defer rows.Close()
applications := []*models.Application{}
for rows.Next() {
item := &models.Application{}
err := rows.Scan(&item.ID, &item.Name)
if err != nil {
return nil, err
}
applications = append(applications, item)
}
return applications, nil
}
func (s *service) GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error) {
rows, err := s.db.Query("select id, name from applications where teamId = $1 and state = $2", teamId, state)
if err != nil {
return nil, err
}
defer rows.Close()
applications := []*models.Application{}
for rows.Next() {
item := &models.Application{}
err := rows.Scan(&item.ID, &item.Name)
if err != nil {
return nil, err
}
applications = append(applications, item)
}
return applications, nil
}
func (s *service) AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
for _, application := range applications {
_, err := s.db.Exec("insert into applications (name, teamId, state) values ($1, $2, $3)", application.Name, teamId, application.State)
if err != nil {
return err
}
}
return nil
}
func (s *service) GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
for _, application := range applications {
_, err := s.db.Exec("update applications set state = \"gave\" where teamId = $1 and id = $2", teamId, application.ID)
if err != nil {
return err
}
}
return nil
}
func (s *service) GetGame(ctx context.Context) (*models.Game, error) {
rows, err := s.db.Query("select state, startAt, endAt from games limit 1")
if err != nil {
return nil, err
}
defer rows.Close()
game := &models.Game{}
if rows.Next() {
err := rows.Scan(&game.State, &game.StartTime, &game.EndTime)
if err != nil {
return nil, err
}
return game, nil
}
state := "NEW"
_, err = s.db.Exec("insert into games (state, startAt, endAt) values ($1, '', '')", state)
if err != nil {
return nil, err
}
game.State = state
return game, nil
}
func (s *service) UpdateGameState(ctx context.Context, state string) error {
game, err := s.GetGame(ctx)
if err != nil {
return err
}
switch state {
case "RUN":
if game.StartTime == "" {
_, err := s.db.Exec("update games set state = $1, startAt = datetime('now', 'localtime')", state)
return err
}
_, err := s.db.Exec("update games set state = $1", state)
return err
case "STOP":
_, err := s.db.Exec("update games set state = $1, endAt = datetime('now', 'localtime')", state)
return err
}
return nil
}