gosuki/database/bookmarkOps.go

148 lines
3.3 KiB
Go
Raw Normal View History

2018-11-09 17:25:50 +00:00
package database
2017-11-19 16:00:37 +00:00
import (
2020-08-12 18:14:27 +00:00
"git.sp4ke.com/sp4ke/gomark/bookmarks"
"strings"
sqlite3 "github.com/mattn/go-sqlite3"
)
2018-11-09 17:25:50 +00:00
const TagJoinSep = "|"
2017-11-19 16:00:37 +00:00
2018-11-09 17:25:50 +00:00
type Bookmark = bookmarks.Bookmark
// Inserts or updates a bookmarks to the passed DB
// In case of a conflict for a UNIQUE URL constraint,
// update the existing bookmark
2018-11-09 17:25:50 +00:00
func (db *DB) InsertOrUpdateBookmark(bk *Bookmark) {
var sqlite3Err sqlite3.Error
var scannedTags string
2018-11-09 17:25:50 +00:00
_db := db.Handle
// Prepare statement that does a pure insert only
tryInsertBk, err := _db.Prepare(
`INSERT INTO
bookmarks(URL, metadata, tags, desc, flags)
VALUES (?, ?, ?, ?, ?)`,
)
defer tryInsertBk.Close()
2018-11-09 17:25:50 +00:00
if err != nil {
log.Errorf("%s: %s", err, bk.URL)
}
// Prepare statement that updates an existing bookmark in db
updateBk, err := _db.Prepare(
`UPDATE bookmarks SET metadata=?, tags=?, modified=strftime('%s')
WHERE url=?`,
)
defer updateBk.Close()
2018-11-09 17:25:50 +00:00
if err != nil {
log.Errorf("%s: %s", err, bk.URL)
}
// Stmt to fetch existing bookmark and tags in db
getTags, err := _db.Prepare(`SELECT tags FROM bookmarks WHERE url=? LIMIT 1`)
defer getTags.Close()
2018-11-09 17:25:50 +00:00
if err != nil {
log.Errorf("%s: %s", err, bk.URL)
}
// Begin transaction
tx, err := _db.Begin()
2018-10-28 19:19:12 +00:00
if err != nil {
log.Error(err)
}
// First try to insert the bookmark (assume it's new)
_, err = tx.Stmt(tryInsertBk).Exec(
bk.URL,
bk.Metadata,
strings.Join(bk.Tags, TagJoinSep),
"", 0,
)
if err != nil {
sqlite3Err = err.(sqlite3.Error)
}
if err != nil && sqlite3Err.Code != sqlite3.ErrConstraint {
2018-11-09 17:25:50 +00:00
log.Errorf("%s: %s", err, bk.URL)
}
// We will handle ErrConstraint ourselves
// ErrConstraint means the bookmark (url) already exists in table,
// we need to update it instead.
if err != nil && sqlite3Err.Code == sqlite3.ErrConstraint {
//log.Debugf("Updating bookmark %s", bk.URL)
// First get existing tags for this bookmark if any ?
res := tx.Stmt(getTags).QueryRow(
bk.URL,
)
res.Scan(&scannedTags)
cacheTags := strings.Split(scannedTags, TagJoinSep)
// If tags are different, merge current bookmark tags and existing tags
// Put them in a map first to remove duplicates
tagMap := make(map[string]bool)
for _, v := range cacheTags {
tagMap[v] = true
}
for _, v := range bk.Tags {
tagMap[v] = true
}
var newTags []string // merged tags
// Merge in a single slice
for k, _ := range tagMap {
newTags = append(newTags, k)
}
_, err = tx.Stmt(updateBk).Exec(
bk.Metadata,
strings.Join(newTags, TagJoinSep), // Join tags with a `|`
bk.URL,
)
2018-11-09 17:25:50 +00:00
if err != nil {
log.Errorf("%s: %s", err, bk.URL)
}
}
err = tx.Commit()
2018-11-09 17:25:50 +00:00
if err != nil {
log.Error(err)
}
}
// Inserts a bookmarks to the passed DB
// In case of conflict follow the default rules
// which for sqlite is a fail with the error `sqlite3.ErrConstraint`
func (db *DB) InsertBookmark(bk *Bookmark) {
//log.Debugf("Adding bookmark %s", bk.URL)
_db := db.Handle
tx, err := _db.Begin()
if err != nil {
log.Error(err)
}
2018-11-09 17:25:50 +00:00
stmt, err := tx.Prepare(`INSERT INTO bookmarks(URL, metadata, tags, desc, flags) VALUES (?, ?, ?, ?, ?)`)
if err != nil {
log.Error(err)
}
defer stmt.Close()
_, err = stmt.Exec(bk.URL, bk.Metadata, strings.Join(bk.Tags, TagJoinSep), "", 0)
if err != nil {
log.Errorf("%s: %s", err, bk.URL)
}
err = tx.Commit()
if err != nil {
log.Error(err)
}
}