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>
408 lines
11 KiB
Go
408 lines
11 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: taste_profile.sql
|
|
|
|
package dbq
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const deleteTasteProfileArtistsForUser = `-- name: DeleteTasteProfileArtistsForUser :exec
|
|
DELETE FROM taste_profile_artists WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteTasteProfileArtistsForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteTasteProfileArtistsForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const deleteTasteProfileErasForUser = `-- name: DeleteTasteProfileErasForUser :exec
|
|
DELETE FROM taste_profile_eras WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteTasteProfileErasForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteTasteProfileErasForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const deleteTasteProfileMoodsForUser = `-- name: DeleteTasteProfileMoodsForUser :exec
|
|
DELETE FROM taste_profile_moods WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteTasteProfileMoodsForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteTasteProfileMoodsForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const deleteTasteProfileTagsForUser = `-- name: DeleteTasteProfileTagsForUser :exec
|
|
DELETE FROM taste_profile_tags WHERE user_id = $1
|
|
`
|
|
|
|
func (q *Queries) DeleteTasteProfileTagsForUser(ctx context.Context, userID pgtype.UUID) error {
|
|
_, err := q.db.Exec(ctx, deleteTasteProfileTagsForUser, userID)
|
|
return err
|
|
}
|
|
|
|
const insertTasteProfileArtist = `-- name: InsertTasteProfileArtist :exec
|
|
INSERT INTO taste_profile_artists (user_id, artist_id, weight)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertTasteProfileArtistParams struct {
|
|
UserID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Weight float64
|
|
}
|
|
|
|
func (q *Queries) InsertTasteProfileArtist(ctx context.Context, arg InsertTasteProfileArtistParams) error {
|
|
_, err := q.db.Exec(ctx, insertTasteProfileArtist, arg.UserID, arg.ArtistID, arg.Weight)
|
|
return err
|
|
}
|
|
|
|
const insertTasteProfileEra = `-- name: InsertTasteProfileEra :exec
|
|
INSERT INTO taste_profile_eras (user_id, era, weight)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertTasteProfileEraParams struct {
|
|
UserID pgtype.UUID
|
|
Era string
|
|
Weight float64
|
|
}
|
|
|
|
func (q *Queries) InsertTasteProfileEra(ctx context.Context, arg InsertTasteProfileEraParams) error {
|
|
_, err := q.db.Exec(ctx, insertTasteProfileEra, arg.UserID, arg.Era, arg.Weight)
|
|
return err
|
|
}
|
|
|
|
const insertTasteProfileMood = `-- name: InsertTasteProfileMood :exec
|
|
INSERT INTO taste_profile_moods (user_id, mood, weight)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertTasteProfileMoodParams struct {
|
|
UserID pgtype.UUID
|
|
Mood string
|
|
Weight float64
|
|
}
|
|
|
|
func (q *Queries) InsertTasteProfileMood(ctx context.Context, arg InsertTasteProfileMoodParams) error {
|
|
_, err := q.db.Exec(ctx, insertTasteProfileMood, arg.UserID, arg.Mood, arg.Weight)
|
|
return err
|
|
}
|
|
|
|
const insertTasteProfileTag = `-- name: InsertTasteProfileTag :exec
|
|
INSERT INTO taste_profile_tags (user_id, tag, weight)
|
|
VALUES ($1, $2, $3)
|
|
`
|
|
|
|
type InsertTasteProfileTagParams struct {
|
|
UserID pgtype.UUID
|
|
Tag string
|
|
Weight float64
|
|
}
|
|
|
|
func (q *Queries) InsertTasteProfileTag(ctx context.Context, arg InsertTasteProfileTagParams) error {
|
|
_, err := q.db.Exec(ctx, insertTasteProfileTag, arg.UserID, arg.Tag, arg.Weight)
|
|
return err
|
|
}
|
|
|
|
const listLikedArtistIDsForUser = `-- name: ListLikedArtistIDsForUser :many
|
|
SELECT artist_id FROM general_likes_artists WHERE user_id = $1
|
|
`
|
|
|
|
// Artists the user has explicitly liked; feeds the artist-like bonus.
|
|
func (q *Queries) ListLikedArtistIDsForUser(ctx context.Context, userID pgtype.UUID) ([]pgtype.UUID, error) {
|
|
rows, err := q.db.Query(ctx, listLikedArtistIDsForUser, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []pgtype.UUID
|
|
for rows.Next() {
|
|
var artist_id pgtype.UUID
|
|
if err := rows.Scan(&artist_id); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, artist_id)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listLikedTrackTasteInputsForUser = `-- name: ListLikedTrackTasteInputsForUser :many
|
|
SELECT t.id AS track_id, t.artist_id, t.genre, a.release_date
|
|
FROM general_likes gl
|
|
JOIN tracks t ON t.id = gl.track_id
|
|
JOIN albums a ON a.id = t.album_id
|
|
WHERE gl.user_id = $1
|
|
`
|
|
|
|
type ListLikedTrackTasteInputsForUserRow struct {
|
|
TrackID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Genre *string
|
|
ReleaseDate pgtype.Date
|
|
}
|
|
|
|
// (track_id, artist_id, genre, release_date) for each track the user has
|
|
// explicitly liked. Feeds the track-like bonus into the liked track's artist,
|
|
// tags, and era; track_id keys the enriched track_tags lookup.
|
|
func (q *Queries) ListLikedTrackTasteInputsForUser(ctx context.Context, userID pgtype.UUID) ([]ListLikedTrackTasteInputsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listLikedTrackTasteInputsForUser, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListLikedTrackTasteInputsForUserRow
|
|
for rows.Next() {
|
|
var i ListLikedTrackTasteInputsForUserRow
|
|
if err := rows.Scan(
|
|
&i.TrackID,
|
|
&i.ArtistID,
|
|
&i.Genre,
|
|
&i.ReleaseDate,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listPlayEngagementInputsForUser = `-- name: ListPlayEngagementInputsForUser :many
|
|
|
|
SELECT
|
|
t.id AS track_id,
|
|
t.artist_id,
|
|
t.genre,
|
|
a.release_date,
|
|
LEAST(GREATEST(
|
|
COALESCE(pe.completion_ratio,
|
|
pe.duration_played_ms::float8 / NULLIF(t.duration_ms, 0),
|
|
0), 0), 1)::float8 AS completion,
|
|
(EXTRACT(epoch FROM now() - pe.started_at) / 86400.0)::float8 AS age_days
|
|
FROM play_events pe
|
|
JOIN tracks t ON t.id = pe.track_id
|
|
JOIN albums a ON a.id = t.album_id
|
|
WHERE pe.user_id = $1
|
|
AND pe.started_at > now() - ($2::float8 * INTERVAL '1 day')
|
|
AND NOT EXISTS (
|
|
SELECT 1 FROM quarantine q
|
|
WHERE q.user_id = $1 AND q.track_id = t.id
|
|
)
|
|
`
|
|
|
|
type ListPlayEngagementInputsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Column2 float64
|
|
}
|
|
|
|
type ListPlayEngagementInputsForUserRow struct {
|
|
TrackID pgtype.UUID
|
|
ArtistID pgtype.UUID
|
|
Genre *string
|
|
ReleaseDate pgtype.Date
|
|
Completion float64
|
|
AgeDays float64
|
|
}
|
|
|
|
// Taste profile. The daily build computes signed artist/tag
|
|
// weights in Go (graded engagement + decay + like bonus) and atomic-replaces
|
|
// them here. Read queries serve the scorer's "top taste" lookups.
|
|
// One row per play in the decay-relevant window. completion is the play's
|
|
// completion ratio (precomputed column when present, else duration_played /
|
|
// track duration, clamped to [0,1]); age_days drives the time-decay. Genre
|
|
// is split into tags in Go; release_date derives the decade for the era
|
|
// facet. Quarantined tracks are excluded.
|
|
func (q *Queries) ListPlayEngagementInputsForUser(ctx context.Context, arg ListPlayEngagementInputsForUserParams) ([]ListPlayEngagementInputsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listPlayEngagementInputsForUser, arg.UserID, arg.Column2)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListPlayEngagementInputsForUserRow
|
|
for rows.Next() {
|
|
var i ListPlayEngagementInputsForUserRow
|
|
if err := rows.Scan(
|
|
&i.TrackID,
|
|
&i.ArtistID,
|
|
&i.Genre,
|
|
&i.ReleaseDate,
|
|
&i.Completion,
|
|
&i.AgeDays,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listTasteProfileArtistsForUser = `-- name: ListTasteProfileArtistsForUser :many
|
|
SELECT artist_id, weight
|
|
FROM taste_profile_artists
|
|
WHERE user_id = $1
|
|
ORDER BY weight DESC
|
|
LIMIT $2
|
|
`
|
|
|
|
type ListTasteProfileArtistsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListTasteProfileArtistsForUserRow struct {
|
|
ArtistID pgtype.UUID
|
|
Weight float64
|
|
}
|
|
|
|
// Top-weighted taste artists, for the scorer and tests.
|
|
func (q *Queries) ListTasteProfileArtistsForUser(ctx context.Context, arg ListTasteProfileArtistsForUserParams) ([]ListTasteProfileArtistsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listTasteProfileArtistsForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListTasteProfileArtistsForUserRow
|
|
for rows.Next() {
|
|
var i ListTasteProfileArtistsForUserRow
|
|
if err := rows.Scan(&i.ArtistID, &i.Weight); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listTasteProfileErasForUser = `-- name: ListTasteProfileErasForUser :many
|
|
SELECT era, weight
|
|
FROM taste_profile_eras
|
|
WHERE user_id = $1
|
|
ORDER BY weight DESC
|
|
LIMIT $2
|
|
`
|
|
|
|
type ListTasteProfileErasForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListTasteProfileErasForUserRow struct {
|
|
Era string
|
|
Weight float64
|
|
}
|
|
|
|
// Top-weighted taste eras; consumed by the scorer's era term.
|
|
func (q *Queries) ListTasteProfileErasForUser(ctx context.Context, arg ListTasteProfileErasForUserParams) ([]ListTasteProfileErasForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listTasteProfileErasForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListTasteProfileErasForUserRow
|
|
for rows.Next() {
|
|
var i ListTasteProfileErasForUserRow
|
|
if err := rows.Scan(&i.Era, &i.Weight); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listTasteProfileMoodsForUser = `-- name: ListTasteProfileMoodsForUser :many
|
|
SELECT mood, weight
|
|
FROM taste_profile_moods
|
|
WHERE user_id = $1
|
|
ORDER BY weight DESC
|
|
LIMIT $2
|
|
`
|
|
|
|
type ListTasteProfileMoodsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListTasteProfileMoodsForUserRow struct {
|
|
Mood string
|
|
Weight float64
|
|
}
|
|
|
|
// Top-weighted taste moods; consumed by the scorer's mood term.
|
|
func (q *Queries) ListTasteProfileMoodsForUser(ctx context.Context, arg ListTasteProfileMoodsForUserParams) ([]ListTasteProfileMoodsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listTasteProfileMoodsForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListTasteProfileMoodsForUserRow
|
|
for rows.Next() {
|
|
var i ListTasteProfileMoodsForUserRow
|
|
if err := rows.Scan(&i.Mood, &i.Weight); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const listTasteProfileTagsForUser = `-- name: ListTasteProfileTagsForUser :many
|
|
SELECT tag, weight
|
|
FROM taste_profile_tags
|
|
WHERE user_id = $1
|
|
ORDER BY weight DESC
|
|
LIMIT $2
|
|
`
|
|
|
|
type ListTasteProfileTagsForUserParams struct {
|
|
UserID pgtype.UUID
|
|
Limit int32
|
|
}
|
|
|
|
type ListTasteProfileTagsForUserRow struct {
|
|
Tag string
|
|
Weight float64
|
|
}
|
|
|
|
func (q *Queries) ListTasteProfileTagsForUser(ctx context.Context, arg ListTasteProfileTagsForUserParams) ([]ListTasteProfileTagsForUserRow, error) {
|
|
rows, err := q.db.Query(ctx, listTasteProfileTagsForUser, arg.UserID, arg.Limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListTasteProfileTagsForUserRow
|
|
for rows.Next() {
|
|
var i ListTasteProfileTagsForUserRow
|
|
if err := rows.Scan(&i.Tag, &i.Weight); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|