This commit is contained in:
+166
@@ -0,0 +1,166 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
Email string
|
||||
PasswordHash string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Episode struct {
|
||||
ID int64
|
||||
Title string
|
||||
Description string
|
||||
AudioPath string
|
||||
ImagePath string
|
||||
PublishedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type Store struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func New(path string) (*Store, error) {
|
||||
db, err := sql.Open("sqlite", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db.SetMaxOpenConns(1)
|
||||
|
||||
if err := migrate(db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Store{db: db}, nil
|
||||
}
|
||||
|
||||
func migrate(db *sql.DB) error {
|
||||
schema := `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS episodes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
audio_path TEXT NOT NULL DEFAULT '',
|
||||
image_path TEXT NOT NULL DEFAULT '',
|
||||
published_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
`
|
||||
_, err := db.Exec(schema)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) Close() error {
|
||||
return s.db.Close()
|
||||
}
|
||||
|
||||
// --- Users ---
|
||||
|
||||
func (s *Store) UserCount() (int, error) {
|
||||
var n int
|
||||
err := s.db.QueryRow("SELECT COUNT(*) FROM users").Scan(&n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s *Store) CreateUser(email, passwordHash string) (int64, error) {
|
||||
res, err := s.db.Exec("INSERT INTO users (email, password_hash) VALUES (?, ?)", email, passwordHash)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func (s *Store) UserByEmail(email string) (*User, error) {
|
||||
u := &User{}
|
||||
err := s.db.QueryRow("SELECT id, email, password_hash, created_at FROM users WHERE email = ?", email).
|
||||
Scan(&u.ID, &u.Email, &u.PasswordHash, &u.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// --- Episodes ---
|
||||
func (s *Store) ListEpisodes() ([]Episode, error) {
|
||||
rows, err := s.db.Query("SELECT id, title, description, audio_path, image_path, published_at, created_at FROM episodes ORDER BY published_at DESC")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var eps []Episode
|
||||
for rows.Next() {
|
||||
var e Episode
|
||||
if err := rows.Scan(&e.ID, &e.Title, &e.Description, &e.AudioPath, &e.ImagePath, &e.PublishedAt, &e.CreatedAt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eps = append(eps, e)
|
||||
}
|
||||
return eps, rows.Err()
|
||||
}
|
||||
|
||||
func (s *Store) GetEpisode(id int64) (*Episode, error) {
|
||||
e := &Episode{}
|
||||
err := s.db.QueryRow("SELECT id, title, description, audio_path, image_path, published_at, created_at FROM episodes WHERE id = ?", id).
|
||||
Scan(&e.ID, &e.Title, &e.Description, &e.AudioPath, &e.ImagePath, &e.PublishedAt, &e.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (s *Store) CreateEpisode(title, description, audioPath, imagePath string, publishedAt time.Time) (int64, error) {
|
||||
res, err := s.db.Exec("INSERT INTO episodes (title, description, audio_path, image_path, published_at) VALUES (?, ?, ?, ?, ?)",
|
||||
title, description, audioPath, imagePath, publishedAt)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func (s *Store) UpdateEpisode(id int64, title, description, audioPath, imagePath string, publishedAt time.Time) error {
|
||||
_, err := s.db.Exec("UPDATE episodes SET title=?, description=?, audio_path=?, image_path=?, published_at=? WHERE id=?",
|
||||
title, description, audioPath, imagePath, publishedAt, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) DeleteEpisode(id int64) error {
|
||||
_, err := s.db.Exec("DELETE FROM episodes WHERE id = ?", id)
|
||||
return err
|
||||
}
|
||||
|
||||
// --- Settings ---
|
||||
|
||||
func (s *Store) GetSetting(key string) (string, error) {
|
||||
var val string
|
||||
err := s.db.QueryRow("SELECT value FROM settings WHERE key = ?", key).Scan(&val)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (s *Store) SetSetting(key, value string) error {
|
||||
_, err := s.db.Exec("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", key, value)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user