diff --git a/database/sqlite/user-repository.go b/database/sqlite/user-repository.go new file mode 100644 index 0000000..e1b9364 --- /dev/null +++ b/database/sqlite/user-repository.go @@ -0,0 +1,94 @@ +package sqlite + +import ( + "context" + + "git.aiterp.net/lucifer/lucifer/models" +) + +// UserRepository is a sqlite database. +var UserRepository = &userRepository{} + +type userRepository struct{} + +func (repo *userRepository) FindByID(ctx context.Context, id int) (models.User, error) { + row := db.QueryRowxContext(ctx, "SELECT * FROM user WHERE id=?", id) + if err := row.Err(); err != nil { + return models.User{}, err + } + + user := models.User{} + if err := row.StructScan(&user); err != nil { + return models.User{}, err + } + + return user, nil +} + +func (repo *userRepository) FindByName(ctx context.Context, name string) (models.User, error) { + row := db.QueryRowxContext(ctx, "SELECT * FROM user WHERE name=?", name) + if err := row.Err(); err != nil { + return models.User{}, err + } + + user := models.User{} + if err := row.StructScan(&user); err != nil { + return models.User{}, err + } + + return user, nil +} + +func (repo *userRepository) List(ctx context.Context) ([]models.User, error) { + res, err := db.QueryxContext(ctx, "SELECT * FROM user") + if err != nil { + return nil, err + } else if err := res.Err(); err != nil { + return nil, err + } + + users := make([]models.User, 0, 64) + for res.Next() { + user := models.User{} + if err := res.StructScan(&user); err != nil { + return nil, err + } + + users = append(users, user) + } + + return users, nil +} + +func (repo *userRepository) Insert(ctx context.Context, user models.User) (models.User, error) { + res, err := db.NamedExecContext(ctx, "INSERT INTO user (name, hash) VALUES(:name, :hash)", user) + if err != nil { + return models.User{}, err + } + + id, err := res.LastInsertId() + if err != nil { + return models.User{}, err + } + + user.ID = int(id) + return user, nil +} + +func (repo *userRepository) Update(ctx context.Context, user models.User) error { + _, err := db.NamedExecContext(ctx, "UPDATE user SET name=:name AND hash=:hash WHERE id=:id", user) + if err != nil { + return err + } + + return nil +} + +func (repo *userRepository) Remove(ctx context.Context, user models.User) error { + _, err := db.ExecContext(ctx, "REMOVE FROM user WHERE id=?", user.ID) + if err != nil { + return err + } + + return err +} diff --git a/models/user.go b/models/user.go index 47e73e0..b58a918 100644 --- a/models/user.go +++ b/models/user.go @@ -1,14 +1,16 @@ package models import ( + "context" + "golang.org/x/crypto/bcrypt" ) // The User model represents a registered user. type User struct { - ID int - Name string - PassHash []byte + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` + PassHash []byte `db:"hash" json:"-"` } // SetPassword sets the user's password @@ -35,10 +37,10 @@ func (user *User) CheckPassword(attempt string) error { // UserRepository is an interface for all database operations // the user model makes. type UserRepository interface { - FindUserByID(id int) (User, error) - FindUserByName(name string) (User, error) - ListUsers() ([]User, error) - InsertUser(user User) (int, error) - UpdateUser(user User) error - RemoveUser(user User) error + FindByID(ctx context.Context, id int) (User, error) + FindByName(ctx context.Context, name string) (User, error) + List(ctx context.Context) ([]User, error) + Insert(ctx context.Context, user User) (User, error) + Update(ctx context.Context, user User) error + Remove(ctx context.Context, user User) error }