SubsonicAPI: optimized search for artists

This commit is contained in:
emeric
2023-11-04 19:07:21 +01:00
parent bd59dc3bc9
commit 48ee8e3556
17 changed files with 745 additions and 737 deletions
+104 -90
View File
@@ -33,68 +33,14 @@
namespace Database namespace Database
{ {
namespace
Artist::Artist(const std::string& name, const std::optional<UUID>& MBID) {
: _name {std::string(name, 0 , _maxNameLength)}, template <typename ResultType>
_sortName {_name}, Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Artist::FindParameters& params)
_MBID {MBID ? MBID->getAsString() : ""} {
{
}
Artist::pointer
Artist::create(Session& session, const std::string& name, const std::optional<UUID>& MBID)
{
return session.getDboSession().add(std::unique_ptr<Artist> {new Artist {name, MBID}});
}
std::size_t
Artist::getCount(Session& session)
{
session.checkSharedLocked(); session.checkSharedLocked();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM artist"); auto query{ session.getDboSession().query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM artist a") };
}
std::vector<Artist::pointer>
Artist::find(Session& session, const std::string& name)
{
session.checkSharedLocked();
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res = session.getDboSession().find<Artist>()
.where("name = ?").bind(std::string {name, 0, _maxNameLength})
.orderBy("LENGTH(mbid) DESC"); // put mbid entries first
return std::vector<Artist::pointer>(res.begin(), res.end());
}
Artist::pointer
Artist::find(Session& session, const UUID& mbid)
{
session.checkSharedLocked();
return session.getDboSession().find<Artist>().where("mbid = ?").bind(std::string {mbid.getAsString()}).resultValue();
}
Artist::pointer
Artist::find(Session& session, ArtistId id)
{
session.checkSharedLocked();
return session.getDboSession().find<Artist>().where("id = ?").bind(id).resultValue();
}
bool
Artist::exists(Session& session, ArtistId id)
{
session.checkSharedLocked();
return session.getDboSession().query<int>("SELECT 1 FROM artist").where("id = ?").bind(id).resultValue() == 1;
}
static
Wt::Dbo::Query<ArtistId>
createQuery(Session& session, const Artist::FindParameters& params)
{
session.checkSharedLocked();
auto query {session.getDboSession().query<ArtistId>("SELECT DISTINCT a.id FROM artist a")};
if (params.sortMethod == ArtistSortMethod::LastWritten if (params.sortMethod == ArtistSortMethod::LastWritten
|| params.writtenAfter.isValid() || params.writtenAfter.isValid()
|| params.linkType || params.linkType
@@ -141,7 +87,7 @@ createQuery(Session& session, const Artist::FindParameters& params)
.where("s_a.sync_state <> ?").bind(SyncState::PendingRemove); .where("s_a.sync_state <> ?").bind(SyncState::PendingRemove);
} }
if(params.clusters.size() == 1) if (params.clusters.size() == 1)
{ {
query.join("track_cluster t_c ON t_c.track_id = t.id") query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front()); .where("t_c.cluster_id = ?").bind(params.clusters.front());
@@ -197,29 +143,99 @@ createQuery(Session& session, const Artist::FindParameters& params)
} }
return query; return query;
} }
RangeResults<ArtistId> template <typename ResultType>
Artist::findAllOrphans(Session& session, Range range) Wt::Dbo::Query<ResultType> createQuery(Session& session, const Artist::FindParameters& params)
{ {
std::string_view itemToSelect;
if constexpr (std::is_same_v<ResultType, ArtistId>)
itemToSelect = "a.id";
else if constexpr (std::is_same_v<ResultType, Wt::Dbo::ptr<Artist>>)
itemToSelect = "a";
else
static_assert("Unhandled type");
return createQuery<ResultType>(session, itemToSelect, params);
}
}
Artist::Artist(const std::string& name, const std::optional<UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) },
_sortName{ _name },
_MBID{ MBID ? MBID->getAsString() : "" }
{
}
Artist::pointer Artist::create(Session& session, const std::string& name, const std::optional<UUID>& MBID)
{
return session.getDboSession().add(std::unique_ptr<Artist> {new Artist{ name, MBID }});
}
std::size_t Artist::getCount(Session& session)
{
session.checkSharedLocked(); session.checkSharedLocked();
auto query {session.getDboSession().query<ArtistId>("SELECT DISTINCT a.id FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)")};
return session.getDboSession().query<int>("SELECT COUNT(*) FROM artist");
}
std::vector<Artist::pointer> Artist::find(Session& session, const std::string& name)
{
session.checkSharedLocked();
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res = session.getDboSession().find<Artist>()
.where("name = ?").bind(std::string{ name, 0, _maxNameLength })
.orderBy("LENGTH(mbid) DESC"); // put mbid entries first
return std::vector<Artist::pointer>(res.begin(), res.end());
}
Artist::pointer Artist::find(Session& session, const UUID& mbid)
{
session.checkSharedLocked();
return session.getDboSession().find<Artist>().where("mbid = ?").bind(std::string{ mbid.getAsString() }).resultValue();
}
Artist::pointer Artist::find(Session& session, ArtistId id)
{
session.checkSharedLocked();
return session.getDboSession().find<Artist>().where("id = ?").bind(id).resultValue();
}
bool Artist::exists(Session& session, ArtistId id)
{
session.checkSharedLocked();
return session.getDboSession().query<int>("SELECT 1 FROM artist").where("id = ?").bind(id).resultValue() == 1;
}
RangeResults<ArtistId> Artist::findOrphanIds(Session& session, Range range)
{
session.checkSharedLocked();
auto query{ session.getDboSession().query<ArtistId>("SELECT DISTINCT a.id FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)") };
return Utils::execQuery(query, range); return Utils::execQuery(query, range);
} }
RangeResults<ArtistId> RangeResults<ArtistId> Artist::findIds(Session& session, const FindParameters& params)
Artist::find(Session& session, const FindParameters& params) {
{
session.checkSharedLocked(); session.checkSharedLocked();
auto query {createQuery(session, params)}; auto query{ createQuery<ArtistId>(session, params) };
return Utils::execQuery(query, params.range); return Utils::execQuery(query, params.range);
} }
RangeResults<ArtistId> RangeResults<Artist::pointer> Artist::find(Session& session, const FindParameters& params)
Artist::findSimilarArtists(EnumSet<TrackArtistLinkType> artistLinkTypes, Range range) const {
{ session.checkSharedLocked();
auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) };
return Utils::execQuery(query, params.range);
}
RangeResults<ArtistId> Artist::findSimilarArtistIds(EnumSet<TrackArtistLinkType> artistLinkTypes, Range range) const
{
assert(session()); assert(session());
std::ostringstream oss; std::ostringstream oss;
@@ -241,10 +257,10 @@ Artist::findSimilarArtists(EnumSet<TrackArtistLinkType> artistLinkTypes, Range r
{ {
oss << " AND t_a_l.type IN ("; oss << " AND t_a_l.type IN (";
bool first {true}; bool first{ true };
for (TrackArtistLinkType type : artistLinkTypes) for (TrackArtistLinkType type : artistLinkTypes)
{ {
(void) type; (void)type;
if (!first) if (!first)
oss << ", "; oss << ", ";
oss << "?"; oss << "?";
@@ -253,21 +269,20 @@ Artist::findSimilarArtists(EnumSet<TrackArtistLinkType> artistLinkTypes, Range r
oss << ")"; oss << ")";
} }
auto query {session()->query<ArtistId>(oss.str()) auto query{ session()->query<ArtistId>(oss.str())
.bind(getId()) .bind(getId())
.bind(getId()) .bind(getId())
.groupBy("a.id") .groupBy("a.id")
.orderBy("COUNT(*) DESC, RANDOM()")}; .orderBy("COUNT(*) DESC, RANDOM()") };
for (TrackArtistLinkType type : artistLinkTypes) for (TrackArtistLinkType type : artistLinkTypes)
query.bind(type); query.bind(type);
return Utils::execQuery(query, range); return Utils::execQuery(query, range);
} }
std::vector<std::vector<Cluster::pointer>> std::vector<std::vector<Cluster::pointer>> Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const
Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::size_t size) const {
{
assert(session()); assert(session());
WhereClause where; WhereClause where;
@@ -286,7 +301,7 @@ Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::si
oss << " " << where.get(); oss << " " << where.get();
oss << "GROUP BY c.id ORDER BY COUNT(DISTINCT c.id) DESC"; oss << "GROUP BY c.id ORDER BY COUNT(DISTINCT c.id) DESC";
Wt::Dbo::Query<Wt::Dbo::ptr<Cluster>> query = session()->query<Wt::Dbo::ptr<Cluster>>( oss.str() ); Wt::Dbo::Query<Wt::Dbo::ptr<Cluster>> query = session()->query<Wt::Dbo::ptr<Cluster>>(oss.str());
for (const std::string& bindArg : where.getBindArgs()) for (const std::string& bindArg : where.getBindArgs())
query.bind(bindArg); query.bind(bindArg);
@@ -305,12 +320,11 @@ Artist::getClusterGroups(std::vector<ClusterType::pointer> clusterTypes, std::si
res.push_back(clusters); res.push_back(clusters);
return res; return res;
} }
void void Artist::setSortName(const std::string& sortName)
Artist::setSortName(const std::string& sortName) {
{ _sortName = std::string(sortName, 0, _maxNameLength);
_sortName = std::string(sortName, 0 , _maxNameLength); }
}
} // namespace Database } // namespace Database
@@ -40,24 +40,24 @@
namespace Database namespace Database
{ {
class Cluster; class Cluster;
class ClusterType; class ClusterType;
class Release; class Release;
class Session; class Session;
class StarredArtist; class StarredArtist;
class Track; class Track;
class TrackArtistLink; class TrackArtistLink;
class User; class User;
class Artist final : public Object<Artist, ArtistId> class Artist final : public Object<Artist, ArtistId>
{ {
public: public:
struct FindParameters struct FindParameters
{ {
std::vector<ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters std::vector<ClusterId> clusters; // if non empty, at least one artist that belongs to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords (on either name field OR sort name field) std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords (on either name field OR sort name field)
std::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type std::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
ArtistSortMethod sortMethod {ArtistSortMethod::None}; ArtistSortMethod sortMethod{ ArtistSortMethod::None };
Range range; Range range;
Wt::WDateTime writtenAfter; Wt::WDateTime writtenAfter;
UserId starringUser; // only artists starred by this user UserId starringUser; // only artists starred by this user
@@ -68,8 +68,8 @@ class Artist final : public Object<Artist, ArtistId>
FindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; } FindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; }
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; } FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
FindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; } FindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; }
FindParameters& setSortMethod(ArtistSortMethod _sortMethod) {sortMethod = _sortMethod; return *this; } FindParameters& setSortMethod(ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
FindParameters& setRange(Range _range) {range = _range; return *this; } FindParameters& setRange(Range _range) { range = _range; return *this; }
FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; } FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; }
FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; } FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; }
FindParameters& setTrack(TrackId _track) { track = _track; return *this; } FindParameters& setTrack(TrackId _track) { track = _track; return *this; }
@@ -83,8 +83,9 @@ class Artist final : public Object<Artist, ArtistId>
static pointer find(Session& session, const UUID& MBID); static pointer find(Session& session, const UUID& MBID);
static pointer find(Session& session, ArtistId id); static pointer find(Session& session, ArtistId id);
static std::vector<pointer> find(Session& session, const std::string& name); // exact match on name field static std::vector<pointer> find(Session& session, const std::string& name); // exact match on name field
static RangeResults<ArtistId> find(Session& session, const FindParameters& parameters); static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static RangeResults<ArtistId> findAllOrphans(Session& session, Range range); // No track related static RangeResults<ArtistId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<ArtistId> findOrphanIds(Session& session, Range range); // No track related
static bool exists(Session& session, ArtistId id); static bool exists(Session& session, ArtistId id);
// Accessors // Accessors
@@ -93,7 +94,7 @@ class Artist final : public Object<Artist, ArtistId>
std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); } std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); }
// No artistLinkTypes means get them all // No artistLinkTypes means get them all
RangeResults<ArtistId> findSimilarArtists(EnumSet<TrackArtistLinkType> artistLinkTypes = {}, Range range = {}) const; RangeResults<ArtistId> findSimilarArtistIds(EnumSet<TrackArtistLinkType> artistLinkTypes = {}, Range range = {}) const;
// Get the cluster of the tracks made by this artist // Get the cluster of the tracks made by this artist
// Each clusters are grouped by cluster type, sorted by the number of occurence // Each clusters are grouped by cluster type, sorted by the number of occurence
@@ -116,7 +117,7 @@ class Artist final : public Object<Artist, ArtistId>
} }
private: private:
static constexpr std::size_t _maxNameLength {128}; static constexpr std::size_t _maxNameLength{ 128 };
friend class Session; friend class Session;
// Create // Create
@@ -129,7 +130,7 @@ class Artist final : public Object<Artist, ArtistId>
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks; // Tracks involving this artist Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks; // Tracks involving this artist
Wt::Dbo::collection<Wt::Dbo::ptr<StarredArtist>> _starredArtists; // starred entries for this artist Wt::Dbo::collection<Wt::Dbo::ptr<StarredArtist>> _starredArtists; // starred entries for this artist
}; };
} // namespace Database } // namespace Database
+46 -37
View File
@@ -47,14 +47,23 @@ TEST_F(DatabaseFixture, Artist)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
artists = Artist::findAllOrphans(session, Range{}); artists = Artist::findOrphanIds(session, Range{});
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
} }
{
auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front()->getId(), artist.getId());
}
} }
TEST_F(DatabaseFixture, Artist_singleTrack) TEST_F(DatabaseFixture, Artist_singleTrack)
@@ -71,7 +80,7 @@ TEST_F(DatabaseFixture, Artist_singleTrack)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
@@ -121,7 +130,7 @@ TEST_F(DatabaseFixture, Artist_singleTrack)
} }
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters{}.setTrack(track->getId())) }; auto artists{ Artist::findIds(session, Artist::FindParameters{}.setTrack(track->getId())) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
} }
@@ -141,16 +150,16 @@ TEST_F(DatabaseFixture, Artist_singleTracktMultiRoles)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}).results.size(), 1); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}).results.size(), 1);
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Artist)).results.size(), 1); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Artist)).results.size(), 1);
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::ReleaseArtist)).results.size(), 1); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::ReleaseArtist)).results.size(), 1);
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Writer)).results.size(), 1); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Writer)).results.size(), 1);
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Composer)).results.size(), 0); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setLinkType(TrackArtistLinkType::Composer)).results.size(), 0);
} }
{ {
@@ -206,7 +215,7 @@ TEST_F(DatabaseFixture, Artist_singleTrackMultiArtists)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
@@ -220,8 +229,8 @@ TEST_F(DatabaseFixture, Artist_singleTrackMultiArtists)
EXPECT_EQ(track->getArtists({}).size(), 2); EXPECT_EQ(track->getArtists({}).size(), 2);
EXPECT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 2); EXPECT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 2);
EXPECT_TRUE(track->getArtists({ TrackArtistLinkType::ReleaseArtist }).empty()); EXPECT_TRUE(track->getArtists({ TrackArtistLinkType::ReleaseArtist }).empty());
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}).results.size(), 2); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}).results.size(), 2);
EXPECT_EQ(Artist::find(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::Random)).results.size(), 2); EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::Random)).results.size(), 2);
} }
{ {
@@ -263,13 +272,13 @@ TEST_F(DatabaseFixture, Artist_findByName)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Artist::find(session, Artist::FindParameters{}.setKeywords({ "N" })).results.empty()); EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "N" })).results.empty());
const auto artistsByAAA{ Artist::find(session, Artist::FindParameters {}.setKeywords({"A"})) }; const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"A"})) };
ASSERT_EQ(artistsByAAA.results.size(), 1); ASSERT_EQ(artistsByAAA.results.size(), 1);
EXPECT_EQ(artistsByAAA.results.front(), artist.getId()); EXPECT_EQ(artistsByAAA.results.front(), artist.getId());
const auto artistsByZZZ{ Artist::Artist::find(session, Artist::FindParameters {}.setKeywords({"Z"})) }; const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters {}.setKeywords({"Z"})) };
ASSERT_EQ(artistsByZZZ.results.size(), 1); ASSERT_EQ(artistsByZZZ.results.size(), 1);
EXPECT_EQ(artistsByZZZ.results.front(), artist.getId()); EXPECT_EQ(artistsByZZZ.results.front(), artist.getId());
@@ -280,59 +289,59 @@ TEST_F(DatabaseFixture, Artist_findByName)
TEST_F(DatabaseFixture, Artist_findByNameEscaped) TEST_F(DatabaseFixture, Artist_findByNameEscaped)
{ {
ScopedArtist artist1{ session, "MyArtist%" }; ScopedArtist artist1{ session, R"(MyArtist%)" };
ScopedArtist artist2{ session, "%MyArtist" }; ScopedArtist artist2{ session, R"(%MyArtist)" };
ScopedArtist artist3{ session, "%_MyArtist" }; ScopedArtist artist3{ session, R"(%_MyArtist)" };
ScopedArtist artist4{ session, "MyArtist%foo" }; ScopedArtist artist4{ session, R"(MyArtist%foo)" };
ScopedArtist artist5{ session, "foo%MyArtist" }; ScopedArtist artist5{ session, R"(foo%MyArtist)" };
ScopedArtist artist6{ session, "%AMyArtist" }; ScopedArtist artist6{ session, R"(%AMyArtist)" };
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
{ {
const auto artists{ Artist::find(session, "MyArtist%") }; const auto artists{ Artist::find(session, R"(MyArtist%)") };
ASSERT_TRUE(artists.size() == 1); ASSERT_TRUE(artists.size() == 1);
EXPECT_EQ(artists.front()->getId(), artist1.getId()); EXPECT_EQ(artists.front()->getId(), artist1.getId());
EXPECT_TRUE(Artist::find(session, "MyArtistFoo").empty()); EXPECT_TRUE(Artist::find(session, R"(MyArtistFoo)").empty());
} }
{ {
const auto artists{ Artist::find(session, "%MyArtist") }; const auto artists{ Artist::find(session, R"(%MyArtist)") };
ASSERT_TRUE(artists.size() == 1); ASSERT_TRUE(artists.size() == 1);
EXPECT_EQ(artists.front()->getId(), artist2.getId()); EXPECT_EQ(artists.front()->getId(), artist2.getId());
EXPECT_TRUE(Artist::find(session, "FooMyArtist").empty()); EXPECT_TRUE(Artist::find(session, R"(FooMyArtist)").empty());
} }
{ {
const auto artists{ Artist::find(session, "%_MyArtist") }; const auto artists{ Artist::find(session, R"(%_MyArtist)") };
ASSERT_TRUE(artists.size() == 1); ASSERT_TRUE(artists.size() == 1);
ASSERT_EQ(artists.front()->getId(), artist3.getId()); ASSERT_EQ(artists.front()->getId(), artist3.getId());
EXPECT_TRUE(Artist::find(session, "%CMyArtist").empty()); EXPECT_TRUE(Artist::find(session, R"(%CMyArtist)").empty());
} }
} }
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
{ {
const auto artists{ Artist::find(session, Artist::FindParameters {}.setKeywords({"MyArtist"})) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist"})) };
EXPECT_EQ(artists.results.size(), 6); EXPECT_EQ(artists.results.size(), 6);
} }
{ {
const auto artists{ Artist::find(session, Artist::FindParameters {}.setKeywords({"MyArtist%"}).setSortMethod(ArtistSortMethod::ByName)) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist%"}).setSortMethod(ArtistSortMethod::ByName)) };
ASSERT_EQ(artists.results.size(), 2); ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], artist1.getId()); EXPECT_EQ(artists.results[0], artist1.getId());
EXPECT_EQ(artists.results[1], artist4.getId()); EXPECT_EQ(artists.results[1], artist4.getId());
} }
{ {
const auto artists{ Artist::find(session, Artist::FindParameters {}.setKeywords({"%MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"%MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) };
ASSERT_EQ(artists.results.size(), 2); ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], artist2.getId()); EXPECT_EQ(artists.results[0], artist2.getId());
EXPECT_EQ(artists.results[1], artist5.getId()); EXPECT_EQ(artists.results[1], artist5.getId());
} }
{ {
const auto artists{ Artist::find(session, Artist::FindParameters {}.setKeywords({"_MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"_MyArtist"}).setSortMethod(ArtistSortMethod::ByName)) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results[0], artist3.getId()); EXPECT_EQ(artists.results[0], artist3.getId());
} }
@@ -354,8 +363,8 @@ TEST_F(DatabaseFixture, Artist_sortMethod)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto allArtistsByName{ Artist::find(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::ByName)) }; auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::ByName)) };
auto allArtistsBySortName{ Artist::find(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::BySortName)) }; auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::BySortName)) };
ASSERT_EQ(allArtistsByName.results.size(), 2); ASSERT_EQ(allArtistsByName.results.size(), 2);
EXPECT_EQ(allArtistsByName.results.front(), artistA.getId()); EXPECT_EQ(allArtistsByName.results.front(), artistA.getId());
@@ -407,7 +416,7 @@ TEST_F(DatabaseFixture, Artist_findByRelease)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
const auto artists{ Artist::find(session, Artist::FindParameters {}.setRelease(release.getId())) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
EXPECT_EQ(artists.results.size(), 0); EXPECT_EQ(artists.results.size(), 0);
} }
@@ -418,7 +427,7 @@ TEST_F(DatabaseFixture, Artist_findByRelease)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
const auto artists{ Artist::find(session, Artist::FindParameters {}.setRelease(release.getId())) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
EXPECT_EQ(artists.results.size(), 0); EXPECT_EQ(artists.results.size(), 0);
} }
@@ -429,7 +438,7 @@ TEST_F(DatabaseFixture, Artist_findByRelease)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
const auto artists{ Artist::find(session, Artist::FindParameters {}.setRelease(release.getId())) }; const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
} }
+23 -23
View File
@@ -416,7 +416,7 @@ TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiClusters)
EXPECT_TRUE(ClusterType::findOrphans(session, Range{}).results.empty()); EXPECT_TRUE(ClusterType::findOrphans(session, Range{}).results.empty());
EXPECT_EQ(Cluster::findOrphans(session, Range{}).results.size(), 2); EXPECT_EQ(Cluster::findOrphans(session, Range{}).results.size(), 2);
EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty()); EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty());
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
@@ -428,12 +428,12 @@ TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiClusters)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
EXPECT_TRUE(Artist::find(session, Artist::FindParameters{}.setClusters({ cluster2.getId() })).results.empty()); EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster2.getId() })).results.empty());
EXPECT_TRUE(Artist::find(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty()); EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty());
cluster2.get().modify()->addTrack(track.get()); cluster2.get().modify()->addTrack(track.get());
} }
@@ -441,19 +441,19 @@ TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiClusters)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster1.getId()})) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
artists = Artist::find(session, Artist::FindParameters{}.setClusters({ cluster2.getId() })); artists = Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster2.getId() }));
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
artists = Artist::find(session, Artist::FindParameters{}.setClusters({ cluster1.getId() })); artists = Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster1.getId() }));
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
EXPECT_TRUE(Artist::find(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty()); EXPECT_TRUE(Artist::findIds(session, Artist::FindParameters{}.setClusters({ cluster3.getId() })).results.empty());
} }
} }
@@ -476,13 +476,13 @@ TEST_F(DatabaseFixture, SingleTrackSingleArtistMultiRolesMultiClusters)
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty());
EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty()); EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty());
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setClusters({cluster.getId()})) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster.getId()})) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
} }
@@ -515,7 +515,7 @@ TEST_F(DatabaseFixture, MultiTracksSingleArtistMultiClusters)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty());
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
@@ -524,7 +524,7 @@ TEST_F(DatabaseFixture, MultiTracksSingleArtistMultiClusters)
std::vector<ClusterId> clusterIds; std::vector<ClusterId> clusterIds;
std::transform(std::cbegin(clusters), std::cend(clusters), std::back_inserter(clusterIds), [](const ScopedCluster& cluster) { return cluster.getId(); }); std::transform(std::cbegin(clusters), std::cend(clusters), std::back_inserter(clusterIds), [](const ScopedCluster& cluster) { return cluster.getId(); });
auto artists{ Artist::find(session, Artist::FindParameters {}.setClusters(clusterIds)) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(clusterIds)) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
} }
@@ -627,14 +627,14 @@ TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtistSingleCluster)
EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Cluster::findOrphans(session, Range{}).results.empty());
EXPECT_TRUE(ClusterType::findOrphans(session, Range{}).results.empty()); EXPECT_TRUE(ClusterType::findOrphans(session, Range{}).results.empty());
EXPECT_TRUE(Artist::findAllOrphans(session, Range{}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty()); EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty());
} }
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setClusters({cluster.getId()})) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters({cluster.getId()})) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId()); EXPECT_EQ(artists.results.front(), artist.getId());
@@ -1027,9 +1027,9 @@ TEST_F(DatabaseFixture, MultipleTracksMultipleArtistsMultiClusters)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(artist1->findSimilarArtists().results.empty()); EXPECT_TRUE(artist1->findSimilarArtistIds().results.empty());
EXPECT_TRUE(artist2->findSimilarArtists().results.empty()); EXPECT_TRUE(artist2->findSimilarArtistIds().results.empty());
EXPECT_TRUE(artist3->findSimilarArtists().results.empty()); EXPECT_TRUE(artist3->findSimilarArtistIds().results.empty());
} }
std::list<ScopedTrack> tracks; std::list<ScopedTrack> tracks;
@@ -1061,35 +1061,35 @@ TEST_F(DatabaseFixture, MultipleTracksMultipleArtistsMultiClusters)
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
{ {
auto artists{ artist1->findSimilarArtists() }; auto artists{ artist1->findSimilarArtistIds() };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist2.getId()); EXPECT_EQ(artists.results.front(), artist2.getId());
} }
{ {
auto artists{ artist1->findSimilarArtists({TrackArtistLinkType::Artist}) }; auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist}) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist2.getId()); EXPECT_EQ(artists.results.front(), artist2.getId());
} }
{ {
auto artists{ artist1->findSimilarArtists({TrackArtistLinkType::ReleaseArtist}) }; auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::ReleaseArtist}) };
EXPECT_EQ(artists.results.empty(), 1); EXPECT_EQ(artists.results.empty(), 1);
} }
{ {
auto artists{ artist1->findSimilarArtists({TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}) }; auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}) };
ASSERT_EQ(artists.results.size(), 1); ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist2.getId()); EXPECT_EQ(artists.results.front(), artist2.getId());
} }
{ {
auto artists{ artist1->findSimilarArtists({TrackArtistLinkType::Composer}) }; auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Composer}) };
EXPECT_TRUE(artists.results.empty()); EXPECT_TRUE(artists.results.empty());
} }
{ {
auto artists{ artist2->findSimilarArtists() }; auto artists{ artist2->findSimilarArtistIds() };
ASSERT_EQ(artists.results.size(), 2); ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], artist1.getId()); EXPECT_EQ(artists.results[0], artist1.getId());
EXPECT_EQ(artists.results[1], artist3.getId()); EXPECT_EQ(artists.results[1], artist3.getId());
@@ -25,60 +25,60 @@ using namespace Database;
TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease) TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease)
{ {
constexpr std::size_t nbTracks {10}; constexpr std::size_t nbTracks{ 10 };
std::list<ScopedTrack> tracks; std::list<ScopedTrack> tracks;
ScopedArtist artist {session, "MyArtst"}; ScopedArtist artist{ session, "MyArtst" };
ScopedRelease release {session, "MyRelease"}; ScopedRelease release{ session, "MyRelease" };
for (std::size_t i {}; i < nbTracks; ++i) for (std::size_t i{}; i < nbTracks; ++i)
{ {
tracks.emplace_back(session, "MyTrack" + std::to_string(i)); tracks.emplace_back(session, "MyTrack" + std::to_string(i));
auto transaction {session.createUniqueTransaction()}; auto transaction{ session.createUniqueTransaction() };
TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist); TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist);
tracks.back().get().modify()->setRelease(release.get()); tracks.back().get().modify()->setRelease(release.get());
} }
{ {
auto transaction {session.createSharedTransaction()}; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(Release::findOrphanIds(session, Range {}).results.empty()); EXPECT_TRUE(Release::findOrphanIds(session, Range{}).results.empty());
EXPECT_TRUE(Artist::findAllOrphans(session, Range {}).results.empty()); EXPECT_TRUE(Artist::findOrphanIds(session, Range{}).results.empty());
} }
{ {
auto transaction {session.createSharedTransaction()}; auto transaction{ session.createSharedTransaction() };
auto releases {Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId()))}; auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
ASSERT_EQ(releases.results.size(), 1); ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release.getId()); EXPECT_EQ(releases.results.front(), release.getId());
const auto releaseTracks {Track::find(session, Track::FindParameters {}.setRelease(release.getId()))}; const auto releaseTracks{ Track::find(session, Track::FindParameters {}.setRelease(release.getId())) };
EXPECT_EQ(releaseTracks.results.size(), nbTracks); EXPECT_EQ(releaseTracks.results.size(), nbTracks);
} }
} }
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist) TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist)
{ {
ScopedTrack track {session, "MyTrack"}; ScopedTrack track{ session, "MyTrack" };
ScopedRelease release {session, "MyRelease"}; ScopedRelease release{ session, "MyRelease" };
ScopedArtist artist {session, "MyArtist"}; ScopedArtist artist{ session, "MyArtist" };
{ {
auto transaction {session.createUniqueTransaction()}; auto transaction{ session.createUniqueTransaction() };
auto trackArtistLink {TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist)}; auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
track.get().modify()->setRelease(release.get()); track.get().modify()->setRelease(release.get());
} }
{ {
auto transaction {session.createUniqueTransaction()}; auto transaction{ session.createUniqueTransaction() };
auto releases {Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId()))}; auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
ASSERT_EQ(releases.results.size(), 1); ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release.getId()); EXPECT_EQ(releases.results.front(), release.getId());
auto artists {release->getArtists()}; auto artists{ release->getArtists() };
ASSERT_EQ(artists.size(), 1); ASSERT_EQ(artists.size(), 1);
ASSERT_EQ(artists.front()->getId(), artist.getId()); ASSERT_EQ(artists.front()->getId(), artist.getId());
} }
@@ -87,22 +87,22 @@ TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist)
TEST_F(DatabaseFixture, SingleUser) TEST_F(DatabaseFixture, SingleUser)
{ {
{ {
auto transaction {session.createSharedTransaction()}; auto transaction{ session.createSharedTransaction() };
EXPECT_TRUE(User::find(session, User::FindParameters {}).results.empty()); EXPECT_TRUE(User::find(session, User::FindParameters{}).results.empty());
EXPECT_EQ(User::getCount(session), 0); EXPECT_EQ(User::getCount(session), 0);
} }
ScopedUser user {session, "MyUser"}; ScopedUser user{ session, "MyUser" };
{ {
auto transaction {session.createSharedTransaction()}; auto transaction{ session.createSharedTransaction() };
EXPECT_EQ(User::find(session, User::FindParameters {}).results.size(), 1); EXPECT_EQ(User::find(session, User::FindParameters{}).results.size(), 1);
EXPECT_EQ(User::getCount(session), 1); EXPECT_EQ(User::getCount(session), 1);
} }
} }
int main(int argc, char **argv) int main(int argc, char** argv)
{ {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
@@ -37,7 +37,7 @@ TEST_F(DatabaseFixture, StarredArtist)
EXPECT_FALSE(starredArtist); EXPECT_FALSE(starredArtist);
EXPECT_EQ(StarredArtist::getCount(session), 0); EXPECT_EQ(StarredArtist::getCount(session), 0);
auto artists{ Artist::find(session, Artist::FindParameters {}) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
EXPECT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.size(), 1);
} }
@@ -53,13 +53,13 @@ TEST_F(DatabaseFixture, StarredArtist)
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
EXPECT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.size(), 1);
artists = Artist::find(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)); artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
EXPECT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.size(), 1);
artists = Artist::find(session, Artist::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal)); artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
EXPECT_EQ(artists.results.size(), 0); EXPECT_EQ(artists.results.size(), 0);
} }
} }
@@ -73,11 +73,11 @@ TEST_F(DatabaseFixture, StarredArtist_PendingDestroy)
{ {
auto transaction{ session.createUniqueTransaction() }; auto transaction{ session.createUniqueTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(artists.results.size(), 1); EXPECT_EQ(artists.results.size(), 1);
starredArtist.get().modify()->setSyncState(SyncState::PendingRemove); starredArtist.get().modify()->setSyncState(SyncState::PendingRemove);
artists = Artist::find(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)); artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
EXPECT_EQ(artists.results.size(), 0); EXPECT_EQ(artists.results.size(), 0);
} }
} }
@@ -106,7 +106,7 @@ TEST_F(DatabaseFixture, StarredArtist_dateTime)
starredArtist1.get().modify()->setDateTime(dateTime); starredArtist1.get().modify()->setDateTime(dateTime);
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(-1)); starredArtist2.get().modify()->setDateTime(dateTime.addSecs(-1));
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) };
ASSERT_EQ(artists.results.size(), 2); ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId()); EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId());
EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId()); EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId());
@@ -117,7 +117,7 @@ TEST_F(DatabaseFixture, StarredArtist_dateTime)
starredArtist1.get().modify()->setDateTime(dateTime); starredArtist1.get().modify()->setDateTime(dateTime);
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(1)); starredArtist2.get().modify()->setDateTime(dateTime.addSecs(1));
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) }; auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ArtistSortMethod::StarredDateDesc)) };
ASSERT_EQ(artists.results.size(), 2); ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId()); EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId());
EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId()); EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId());
@@ -103,7 +103,7 @@ namespace Feedback
Session& session{ _db.getTLSSession() }; Session& session{ _db.getTLSSession() };
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
return Artist::find(session, params); return Artist::findIds(session, params);
} }
void FeedbackService::star(UserId userId, ReleaseId releaseId) void FeedbackService::star(UserId userId, ReleaseId releaseId)
@@ -104,7 +104,7 @@ namespace Recommendation {
if (!artist) if (!artist)
return {}; return {};
const auto similarArtistIds{ artist->findSimilarArtists(artistLinkTypes, Range {0, maxCount}) }; const auto similarArtistIds{ artist->findSimilarArtistIds(artistLinkTypes, Range {0, maxCount}) };
return std::move(similarArtistIds.results); return std::move(similarArtistIds.results);
} }
@@ -137,7 +137,7 @@ namespace Scanner
Session& session {_db.getTLSSession()}; Session& session {_db.getTLSSession()};
auto transaction {session.createUniqueTransaction()}; auto transaction {session.createUniqueTransaction()};
auto artistIds {Artist::findAllOrphans(session, Range {})}; auto artistIds {Artist::findOrphanIds(session, Range {})};
for (const ArtistId artistId : artistIds.results) for (const ArtistId artistId : artistIds.results)
{ {
Artist::pointer artist {Artist::find(session, artistId)}; Artist::pointer artist {Artist::find(session, artistId)};
@@ -132,10 +132,9 @@ namespace API::Subsonic
auto transaction{ context.dbSession.createSharedTransaction() }; auto transaction{ context.dbSession.createSharedTransaction() };
parameters.setRange(Range{ currentArtistOffset, batchSize }); parameters.setRange(Range{ currentArtistOffset, batchSize });
const RangeResults<ArtistId> artists{ Artist::find(context.dbSession, parameters) }; const auto artists{ Artist::find(context.dbSession, parameters) };
for (const ArtistId artistId : artists.results) for (const Artist::pointer& artist : artists.results)
{ {
const Artist::pointer artist{ Artist::find(context.dbSession, artistId) };
std::string_view sortName{ artist->getSortName() }; std::string_view sortName{ artist->getSortName() };
char sortChar; char sortChar;
@@ -144,7 +143,7 @@ namespace API::Subsonic
else else
sortChar = std::toupper(sortName[0]); sortChar = std::toupper(sortName[0]);
artistsSortedByFirstChar[sortChar].push_back(artistId); artistsSortedByFirstChar[sortChar].push_back(artist->getId());
} }
hasMoreArtists = artists.moreResults; hasMoreArtists = artists.moreResults;
@@ -317,13 +316,10 @@ namespace API::Subsonic
directoryNode.setAttribute("id", idToString(RootId{})); directoryNode.setAttribute("id", idToString(RootId{}));
directoryNode.setAttribute("name", "Music"); directoryNode.setAttribute("name", "Music");
auto rootArtistIds{ Artist::find(context.dbSession, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::BySortName)) }; const auto rootArtistIds{ Artist::find(context.dbSession, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::BySortName)) };
for (const ArtistId rootArtistId : rootArtistIds.results) for (const Artist::pointer& artist : rootArtistIds.results)
{
const Artist::pointer artist{ Artist::find(context.dbSession, rootArtistId) };
directoryNode.addArrayChild("child", createArtistNode(context, artist, user, false /* no id3 */)); directoryNode.addArrayChild("child", createArtistNode(context, artist, user, false /* no id3 */));
} }
}
else if (artistId) else if (artistId)
{ {
directoryNode.setAttribute("id", idToString(*artistId)); directoryNode.setAttribute("id", idToString(*artistId));
@@ -72,13 +72,9 @@ namespace API::Subsonic
params.setKeywords(keywords); params.setKeywords(keywords);
params.setRange({ artistOffset, artistCount }); params.setRange({ artistOffset, artistCount });
RangeResults<ArtistId> artistIds{ Artist::find(context.dbSession, params) }; for (const Artist::pointer& artist : Artist::find(context.dbSession, params).results)
for (const ArtistId artistId : artistIds.results)
{
const auto artist{ Artist::find(context.dbSession, artistId) };
searchResult2Node.addArrayChild("artist", createArtistNode(context, artist, user, id3)); searchResult2Node.addArrayChild("artist", createArtistNode(context, artist, user, id3));
} }
}
if (albumCount > 0) if (albumCount > 0)
{ {
+2 -2
View File
@@ -191,7 +191,7 @@ namespace UserInterface::Utils
params.setRelease(release->getId()); params.setRelease(release->getId());
params.setLinkType(TrackArtistLinkType::ReleaseArtist); params.setLinkType(TrackArtistLinkType::ReleaseArtist);
if (const auto releaseArtists{ Artist::find(LmsApp->getDbSession(), params) }; !releaseArtists.results.empty()) if (const auto releaseArtists{ Artist::findIds(LmsApp->getDbSession(), params) }; !releaseArtists.results.empty())
{ {
if (releaseArtists.results.size() == 1 && releaseArtists.results.front() == omitIfMatchThisArtist) if (releaseArtists.results.size() == 1 && releaseArtists.results.front() == omitIfMatchThisArtist)
return {}; return {};
@@ -200,7 +200,7 @@ namespace UserInterface::Utils
} }
params.setLinkType(TrackArtistLinkType::Artist); params.setLinkType(TrackArtistLinkType::Artist);
const auto artists{ Artist::find(LmsApp->getDbSession(), params) }; const auto artists{ Artist::findIds(LmsApp->getDbSession(), params) };
if (artists.results.size() == 1) if (artists.results.size() == 1)
{ {
if (artists.results.front() == omitIfMatchThisArtist) if (artists.results.front() == omitIfMatchThisArtist)
+4 -4
View File
@@ -72,7 +72,7 @@ namespace UserInterface
{ {
auto transaction{ LmsApp->getDbSession().createSharedTransaction() }; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
artists = Artist::find(LmsApp->getDbSession(), params); artists = Artist::findIds(LmsApp->getDbSession(), params);
} }
break; break;
} }
@@ -87,7 +87,7 @@ namespace UserInterface
{ {
auto transaction{ LmsApp->getDbSession().createSharedTransaction() }; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
artists = Artist::find(LmsApp->getDbSession(), params); artists = Artist::findIds(LmsApp->getDbSession(), params);
} }
break; break;
} }
@@ -102,7 +102,7 @@ namespace UserInterface
{ {
auto transaction{ LmsApp->getDbSession().createSharedTransaction() }; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
artists = Artist::find(LmsApp->getDbSession(), params); artists = Artist::findIds(LmsApp->getDbSession(), params);
} }
break; break;
} }
@@ -128,7 +128,7 @@ namespace UserInterface
{ {
auto transaction{ LmsApp->getDbSession().createSharedTransaction() }; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
_randomArtists = Artist::find(LmsApp->getDbSession(), params); _randomArtists = Artist::findIds(LmsApp->getDbSession(), params);
} }
} }
+90 -98
View File
@@ -46,11 +46,31 @@
using namespace Database; using namespace Database;
namespace UserInterface { namespace UserInterface
bool
Artist::ReleaseType::operator<(const ReleaseType& other) const
{ {
namespace
{
std::optional<ArtistId> extractArtistIdFromInternalPath()
{
if (wApp->internalPathMatches("/artist/mbid/"))
{
const auto mbid{ UUID::fromString(wApp->internalPathNextPart("/artist/mbid/")) };
if (mbid)
{
auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
if (const Database::Artist::pointer artist{ Database::Artist::find(LmsApp->getDbSession(), *mbid) })
return artist->getId();
}
return std::nullopt;
}
return StringUtils::readAs<ArtistId::ValueType>(wApp->internalPathNextPart("/artist/"));
}
}
bool Artist::ReleaseType::operator<(const ReleaseType& other) const
{
if (!primaryType && other.primaryType) if (!primaryType && other.primaryType)
return false; return false;
else if (primaryType && !other.primaryType) else if (primaryType && !other.primaryType)
@@ -59,13 +79,13 @@ Artist::ReleaseType::operator<(const ReleaseType& other) const
return secondaryTypes.getBitfield() < other.secondaryTypes.getBitfield(); return secondaryTypes.getBitfield() < other.secondaryTypes.getBitfield();
else else
return static_cast<int>(*primaryType) < static_cast<int>(*other.primaryType); return static_cast<int>(*primaryType) < static_cast<int>(*other.primaryType);
} }
Artist::Artist(Filters& filters, PlayQueueController& controller) Artist::Artist(Filters& filters, PlayQueueController& controller)
: Template {Wt::WString::tr("Lms.Explore.Artist.template")} : Template{ Wt::WString::tr("Lms.Explore.Artist.template") }
, _filters {filters} , _filters{ filters }
, _playQueueController {controller} , _playQueueController{ controller }
{ {
addFunction("tr", &Wt::WTemplate::Functions::tr); addFunction("tr", &Wt::WTemplate::Functions::tr);
addFunction("id", &Wt::WTemplate::Functions::id); addFunction("id", &Wt::WTemplate::Functions::id);
@@ -81,35 +101,14 @@ Artist::Artist(Filters& filters, PlayQueueController& controller)
}); });
refreshView(); refreshView();
}
static
std::optional<ArtistId>
extractArtistIdFromInternalPath()
{
if (wApp->internalPathMatches("/artist/mbid/"))
{
const auto mbid {UUID::fromString(wApp->internalPathNextPart("/artist/mbid/"))};
if (mbid)
{
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
if (const Database::Artist::pointer artist {Database::Artist::find(LmsApp->getDbSession(), *mbid)})
return artist->getId();
} }
return std::nullopt; void Artist::refreshView()
} {
return StringUtils::readAs<ArtistId::ValueType>(wApp->internalPathNextPart("/artist/"));
}
void
Artist::refreshView()
{
if (!wApp->internalPathMatches("/artist/")) if (!wApp->internalPathMatches("/artist/"))
return; return;
const auto artistId {extractArtistIdFromInternalPath()}; const auto artistId{ extractArtistIdFromInternalPath() };
// consider everything is up to date is the same artist is being rendered // consider everything is up to date is the same artist is being rendered
if (!_needForceRefresh && artistId && *artistId == _artistId) if (!_needForceRefresh && artistId && *artistId == _artistId)
@@ -121,15 +120,15 @@ Artist::refreshView()
_needForceRefresh = false; _needForceRefresh = false;
if (!artistId) if (!artistId)
throw ArtistNotFoundException {}; throw ArtistNotFoundException{};
const auto similarArtistIds {Service<Recommendation::IRecommendationService>::get()->getSimilarArtists(*artistId, {TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}, 5)}; const auto similarArtistIds{ Service<Recommendation::IRecommendationService>::get()->getSimilarArtists(*artistId, {TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}, 5) };
auto transaction {LmsApp->getDbSession().createSharedTransaction()}; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
const Database::Artist::pointer artist {Database::Artist::find(LmsApp->getDbSession(), *artistId)}; const Database::Artist::pointer artist{ Database::Artist::find(LmsApp->getDbSession(), *artistId) };
if (!artist) if (!artist)
throw ArtistNotFoundException {}; throw ArtistNotFoundException{};
LmsApp->setTitle(artist->getName()); LmsApp->setTitle(artist->getName());
_artistId = *artistId; _artistId = *artistId;
@@ -140,7 +139,7 @@ Artist::refreshView()
refreshLinks(artist); refreshLinks(artist);
refreshSimilarArtists(similarArtistIds); refreshSimilarArtists(similarArtistIds);
Wt::WContainerWidget* clusterContainers {bindNew<Wt::WContainerWidget>("clusters")}; Wt::WContainerWidget* clusterContainers{ bindNew<Wt::WContainerWidget>("clusters") };
{ {
auto clusterTypes = ScanSettings::get(LmsApp->getDbSession())->getClusterTypes(); auto clusterTypes = ScanSettings::get(LmsApp->getDbSession())->getClusterTypes();
@@ -151,7 +150,7 @@ Artist::refreshView()
for (const Database::Cluster::pointer& cluster : clusters) for (const Database::Cluster::pointer& cluster : clusters)
{ {
const Database::ClusterId clusterId = cluster->getId(); const Database::ClusterId clusterId = cluster->getId();
Wt::WInteractWidget* entry {clusterContainers->addWidget(Utils::createCluster(clusterId))}; Wt::WInteractWidget* entry{ clusterContainers->addWidget(Utils::createCluster(clusterId)) };
entry->clicked().connect([=] entry->clicked().connect([=]
{ {
_filters.add(clusterId); _filters.add(clusterId);
@@ -165,31 +164,31 @@ Artist::refreshView()
bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML) bindNew<Wt::WPushButton>("play-btn", Wt::WString::tr("Lms.Explore.play"), Wt::TextFormat::XHTML)
->clicked().connect([=] ->clicked().connect([=]
{ {
_playQueueController.processCommand(PlayQueueController::Command::Play, {_artistId}); _playQueueController.processCommand(PlayQueueController::Command::Play, { _artistId });
}); });
bindNew<Wt::WPushButton>("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain) bindNew<Wt::WPushButton>("play-shuffled", Wt::WString::tr("Lms.Explore.play-shuffled"), Wt::TextFormat::Plain)
->clicked().connect([=] ->clicked().connect([=]
{ {
_playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, {_artistId}); _playQueueController.processCommand(PlayQueueController::Command::PlayShuffled, { _artistId });
}); });
bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain) bindNew<Wt::WPushButton>("play-next", Wt::WString::tr("Lms.Explore.play-next"), Wt::TextFormat::Plain)
->clicked().connect([=] ->clicked().connect([=]
{ {
_playQueueController.processCommand(PlayQueueController::Command::PlayNext, {_artistId}); _playQueueController.processCommand(PlayQueueController::Command::PlayNext, { _artistId });
}); });
bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain) bindNew<Wt::WPushButton>("play-last", Wt::WString::tr("Lms.Explore.play-last"), Wt::TextFormat::Plain)
->clicked().connect([=] ->clicked().connect([=]
{ {
_playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, {_artistId}); _playQueueController.processCommand(PlayQueueController::Command::PlayOrAddLast, { _artistId });
}); });
bindNew<Wt::WPushButton>("download", Wt::WString::tr("Lms.Explore.download")) bindNew<Wt::WPushButton>("download", Wt::WString::tr("Lms.Explore.download"))
->setLink(Wt::WLink {std::make_unique<DownloadArtistResource>(_artistId)}); ->setLink(Wt::WLink{ std::make_unique<DownloadArtistResource>(_artistId) });
{ {
auto isStarred {[=] { return Service<Feedback::IFeedbackService>::get()->isStarred(LmsApp->getUserId(), _artistId); }}; auto isStarred{ [=] { return Service<Feedback::IFeedbackService>::get()->isStarred(LmsApp->getUserId(), _artistId); } };
Wt::WPushButton* starBtn {bindNew<Wt::WPushButton>("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star"))}; Wt::WPushButton* starBtn{ bindNew<Wt::WPushButton>("star", Wt::WString::tr(isStarred() ? "Lms.Explore.unstar" : "Lms.Explore.star")) };
starBtn->clicked().connect([=] starBtn->clicked().connect([=]
{ {
if (isStarred()) if (isStarred())
@@ -204,35 +203,34 @@ Artist::refreshView()
} }
}); });
} }
} }
void void Artist::refreshReleases()
Artist::refreshReleases() {
{
_releaseContainers.clear(); _releaseContainers.clear();
Release::FindParameters params; Release::FindParameters params;
params.setClusters(_filters.getClusterIds()); params.setClusters(_filters.getClusterIds());
params.setArtist(_artistId, {TrackArtistLinkType::ReleaseArtist}, {}); params.setArtist(_artistId, { TrackArtistLinkType::ReleaseArtist }, {});
params.setSortMethod(ReleaseSortMethod::OriginalDateDesc); params.setSortMethod(ReleaseSortMethod::OriginalDateDesc);
const auto releases {Release::findIds(LmsApp->getDbSession(), params)}; const auto releases{ Release::findIds(LmsApp->getDbSession(), params) };
if (!releases.results.empty()) if (!releases.results.empty())
{ {
// first pass: gather all ids and sort by type // first pass: gather all ids and sort by type
for (const ReleaseId releaseId : releases.results) for (const ReleaseId releaseId : releases.results)
{ {
const Database::Release::pointer release {Database::Release::find(LmsApp->getDbSession(), releaseId)}; const Database::Release::pointer release{ Database::Release::find(LmsApp->getDbSession(), releaseId) };
ReleaseType releaseType {release->getPrimaryType(), release->getSecondaryTypes()}; ReleaseType releaseType{ release->getPrimaryType(), release->getSecondaryTypes() };
_releaseContainers[releaseType].releases.push_back(releaseId); _releaseContainers[releaseType].releases.push_back(releaseId);
} }
// second pass: construct widgets // second pass: construct widgets
Wt::WContainerWidget* releaseContainers {bindNew<Wt::WContainerWidget>("release-containers")}; Wt::WContainerWidget* releaseContainers{ bindNew<Wt::WContainerWidget>("release-containers") };
for (auto& [releaseType, releases] : _releaseContainers) for (auto& [releaseType, releases] : _releaseContainers)
{ {
Wt::WTemplate* releaseContainer {releaseContainers->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Artist.template.release-container"))}; Wt::WTemplate* releaseContainer{ releaseContainers->addNew<Wt::WTemplate>(Wt::WString::tr("Lms.Explore.Artist.template.release-container")) };
if (releaseType.primaryType) if (releaseType.primaryType)
releaseContainer->bindString("release-type", ReleaseHelpers::buildReleaseTypeString(*releaseType.primaryType, releaseType.secondaryTypes)); releaseContainer->bindString("release-type", ReleaseHelpers::buildReleaseTypeString(*releaseType.primaryType, releaseType.secondaryTypes));
@@ -250,11 +248,10 @@ Artist::refreshReleases()
{ {
bindEmpty("release-containers"); bindEmpty("release-containers");
} }
} }
void void Artist::refreshAppearsOnReleases()
Artist::refreshAppearsOnReleases() {
{
constexpr EnumSet<TrackArtistLinkType> types constexpr EnumSet<TrackArtistLinkType> types
{ {
TrackArtistLinkType::Artist, TrackArtistLinkType::Artist,
@@ -273,13 +270,13 @@ Artist::refreshAppearsOnReleases()
Release::FindParameters params; Release::FindParameters params;
params.setClusters(_filters.getClusterIds()); params.setClusters(_filters.getClusterIds());
params.setArtist(_artistId, types, {TrackArtistLinkType::ReleaseArtist}); params.setArtist(_artistId, types, { TrackArtistLinkType::ReleaseArtist });
params.setSortMethod(ReleaseSortMethod::OriginalDateDesc); params.setSortMethod(ReleaseSortMethod::OriginalDateDesc);
const auto releases {Release::findIds(LmsApp->getDbSession(), params)}; const auto releases{ Release::findIds(LmsApp->getDbSession(), params) };
if (!releases.results.empty()) if (!releases.results.empty())
{ {
Wt::WTemplate* releaseContainer {bindNew<Wt::WTemplate>("appears-on-releases", Wt::WString::tr("Lms.Explore.Artist.template.release-container"))}; Wt::WTemplate* releaseContainer{ bindNew<Wt::WTemplate>("appears-on-releases", Wt::WString::tr("Lms.Explore.Artist.template.release-container")) };
releaseContainer->bindString("release-type", Wt::WString::tr("Lms.Explore.Artist.appears-on")); releaseContainer->bindString("release-type", Wt::WString::tr("Lms.Explore.Artist.appears-on"));
_appearsOnReleaseContainer.releases = releases.results; _appearsOnReleaseContainer.releases = releases.results;
_appearsOnReleaseContainer.container = releaseContainer->bindNew<InfiniteScrollingContainer>("releases", Wt::WString::tr("Lms.Explore.Releases.template.container")); _appearsOnReleaseContainer.container = releaseContainer->bindNew<InfiniteScrollingContainer>("releases", Wt::WString::tr("Lms.Explore.Releases.template.container"));
@@ -292,11 +289,10 @@ Artist::refreshAppearsOnReleases()
{ {
bindEmpty("appears-on-releases"); bindEmpty("appears-on-releases");
} }
} }
void void Artist::refreshNonReleaseTracks()
Artist::refreshNonReleaseTracks() {
{
setCondition("if-has-non-release-tracks", true); setCondition("if-has-non-release-tracks", true);
_trackContainer = bindNew<InfiniteScrollingContainer>("tracks"); _trackContainer = bindNew<InfiniteScrollingContainer>("tracks");
_trackContainer->onRequestElements.connect(this, [this] _trackContainer->onRequestElements.connect(this, [this]
@@ -304,62 +300,58 @@ Artist::refreshNonReleaseTracks()
addSomeNonReleaseTracks(); addSomeNonReleaseTracks();
}); });
const bool added {addSomeNonReleaseTracks()}; const bool added{ addSomeNonReleaseTracks() };
setCondition("if-has-non-release-tracks", added); setCondition("if-has-non-release-tracks", added);
} }
void void Artist::refreshSimilarArtists(const std::vector<ArtistId>& similarArtistsId)
Artist::refreshSimilarArtists(const std::vector<ArtistId>& similarArtistsId) {
{
if (similarArtistsId.empty()) if (similarArtistsId.empty())
return; return;
setCondition("if-has-similar-artists", true); setCondition("if-has-similar-artists", true);
Wt::WContainerWidget* similarArtistsContainer {bindNew<Wt::WContainerWidget>("similar-artists")}; Wt::WContainerWidget* similarArtistsContainer{ bindNew<Wt::WContainerWidget>("similar-artists") };
for (const ArtistId artistId : similarArtistsId) for (const ArtistId artistId : similarArtistsId)
{ {
const Database::Artist::pointer similarArtist {Database::Artist::find(LmsApp->getDbSession(), artistId)}; const Database::Artist::pointer similarArtist{ Database::Artist::find(LmsApp->getDbSession(), artistId) };
if (!similarArtist) if (!similarArtist)
continue; continue;
similarArtistsContainer->addWidget(ArtistListHelpers::createEntry(similarArtist)); similarArtistsContainer->addWidget(ArtistListHelpers::createEntry(similarArtist));
} }
} }
void void Artist::refreshLinks(const Database::Artist::pointer& artist)
Artist::refreshLinks(const Database::Artist::pointer& artist) {
{ const auto mbid{ artist->getMBID() };
const auto mbid {artist->getMBID()};
if (mbid) if (mbid)
{ {
setCondition("if-has-mbid", true); setCondition("if-has-mbid", true);
bindString("mbid-link", std::string {"https://musicbrainz.org/artist/"} + std::string {mbid->getAsString()}); bindString("mbid-link", std::string{ "https://musicbrainz.org/artist/" } + std::string{ mbid->getAsString() });
}
} }
}
void void Artist::addSomeReleases(ReleaseContainer& releaseContainer)
Artist::addSomeReleases(ReleaseContainer& releaseContainer) {
{ auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
auto transaction {LmsApp->getDbSession().createSharedTransaction()};
if (const Database::Artist::pointer artist {Database::Artist::find(LmsApp->getDbSession(), _artistId)}) if (const Database::Artist::pointer artist{ Database::Artist::find(LmsApp->getDbSession(), _artistId) })
{ {
for (std::size_t i {static_cast<std::size_t>(releaseContainer.container->getCount())}; i < releaseContainer.releases.size(); ++i) for (std::size_t i{ static_cast<std::size_t>(releaseContainer.container->getCount()) }; i < releaseContainer.releases.size(); ++i)
{ {
const Database::Release::pointer release {Database::Release::find(LmsApp->getDbSession(), releaseContainer.releases[i])}; const Database::Release::pointer release{ Database::Release::find(LmsApp->getDbSession(), releaseContainer.releases[i]) };
releaseContainer.container->add(ReleaseListHelpers::createEntryForArtist(release, artist)); releaseContainer.container->add(ReleaseListHelpers::createEntryForArtist(release, artist));
} }
} }
} }
bool bool Artist::addSomeNonReleaseTracks()
Artist::addSomeNonReleaseTracks() {
{
bool areTracksAdded{}; bool areTracksAdded{};
auto transaction {LmsApp->getDbSession().createSharedTransaction()}; auto transaction{ LmsApp->getDbSession().createSharedTransaction() };
const Range range {static_cast<std::size_t>(_trackContainer->getCount()), _tracksBatchSize}; const Range range{ static_cast<std::size_t>(_trackContainer->getCount()), _tracksBatchSize };
Track::FindParameters params; Track::FindParameters params;
params.setClusters(_filters.getClusterIds()); params.setClusters(_filters.getClusterIds());
@@ -368,7 +360,7 @@ Artist::addSomeNonReleaseTracks()
params.setSortMethod(TrackSortMethod::Name); params.setSortMethod(TrackSortMethod::Name);
params.setNonRelease(true); params.setNonRelease(true);
const auto tracks {Track::find(LmsApp->getDbSession(), params)}; const auto tracks{ Track::find(LmsApp->getDbSession(), params) };
for (const Track::pointer& track : tracks.results) for (const Track::pointer& track : tracks.results)
{ {
// TODO handle this with range // TODO handle this with range
@@ -381,7 +373,7 @@ Artist::addSomeNonReleaseTracks()
} }
return areTracksAdded; return areTracksAdded;
} }
} // namespace UserInterface } // namespace UserInterface
+1 -1
View File
@@ -79,7 +79,7 @@ namespace UserInterface
Artist::FindParameters params; Artist::FindParameters params;
params.setRelease(releaseId); params.setRelease(releaseId);
params.setLinkType(linkType); params.setLinkType(linkType);
const auto artistIds{ Artist::find(LmsApp->getDbSession(), params) }; const auto artistIds{ Artist::findIds(LmsApp->getDbSession(), params) };
if (artistIds.results.empty()) if (artistIds.results.empty())
return; return;
+1 -1
View File
@@ -67,7 +67,7 @@ namespace UserInterface::TrackListHelpers
Artist::FindParameters params; Artist::FindParameters params;
params.setTrack(trackId); params.setTrack(trackId);
params.setLinkType(linkType); params.setLinkType(linkType);
const auto artistIds {Artist::find(LmsApp->getDbSession(), params)}; const auto artistIds {Artist::findIds(LmsApp->getDbSession(), params)};
if (artistIds.results.empty()) if (artistIds.results.empty())
return; return;
@@ -102,7 +102,7 @@ static void dumpArtistsRecommendation(Session session, Recommendation::IRecommen
const RangeResults<ArtistId> artistIds = std::invoke([&]() const RangeResults<ArtistId> artistIds = std::invoke([&]()
{ {
auto transaction{ session.createSharedTransaction() }; auto transaction{ session.createSharedTransaction() };
return Artist::find(session, Artist::FindParameters{}); return Artist::findIds(session, Artist::FindParameters{});
}); });
std::cout << "*** Artists ***" << std::endl; std::cout << "*** Artists ***" << std::endl;