Optimm to get all artists of a track in a single query
This commit is contained in:
@@ -39,19 +39,17 @@ namespace lms::db
|
|||||||
if (params.linkType)
|
if (params.linkType)
|
||||||
query.where("t_a_l.type = ?").bind(*params.linkType);
|
query.where("t_a_l.type = ?").bind(*params.linkType);
|
||||||
|
|
||||||
if (params.track.isValid() || params.release.isValid())
|
if (params.track.isValid())
|
||||||
query.join("track t ON t.id = t_a_l.track_id");
|
query.where("t_a_l.track_id = ?").bind(params.track);
|
||||||
|
|
||||||
if (params.artist.isValid())
|
if (params.artist.isValid())
|
||||||
query.join("artist a ON a.id = t_a_l.artist_id");
|
query.where("t_a_l.artist_id = ?").bind(params.artist);
|
||||||
|
|
||||||
if (params.release.isValid())
|
if (params.release.isValid())
|
||||||
|
{
|
||||||
|
query.join("track t ON t.id = t_a_l.track_id");
|
||||||
query.where("t.release_id = ?").bind(params.release);
|
query.where("t.release_id = ?").bind(params.release);
|
||||||
|
}
|
||||||
if (params.track.isValid())
|
|
||||||
query.where("t.id = ?").bind(params.track);
|
|
||||||
|
|
||||||
query.groupBy("t_a_l.id");
|
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
@@ -81,6 +79,22 @@ namespace lms::db
|
|||||||
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackArtistLink>().where("id = ?").bind(id));
|
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackArtistLink>().where("id = ?").bind(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TrackArtistLink::find(Session& session, TrackId trackId, const std::function<void(const TrackArtistLink::pointer& link, const ObjectPtr<Artist>& artist)>& func)
|
||||||
|
{
|
||||||
|
session.checkReadTransaction();
|
||||||
|
|
||||||
|
using ResultType = std::tuple < Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>;
|
||||||
|
|
||||||
|
const auto query{ session.getDboSession()->query<ResultType>("SELECT t_a_l, a FROM track_artist_link t_a_l")
|
||||||
|
.join("artist a ON t_a_l.artist_id = a.id")
|
||||||
|
.where("t_a_l.track_id = ?").bind(trackId) };
|
||||||
|
|
||||||
|
utils::forEachQueryResult(query, [&](const ResultType& result)
|
||||||
|
{
|
||||||
|
func(std::get<Wt::Dbo::ptr<TrackArtistLink>>(result), std::get<Wt::Dbo::ptr<Artist>>(result));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void TrackArtistLink::find(Session& session, const FindParameters& parameters, const std::function<void(const TrackArtistLink::pointer&)>& func)
|
void TrackArtistLink::find(Session& session, const FindParameters& parameters, const std::function<void(const TrackArtistLink::pointer&)>& func)
|
||||||
{
|
{
|
||||||
const auto query{ createQuery(session, parameters) };
|
const auto query{ createQuery(session, parameters) };
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ namespace lms::db
|
|||||||
TrackArtistLink() = default;
|
TrackArtistLink() = default;
|
||||||
TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType);
|
TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType);
|
||||||
|
|
||||||
|
static void find(Session& session, TrackId trackId, const std::function<void(const TrackArtistLink::pointer&, const ObjectPtr<Artist>&)>&);
|
||||||
static void find(Session& session, const FindParameters& parameters, const std::function<void(const TrackArtistLink::pointer&)>&);
|
static void find(Session& session, const FindParameters& parameters, const std::function<void(const TrackArtistLink::pointer&)>&);
|
||||||
static pointer find(Session& session, TrackArtistLinkId linkId);
|
static pointer find(Session& session, TrackArtistLinkId linkId);
|
||||||
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType = {});
|
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType = {});
|
||||||
|
|||||||
@@ -394,6 +394,29 @@ namespace lms::db::tests
|
|||||||
EXPECT_TRUE(types.contains(TrackArtistLinkType::Writer));
|
EXPECT_TRUE(types.contains(TrackArtistLinkType::Writer));
|
||||||
EXPECT_FALSE(types.contains(TrackArtistLinkType::Composer));
|
EXPECT_FALSE(types.contains(TrackArtistLinkType::Composer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createReadTransaction() };
|
||||||
|
|
||||||
|
std::vector<TrackArtistLink::pointer> visitedLinks;
|
||||||
|
TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link)
|
||||||
|
{
|
||||||
|
visitedLinks.push_back(link);
|
||||||
|
});
|
||||||
|
ASSERT_EQ(visitedLinks.size(), 3);
|
||||||
|
EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist.getId());
|
||||||
|
EXPECT_EQ(visitedLinks[1]->getArtist()->getId(), artist.getId());
|
||||||
|
EXPECT_EQ(visitedLinks[2]->getArtist()->getId(), artist.getId());
|
||||||
|
|
||||||
|
auto containsType = [&](TrackArtistLinkType type)
|
||||||
|
{
|
||||||
|
return std::any_of(std::cbegin(visitedLinks), std::cend(visitedLinks), [type](const TrackArtistLink::pointer& link) { return link->getType() == type;});
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPECT_TRUE(containsType(TrackArtistLinkType::Artist));
|
||||||
|
EXPECT_TRUE(containsType(TrackArtistLinkType::ReleaseArtist));
|
||||||
|
EXPECT_TRUE(containsType(TrackArtistLinkType::Writer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseFixture, Artist_singleTrackMultiArtists)
|
TEST_F(DatabaseFixture, Artist_singleTrackMultiArtists)
|
||||||
@@ -453,6 +476,47 @@ namespace lms::db::tests
|
|||||||
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist2->getId(), { TrackArtistLinkType::Artist }));
|
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist2->getId(), { TrackArtistLinkType::Artist }));
|
||||||
EXPECT_EQ(tracks.results.size(), 1);
|
EXPECT_EQ(tracks.results.size(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createReadTransaction() };
|
||||||
|
|
||||||
|
std::vector<TrackArtistLink::pointer> visitedLinks;
|
||||||
|
TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setTrack(track.getId()), [&](const TrackArtistLink::pointer& link)
|
||||||
|
{
|
||||||
|
visitedLinks.push_back(link);
|
||||||
|
});
|
||||||
|
ASSERT_EQ(visitedLinks.size(), 2);
|
||||||
|
EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist1.getId());
|
||||||
|
EXPECT_EQ(visitedLinks[1]->getArtist()->getId(), artist2.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createReadTransaction() };
|
||||||
|
|
||||||
|
std::vector<TrackArtistLink::pointer> visitedLinks;
|
||||||
|
TrackArtistLink::find(session, TrackArtistLink::FindParameters{}.setArtist(artist2.getId()), [&](const TrackArtistLink::pointer& link)
|
||||||
|
{
|
||||||
|
visitedLinks.push_back(link);
|
||||||
|
});
|
||||||
|
ASSERT_EQ(visitedLinks.size(), 1);
|
||||||
|
EXPECT_EQ(visitedLinks[0]->getArtist()->getId(), artist2.getId());
|
||||||
|
EXPECT_EQ(visitedLinks[0]->getTrack()->getId(), track.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto transaction{ session.createReadTransaction() };
|
||||||
|
|
||||||
|
std::vector<std::pair<TrackArtistLink::pointer, Artist::pointer>> visitedEntries;
|
||||||
|
TrackArtistLink::find(session, track.getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist)
|
||||||
|
{
|
||||||
|
visitedEntries.push_back(std::make_pair(link, artist));
|
||||||
|
});
|
||||||
|
ASSERT_EQ(visitedEntries.size(), 2);
|
||||||
|
EXPECT_EQ(visitedEntries[0].first->getArtist()->getId(), artist1.getId());
|
||||||
|
EXPECT_EQ(visitedEntries[0].second->getId(), artist1.getId());
|
||||||
|
EXPECT_EQ(visitedEntries[1].first->getArtist()->getId(), artist2.getId());
|
||||||
|
EXPECT_EQ(visitedEntries[1].second->getId(), artist2.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseFixture, Artist_findByName)
|
TEST_F(DatabaseFixture, Artist_findByName)
|
||||||
|
|||||||
@@ -26,14 +26,14 @@
|
|||||||
|
|
||||||
namespace lms::api::subsonic
|
namespace lms::api::subsonic
|
||||||
{
|
{
|
||||||
Response::Node createContributorNode(const db::ObjectPtr<db::TrackArtistLink>& trackArtistLink)
|
Response::Node createContributorNode(const db::ObjectPtr<db::TrackArtistLink>& trackArtistLink, const db::ObjectPtr<db::Artist>& artist)
|
||||||
{
|
{
|
||||||
Response::Node contributorNode;
|
Response::Node contributorNode;
|
||||||
|
|
||||||
contributorNode.setAttribute("role", utils::toString(trackArtistLink->getType()));
|
contributorNode.setAttribute("role", utils::toString(trackArtistLink->getType()));
|
||||||
if (!trackArtistLink->getSubType().empty())
|
if (!trackArtistLink->getSubType().empty())
|
||||||
contributorNode.setAttribute("subRole", trackArtistLink->getSubType());
|
contributorNode.setAttribute("subRole", trackArtistLink->getSubType());
|
||||||
contributorNode.addChild("artist", createArtistNode(trackArtistLink->getArtist()));
|
contributorNode.addChild("artist", createArtistNode(artist));
|
||||||
|
|
||||||
return contributorNode;
|
return contributorNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,11 @@
|
|||||||
|
|
||||||
namespace lms::db
|
namespace lms::db
|
||||||
{
|
{
|
||||||
|
class Artist;
|
||||||
class TrackArtistLink;
|
class TrackArtistLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace lms::api::subsonic
|
namespace lms::api::subsonic
|
||||||
{
|
{
|
||||||
Response::Node createContributorNode(const db::ObjectPtr<db::TrackArtistLink>& trackArtistLink);
|
Response::Node createContributorNode(const db::ObjectPtr<db::TrackArtistLink>& trackArtistLink, const db::ObjectPtr<db::Artist>& artist);
|
||||||
}
|
}
|
||||||
@@ -156,25 +156,22 @@ namespace lms::api::subsonic
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TrackArtistLink::FindParameters params;
|
|
||||||
params.setTrack(track->getId());
|
|
||||||
|
|
||||||
trackResponse.createEmptyArrayChild("albumartists");
|
trackResponse.createEmptyArrayChild("albumartists");
|
||||||
trackResponse.createEmptyArrayChild("artists");
|
trackResponse.createEmptyArrayChild("artists");
|
||||||
trackResponse.createEmptyArrayChild("contributors");
|
trackResponse.createEmptyArrayChild("contributors");
|
||||||
|
|
||||||
TrackArtistLink::find(context.dbSession, params, [&](const TrackArtistLink::pointer& link)
|
TrackArtistLink::find(context.dbSession, track->getId(), [&](const TrackArtistLink::pointer& link, const Artist::pointer& artist)
|
||||||
{
|
{
|
||||||
switch (link->getType())
|
switch (link->getType())
|
||||||
{
|
{
|
||||||
case TrackArtistLinkType::Artist:
|
case TrackArtistLinkType::Artist:
|
||||||
trackResponse.addArrayChild("artists", createArtistNode(link->getArtist()));
|
trackResponse.addArrayChild("artists", createArtistNode(artist));
|
||||||
break;
|
break;
|
||||||
case TrackArtistLinkType::ReleaseArtist:
|
case TrackArtistLinkType::ReleaseArtist:
|
||||||
trackResponse.addArrayChild("albumartists", createArtistNode(link->getArtist()));
|
trackResponse.addArrayChild("albumartists", createArtistNode(artist));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
trackResponse.addArrayChild("contributors", createContributorNode(link));
|
trackResponse.addArrayChild("contributors", createContributorNode(link, artist));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user