AddTaskTag attaches a tag to a task. Idempotent: re-adding an existing (task_slug, tag) pair is a no-op via INSERT OR IGNORE.
(db *sql.DB, slug, tag string)
| 962 | // AddTaskTag attaches a tag to a task. Idempotent: re-adding an existing |
| 963 | // (task_slug, tag) pair is a no-op via INSERT OR IGNORE. |
| 964 | func AddTaskTag(db *sql.DB, slug, tag string) error { |
| 965 | t := NormalizeTag(tag) |
| 966 | if t == "" { |
| 967 | return fmt.Errorf("tag is empty") |
| 968 | } |
| 969 | _, err := db.Exec( |
| 970 | `INSERT OR IGNORE INTO task_tags (task_slug, tag, created_at) VALUES (?, ?, ?)`, |
| 971 | slug, t, NowISO(), |
| 972 | ) |
| 973 | if err != nil { |
| 974 | return fmt.Errorf("add tag %s on %s: %w", t, slug, err) |
| 975 | } |
| 976 | return nil |
| 977 | } |
| 978 | |
| 979 | // RemoveTaskTag detaches a tag from a task. No error if the pair doesn't |
| 980 | // exist; caller can pre-check via GetTaskTags. |