Files
yellowjacket/backend/database/sql/sqlcgen/home.sql.go
T
logan ff687f0bd9 feat(home): populate the home page with start-listening shelves
The sidebar had a Home item that fell through to "Coming soon". What
was missing was not another view of the library — four of those exist,
sorted and complete — but the opposite: a complete, sorted library is
exactly what gives you nothing to play, because every entry point into
it is alphabetical and identical every time you open the app.

So a shelf is a *reason*, not a filter. Each one answers a different
question you might be asking when you do not know what you want (what
was I listening to, what is new, what do I keep coming back to, what
have I forgotten, what fits, what would I never pick myself) and each
says which question it answered — a row of covers with no explanation
is just another grid.

Two consequences run through it. Shelves are built from what the user
actually did — play counts, last played, import order — with random
sampling only where there is no signal to use, so randomness is the
fallback rather than the design. And a shelf with nothing behind it is
omitted instead of rendered empty: a fresh library legitimately gets
three, and an empty row labelled "on repeat" would be a lie.

The queries return album ids and nothing else, joined back to
GetAllAlbumsWithDetails in Go, so the album projection keeps having one
definition rather than one per shelf.
2026-08-11 01:15:34 -04:00

368 lines
9.3 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: home.sql
package sqlcgen
import (
"context"
"database/sql"
)
const homeAlbumsByGenre = `-- name: HomeAlbumsByGenre :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN recording_genres rgen ON rgen.recording_id = rgr.recording_id
JOIN genres g ON g.id = rgen.genre_id
WHERE g.name = ?
GROUP BY rg.id
ORDER BY RANDOM()
LIMIT ?
`
type HomeAlbumsByGenreParams struct {
Name string
Limit int64
}
// A random sample of albums carrying a genre, so the same genre shelf
// is not the same ten albums every time the page opens.
func (q *Queries) HomeAlbumsByGenre(ctx context.Context, arg HomeAlbumsByGenreParams) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeAlbumsByGenre, arg.Name, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeMostPlayedAlbums = `-- name: HomeMostPlayedAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
GROUP BY rg.id
HAVING SUM(af.play_count) > 0
ORDER BY SUM(af.play_count) DESC
LIMIT ?
`
// Albums by total plays across their tracks.
func (q *Queries) HomeMostPlayedAlbums(ctx context.Context, limit int64) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeMostPlayedAlbums, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeRandomAlbums = `-- name: HomeRandomAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
GROUP BY rg.id
ORDER BY RANDOM()
LIMIT ?
`
func (q *Queries) HomeRandomAlbums(ctx context.Context, limit int64) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeRandomAlbums, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeRecentlyAddedAlbums = `-- name: HomeRecentlyAddedAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
GROUP BY rg.id
ORDER BY MAX(af.id) DESC
LIMIT ?
`
// Newest albums. audio_files has no import timestamp, so the row id
// stands in for one: it is monotonic and assigned at import, which is
// the same ordering an added_at column would give.
func (q *Queries) HomeRecentlyAddedAlbums(ctx context.Context, limit int64) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeRecentlyAddedAlbums, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeRecentlyPlayedAlbums = `-- name: HomeRecentlyPlayedAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
WHERE af.last_played IS NOT NULL
GROUP BY rg.id
ORDER BY MAX(af.last_played) DESC
LIMIT ?
`
// Queries behind the home page's "start listening" shelves.
//
// Every one of these returns album ids and nothing else. The display
// columns (cover art, artist credit, year) already have exactly one
// correct expression of them, in GetAllAlbumsWithDetails, and a second
// copy per shelf would be six more places for that to drift. The home
// service joins the ids back to that one album list in Go.
// Albums with the most recent play, newest first.
func (q *Queries) HomeRecentlyPlayedAlbums(ctx context.Context, limit int64) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeRecentlyPlayedAlbums, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeStaleAlbums = `-- name: HomeStaleAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
WHERE af.last_played IS NOT NULL
GROUP BY rg.id
HAVING MAX(af.last_played) < datetime('now', ?)
ORDER BY MAX(af.last_played) ASC
LIMIT ?
`
type HomeStaleAlbumsParams struct {
Datetime interface{}
Limit int64
}
// Played before, but not for a long while.
func (q *Queries) HomeStaleAlbums(ctx context.Context, arg HomeStaleAlbumsParams) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeStaleAlbums, arg.Datetime, arg.Limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeTopArtists = `-- name: HomeTopArtists :many
SELECT
COALESCE(ac.text, '') AS artist_name,
SUM(af.play_count) AS plays
FROM release_groups rg
JOIN artist_credit ac ON ac.id = rg.album_artist_credit_id
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
WHERE ac.text <> ''
GROUP BY ac.text
HAVING plays > 0
ORDER BY plays DESC
LIMIT ?
`
type HomeTopArtistsRow struct {
ArtistName string
Plays sql.NullFloat64
}
// Artists by total plays, as the album-artist credit text the album
// list already displays.
func (q *Queries) HomeTopArtists(ctx context.Context, limit int64) ([]HomeTopArtistsRow, error) {
rows, err := q.db.QueryContext(ctx, homeTopArtists, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []HomeTopArtistsRow
for rows.Next() {
var i HomeTopArtistsRow
if err := rows.Scan(&i.ArtistName, &i.Plays); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeTopGenres = `-- name: HomeTopGenres :many
SELECT
g.name AS genre,
COUNT(DISTINCT rgr.release_group_id) AS album_count
FROM genres g
JOIN recording_genres rgen ON rgen.genre_id = g.id
JOIN release_group_recordings rgr ON rgr.recording_id = rgen.recording_id
GROUP BY g.id
HAVING album_count >= 3
ORDER BY album_count DESC
LIMIT ?
`
type HomeTopGenresRow struct {
Genre string
AlbumCount int64
}
// Genres ranked by how much of the library carries them, restricted to
// ones with at least a few albums: a shelf built from a genre one
// album carries is a shelf about that one album.
func (q *Queries) HomeTopGenres(ctx context.Context, limit int64) ([]HomeTopGenresRow, error) {
rows, err := q.db.QueryContext(ctx, homeTopGenres, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []HomeTopGenresRow
for rows.Next() {
var i HomeTopGenresRow
if err := rows.Scan(&i.Genre, &i.AlbumCount); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const homeUnplayedAlbums = `-- name: HomeUnplayedAlbums :many
SELECT rg.id AS album_id
FROM release_groups rg
JOIN release_group_recordings rgr ON rgr.release_group_id = rg.id
JOIN audio_files af ON af.recording_id = rgr.recording_id
GROUP BY rg.id
HAVING SUM(af.play_count) = 0
ORDER BY RANDOM()
LIMIT ?
`
// Albums nothing on has ever been played, sampled at random so the
// shelf is a different suggestion each time rather than the same
// alphabetical head of the list forever.
func (q *Queries) HomeUnplayedAlbums(ctx context.Context, limit int64) ([]int64, error) {
rows, err := q.db.QueryContext(ctx, homeUnplayedAlbums, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var items []int64
for rows.Next() {
var album_id int64
if err := rows.Scan(&album_id); err != nil {
return nil, err
}
items = append(items, album_id)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}