-- "You might like" Home rows (#790). 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;