Subsonic API: fixed release artists not always retrieved when filtering by media library

This commit is contained in:
emeric
2026-02-25 22:12:32 +01:00
parent 4a7e673a4b
commit 74cd9e827c
2 changed files with 126 additions and 5 deletions
+9 -5
View File
@@ -55,7 +55,6 @@ namespace lms::db
|| params.track.isValid()
|| params.filters.clusters.size() == 1
|| params.filters.codec.has_value()
|| params.filters.mediaLibrary.isValid()
|| params.filters.label.isValid()
|| params.filters.releaseType.isValid())
{
@@ -66,7 +65,6 @@ namespace lms::db
|| params.sortMethod == ArtistSortMethod::AddedDesc
|| params.writtenAfter.isValid()
|| params.filters.codec.has_value()
|| params.filters.mediaLibrary.isValid()
|| params.filters.label.isValid()
|| params.filters.releaseType.isValid())
{
@@ -78,9 +76,6 @@ namespace lms::db
if (params.filters.codec.has_value())
query.where("t.codec = ?").bind(detail::getDbCodec(*params.filters.codec));
if (params.filters.mediaLibrary.isValid())
query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary);
if (params.filters.label.isValid())
{
query.join("release_label r_l ON r_l.release_id = t.release_id");
@@ -97,6 +92,15 @@ namespace lms::db
if (params.releaseArtistsOnly)
query.join("release_artist_link r_a_l ON r_a_l.artist_id = a.id");
if (params.filters.mediaLibrary.isValid())
{
query.where(
"EXISTS (SELECT 1 FROM track_artist_link t_a_l JOIN track t ON t.id = t_a_l.track_id WHERE t_a_l.artist_id = a.id AND t.media_library_id = ?)"
" OR EXISTS (SELECT 1 FROM release_artist_link r_a_l JOIN release r ON r.id = r_a_l.release_id JOIN track t ON t.release_id = r.id WHERE r_a_l.artist_id = a.id AND t.media_library_id = ?)")
.bind(params.filters.mediaLibrary)
.bind(params.filters.mediaLibrary);
}
if (params.trackArtistLinkType.has_value())
query.where("+t_a_l.type = ?").bind(*params.trackArtistLinkType); // Exclude this since the query planner does not do a good job when db is not analyzed
+117
View File
@@ -390,6 +390,123 @@ namespace lms::db::tests
}
}
TEST_F(DatabaseFixture, Artist_singleTrack_singleRelease_mediaLibrary)
{
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedArtist artist{ session, "MyArtist" };
ScopedRelease release2{ session, "MyRelease" };
ScopedMediaLibrary library1{ session, "Library1", "/root1" };
ScopedMediaLibrary library2{ session, "Library2", "/root2" };
ScopedMediaLibrary otherLibrary{ session, "OtherLibrary", "/otherRoot" };
{
auto transaction{ session.createWriteTransaction() };
track1.get().modify()->setName("Track1");
session.create<TrackArtistLink>(track1.get(), artist.get(), TrackArtistLinkType::Artist);
track1.get().modify()->setMediaLibrary(library1.get());
track2.get().modify()->setName("Track2");
track2.get().modify()->setRelease(release2.get());
session.create<ReleaseArtistLink>(release2.get(), artist.get(), false);
track2.get().modify()->setMediaLibrary(library2.get());
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setFilters(Filters{}.setMediaLibrary(library1->getId()))) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setFilters(Filters{}.setMediaLibrary(library2->getId()))) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setFilters(Filters{}.setMediaLibrary(otherLibrary->getId()))) };
EXPECT_EQ(artists.results.size(), 0);
}
}
TEST_F(DatabaseFixture, Artist_singleTrack_singleRelease_single_mediaLibrary)
{
ScopedTrack track{ session };
ScopedArtist artist{ session, "MyArtist" };
ScopedRelease release{ session, "MyRelease" };
ScopedMediaLibrary library{ session, "Library1", "/root1" };
{
auto transaction{ session.createWriteTransaction() };
track.get().modify()->setName("Track1");
track.get().modify()->setRelease(release.get());
track.get().modify()->setMediaLibrary(library.get());
session.create<TrackArtistLink>(track.get(), artist.get(), TrackArtistLinkType::Artist);
session.create<ReleaseArtistLink>(release.get(), artist.get(), false);
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setFilters(Filters{}.setMediaLibrary(library->getId()))) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
Artist::FindParameters params;
params.setTrackArtistLinkType(TrackArtistLinkType::Artist);
params.setFilters(Filters{}.setMediaLibrary(library.getId()));
auto artists{ Artist::findIds(session, params) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
{
auto transaction{ session.createReadTransaction() };
Artist::FindParameters params;
params.setTrackArtistLinkType(TrackArtistLinkType::Performer);
params.setFilters(Filters{}.setMediaLibrary(library.getId()));
auto artists{ Artist::findIds(session, params) };
EXPECT_EQ(artists.results.size(), 0);
}
{
auto transaction{ session.createReadTransaction() };
Artist::FindParameters params;
params.setReleaseArtistsOnly(true);
params.setFilters(Filters{}.setMediaLibrary(library.getId()));
auto artists{ Artist::findIds(session, params) };
EXPECT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
}
TEST_F(DatabaseFixture, Artist_singleTracktMultiRoles)
{
ScopedTrack track{ session };