120 lines
2.0 KiB
Go
120 lines
2.0 KiB
Go
package nomad
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
type Executor interface {
|
|
Exec(stmt string, args ...interface{}) (sql.Result, error)
|
|
Query(stmt string, args ...interface{}) (*sql.Rows, error)
|
|
}
|
|
|
|
func buildArgs(n int) string {
|
|
s := ""
|
|
for i := 0; i < n; i++ {
|
|
s += "?,"
|
|
}
|
|
|
|
return s[:len(s)-1]
|
|
}
|
|
|
|
type DB struct {
|
|
path string
|
|
db *sql.DB
|
|
}
|
|
|
|
func NewDB(path string) *DB {
|
|
return &DB{path: path}
|
|
}
|
|
|
|
func (db *DB) Connect() (err error) {
|
|
if db.db != nil {
|
|
return nil
|
|
}
|
|
db.db, err = sql.Open("sqlite3", db.path)
|
|
return err
|
|
}
|
|
|
|
func (db *DB) Close() error {
|
|
if db.db == nil {
|
|
return nil
|
|
}
|
|
err := db.db.Close()
|
|
db.db = nil
|
|
return err
|
|
}
|
|
|
|
func (db *DB) Create() (err error) {
|
|
err = db.Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = db.db.Exec(createSQL)
|
|
return err
|
|
}
|
|
|
|
func (db *DB) Begin() (tx *sql.Tx, err error) {
|
|
err = db.Connect()
|
|
if err != nil {
|
|
return tx, err
|
|
}
|
|
|
|
return db.db.Begin()
|
|
}
|
|
|
|
func (db *DB) executor(tx *sql.Tx) Executor {
|
|
if tx != nil {
|
|
return tx
|
|
}
|
|
|
|
return db.db
|
|
}
|
|
|
|
func (db *DB) Mark(tx *sql.Tx, item Item) (err error) {
|
|
_, err = db.executor(tx).Exec(markSQL, item.URL.ID(), item.Title, item.PubDate)
|
|
return err
|
|
}
|
|
|
|
func (db *DB) Filter(tx *sql.Tx, items []Item) (newItems []Item, err error) {
|
|
seen := map[string]bool{}
|
|
args := buildArgs(len(items))
|
|
stmt := fmt.Sprintf(filterSQLTpl, args)
|
|
urls := make([]interface{}, 0, len(items))
|
|
for _, item := range items {
|
|
urls = append(urls, item.URL.ID())
|
|
}
|
|
|
|
rows, err := db.executor(tx).Query(stmt, urls...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for rows.Next() {
|
|
var url string
|
|
err = rows.Scan(&url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
seen[url] = true
|
|
}
|
|
|
|
for _, item := range items {
|
|
if seen[item.URL.ID()] {
|
|
continue
|
|
}
|
|
newItems = append(newItems, item)
|
|
}
|
|
|
|
// Reverse the list of items so that they are in reverse chronological order.
|
|
nitems := len(items) - 1
|
|
for i := range items {
|
|
j := nitems - i
|
|
items[i], items[j] = items[j], items[i]
|
|
}
|
|
|
|
return newItems, nil
|
|
}
|