Refactor database to separate package
This commit is contained in:
parent
363f557c35
commit
b07f1b080a
9 changed files with 84 additions and 62 deletions
83
storage/sqlite/sqlite.go
Normal file
83
storage/sqlite/sqlite.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"git.a71.su/Andrew71/pye/storage"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const create string = `
|
||||
CREATE TABLE "users" (
|
||||
"uuid" TEXT NOT NULL UNIQUE,
|
||||
"email" TEXT NOT NULL UNIQUE,
|
||||
"password" TEXT NOT NULL,
|
||||
PRIMARY KEY("uuid")
|
||||
);`
|
||||
|
||||
var (
|
||||
DataFile = "data.db"
|
||||
)
|
||||
|
||||
type SQLiteStorage struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) AddUser(email, password string) error {
|
||||
user, err := storage.NewUser(email, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.db.Exec("insert into users (uuid, email, password) values ($1, $2, $3)",
|
||||
user.Uuid.String(), user.Email, user.Hash)
|
||||
if err != nil {
|
||||
slog.Error("error adding user to database", "error", err, "user", user)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) ById(uuid string) (storage.User, bool) {
|
||||
row := s.db.QueryRow("select * from users where uuid = $1", uuid)
|
||||
user := storage.User{}
|
||||
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
|
||||
|
||||
return user, err == nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) ByEmail(email string) (storage.User, bool) {
|
||||
row := s.db.QueryRow("select * from users where email = $1", email)
|
||||
user := storage.User{}
|
||||
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
|
||||
|
||||
return user, err == nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) EmailExists(email string) bool {
|
||||
_, ok := s.ByEmail(email)
|
||||
return ok
|
||||
}
|
||||
|
||||
func MustLoadSQLite() SQLiteStorage {
|
||||
// I *think* we need some file, even if only empty
|
||||
if _, err := os.Stat(DataFile); errors.Is(err, os.ErrNotExist) {
|
||||
slog.Error("sqlite3 database file required", "file", DataFile)
|
||||
os.Exit(1)
|
||||
}
|
||||
db, err := sql.Open("sqlite3", DataFile)
|
||||
if err != nil {
|
||||
slog.Error("error opening database", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// TODO: Apparently "prepare" works here
|
||||
if _, err := db.Exec(create); err != nil && err.Error() != "table \"users\" already exists" {
|
||||
slog.Info("error initialising database table", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
slog.Info("loaded database")
|
||||
return SQLiteStorage{db}
|
||||
}
|
8
storage/storage.go
Normal file
8
storage/storage.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package storage
|
||||
|
||||
type Storage interface {
|
||||
AddUser(email, password string) error
|
||||
ById(uuid string) (User, bool)
|
||||
ByEmail(uuid string) (User, bool)
|
||||
EmailExists(email string) bool
|
||||
}
|
28
storage/user.go
Normal file
28
storage/user.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Uuid uuid.UUID
|
||||
Email string
|
||||
Hash []byte // bcrypt hash of password
|
||||
}
|
||||
|
||||
func (u User) PasswordFits(password string) bool {
|
||||
err := bcrypt.CompareHashAndPassword(u.Hash, []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func NewUser(email, password string) (User, error) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||
if err != nil {
|
||||
slog.Error("error creating a new user", "error", err)
|
||||
return User{}, err
|
||||
}
|
||||
return User{uuid.New(), email, hash}, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue