Files
NaviWatcher/internal/database/notifications.go
Vladimir Zagainov 5c2aadaab6 fix: address code review findings
- Add is_ignored=0 filter to GetUnnotifiedReleases query per spec section 4.4
  (notification lifecycle must exclude ignored releases)
- Add FK constraint on notifications_sent.rgid referencing external_releases(rgid)
  per spec schema definition
- Wrap migration application + recording in transactions for atomicity
- Add config.yaml to .gitignore to prevent accidental secret commits
- Pin Dockerfile base image to alpine:3.21 and add non-root appuser
- Add test TestGetUnnotifiedReleases_IgnoredExcluded

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 11:46:51 +03:00

70 lines
2.0 KiB
Go

package database
import (
"fmt"
)
// MarkNotificationSent records that a notification has been sent for the given RGID.
func MarkNotificationSent(db *DB, rgid string) error {
_, err := db.Conn().Exec(
"INSERT INTO notifications_sent (rgid) VALUES (?)",
rgid,
)
if err != nil {
return fmt.Errorf("mark notification sent: %w", err)
}
return nil
}
// IsNotificationSent checks whether a notification has already been sent for the given RGID.
func IsNotificationSent(db *DB, rgid string) (bool, error) {
var count int
err := db.Conn().QueryRow(
"SELECT COUNT(*) FROM notifications_sent WHERE rgid = ?", rgid,
).Scan(&count)
if err != nil {
return false, fmt.Errorf("check notification sent: %w", err)
}
return count > 0, nil
}
// GetUnnotifiedReleases returns all external_release rows that have no entry in notifications_sent.
func GetUnnotifiedReleases(db *DB) ([]ExternalRelease, error) {
rows, err := db.Conn().Query(`
SELECT e.rgid, e.artist_id, e.title, e.type, e.release_date, e.is_ignored
FROM external_releases e
LEFT JOIN notifications_sent n ON e.rgid = n.rgid
WHERE n.rgid IS NULL AND e.is_ignored = 0
`)
if err != nil {
return nil, fmt.Errorf("query unnotified releases: %w", err)
}
defer rows.Close()
var results []ExternalRelease
for rows.Next() {
var r ExternalRelease
if err := rows.Scan(&r.RGID, &r.ArtistID, &r.Title, &r.Type, &r.ReleaseDate, &r.IsIgnored); err != nil {
return nil, fmt.Errorf("scan unnotified release: %w", err)
}
results = append(results, r)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate unnotified releases: %w", err)
}
return results, nil
}
// GetNotificationSentAt returns the sent_at time for a given RGID.
// Returns sql.ErrNoRows if no notification has been sent.
func GetNotificationSentAt(db *DB, rgid string) (string, error) {
var sentAt string
err := db.Conn().QueryRow(
"SELECT sent_at FROM notifications_sent WHERE rgid = ? ORDER BY sent_at DESC LIMIT 1", rgid,
).Scan(&sentAt)
if err != nil {
return "", err
}
return sentAt, nil
}