v0.5.0: manifests, filters, logging, docs
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
package manifest
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
type sqliteManifest struct {
|
||||
path string
|
||||
db *sql.DB
|
||||
open sqlOpenerFunc
|
||||
execFunc func(query string, args ...any) (sql.Result, error)
|
||||
}
|
||||
|
||||
type sqlOpenerFunc func(driverName, dataSourceName string) (*sql.DB, error)
|
||||
|
||||
var sqliteOpenFunc sqlOpenerFunc
|
||||
|
||||
func defaultSQLOpener() sqlOpenerFunc {
|
||||
if sqliteOpenFunc != nil {
|
||||
return sqliteOpenFunc
|
||||
}
|
||||
return sql.Open
|
||||
}
|
||||
|
||||
func SQLitePath(dir string) string {
|
||||
return filepath.Join(dir, "downloads.db")
|
||||
}
|
||||
|
||||
func LoadSQLite(dir string) (*sqliteManifest, error) {
|
||||
m := &sqliteManifest{
|
||||
path: SQLitePath(dir),
|
||||
open: defaultSQLOpener(),
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) OpenAppend() error {
|
||||
if m.db != nil {
|
||||
return nil
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(m.path), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
opener := m.open
|
||||
if opener == nil {
|
||||
opener = sql.Open
|
||||
}
|
||||
db, err := opener("sqlite", m.path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open sqlite: %w", err)
|
||||
}
|
||||
execFn := m.execFunc
|
||||
if execFn == nil {
|
||||
execFn = db.Exec
|
||||
}
|
||||
_, err = execFn(`CREATE TABLE IF NOT EXISTS downloads (
|
||||
id TEXT PRIMARY KEY,
|
||||
filename TEXT NOT NULL DEFAULT '',
|
||||
size INTEGER NOT NULL DEFAULT 0,
|
||||
cloud TEXT NOT NULL DEFAULT '',
|
||||
exported INTEGER NOT NULL DEFAULT 0
|
||||
)`)
|
||||
if err != nil {
|
||||
db.Close()
|
||||
return fmt.Errorf("create table: %w", err)
|
||||
}
|
||||
_, err = execFn(`CREATE INDEX IF NOT EXISTS idx_downloads_id ON downloads(id)`)
|
||||
if err != nil {
|
||||
db.Close()
|
||||
return fmt.Errorf("create index: %w", err)
|
||||
}
|
||||
m.db = db
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) Has(id string) bool {
|
||||
if m.db == nil {
|
||||
return false
|
||||
}
|
||||
var count int
|
||||
err := m.db.QueryRow(`SELECT COUNT(*) FROM downloads WHERE id = ?`, id).Scan(&count)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) Add(id string, filename string, size int64, cloud string) {
|
||||
if m.db == nil {
|
||||
return
|
||||
}
|
||||
entry := newEntry(id, filename, size, cloud)
|
||||
m.db.Exec(`INSERT OR REPLACE INTO downloads (id, filename, size, cloud, exported) VALUES (?, ?, ?, ?, ?)`,
|
||||
id, entry.Filename, entry.Size, entry.Cloud, entry.Exported)
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) Save() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) Close() {
|
||||
if m.db != nil {
|
||||
m.db.Close()
|
||||
m.db = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) DB() *sql.DB {
|
||||
return m.db
|
||||
}
|
||||
|
||||
func (m *sqliteManifest) Entries() map[string]Entry {
|
||||
if m.db == nil {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]Entry)
|
||||
rows, err := m.db.Query(`SELECT id, filename, size, cloud, exported FROM downloads`)
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var e Entry
|
||||
if err := rows.Scan(&e.ID, &e.Filename, &e.Size, &e.Cloud, &e.Exported); err == nil {
|
||||
out[e.ID] = e
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user