-- Time-boxed "not right now" on a Discover artist suggestion (#2374). -- -- See 0049_suggestion_snoozes.up.sql for why this is a snooze and not a -- dismissal: it records no verdict on the music, expires on its own, and -- must never reach the taste profile. Nothing in internal/taste may read -- this table. -- name: SnoozeSuggestion :exec -- Upsert, so re-snoozing an already-snoozed candidate EXTENDS it instead of -- erroring on the PK. The name is refreshed too — a later suggestion may -- carry a corrected spelling from the similarity feed. -- $1=user_id, $2=candidate_mbid, $3=candidate_name, $4=duration in days. INSERT INTO suggestion_snoozes (user_id, candidate_mbid, candidate_name, snoozed_until) VALUES ($1, $2, $3, now() + ($4::float8 * INTERVAL '1 day')) ON CONFLICT (user_id, candidate_mbid) DO UPDATE SET snoozed_until = EXCLUDED.snoozed_until, candidate_name = EXCLUDED.candidate_name; -- name: UnsnoozeSuggestion :execrows -- Row count is returned so the handler can 404 an MBID that was never -- snoozed rather than reporting success for a no-op. DELETE FROM suggestion_snoozes WHERE user_id = $1 AND candidate_mbid = $2; -- name: ListActiveSuggestionSnoozes :many -- Backs the manage / un-snooze surface. Expired rows are filtered HERE -- rather than left to the sweeper: gc runs on an hourly tick, so a row can -- outlive its expiry by up to a tick and must not read as still-snoozed in -- the meantime. SELECT candidate_mbid, candidate_name, snoozed_until, created_at FROM suggestion_snoozes WHERE user_id = $1 AND snoozed_until > now() ORDER BY snoozed_until, candidate_mbid; -- name: GcDeleteExpiredSuggestionSnoozes :execrows -- Keeps the table from growing without bound. Every read already filters on -- snoozed_until > now(), so deleting an expired row changes no behaviour — -- this is purely reclamation. DELETE FROM suggestion_snoozes WHERE snoozed_until < now();