Refactor everything again
This commit is contained in:
parent
7fdb0bf0f4
commit
96c369e4b1
14 changed files with 72 additions and 53 deletions
92
internal/storage/sqlite/sqlite.go
Normal file
92
internal/storage/sqlite/sqlite.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"git.a71.su/Andrew71/pye/internal/models/user"
|
||||
"git.a71.su/Andrew71/pye/internal/storage"
|
||||
sqlite "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")
|
||||
);`
|
||||
|
||||
// SQLiteStorage is a Storage implementation with SQLite3
|
||||
type SQLiteStorage struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) Add(email, password string) error {
|
||||
user, err := user.New(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 {
|
||||
e, ok := err.(sqlite.Error)
|
||||
if ok && errors.Is(e.ExtendedCode, sqlite.ErrConstraintUnique) {
|
||||
// Return a standard error if the user already exists
|
||||
slog.Info("can't add user because email already taken", "user", user)
|
||||
return fmt.Errorf("%w (%s)", storage.ErrExist, user.Email)
|
||||
}
|
||||
slog.Error("error adding user to database", "error", err, "user", user)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) ById(uuid string) (user.User, bool) {
|
||||
row := s.db.QueryRow("select * from users where uuid = $1", uuid)
|
||||
user := user.User{}
|
||||
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
|
||||
|
||||
return user, err == nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) ByEmail(email string) (user.User, bool) {
|
||||
row := s.db.QueryRow("select * from users where email = $1", email)
|
||||
user := user.User{}
|
||||
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
|
||||
|
||||
return user, err == nil
|
||||
}
|
||||
|
||||
func (s SQLiteStorage) Taken(email string) bool {
|
||||
_, ok := s.ByEmail(email)
|
||||
return ok
|
||||
}
|
||||
|
||||
func MustLoad(dataFile string) SQLiteStorage {
|
||||
if _, err := os.Stat(dataFile); errors.Is(err, os.ErrNotExist) {
|
||||
os.Create(dataFile)
|
||||
slog.Debug("created sqlite3 database file", "file", dataFile)
|
||||
}
|
||||
db, err := sql.Open("sqlite3", dataFile)
|
||||
if err != nil {
|
||||
slog.Error("error opening sqlite3 database", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
statement, err := db.Prepare(create)
|
||||
if err != nil {
|
||||
if err.Error() != "table \"users\" already exists" {
|
||||
slog.Error("error initialising sqlite3 database table", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
statement.Exec()
|
||||
}
|
||||
|
||||
slog.Debug("loaded database", "file", dataFile)
|
||||
return SQLiteStorage{db}
|
||||
}
|
21
internal/storage/storage.go
Normal file
21
internal/storage/storage.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.a71.su/Andrew71/pye/internal/models/user"
|
||||
)
|
||||
|
||||
var ErrExist = errors.New("user already exists")
|
||||
|
||||
// Storage is an interface for arbitrary storage
|
||||
type Storage interface {
|
||||
Add(email, password string) error // Add inserts a user into data
|
||||
ById(uuid string) (user.User, bool) // ById retrieves a user by their UUID
|
||||
ByEmail(email string) (user.User, bool) // ByEmail retrieves a user by their email
|
||||
Taken(email string) bool // Taken checks whether an email is taken
|
||||
}
|
||||
|
||||
// Data stores active information for the app.
|
||||
// It should be populated on startup
|
||||
var Data Storage
|
Loading…
Add table
Add a link
Reference in a new issue