Cybersecurity-Projects/PROJECTS/intermediate/security-news-scraper/internal/store/ai_notes.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()
}