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
|
package store
import (
"encoding/json"
"task-dashboard/internal/models"
)
// SetTaskLabels replaces a task's label set entirely (not an add/remove
// single-label API), matching UpdateNativeTask's replace-whole-value style.
// Returns ErrNativeTaskNotFound if id doesn't match any row.
func (s *Store) SetTaskLabels(id string, labels []string) error {
labelsJSON, _ := json.Marshal(labels)
result, err := s.db.Exec(`
UPDATE native_tasks SET labels = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
`, string(labelsJSON), id)
if err != nil {
return err
}
return checkRowsAffected(result)
}
// GetLabelColors returns every label that has been assigned a color.
func (s *Store) GetLabelColors() ([]models.LabelColor, error) {
rows, err := s.db.Query(`SELECT name, color, budget_tracked FROM labels ORDER BY name ASC`)
if err != nil {
return nil, err
}
defer func() { _ = rows.Close() }()
var colors []models.LabelColor
for rows.Next() {
var c models.LabelColor
if err := rows.Scan(&c.Name, &c.Color, &c.BudgetTracked); err != nil {
return nil, err
}
colors = append(colors, c)
}
return colors, rows.Err()
}
// SetLabelColor assigns (or reassigns) a label's display color, preserving
// any existing budget_tracked flag -- a plain INSERT OR REPLACE would
// delete-and-reinsert the row, silently resetting budget_tracked to 0.
func (s *Store) SetLabelColor(name, color string) error {
_, err := s.db.Exec(`
INSERT INTO labels (name, color, budget_tracked) VALUES (?, ?, 0)
ON CONFLICT(name) DO UPDATE SET color = excluded.color
`, name, color)
return err
}
// SetLabelBudgetTracked marks a label as opted in (or out) of budget
// tracking, preserving any existing color the same way SetLabelColor
// preserves budget_tracked.
func (s *Store) SetLabelBudgetTracked(name string, tracked bool) error {
_, err := s.db.Exec(`
INSERT INTO labels (name, color, budget_tracked) VALUES (?, '', ?)
ON CONFLICT(name) DO UPDATE SET budget_tracked = excluded.budget_tracked
`, name, tracked)
return err
}
// GetBudgetTrackedLabelNames returns the set of label names opted into budget tracking.
func (s *Store) GetBudgetTrackedLabelNames() (map[string]bool, error) {
rows, err := s.db.Query(`SELECT name FROM labels WHERE budget_tracked = 1`)
if err != nil {
return nil, err
}
defer func() { _ = rows.Close() }()
names := make(map[string]bool)
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
names[name] = true
}
return names, rows.Err()
}
|