Rename to craban
This commit is contained in:
parent
38767a78d3
commit
ca0bfa2398
217 changed files with 23 additions and 23 deletions
80
server/services/store/store.go
Normal file
80
server/services/store/store.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
Path string
|
||||
Conn *sql.DB
|
||||
|
||||
userStore *UserStore
|
||||
}
|
||||
|
||||
func addPathOptions(path string) string {
|
||||
if !strings.HasPrefix(path, ":memory:") {
|
||||
path = "file:" + path
|
||||
}
|
||||
return fmt.Sprintf("%s?_foreign_keys=true", path)
|
||||
}
|
||||
|
||||
func NewStore(path string) (*Store, error) {
|
||||
s := &Store{Path: path}
|
||||
|
||||
// ToDo: should do this at start time instead of create time?
|
||||
conn, err := sql.Open("sqlite3", addPathOptions(path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.Conn = conn
|
||||
|
||||
if err := s.EnsureSchema(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// init stores
|
||||
s.userStore = NewUserStore(s)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Store) Close() error {
|
||||
return s.Conn.Close()
|
||||
}
|
||||
|
||||
func (s *Store) User() *UserStore {
|
||||
return s.userStore
|
||||
}
|
||||
|
||||
func (s *Store) EnsureSchema() error {
|
||||
schema := `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
mail VARCHAR(255) UNIQUE NOT NULL,
|
||||
username VARCHAR(255) UNIQUE NOT NULL,
|
||||
password VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS game (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
name VARCHAR(255) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS gamemember (
|
||||
game_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
role VARCHAR(255) NOT NULL,
|
||||
|
||||
PRIMARY KEY (game_id, user_id)
|
||||
);
|
||||
`
|
||||
|
||||
_, err := s.Conn.Exec(schema)
|
||||
return err
|
||||
}
|
32
server/services/store/store_test.go
Normal file
32
server/services/store/store_test.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAddPathOptions(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Name string
|
||||
Path string
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
Name: "Path is memory",
|
||||
Path: ":memory:",
|
||||
Expected: ":memory:?_foreign_keys=true",
|
||||
},
|
||||
{
|
||||
Name: "Path is a file path",
|
||||
Path: "./some_file.sqlite",
|
||||
Expected: "file:./some_file.sqlite?_foreign_keys=true",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
require.Equal(t, tc.Expected, addPathOptions(tc.Path))
|
||||
})
|
||||
}
|
||||
}
|
40
server/services/store/testlib.go
Normal file
40
server/services/store/testlib.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/craban/model"
|
||||
|
||||
"github.com/icrowley/fake"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type TestHelper struct {
|
||||
t *testing.T
|
||||
store *Store
|
||||
}
|
||||
|
||||
func NewTestHelper(t *testing.T) (*TestHelper, func()) {
|
||||
s, err := NewStore(":memory:")
|
||||
require.NoError(t, err)
|
||||
|
||||
teardown := func() {
|
||||
require.NoError(t, s.Close())
|
||||
}
|
||||
|
||||
return &TestHelper{t: t, store: s}, teardown
|
||||
}
|
||||
|
||||
func (th *TestHelper) NewUser() *model.User {
|
||||
user := &model.User{
|
||||
Name: fake.FullName(),
|
||||
Mail: fake.EmailAddress(),
|
||||
Username: fake.UserName(),
|
||||
Password: fake.SimplePassword(),
|
||||
}
|
||||
|
||||
newUser, err := th.store.User().Create(user)
|
||||
require.NoError(th.t, err)
|
||||
|
||||
return newUser
|
||||
}
|
87
server/services/store/user.go
Normal file
87
server/services/store/user.go
Normal file
|
@ -0,0 +1,87 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/craban/model"
|
||||
)
|
||||
|
||||
var userColumns = []string{"id", "name", "mail", "username", "password"}
|
||||
|
||||
type UserStore struct {
|
||||
Conn *sql.DB
|
||||
}
|
||||
|
||||
func NewUserStore(s *Store) *UserStore {
|
||||
return &UserStore{Conn: s.Conn}
|
||||
}
|
||||
|
||||
func (us *UserStore) Q() sq.StatementBuilderType {
|
||||
return sq.StatementBuilder.RunWith(us.Conn)
|
||||
}
|
||||
|
||||
func (us *UserStore) usersFromRows(rows *sql.Rows) ([]*model.User, error) {
|
||||
users := []*model.User{}
|
||||
|
||||
for rows.Next() {
|
||||
var user model.User
|
||||
|
||||
err := rows.Scan(
|
||||
&user.ID,
|
||||
&user.Name,
|
||||
&user.Mail,
|
||||
&user.Username,
|
||||
&user.Password,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users = append(users, &user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (us *UserStore) GetByID(id int) (*model.User, error) {
|
||||
query := us.Q().Select(userColumns...).
|
||||
From("users").
|
||||
Where(sq.Eq{"id": id})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
users, err := us.usersFromRows(rows)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(users) == 0 {
|
||||
return nil, sql.ErrNoRows
|
||||
}
|
||||
|
||||
return users[0], nil
|
||||
}
|
||||
|
||||
func (us *UserStore) Create(user *model.User) (*model.User, error) {
|
||||
query := us.Q().Insert("users").
|
||||
Columns(userColumns[1:]...).
|
||||
Values(user.Name, user.Mail, user.Username, user.Password)
|
||||
|
||||
res, err := query.Exec()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
id, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return us.GetByID(int(id))
|
||||
}
|
44
server/services/store/user_test.go
Normal file
44
server/services/store/user_test.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.ctrlz.es/mgdelacroix/craban/model"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestCreateUser(t *testing.T) {
|
||||
th, teardown := NewTestHelper(t)
|
||||
defer teardown()
|
||||
|
||||
user := &model.User{
|
||||
Name: "John",
|
||||
Mail: "john_doe@example.com",
|
||||
Username: "john_doe",
|
||||
Password: "mysupersecret",
|
||||
}
|
||||
|
||||
newUser, err := th.store.User().Create(user)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, newUser.ID)
|
||||
require.Equal(t, user.Name, newUser.Name)
|
||||
require.Equal(t, user.Mail, newUser.Mail)
|
||||
require.Equal(t, user.Username, newUser.Username)
|
||||
require.Equal(t, user.Password, newUser.Password)
|
||||
}
|
||||
|
||||
func TestGetByID(t *testing.T) {
|
||||
th, teardown := NewTestHelper(t)
|
||||
defer teardown()
|
||||
|
||||
user := th.NewUser()
|
||||
|
||||
user2, err := th.store.User().GetByID(user.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, user.ID, user2.ID)
|
||||
require.Equal(t, user.Name, user2.Name)
|
||||
require.Equal(t, user.Mail, user2.Mail)
|
||||
require.Equal(t, user.Username, user2.Username)
|
||||
require.Equal(t, user.Password, user2.Password)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue