package services import ( "database/sql" "fmt" "time" "github.com/HoHD/PR-Helper/models" ) // SaveNote upserts a review note (insert or update if exists for the same analysis_id + scope + scope_key). func SaveNote(db *sql.DB, analysisID int64, scope, scopeKey, content string) (*models.ReviewNote, error) { now := time.Now().UTC() // Try to find existing note var existingID int64 err := db.QueryRow(`SELECT id FROM review_notes WHERE analysis_id = ? AND scope = ? AND scope_key = ?`, analysisID, scope, scopeKey).Scan(&existingID) if err == sql.ErrNoRows { // Insert new result, err := db.Exec(`INSERT INTO review_notes (analysis_id, scope, scope_key, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)`, analysisID, scope, scopeKey, content, now, now) if err != nil { return nil, fmt.Errorf("insert note: %w", err) } id, _ := result.LastInsertId() return &models.ReviewNote{ ID: id, AnalysisID: analysisID, Scope: scope, ScopeKey: scopeKey, Content: content, CreatedAt: now, UpdatedAt: now, }, nil } if err != nil { return nil, fmt.Errorf("query existing note: %w", err) } // Update existing _, err = db.Exec(`UPDATE review_notes SET content = ?, updated_at = ? WHERE id = ?`, content, now, existingID) if err != nil { return nil, fmt.Errorf("update note: %w", err) } return &models.ReviewNote{ ID: existingID, AnalysisID: analysisID, Scope: scope, ScopeKey: scopeKey, Content: content, UpdatedAt: now, }, nil } // GetNotes returns all review notes for a given analysis, optionally filtered by scope. func GetNotes(db *sql.DB, analysisID int64, scope string) ([]models.ReviewNote, error) { var rows *sql.Rows var err error if scope != "" { rows, err = db.Query(`SELECT id, analysis_id, scope, scope_key, content, created_at, updated_at FROM review_notes WHERE analysis_id = ? AND scope = ? ORDER BY id`, analysisID, scope) } else { rows, err = db.Query(`SELECT id, analysis_id, scope, scope_key, content, created_at, updated_at FROM review_notes WHERE analysis_id = ? ORDER BY id`, analysisID) } if err != nil { return nil, fmt.Errorf("query notes: %w", err) } defer rows.Close() var notes []models.ReviewNote for rows.Next() { var n models.ReviewNote if err := rows.Scan(&n.ID, &n.AnalysisID, &n.Scope, &n.ScopeKey, &n.Content, &n.CreatedAt, &n.UpdatedAt); err != nil { continue } notes = append(notes, n) } return notes, nil } // DeleteNote deletes a specific review note by ID. func DeleteNote(db *sql.DB, noteID int64) error { _, err := db.Exec(`DELETE FROM review_notes WHERE id = ?`, noteID) return err }