// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.30.0 // source: albums.sql package sqlcgen import ( "context" "database/sql" "strings" ) const deleteAlbum = `-- name: DeleteAlbum :exec DELETE FROM albums WHERE id = ? ` func (q *Queries) DeleteAlbum(ctx context.Context, id int64) error { _, err := q.db.ExecContext(ctx, deleteAlbum, id) return err } const deleteAllAlbums = `-- name: DeleteAllAlbums :exec DELETE FROM albums ` func (q *Queries) DeleteAllAlbums(ctx context.Context) error { _, err := q.db.ExecContext(ctx, deleteAllAlbums) return err } const getAlbum = `-- name: GetAlbum :one SELECT id, name, artist_credit, artist_id, mbid, year, original_year, cover_art_id, pending_release_mbid FROM albums WHERE id = ? LIMIT 1 ` func (q *Queries) GetAlbum(ctx context.Context, id int64) (Album, error) { row := q.db.QueryRowContext(ctx, getAlbum, id) var i Album err := row.Scan( &i.ID, &i.Name, &i.ArtistCredit, &i.ArtistID, &i.Mbid, &i.Year, &i.OriginalYear, &i.CoverArtID, &i.PendingReleaseMbid, ) return i, err } const getAlbumCompleteness = `-- name: GetAlbumCompleteness :one SELECT -- Distinct (disc, track) pairs: this app detects duplicates, and -- counting two files of track 3 twice would report a short album as -- complete. A file with no track number falls back to its own id, -- because three untagged files are three tracks, not one. CAST(COUNT(DISTINCT CAST(COALESCE(a.disc_number, 1) AS TEXT) || ':' || COALESCE(CAST(a.track_number AS TEXT), 'f' || a.id) ) AS INTEGER) AS owned, CAST(COALESCE(( SELECT SUM(per_disc.total) FROM ( SELECT MAX(b.total_tracks) AS total FROM audio_files b WHERE b.album_id = ?1 AND b.total_tracks IS NOT NULL GROUP BY COALESCE(b.disc_number, 1) ) per_disc ), 0) AS INTEGER) AS expected, CAST(( SELECT COUNT(*) = 0 FROM audio_files c WHERE c.album_id = ?1 AND c.total_tracks IS NULL ) AS INTEGER) AS known FROM audio_files a WHERE a.album_id = ?1 ` type GetAlbumCompletenessRow struct { Owned int64 Expected int64 Known int64 } // "Do I have all of this album", answered from the tags on disk. // // The expectation is a **sum over discs**, not one number: totals are // declared per disc ("5/12" on disc 2 means 12 tracks on disc 2), so a // multi-disc album's expectation is the sum of each disc's declared // total. A disc whose files declared nothing leaves the whole album // unknowable rather than being covered by the discs that did -- which is // what `known` reports. // // Owned counts DISTINCT track numbers: this app detects duplicates, and // counting two files of track 3 twice would report a short album as // complete. func (q *Queries) GetAlbumCompleteness(ctx context.Context, albumID sql.NullInt64) (GetAlbumCompletenessRow, error) { row := q.db.QueryRowContext(ctx, getAlbumCompleteness, albumID) var i GetAlbumCompletenessRow err := row.Scan(&i.Owned, &i.Expected, &i.Known) return i, err } const getAlbums = `-- name: GetAlbums :many SELECT al.id, al.name, COALESCE(al.original_year, al.year) AS year, COALESCE(al.year, 0) AS release_year, al.mbid, al.artist_credit AS artist_name, CAST(COALESCE(ar.mbid, '') AS TEXT) AS artist_mbid, COALESCE(ca.file_path, '') AS cover_art_path FROM albums al LEFT JOIN artists ar ON ar.id = al.artist_id LEFT JOIN cover_art ca ON ca.id = al.cover_art_id WHERE EXISTS ( SELECT 1 FROM audio_files af WHERE af.album_id = al.id AND af.library_id = COALESCE(NULLIF(CAST(?1 AS INTEGER), 0), af.library_id) ) ORDER BY al.name ` type GetAlbumsRow struct { ID int64 Name string Year sql.NullInt64 ReleaseYear int64 Mbid sql.NullString ArtistName string ArtistMbid string CoverArtPath string } func (q *Queries) GetAlbums(ctx context.Context, libraryID int64) ([]GetAlbumsRow, error) { rows, err := q.db.QueryContext(ctx, getAlbums, libraryID) if err != nil { return nil, err } defer rows.Close() var items []GetAlbumsRow for rows.Next() { var i GetAlbumsRow if err := rows.Scan( &i.ID, &i.Name, &i.Year, &i.ReleaseYear, &i.Mbid, &i.ArtistName, &i.ArtistMbid, &i.CoverArtPath, ); 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 getAlbumsByArtistName = `-- name: GetAlbumsByArtistName :many SELECT al.id, al.name, COALESCE(al.original_year, al.year) AS year, COALESCE(al.year, 0) AS release_year, al.mbid, al.artist_credit AS artist_name, CAST(COALESCE(ar.mbid, '') AS TEXT) AS artist_mbid, COALESCE(ca.file_path, '') AS cover_art_path FROM albums al LEFT JOIN artists ar ON ar.id = al.artist_id LEFT JOIN cover_art ca ON ca.id = al.cover_art_id WHERE (al.artist_credit = ?1 OR ar.name = ?1) AND EXISTS ( SELECT 1 FROM audio_files af WHERE af.album_id = al.id AND af.library_id = COALESCE(NULLIF(CAST(?2 AS INTEGER), 0), af.library_id) ) ORDER BY year, al.name ` type GetAlbumsByArtistNameParams struct { Artist string LibraryID int64 } type GetAlbumsByArtistNameRow struct { ID int64 Name string Year sql.NullInt64 ReleaseYear int64 Mbid sql.NullString ArtistName string ArtistMbid string CoverArtPath string } func (q *Queries) GetAlbumsByArtistName(ctx context.Context, arg GetAlbumsByArtistNameParams) ([]GetAlbumsByArtistNameRow, error) { rows, err := q.db.QueryContext(ctx, getAlbumsByArtistName, arg.Artist, arg.LibraryID) if err != nil { return nil, err } defer rows.Close() var items []GetAlbumsByArtistNameRow for rows.Next() { var i GetAlbumsByArtistNameRow if err := rows.Scan( &i.ID, &i.Name, &i.Year, &i.ReleaseYear, &i.Mbid, &i.ArtistName, &i.ArtistMbid, &i.CoverArtPath, ); 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 getAlbumsCompleteness = `-- name: GetAlbumsCompleteness :many WITH per_disc AS ( SELECT album_id AS album_id, COUNT(DISTINCT COALESCE(CAST(track_number AS TEXT), 'f' || id)) AS owned_on_disc, MAX(total_tracks) AS disc_total, SUM(CASE WHEN total_tracks IS NULL THEN 1 ELSE 0 END) AS discs_without_a_total FROM audio_files WHERE album_id IN (/*SLICE:album_ids*/?) GROUP BY album_id, COALESCE(disc_number, 1) ) SELECT CAST(album_id AS INTEGER) AS album_id, CAST(SUM(owned_on_disc) AS INTEGER) AS owned, CAST(COALESCE(SUM(disc_total), 0) AS INTEGER) AS expected, CAST(SUM(discs_without_a_total) = 0 AS INTEGER) AS known FROM per_disc GROUP BY album_id ` type GetAlbumsCompletenessRow struct { AlbumID int64 Owned int64 Expected int64 Known int64 } // The same question as GetAlbumCompleteness, asked of a screenful of // albums at once. // // A card grid cannot afford one query per card, and the answer it wants // is the one thing a badge cannot guess: an album held 9 tracks of 12 // must show the count, never a bare tick. So this is one query for the // whole grid, asked only of the cards that have a local album id. // // It is two grouping levels rather than the single-album form's // correlated subqueries, because a correlated subquery in the FROM // clause is not something SQLite will reliably do -- and because the // slice may only be spelled once, or sqlc expands it twice with // independently numbered placeholders. // // The per-disc level is where the meaning is, and it is the same // meaning as the single-album query. `owned` counts DISTINCT track // numbers within a disc (this app detects duplicates, and counting two // files of track 3 twice would report a short album as complete), with // a file that declares no track number falling back to its own id // because three untagged files are three tracks and not one. // `expected` takes each disc's declared total and sums over discs, // since a total is declared per disc and a release total written on // every file of a two-disc album would double its expectation. A disc // whose files declared nothing contributes a NULL that SUM ignores, // and `known` is what says the album is therefore unanswerable. func (q *Queries) GetAlbumsCompleteness(ctx context.Context, albumIds []sql.NullInt64) ([]GetAlbumsCompletenessRow, error) { query := getAlbumsCompleteness var queryParams []interface{} if len(albumIds) > 0 { for _, v := range albumIds { queryParams = append(queryParams, v) } query = strings.Replace(query, "/*SLICE:album_ids*/?", strings.Repeat(",?", len(albumIds))[1:], 1) } else { query = strings.Replace(query, "/*SLICE:album_ids*/?", "NULL", 1) } rows, err := q.db.QueryContext(ctx, query, queryParams...) if err != nil { return nil, err } defer rows.Close() var items []GetAlbumsCompletenessRow for rows.Next() { var i GetAlbumsCompletenessRow if err := rows.Scan( &i.AlbumID, &i.Owned, &i.Expected, &i.Known, ); 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 getAlbumsWithPendingReleaseMBID = `-- name: GetAlbumsWithPendingReleaseMBID :many SELECT id, pending_release_mbid FROM albums WHERE pending_release_mbid IS NOT NULL AND pending_release_mbid != '' AND (mbid IS NULL OR mbid = '') ` type GetAlbumsWithPendingReleaseMBIDRow struct { ID int64 PendingReleaseMbid sql.NullString } func (q *Queries) GetAlbumsWithPendingReleaseMBID(ctx context.Context) ([]GetAlbumsWithPendingReleaseMBIDRow, error) { rows, err := q.db.QueryContext(ctx, getAlbumsWithPendingReleaseMBID) if err != nil { return nil, err } defer rows.Close() var items []GetAlbumsWithPendingReleaseMBIDRow for rows.Next() { var i GetAlbumsWithPendingReleaseMBIDRow if err := rows.Scan(&i.ID, &i.PendingReleaseMbid); 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 getEmptyAlbumIDs = `-- name: GetEmptyAlbumIDs :many SELECT id FROM albums al WHERE NOT EXISTS ( SELECT 1 FROM audio_files af WHERE af.album_id = al.id ) ` // Albums with no file left behind them. Under the old schema this was // one of three orphan sweeps that had to run by hand and did not; // audio_files is the only thing that can leave an album empty now, so // this is the whole of it. func (q *Queries) GetEmptyAlbumIDs(ctx context.Context) ([]int64, error) { rows, err := q.db.QueryContext(ctx, getEmptyAlbumIDs) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Close(); err != nil { return nil, err } if err := rows.Err(); err != nil { return nil, err } return items, nil } const resolveAlbumPendingReleaseMBID = `-- name: ResolveAlbumPendingReleaseMBID :exec UPDATE albums SET mbid = ?, pending_release_mbid = NULL WHERE id = ? AND (mbid IS NULL OR mbid = '') ` type ResolveAlbumPendingReleaseMBIDParams struct { Mbid sql.NullString ID int64 } // Clears the pending marker once the release-group MBID it stood in for // has been resolved. Guarded so a real MBID is never overwritten. func (q *Queries) ResolveAlbumPendingReleaseMBID(ctx context.Context, arg ResolveAlbumPendingReleaseMBIDParams) error { _, err := q.db.ExecContext(ctx, resolveAlbumPendingReleaseMBID, arg.Mbid, arg.ID) return err } const setAlbumCoverArt = `-- name: SetAlbumCoverArt :exec UPDATE albums SET cover_art_id = ? WHERE id = ? ` type SetAlbumCoverArtParams struct { CoverArtID sql.NullInt64 ID int64 } func (q *Queries) SetAlbumCoverArt(ctx context.Context, arg SetAlbumCoverArtParams) error { _, err := q.db.ExecContext(ctx, setAlbumCoverArt, arg.CoverArtID, arg.ID) return err } const setAlbumMBID = `-- name: SetAlbumMBID :exec UPDATE albums SET mbid = ? WHERE id = ? ` type SetAlbumMBIDParams struct { Mbid sql.NullString ID int64 } func (q *Queries) SetAlbumMBID(ctx context.Context, arg SetAlbumMBIDParams) error { _, err := q.db.ExecContext(ctx, setAlbumMBID, arg.Mbid, arg.ID) return err } const setAlbumOriginalYear = `-- name: SetAlbumOriginalYear :exec UPDATE albums SET original_year = ? WHERE id = ? ` type SetAlbumOriginalYearParams struct { OriginalYear sql.NullInt64 ID int64 } func (q *Queries) SetAlbumOriginalYear(ctx context.Context, arg SetAlbumOriginalYearParams) error { _, err := q.db.ExecContext(ctx, setAlbumOriginalYear, arg.OriginalYear, arg.ID) return err } const setAlbumPendingReleaseMBID = `-- name: SetAlbumPendingReleaseMBID :exec UPDATE albums SET pending_release_mbid = ? WHERE id = ? ` type SetAlbumPendingReleaseMBIDParams struct { PendingReleaseMbid sql.NullString ID int64 } func (q *Queries) SetAlbumPendingReleaseMBID(ctx context.Context, arg SetAlbumPendingReleaseMBIDParams) error { _, err := q.db.ExecContext(ctx, setAlbumPendingReleaseMBID, arg.PendingReleaseMbid, arg.ID) return err } const upsertAlbum = `-- name: UpsertAlbum :one INSERT INTO albums (name, artist_credit, artist_id, year, cover_art_id) VALUES (?, ?, ?, ?, ?) ON CONFLICT(name, artist_credit) DO UPDATE SET artist_id = COALESCE(excluded.artist_id, albums.artist_id), year = COALESCE(excluded.year, albums.year), cover_art_id = COALESCE(excluded.cover_art_id, albums.cover_art_id) RETURNING id, name, artist_credit, artist_id, mbid, year, original_year, cover_art_id, pending_release_mbid ` type UpsertAlbumParams struct { Name string ArtistCredit string ArtistID sql.NullInt64 Year sql.NullInt64 CoverArtID sql.NullInt64 } // Queries over albums (formerly release_groups). // // The two-copy pattern is gone here too: one query answers both the // whole-library and the single-library case. The `fallback_ac` // subquery every album read used to carry -- "if the album has no album // artist credit, borrow one from any of its recordings" -- is gone with // it, because the album carries its own credit text now. func (q *Queries) UpsertAlbum(ctx context.Context, arg UpsertAlbumParams) (Album, error) { row := q.db.QueryRowContext(ctx, upsertAlbum, arg.Name, arg.ArtistCredit, arg.ArtistID, arg.Year, arg.CoverArtID, ) var i Album err := row.Scan( &i.ID, &i.Name, &i.ArtistCredit, &i.ArtistID, &i.Mbid, &i.Year, &i.OriginalYear, &i.CoverArtID, &i.PendingReleaseMbid, ) return i, err }