internal/store/bookmarks.go
62 lines · 1842 bytes
1package store
2
3// Bookmarks are public and counted; pins are private quick access. The
4// two are deliberately separate tables rather than a flag on one, because
5// they answer different questions: "what am I working on" and "what is
6// worth coming back to" (#146).
7
8func (s *Store) BookmarkRepo(userID, repoID int64) error {
9 _, err := s.DB.Exec(
10 "INSERT INTO repo_bookmarks (user_id, repo_id) VALUES (?, ?) ON CONFLICT DO NOTHING",
11 userID, repoID)
12 return err
13}
14
15func (s *Store) UnbookmarkRepo(userID, repoID int64) error {
16 res, err := s.DB.Exec(
17 "DELETE FROM repo_bookmarks WHERE user_id = ? AND repo_id = ?", userID, repoID)
18 if err != nil {
19 return err
20 }
21 if n, _ := res.RowsAffected(); n == 0 {
22 return ErrNotFound
23 }
24 return nil
25}
26
27func (s *Store) IsBookmarked(userID, repoID int64) bool {
28 var n int
29 s.DB.QueryRow("SELECT COUNT(*) FROM repo_bookmarks WHERE user_id = ? AND repo_id = ?",
30 userID, repoID).Scan(&n)
31 return n > 0
32}
33
34// BookmarkCount is how many people have bookmarked a repository. It is
35// public: the count is the point, and it names nobody.
36func (s *Store) BookmarkCount(repoID int64) int {
37 var n int
38 s.DB.QueryRow("SELECT COUNT(*) FROM repo_bookmarks WHERE repo_id = ?", repoID).Scan(&n)
39 return n
40}
41
42// ListBookmarks returns one user's bookmarked repositories, newest first.
43// The caller filters by what the viewer may see: a bookmarked repository
44// can since have gone private.
45func (s *Store) ListBookmarks(userID int64) ([]Repo, error) {
46 rows, err := s.DB.Query(repoSelect+`
47 JOIN repo_bookmarks b ON b.repo_id = r.id
48 WHERE b.user_id = ? ORDER BY b.bookmarked_at DESC`, userID)
49 if err != nil {
50 return nil, err
51 }
52 defer rows.Close()
53 var out []Repo
54 for rows.Next() {
55 r, err := scanRepo(rows)
56 if err != nil {
57 return nil, err
58 }
59 out = append(out, r)
60 }
61 return out, rows.Err()
62}