// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: recommendation_metrics.sql package dbq import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const recommendationSourceMetricsForUser = `-- name: RecommendationSourceMetricsForUser :many SELECT pe.source, pe.pick_kind, count(*)::bigint AS plays, count(*) FILTER (WHERE pe.was_skipped)::bigint AS skips, count(pe.completion_ratio)::bigint AS completion_n, COALESCE(avg(pe.completion_ratio), 0)::float8 AS avg_completion FROM play_events pe WHERE pe.user_id = $1 AND pe.started_at > now() - ($2::float8 * INTERVAL '1 day') GROUP BY pe.source, pe.pick_kind ORDER BY plays DESC ` type RecommendationSourceMetricsForUserParams struct { UserID pgtype.UUID Column2 float64 } type RecommendationSourceMetricsForUserRow struct { Source *string PickKind *string Plays int64 Skips int64 CompletionN int64 AvgCompletion float64 } // $1 user_id, $2 window_days. plays/skips are counts; avg_completion is the // mean completion ratio over the completion_n plays that recorded one. // pick_kind splits For You plays into taste/fresh/unattributed (#1249); // it is NULL for every other source, so those still group to one row. func (q *Queries) RecommendationSourceMetricsForUser(ctx context.Context, arg RecommendationSourceMetricsForUserParams) ([]RecommendationSourceMetricsForUserRow, error) { rows, err := q.db.Query(ctx, recommendationSourceMetricsForUser, arg.UserID, arg.Column2) if err != nil { return nil, err } defer rows.Close() var items []RecommendationSourceMetricsForUserRow for rows.Next() { var i RecommendationSourceMetricsForUserRow if err := rows.Scan( &i.Source, &i.PickKind, &i.Plays, &i.Skips, &i.CompletionN, &i.AvgCompletion, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const recommendationWeeklyTrends = `-- name: RecommendationWeeklyTrends :many SELECT date_trunc('week', pe.started_at)::date AS week_start, pe.source, count(*)::bigint AS plays, count(*) FILTER (WHERE pe.was_skipped)::bigint AS skips, count(pe.completion_ratio)::bigint AS completion_n, COALESCE(avg(pe.completion_ratio), 0)::float8 AS avg_completion, count(*) FILTER (WHERE tpa.artist_id IS NOT NULL)::bigint AS taste_hits FROM play_events pe JOIN tracks t ON t.id = pe.track_id LEFT JOIN taste_profile_artists tpa ON tpa.user_id = pe.user_id AND tpa.artist_id = t.artist_id AND tpa.weight > 0 WHERE pe.started_at > now() - ($1::int * INTERVAL '1 week') GROUP BY 1, 2 ORDER BY 1, 2 ` type RecommendationWeeklyTrendsRow struct { WeekStart pgtype.Date Source *string Plays int64 Skips int64 CompletionN int64 AvgCompletion float64 TasteHits int64 } // Recommendation observability (#796 phase 4). Per-source play outcomes so the // operator can see whether each recommendation surface is landing and tune the // taste weights. Source is stamped on play_events when a play is launched from // a recommendation surface; NULL means the user picked the track manually — // those rows are INCLUDED here as the baseline control group the surfaces are // judged against (milestone #127: delta-vs-baseline is what makes the numbers // actionable). Raw source strings are bucketed into stable surface families in // the Go handler; completion_n is carried so family merges can weight // avg_completion correctly. // Weekly per-source outcome series for the tuning lab's trend view // (#1251). Aggregated across ALL users: the tuning knobs are global, // so judging a knob turn needs global outcomes — rows carry rates // only, no track or user identity. NULL-source (manual) rows are // included as the baseline family. // // taste_hits counts plays whose track's artist has a positive weight // in that user's CURRENT taste profile — the "cheap recompute" option: // retroactive over the whole window, at the cost of drift (the profile // is today's, the play may be weeks old). Good enough to read whether // a surface is feeding taste-fitting tracks. // $1 window in weeks. func (q *Queries) RecommendationWeeklyTrends(ctx context.Context, weeks int32) ([]RecommendationWeeklyTrendsRow, error) { rows, err := q.db.Query(ctx, recommendationWeeklyTrends, weeks) if err != nil { return nil, err } defer rows.Close() var items []RecommendationWeeklyTrendsRow for rows.Next() { var i RecommendationWeeklyTrendsRow if err := rows.Scan( &i.WeekStart, &i.Source, &i.Plays, &i.Skips, &i.CompletionN, &i.AvgCompletion, &i.TasteHits, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil }