71 lines
2.2 KiB
Go
71 lines
2.2 KiB
Go
|
|
package storage
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ListCategories returns all categories ordered by label.
|
||
|
|
func (s *Store) ListCategories() ([]Lookup, error) { return s.listLookup("categories") }
|
||
|
|
|
||
|
|
// ListPeople returns all people ("Who") ordered by label.
|
||
|
|
func (s *Store) ListPeople() ([]Lookup, error) { return s.listLookup("people") }
|
||
|
|
|
||
|
|
// AddCategory inserts a new category label and returns its id.
|
||
|
|
func (s *Store) AddCategory(label string) (int64, error) { return s.addLookup("categories", label) }
|
||
|
|
|
||
|
|
// AddPerson inserts a new person label and returns its id.
|
||
|
|
func (s *Store) AddPerson(label string) (int64, error) { return s.addLookup("people", label) }
|
||
|
|
|
||
|
|
// RenameCategory updates a category's label (the change propagates to every
|
||
|
|
// receipt referencing it, since receipts hold the id, not the text).
|
||
|
|
func (s *Store) RenameCategory(id int64, label string) error {
|
||
|
|
return s.renameLookup("categories", id, label)
|
||
|
|
}
|
||
|
|
|
||
|
|
// RenamePerson updates a person's label.
|
||
|
|
func (s *Store) RenamePerson(id int64, label string) error {
|
||
|
|
return s.renameLookup("people", id, label)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Store) listLookup(table string) ([]Lookup, error) {
|
||
|
|
rows, err := s.db.Query(`SELECT id, label FROM ` + table + ` ORDER BY label COLLATE NOCASE`)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("list %s: %w", table, err)
|
||
|
|
}
|
||
|
|
defer rows.Close()
|
||
|
|
|
||
|
|
var out []Lookup
|
||
|
|
for rows.Next() {
|
||
|
|
var l Lookup
|
||
|
|
if err := rows.Scan(&l.ID, &l.Label); err != nil {
|
||
|
|
return nil, fmt.Errorf("scan %s: %w", table, err)
|
||
|
|
}
|
||
|
|
out = append(out, l)
|
||
|
|
}
|
||
|
|
return out, rows.Err()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Store) addLookup(table, label string) (int64, error) {
|
||
|
|
label = strings.TrimSpace(label)
|
||
|
|
if label == "" {
|
||
|
|
return 0, fmt.Errorf("label cannot be empty")
|
||
|
|
}
|
||
|
|
res, err := s.db.Exec(`INSERT INTO `+table+`(label) VALUES (?)`, label)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("add %s: %w", table, err)
|
||
|
|
}
|
||
|
|
return res.LastInsertId()
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Store) renameLookup(table string, id int64, label string) error {
|
||
|
|
label = strings.TrimSpace(label)
|
||
|
|
if label == "" {
|
||
|
|
return fmt.Errorf("label cannot be empty")
|
||
|
|
}
|
||
|
|
if _, err := s.db.Exec(`UPDATE `+table+` SET label = ? WHERE id = ?`, label, id); err != nil {
|
||
|
|
return fmt.Errorf("rename %s: %w", table, err)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|