all repos

smutok @ cfe45f84e943de1ee39f995f3029727d4034b1d9

yet another tui rss reader (not abandoned, just paused development)

smutok/internal/store/sqlite_pendin_actions.go(view raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package store

import (
	"context"
	"fmt"
)

type Action int

const (
	Read Action = iota
	Unread
	Star
	Unstar
)

func (a Action) String() string {
	switch a {
	case Read:
		return "read"
	case Unread:
		return "unread"
	case Star:
		return "star"
	case Unstar:
		return "unstar"
	default:
		return "unsupported"
	}
}

var changeArticleStatusQuery = map[Action]string{
	Read:   `update article_statuses set is_read = 1 where article_id = ?`,
	Unread: `update article_statuses set is_read = 0 where article_id = ?`,
	Star:   `update article_statuses set is_starred = 1 where article_id = ?`,
	Unstar: `update article_statuses set is_starred = 0 where article_id = ?`,
}

func (s *Sqlite) ChangeArticleStatus(ctx context.Context, articleID string, action Action) error {
	tx, err := s.db.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	// update article status
	e, err := tx.ExecContext(ctx, changeArticleStatusQuery[action], articleID)
	if err != nil {
		return err
	}
	if n, _ := e.RowsAffected(); n == 0 {
		return ErrNotFound
	}

	// enqueue action
	if _, err := tx.ExecContext(ctx, `insert into pending_actions (article_id, action) values (?, ?)`,
		articleID, action.String()); err != nil {
		return err
	}

	return tx.Commit()
}

func (s *Sqlite) GetPendingActions(ctx context.Context, action Action) ([]string, error) {
	query := `--sql
	select article_id
	from pending_actions
	where action = ?
	order by created_at desc
	limit 20`

	rows, err := s.db.QueryContext(ctx, query, action.String())
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var res []string
	for rows.Next() {
		var pa string
		if serr := rows.Scan(&pa); serr != nil {
			return res, serr
		}
		res = append(res, pa)
	}

	if err = rows.Err(); err != nil {
		return res, err
	}

	return res, nil
}

func (s *Sqlite) DeletePendingActions(
	ctx context.Context,
	action Action,
	articleIDs []string,
) error {
	placeholders, args := buildPlaceholdersAndArgs(articleIDs, action.String())
	query := fmt.Sprintf(`--sql
	delete from pending_actions
	where action = ?
	  and article_id in (%s)
	`, placeholders)

	_, err := s.db.ExecContext(ctx, query, args...)
	return err
}