// subs.go stores forum subscriptions. The rule that matters: an
// EXPLICIT unsubscribe outranks every auto-subscribe forever — "leave
// me alone" must survive the subscriber's own later replies.
package oltp
const subsSchema = `
CREATE TABLE IF NOT EXISTS forum_sub (
repo TEXT NOT NULL,
account TEXT NOT NULL,
thread TEXT NOT NULL, -- thread root hash
state TEXT NOT NULL, -- 'sub' | 'unsub'
at TEXT NOT NULL,
PRIMARY KEY (repo, account, thread)
);
CREATE INDEX IF NOT EXISTS forum_sub_by_thread ON forum_sub (repo, thread, state);`
// SetForumSub records an EXPLICIT choice, replacing whatever stood.
func (d *DB) SetForumSub(repo, account, thread, state string) error {
_, err := d.w.Exec(`INSERT INTO forum_sub (repo, account, thread, state, at)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (repo, account, thread) DO UPDATE SET state = excluded.state, at = excluded.at`,
repo, account, thread, state, now())
return err
}
// AutoSubscribe subscribes an author to a thread they touched — unless
// ANY explicit row exists. INSERT OR IGNORE is the whole mechanism: an
// earlier unsubscribe is a row, so it is never overridden.
func (d *DB) AutoSubscribe(repo, account, thread string) error {
_, err := d.w.Exec(`INSERT OR IGNORE INTO forum_sub (repo, account, thread, state, at)
VALUES (?, ?, ?, 'sub', ?)`, repo, account, thread, now())
return err
}
// ForumSubscribers lists the accounts subscribed to a thread.
func (d *DB) ForumSubscribers(repo, thread string) ([]string, error) {
rows, err := d.db.Query(`SELECT account FROM forum_sub
WHERE repo = ? AND thread = ? AND state = 'sub' ORDER BY account`, repo, thread)
if err != nil {
return nil, err
}
defer rows.Close()
var out []string
for rows.Next() {
var a string
if err := rows.Scan(&a); err != nil {
return nil, err
}
out = append(out, a)
}
return out, rows.Err()
}
// ForumSubState answers one account's standing: "sub", "unsub", or empty.
// Double quotes deliberately: gofmt rewrites a pair of apostrophes in a
// comment into a typographic closing quote, which reads as a typo.
func (d *DB) ForumSubState(repo, account, thread string) string {
var s string
if account == "" {
return ""
}
d.db.QueryRow(`SELECT state FROM forum_sub WHERE repo = ? AND account = ? AND thread = ?`,
repo, account, thread).Scan(&s)
return s
}