93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
// ©AngelaMos | 2026
|
|
// ai_notes.go
|
|
|
|
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
type AINote struct {
|
|
ID int64
|
|
ClusterID int64
|
|
Provider string
|
|
Summary string
|
|
Why string
|
|
AnglesJSON string
|
|
Format string
|
|
CreatedAt int64
|
|
}
|
|
|
|
func (s *Store) InsertAINote(n AINote) error {
|
|
_, err := s.db.Exec(`
|
|
INSERT INTO ai_notes (cluster_id, provider, summary, why, angles_json, format, created_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT(cluster_id, provider) DO UPDATE SET
|
|
summary = excluded.summary,
|
|
why = excluded.why,
|
|
angles_json = excluded.angles_json,
|
|
format = excluded.format,
|
|
created_at = excluded.created_at`,
|
|
n.ClusterID, n.Provider, n.Summary, n.Why, n.AnglesJSON, n.Format, n.CreatedAt,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("insert ai_note cluster=%d provider=%q: %w", n.ClusterID, n.Provider, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *Store) AINoteExists(clusterID int64, provider string) (bool, error) {
|
|
var one int
|
|
err := s.db.QueryRow(
|
|
`SELECT 1 FROM ai_notes WHERE cluster_id = ? AND provider = ? LIMIT 1`,
|
|
clusterID, provider,
|
|
).Scan(&one)
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return false, nil
|
|
}
|
|
if err != nil {
|
|
return false, fmt.Errorf("ai_note exists cluster=%d provider=%q: %w", clusterID, provider, err)
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func (s *Store) AINotesForCluster(clusterID int64) ([]AINote, error) {
|
|
rows, err := s.db.Query(`
|
|
SELECT id, cluster_id, provider, summary, why, angles_json, format, created_at
|
|
FROM ai_notes WHERE cluster_id = ? ORDER BY provider`, clusterID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("ai_notes for cluster %d: %w", clusterID, err)
|
|
}
|
|
defer rows.Close()
|
|
var out []AINote
|
|
for rows.Next() {
|
|
var n AINote
|
|
if err := rows.Scan(&n.ID, &n.ClusterID, &n.Provider, &n.Summary, &n.Why, &n.AnglesJSON, &n.Format, &n.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("ai_notes for cluster %d: scan: %w", clusterID, err)
|
|
}
|
|
out = append(out, n)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
func (s *Store) LatestAINotes() (map[int64]AINote, error) {
|
|
rows, err := s.db.Query(`
|
|
SELECT id, cluster_id, provider, summary, why, angles_json, format, created_at
|
|
FROM ai_notes ORDER BY cluster_id, created_at`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("latest ai_notes: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
out := make(map[int64]AINote)
|
|
for rows.Next() {
|
|
var n AINote
|
|
if err := rows.Scan(&n.ID, &n.ClusterID, &n.Provider, &n.Summary, &n.Why, &n.AnglesJSON, &n.Format, &n.CreatedAt); err != nil {
|
|
return nil, fmt.Errorf("latest ai_notes: scan: %w", err)
|
|
}
|
|
out[n.ClusterID] = n
|
|
}
|
|
return out, rows.Err()
|
|
}
|