feat(backend): add Store.Get and bookmark view helpers

This commit is contained in:
2026-07-25 22:42:14 +07:00
parent 933d3a9499
commit e42b30057f
2 changed files with 114 additions and 0 deletions
+32
View File
@@ -2,6 +2,7 @@ package main
import (
"database/sql"
"errors"
"fmt"
"strings"
@@ -28,6 +29,22 @@ type Bookmark struct {
UpdatedAt int64 `json:"updated_at"` // unix ms; see Upsert
}
// HasNewChapter reports whether the site has published past the read point.
// A nil LatestChapterNum means nothing has been captured yet, which is not the
// same as "nothing new".
func (b Bookmark) HasNewChapter() bool {
return b.LatestChapterNum != nil && *b.LatestChapterNum > b.LastChapterNum
}
// ContinueURL is where the Continue button points: the chapter last read, or
// the series page when no chapter URL was ever captured.
func (b Bookmark) ContinueURL() string {
if b.LastChapterURL != "" {
return b.LastChapterURL
}
return b.SeriesURL
}
const schema = `
CREATE TABLE IF NOT EXISTS bookmarks (
key TEXT PRIMARY KEY,
@@ -182,6 +199,21 @@ func (s *Store) List() ([]Bookmark, error) {
return out, rows.Err()
}
// Get returns one bookmark by key. A missing key is not an error: ok is false
// and err is nil. UI mutations read-modify-write through this so they preserve
// the fields they do not touch.
func (s *Store) Get(key string) (Bookmark, bool, error) {
b, err := scanBookmark(s.db.QueryRow(
`SELECT `+bookmarkColumns+` FROM bookmarks WHERE key = ?`, key).Scan)
if errors.Is(err, sql.ErrNoRows) {
return Bookmark{}, false, nil
}
if err != nil {
return Bookmark{}, false, fmt.Errorf("get %q: %w", key, err)
}
return b, true, nil
}
// Upsert inserts or replaces a bookmark by key (last-write-wins) and returns
// the row as actually stored.
//