package sqlite import ( "database/sql" "delayed.link/storage" "encoding/json" "errors" "github.com/google/uuid" _ "github.com/mattn/go-sqlite3" "github.com/spf13/pflag" "log" ) var ( dbFile = pflag.StringP("dbfile", "d", "delayedlink.db", "") ) type SqliteStorage struct { *sql.DB } func (s *SqliteStorage) Close() error { return s.DB.Close() } func (s *SqliteStorage) Save(item storage.Link) (uuid.UUID, error) { stmt, err := s.Prepare("INSERT INTO links VALUES (?, ?)") if err != nil { return storage.Null, err } id := uuid.New() item.Id = id obj, err := item.Serialize() if err != nil { return storage.Null, err } _, err = stmt.Exec(id, obj) if err != nil { return storage.Null, err } return id, nil } const insertStatement = `SELECT (obj) FROM links WHERE id = ? LIMIT 1` func (s *SqliteStorage) Load(key uuid.UUID) (*storage.Link, error) { stmt, err := s.DB.Prepare(insertStatement) if err != nil { return nil, err } rows, err := stmt.Query(key.String()) if err != nil { return nil, err } defer rows.Close() var link *storage.Link var data []byte if !rows.Next() { return nil, storage.NotFoundError } err = rows.Scan(&data) if err != nil { return nil, err } err = json.Unmarshal(data, &link) if err != nil { return nil, err } return link, nil } const creation_sql = `CREATE TABLE IF NOT EXISTS links ( id UUID PRIMARY KEY, obj JSONB NOT NULL );` func New() *SqliteStorage { db, err := sql.Open("sqlite3", *dbFile) if err != nil { log.Panic(err) } _, err = db.Exec(creation_sql) if err != nil { panic(err) } return &SqliteStorage{ db, } } const deleteQuery = `DELETE FROM links WHERE id = ?` var NotFoundError = errors.New("entry not found") func (s *SqliteStorage) Delete(item storage.Link) error { stmt, err := s.DB.Prepare(deleteQuery) if err != nil { return err } res, err := stmt.Exec(item.Id) if err != nil { return err } if aff, err := res.RowsAffected(); aff < 1 || err != nil { if err == nil { return NotFoundError } return err } return nil } const updateQuery = `UPDATE links SET obj = ? WHERE id = ?` func (s *SqliteStorage) Update(item storage.Link) error { stmt, err := s.DB.Prepare(updateQuery) if err != nil { return err } obj, err := item.Serialize() if err != nil { return err } _, err = stmt.Exec(item.Id, obj) if err != nil { return err } return nil }