-- name: UpsertQuarantine :one -- Insert a new quarantine row, or update reason/notes if the user has -- already flagged this track. INSERT INTO lidarr_quarantine (user_id, track_id, reason, notes) VALUES ($1, $2, $3, $4) ON CONFLICT (user_id, track_id) DO UPDATE SET reason = EXCLUDED.reason, notes = EXCLUDED.notes, created_at = now() RETURNING user_id, track_id, reason, notes, created_at; -- name: DeleteQuarantine :one -- Removes the caller's row. Returns the deleted row so the handler can -- distinguish "no row existed" (zero rows -> ErrNoRows) from success. DELETE FROM lidarr_quarantine WHERE user_id = $1 AND track_id = $2 RETURNING user_id, track_id, reason, notes, created_at; -- name: ListQuarantineForUser :many -- Caller's own quarantines plus just the joined fields the SPA's -- /library/hidden actually renders. Embedding the full tracks/albums/artists -- structs would drag ~28 columns of file_path / sort_* / mbid / etc. that -- the row card never uses. SELECT sqlc.embed(q), t.id AS track_id_join, t.title AS track_title, t.duration_ms AS track_duration_ms, al.id AS album_id, al.title AS album_title, al.cover_art_path AS album_cover_art_path, ar.id AS artist_id, ar.name AS artist_name FROM lidarr_quarantine q JOIN tracks t ON t.id = q.track_id JOIN albums al ON al.id = t.album_id JOIN artists ar ON ar.id = t.artist_id WHERE q.user_id = $1 ORDER BY q.created_at DESC; -- name: ListAdminQuarantineQueue :many -- Aggregated admin queue. One row per track. The handler post-processes -- the rows it gets from this query plus a per-track ListQuarantineReports -- call to materialize reason_counts and the per-user reports list. SELECT t.id AS track_id, t.title AS track_title, ar.name AS artist_name, al.title AS album_title, al.id AS album_id, al.mbid AS lidarr_album_mbid, count(q.user_id)::int AS report_count, max(q.created_at)::timestamptz AS latest_at FROM lidarr_quarantine q JOIN tracks t ON t.id = q.track_id JOIN albums al ON al.id = t.album_id JOIN artists ar ON ar.id = t.artist_id GROUP BY t.id, ar.name, al.title, al.id, al.mbid ORDER BY max(q.created_at) DESC; -- name: ListQuarantineReportsForTrack :many -- Per-user reports for a single track. Returned by ListAdminQuarantineQueue -- post-processing and exposed expandable in the SPA admin queue rows. SELECT q.user_id, u.username, q.reason, q.notes, q.created_at FROM lidarr_quarantine q JOIN users u ON u.id = q.user_id WHERE q.track_id = $1 ORDER BY q.created_at DESC; -- name: DeleteQuarantineForTrack :exec -- Clears all per-user rows for a given track. Used by Resolve and the -- two delete actions. Caller writes the audit row separately before -- this fires (so we can capture the affected_users count). DELETE FROM lidarr_quarantine WHERE track_id = $1; -- name: CountQuarantineForTrack :one -- Reads affected_users for the audit row before the delete fires. SELECT count(*)::int FROM lidarr_quarantine WHERE track_id = $1; -- name: WriteQuarantineAction :one -- Audit row for an admin destructive action. INSERT INTO lidarr_quarantine_actions ( track_id, track_title, artist_name, album_title, action, admin_id, lidarr_album_mbid, affected_users ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *; -- name: ListQuarantineActions :many SELECT * FROM lidarr_quarantine_actions ORDER BY created_at DESC LIMIT $1;