From 5cc58ce66ab70d8d5a570df5067f79ae2201037e Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Mon, 16 Mar 2026 09:26:42 -0400 Subject: [PATCH] feat(13-01): add library-filtered sqlc queries for all browse views - GetAllTracksWithFullMetadataByLibrary for tracks filtered by library - GetAudioFilesByReleaseGroupByLibrary for album tracks in a library - GetAllAlbumsWithDetailsByLibrary for albums with tracks in a library - GetAlbumsByArtistByLibrary for artist albums in a library - GetAlbumArtistsByLibrary for artists with albums in a library - GetAllGenresWithCountsByLibrary for genre counts within a library - GetTracksByGenreByLibrary for genre tracks within a library --- backend/database/sql/queries/artists.sql | 18 ++ backend/database/sql/queries/audio_files.sql | 65 ++++++ backend/database/sql/queries/genres.sql | 50 +++++ .../database/sql/queries/release_groups.sql | 54 +++++ backend/database/sql/sqlcgen/artists.sql.go | 42 ++++ .../database/sql/sqlcgen/audio_files.sql.go | 190 ++++++++++++++++++ backend/database/sql/sqlcgen/genres.sql.go | 144 +++++++++++++ .../sql/sqlcgen/release_groups.sql.go | 135 +++++++++++++ 8 files changed, 698 insertions(+) diff --git a/backend/database/sql/queries/artists.sql b/backend/database/sql/queries/artists.sql index a16b201..caf7af0 100644 --- a/backend/database/sql/queries/artists.sql +++ b/backend/database/sql/queries/artists.sql @@ -38,3 +38,21 @@ JOIN artist_credit_artist aca ON aca.artist_id = a.id JOIN artist_credit ac ON ac.id = aca.credit_id JOIN release_groups rg ON rg.album_artist_credit_id = ac.id ORDER BY a.name; + +-- name: GetAlbumArtistsByLibrary :many +SELECT DISTINCT a.id, a.name +FROM artists a +JOIN artist_credit_artist aca ON aca.artist_id = a.id +JOIN artist_credit ac ON ac.id = aca.credit_id +JOIN release_groups rg ON rg.album_artist_credit_id = ac.id +WHERE a.id IN ( + SELECT DISTINCT aca2.artist_id + FROM artist_credit_artist aca2 + JOIN artist_credit ac2 ON ac2.id = aca2.credit_id + JOIN release_groups rg2 ON rg2.album_artist_credit_id = ac2.id + JOIN release_group_recordings rgr2 ON rgr2.release_group_id = rg2.id + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY a.name; diff --git a/backend/database/sql/queries/audio_files.sql b/backend/database/sql/queries/audio_files.sql index bc8c709..54fde5e 100644 --- a/backend/database/sql/queries/audio_files.sql +++ b/backend/database/sql/queries/audio_files.sql @@ -136,6 +136,38 @@ SELECT COUNT(*) AS count FROM audio_files WHERE library_id = ?; -- name: DeleteAllAudioFiles :exec DELETE FROM audio_files; +-- name: GetAllTracksWithFullMetadataByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + r.track_number, + r.disc_number, + COALESCE(rg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g.name, '||') + FROM recording_genres rg_sub + JOIN genres g ON rg_sub.genre_id = g.id + WHERE rg_sub.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM audio_files af +JOIN recordings r ON af.recording_id = r.id +JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN release_group_recordings rgr ON r.id = rgr.recording_id +LEFT JOIN release_groups rg ON rgr.release_group_id = rg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE af.library_id = ?; + -- name: GetAudioFilesByReleaseGroup :many SELECT af.file_path, @@ -168,3 +200,36 @@ LEFT JOIN release_groups rg ON rgr.release_group_id = rg.id LEFT JOIN file_types ft ON af.file_type_id = ft.id WHERE rgr.release_group_id = ? ORDER BY rgr.disc_number, rgr.track_number; + +-- name: GetAudioFilesByReleaseGroupByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + rgr.track_number, + rgr.disc_number, + COALESCE(rg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g.name, '||') + FROM recording_genres rg_sub + JOIN genres g ON rg_sub.genre_id = g.id + WHERE rg_sub.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM release_group_recordings rgr +JOIN recordings r ON rgr.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +LEFT JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN release_groups rg ON rgr.release_group_id = rg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE rgr.release_group_id = ? AND af.library_id = ? +ORDER BY rgr.disc_number, rgr.track_number; diff --git a/backend/database/sql/queries/genres.sql b/backend/database/sql/queries/genres.sql index 0b3d01e..301e8f5 100644 --- a/backend/database/sql/queries/genres.sql +++ b/backend/database/sql/queries/genres.sql @@ -63,9 +63,59 @@ LEFT JOIN file_types ft ON af.file_type_id = ft.id WHERE g.name = ? ORDER BY r.name; +-- name: GetTracksByGenreByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + r.track_number, + r.disc_number, + COALESCE(rlg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g2.name, '||') + FROM recording_genres rg2 + JOIN genres g2 ON rg2.genre_id = g2.id + WHERE rg2.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM genres g +JOIN recording_genres rg ON g.id = rg.genre_id +JOIN recordings r ON rg.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN ( + SELECT recording_id, + MIN(release_group_id) AS release_group_id + FROM release_group_recordings + GROUP BY recording_id +) rgr ON r.id = rgr.recording_id +LEFT JOIN release_groups rlg ON rgr.release_group_id = rlg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE g.name = ? AND af.library_id = ? +ORDER BY r.name; + -- name: GetAllGenresWithCounts :many SELECT g.name, COUNT(rg.recording_id) AS track_count FROM genres g JOIN recording_genres rg ON g.id = rg.genre_id GROUP BY g.id, g.name ORDER BY g.name; + +-- name: GetAllGenresWithCountsByLibrary :many +SELECT g.name, COUNT(rg.recording_id) AS track_count +FROM genres g +JOIN recording_genres rg ON g.id = rg.genre_id +JOIN recordings r ON rg.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +WHERE af.library_id = ? +GROUP BY g.id, g.name +ORDER BY g.name; diff --git a/backend/database/sql/queries/release_groups.sql b/backend/database/sql/queries/release_groups.sql index abb0ae3..9435a87 100644 --- a/backend/database/sql/queries/release_groups.sql +++ b/backend/database/sql/queries/release_groups.sql @@ -64,6 +64,32 @@ LEFT JOIN ( ) fallback_ac ON fallback_ac.release_group_id = rg.id ORDER BY rg.name; +-- name: GetAllAlbumsWithDetailsByLibrary :many +SELECT + rg.id, + rg.name, + rg.year, + COALESCE(ac.text, fallback_ac.text, '') as artist_name, + COALESCE(ca.file_path, '') as cover_art_path +FROM release_groups rg +LEFT JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id +LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id +LEFT JOIN ( + SELECT rgr.release_group_id, ac2.text + FROM release_group_recordings rgr + JOIN recordings rec ON rec.id = rgr.recording_id + JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id + GROUP BY rgr.release_group_id +) fallback_ac ON fallback_ac.release_group_id = rg.id +WHERE rg.id IN ( + SELECT DISTINCT rgr2.release_group_id + FROM release_group_recordings rgr2 + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY rg.name; + -- name: GetAlbumsByArtist :many SELECT rg.id, @@ -84,3 +110,31 @@ LEFT JOIN ( ) fallback_ac ON fallback_ac.release_group_id = rg.id WHERE aca.artist_id = ? ORDER BY rg.name; + +-- name: GetAlbumsByArtistByLibrary :many +SELECT + rg.id, + rg.name, + rg.year, + COALESCE(ac.text, fallback_ac.text, '') as artist_name, + COALESCE(ca.file_path, '') as cover_art_path +FROM release_groups rg +JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id +JOIN artist_credit_artist aca ON aca.credit_id = ac.id +LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id +LEFT JOIN ( + SELECT rgr.release_group_id, ac2.text + FROM release_group_recordings rgr + JOIN recordings rec ON rec.id = rgr.recording_id + JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id + GROUP BY rgr.release_group_id +) fallback_ac ON fallback_ac.release_group_id = rg.id +WHERE aca.artist_id = ? + AND rg.id IN ( + SELECT DISTINCT rgr2.release_group_id + FROM release_group_recordings rgr2 + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY rg.name; diff --git a/backend/database/sql/sqlcgen/artists.sql.go b/backend/database/sql/sqlcgen/artists.sql.go index a4524d4..b1d563f 100644 --- a/backend/database/sql/sqlcgen/artists.sql.go +++ b/backend/database/sql/sqlcgen/artists.sql.go @@ -72,6 +72,48 @@ func (q *Queries) GetAlbumArtists(ctx context.Context) ([]Artist, error) { return items, nil } +const getAlbumArtistsByLibrary = `-- name: GetAlbumArtistsByLibrary :many +SELECT DISTINCT a.id, a.name +FROM artists a +JOIN artist_credit_artist aca ON aca.artist_id = a.id +JOIN artist_credit ac ON ac.id = aca.credit_id +JOIN release_groups rg ON rg.album_artist_credit_id = ac.id +WHERE a.id IN ( + SELECT DISTINCT aca2.artist_id + FROM artist_credit_artist aca2 + JOIN artist_credit ac2 ON ac2.id = aca2.credit_id + JOIN release_groups rg2 ON rg2.album_artist_credit_id = ac2.id + JOIN release_group_recordings rgr2 ON rgr2.release_group_id = rg2.id + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY a.name +` + +func (q *Queries) GetAlbumArtistsByLibrary(ctx context.Context, libraryID int64) ([]Artist, error) { + rows, err := q.db.QueryContext(ctx, getAlbumArtistsByLibrary, libraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Artist + for rows.Next() { + var i Artist + if err := rows.Scan(&i.ID, &i.Name); 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 getAllArtists = `-- name: GetAllArtists :many SELECT id, name FROM artists ORDER BY name diff --git a/backend/database/sql/sqlcgen/audio_files.sql.go b/backend/database/sql/sqlcgen/audio_files.sql.go index d8e0f79..232ae91 100644 --- a/backend/database/sql/sqlcgen/audio_files.sql.go +++ b/backend/database/sql/sqlcgen/audio_files.sql.go @@ -321,6 +321,98 @@ func (q *Queries) GetAllTracksWithFullMetadata(ctx context.Context) ([]GetAllTra return items, nil } +const getAllTracksWithFullMetadataByLibrary = `-- name: GetAllTracksWithFullMetadataByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + r.track_number, + r.disc_number, + COALESCE(rg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g.name, '||') + FROM recording_genres rg_sub + JOIN genres g ON rg_sub.genre_id = g.id + WHERE rg_sub.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM audio_files af +JOIN recordings r ON af.recording_id = r.id +JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN release_group_recordings rgr ON r.id = rgr.recording_id +LEFT JOIN release_groups rg ON rgr.release_group_id = rg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE af.library_id = ? +` + +type GetAllTracksWithFullMetadataByLibraryRow struct { + FilePath string + LengthMilliseconds int64 + Title string + ArtistName string + TrackNumber sql.NullInt64 + DiscNumber sql.NullInt64 + Album string + Genre string + Year int64 + Composer string + FileType string + SampleRate int64 + BitDepth int64 + Channels int64 + Bitrate int64 + FileSize int64 +} + +func (q *Queries) GetAllTracksWithFullMetadataByLibrary(ctx context.Context, libraryID int64) ([]GetAllTracksWithFullMetadataByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getAllTracksWithFullMetadataByLibrary, libraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAllTracksWithFullMetadataByLibraryRow + for rows.Next() { + var i GetAllTracksWithFullMetadataByLibraryRow + if err := rows.Scan( + &i.FilePath, + &i.LengthMilliseconds, + &i.Title, + &i.ArtistName, + &i.TrackNumber, + &i.DiscNumber, + &i.Album, + &i.Genre, + &i.Year, + &i.Composer, + &i.FileType, + &i.SampleRate, + &i.BitDepth, + &i.Channels, + &i.Bitrate, + &i.FileSize, + ); 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 getAudioFile = `-- name: GetAudioFile :one SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files WHERE id = ? LIMIT 1 @@ -504,6 +596,104 @@ func (q *Queries) GetAudioFilesByReleaseGroup(ctx context.Context, releaseGroupI return items, nil } +const getAudioFilesByReleaseGroupByLibrary = `-- name: GetAudioFilesByReleaseGroupByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + rgr.track_number, + rgr.disc_number, + COALESCE(rg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g.name, '||') + FROM recording_genres rg_sub + JOIN genres g ON rg_sub.genre_id = g.id + WHERE rg_sub.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM release_group_recordings rgr +JOIN recordings r ON rgr.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +LEFT JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN release_groups rg ON rgr.release_group_id = rg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE rgr.release_group_id = ? AND af.library_id = ? +ORDER BY rgr.disc_number, rgr.track_number +` + +type GetAudioFilesByReleaseGroupByLibraryParams struct { + ReleaseGroupID int64 + LibraryID int64 +} + +type GetAudioFilesByReleaseGroupByLibraryRow struct { + FilePath string + LengthMilliseconds int64 + Title string + ArtistName string + TrackNumber sql.NullInt64 + DiscNumber sql.NullInt64 + Album string + Genre string + Year int64 + Composer string + FileType string + SampleRate int64 + BitDepth int64 + Channels int64 + Bitrate int64 + FileSize int64 +} + +func (q *Queries) GetAudioFilesByReleaseGroupByLibrary(ctx context.Context, arg GetAudioFilesByReleaseGroupByLibraryParams) ([]GetAudioFilesByReleaseGroupByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getAudioFilesByReleaseGroupByLibrary, arg.ReleaseGroupID, arg.LibraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAudioFilesByReleaseGroupByLibraryRow + for rows.Next() { + var i GetAudioFilesByReleaseGroupByLibraryRow + if err := rows.Scan( + &i.FilePath, + &i.LengthMilliseconds, + &i.Title, + &i.ArtistName, + &i.TrackNumber, + &i.DiscNumber, + &i.Album, + &i.Genre, + &i.Year, + &i.Composer, + &i.FileType, + &i.SampleRate, + &i.BitDepth, + &i.Channels, + &i.Bitrate, + &i.FileSize, + ); 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 getAudioFilesNeedingMetadata = `-- name: GetAudioFilesNeedingMetadata :many SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files WHERE recording_id = 0 diff --git a/backend/database/sql/sqlcgen/genres.sql.go b/backend/database/sql/sqlcgen/genres.sql.go index 07082d9..b77e58f 100644 --- a/backend/database/sql/sqlcgen/genres.sql.go +++ b/backend/database/sql/sqlcgen/genres.sql.go @@ -89,6 +89,45 @@ func (q *Queries) GetAllGenresWithCounts(ctx context.Context) ([]GetAllGenresWit return items, nil } +const getAllGenresWithCountsByLibrary = `-- name: GetAllGenresWithCountsByLibrary :many +SELECT g.name, COUNT(rg.recording_id) AS track_count +FROM genres g +JOIN recording_genres rg ON g.id = rg.genre_id +JOIN recordings r ON rg.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +WHERE af.library_id = ? +GROUP BY g.id, g.name +ORDER BY g.name +` + +type GetAllGenresWithCountsByLibraryRow struct { + Name string + TrackCount int64 +} + +func (q *Queries) GetAllGenresWithCountsByLibrary(ctx context.Context, libraryID int64) ([]GetAllGenresWithCountsByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getAllGenresWithCountsByLibrary, libraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAllGenresWithCountsByLibraryRow + for rows.Next() { + var i GetAllGenresWithCountsByLibraryRow + if err := rows.Scan(&i.Name, &i.TrackCount); 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 getGenresByRecordingID = `-- name: GetGenresByRecordingID :many SELECT g.id, g.name FROM genres g @@ -219,6 +258,111 @@ func (q *Queries) GetTracksByGenre(ctx context.Context, name string) ([]GetTrack return items, nil } +const getTracksByGenreByLibrary = `-- name: GetTracksByGenreByLibrary :many +SELECT + af.file_path, + af.length_milliseconds, + COALESCE(r.name, '') AS title, + COALESCE(ac.text, '') AS artist_name, + r.track_number, + r.disc_number, + COALESCE(rlg.name, '') AS album, + CAST(COALESCE( + (SELECT GROUP_CONCAT(g2.name, '||') + FROM recording_genres rg2 + JOIN genres g2 ON rg2.genre_id = g2.id + WHERE rg2.recording_id = r.id), + '' + ) AS TEXT) AS genre, + COALESCE(r.year, 0) AS year, + COALESCE(r.composer, '') AS composer, + COALESCE(ft.extension, '') AS file_type, + af.sample_rate, + af.bit_depth, + af.channels, + af.bitrate, + af.file_size +FROM genres g +JOIN recording_genres rg ON g.id = rg.genre_id +JOIN recordings r ON rg.recording_id = r.id +JOIN audio_files af ON af.recording_id = r.id +JOIN artist_credit ac ON r.artist_credit_id = ac.id +LEFT JOIN ( + SELECT recording_id, + MIN(release_group_id) AS release_group_id + FROM release_group_recordings + GROUP BY recording_id +) rgr ON r.id = rgr.recording_id +LEFT JOIN release_groups rlg ON rgr.release_group_id = rlg.id +LEFT JOIN file_types ft ON af.file_type_id = ft.id +WHERE g.name = ? AND af.library_id = ? +ORDER BY r.name +` + +type GetTracksByGenreByLibraryParams struct { + Name string + LibraryID int64 +} + +type GetTracksByGenreByLibraryRow struct { + FilePath string + LengthMilliseconds int64 + Title string + ArtistName string + TrackNumber sql.NullInt64 + DiscNumber sql.NullInt64 + Album string + Genre string + Year int64 + Composer string + FileType string + SampleRate int64 + BitDepth int64 + Channels int64 + Bitrate int64 + FileSize int64 +} + +func (q *Queries) GetTracksByGenreByLibrary(ctx context.Context, arg GetTracksByGenreByLibraryParams) ([]GetTracksByGenreByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getTracksByGenreByLibrary, arg.Name, arg.LibraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTracksByGenreByLibraryRow + for rows.Next() { + var i GetTracksByGenreByLibraryRow + if err := rows.Scan( + &i.FilePath, + &i.LengthMilliseconds, + &i.Title, + &i.ArtistName, + &i.TrackNumber, + &i.DiscNumber, + &i.Album, + &i.Genre, + &i.Year, + &i.Composer, + &i.FileType, + &i.SampleRate, + &i.BitDepth, + &i.Channels, + &i.Bitrate, + &i.FileSize, + ); 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 upsertGenre = `-- name: UpsertGenre :one INSERT INTO genres (name) VALUES (?) ON CONFLICT(name) DO UPDATE SET name = name diff --git a/backend/database/sql/sqlcgen/release_groups.sql.go b/backend/database/sql/sqlcgen/release_groups.sql.go index 3316f56..cc99f25 100644 --- a/backend/database/sql/sqlcgen/release_groups.sql.go +++ b/backend/database/sql/sqlcgen/release_groups.sql.go @@ -146,6 +146,77 @@ func (q *Queries) GetAlbumsByArtist(ctx context.Context, artistID int64) ([]GetA return items, nil } +const getAlbumsByArtistByLibrary = `-- name: GetAlbumsByArtistByLibrary :many +SELECT + rg.id, + rg.name, + rg.year, + COALESCE(ac.text, fallback_ac.text, '') as artist_name, + COALESCE(ca.file_path, '') as cover_art_path +FROM release_groups rg +JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id +JOIN artist_credit_artist aca ON aca.credit_id = ac.id +LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id +LEFT JOIN ( + SELECT rgr.release_group_id, ac2.text + FROM release_group_recordings rgr + JOIN recordings rec ON rec.id = rgr.recording_id + JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id + GROUP BY rgr.release_group_id +) fallback_ac ON fallback_ac.release_group_id = rg.id +WHERE aca.artist_id = ? + AND rg.id IN ( + SELECT DISTINCT rgr2.release_group_id + FROM release_group_recordings rgr2 + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY rg.name +` + +type GetAlbumsByArtistByLibraryParams struct { + ArtistID int64 + LibraryID int64 +} + +type GetAlbumsByArtistByLibraryRow struct { + ID int64 + Name string + Year sql.NullInt64 + ArtistName string + CoverArtPath string +} + +func (q *Queries) GetAlbumsByArtistByLibrary(ctx context.Context, arg GetAlbumsByArtistByLibraryParams) ([]GetAlbumsByArtistByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getAlbumsByArtistByLibrary, arg.ArtistID, arg.LibraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAlbumsByArtistByLibraryRow + for rows.Next() { + var i GetAlbumsByArtistByLibraryRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Year, + &i.ArtistName, + &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 getAllAlbumsWithDetails = `-- name: GetAllAlbumsWithDetails :many SELECT rg.id, @@ -203,6 +274,70 @@ func (q *Queries) GetAllAlbumsWithDetails(ctx context.Context) ([]GetAllAlbumsWi return items, nil } +const getAllAlbumsWithDetailsByLibrary = `-- name: GetAllAlbumsWithDetailsByLibrary :many +SELECT + rg.id, + rg.name, + rg.year, + COALESCE(ac.text, fallback_ac.text, '') as artist_name, + COALESCE(ca.file_path, '') as cover_art_path +FROM release_groups rg +LEFT JOIN artist_credit ac ON rg.album_artist_credit_id = ac.id +LEFT JOIN cover_art ca ON rg.cover_art_id = ca.id +LEFT JOIN ( + SELECT rgr.release_group_id, ac2.text + FROM release_group_recordings rgr + JOIN recordings rec ON rec.id = rgr.recording_id + JOIN artist_credit ac2 ON ac2.id = rec.artist_credit_id + GROUP BY rgr.release_group_id +) fallback_ac ON fallback_ac.release_group_id = rg.id +WHERE rg.id IN ( + SELECT DISTINCT rgr2.release_group_id + FROM release_group_recordings rgr2 + JOIN recordings r2 ON r2.id = rgr2.recording_id + JOIN audio_files af2 ON af2.recording_id = r2.id + WHERE af2.library_id = ? +) +ORDER BY rg.name +` + +type GetAllAlbumsWithDetailsByLibraryRow struct { + ID int64 + Name string + Year sql.NullInt64 + ArtistName string + CoverArtPath string +} + +func (q *Queries) GetAllAlbumsWithDetailsByLibrary(ctx context.Context, libraryID int64) ([]GetAllAlbumsWithDetailsByLibraryRow, error) { + rows, err := q.db.QueryContext(ctx, getAllAlbumsWithDetailsByLibrary, libraryID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAllAlbumsWithDetailsByLibraryRow + for rows.Next() { + var i GetAllAlbumsWithDetailsByLibraryRow + if err := rows.Scan( + &i.ID, + &i.Name, + &i.Year, + &i.ArtistName, + &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 getAllReleaseGroups = `-- name: GetAllReleaseGroups :many SELECT id, name, cover_art_id, album_artist_credit_id, year, total_tracks, total_discs FROM release_groups ORDER BY name