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>
169 lines
4.8 KiB
Go
169 lines
4.8 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: admin_status.sql
|
|
|
|
package dbq
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
)
|
|
|
|
const downloadsStatus = `-- name: DownloadsStatus :one
|
|
SELECT COUNT(*) FILTER (WHERE ended_at IS NULL AND import_state IN ('', 'downloading', 'waiting', 'importing'))::bigint AS running,
|
|
COUNT(*) FILTER (WHERE ended_at IS NULL AND import_state IN ('review', 'failed'))::bigint AS needs_you,
|
|
MIN(COALESCE(import_updated_at, grabbed_at)) FILTER (WHERE ended_at IS NULL AND import_state IN ('review', 'failed'))::timestamptz AS needs_you_since,
|
|
COUNT(*) FILTER (WHERE imported_at > now() - INTERVAL '24 hours')::bigint AS imported_day,
|
|
COUNT(*) FILTER (WHERE ended_at > now() - INTERVAL '24 hours'
|
|
AND end_reason IN ('stalled', 'failed', 'gone', 'abandoned'))::bigint AS given_up_day
|
|
FROM grabs
|
|
WHERE ended_at IS NULL
|
|
OR ended_at > now() - INTERVAL '24 hours'
|
|
OR imported_at > now() - INTERVAL '24 hours'
|
|
`
|
|
|
|
type DownloadsStatusRow struct {
|
|
Running int64
|
|
NeedsYou int64
|
|
NeedsYouSince pgtype.Timestamptz
|
|
ImportedDay int64
|
|
GivenUpDay int64
|
|
}
|
|
|
|
// Downloads at a glance: running, waiting on a person (and since when), and
|
|
// the last day's imports and give-ups.
|
|
func (q *Queries) DownloadsStatus(ctx context.Context) (DownloadsStatusRow, error) {
|
|
row := q.db.QueryRow(ctx, downloadsStatus)
|
|
var i DownloadsStatusRow
|
|
err := row.Scan(
|
|
&i.Running,
|
|
&i.NeedsYou,
|
|
&i.NeedsYouSince,
|
|
&i.ImportedDay,
|
|
&i.GivenUpDay,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const libraryStatus = `-- name: LibraryStatus :one
|
|
SELECT COUNT(*)::bigint AS tracks,
|
|
COUNT(DISTINCT album_id)::bigint AS albums,
|
|
COUNT(DISTINCT artist_id)::bigint AS artists,
|
|
COALESCE(SUM(file_size), 0)::bigint AS bytes
|
|
FROM tracks
|
|
WHERE missing_since IS NULL
|
|
`
|
|
|
|
type LibraryStatusRow struct {
|
|
Tracks int64
|
|
Albums int64
|
|
Artists int64
|
|
Bytes int64
|
|
}
|
|
|
|
// What the library holds on disk: tracks whose files are present, the
|
|
// albums and artists they make, and their size.
|
|
func (q *Queries) LibraryStatus(ctx context.Context) (LibraryStatusRow, error) {
|
|
row := q.db.QueryRow(ctx, libraryStatus)
|
|
var i LibraryStatusRow
|
|
err := row.Scan(
|
|
&i.Tracks,
|
|
&i.Albums,
|
|
&i.Artists,
|
|
&i.Bytes,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const listListeningNow = `-- name: ListListeningNow :many
|
|
|
|
SELECT pe.started_at, pe.client_id, pe.device_class,
|
|
u.username,
|
|
t.id AS track_id, t.title AS track_title, t.duration_ms,
|
|
ar.name AS artist_name,
|
|
al.id AS album_id, al.title AS album_title
|
|
FROM play_events pe
|
|
JOIN users u ON u.id = pe.user_id
|
|
JOIN tracks t ON t.id = pe.track_id
|
|
JOIN albums al ON al.id = t.album_id
|
|
JOIN artists ar ON ar.id = t.artist_id
|
|
WHERE pe.ended_at IS NULL
|
|
AND pe.started_at > now() - INTERVAL '24 hours'
|
|
AND pe.started_at + make_interval(secs => t.duration_ms / 1000.0) + INTERVAL '5 minutes' > now()
|
|
ORDER BY pe.started_at DESC
|
|
LIMIT 20
|
|
`
|
|
|
|
type ListListeningNowRow struct {
|
|
StartedAt pgtype.Timestamptz
|
|
ClientID *string
|
|
DeviceClass *string
|
|
Username string
|
|
TrackID pgtype.UUID
|
|
TrackTitle string
|
|
DurationMs int32
|
|
ArtistName string
|
|
AlbumID pgtype.UUID
|
|
AlbumTitle string
|
|
}
|
|
|
|
// The admin Overview's status sections: who is listening, what is
|
|
// downloading, what the library holds. Each is one cheap read.
|
|
// Plays in progress: open play events still inside their track's length,
|
|
// with a few minutes' grace for a pause. A client that never says a play
|
|
// ended would otherwise read as listening until the 24-hour sweep closes it.
|
|
func (q *Queries) ListListeningNow(ctx context.Context) ([]ListListeningNowRow, error) {
|
|
rows, err := q.db.Query(ctx, listListeningNow)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []ListListeningNowRow
|
|
for rows.Next() {
|
|
var i ListListeningNowRow
|
|
if err := rows.Scan(
|
|
&i.StartedAt,
|
|
&i.ClientID,
|
|
&i.DeviceClass,
|
|
&i.Username,
|
|
&i.TrackID,
|
|
&i.TrackTitle,
|
|
&i.DurationMs,
|
|
&i.ArtistName,
|
|
&i.AlbumID,
|
|
&i.AlbumTitle,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|
|
|
|
const playsLastDay = `-- name: PlaysLastDay :one
|
|
SELECT COUNT(*)::bigint AS plays,
|
|
COUNT(DISTINCT user_id)::bigint AS listeners,
|
|
MAX(started_at)::timestamptz AS last_at
|
|
FROM play_events
|
|
WHERE started_at > now() - INTERVAL '24 hours'
|
|
`
|
|
|
|
type PlaysLastDayRow struct {
|
|
Plays int64
|
|
Listeners int64
|
|
LastAt pgtype.Timestamptz
|
|
}
|
|
|
|
// The last day's listening, for the line under Listening now.
|
|
func (q *Queries) PlaysLastDay(ctx context.Context) (PlaysLastDayRow, error) {
|
|
row := q.db.QueryRow(ctx, playsLastDay)
|
|
var i PlaysLastDayRow
|
|
err := row.Scan(&i.Plays, &i.Listeners, &i.LastAt)
|
|
return i, err
|
|
}
|