Files
minstrel/internal/db/queries/you_might_like.sql
T
bvandeusenandClaude Opus 5.5 1d4ef1a23f docs: query comments say what each query selects and why, not how it came to be (#6277)
Rewrites the internal/db/queries comments to rule 32 and regenerates
dbq, whose doc comments and embedded SQL carry them. The bugs behind the
tiered mixes, the md5 order seed, the score bands and the round-robin
arms are restated as the constraint each one enforces; counts from one
library and stale cross-references are gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 12:31:13 -04:00

126 lines
4.7 KiB
SQL

-- "You might like" Home rows. The daily build computes ranked
-- album/artist IDs in Go (similarity roll-up + cold-start gate) and
-- atomic-replaces them here; /api/home reads them back hydrated.
-- name: CountListeningSignalForUser :one
-- Cold-start gate. Returns the breadth of the user's real listening:
-- distinct unskipped tracks played and distinct artists played. The
-- build skips You-might-like entirely below a threshold (a thin history
-- yields near-random roll-ups). was_skipped=false so a user spamming
-- next can't inflate the signal.
SELECT
count(DISTINCT pe.track_id)::bigint AS distinct_tracks,
count(DISTINCT t.artist_id)::bigint AS distinct_artists
FROM play_events pe
JOIN tracks t ON t.id = pe.track_id
WHERE pe.user_id = $1 AND pe.was_skipped = false;
-- name: DeleteYouMightLikeAlbumsForUser :exec
DELETE FROM you_might_like_albums WHERE user_id = $1;
-- name: InsertYouMightLikeAlbum :exec
INSERT INTO you_might_like_albums (user_id, album_id, rank)
VALUES ($1, $2, $3);
-- name: DeleteYouMightLikeArtistsForUser :exec
DELETE FROM you_might_like_artists WHERE user_id = $1;
-- name: InsertYouMightLikeArtist :exec
INSERT INTO you_might_like_artists (user_id, artist_id, rank)
VALUES ($1, $2, $3);
-- name: ListYouMightLikeAlbumsForUser :many
-- Read path. Same projection as ListRediscoverAlbumsForUser so the API
-- layer reuses albumRefFrom(row.Album, row.ArtistName, …). Ordered by
-- the rank persisted at build time. Final cross-section dedup (vs Most
-- Played / Rediscover) and the output cap land in the Go layer
-- (internal/recommendation/home.go).
SELECT sqlc.embed(albums), artists.name AS artist_name
FROM you_might_like_albums yml
JOIN albums ON albums.id = yml.album_id
JOIN artists ON artists.id = albums.artist_id
WHERE yml.user_id = $1
ORDER BY yml.rank
LIMIT $2;
-- name: ListYouMightLikeArtistsForUser :many
-- Read path. Same projection as ListRediscoverArtistsForUser (embeds the
-- artist + a representative cover_album_id + album_count) so the API
-- layer reuses artistRefFromCovered. Ordered by persisted rank.
SELECT sqlc.embed(artists),
cov.id AS cover_album_id,
cnt.album_count::bigint AS album_count
FROM you_might_like_artists yml
JOIN artists ON artists.id = yml.artist_id
LEFT JOIN LATERAL (
SELECT id FROM albums
WHERE artist_id = artists.id AND cover_art_path IS NOT NULL
ORDER BY created_at DESC LIMIT 1
) cov ON true
LEFT JOIN LATERAL (
SELECT count(*) AS album_count
FROM albums WHERE artist_id = artists.id
) cnt ON true
WHERE yml.user_id = $1
ORDER BY yml.rank
LIMIT $2;
-- name: ListYouMightLikeArtistFallbackForUser :many
-- Broad "artists you've shown affinity for" pool to fill a thin
-- You-might-like artists row: explicitly liked artists PLUS the artists of
-- liked albums and liked tracks. Most users like albums/tracks far more than
-- they like artists explicitly, so the union is much deeper than
-- general_likes_artists alone. Daily-stable order; same projection as
-- ListYouMightLikeArtistsForUser so the Go layer reuses it directly.
WITH liked_artist_ids AS (
SELECT lika.artist_id AS artist_id
FROM general_likes_artists lika
WHERE lika.user_id = $1
UNION
SELECT alb.artist_id AS artist_id
FROM general_likes_albums likb
JOIN albums alb ON alb.id = likb.album_id
WHERE likb.user_id = $1
UNION
SELECT trk.artist_id AS artist_id
FROM general_likes likt
JOIN tracks trk ON trk.id = likt.track_id
WHERE likt.user_id = $1
)
SELECT sqlc.embed(artists),
cov.id AS cover_album_id,
cnt.album_count::bigint AS album_count
FROM liked_artist_ids lai
JOIN artists ON artists.id = lai.artist_id
LEFT JOIN LATERAL (
SELECT id FROM albums
WHERE artist_id = artists.id AND cover_art_path IS NOT NULL
ORDER BY created_at DESC LIMIT 1
) cov ON true
LEFT JOIN LATERAL (
SELECT count(*) AS album_count
FROM albums WHERE artist_id = artists.id
) cnt ON true
ORDER BY md5(artists.id::text || current_date::text)
LIMIT $2;
-- name: ListYouMightLikeAlbumFallbackForUser :many
-- Broad "albums you've shown affinity for" pool: explicitly liked albums PLUS
-- the albums of liked tracks. Same projection as ListYouMightLikeAlbumsForUser.
WITH liked_album_ids AS (
SELECT likb.album_id AS album_id
FROM general_likes_albums likb
WHERE likb.user_id = $1
UNION
SELECT trk.album_id AS album_id
FROM general_likes likt
JOIN tracks trk ON trk.id = likt.track_id
WHERE likt.user_id = $1
)
SELECT sqlc.embed(albums), artists.name AS artist_name
FROM liked_album_ids lai
JOIN albums ON albums.id = lai.album_id
JOIN artists ON artists.id = albums.artist_id
ORDER BY md5(albums.id::text || current_date::text)
LIMIT $2;