Refactor database to separate package

This commit is contained in:
Andrew-71 2024-10-12 20:41:30 +03:00
parent 363f557c35
commit b07f1b080a
9 changed files with 84 additions and 62 deletions

83
storage/sqlite/sqlite.go Normal file
View 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
View 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
View 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
}