94 lines
2.0 KiB
Go
94 lines
2.0 KiB
Go
package store
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// ErrLastAdmin is returned by DeleteUser when attempting to delete the last admin.
|
|
var ErrLastAdmin = errors.New("cannot delete the last admin")
|
|
|
|
// ErrUniqueViolation is a sentinel for PostgreSQL unique constraint violations.
|
|
var ErrUniqueViolation = errors.New("unique violation")
|
|
|
|
// IsUniqueViolation reports whether err is a PostgreSQL unique constraint violation (23505).
|
|
func IsUniqueViolation(err error) bool {
|
|
var pgErr *pgconn.PgError
|
|
return errors.As(err, &pgErr) && pgErr.Code == "23505"
|
|
}
|
|
|
|
// Store provides database access. The pool is unexported; all access goes through methods.
|
|
type Store struct{ p *pgxpool.Pool }
|
|
|
|
func New(p *pgxpool.Pool) *Store { return &Store{p: p} }
|
|
|
|
// ---------- types ----------
|
|
|
|
type User struct {
|
|
ID int64
|
|
Username string
|
|
PasswordHash string
|
|
Role string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type Library struct {
|
|
ID int64
|
|
Name string
|
|
RootPath string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type Book struct {
|
|
ID, LibraryID int64
|
|
Path string
|
|
Title string
|
|
Format string
|
|
FileSize int64
|
|
ModTS int64
|
|
PageCount int // 0 means unknown (pdf/epub/txt)
|
|
State string
|
|
ErrMsg string
|
|
AddedAt time.Time
|
|
}
|
|
|
|
type BookMeta struct {
|
|
ID int64
|
|
Size int64
|
|
ModTS int64
|
|
Format string
|
|
}
|
|
|
|
type BookView struct {
|
|
Book
|
|
LibraryName string
|
|
Percent float64
|
|
}
|
|
|
|
type Progress struct {
|
|
LibraryID int64
|
|
LibraryName string
|
|
BookPath string
|
|
Title string // empty when book deleted
|
|
Locator []byte
|
|
Percent float64
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
type Bookmark struct {
|
|
ID int64
|
|
LibraryID int64
|
|
BookPath string
|
|
Locator []byte
|
|
Percent float64
|
|
Note string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
// Pool returns the underlying pool for test setup only.
|
|
// Production code should use Store methods exclusively.
|
|
func (s *Store) Pool() *pgxpool.Pool { return s.p }
|