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>
368 lines
12 KiB
Go
368 lines
12 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: you_might_like.sql
|
|
|
|
package dbq
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const countListeningSignalForUser = `-- name: CountListeningSignalForUser :one
|
|
|
|
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
|
|
`
|
|
|
|
type CountListeningSignalForUserRow struct {
|
|
DistinctTracks int64
|
|
DistinctArtists int64
|
|
}
|
|
|
|
// "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.
|
|
// 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.
|
|
func (q *Queries) CountListeningSignalForUser(ctx context.Context, userID pgtype.UUID) (CountListeningSignalForUserRow, error) {
|
|
row := q.db.QueryRow(ctx, countListeningSignalForUser, userID)
|
|
var i CountListeningSignalForUserRow
|
|
err := row.Scan(&i.DistinctTracks, &i.DistinctArtists)
|
|
return i, err
|
|
}
|
|
|
|
const deleteYouMightLikeAlbumsForUser = `-- name: DeleteYouMightLikeAlbumsForUser :exec
|
|
DELETE FROM you_might_like_albums WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteYouMightLikeAlbumsForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteYouMightLikeAlbumsForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const deleteYouMightLikeArtistsForUser = `-- name: DeleteYouMightLikeArtistsForUser :exec
|
|
DELETE FROM you_might_like_artists WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteYouMightLikeArtistsForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteYouMightLikeArtistsForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const insertYouMightLikeAlbum = `-- name: InsertYouMightLikeAlbum :exec
|
|
INSERT INTO you_might_like_albums (user_id, album_id, rank)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertYouMightLikeAlbumParams struct {
|
|
UserID pgtype.UUID
|
|
AlbumID pgtype.UUID
|
|
Rank int32
|
|
}
|
|
|
|
func (q *Queries) InsertYouMightLikeAlbum(ctx context.Context, arg InsertYouMightLikeAlbumParams) error {
|
|
_, err := q.db.Exec(ctx, insertYouMightLikeAlbum, arg.UserID, arg.AlbumID, arg.Rank)
|
|
return err
|
|
}
|
|
|
|
const insertYouMightLikeArtist = `-- name: InsertYouMightLikeArtist :exec
|
|
INSERT INTO you_might_like_artists (user_id, artist_id, rank)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertYouMightLikeArtistParams struct {
|
|
UserID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Rank int32
|
|
}
|
|
|
|
func (q *Queries) InsertYouMightLikeArtist(ctx context.Context, arg InsertYouMightLikeArtistParams) error {
|
|
_, err := q.db.Exec(ctx, insertYouMightLikeArtist, arg.UserID, arg.ArtistID, arg.Rank)
|
|
return err
|
|
}
|
|
|
|
const listYouMightLikeAlbumFallbackForUser = `-- name: ListYouMightLikeAlbumFallbackForUser :many
|
|
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 albums.id, albums.title, albums.sort_title, albums.artist_id, albums.release_date, albums.mbid, albums.cover_art_path, albums.created_at, albums.updated_at, albums.cover_art_source, albums.cover_art_sources_version, albums.release_group_mbid, 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
|
|
`
|
|
|
|
type ListYouMightLikeAlbumFallbackForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListYouMightLikeAlbumFallbackForUserRow struct {
|
|
Album Album
|
|
ArtistName string
|
|
}
|
|
|
|
// Broad "albums you've shown affinity for" pool: explicitly liked albums PLUS
|
|
// the albums of liked tracks. Same projection as ListYouMightLikeAlbumsForUser.
|
|
func (q *Queries) ListYouMightLikeAlbumFallbackForUser(ctx context.Context, arg ListYouMightLikeAlbumFallbackForUserParams) ([]ListYouMightLikeAlbumFallbackForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listYouMightLikeAlbumFallbackForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListYouMightLikeAlbumFallbackForUserRow
|
|
for rows.Next() {
|
|
var i ListYouMightLikeAlbumFallbackForUserRow
|
|
if err := rows.Scan(
|
|
&i.Album.ID,
|
|
&i.Album.Title,
|
|
&i.Album.SortTitle,
|
|
&i.Album.ArtistID,
|
|
&i.Album.ReleaseDate,
|
|
&i.Album.Mbid,
|
|
&i.Album.CoverArtPath,
|
|
&i.Album.CreatedAt,
|
|
&i.Album.UpdatedAt,
|
|
&i.Album.CoverArtSource,
|
|
&i.Album.CoverArtSourcesVersion,
|
|
&i.Album.ReleaseGroupMbid,
|
|
&i.ArtistName,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listYouMightLikeAlbumsForUser = `-- name: ListYouMightLikeAlbumsForUser :many
|
|
SELECT albums.id, albums.title, albums.sort_title, albums.artist_id, albums.release_date, albums.mbid, albums.cover_art_path, albums.created_at, albums.updated_at, albums.cover_art_source, albums.cover_art_sources_version, albums.release_group_mbid, 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
|
|
`
|
|
|
|
type ListYouMightLikeAlbumsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListYouMightLikeAlbumsForUserRow struct {
|
|
Album Album
|
|
ArtistName string
|
|
}
|
|
|
|
// 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).
|
|
func (q *Queries) ListYouMightLikeAlbumsForUser(ctx context.Context, arg ListYouMightLikeAlbumsForUserParams) ([]ListYouMightLikeAlbumsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listYouMightLikeAlbumsForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListYouMightLikeAlbumsForUserRow
|
|
for rows.Next() {
|
|
var i ListYouMightLikeAlbumsForUserRow
|
|
if err := rows.Scan(
|
|
&i.Album.ID,
|
|
&i.Album.Title,
|
|
&i.Album.SortTitle,
|
|
&i.Album.ArtistID,
|
|
&i.Album.ReleaseDate,
|
|
&i.Album.Mbid,
|
|
&i.Album.CoverArtPath,
|
|
&i.Album.CreatedAt,
|
|
&i.Album.UpdatedAt,
|
|
&i.Album.CoverArtSource,
|
|
&i.Album.CoverArtSourcesVersion,
|
|
&i.Album.ReleaseGroupMbid,
|
|
&i.ArtistName,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listYouMightLikeArtistFallbackForUser = `-- name: ListYouMightLikeArtistFallbackForUser :many
|
|
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 artists.id, artists.name, artists.sort_name, artists.mbid, artists.created_at, artists.updated_at, artists.artist_thumb_path, artists.artist_fanart_path, artists.artist_art_source, artists.artist_art_sources_version,
|
|
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
|
|
`
|
|
|
|
type ListYouMightLikeArtistFallbackForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListYouMightLikeArtistFallbackForUserRow struct {
|
|
Artist Artist
|
|
CoverAlbumID pgtype.UUID
|
|
AlbumCount int64
|
|
}
|
|
|
|
// 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.
|
|
func (q *Queries) ListYouMightLikeArtistFallbackForUser(ctx context.Context, arg ListYouMightLikeArtistFallbackForUserParams) ([]ListYouMightLikeArtistFallbackForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listYouMightLikeArtistFallbackForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListYouMightLikeArtistFallbackForUserRow
|
|
for rows.Next() {
|
|
var i ListYouMightLikeArtistFallbackForUserRow
|
|
if err := rows.Scan(
|
|
&i.Artist.ID,
|
|
&i.Artist.Name,
|
|
&i.Artist.SortName,
|
|
&i.Artist.Mbid,
|
|
&i.Artist.CreatedAt,
|
|
&i.Artist.UpdatedAt,
|
|
&i.Artist.ArtistThumbPath,
|
|
&i.Artist.ArtistFanartPath,
|
|
&i.Artist.ArtistArtSource,
|
|
&i.Artist.ArtistArtSourcesVersion,
|
|
&i.CoverAlbumID,
|
|
&i.AlbumCount,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listYouMightLikeArtistsForUser = `-- name: ListYouMightLikeArtistsForUser :many
|
|
SELECT artists.id, artists.name, artists.sort_name, artists.mbid, artists.created_at, artists.updated_at, artists.artist_thumb_path, artists.artist_fanart_path, artists.artist_art_source, artists.artist_art_sources_version,
|
|
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
|
|
`
|
|
|
|
type ListYouMightLikeArtistsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListYouMightLikeArtistsForUserRow struct {
|
|
Artist Artist
|
|
CoverAlbumID pgtype.UUID
|
|
AlbumCount int64
|
|
}
|
|
|
|
// 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.
|
|
func (q *Queries) ListYouMightLikeArtistsForUser(ctx context.Context, arg ListYouMightLikeArtistsForUserParams) ([]ListYouMightLikeArtistsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listYouMightLikeArtistsForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListYouMightLikeArtistsForUserRow
|
|
for rows.Next() {
|
|
var i ListYouMightLikeArtistsForUserRow
|
|
if err := rows.Scan(
|
|
&i.Artist.ID,
|
|
&i.Artist.Name,
|
|
&i.Artist.SortName,
|
|
&i.Artist.Mbid,
|
|
&i.Artist.CreatedAt,
|
|
&i.Artist.UpdatedAt,
|
|
&i.Artist.ArtistThumbPath,
|
|
&i.Artist.ArtistFanartPath,
|
|
&i.Artist.ArtistArtSource,
|
|
&i.Artist.ArtistArtSourcesVersion,
|
|
&i.CoverAlbumID,
|
|
&i.AlbumCount,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|