-- name: CreateRequest :one INSERT INTO requests ( user_id, kind, artist_mbid, album_mbid, track_mbid, artist_name, album_title, track_title ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *; -- name: GetRequestByID :one SELECT * FROM requests WHERE id = $1; -- name: ListRequestsForUser :many SELECT * FROM requests WHERE user_id = $1 ORDER BY requested_at DESC LIMIT $2; -- name: ListRequestsByStatus :many SELECT * FROM requests WHERE status = $1 ORDER BY requested_at DESC LIMIT $2; -- name: ListApprovedRequestsForReconcile :many SELECT * FROM requests WHERE status = 'approved' ORDER BY decided_at ASC LIMIT $1; -- name: ApproveRequest :one UPDATE requests SET status = 'approved', decided_at = now(), decided_by = $2, updated_at = now() WHERE id = $1 AND status = 'pending' RETURNING *; -- name: RejectRequest :one UPDATE requests SET status = 'rejected', notes = $2, decided_at = now(), decided_by = $3, updated_at = now() WHERE id = $1 AND status = 'pending' RETURNING *; -- name: CancelRequest :one -- $2 serves as both the ownership guard (user_id = $2) and the -- decided_by audit field. The generated parameter struct names it -- DecidedBy — callers must pass the cancelling user's UUID, and -- a wrong UUID will silently no-op (zero rows updated) rather than -- erroring at the SQL layer. UPDATE requests SET status = 'rejected', notes = 'cancelled by user', decided_at = now(), decided_by = $2, updated_at = now() WHERE id = $1 AND user_id = $2 AND status = 'pending' RETURNING *; -- name: CompleteRequest :one -- Reconciler transitions an approved request to completed when its -- target track/album/artist has appeared in the library. Callers -- should set ONLY the matched_*_id corresponding to the request's -- kind and pass pgtype.UUID{} (Valid: false) for the others — -- per-kind one-of-three is the contract, NULL for the others -- preserves auditability if the matched row is later evicted. UPDATE requests SET status = 'completed', matched_track_id = $2, matched_album_id = $3, matched_artist_id = $4, completed_at = now(), updated_at = now() WHERE id = $1 AND status = 'approved' RETURNING *; -- name: HasNonTerminalRequestForMBID :one -- Whether something is already on its way: a pending, approved or completed -- request at the given level, an open want for the release group, or a -- follow of the artist. Sets the `requested` flag on catalogue search. -- Terminal-status (rejected, failed) requests do not count. MBIDs are unique -- per entity type, so checking one id against every column cannot -- false-match. SELECT (EXISTS ( SELECT 1 FROM requests r WHERE r.status IN ('pending', 'approved', 'completed') AND ((r.kind = 'artist' AND r.artist_mbid = @mbid) OR (r.kind = 'album' AND r.album_mbid = @mbid) OR (r.kind = 'track' AND r.track_mbid = @mbid)) ) OR EXISTS ( SELECT 1 FROM wants w WHERE w.release_group_mbid = @mbid AND w.fulfilled_at IS NULL ) OR EXISTS ( SELECT 1 FROM follows f WHERE f.artist_mbid = @mbid ))::bool AS requested; -- name: GetNonTerminalRequestForMBID :one -- Returns the oldest non-terminal (pending/approved/completed) request -- whose own-kind MBID matches @mbid, or pgx.ErrNoRows when none. Create() -- uses this to dedupe: a re-request for something already in flight -- returns the existing row instead of inserting a duplicate. SELECT * FROM requests WHERE status IN ('pending', 'approved', 'completed') AND ((kind = 'artist' AND artist_mbid = @mbid) OR (kind = 'album' AND album_mbid = @mbid) OR (kind = 'track' AND track_mbid = @mbid)) ORDER BY requested_at ASC LIMIT 1; -- name: RepointRequestsAlbumMbid :exec -- A want moved from a release id to its group (#5241) takes the requests -- that name it along, so the reconciler finds it. UPDATE requests SET album_mbid = sqlc.arg(new_mbid), updated_at = now() WHERE album_mbid = sqlc.arg(old_mbid);