Auto reformatted the base, ref #470

This commit is contained in:
emeric
2024-05-24 23:31:52 +02:00
parent 83b868673c
commit 39941d90a3
460 changed files with 8583 additions and 8514 deletions
+42 -49
View File
@@ -20,22 +20,23 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
#include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Artist::FindParameters& params)
{
session.checkReadTransaction();
@@ -97,21 +98,25 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_artist s_a ON s_a.artist_id = a.id")
.where("s_a.user_id = ?").bind(params.starringUser)
.where("s_a.backend = ?").bind(*params.feedbackBackend)
.where("s_a.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_a.user_id = ?")
.bind(params.starringUser)
.where("s_a.backend = ?")
.bind(*params.feedbackBackend)
.where("s_a.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.clusters.size() == 1)
{
query.join("track_cluster t_c ON t_c.track_id = t_a_l.track_id")
.where("t_c.cluster_id = ?").bind(params.clusters.front());
.where("t_c.cluster_id = ?")
.bind(params.clusters.front());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -159,7 +164,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Artist::FindParameters& params)
{
std::string_view itemToSelect;
@@ -173,12 +178,12 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Artist::Artist(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) },
_sortName{ _name },
_MBID{ MBID ? MBID->getAsString() : "" }
: _name{ std::string(name, 0, _maxNameLength) }
, _sortName{ _name }
, _MBID{ MBID ? MBID->getAsString() : "" }
{
}
@@ -198,10 +203,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a")
.orderBy("a.id")
.where("a.id > ?").bind(lastRetrievedArtist)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a").orderBy("a.id").where("a.id > ?").bind(lastRetrievedArtist).limit(static_cast<int>(count)) };
if (library.isValid())
{
@@ -209,20 +211,17 @@ namespace lms::db
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 = ?)").bind(library);
}
utils::forEachQueryResult(query, [&](const Artist::pointer& artist)
{
func(artist);
lastRetrievedArtist = artist->getId();
});
utils::forEachQueryResult(query, [&](const Artist::pointer& artist) {
func(artist);
lastRetrievedArtist = artist->getId();
});
}
std::vector<Artist::pointer> Artist::find(Session& session, std::string_view name)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>()
.where("name = ?").bind(std::string{ name, 0, _maxNameLength })
.orderBy("LENGTH(mbid) DESC")); // put mbid entries first
return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>().where("name = ?").bind(std::string{ name, 0, _maxNameLength }).orderBy("LENGTH(mbid) DESC")); // put mbid entries first
}
Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
@@ -279,19 +278,18 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT a.id FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN artist a ON a.id = t_a_l.artist_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" WHERE a.id = ?)"
" AND a.id <> ?";
oss << "SELECT a.id FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN artist a ON a.id = t_a_l.artist_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" WHERE a.id = ?)"
" AND a.id <> ?";
if (!artistLinkTypes.empty())
{
@@ -309,11 +307,7 @@ namespace lms::db
oss << ")";
}
auto query{ session()->query<ArtistId>(oss.str())
.bind(getId())
.bind(getId())
.groupBy("a.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
auto query{ session()->query<ArtistId>(oss.str()).bind(getId()).bind(getId()).groupBy("a.id").orderBy("COUNT(*) DESC, RANDOM()") };
for (const TrackArtistLinkType type : artistLinkTypes)
query.bind(type);
@@ -347,11 +341,10 @@ namespace lms::db
query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [clusterTypeId, clusters] : clustersByType)
+5 -3
View File
@@ -20,10 +20,12 @@
#include "database/AuthToken.hpp"
#include <Wt/Dbo/WtSqlTraits.h>
#include "database/Session.hpp"
#include "database/User.hpp"
#include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
namespace lms::db
@@ -37,7 +39,7 @@ namespace lms::db
AuthToken::pointer AuthToken::create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user)
{
return session.getDboSession()->add(std::unique_ptr<AuthToken> {new AuthToken{ value, expiry, user }});
return session.getDboSession()->add(std::unique_ptr<AuthToken>{ new AuthToken{ value, expiry, user } });
}
void AuthToken::removeExpiredTokens(Session& session, const Wt::WDateTime& now)
@@ -53,4 +55,4 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value));
}
}
} // namespace lms::db
+20 -26
View File
@@ -25,16 +25,17 @@
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Cluster::FindParameters& params)
{
session.checkReadTransaction();
@@ -44,7 +45,7 @@ namespace lms::db
if (params.track.isValid() || params.release.isValid())
query.join("track_cluster t_c ON t_c.cluster_id = c.id");
if (!params.clusterTypeName.empty())
query.join("cluster_type c_t ON c_t.id = c.cluster_type_id");
@@ -77,7 +78,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Cluster::FindParameters& params)
{
std::string_view itemToSelect;
@@ -91,17 +92,17 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Cluster::Cluster(ObjectPtr<ClusterType> type, std::string_view name)
: _name{ std::string {name, 0, _maxNameLength} },
_clusterType{ getDboPtr(type) }
: _name{ std::string{ name, 0, _maxNameLength } }
, _clusterType{ getDboPtr(type) }
{
}
Cluster::pointer Cluster::create(Session& session, ObjectPtr<ClusterType> type, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<Cluster> {new Cluster{ type, name }});
return session.getDboSession()->add(std::unique_ptr<Cluster>{ new Cluster{ type, name } });
}
std::size_t Cluster::getCount(Session& session)
@@ -154,16 +155,14 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
}
std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
}
void Cluster::addTrack(ObjectPtr<Track> track)
@@ -175,8 +174,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("c.id = ?").bind(getId()) };
auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("c.id = ?").bind(getId()) };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -188,7 +186,7 @@ namespace lms::db
ClusterType::pointer ClusterType::create(Session& session, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<ClusterType> {new ClusterType{ name }});
return session.getDboSession()->add(std::unique_ptr<ClusterType>{ new ClusterType{ name } });
}
std::size_t ClusterType::getCount(Session& session)
@@ -203,9 +201,9 @@ namespace lms::db
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT c_t.id from cluster_type c_t"
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
.where("c.id IS NULL") };
"SELECT c_t.id from cluster_type c_t"
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
.where("c.id IS NULL") };
return utils::execRangeQuery<ClusterTypeId>(query, range);
}
@@ -215,8 +213,8 @@ namespace lms::db
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT DISTINCT c_t.id from cluster_type c_t")
.join("cluster c ON c_t.id = c.cluster_type_id") };
"SELECT DISTINCT c_t.id from cluster_type c_t")
.join("cluster c ON c_t.id = c.cluster_type_id") };
return utils::execRangeQuery<ClusterTypeId>(query, range);
}
@@ -255,9 +253,7 @@ namespace lms::db
assert(self());
assert(session());
return utils::fetchQuerySingleResult(session()->find<Cluster>()
.where("name = ?").bind(name)
.where("cluster_type_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->find<Cluster>().where("name = ?").bind(name).where("cluster_type_id = ?").bind(getId()));
}
std::vector<Cluster::pointer> ClusterType::getClusters() const
@@ -265,8 +261,6 @@ namespace lms::db
assert(self());
assert(session());
return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>()
.where("cluster_type_id = ?").bind(getId())
.orderBy("name"));
return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>().where("cluster_type_id = ?").bind(getId()).orderBy("name"));
}
} // namespace lms::db
+4 -4
View File
@@ -22,12 +22,12 @@
#include <Wt/Dbo/FixedSqlConnectionPool.h>
#include <Wt/Dbo/backend/Sqlite3.h>
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/IConfig.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "core/Service.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
namespace lms::db
{
@@ -68,7 +68,7 @@ namespace lms::db
std::filesystem::path _dbPath;
};
}
} // namespace
// Session living class handling the database and the login
Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount)
@@ -76,7 +76,7 @@ namespace lms::db
LMS_LOG(DB, INFO, "Creating connection pool on file " << dbPath.string());
auto connection{ std::make_unique<Connection>(dbPath.string()) };
if (core::IConfig * config{ core::Service<core::IConfig>::get() })// may not be here on testU
if (core::IConfig * config{ core::Service<core::IConfig>::get() }) // may not be here on testU
connection->setProperty("show-queries", config->getBool("db-show-queries", false) ? "true" : "false");
auto connectionPool{ std::make_unique<Wt::Dbo::FixedSqlConnectionPool>(std::move(connection), connectionCount) };
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h>
#include "core/EnumSet.hpp"
@@ -49,5 +50,4 @@ namespace Wt::Dbo
return false;
}
};
}
} // namespace Wt::Dbo
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h>
#include "database/Types.hpp"
@@ -55,5 +56,4 @@ namespace Wt::Dbo
return false;
}
};
}
} // namespace Wt::Dbo
+41 -59
View File
@@ -21,6 +21,7 @@
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
@@ -31,9 +32,7 @@ namespace lms::db
{
Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params)
{
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t_a_l.track_id") };
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a").join("track_artist_link t_a_l ON t_a_l.artist_id = a.id").join("listen l ON l.track_id = t_a_l.track_id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -56,7 +55,7 @@ namespace lms::db
{
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
WhereClause clusterClause;
for (auto id : params.clusters)
@@ -96,9 +95,7 @@ namespace lms::db
Wt::Dbo::Query<ReleaseId> createReleasesQuery(Session& session, const Listen::StatsFindParameters& params)
{
auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r")
.join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id") };
auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r").join("track t ON t.release_id = r.id").join("listen l ON l.track_id = t.id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -109,7 +106,8 @@ namespace lms::db
if (params.artist.isValid())
{
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist);
.where("t_a_l.artist_id = ?")
.bind(params.artist);
}
if (params.library.isValid())
@@ -119,9 +117,9 @@ namespace lms::db
{
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (ClusterId id : params.clusters)
@@ -144,8 +142,7 @@ namespace lms::db
Wt::Dbo::Query<TrackId> createTracksQuery(Session& session, const Listen::StatsFindParameters& params)
{
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t")
.join("listen l ON l.track_id = t.id") };
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t").join("listen l ON l.track_id = t.id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -156,7 +153,8 @@ namespace lms::db
if (params.artist.isValid())
{
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist);
.where("t_a_l.artist_id = ?")
.bind(params.artist);
}
if (params.library.isValid())
@@ -166,8 +164,8 @@ namespace lms::db
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
WhereClause clusterClause;
for (auto id : params.clusters)
@@ -187,19 +185,20 @@ namespace lms::db
return query;
}
}
} // namespace
Listen::Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
: _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) }
, _backend{ backend }
, _user{ getDboPtr(user) }
, _track{ getDboPtr(track) }
{}
{
}
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
{
session.checkWriteTransaction();
return session.getDboSession()->add(std::unique_ptr<Listen> {new Listen{ user, track, backend, dateTime }});
return session.getDboSession()->add(std::unique_ptr<Listen>{ new Listen{ user, track, backend, dateTime } });
}
std::size_t Listen::getCount(Session& session)
@@ -218,8 +217,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen")
.orderBy("date_time") };
auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen").orderBy("date_time") };
if (parameters.user.isValid())
query.where("user_id = ?").bind(parameters.user);
@@ -237,11 +235,7 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>()
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId)
.where("backend = ?").bind(backend)
.where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId).where("backend = ?").bind(backend).where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
}
RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params)
@@ -250,8 +244,8 @@ namespace lms::db
auto query{ createArtistsQuery(session, params) };
auto collection{ query
.orderBy("COUNT(a.id) DESC")
.groupBy("a.id") };
.orderBy("COUNT(a.id) DESC")
.groupBy("a.id") };
return utils::execRangeQuery<ArtistId>(query, params.range);
}
@@ -280,7 +274,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createArtistsQuery(session, params)
.groupBy("a.id").having("l.date_time = MAX(l.date_time)")
.groupBy("a.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<ArtistId>(query, params.range);
@@ -290,7 +285,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createReleasesQuery(session, params)
.groupBy("r.id").having("l.date_time = MAX(l.date_time)")
.groupBy("r.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<ReleaseId>(query, params.range);
@@ -300,7 +296,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createTracksQuery(session, params)
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
.groupBy("t.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<TrackId>(query, params.range);
@@ -310,11 +307,7 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l")
.join("user u ON u.id = l.user_id")
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = u.scrobbling_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l").join("user u ON u.id = l.user_id").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = u.scrobbling_backend"));
}
std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId)
@@ -322,16 +315,16 @@ namespace lms::db
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>(
"SELECT IFNULL(MIN(count_result), 0)"
" FROM ("
" SELECT COUNT(l.track_id) AS count_result"
" FROM track t"
" LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?"
" WHERE t.release_id = ?"
" GROUP BY t.id)")
.bind(userId)
.bind(userId)
.bind(releaseId));
"SELECT IFNULL(MIN(count_result), 0)"
" FROM ("
" SELECT COUNT(l.track_id) AS count_result"
" FROM track t"
" LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?"
" WHERE t.release_id = ?"
" GROUP BY t.id)")
.bind(userId)
.bind(userId)
.bind(releaseId));
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
@@ -339,24 +332,13 @@ namespace lms::db
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.join("track t ON l.track_id = t.id")
.where("t.release_id = ?").bind(releaseId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC")
.limit(1));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").join("track t ON l.track_id = t.id").where("t.release_id = ?").bind(releaseId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
{
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC")
.limit(1));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
}
} // namespace lms::db
+6 -6
View File
@@ -22,6 +22,7 @@
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "IdTypeTraits.hpp"
#include "PathTraits.hpp"
#include "StringViewTraits.hpp"
@@ -30,8 +31,8 @@
namespace lms::db
{
MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name)
: _path{ p },
_name{ std::string {name, 0, maxNameLength} }
: _path{ p }
, _name{ std::string{ name, 0, maxNameLength } }
{
}
@@ -72,9 +73,8 @@ namespace lms::db
{
session.checkReadTransaction();
utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary)
{
func(mediaLibrary);
});
utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary) {
func(mediaLibrary);
});
}
} // namespace lms::db
+44 -40
View File
@@ -21,13 +21,14 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Db.hpp"
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "Utils.hpp"
namespace lms::db
@@ -39,7 +40,8 @@ namespace lms::db
VersionInfo::VersionInfo()
: _version{ LMS_DATABASE_VERSION }
{}
{
}
VersionInfo::pointer VersionInfo::getOrCreate(Session& session)
{
@@ -58,14 +60,15 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<VersionInfo>());
}
}
} // namespace lms::db
namespace lms::db::Migration
{
class ScopedNoForeignKeys
{
public:
ScopedNoForeignKeys(Db& db) : _db{ db }
ScopedNoForeignKeys(Db& db)
: _db{ db }
{
_db.executeSql("PRAGMA foreign_keys=OFF");
}
@@ -73,6 +76,7 @@ namespace lms::db::Migration
{
_db.executeSql("PRAGMA foreign_keys=ON");
}
private:
ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete;
ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete;
@@ -106,9 +110,9 @@ CREATE TABLE IF NOT EXISTS "track_artist_link_backup" (
{
// Add scrobbling state
// By default, everything needs to be sent
session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
}
static void migrateFromV35(Session& session)
@@ -251,7 +255,7 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
void migrateFromV45(Session& session)
{
// add subsonic_enable_transcoding_by_default, default is disabled
session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultSubsonicEnableTranscodingByDefault*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultSubsonicEnableTranscodingByDefault*/ 0)) + ")");
}
void migrateFromV46(Session& session)
@@ -330,7 +334,8 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name")
SELECT 1, 0, s_s.media_directory, "Main"
FROM scan_settings s_s
WHERE id = ?)").bind(scanSettingsId);
WHERE id = ?)")
.bind(scanSettingsId);
// Remove the outdated column in scan_settings
session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory");
@@ -479,34 +484,33 @@ SELECT
using MigrationFunction = std::function<void(Session&)>;
const std::map<unsigned, MigrationFunction> migrationFunctions
{
{33, migrateFromV33},
{34, migrateFromV34},
{35, migrateFromV35},
{36, migrateFromV36},
{37, migrateFromV37},
{38, migrateFromV38},
{39, migrateFromV39},
{40, migrateFromV40},
{41, migrateFromV41},
{42, migrateFromV42},
{43, migrateFromV43},
{44, migrateFromV44},
{45, migrateFromV45},
{46, migrateFromV46},
{47, migrateFromV47},
{48, migrateFromV48},
{49, migrateFromV49},
{50, migrateFromV50},
{51, migrateFromV51},
{52, migrateFromV52},
{53, migrateFromV53},
{54, migrateFromV54},
{55, migrateFromV55},
{56, migrateFromV56},
{57, migrateFromV57},
{58, migrateFromV58},
const std::map<unsigned, MigrationFunction> migrationFunctions{
{ 33, migrateFromV33 },
{ 34, migrateFromV34 },
{ 35, migrateFromV35 },
{ 36, migrateFromV36 },
{ 37, migrateFromV37 },
{ 38, migrateFromV38 },
{ 39, migrateFromV39 },
{ 40, migrateFromV40 },
{ 41, migrateFromV41 },
{ 42, migrateFromV42 },
{ 43, migrateFromV43 },
{ 44, migrateFromV44 },
{ 45, migrateFromV45 },
{ 46, migrateFromV46 },
{ 47, migrateFromV47 },
{ 48, migrateFromV48 },
{ 49, migrateFromV49 },
{ 50, migrateFromV50 },
{ 51, migrateFromV51 },
{ 52, migrateFromV52 },
{ 53, migrateFromV53 },
{ 54, migrateFromV54 },
{ 55, migrateFromV55 },
{ 56, migrateFromV56 },
{ 57, migrateFromV57 },
{ 58, migrateFromV58 },
};
bool migrationPerformed{};
@@ -550,4 +554,4 @@ SELECT
return migrationPerformed;
}
}
} // namespace lms::db::Migration
+1 -1
View File
@@ -54,4 +54,4 @@ namespace lms::db
{
bool doDbMigration(Session& session); // return true if migration was performed
}
}
} // namespace lms::db
+3 -3
View File
@@ -19,8 +19,9 @@
#pragma once
#include <string>
#include <filesystem>
#include <string>
#include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo
@@ -50,5 +51,4 @@ namespace Wt::Dbo
return true;
}
};
}
} // namespace Wt::Dbo
+72 -96
View File
@@ -21,15 +21,16 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
@@ -37,7 +38,7 @@ namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Release::FindParameters& params)
{
auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " from release r") };
@@ -63,7 +64,8 @@ namespace lms::db
{
query.join("release_release_type r_r_t ON r_r_t.release_id = r.id");
query.join("release_type r_t ON r_t.id = r_r_t.release_type_id")
.where("r_t.name = ?").bind(params.releaseType);
.where("r_t.name = ?")
.bind(params.releaseType);
}
if (params.writtenAfter.isValid())
@@ -82,9 +84,12 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_release s_r ON s_r.release_id = r.id")
.where("s_r.user_id = ?").bind(params.starringUser)
.where("s_r.backend = ?").bind(*params.feedbackBackend)
.where("s_r.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_r.user_id = ?")
.bind(params.starringUser)
.where("s_r.backend = ?")
.bind(*params.feedbackBackend)
.where("s_r.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.artist.isValid()
@@ -119,9 +124,9 @@ namespace lms::db
{
std::ostringstream oss;
oss << "r.id NOT IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" INNER JOIN track t ON t.release_id = r.id"
" WHERE (t_a_l.artist_id = ? AND (";
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" INNER JOIN track t ON t.release_id = r.id"
" WHERE (t_a_l.artist_id = ? AND (";
query.bind(params.artist);
@@ -143,13 +148,14 @@ namespace lms::db
if (params.clusters.size() == 1)
{
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());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT t.release_id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -200,69 +206,62 @@ namespace lms::db
return query;
}
}
} // namespace
ReleaseType::ReleaseType(std::string_view name)
: _name{ std::string(name, 0 , _maxNameLength) }
: _name{ std::string(name, 0, _maxNameLength) }
{
}
ReleaseType::pointer ReleaseType::create(Session& session, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<ReleaseType> {new ReleaseType{ name }});
return session.getDboSession()->add(std::unique_ptr<ReleaseType>{ new ReleaseType{ name } });
}
ReleaseType::pointer ReleaseType::find(Session& session, ReleaseTypeId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("id = ?").bind(id));
}
ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("name = ?").bind(name));
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("name = ?").bind(name));
}
Release::Release(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) },
_MBID{ MBID ? MBID->getAsString() : "" }
: _name{ std::string(name, 0, _maxNameLength) }
, _MBID{ MBID ? MBID->getAsString() : "" }
{
}
Release::pointer Release::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID)
{
return session.getDboSession()->add(std::unique_ptr<Release> {new Release{ name, MBID }});
return session.getDboSession()->add(std::unique_ptr<Release>{ new Release{ name, MBID } });
}
std::vector<Release::pointer> Release::find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r")
.join("track t ON t.release_id = r.id")
.where("r.name = ?").bind(std::string(name, 0, _maxNameLength))
.where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r").join("track t ON t.release_id = r.id").where("r.name = ?").bind(std::string(name, 0, _maxNameLength)).where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
}
Release::pointer Release::find(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("mbid = ?").bind(mbid.getAsString()));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("mbid = ?").bind(mbid.getAsString()));
}
Release::pointer Release::find(Session& session, ReleaseId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("id = ?").bind(id));
}
bool Release::exists(Session& session, ReleaseId id)
@@ -290,10 +289,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r")
.orderBy("r.id")
.where("r.id > ?").bind(lastRetrievedRelease)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r").orderBy("r.id").where("r.id > ?").bind(lastRetrievedRelease).limit(static_cast<int>(count)) };
if (library.isValid())
{
@@ -301,11 +297,10 @@ namespace lms::db
query.where("EXISTS (SELECT 1 FROM track t WHERE t.release_id = r.id AND t.media_library_id = ?)").bind(library);
}
utils::forEachQueryResult(query, [&](const Release::pointer& release)
{
func(release);
lastRetrievedRelease = release->getId();
});
utils::forEachQueryResult(query, [&](const Release::pointer& release) {
func(release);
lastRetrievedRelease = release->getId();
});
}
RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params)
@@ -342,8 +337,7 @@ namespace lms::db
std::size_t Release::getDiscCount() const
{
assert(session());
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t")
.where("t.release_id = ?").bind(getId()))};
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t").where("t.release_id = ?").bind(getId())) };
return res;
}
@@ -352,15 +346,12 @@ namespace lms::db
assert(session());
using ResultType = std::tuple<int, std::string>;
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t")
.where("t.release_id = ?").bind(getId())
.orderBy("disc_number")};
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t").where("t.release_id = ?").bind(getId()).orderBy("disc_number") };
std::vector<DiscInfo> discs;
utils::forEachQueryResult(query, [&](ResultType&& res)
{
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
});
utils::forEachQueryResult(query, [&](ResultType&& res) {
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
});
return discs;
}
@@ -380,10 +371,7 @@ namespace lms::db
assert(session());
const char* field{ original ? "original_date" : "date" };
auto query{ (session()->query<Wt::WDate>(std::string {"SELECT "} + "t." + field + " FROM track t")
.where("t.release_id = ?")
.groupBy(field)
.bind(getId())) };
auto query{ (session()->query<Wt::WDate>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").groupBy(field).bind(getId())) };
const auto dates{ utils::fetchQueryResults(query) };
@@ -409,9 +397,7 @@ namespace lms::db
assert(session());
const char* field{ original ? "original_year" : "year" };
auto query{ session()->query<std::optional<int>>(std::string {"SELECT "} + "t." + field + " FROM track t")
.where("t.release_id = ?").bind(getId())
.groupBy(field) };
auto query{ session()->query<std::optional<int>>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").bind(getId()).groupBy(field) };
const auto years{ utils::fetchQueryResults(query) };
@@ -427,10 +413,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?")
.groupBy("copyright")
.bind(getId()) };
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) };
const auto copyrights{ utils::fetchQueryResults(query) };
@@ -445,10 +428,7 @@ namespace lms::db
{
assert(session());
const auto query{ session()->query<std::string>
("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId())
.groupBy("copyright_url") };
const auto query{ session()->query<std::string>("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") };
const auto copyrights{ utils::fetchQueryResults(query) };
@@ -463,9 +443,7 @@ namespace lms::db
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t")
.where("release_id = ?").bind(getId())
.where("bitrate > 0"));
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t").where("release_id = ?").bind(getId()).where("bitrate > 0"));
}
std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const
@@ -473,12 +451,14 @@ namespace lms::db
assert(session());
const auto query{ session()->query<Wt::Dbo::ptr<Artist>>(
"SELECT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id")
.where("t.release_id = ?").bind(getId())
.where("+t_a_l.type = ?").bind(linkType) // adding + since the query planner does not a good job when analyze is not performed
.groupBy("a.id") };
"SELECT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id")
.where("t.release_id = ?")
.bind(getId())
.where("+t_a_l.type = ?")
.bind(linkType) // adding + since the query planner does not a good job when analyze is not performed
.groupBy("a.id") };
return utils::fetchQueryResults<Artist::pointer>(query);
}
@@ -489,24 +469,23 @@ namespace lms::db
// Select the similar releases using the 5 most used clusters of the release
auto query{ session()->query<Wt::Dbo::ptr<Release>>(
"SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN "
"(SELECT DISTINCT c.id FROM cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN release r ON r.id = t.release_id"
" WHERE r.id = ?)"
" AND r.id <> ?"
)
.bind(getId())
.bind(getId())
.groupBy("r.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
"SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN "
"(SELECT DISTINCT c.id FROM cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN release r ON r.id = t.release_id"
" WHERE r.id = ?)"
" AND r.id <> ?")
.bind(getId())
.bind(getId())
.groupBy("r.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
return utils::fetchQueryResults<Release::pointer>(query);
}
@@ -530,8 +509,7 @@ namespace lms::db
std::size_t Release::getTrackCount() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()));
}
std::vector<ReleaseType::pointer> Release::getReleaseTypes() const
@@ -556,16 +534,14 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t")
.where("t.release_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t").where("t.release_id = ?").bind(getId()));
}
Wt::WDateTime Release::getLastWritten() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t")
.where("t.release_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t").where("t.release_id = ?").bind(getId()));
}
std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
+2 -1
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/String.hpp"
#include "database/MediaLibrary.hpp"
#include "database/Session.hpp"
#include "core/String.hpp"
#include "Utils.hpp"
namespace lms::db
+6 -6
View File
@@ -22,7 +22,6 @@
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Artist.hpp"
#include "database/AuthToken.hpp"
#include "database/Cluster.hpp"
@@ -35,22 +34,23 @@
#include "database/StarredRelease.hpp"
#include "database/StarredTrack.hpp"
#include "database/Track.hpp"
#include "database/TrackBookmark.hpp"
#include "database/TrackArtistLink.hpp"
#include "database/TrackList.hpp"
#include "database/TrackBookmark.hpp"
#include "database/TrackFeatures.hpp"
#include "database/TrackList.hpp"
#include "database/TransactionChecker.hpp"
#include "database/User.hpp"
#include "EnumSetTraits.hpp"
#include "PathTraits.hpp"
#include "Migration.hpp"
#include "PathTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
: _lock{ mutex },
_transaction{ session }
: _lock{ mutex }
, _transaction{ session }
{
#if LMS_CHECK_TRANSACTION_ACCESSES
TransactionChecker::pushWriteTransaction(_transaction.session());
+8 -5
View File
@@ -27,7 +27,8 @@ namespace lms::db
{
WhereClause& WhereClause::And(const WhereClause& otherClause)
{
if (!otherClause._clause.empty()) {
if (!otherClause._clause.empty())
{
if (!_clause.empty())
_clause += " AND ";
_clause += "(" + otherClause._clause + ")";
@@ -43,7 +44,8 @@ namespace lms::db
WhereClause& WhereClause::Or(const WhereClause& otherClause)
{
if (!otherClause._clause.empty()) {
if (!otherClause._clause.empty())
{
if (!_clause.empty())
_clause += " OR ";
_clause += "(" + otherClause._clause + ")";
@@ -75,7 +77,7 @@ namespace lms::db
}
InnerJoinClause::InnerJoinClause(const std::string& clause)
:_clause(clause)
: _clause(clause)
{
}
@@ -154,7 +156,8 @@ namespace lms::db
if (!_clause.empty())
{
oss << "FROM ";
for (auto it = _clause.begin(); it != _clause.end(); ++it) {
for (auto it = _clause.begin(); it != _clause.end(); ++it)
{
if (it != _clause.begin())
oss << ",";
@@ -185,4 +188,4 @@ namespace lms::db
return oss.str();
}
}
} // namespace lms::db
+23 -15
View File
@@ -19,8 +19,8 @@
#pragma once
#include <vector>
#include <string>
#include <vector>
namespace lms::db
{
@@ -40,8 +40,8 @@ namespace lms::db
const std::vector<std::string>& getBindArgs() const { return _bindArgs; }
private:
std::string _clause; // WHERE clause
std::vector<std::string> _bindArgs;
std::string _clause; // WHERE clause
std::vector<std::string> _bindArgs;
};
class InnerJoinClause
@@ -68,13 +68,13 @@ namespace lms::db
std::string get() const { return _statement; }
private:
std::string _statement; // SELECT statement
std::string _statement; // SELECT statement
};
class SelectStatement
{
public:
SelectStatement() {};
SelectStatement(){};
SelectStatement(const std::string& item);
SelectStatement& And(const std::string& item);
@@ -82,7 +82,7 @@ namespace lms::db
std::string get() const;
private:
std::vector<std::string> _statement;
std::vector<std::string> _statement;
};
class FromClause
@@ -96,16 +96,24 @@ namespace lms::db
std::string get() const;
private:
std::vector<std::string> _clause;
std::vector<std::string> _clause;
};
class SqlQuery
{
public:
SelectStatement& select() { return _selectStatement; }
SelectStatement& select(const std::string& statement) { _selectStatement = SelectStatement(statement); return _selectStatement; }
SelectStatement& select(const std::string& statement)
{
_selectStatement = SelectStatement(statement);
return _selectStatement;
}
FromClause& from() { return _fromClause; }
FromClause& from(const std::string& clause) { _whereClause = WhereClause(clause); return _fromClause; }
FromClause& from(const std::string& clause)
{
_whereClause = WhereClause(clause);
return _fromClause;
}
InnerJoinClause& innerJoin() { return _innerJoinClause; }
WhereClause& where() { return _whereClause; }
const WhereClause& where() const { return _whereClause; }
@@ -115,10 +123,10 @@ namespace lms::db
std::string get() const;
private:
SelectStatement _selectStatement; // SELECT statement
InnerJoinClause _innerJoinClause; // INNER JOIN
FromClause _fromClause; // FROM tables
WhereClause _whereClause; // WHERE clause
GroupByStatement _groupByStatement; // GROUP BY statement
SelectStatement _selectStatement; // SELECT statement
InnerJoinClause _innerJoinClause; // INNER JOIN
FromClause _fromClause; // FROM tables
WhereClause _whereClause; // WHERE clause
GroupByStatement _groupByStatement; // GROUP BY statement
};
}
} // namespace lms::db
+5 -11
View File
@@ -24,6 +24,7 @@
#include "database/Artist.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredArtist::pointer StarredArtist::create(Session& session, ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredArtist> {new StarredArtist{ artist, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredArtist>{ new StarredArtist{ artist, user, backend } });
}
std::size_t StarredArtist::getCount(Session& session)
@@ -56,24 +57,17 @@ namespace lms::db
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a")
.join("user u ON u.id = s_a.user_id")
.where("s_a.artist_id = ?").bind(artistId)
.where("s_a.user_id = ?").bind(userId)
.where("s_a.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a").join("user u ON u.id = s_a.user_id").where("s_a.artist_id = ?").bind(artistId).where("s_a.user_id = ?").bind(userId).where("s_a.backend = u.feedback_backend"));
}
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>()
.where("artist_id = ?").bind(artistId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>().where("artist_id = ?").bind(artistId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
void StarredArtist::setDateTime(const Wt::WDateTime& dateTime)
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+5 -11
View File
@@ -24,6 +24,7 @@
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredRelease::pointer StarredRelease::create(Session& session, ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredRelease>{new StarredRelease{ release, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredRelease>{ new StarredRelease{ release, user, backend } });
}
std::size_t StarredRelease::getCount(Session& session)
@@ -56,24 +57,17 @@ namespace lms::db
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r")
.join("user u ON u.id = s_r.user_id")
.where("s_r.release_id = ?").bind(releaseId)
.where("s_r.user_id = ?").bind(userId)
.where("s_r.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r").join("user u ON u.id = s_r.user_id").where("s_r.release_id = ?").bind(releaseId).where("s_r.user_id = ?").bind(userId).where("s_r.backend = u.feedback_backend"));
}
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>()
.where("release_id = ?").bind(releaseId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>().where("release_id = ?").bind(releaseId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
void StarredRelease::setDateTime(const Wt::WDateTime& dateTime)
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+7 -16
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "database/Track.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredTrack::pointer StarredTrack::create(Session& session, ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredTrack> {new StarredTrack{ track, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredTrack>{ new StarredTrack{ track, user, backend } });
}
std::size_t StarredTrack::getCount(Session& session)
@@ -56,28 +57,18 @@ namespace lms::db
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t")
.join("user u ON u.id = s_t.user_id")
.where("s_t.track_id = ?").bind(trackId)
.where("s_t.user_id = ?").bind(userId)
.where("s_t.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t").join("user u ON u.id = s_t.user_id").where("s_t.track_id = ?").bind(trackId).where("s_t.user_id = ?").bind(userId).where("s_t.backend = u.feedback_backend"));
}
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>()
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>().where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track")
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track").where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params)
@@ -100,4 +91,4 @@ namespace lms::db
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <string_view>
#include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo
@@ -32,5 +33,4 @@ namespace Wt::Dbo
statement->bind(column, std::string{ str });
}
};
}
} // namespace Wt::Dbo
+43 -53
View File
@@ -21,15 +21,15 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/MediaLibrary.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/TrackArtistLink.hpp"
#include "database/TrackFeatures.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "PathTraits.hpp"
@@ -41,7 +41,7 @@ namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Track::FindParameters& params)
{
session.checkReadTransaction();
@@ -62,22 +62,26 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_track s_t ON s_t.track_id = t.id")
.where("s_t.user_id = ?").bind(params.starringUser)
.where("s_t.backend = ?").bind(*params.feedbackBackend)
.where("s_t.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_t.user_id = ?")
.bind(params.starringUser)
.where("s_t.backend = ?")
.bind(*params.feedbackBackend)
.where("s_t.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.clusters.size() == 1)
{
// optim
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());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -183,7 +187,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Track::FindParameters& params)
{
std::string_view itemToSelect;
@@ -197,7 +201,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Track::pointer Track::create(Session& session)
{
@@ -222,27 +226,22 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>().where("id = ?").bind(id));
}
void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library)
{
session.checkReadTransaction();
auto query{ session.getDboSession()->find<Track>()
.orderBy("id")
.where("id > ?").bind(lastRetrievedTrack)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->find<Track>().orderBy("id").where("id > ?").bind(lastRetrievedTrack).limit(static_cast<int>(count)) };
if (library.isValid())
query.where("media_library_id = ?").bind(library);
utils::forEachQueryResult(query, [&](const Track::pointer& track)
{
func(track);
lastRetrievedTrack = track->getId();
});
utils::forEachQueryResult(query, [&](const Track::pointer& track) {
func(track);
lastRetrievedTrack = track->getId();
});
}
bool Track::exists(Session& session, TrackId id)
@@ -256,24 +255,21 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("mbid = ?").bind(mbid.getAsString()));
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("mbid = ?").bind(mbid.getAsString()));
}
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("recording_mbid = ?").bind(mbid.getAsString()));
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("recording_mbid = ?").bind(mbid.getAsString()));
}
RangeResults<TrackId> Track::findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range)
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)")
.orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -282,9 +278,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t")
.where("LENGTH(t.recording_mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t").where("LENGTH(t.recording_mbid) > 0").where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -298,10 +292,7 @@ namespace lms::db
{
assert(session());
const auto query{ session()->query<ClusterId>
("SELECT t_c.cluster_id FROM track_cluster t_c")
.where("t_c.track_id = ?").bind(getId())
.groupBy("t_c.cluster_id") };
const auto query{ session()->query<ClusterId>("SELECT t_c.cluster_id FROM track_cluster t_c").where("t_c.track_id = ?").bind(getId()).groupBy("t_c.cluster_id") };
return utils::fetchQueryResults(query);
}
@@ -352,12 +343,14 @@ namespace lms::db
}
auto query{ session.getDboSession()->query<TrackId>(
"SELECT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + oss.str() + "))"
" AND t.id NOT IN (" + oss.str() + ")")
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
"SELECT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN ("
+ oss.str() + "))"
" AND t.id NOT IN ("
+ oss.str() + ")")
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
for (TrackId trackId : tracks)
query.bind(trackId);
@@ -412,10 +405,9 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT a from artist a"
" INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id"
" INNER JOIN track t ON t.id = t_a_l.track_id";
oss << "SELECT a from artist a"
" INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id"
" INNER JOIN track t ON t.id = t_a_l.track_id";
if (!linkTypes.empty())
{
@@ -447,9 +439,8 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track t ON t.id = t_a_l.track_id";
oss << "SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track t ON t.id = t_a_l.track_id";
if (!linkTypes.empty())
{
@@ -507,11 +498,10 @@ namespace lms::db
query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster);
});
std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [type, clusters] : clusters)
@@ -545,6 +535,6 @@ namespace lms::db
return os;
}
}
} // namespace Debug
} // namespace lms::db
+14 -20
View File
@@ -53,7 +53,7 @@ namespace lms::db
return query;
}
}
} // namespace
TrackArtistLink::TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType)
: _type{ type }
@@ -83,40 +83,34 @@ namespace lms::db
{
session.checkReadTransaction();
using ResultType = std::tuple < Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>;
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) };
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));
});
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)
{
const auto query{ createQuery(session, parameters) };
utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link)
{
func(link);
});
utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) {
func(link);
});
}
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId)
{
session.checkReadTransaction();
const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")
.where("artist_id = ?").bind(artistId) };
const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link").where("artist_id = ?").bind(artistId) };
core::EnumSet<TrackArtistLinkType> res;
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType)
{
res.insert(linkType);
});
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) {
res.insert(linkType);
});
return res;
}
}
} // namespace lms::db
+7 -11
View File
@@ -22,20 +22,21 @@
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
TrackBookmark::TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track)
: _user{ getDboPtr(user) },
_track{ getDboPtr(track) }
: _user{ getDboPtr(user) }
, _track{ getDboPtr(track) }
{
}
TrackBookmark::pointer TrackBookmark::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track)
{
return session.getDboSession()->add(std::unique_ptr<TrackBookmark> {new TrackBookmark{ user, track }});
return session.getDboSession()->add(std::unique_ptr<TrackBookmark>{ new TrackBookmark{ user, track } });
}
std::size_t TrackBookmark::getCount(Session& session)
@@ -49,8 +50,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark")
.where("user_id = ?").bind(userId) };
auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark").where("user_id = ?").bind(userId) };
return utils::execRangeQuery<TrackBookmarkId>(query, range);
}
@@ -59,18 +59,14 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId));
}
TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("id = ?").bind(id));
}
} // namespace lms::db
+11 -11
View File
@@ -19,26 +19,28 @@
#include "database/TrackFeatures.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include "core/ILogger.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db {
namespace lms::db
{
TrackFeatures::TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
: _data{ jsonEncodedFeatures },
_track{ getDboPtr(track) }
: _data{ jsonEncodedFeatures }
, _track{ getDboPtr(track) }
{
}
TrackFeatures::pointer TrackFeatures::create(Session& session, ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
{
return session.getDboSession()->add(std::unique_ptr<TrackFeatures> {new TrackFeatures{ track, jsonEncodedFeatures }});
return session.getDboSession()->add(std::unique_ptr<TrackFeatures>{ new TrackFeatures{ track, jsonEncodedFeatures } });
}
std::size_t TrackFeatures::getCount(Session& session)
@@ -52,16 +54,14 @@ namespace lms::db {
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("id = ?").bind(id));
}
TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("track_id = ?").bind(trackId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("track_id = ?").bind(trackId));
}
RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range)
@@ -75,7 +75,7 @@ namespace lms::db {
FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const
{
FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({featureNode}) };
FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({ featureNode }) };
return std::move(featuresValuesMap[featureNode]);
}
+33 -47
View File
@@ -21,23 +21,23 @@
#include <cassert>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const TrackList::FindParameters& params)
{
auto query{ session.getDboSession()->query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM tracklist t_l") };
@@ -61,8 +61,8 @@ namespace lms::db
{
std::ostringstream oss;
oss << "t_l_e.track_id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -92,7 +92,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const TrackList::FindParameters& params)
{
std::string_view itemToSelect;
@@ -106,7 +106,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
: _name{ name }
@@ -121,7 +121,7 @@ namespace lms::db
TrackList::pointer TrackList::create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
{
return session.getDboSession()->add(std::unique_ptr<TrackList> {new TrackList{ name, type, isPublic, user }});
return session.getDboSession()->add(std::unique_ptr<TrackList>{ new TrackList{ name, type, isPublic, user } });
}
std::size_t TrackList::getCount(Session& session)
@@ -136,10 +136,7 @@ namespace lms::db
session.checkReadTransaction();
assert(userId.isValid());
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>()
.where("name = ?").bind(name)
.where("type = ?").bind(type)
.where("user_id = ?").bind(userId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>().where("name = ?").bind(name).where("type = ?").bind(type).where("user_id = ?").bind(userId));
}
RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params)
@@ -188,9 +185,7 @@ namespace lms::db
{
assert(session());
auto query{session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId())
.orderBy("id") };
auto query{ session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).orderBy("id") };
return utils::execRangeQuery<TrackListEntry::pointer>(query, range);
}
@@ -199,20 +194,14 @@ namespace lms::db
{
assert(session());
return utils::fetchQuerySingleResult(session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId())
.where("track_id = ?").bind(track->getId())
.where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
return utils::fetchQuerySingleResult(session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).where("track_id = ?").bind(track->getId()).where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
}
std::vector<Cluster::pointer> TrackList::getClusters() const
{
assert(session());
const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
.where("p.id = ?").bind(getId())
.groupBy("c.id")
.orderBy("COUNT(c.id) DESC") };
const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id").where("p.id = ?").bind(getId()).groupBy("c.id").orderBy("COUNT(c.id) DESC") };
return utils::fetchQueryResults<Cluster::pointer>(query);
}
@@ -232,7 +221,8 @@ namespace lms::db
.join("cluster_type c_type ON c.cluster_type_id = c_type.id")
.join("tracklist_entry t_l_e ON t_l_e.track_id = t.id")
.join("tracklist t_l ON t_l.id = t_l_e.tracklist_id")
.where("t_l.id = ?").bind(getId());
.where("t_l.id = ?")
.bind(getId());
{
std::ostringstream oss;
@@ -253,11 +243,10 @@ namespace lms::db
query.orderBy("COUNT(c.id) DESC");
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
for (const auto& [clusterTypeId, clusters] : clustersByType)
res.push_back(clusters);
@@ -270,18 +259,17 @@ namespace lms::db
assert(session());
auto query{ session()->query<Wt::Dbo::ptr<Track>>(
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))"
)
.bind(getId())
.bind(getId())
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))")
.bind(getId())
.bind(getId())
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
return utils::fetchQueryResults<Track::pointer>(query);
}
@@ -290,8 +278,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
.where("p.id = ?").bind(getId()) };
auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id").where("p.id = ?").bind(getId()) };
return utils::fetchQueryResults(query);
}
@@ -302,8 +289,7 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id")
.where("p_e.tracklist_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id").where("p_e.tracklist_id = ?").bind(getId()));
}
void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime)
@@ -322,7 +308,7 @@ namespace lms::db
TrackListEntry::pointer TrackListEntry::create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime)
{
return session.getDboSession()->add(std::unique_ptr<TrackListEntry> {new TrackListEntry{ track, tracklist, dateTime }});
return session.getDboSession()->add(std::unique_ptr<TrackListEntry>{ new TrackListEntry{ track, tracklist, dateTime } });
}
void TrackListEntry::onPostCreated()
@@ -22,6 +22,7 @@
static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build");
#include <cassert>
#include "database/Session.hpp"
namespace lms::db
@@ -35,7 +36,7 @@ namespace lms::db
};
static thread_local std::vector<StackEntry> transactionStack;
}
} // namespace
void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session)
{
@@ -93,4 +94,4 @@ namespace lms::db
{
checkReadTransaction(*session.getDboSession());
}
}
} // namespace lms::db
+2 -4
View File
@@ -23,8 +23,7 @@
namespace lms::db
{
static const std::set<Bitrate> allowedAudioBitrates
{
static const std::set<Bitrate> allowedAudioBitrates{
64000,
96000,
128000,
@@ -47,5 +46,4 @@ namespace lms::db
{
return DateRange{ from, to };
}
}
} // namespace lms::db
+4 -4
View File
@@ -19,11 +19,12 @@
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
@@ -37,7 +38,7 @@ namespace lms::db
User::pointer User::create(Session& session, std::string_view loginName)
{
return session.getDboSession()->add(std::unique_ptr<User> {new User{ loginName }});
return session.getDboSession()->add(std::unique_ptr<User>{ new User{ loginName } });
}
std::size_t User::getCount(Session& session)
@@ -87,8 +88,7 @@ namespace lms::db
User::pointer User::find(Session& session, std::string_view name)
{
return utils::fetchQuerySingleResult(session.getDboSession()->find<User>()
.where("login_name = ?").bind(name));
return utils::fetchQuerySingleResult(session.getDboSession()->find<User>().where("login_name = ?").bind(name));
}
void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate)
+1 -2
View File
@@ -33,5 +33,4 @@ namespace lms::db::utils
// force second resolution
return Wt::WDateTime::fromTime_t(dateTime.toTime_t());
}
} // namespace lms::db::Utils
} // namespace lms::db::utils
+16 -16
View File
@@ -26,8 +26,8 @@
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "database/Types.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Types.hpp"
namespace lms::db::utils
{
@@ -35,7 +35,7 @@ namespace lms::db::utils
static inline constexpr char escapeChar{ '\\' };
std::string escapeLikeKeyword(std::string_view keywords);
template <typename Query>
template<typename Query>
void applyRange(Query& query, std::optional<Range> range)
{
if (range)
@@ -45,21 +45,21 @@ namespace lms::db::utils
}
}
template <typename T>
template<typename T>
auto fetchFirstResult(const Wt::Dbo::collection<T>& collection)
{
LMS_SCOPED_TRACE_DETAILED("Database", "FetchFirstResult");
return collection.begin();
}
template <typename T>
template<typename T>
void fetchNextResult(typename Wt::Dbo::collection<T>::const_iterator& it)
{
LMS_SCOPED_TRACE_DETAILED("Database", "FetchNextResult");
it++;
}
template <typename T, typename Func>
template<typename T, typename Func>
void forEachResult(const Wt::Dbo::collection<T>& collection, Func&& func)
{
typename Wt::Dbo::collection<T>::const_iterator it{ fetchFirstResult(collection) };
@@ -70,23 +70,23 @@ namespace lms::db::utils
}
}
template <typename T>
template<typename T>
struct QueryResultType;
template <class ResultType, typename BindStrategy>
template<class ResultType, typename BindStrategy>
struct QueryResultType<Wt::Dbo::Query<ResultType, BindStrategy>>
{
using type = ResultType;
};
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryResult(const Query& query, UnaryFunc&& func)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString());
forEachResult(query.resultList(), std::forward<UnaryFunc>(func));
}
template <typename T, typename Query>
template<typename T, typename Query>
std::vector<T> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -95,7 +95,7 @@ namespace lms::db::utils
return std::vector<T>(collection.begin(), collection.end());
}
template <typename Query>
template<typename Query>
std::vector<typename QueryResultType<Query>::type> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -103,15 +103,15 @@ namespace lms::db::utils
auto collection{ query.resultList() };
return std::vector<typename QueryResultType<Query>::type>(collection.begin(), collection.end());
}
template <typename Query>
template<typename Query>
auto fetchQuerySingleResult(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString());
return query.resultValue();
}
template <typename ResultType, typename Query>
template<typename ResultType, typename Query>
RangeResults<ResultType> execRangeQuery(Query& query, const std::optional<Range> range)
{
RangeResults<ResultType> res;
@@ -137,7 +137,7 @@ namespace lms::db::utils
return res;
}
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryRangeResult(Query& query, std::optional<Range> range, UnaryFunc&& func)
{
if (range)
@@ -146,7 +146,7 @@ namespace lms::db::utils
forEachQueryResult(query, std::forward<UnaryFunc>(func));
}
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryRangeResult(Query& query, std::optional<Range> range, bool& moreResults, UnaryFunc&& func)
{
using ResultType = typename QueryResultType<Query>::type;
@@ -173,4 +173,4 @@ namespace lms::db::utils
}
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime);
}
} // namespace lms::db::utils
+79 -39
View File
@@ -25,8 +25,8 @@
#include <string_view>
#include <vector>
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "core/EnumSet.hpp"
#include "core/UUID.hpp"
@@ -35,9 +35,9 @@
#include "database/MediaLibraryId.hpp"
#include "database/Object.hpp"
#include "database/ReleaseId.hpp"
#include "database/TrackId.hpp"
#include "database/Types.hpp"
#include "database/UserId.hpp"
#include "database/TrackId.hpp"
namespace lms::db
{
@@ -56,51 +56,92 @@ namespace lms::db
public:
struct FindParameters
{
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::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
ArtistSortMethod sortMethod{ ArtistSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
UserId starringUser; // only artists starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this feedback backend
TrackId track; // artists involved in this track
ReleaseId release; // artists involved in this release
MediaLibraryId mediaLibrary; // artists that belong to this library
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::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
ArtistSortMethod sortMethod{ ArtistSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
UserId starringUser; // only artists starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this feedback backend
TrackId track; // artists involved in this track
ReleaseId release; // artists involved in this release
MediaLibraryId mediaLibrary; // artists that belong to this library
FindParameters& setClusters(std::span<const ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); 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& setSortMethod(ArtistSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; 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& setTrack(TrackId _track) { track = _track; return *this; }
FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; }
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; }
FindParameters& setClusters(std::span<const ClusterId> _clusters)
{
clusters.assign(std::cbegin(_clusters), std::cend(_clusters));
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& setSortMethod(ArtistSortMethod _sortMethod)
{
sortMethod = _sortMethod;
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
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& setTrack(TrackId _track)
{
track = _track;
return *this;
}
FindParameters& setRelease(ReleaseId _release)
{
release = _release;
return *this;
}
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary)
{
mediaLibrary = _mediaLibrary;
return *this;
}
};
Artist() = default;
// Accessors
static std::size_t getCount(Session& session);
static pointer find(Session& session, const core::UUID& MBID);
static pointer find(Session& session, ArtistId id);
static std::vector<pointer> find(Session& session, std::string_view name); // exact match on name field
static void find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function<void(const Artist::pointer&)>& func, MediaLibraryId library = {});
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, std::function<void(const pointer&)> func);
static RangeResults<ArtistId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<ArtistId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // No track related
static bool exists(Session& session, ArtistId id);
static std::size_t getCount(Session& session);
static pointer find(Session& session, const core::UUID& MBID);
static pointer find(Session& session, ArtistId id);
static std::vector<pointer> find(Session& session, std::string_view name); // exact match on name field
static void find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function<void(const Artist::pointer&)>& func, MediaLibraryId library = {});
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, std::function<void(const pointer&)> func);
static RangeResults<ArtistId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<ArtistId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // No track related
static bool exists(Session& session, ArtistId id);
// Accessors
const std::string& getName() const { return _name; }
const std::string& getSortName() const { return _sortName; }
std::optional<core::UUID> getMBID() const { return core::UUID::fromString(_MBID); }
std::optional<core::UUID> getMBID() const { return core::UUID::fromString(_MBID); }
// No artistLinkTypes means get them all
RangeResults<ArtistId> findSimilarArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes = {}, std::optional<Range> range = std::nullopt) const;
RangeResults<ArtistId> findSimilarArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes = {}, std::optional<Range> range = std::nullopt) const;
// Get the cluster of the tracks made by this artist
// Each clusters are grouped by cluster type, sorted by the number of occurence
@@ -132,11 +173,10 @@ namespace lms::db
std::string _name;
std::string _sortName;
std::string _MBID; // Musicbrainz Identifier
std::string _MBID; // Musicbrainz Identifier
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<TrackArtistLink>> _trackArtistLinks; // Tracks involving this artist
Wt::Dbo::collection<Wt::Dbo::ptr<StarredArtist>> _starredArtists; // starred entries for this artist
};
} // namespace lms::db
@@ -22,4 +22,3 @@
#include "database/IdType.hpp"
LMS_DECLARE_IDTYPE(ArtistId)
@@ -29,39 +29,38 @@
namespace lms::db
{
class Session;
class Session;
class User;
class AuthToken final : public Object<AuthToken, AuthTokenId>
{
public:
AuthToken() = default;
class User;
class AuthToken final : public Object<AuthToken, AuthTokenId>
{
public:
AuthToken() = default;
// Utility
static void removeExpiredTokens(Session& session, const Wt::WDateTime& now);
static pointer find(Session& session, std::string_view value);
// Utility
static void removeExpiredTokens(Session& session, const Wt::WDateTime& now);
static pointer find(Session& session, std::string_view value);
// Accessors
const Wt::WDateTime& getExpiry() const { return _expiry; }
ObjectPtr<User> getUser() const { return _user; }
const std::string& getValue() const { return _value; }
// Accessors
const Wt::WDateTime& getExpiry() const { return _expiry; }
ObjectPtr<User> getUser() const { return _user; }
const std::string& getValue() const { return _value; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _value, "value");
Wt::Dbo::field(a, _expiry, "expiry");
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
}
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _value, "value");
Wt::Dbo::field(a, _expiry, "expiry");
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
}
private:
friend class Session;
AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user);
static pointer create(Session& session, std::string_view value, const Wt::WDateTime&expiry, ObjectPtr<User> user);
std::string _value;
Wt::WDateTime _expiry;
Wt::Dbo::ptr<User> _user;
};
} // namespace Databas'
private:
friend class Session;
AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user);
static pointer create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user);
std::string _value;
Wt::WDateTime _expiry;
Wt::Dbo::ptr<User> _user;
};
} // namespace lms::db
+62 -40
View File
@@ -45,41 +45,65 @@ namespace lms::db
public:
struct FindParameters
{
std::optional<Range> range;
ClusterSortMethod sortMethod;
ClusterTypeId clusterType; // if non empty, clusters that belong to this cluster type
std::string clusterTypeName; // if non empty, clusters that belong to this cluster type
TrackId track; // if set, clusters involved in this track
ReleaseId release; // if set, clusters involved in this release
std::optional<Range> range;
ClusterSortMethod sortMethod;
ClusterTypeId clusterType; // if non empty, clusters that belong to this cluster type
std::string clusterTypeName; // if non empty, clusters that belong to this cluster type
TrackId track; // if set, clusters involved in this track
ReleaseId release; // if set, clusters involved in this release
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setSortMethod(ClusterSortMethod _method) { sortMethod = _method; return *this; }
FindParameters& setClusterType(ClusterTypeId _clusterType) { clusterType = _clusterType; return *this; }
FindParameters& setClusterTypeName(std::string_view _name) { clusterTypeName = _name; return *this; }
FindParameters& setTrack(TrackId _track) { track = _track; return *this; }
FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; }
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
FindParameters& setSortMethod(ClusterSortMethod _method)
{
sortMethod = _method;
return *this;
}
FindParameters& setClusterType(ClusterTypeId _clusterType)
{
clusterType = _clusterType;
return *this;
}
FindParameters& setClusterTypeName(std::string_view _name)
{
clusterTypeName = _name;
return *this;
}
FindParameters& setTrack(TrackId _track)
{
track = _track;
return *this;
}
FindParameters& setRelease(ReleaseId _release)
{
release = _release;
return *this;
}
};
Cluster() = default;
// Find utility
static std::size_t getCount(Session& session);
static RangeResults<ClusterId> findIds(Session& session, const FindParameters& params);
static RangeResults<pointer> find(Session& session, const FindParameters& params);
static void find(Session& session, const FindParameters& params, std::function<void(const pointer& cluster)> _func);
static pointer find(Session& session, ClusterId id);
static RangeResults<ClusterId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt);
static std::size_t getCount(Session& session);
static RangeResults<ClusterId> findIds(Session& session, const FindParameters& params);
static RangeResults<pointer> find(Session& session, const FindParameters& params);
static void find(Session& session, const FindParameters& params, std::function<void(const pointer& cluster)> _func);
static pointer find(Session& session, ClusterId id);
static RangeResults<ClusterId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt);
// May be very slow
static std::size_t computeTrackCount(Session& session, ClusterId id);
static std::size_t computeReleaseCount(Session& session, ClusterId id);
static std::size_t computeTrackCount(Session& session, ClusterId id);
static std::size_t computeReleaseCount(Session& session, ClusterId id);
// Accessors
std::string_view getName() const { return _name; }
ObjectPtr<ClusterType> getType() const { return _clusterType; }
std::size_t getTrackCount() const { return _trackCount; }
RangeResults<TrackId> getTracks(std::optional<Range> range = std::nullopt) const;
std::size_t getReleasesCount() const { return _releaseCount; };
std::string_view getName() const { return _name; }
ObjectPtr<ClusterType> getType() const { return _clusterType; }
std::size_t getTrackCount() const { return _trackCount; }
RangeResults<TrackId> getTracks(std::optional<Range> range = std::nullopt) const;
std::size_t getReleasesCount() const { return _releaseCount; };
void setReleaseCount(std::size_t releaseCount) { _releaseCount = releaseCount; }
void setTrackCount(std::size_t trackCount) { _trackCount = trackCount; }
@@ -104,35 +128,34 @@ namespace lms::db
static const std::size_t _maxNameLength = 128;
std::string _name;
std::string _name;
int _trackCount{};
int _releaseCount{};
Wt::Dbo::ptr<ClusterType> _clusterType;
Wt::Dbo::collection< Wt::Dbo::ptr<Track> > _tracks;
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks;
};
class ClusterType final : public Object<ClusterType, ClusterTypeId>
{
public:
ClusterType() = default;
// Getters
static std::size_t getCount(Session& session);
static RangeResults<ClusterTypeId> findIds(Session& session, std::optional<Range> range = std::nullopt);
static void find(Session& session, const std::function<void(const pointer&)>& func);
static pointer find(Session& session, std::string_view name);
static pointer find(Session& session, ClusterTypeId id);
static RangeResults<ClusterTypeId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<ClusterTypeId> findUsed(Session& session, std::optional<Range> range = std::nullopt);
static std::size_t getCount(Session& session);
static RangeResults<ClusterTypeId> findIds(Session& session, std::optional<Range> range = std::nullopt);
static void find(Session& session, const std::function<void(const pointer&)>& func);
static pointer find(Session& session, std::string_view name);
static pointer find(Session& session, ClusterTypeId id);
static RangeResults<ClusterTypeId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<ClusterTypeId> findUsed(Session& session, std::optional<Range> range = std::nullopt);
static void remove(Session& session, const std::string& name);
// Accessors
std::string_view getName() const { return _name; }
std::vector<Cluster::pointer> getClusters() const;
Cluster::pointer getCluster(const std::string& name) const;
std::vector<Cluster::pointer> getClusters() const;
Cluster::pointer getCluster(const std::string& name) const;
template<class Action>
void persist(Action& a)
@@ -148,9 +171,8 @@ namespace lms::db
static const std::size_t _maxNameLength = 128;
std::string _name;
Wt::Dbo::collection< Wt::Dbo::ptr<Cluster> > _clusters;
std::string _name;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
};
} // namespace lms::db
@@ -23,4 +23,3 @@
LMS_DECLARE_IDTYPE(ClusterId)
LMS_DECLARE_IDTYPE(ClusterTypeId)
+2 -2
View File
@@ -63,10 +63,10 @@ namespace lms::db
};
core::RecursiveSharedMutex _sharedMutex;
std::unique_ptr<Wt::Dbo::SqlConnectionPool> _connectionPool;
std::unique_ptr<Wt::Dbo::SqlConnectionPool> _connectionPool;
std::mutex _tlsSessionsMutex;
std::vector<std::unique_ptr<Session>> _tlsSessions;
};
}
} // namespace lms::db
+29 -25
View File
@@ -19,10 +19,9 @@
#pragma once
#include <Wt/Dbo/ptr.h>
#include <cassert>
#include <functional>
#include <Wt/Dbo/ptr.h>
namespace lms::db
{
@@ -32,38 +31,43 @@ namespace lms::db
using ValueType = Wt::Dbo::dbo_default_traits::IdType;
IdType() = default;
IdType(ValueType id) : _id{ id } { assert(isValid()); }
IdType(ValueType id)
: _id{ id } { assert(isValid()); }
bool isValid() const { return _id != Wt::Dbo::dbo_default_traits::invalidId(); }
std::string toString() const { assert(isValid()); return std::to_string(_id); }
std::string toString() const
{
assert(isValid());
return std::to_string(_id);
}
ValueType getValue() const { return _id; }
auto operator<=>(const IdType& other) const = default; \
auto operator<=>(const IdType& other) const = default;
private:
Wt::Dbo::dbo_default_traits::IdType _id{ Wt::Dbo::dbo_default_traits::invalidId() };
};
#define LMS_DECLARE_IDTYPE(name) \
namespace lms::db { \
class name : public IdType \
{ \
public: \
using IdType::IdType; \
auto operator<=>(const name& other) const = default; \
};\
} \
namespace std \
{ \
template<> \
class hash<lms::db::name> \
{ \
public: \
size_t operator()(lms::db::name id) const \
{ \
#define LMS_DECLARE_IDTYPE(name) \
namespace lms::db \
{ \
class name : public IdType \
{ \
public: \
using IdType::IdType; \
auto operator<=>(const name& other) const = default; \
}; \
} \
namespace std \
{ \
template<> \
class hash<lms::db::name> \
{ \
public: \
size_t operator()(lms::db::name id) const \
{ \
return std::hash<lms::db::name::ValueType>()(id.getValue()); \
} \
}; \
} \
}; \
} // ns std
} // namespace lms::db
+96 -49
View File
@@ -47,76 +47,124 @@ namespace lms::db
struct FindParameters
{
UserId user;
std::optional<ScrobblingBackend> backend;
std::optional<SyncState> syncState;
std::optional<Range> range;
UserId user;
std::optional<ScrobblingBackend> backend;
std::optional<SyncState> syncState;
std::optional<Range> range;
FindParameters& setUser(UserId _user) { user = _user; return *this; }
FindParameters& setScrobblingBackend(ScrobblingBackend _backend) { backend = _backend; return *this; }
FindParameters& setSyncState(SyncState _syncState) { syncState = _syncState; return *this; }
FindParameters& setRange(Range _range) { range = _range; return *this; }
FindParameters& setUser(UserId _user)
{
user = _user;
return *this;
}
FindParameters& setScrobblingBackend(ScrobblingBackend _backend)
{
backend = _backend;
return *this;
}
FindParameters& setSyncState(SyncState _syncState)
{
syncState = _syncState;
return *this;
}
FindParameters& setRange(Range _range)
{
range = _range;
return *this;
}
};
// Accessors
static std::size_t getCount(Session& session);
static pointer find(Session& session, ListenId id);
static pointer find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime);
static RangeResults<ListenId> find(Session& session, const FindParameters& parameters);
static std::size_t getCount(Session& session);
static pointer find(Session& session, ListenId id);
static pointer find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime);
static RangeResults<ListenId> find(Session& session, const FindParameters& parameters);
// Stats
struct StatsFindParameters
{
UserId user;
std::optional<ScrobblingBackend> backend;
std::vector<ClusterId> clusters; // if non empty, entities that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::optional<Range> range;
ArtistId artist; // if set, matching this artist
MediaLibraryId library;
UserId user;
std::optional<ScrobblingBackend> backend;
std::vector<ClusterId> clusters; // if non empty, entities that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::optional<Range> range;
ArtistId artist; // if set, matching this artist
MediaLibraryId library;
StatsFindParameters& setUser(UserId _user) { user = _user; return *this; }
StatsFindParameters& setScrobblingBackend(std::optional<ScrobblingBackend> _backend) { backend = _backend; return *this; }
StatsFindParameters& setClusters(const std::vector<ClusterId>& _clusters) { clusters = _clusters; return *this; }
StatsFindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
StatsFindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
StatsFindParameters& setArtist(ArtistId _artist) { artist = _artist; return *this; }
StatsFindParameters& setMediaLibrary(MediaLibraryId _library) { library = _library; return *this; }
StatsFindParameters& setUser(UserId _user)
{
user = _user;
return *this;
}
StatsFindParameters& setScrobblingBackend(std::optional<ScrobblingBackend> _backend)
{
backend = _backend;
return *this;
}
StatsFindParameters& setClusters(const std::vector<ClusterId>& _clusters)
{
clusters = _clusters;
return *this;
}
StatsFindParameters& setKeywords(const std::vector<std::string_view>& _keywords)
{
keywords = _keywords;
return *this;
}
StatsFindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
StatsFindParameters& setArtist(ArtistId _artist)
{
artist = _artist;
return *this;
}
StatsFindParameters& setMediaLibrary(MediaLibraryId _library)
{
library = _library;
return *this;
}
};
struct ArtistStatsFindParameters : public StatsFindParameters
{
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
ArtistStatsFindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; }
ArtistStatsFindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType)
{
linkType = _linkType;
return *this;
}
};
static RangeResults<ArtistId> getTopArtists(Session& session, const ArtistStatsFindParameters& params);
static RangeResults<ReleaseId> getTopReleases(Session& session, const StatsFindParameters& params);
static RangeResults<TrackId> getTopTracks(Session& session, const StatsFindParameters& params);
static RangeResults<ArtistId> getTopArtists(Session& session, const ArtistStatsFindParameters& params);
static RangeResults<ReleaseId> getTopReleases(Session& session, const StatsFindParameters& params);
static RangeResults<TrackId> getTopTracks(Session& session, const StatsFindParameters& params);
static RangeResults<ArtistId> getRecentArtists(Session& session, const ArtistStatsFindParameters& params);
static RangeResults<ReleaseId> getRecentReleases(Session& session, const StatsFindParameters& params);
static RangeResults<TrackId> getRecentTracks(Session& session, const StatsFindParameters& params);
static RangeResults<ArtistId> getRecentArtists(Session& session, const ArtistStatsFindParameters& params);
static RangeResults<ReleaseId> getRecentReleases(Session& session, const StatsFindParameters& params);
static RangeResults<TrackId> getRecentTracks(Session& session, const StatsFindParameters& params);
static std::size_t getCount(Session& session, UserId userId, TrackId trackId); // for the current backend
static std::size_t getCount(Session& session, UserId userId, ReleaseId trackId); // for the current backend
static std::size_t getCount(Session& session, UserId userId, TrackId trackId); // for the current backend
static std::size_t getCount(Session& session, UserId userId, ReleaseId trackId); // for the current backend
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId);
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId);
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId);
static pointer getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId releaseId);
SyncState getSyncState() const { return _syncState; }
ObjectPtr<User> getUser() const { return _user; }
ObjectPtr<Track> getTrack() const { return _track; }
SyncState getSyncState() const { return _syncState; }
ObjectPtr<User> getUser() const { return _user; }
ObjectPtr<Track> getTrack() const { return _track; }
const Wt::WDateTime& getDateTime() const { return _dateTime; }
void setSyncState(SyncState state) { _syncState = state; }
void setSyncState(SyncState state) { _syncState = state; }
template<class Action>
void persist(Action& a)
{
Wt::Dbo::field(a, _dateTime, "date_time");
Wt::Dbo::field(a, _backend, "backend"); // TODO rename
Wt::Dbo::field(a, _backend, "backend"); // TODO rename
Wt::Dbo::field(a, _syncState, "sync_state"); // TODO rename
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
@@ -128,13 +176,12 @@ namespace lms::db
Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime);
static pointer create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime);
Wt::WDateTime _dateTime;
ScrobblingBackend _backend;
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime;
ScrobblingBackend _backend;
SyncState _syncState{ SyncState::PendingAdd };
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Track> _track;
};
} // namespace lms::db
@@ -22,4 +22,3 @@
#include "database/IdType.hpp"
LMS_DECLARE_IDTYPE(ListenId)
@@ -44,7 +44,7 @@ namespace lms::db
static pointer find(Session& session, MediaLibraryId id);
static pointer find(Session& session, std::string_view name);
static pointer find(Session& session, const std::filesystem::path& path);
static void find(Session& session, std::function<void(const pointer&)> func);
static void find(Session& session, std::function<void(const pointer&)> func);
static std::vector<pointer> find(Session& session);
// getters
@@ -67,7 +67,7 @@ namespace lms::db
MediaLibrary(const std::filesystem::path& p, std::string_view name);
static pointer create(Session& session, const std::filesystem::path& p = {}, std::string_view name = {});
std::filesystem::path _path;
std::string _name;
std::filesystem::path _path;
std::string _name;
};
} // namespace lms::db
+18 -11
View File
@@ -19,20 +19,23 @@
#pragma once
#include <Wt/WSignal.h>
#include <Wt/Dbo/ptr.h>
#include <Wt/WSignal.h>
#include "database/IdType.hpp"
#include "database/TransactionChecker.hpp"
namespace lms::db
{
template <typename T>
template<typename T>
class ObjectPtr
{
public:
ObjectPtr() = default;
ObjectPtr(const Wt::Dbo::ptr<T>& obj) : _obj{ obj } {}
ObjectPtr(Wt::Dbo::ptr<T>&& obj) : _obj{ std::move(obj) } {}
ObjectPtr(const Wt::Dbo::ptr<T>& obj)
: _obj{ obj } {}
ObjectPtr(Wt::Dbo::ptr<T>&& obj)
: _obj{ std::move(obj) } {}
const T* operator->() const { return _obj.get(); }
operator bool() const { return _obj.get(); }
@@ -60,11 +63,12 @@ namespace lms::db
}
private:
template <typename, typename> friend class Object;
template<typename, typename>
friend class Object;
Wt::Dbo::ptr<T> _obj;
};
template <typename T, typename ObjectIdType>
template<typename T, typename ObjectIdType>
class Object : public Wt::Dbo::Dbo<T>
{
static_assert(std::is_base_of_v<db::IdType, ObjectIdType>);
@@ -80,7 +84,8 @@ namespace lms::db
typename Wt::Dbo::dbo_traits<T>::IdType id() const = delete;
protected:
template <typename> friend class ObjectPtr;
template<typename>
friend class ObjectPtr;
virtual bool hasOnPreRemove() const { return false; }
virtual void onPreRemove() {}
@@ -89,8 +94,10 @@ namespace lms::db
virtual void onPostCreated() {}
// Can get raw dbo ptr only from Objects
template <typename SomeObject>
static
Wt::Dbo::ptr<SomeObject> getDboPtr(ObjectPtr<SomeObject> ptr) { return ptr._obj; }
template<typename SomeObject>
static Wt::Dbo::ptr<SomeObject> getDboPtr(ObjectPtr<SomeObject> ptr)
{
return ptr._obj;
}
};
}
} // namespace lms::db
+105 -68
View File
@@ -26,8 +26,8 @@
#include <string_view>
#include <vector>
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "core/EnumSet.hpp"
#include "core/UUID.hpp"
@@ -54,8 +54,8 @@ namespace lms::db
{
public:
ReleaseType() = default;
static pointer find(Session& session, ReleaseTypeId id);
static pointer find(Session& session, std::string_view name);
static pointer find(Session& session, ReleaseTypeId id);
static pointer find(Session& session, std::string_view name);
// Accessors
std::string_view getName() const { return _name; }
@@ -75,7 +75,7 @@ namespace lms::db
static pointer create(Session& session, std::string_view name);
std::string _name;
Wt::Dbo::collection<Wt::Dbo::ptr<Release>> _releases; // releases that match this type
Wt::Dbo::collection<Wt::Dbo::ptr<Release>> _releases; // releases that match this type
};
class Release final : public Object<Release, ReleaseId>
@@ -83,27 +83,56 @@ namespace lms::db
public:
struct FindParameters
{
std::vector<ClusterId> clusters; // if non empty, releases that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
ReleaseSortMethod sortMethod{ ReleaseSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
std::optional<DateRange> dateRange;
UserId starringUser; // only releases starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this backend
ArtistId artist; // only releases that involved this user
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
core::EnumSet<TrackArtistLinkType> excludedTrackArtistLinkTypes; // but not for these link types
std::string releaseType; // If set, albums that has this release type
MediaLibraryId mediaLibrary; // If set, releases that has at least a track in this library
std::vector<ClusterId> clusters; // if non empty, releases that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
ReleaseSortMethod sortMethod{ ReleaseSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
std::optional<DateRange> dateRange;
UserId starringUser; // only releases starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this backend
ArtistId artist; // only releases that involved this user
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
core::EnumSet<TrackArtistLinkType> excludedTrackArtistLinkTypes; // but not for these link types
std::string releaseType; // If set, albums that has this release type
MediaLibraryId mediaLibrary; // If set, releases that has at least a track in this library
FindParameters& setClusters(std::span<const ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; }
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
FindParameters& setSortMethod(ReleaseSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setWrittenAfter(const Wt::WDateTime& _after) { writtenAfter = _after; return *this; }
FindParameters& setDateRange(const std::optional<DateRange>& _dateRange) { dateRange = _dateRange; return *this; }
FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend) { starringUser = _user; feedbackBackend = _feedbackBackend; return *this; }
FindParameters& setClusters(std::span<const ClusterId> _clusters)
{
clusters.assign(std::cbegin(_clusters), std::cend(_clusters));
return *this;
}
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords)
{
keywords = _keywords;
return *this;
}
FindParameters& setSortMethod(ReleaseSortMethod _sortMethod)
{
sortMethod = _sortMethod;
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
FindParameters& setWrittenAfter(const Wt::WDateTime& _after)
{
writtenAfter = _after;
return *this;
}
FindParameters& setDateRange(const std::optional<DateRange>& _dateRange)
{
dateRange = _dateRange;
return *this;
}
FindParameters& setStarringUser(UserId _user, FeedbackBackend _feedbackBackend)
{
starringUser = _user;
feedbackBackend = _feedbackBackend;
return *this;
}
FindParameters& setArtist(ArtistId _artist, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}, core::EnumSet<TrackArtistLinkType> _excludedTrackArtistLinkTypes = {})
{
artist = _artist;
@@ -111,24 +140,32 @@ namespace lms::db
excludedTrackArtistLinkTypes = _excludedTrackArtistLinkTypes;
return *this;
}
FindParameters& setReleaseType(std::string_view _releaseType) { releaseType = _releaseType; return *this; }
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; }
FindParameters& setReleaseType(std::string_view _releaseType)
{
releaseType = _releaseType;
return *this;
}
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary)
{
mediaLibrary = _mediaLibrary;
return *this;
}
};
Release() = default;
// Accessors
static std::size_t getCount(Session& session);
static bool exists(Session& session, ReleaseId id);
static pointer find(Session& session, const core::UUID& MBID);
static std::vector<pointer> find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory);
static pointer find(Session& session, ReleaseId id);
static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library = {});
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, const std::function<void(const pointer&)>& func);
static RangeResults<ReleaseId> findIds(Session& session, const FindParameters& parameters);
static std::size_t getCount(Session& session, const FindParameters& parameters);
static RangeResults<ReleaseId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // not track related
static std::size_t getCount(Session& session);
static bool exists(Session& session, ReleaseId id);
static pointer find(Session& session, const core::UUID& MBID);
static std::vector<pointer> find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory);
static pointer find(Session& session, ReleaseId id);
static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library = {});
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, const std::function<void(const pointer&)>& func);
static RangeResults<ReleaseId> findIds(Session& session, const FindParameters& parameters);
static std::size_t getCount(Session& session, const FindParameters& parameters);
static RangeResults<ReleaseId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // not track related
// Get the cluster of the tracks that belong to this release
// Each clusters are grouped by cluster type, sorted by the number of occurence (max to min)
@@ -136,28 +173,28 @@ namespace lms::db
std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const;
// Utility functions (if all tracks have the same values, which is legit to not be the case)
Wt::WDate getDate() const;
std::optional<int> getYear() const;
Wt::WDate getOriginalDate() const;
std::optional<int> getOriginalYear() const;
std::optional<std::string> getCopyright() const;
std::optional<std::string> getCopyrightURL() const;
std::size_t getMeanBitrate() const;
Wt::WDate getDate() const;
std::optional<int> getYear() const;
Wt::WDate getOriginalDate() const;
std::optional<int> getOriginalYear() const;
std::optional<std::string> getCopyright() const;
std::optional<std::string> getCopyrightURL() const;
std::size_t getMeanBitrate() const;
// Accessors
std::string_view getName() const { return _name; }
std::string_view getSortName() const { return _sortName; }
std::optional<core::UUID> getMBID() const { return core::UUID::fromString(_MBID); }
std::optional<core::UUID> getGroupMBID() const { return core::UUID::fromString(_groupMBID); }
std::optional<std::size_t> getTotalDisc() const { return _totalDisc; }
std::size_t getDiscCount() const; // may not be total disc (if incomplete for example)
std::vector<DiscInfo> getDiscs() const;
std::chrono::milliseconds getDuration() const;
Wt::WDateTime getLastWritten() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
std::size_t getTrackCount() const;
std::string_view getName() const { return _name; }
std::string_view getSortName() const { return _sortName; }
std::optional<core::UUID> getMBID() const { return core::UUID::fromString(_MBID); }
std::optional<core::UUID> getGroupMBID() const { return core::UUID::fromString(_groupMBID); }
std::optional<std::size_t> getTotalDisc() const { return _totalDisc; }
std::size_t getDiscCount() const; // may not be total disc (if incomplete for example)
std::vector<DiscInfo> getDiscs() const;
std::chrono::milliseconds getDuration() const;
Wt::WDateTime getLastWritten() const;
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
std::size_t getTrackCount() const;
std::vector<ObjectPtr<ReleaseType>> getReleaseTypes() const;
std::vector<std::string> getReleaseTypeNames() const;
std::vector<std::string> getReleaseTypeNames() const;
// Setters
void setName(std::string_view name) { _name = name; }
@@ -170,10 +207,10 @@ namespace lms::db
void addReleaseType(ObjectPtr<ReleaseType> releaseType);
// Get the artists of this release
std::vector<ObjectPtr<Artist>> getArtists(TrackArtistLinkType type = TrackArtistLinkType::Artist) const;
std::vector<ObjectPtr<Artist>> getReleaseArtists() const { return getArtists(TrackArtistLinkType::ReleaseArtist); }
bool hasVariousArtists() const;
std::vector<pointer> getSimilarReleases(std::optional<std::size_t> offset = {}, std::optional<std::size_t> count = {}) const;
std::vector<ObjectPtr<Artist>> getArtists(TrackArtistLinkType type = TrackArtistLinkType::Artist) const;
std::vector<ObjectPtr<Artist>> getReleaseArtists() const { return getArtists(TrackArtistLinkType::ReleaseArtist); }
bool hasVariousArtists() const;
std::vector<pointer> getSimilarReleases(std::optional<std::size_t> offset = {}, std::optional<std::size_t> count = {}) const;
template<class Action>
void persist(Action& a)
@@ -198,15 +235,15 @@ namespace lms::db
static constexpr std::size_t _maxNameLength{ 256 };
std::string _name;
std::string _sortName;
std::string _MBID;
std::string _groupMBID;
std::optional<int> _totalDisc{};
std::string _artistDisplayName;
std::string _name;
std::string _sortName;
std::string _MBID;
std::string _groupMBID;
std::optional<int> _totalDisc{};
std::string _artistDisplayName;
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks; // Tracks in the release
Wt::Dbo::collection<Wt::Dbo::ptr<ReleaseType>> _releaseTypes; // Release types
Wt::Dbo::collection<Wt::Dbo::ptr<Track>> _tracks; // Tracks in the release
Wt::Dbo::collection<Wt::Dbo::ptr<ReleaseType>> _releaseTypes; // Release types
};
} // namespace lms::db
@@ -63,14 +63,14 @@ namespace lms::db
static pointer get(Session& session);
// Getters
std::size_t getScanVersion() const { return _scanVersion; }
Wt::WTime getUpdateStartTime() const { return _startTime; }
UpdatePeriod getUpdatePeriod() const { return _updatePeriod; }
std::vector<std::string_view> getExtraTagsToScan() const;
std::vector<std::filesystem::path> getAudioFileExtensions() const;
SimilarityEngineType getSimilarityEngineType() const { return _similarityEngineType; }
std::vector<std::string> getArtistTagDelimiters() const;
std::vector<std::string> getDefaultTagDelimiters() const;
std::size_t getScanVersion() const { return _scanVersion; }
Wt::WTime getUpdateStartTime() const { return _startTime; }
UpdatePeriod getUpdatePeriod() const { return _updatePeriod; }
std::vector<std::string_view> getExtraTagsToScan() const;
std::vector<std::filesystem::path> getAudioFileExtensions() const;
SimilarityEngineType getSimilarityEngineType() const { return _similarityEngineType; }
std::vector<std::string> getArtistTagDelimiters() const;
std::vector<std::string> getDefaultTagDelimiters() const;
// Setters
void setUpdateStartTime(Wt::WTime t) { _startTime = t; }
@@ -95,13 +95,13 @@ namespace lms::db
}
private:
int _scanVersion{};
Wt::WTime _startTime = Wt::WTime{ 0,0,0 };
UpdatePeriod _updatePeriod{ UpdatePeriod::Never };
SimilarityEngineType _similarityEngineType{ SimilarityEngineType::Clusters };
std::string _audioFileExtensions{ ".alac .mp3 .ogg .oga .aac .m4a .m4b .flac .wav .wma .aif .aiff .ape .mpc .shn .opus .wv .dsf" };
std::string _extraTagsToScan;
std::string _artistTagDelimiters;
std::string _defaultTagDelimiters;
int _scanVersion{};
Wt::WTime _startTime = Wt::WTime{ 0, 0, 0 };
UpdatePeriod _updatePeriod{ UpdatePeriod::Never };
SimilarityEngineType _similarityEngineType{ SimilarityEngineType::Clusters };
std::string _audioFileExtensions{ ".alac .mp3 .ogg .oga .aac .m4a .m4b .flac .wav .wma .aif .aiff .ape .mpc .shn .opus .wv .dsf" };
std::string _extraTagsToScan;
std::string _artistTagDelimiters;
std::string _defaultTagDelimiters;
};
} // namespace lms::db
+11 -4
View File
@@ -24,6 +24,7 @@
#include <string>
#include <vector>
#include "core/ITraceLogger.hpp"
#include "core/RecursiveSharedMutex.hpp"
#include "database/Object.hpp"
@@ -101,10 +102,16 @@ namespace lms::db
void refreshTracingLoggerStats();
// returning a ptr here to ease further wrapping using operator->
Wt::Dbo::Session* getDboSession() { return &_session; }
Db& getDb() { return _db; }
Wt::Dbo::Session* getDboSession()
{
return &_session;
}
Db& getDb()
{
return _db;
}
template <typename Object, typename... Args>
template<typename Object, typename... Args>
typename Object::pointer create(Args&&... args)
{
checkWriteTransaction();
@@ -123,6 +130,6 @@ namespace lms::db
Session& operator=(const Session&) = delete;
Db& _db;
Wt::Dbo::Session _session;
Wt::Dbo::Session _session;
};
} // namespace lms::db
@@ -19,8 +19,8 @@
#pragma once
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "database/ArtistId.hpp"
#include "database/Object.hpp"
@@ -40,17 +40,17 @@ namespace lms::db
StarredArtist() = default;
// Search utility
static std::size_t getCount(Session& session);
static pointer find(Session& session, StarredArtistId id);
static pointer find(Session& session, ArtistId artistId, UserId userId); // current backend
static pointer find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend);
static std::size_t getCount(Session& session);
static pointer find(Session& session, StarredArtistId id);
static pointer find(Session& session, ArtistId artistId, UserId userId); // current backend
static pointer find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend);
// Accessors
ObjectPtr<Artist> getArtist() const { return _artist; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getFeedbackBackend() const { return _backend; }
ObjectPtr<Artist> getArtist() const { return _artist; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getFeedbackBackend() const { return _backend; }
const Wt::WDateTime& getDateTime() const { return _dateTime; }
SyncState getSyncState() const { return _syncState; }
SyncState getSyncState() const { return _syncState; }
// Setters
void setDateTime(const Wt::WDateTime& dateTime);
@@ -72,12 +72,11 @@ namespace lms::db
StarredArtist(ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend scrobblingbackend);
static pointer create(Session& session, ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend scrobblingbackend);
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
Wt::Dbo::ptr<Artist> _artist;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Artist> _artist;
Wt::Dbo::ptr<User> _user;
};
} // namespace lms::db
@@ -19,8 +19,8 @@
#pragma once
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "database/Object.hpp"
#include "database/ReleaseId.hpp"
@@ -47,8 +47,8 @@ namespace lms::db
// Accessors
ObjectPtr<Release> getRelease() const { return _release; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getFeedbackBackend() const { return _backend; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getFeedbackBackend() const { return _backend; }
const Wt::WDateTime& getDateTime() const { return _dateTime; }
SyncState getSyncState() const { return _syncState; }
@@ -72,12 +72,11 @@ namespace lms::db
StarredRelease(ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend);
static pointer create(Session& session, ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend);
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::ptr<User> _user;
};
} // namespace lms::db
@@ -19,13 +19,13 @@
#pragma once
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "core/EnumSet.hpp"
#include "database/TrackId.hpp"
#include "database/Object.hpp"
#include "database/StarredTrackId.hpp"
#include "database/TrackId.hpp"
#include "database/Types.hpp"
#include "database/UserId.hpp"
@@ -42,30 +42,43 @@ namespace lms::db
struct FindParameters
{
std::optional<FeedbackBackend> backend; // for this backend
std::optional<SyncState> syncState; // and these states
UserId user; // and this user
std::optional<Range> range;
std::optional<FeedbackBackend> backend; // for this backend
std::optional<SyncState> syncState; // and these states
UserId user; // and this user
std::optional<Range> range;
FindParameters& setFeedbackBackend(FeedbackBackend _backend, SyncState _syncState) { backend = _backend; syncState = _syncState; return *this; }
FindParameters& setUser(UserId _user) { user = _user; return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setFeedbackBackend(FeedbackBackend _backend, SyncState _syncState)
{
backend = _backend;
syncState = _syncState;
return *this;
}
FindParameters& setUser(UserId _user)
{
user = _user;
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
};
// Search utility
static std::size_t getCount(Session& session);
static pointer find(Session& session, StarredTrackId id);
static pointer find(Session& session, TrackId trackId, UserId userId); // current feedback backend
static pointer find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend);
static bool exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend);
static RangeResults<StarredTrackId> find(Session& session, const FindParameters& findParams);
static std::size_t getCount(Session& session);
static pointer find(Session& session, StarredTrackId id);
static pointer find(Session& session, TrackId trackId, UserId userId); // current feedback backend
static pointer find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend);
static bool exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend);
static RangeResults<StarredTrackId> find(Session& session, const FindParameters& findParams);
// Accessors
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getBackend() const { return _backend; }
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<User> getUser() const { return _user; }
FeedbackBackend getBackend() const { return _backend; }
const Wt::WDateTime& getDateTime() const { return _dateTime; }
SyncState getSyncState() const { return _syncState; }
SyncState getSyncState() const { return _syncState; }
// Setters
void setDateTime(const Wt::WDateTime& dateTime);
@@ -87,12 +100,11 @@ namespace lms::db
StarredTrack(ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend);
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend);
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
FeedbackBackend _backend; // for which backend
SyncState _syncState{ SyncState::PendingAdd };
Wt::WDateTime _dateTime; // when it was starred
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<User> _user;
};
} // namespace lms::db
+181 -114
View File
@@ -21,17 +21,17 @@
#include <chrono>
#include <filesystem>
#include <ostream>
#include <optional>
#include <ostream>
#include <span>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <Wt/WDateTime.h>
#include <Wt/Dbo/Dbo.h>
#include <Wt/Dbo/WtSqlTraits.h>
#include <Wt/WDateTime.h>
#include "core/EnumSet.hpp"
#include "core/UUID.hpp"
@@ -62,67 +62,134 @@ namespace lms::db
public:
struct FindParameters
{
std::vector<ClusterId> clusters; // if non empty, tracks that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::string name; // if non empty, must match this name
TrackSortMethod sortMethod{ TrackSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
UserId starringUser; // only tracks starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this feedback backend
ArtistId artist; // only tracks that involve this artist
std::string artistName; // only tracks that involve this artist name
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
bool nonRelease{}; // only tracks that do not belong to a release
ReleaseId release; // matching this release
std::string releaseName; // matching this release name
TrackListId trackList; // matching this trackList
std::optional<int> trackNumber; // matching this track number
std::optional<int> discNumber; // matching this disc number
MediaLibraryId mediaLibrary; // If set, tracks in this library
std::vector<ClusterId> clusters; // if non empty, tracks that belong to these clusters
std::vector<std::string_view> keywords; // if non empty, name must match all of these keywords
std::string name; // if non empty, must match this name
TrackSortMethod sortMethod{ TrackSortMethod::None };
std::optional<Range> range;
Wt::WDateTime writtenAfter;
UserId starringUser; // only tracks starred by this user
std::optional<FeedbackBackend> feedbackBackend; // and for this feedback backend
ArtistId artist; // only tracks that involve this artist
std::string artistName; // only tracks that involve this artist name
core::EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
bool nonRelease{}; // only tracks that do not belong to a release
ReleaseId release; // matching this release
std::string releaseName; // matching this release name
TrackListId trackList; // matching this trackList
std::optional<int> trackNumber; // matching this track number
std::optional<int> discNumber; // matching this disc number
MediaLibraryId mediaLibrary; // If set, tracks in this library
FindParameters& setClusters(std::span<const ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; }
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords) { keywords = _keywords; return *this; }
FindParameters& setName(std::string_view _name) { name = _name; return *this; }
FindParameters& setSortMethod(TrackSortMethod _method) { sortMethod = _method; return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; 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& setArtist(ArtistId _artist, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artist = _artist; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; }
FindParameters& setArtistName(std::string_view _artistName, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artistName = _artistName; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; }
FindParameters& setNonRelease(bool _nonRelease) { nonRelease = _nonRelease; return *this; }
FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; }
FindParameters& setReleaseName(std::string_view _releaseName) { releaseName = _releaseName; return *this; }
FindParameters& setTrackList(TrackListId _trackList) { trackList = _trackList; return *this; }
FindParameters& setTrackNumber(int _trackNumber) { trackNumber = _trackNumber; return *this; }
FindParameters& setDiscNumber(int _discNumber) { discNumber = _discNumber; return *this; }
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; }
FindParameters& setClusters(std::span<const ClusterId> _clusters)
{
clusters.assign(std::cbegin(_clusters), std::cend(_clusters));
return *this;
}
FindParameters& setKeywords(const std::vector<std::string_view>& _keywords)
{
keywords = _keywords;
return *this;
}
FindParameters& setName(std::string_view _name)
{
name = _name;
return *this;
}
FindParameters& setSortMethod(TrackSortMethod _method)
{
sortMethod = _method;
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
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& setArtist(ArtistId _artist, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {})
{
artist = _artist;
trackArtistLinkTypes = _trackArtistLinkTypes;
return *this;
}
FindParameters& setArtistName(std::string_view _artistName, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {})
{
artistName = _artistName;
trackArtistLinkTypes = _trackArtistLinkTypes;
return *this;
}
FindParameters& setNonRelease(bool _nonRelease)
{
nonRelease = _nonRelease;
return *this;
}
FindParameters& setRelease(ReleaseId _release)
{
release = _release;
return *this;
}
FindParameters& setReleaseName(std::string_view _releaseName)
{
releaseName = _releaseName;
return *this;
}
FindParameters& setTrackList(TrackListId _trackList)
{
trackList = _trackList;
return *this;
}
FindParameters& setTrackNumber(int _trackNumber)
{
trackNumber = _trackNumber;
return *this;
}
FindParameters& setDiscNumber(int _discNumber)
{
discNumber = _discNumber;
return *this;
}
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary)
{
mediaLibrary = _mediaLibrary;
return *this;
}
};
struct PathResult
{
TrackId trackId;
std::filesystem::path path;
TrackId trackId;
std::filesystem::path path;
};
Track() = default;
// Find utility functions
static std::size_t getCount(Session& session);
static pointer findByPath(Session& session, const std::filesystem::path& p);
static pointer find(Session& session, TrackId id);
static void find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library = {});
static bool exists(Session& session, TrackId id);
static std::vector<pointer> findByRecordingMBID(Session& session, const core::UUID& MBID);
static std::vector<pointer> findByMBID(Session& session, const core::UUID& MBID);
static RangeResults<TrackId> findSimilarTrackIds(Session& session, const std::vector<TrackId>& trackIds, std::optional<Range> range = std::nullopt);
static std::size_t getCount(Session& session);
static pointer findByPath(Session& session, const std::filesystem::path& p);
static pointer find(Session& session, TrackId id);
static void find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library = {});
static bool exists(Session& session, TrackId id);
static std::vector<pointer> findByRecordingMBID(Session& session, const core::UUID& MBID);
static std::vector<pointer> findByMBID(Session& session, const core::UUID& MBID);
static RangeResults<TrackId> findSimilarTrackIds(Session& session, const std::vector<TrackId>& trackIds, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, const std::function<void(const Track::pointer&)>& func);
static void find(Session& session, const FindParameters& parameters, bool& moreResults, const std::function<void(const Track::pointer&)>& func);
static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, const std::function<void(const Track::pointer&)>& func);
static void find(Session& session, const FindParameters& parameters, bool& moreResults, const std::function<void(const Track::pointer&)>& func);
static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt);
// Accessors
void setScanVersion(std::size_t version) { _scanVersion = version; }
@@ -159,43 +226,43 @@ namespace lms::db
void setClusters(const std::vector<ObjectPtr<Cluster>>& clusters);
void setMediaLibrary(ObjectPtr<MediaLibrary> mediaLibrary) { _mediaLibrary = getDboPtr(mediaLibrary); }
std::size_t getScanVersion() const { return _scanVersion; }
std::optional<std::size_t> getTrackNumber() const { return _trackNumber; }
std::optional<std::size_t> getTotalTrack() const { return _totalTrack; }
std::optional<std::size_t> getDiscNumber() const { return _discNumber; }
std::size_t getScanVersion() const { return _scanVersion; }
std::optional<std::size_t> getTrackNumber() const { return _trackNumber; }
std::optional<std::size_t> getTotalTrack() const { return _totalTrack; }
std::optional<std::size_t> getDiscNumber() const { return _discNumber; }
const std::string& getDiscSubtitle() const { return _discSubtitle; }
std::string getName() const { return _name; }
std::string getName() const { return _name; }
const std::filesystem::path& getAbsoluteFilePath() const { return _absoluteFilePath; }
const std::filesystem::path& getRelativeFilePath() const { return _relativeFilePath; }
long long getFileSize() const { return _fileSize; }
std::size_t getBitrate() const { return _bitrate; }
std::size_t getBitsPerSample() const { return _bitsPerSample; }
std::size_t getChannelCount() const { return _channelCount; }
std::chrono::milliseconds getDuration() const { return _duration; }
std::size_t getSampleRate() const { return _sampleRate; }
long long getFileSize() const { return _fileSize; }
std::size_t getBitrate() const { return _bitrate; }
std::size_t getBitsPerSample() const { return _bitsPerSample; }
std::size_t getChannelCount() const { return _channelCount; }
std::chrono::milliseconds getDuration() const { return _duration; }
std::size_t getSampleRate() const { return _sampleRate; }
const Wt::WDateTime& getLastWritten() const { return _fileLastWrite; }
const Wt::WDate& getDate() const { return _date; }
std::optional<int> getYear() const { return _year; }
std::optional<int> getYear() const { return _year; }
const Wt::WDate& getOriginalDate() const { return _originalDate; }
std::optional<int> getOriginalYear() const { return _originalYear; };
std::optional<int> getOriginalYear() const { return _originalYear; };
const Wt::WDateTime& getLastWriteTime() const { return _fileLastWrite; }
const Wt::WDateTime& getAddedTime() const { return _fileAdded; }
bool hasCover() const { return _hasCover; }
std::optional<core::UUID> getTrackMBID() const { return core::UUID::fromString(_trackMBID); }
std::optional<core::UUID> getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); }
std::optional<std::string> getCopyright() const;
std::optional<std::string> getCopyrightURL() const;
std::optional<float> getTrackReplayGain() const { return _trackReplayGain; }
std::optional<float> getReleaseReplayGain() const { return _releaseReplayGain; }
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
bool hasCover() const { return _hasCover; }
std::optional<core::UUID> getTrackMBID() const { return core::UUID::fromString(_trackMBID); }
std::optional<core::UUID> getRecordingMBID() const { return core::UUID::fromString(_recordingMBID); }
std::optional<std::string> getCopyright() const;
std::optional<std::string> getCopyrightURL() const;
std::optional<float> getTrackReplayGain() const { return _trackReplayGain; }
std::optional<float> getReleaseReplayGain() const { return _releaseReplayGain; }
std::string_view getArtistDisplayName() const { return _artistDisplayName; }
// no artistLinkTypes means get all
std::vector<ObjectPtr<Artist>> getArtists(core::EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means all
std::vector<ArtistId> getArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means all
std::vector<ObjectPtr<TrackArtistLink>> getArtistLinks() const;
ObjectPtr<Release> getRelease() const { return _release; }
std::vector<ObjectPtr<Cluster>> getClusters() const;
std::vector<ClusterId> getClusterIds() const;
ObjectPtr<MediaLibrary> getMediaLibrary() const { return _mediaLibrary; }
std::vector<ObjectPtr<Artist>> getArtists(core::EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means all
std::vector<ArtistId> getArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means all
std::vector<ObjectPtr<TrackArtistLink>> getArtistLinks() const;
ObjectPtr<Release> getRelease() const { return _release; }
std::vector<ObjectPtr<Cluster>> getClusters() const;
std::vector<ClusterId> getClusterIds() const;
ObjectPtr<MediaLibrary> getMediaLibrary() const { return _mediaLibrary; }
std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(const std::vector<ClusterTypeId>& clusterTypes, std::size_t size) const;
@@ -205,7 +272,7 @@ namespace lms::db
Wt::Dbo::field(a, _scanVersion, "scan_version");
Wt::Dbo::field(a, _trackNumber, "track_number");
Wt::Dbo::field(a, _discNumber, "disc_number");
Wt::Dbo::field(a, _totalTrack, "total_track"); // here in Track since Release does not have concept of "disc" (yet?)
Wt::Dbo::field(a, _totalTrack, "total_track"); // here in Track since Release does not have concept of "disc" (yet?)
Wt::Dbo::field(a, _discSubtitle, "disc_subtitle"); // here in Track since Release does not have concept of "disc" (yet?)
Wt::Dbo::field(a, _name, "name");
Wt::Dbo::field(a, _duration, "duration");
@@ -244,39 +311,39 @@ namespace lms::db
static constexpr std::size_t _maxCopyrightLength{ 256 };
static constexpr std::size_t _maxCopyrightURLLength{ 256 };
int _scanVersion{};
std::optional<int> _trackNumber{};
std::optional<int> _discNumber{};
std::optional<int> _totalTrack{};
std::string _discSubtitle;
std::string _name;
int _bitrate{}; // in bps
int _bitsPerSample{};
int _channelCount{};
std::chrono::duration<int, std::milli> _duration{};
int _sampleRate{};
Wt::WDate _date;
std::optional<int> _year;
Wt::WDate _originalDate;
std::optional<int> _originalYear;
std::filesystem::path _absoluteFilePath; // full path
std::filesystem::path _relativeFilePath; // relative to root (that may be deleted)
long long _fileSize{};
Wt::WDateTime _fileLastWrite;
Wt::WDateTime _fileAdded;
bool _hasCover{};
std::string _trackMBID;
std::string _recordingMBID;
std::string _copyright;
std::string _copyrightURL;
std::optional<float> _trackReplayGain;
std::optional<float> _releaseReplayGain;
std::string _artistDisplayName;
int _scanVersion{};
std::optional<int> _trackNumber{};
std::optional<int> _discNumber{};
std::optional<int> _totalTrack{};
std::string _discSubtitle;
std::string _name;
int _bitrate{}; // in bps
int _bitsPerSample{};
int _channelCount{};
std::chrono::duration<int, std::milli> _duration{};
int _sampleRate{};
Wt::WDate _date;
std::optional<int> _year;
Wt::WDate _originalDate;
std::optional<int> _originalYear;
std::filesystem::path _absoluteFilePath; // full path
std::filesystem::path _relativeFilePath; // relative to root (that may be deleted)
long long _fileSize{};
Wt::WDateTime _fileLastWrite;
Wt::WDateTime _fileAdded;
bool _hasCover{};
std::string _trackMBID;
std::string _recordingMBID;
std::string _copyright;
std::string _copyrightURL;
std::optional<float> _trackReplayGain;
std::optional<float> _releaseReplayGain;
std::string _artistDisplayName;
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::ptr<MediaLibrary> _mediaLibrary;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::ptr<MediaLibrary> _mediaLibrary;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks;
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> _clusters;
};
namespace Debug
@@ -287,5 +354,5 @@ namespace lms::db
TrackId trackId;
};
std::ostream& operator<<(std::ostream& os, const TrackInfo& trackInfo);
}
} // namespace Debug
} // namespace lms::db
@@ -46,32 +46,52 @@ namespace lms::db
public:
struct FindParameters
{
std::optional<Range> range;
std::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
ArtistId artist; // if set, links involved with this artist
ReleaseId release; // if set, artists involved in this release
TrackId track; // if set, artists involved in this track
std::optional<Range> range;
std::optional<TrackArtistLinkType> linkType; // if set, only artists that have produced at least one track with this link type
ArtistId artist; // if set, links involved with this artist
ReleaseId release; // if set, artists involved in this release
TrackId track; // if set, artists involved in this track
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType) { linkType = _linkType; return *this; }
FindParameters& setArtist(ArtistId _artist) { artist = _artist; return *this; }
FindParameters& setRelease(ReleaseId _release) { release = _release; return *this; }
FindParameters& setTrack(TrackId _track) { track = _track; return *this; }
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
FindParameters& setLinkType(std::optional<TrackArtistLinkType> _linkType)
{
linkType = _linkType;
return *this;
}
FindParameters& setArtist(ArtistId _artist)
{
artist = _artist;
return *this;
}
FindParameters& setRelease(ReleaseId _release)
{
release = _release;
return *this;
}
FindParameters& setTrack(TrackId _track)
{
track = _track;
return *this;
}
};
TrackArtistLink() = default;
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 pointer find(Session& session, TrackArtistLinkId linkId);
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType = {});
static core::EnumSet<TrackArtistLinkType> findUsedTypes(Session& session, ArtistId _artist);
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 pointer find(Session& session, TrackArtistLinkId linkId);
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType = {});
static core::EnumSet<TrackArtistLinkType> findUsedTypes(Session& session, ArtistId _artist);
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<Artist> getArtist() const { return _artist; }
TrackArtistLinkType getType() const { return _type; }
std::string_view getSubType() const { return _subType; }
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<Artist> getArtist() const { return _artist; }
TrackArtistLinkType getType() const { return _type; }
std::string_view getSubType() const { return _subType; }
template<class Action>
void persist(Action& a)
@@ -90,5 +110,4 @@ namespace lms::db
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<Artist> _artist;
};
}
} // namespace lms::db
@@ -44,20 +44,20 @@ namespace lms::db
TrackBookmark() = default;
// Find utility functions
static std::size_t getCount(Session& session);
static pointer find(Session& session, TrackBookmarkId id);
static RangeResults<TrackBookmarkId> find(Session& session, UserId userId, std::optional<Range> range = std::nullopt);
static pointer find(Session& session, UserId userId, TrackId trackId);
static std::size_t getCount(Session& session);
static pointer find(Session& session, TrackBookmarkId id);
static RangeResults<TrackBookmarkId> find(Session& session, UserId userId, std::optional<Range> range = std::nullopt);
static pointer find(Session& session, UserId userId, TrackId trackId);
// Setters
void setOffset(std::chrono::milliseconds offset) { _offset = offset; }
void setComment(std::string_view comment) { _comment = comment; }
// Getters
std::chrono::milliseconds getOffset() const { return _offset; }
std::string_view getComment() const { return _comment; }
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<User> getUser() const { return _user; }
std::chrono::milliseconds getOffset() const { return _offset; }
std::string_view getComment() const { return _comment; }
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<User> getUser() const { return _user; }
template<class Action>
void persist(Action& a)
@@ -75,11 +75,11 @@ namespace lms::db
static const std::size_t _maxCommentLength = 128;
std::chrono::duration<int, std::milli> _offset;
std::string _comment;
std::chrono::duration<int, std::milli> _offset;
std::string _comment;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<Track> _track;
};
} // namespace lms::db
@@ -49,13 +49,13 @@ namespace lms::db
TrackFeatures() = default;
// Find utilities
static std::size_t getCount(Session& session);
static pointer find(Session& session, TrackFeaturesId id);
static pointer find(Session& session, TrackId trackId);
static RangeResults<TrackFeaturesId> find(Session& session, std::optional<Range> range = std::nullopt);
static std::size_t getCount(Session& session);
static pointer find(Session& session, TrackFeaturesId id);
static pointer find(Session& session, TrackId trackId);
static RangeResults<TrackFeaturesId> find(Session& session, std::optional<Range> range = std::nullopt);
FeatureValues getFeatureValues(const FeatureName& feature) const;
FeatureValuesMap getFeatureValuesMap(const std::unordered_set<FeatureName>& featureNames) const;
FeatureValues getFeatureValues(const FeatureName& feature) const;
FeatureValuesMap getFeatureValuesMap(const std::unordered_set<FeatureName>& featureNames) const;
// Accessors
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
@@ -55,48 +55,72 @@ namespace lms::db
// Search utility
struct FindParameters
{
std::vector<ClusterId> clusters; // if non empty, tracklists that have tracks that belong to these clusters
std::optional<Range> range;
std::optional<TrackListType> type;
UserId user; // only tracklists owned by this user
MediaLibraryId mediaLibrary; // only tracklists that have songs in this media library
TrackListSortMethod sortMethod{ TrackListSortMethod::None };
std::vector<ClusterId> clusters; // if non empty, tracklists that have tracks that belong to these clusters
std::optional<Range> range;
std::optional<TrackListType> type;
UserId user; // only tracklists owned by this user
MediaLibraryId mediaLibrary; // only tracklists that have songs in this media library
TrackListSortMethod sortMethod{ TrackListSortMethod::None };
FindParameters& setClusters(std::span<const ClusterId> _clusters) { clusters.assign(std::cbegin(_clusters), std::cend(_clusters)); return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setType(TrackListType _type) { type = _type; return *this; }
FindParameters& setUser(UserId _user) { user = _user; return *this; }
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary) { mediaLibrary = _mediaLibrary; return *this; }
FindParameters& setSortMethod(TrackListSortMethod _sortMethod) { sortMethod = _sortMethod; return *this; }
FindParameters& setClusters(std::span<const ClusterId> _clusters)
{
clusters.assign(std::cbegin(_clusters), std::cend(_clusters));
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
FindParameters& setType(TrackListType _type)
{
type = _type;
return *this;
}
FindParameters& setUser(UserId _user)
{
user = _user;
return *this;
}
FindParameters& setMediaLibrary(MediaLibraryId _mediaLibrary)
{
mediaLibrary = _mediaLibrary;
return *this;
}
FindParameters& setSortMethod(TrackListSortMethod _sortMethod)
{
sortMethod = _sortMethod;
return *this;
}
};
static std::size_t getCount(Session& session);
static pointer find(Session& session, std::string_view name, TrackListType type, UserId userId);
static pointer find(Session& session, TrackListId tracklistId);
static RangeResults<TrackListId> find(Session& session, const FindParameters& params);
static void find(Session& session, const FindParameters& params, const std::function<void(const TrackList::pointer&)>& func);
static std::size_t getCount(Session& session);
static pointer find(Session& session, std::string_view name, TrackListType type, UserId userId);
static pointer find(Session& session, TrackListId tracklistId);
static RangeResults<TrackListId> find(Session& session, const FindParameters& params);
static void find(Session& session, const FindParameters& params, const std::function<void(const TrackList::pointer&)>& func);
// Accessors
std::string_view getName() const { return _name; }
bool isPublic() const { return _isPublic; }
TrackListType getType() const { return _type; }
ObjectPtr<User> getUser() const { return _user; }
std::string_view getName() const { return _name; }
bool isPublic() const { return _isPublic; }
TrackListType getType() const { return _type; }
ObjectPtr<User> getUser() const { return _user; }
// Modifiers
void setName(const std::string& name) { _name = name; }
void setIsPublic(bool isPublic) { _isPublic = isPublic; }
void clear() { _entries.clear(); }
void setName(const std::string& name) { _name = name; }
void setIsPublic(bool isPublic) { _isPublic = isPublic; }
void clear() { _entries.clear(); }
// Get tracks, ordered by position
bool isEmpty() const;
std::size_t getCount() const;
ObjectPtr<TrackListEntry> getEntry(std::size_t pos) const;
RangeResults<ObjectPtr<TrackListEntry>> getEntries(std::optional<Range> range = {}) const;
ObjectPtr<TrackListEntry> getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const;
bool isEmpty() const;
std::size_t getCount() const;
ObjectPtr<TrackListEntry> getEntry(std::size_t pos) const;
RangeResults<ObjectPtr<TrackListEntry>> getEntries(std::optional<Range> range = {}) const;
ObjectPtr<TrackListEntry> getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const;
std::vector<TrackId> getTrackIds() const;
std::chrono::milliseconds getDuration() const;
std::vector<TrackId> getTrackIds() const;
std::chrono::milliseconds getDuration() const;
void setLastModifiedDateTime(const Wt::WDateTime& dateTime);
void setLastModifiedDateTime(const Wt::WDateTime& dateTime);
// Get clusters, order by occurence
std::vector<ObjectPtr<Cluster>> getClusters() const;
@@ -123,13 +147,13 @@ namespace lms::db
TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user);
static pointer create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user);
std::string _name;
TrackListType _type{ TrackListType::Playlist };
bool _isPublic{ false };
Wt::WDateTime _creationDateTime;
Wt::WDateTime _lastModifiedDateTime;
std::string _name;
TrackListType _type{ TrackListType::Playlist };
bool _isPublic{ false };
Wt::WDateTime _creationDateTime;
Wt::WDateTime _lastModifiedDateTime;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::ptr<User> _user;
Wt::Dbo::collection<Wt::Dbo::ptr<TrackListEntry>> _entries;
};
@@ -148,7 +172,7 @@ namespace lms::db
static pointer getById(Session& session, TrackListEntryId id);
// Accessors
ObjectPtr<Track> getTrack() const { return _track; }
ObjectPtr<Track> getTrack() const { return _track; }
const Wt::WDateTime& getDateTime() const { return _dateTime; }
template<class Action>
@@ -166,10 +190,9 @@ namespace lms::db
TrackListEntry(ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist);
static pointer create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime = {});
Wt::WDateTime _dateTime; // optional date time
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<TrackList> _tracklist;
Wt::WDateTime _dateTime; // optional date time
Wt::Dbo::ptr<Track> _track;
Wt::Dbo::ptr<TrackList> _tracklist;
};
} // namespace lms::db
@@ -20,15 +20,14 @@
#pragma once
#if !defined(NDEBUG)
#define LMS_CHECK_TRANSACTION_ACCESSES 1
#define LMS_CHECK_TRANSACTION_ACCESSES 1
#else
#define LMS_CHECK_TRANSACTION_ACCESSES 0
#define LMS_CHECK_TRANSACTION_ACCESSES 0
#endif
#if LMS_CHECK_TRANSACTION_ACCESSES
#include <vector>
#include <Wt/Dbo/Session.h>
#include <Wt/Dbo/Session.h>
#include <vector>
namespace lms::db
{
@@ -58,6 +57,6 @@ namespace lms::db
static void pushTransaction(TransactionType type, Wt::Dbo::Session& session);
static void popTransaction(TransactionType type, Wt::Dbo::Session& session);
};
}
} // namespace lms::db
#endif
+9 -9
View File
@@ -19,9 +19,10 @@
#pragma once
#include <cstdint>
#include <cassert>
#include <cstdint>
#include <functional>
#include <Wt/WDate.h>
namespace lms::db
@@ -41,7 +42,7 @@ namespace lms::db
};
// Func must return true to continue iterating
template <typename Func>
template<typename Func>
void foreachSubRange(Range range, std::size_t subRangeSize, Func&& func)
{
assert(subRangeSize > 0);
@@ -57,7 +58,7 @@ namespace lms::db
}
}
template <typename T>
template<typename T>
struct RangeResults
{
Range range;
@@ -152,13 +153,13 @@ namespace lms::db
StarredDateDesc,
Name,
DateDescAndRelease,
Release, // order by disc/track number
Release, // order by disc/track number
TrackList, // order by asc order in tracklist
};
enum class TrackArtistLinkType
{
Artist = 0, // regular track artist
Artist = 0, // regular track artist
Arranger = 1,
Composer = 2,
Conductor = 3,
@@ -227,8 +228,7 @@ namespace lms::db
enum class TrackListType
{
Playlist, // user controlled playlists
Internal, // internal usage (current playqueue, history, ...)
Playlist, // user controlled playlists
Internal, // internal usage (current playqueue, history, ...)
};
}
} // namespace lms::db
+64 -48
View File
@@ -47,43 +47,59 @@ namespace lms::db
struct FindParameters
{
std::optional<ScrobblingBackend> scrobblingBackend;
std::optional<FeedbackBackend> feedbackBackend;
std::optional<Range> range;
std::optional<ScrobblingBackend> scrobblingBackend;
std::optional<FeedbackBackend> feedbackBackend;
std::optional<Range> range;
FindParameters& setFeedbackBackend(FeedbackBackend _feedbackBackend) { feedbackBackend = _feedbackBackend; return *this; }
FindParameters& setScrobblingBackend(ScrobblingBackend _scrobblingBackend) { scrobblingBackend = _scrobblingBackend; return *this; }
FindParameters& setRange(std::optional<Range> _range) { range = _range; return *this; }
FindParameters& setFeedbackBackend(FeedbackBackend _feedbackBackend)
{
feedbackBackend = _feedbackBackend;
return *this;
}
FindParameters& setScrobblingBackend(ScrobblingBackend _scrobblingBackend)
{
scrobblingBackend = _scrobblingBackend;
return *this;
}
FindParameters& setRange(std::optional<Range> _range)
{
range = _range;
return *this;
}
};
static inline constexpr std::size_t MinNameLength{ 3 };
static inline constexpr std::size_t MaxNameLength{ 15 };
static inline constexpr bool defaultSubsonicEnableTranscodingByDefault{ false };
static inline constexpr std::size_t MinNameLength{ 3 };
static inline constexpr std::size_t MaxNameLength{ 15 };
static inline constexpr bool defaultSubsonicEnableTranscodingByDefault{ false };
static inline constexpr TranscodingOutputFormat defaultSubsonicTranscodingOutputFormat{ TranscodingOutputFormat::OGG_OPUS };
static inline constexpr Bitrate defaultSubsonicTranscodingOutputBitrate{ 128000 };
static inline constexpr UITheme defaultUITheme{ UITheme::Dark };
static inline constexpr SubsonicArtistListMode defaultSubsonicArtistListMode{ SubsonicArtistListMode::AllArtists };
static inline constexpr ScrobblingBackend defaultScrobblingBackend{ ScrobblingBackend::Internal };
static inline constexpr FeedbackBackend defaultFeedbackBackend{ FeedbackBackend::Internal };
static inline constexpr Bitrate defaultSubsonicTranscodingOutputBitrate{ 128000 };
static inline constexpr UITheme defaultUITheme{ UITheme::Dark };
static inline constexpr SubsonicArtistListMode defaultSubsonicArtistListMode{ SubsonicArtistListMode::AllArtists };
static inline constexpr ScrobblingBackend defaultScrobblingBackend{ ScrobblingBackend::Internal };
static inline constexpr FeedbackBackend defaultFeedbackBackend{ FeedbackBackend::Internal };
User() = default;
static std::size_t getCount(Session& session);
static pointer find(Session& session, UserId id);
static pointer find(Session& session, std::string_view loginName);
static std::size_t getCount(Session& session);
static pointer find(Session& session, UserId id);
static pointer find(Session& session, std::string_view loginName);
static RangeResults<UserId> find(Session& session, const FindParameters& params);
static void find(Session& session, const FindParameters& params, const std::function<void(const pointer&)>& func);
static pointer findDemoUser(Session& session);
static void find(Session& session, const FindParameters& params, const std::function<void(const pointer&)>& func);
static pointer findDemoUser(Session& session);
// accessors
const std::string& getLoginName() const { return _loginName; }
PasswordHash getPasswordHash() const { return PasswordHash{ _passwordSalt, _passwordHash }; }
PasswordHash getPasswordHash() const { return PasswordHash{ _passwordSalt, _passwordHash }; }
const Wt::WDateTime& getLastLogin() const { return _lastLogin; }
std::size_t getAuthTokensCount() const { return _authTokens.size(); }
std::size_t getAuthTokensCount() const { return _authTokens.size(); }
// write
void setLastLogin(const Wt::WDateTime& dateTime) { _lastLogin = dateTime; }
void setPasswordHash(const PasswordHash& passwordHash) { _passwordSalt = passwordHash.salt; _passwordHash = passwordHash.hash; }
void setPasswordHash(const PasswordHash& passwordHash)
{
_passwordSalt = passwordHash.salt;
_passwordHash = passwordHash.hash;
}
void setType(UserType type) { _type = type; }
void setSubsonicEnableTranscodingByDefault(bool value) { _subsonicEnableTranscodingByDefault = value; }
void setSubsonicDefaultTranscodintOutputFormat(TranscodingOutputFormat encoding) { _subsonicDefaultTranscodingOutputFormat = encoding; }
@@ -99,19 +115,19 @@ namespace lms::db
void setListenBrainzToken(const std::optional<core::UUID>& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; }
// read
bool isAdmin() const { return _type == UserType::ADMIN; }
bool isDemo() const { return _type == UserType::DEMO; }
UserType getType() const { return _type; }
bool getSubsonicEnableTranscodingByDefault() const { return _subsonicEnableTranscodingByDefault; }
bool isAdmin() const { return _type == UserType::ADMIN; }
bool isDemo() const { return _type == UserType::DEMO; }
UserType getType() const { return _type; }
bool getSubsonicEnableTranscodingByDefault() const { return _subsonicEnableTranscodingByDefault; }
TranscodingOutputFormat getSubsonicDefaultTranscodingOutputFormat() const { return _subsonicDefaultTranscodingOutputFormat; }
Bitrate getSubsonicDefaultTranscodingOutputBitrate() const { return _subsonicDefaultTranscodingOutputBitrate; }
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
bool isRepeatAllSet() const { return _repeatAll; }
bool isRadioSet() const { return _radio; }
UITheme getUITheme() const { return _uiTheme; }
SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; }
FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; }
ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; }
Bitrate getSubsonicDefaultTranscodingOutputBitrate() const { return _subsonicDefaultTranscodingOutputBitrate; }
std::size_t getCurPlayingTrackPos() const { return _curPlayingTrackPos; }
bool isRepeatAllSet() const { return _repeatAll; }
bool isRadioSet() const { return _radio; }
UITheme getUITheme() const { return _uiTheme; }
SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; }
FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; }
ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; }
std::optional<core::UUID> getListenBrainzToken() const { return core::UUID::fromString(_listenbrainzToken); }
template<class Action>
@@ -144,30 +160,30 @@ namespace lms::db
User(std::string_view loginName);
static pointer create(Session& session, std::string_view loginName);
std::string _loginName;
std::string _passwordSalt;
std::string _passwordHash;
Wt::WDateTime _lastLogin;
UITheme _uiTheme{ defaultUITheme };
std::string _loginName;
std::string _passwordSalt;
std::string _passwordHash;
Wt::WDateTime _lastLogin;
UITheme _uiTheme{ defaultUITheme };
FeedbackBackend _feedbackBackend{ defaultFeedbackBackend };
ScrobblingBackend _scrobblingBackend{ defaultScrobblingBackend };
std::string _listenbrainzToken; // Musicbrainz Identifier
std::string _listenbrainzToken; // Musicbrainz Identifier
// Admin defined settings
UserType _type{ UserType::REGULAR };
UserType _type{ UserType::REGULAR };
// User defined settings
SubsonicArtistListMode _subsonicArtistListMode{ defaultSubsonicArtistListMode };
bool _subsonicEnableTranscodingByDefault{ defaultSubsonicEnableTranscodingByDefault };
SubsonicArtistListMode _subsonicArtistListMode{ defaultSubsonicArtistListMode };
bool _subsonicEnableTranscodingByDefault{ defaultSubsonicEnableTranscodingByDefault };
TranscodingOutputFormat _subsonicDefaultTranscodingOutputFormat{ defaultSubsonicTranscodingOutputFormat };
int _subsonicDefaultTranscodingOutputBitrate{ defaultSubsonicTranscodingOutputBitrate };
int _subsonicDefaultTranscodingOutputBitrate{ defaultSubsonicTranscodingOutputBitrate };
// User's dynamic data (UI)
int _curPlayingTrackPos{}; // Current track position in queue
bool _repeatAll{};
bool _radio{};
int _curPlayingTrackPos{}; // Current track position in queue
bool _repeatAll{};
bool _radio{};
Wt::Dbo::collection<Wt::Dbo::ptr<AuthToken>> _authTokens;
};
} // namespace Databas'
} // namespace lms::db
+63 -70
View File
@@ -47,7 +47,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
@@ -59,7 +59,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}) };
auto artists{ Artist::find(session, Artist::FindParameters{}) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front()->getId(), artist.getId());
}
@@ -68,11 +68,10 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
bool visited{};
Artist::find(session, Artist::FindParameters{}, [&](const Artist::pointer& a)
{
visited = true;
EXPECT_EQ(a->getId(), artist.getId());
});
Artist::find(session, Artist::FindParameters{}, [&](const Artist::pointer& a) {
visited = true;
EXPECT_EQ(a->getId(), artist.getId());
});
EXPECT_TRUE(visited);
}
}
@@ -104,10 +103,9 @@ namespace lms::db::tests
ArtistId lastRetrievedId;
std::vector<Artist::pointer> visitedArtists;
Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist)
{
visitedArtists.push_back(artist);
});
Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist) {
visitedArtists.push_back(artist);
});
ASSERT_EQ(visitedArtists.size(), 3);
EXPECT_EQ(visitedArtists[0]->getId(), artist1.getId());
EXPECT_EQ(visitedArtists[1]->getId(), artist2.getId());
@@ -120,10 +118,9 @@ namespace lms::db::tests
ArtistId lastRetrievedId{ artist1.getId() };
std::vector<Artist::pointer> visitedArtists;
Artist::find(session, lastRetrievedId, 1, [&](const Artist::pointer& artist)
{
visitedArtists.push_back(artist);
});
Artist::find(session, lastRetrievedId, 1, [&](const Artist::pointer& artist) {
visitedArtists.push_back(artist);
});
ASSERT_EQ(visitedArtists.size(), 1);
EXPECT_EQ(visitedArtists[0]->getId(), artist2.getId());
EXPECT_EQ(lastRetrievedId, artist2.getId());
@@ -134,10 +131,9 @@ namespace lms::db::tests
ArtistId lastRetrievedId{ artist1.getId() };
std::vector<Artist::pointer> visitedArtists;
Artist::find(session, lastRetrievedId, 0, [&](const Artist::pointer& artist)
{
visitedArtists.push_back(artist);
});
Artist::find(session, lastRetrievedId, 0, [&](const Artist::pointer& artist) {
visitedArtists.push_back(artist);
});
ASSERT_EQ(visitedArtists.size(), 0);
EXPECT_EQ(lastRetrievedId, artist1.getId());
}
@@ -147,10 +143,11 @@ namespace lms::db::tests
ArtistId lastRetrievedId;
std::vector<Artist::pointer> visitedArtists;
Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist)
{
Artist::find(
session, lastRetrievedId, 10, [&](const Artist::pointer& artist) {
visitedArtists.push_back(artist);
}, otherLibrary.getId());
},
otherLibrary.getId());
ASSERT_EQ(visitedArtists.size(), 0);
EXPECT_EQ(lastRetrievedId, ArtistId{});
}
@@ -160,10 +157,11 @@ namespace lms::db::tests
ArtistId lastRetrievedId;
std::vector<Artist::pointer> visitedArtists;
Artist::find(session, lastRetrievedId, 10, [&](const Artist::pointer& artist)
{
Artist::find(
session, lastRetrievedId, 10, [&](const Artist::pointer& artist) {
visitedArtists.push_back(artist);
}, library.getId());
},
library.getId());
ASSERT_EQ(visitedArtists.size(), 1);
EXPECT_EQ(visitedArtists[0]->getId(), artist2.getId());
EXPECT_EQ(lastRetrievedId, artist2.getId());
@@ -175,7 +173,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
ASSERT_EQ(artists.results.size(), 0);
ASSERT_FALSE(artists.moreResults);
ASSERT_EQ(artists.range.offset, 0);
@@ -199,7 +197,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{0,1})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 0, 1 })) };
ASSERT_EQ(artists.results.size(), 1);
ASSERT_TRUE(artists.moreResults);
ASSERT_EQ(artists.range.offset, 0);
@@ -210,7 +208,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{1,1})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 1, 1 })) };
ASSERT_EQ(artists.results.size(), 1);
ASSERT_TRUE(artists.moreResults);
ASSERT_EQ(artists.range.offset, 1);
@@ -221,7 +219,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{2,1})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRange(Range{ 2, 1 })) };
ASSERT_EQ(artists.results.size(), 1);
ASSERT_FALSE(artists.moreResults);
ASSERT_EQ(artists.range.offset, 2);
@@ -250,7 +248,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) };
ASSERT_EQ(artists.size(), 1);
EXPECT_EQ(artists.front()->getId(), artist.getId());
@@ -267,7 +265,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ track->getArtistIds({TrackArtistLinkType::Artist}) };
auto artists{ track->getArtistIds({ TrackArtistLinkType::Artist }) };
ASSERT_EQ(artists.size(), 1);
EXPECT_EQ(artists.front(), artist.getId());
@@ -362,7 +360,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) };
ASSERT_EQ(artists.size(), 1);
EXPECT_EQ(artists.front()->getId(), artist.getId());
@@ -372,7 +370,7 @@ namespace lms::db::tests
EXPECT_EQ(track->getArtistLinks().size(), 3);
auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId())) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId())) };
EXPECT_EQ(tracks.results.size(), 1);
tracks = Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::ReleaseArtist }));
@@ -399,19 +397,17 @@ namespace lms::db::tests
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);
});
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;});
};
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));
@@ -441,10 +437,10 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ track->getArtists({TrackArtistLinkType::Artist}) };
auto artists{ track->getArtists({ TrackArtistLinkType::Artist }) };
ASSERT_EQ(artists.size(), 2);
EXPECT_TRUE((artists[0]->getId() == artist1.getId() && artists[1]->getId() == artist2.getId())
|| (artists[0]->getId() == artist2.getId() && artists[1]->getId() == artist1.getId()));
|| (artists[0]->getId() == artist2.getId() && artists[1]->getId() == artist1.getId()));
EXPECT_EQ(track->getArtists({}).size(), 2);
EXPECT_EQ(track->getArtists({ TrackArtistLinkType::Artist }).size(), 2);
@@ -456,7 +452,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist1->getId())) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist1->getId())) };
ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track->getId());
@@ -481,10 +477,9 @@ namespace lms::db::tests
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);
});
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());
@@ -494,10 +489,9 @@ namespace lms::db::tests
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);
});
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());
@@ -507,10 +501,9 @@ namespace lms::db::tests
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));
});
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());
@@ -535,11 +528,11 @@ namespace lms::db::tests
EXPECT_EQ(Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "N" })).results.size(), 0);
const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"A"})) };
const auto artistsByAAA{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "A" })) };
ASSERT_EQ(artistsByAAA.results.size(), 1);
EXPECT_EQ(artistsByAAA.results.front(), artist.getId());
const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters {}.setKeywords({"Z"})) };
const auto artistsByZZZ{ Artist::Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "Z" })) };
ASSERT_EQ(artistsByZZZ.results.size(), 1);
EXPECT_EQ(artistsByZZZ.results.front(), artist.getId());
@@ -583,26 +576,26 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
{
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist"})) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "MyArtist" })) };
EXPECT_EQ(artists.results.size(), 6);
}
{
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"MyArtist%"}).setSortMethod(ArtistSortMethod::Name)) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "MyArtist%" }).setSortMethod(ArtistSortMethod::Name)) };
ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], artist1.getId());
EXPECT_EQ(artists.results[1], artist4.getId());
}
{
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"%MyArtist"}).setSortMethod(ArtistSortMethod::Name)) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "%MyArtist" }).setSortMethod(ArtistSortMethod::Name)) };
ASSERT_EQ(artists.results.size(), 2);
EXPECT_EQ(artists.results[0], artist2.getId());
EXPECT_EQ(artists.results[1], artist5.getId());
}
{
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setKeywords({"_MyArtist"}).setSortMethod(ArtistSortMethod::Name)) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setKeywords({ "_MyArtist" }).setSortMethod(ArtistSortMethod::Name)) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results[0], artist3.getId());
}
@@ -624,8 +617,8 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::Name)) };
auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters {}.setSortMethod(ArtistSortMethod::SortName)) };
auto allArtistsByName{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::Name)) };
auto allArtistsBySortName{ Artist::findIds(session, Artist::FindParameters{}.setSortMethod(ArtistSortMethod::SortName)) };
ASSERT_EQ(allArtistsByName.results.size(), 2);
EXPECT_EQ(allArtistsByName.results.front(), artistA.getId());
@@ -647,7 +640,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setNonRelease(true).setArtist(artist->getId())) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setNonRelease(true).setArtist(artist->getId())) };
EXPECT_EQ(tracks.results.size(), 0);
}
@@ -663,7 +656,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setArtist(artist.getId()).setNonRelease(true)) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setArtist(artist.getId()).setNonRelease(true)) };
ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track2.getId());
}
@@ -677,7 +670,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) };
EXPECT_EQ(artists.results.size(), 0);
}
@@ -688,7 +681,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) };
EXPECT_EQ(artists.results.size(), 0);
}
@@ -699,9 +692,9 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto artists{ Artist::findIds(session, Artist::FindParameters {}.setRelease(release.getId())) };
const auto artists{ Artist::findIds(session, Artist::FindParameters{}.setRelease(release.getId())) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
}
}
} // namespace lms::db::tests
+26 -29
View File
@@ -49,7 +49,7 @@ namespace lms::db::tests
EXPECT_EQ(cluster->getType()->getId(), clusterType.getId());
{
const auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}) };
const auto clusters{ Cluster::findIds(session, Cluster::FindParameters{}) };
ASSERT_EQ(clusters.results.size(), 1);
EXPECT_EQ(clusters.results.front(), cluster.getId());
}
@@ -118,7 +118,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto clusters{ Cluster::findIds(session, Cluster::FindParameters {}.setTrack(track.getId())) };
auto clusters{ Cluster::findIds(session, Cluster::FindParameters{}.setTrack(track.getId())) };
ASSERT_EQ(clusters.results.size(), 1);
EXPECT_EQ(clusters.results.front(), cluster1.getId());
EXPECT_EQ(Cluster::computeTrackCount(session, cluster1.getId()), 1);
@@ -137,7 +137,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster1.getId()})) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster1.getId() })) };
ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track.getId());
@@ -243,10 +243,9 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
bool visited{};
ClusterType::find(session, [&](const ClusterType::pointer&)
{
visited = true;
});
ClusterType::find(session, [&](const ClusterType::pointer&) {
visited = true;
});
EXPECT_FALSE(visited);
}
@@ -257,10 +256,9 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
std::vector<ClusterTypeId> visitedClusterTypes;
ClusterType::find(session, [&](const ClusterType::pointer& clusterType)
{
visitedClusterTypes.push_back(clusterType->getId());
});
ClusterType::find(session, [&](const ClusterType::pointer& clusterType) {
visitedClusterTypes.push_back(clusterType->getId());
});
ASSERT_EQ(visitedClusterTypes.size(), 2);
EXPECT_EQ(visitedClusterTypes[0], clusterType1->getId());
EXPECT_EQ(visitedClusterTypes[1], clusterType2->getId());
@@ -350,7 +348,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster.getId()})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster.getId() })) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release.getId());
}
@@ -358,7 +356,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setClusters(std::initializer_list<ClusterId>{unusedCluster.getId()})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ unusedCluster.getId() })) };
EXPECT_EQ(releases.results.size(), 0);
}
@@ -404,7 +402,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster1.getId()})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster1.getId() })) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
@@ -417,7 +415,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster1.getId()})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster1.getId() })) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
@@ -458,7 +456,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster.getId()})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster.getId() })) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
@@ -500,13 +498,12 @@ namespace lms::db::tests
std::vector<ClusterId> clusterIds;
std::transform(std::cbegin(clusters), std::cend(clusters), std::back_inserter(clusterIds), [](const ScopedCluster& cluster) { return cluster.getId(); });
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(clusterIds)) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(clusterIds)) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
}
}
TEST_F(DatabaseFixture, MultipleTracksSingleClusterSimilarity)
{
std::list<ScopedTrack> tracks;
@@ -526,7 +523,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) };
const auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.front().getId() }) };
EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1);
for (const TrackId similarTrackId : similarTracks.results)
{
@@ -567,14 +564,14 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
{
auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.back().getId()}, Range {0, 4}) };
auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.back().getId() }, Range{ 0, 4 }) };
EXPECT_EQ(similarTracks.results.size(), 4);
for (const TrackId similarTrackId : similarTracks.results)
EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 5), std::next(std::cend(tracks), -1), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks));
}
{
auto similarTracks{ Track::findSimilarTrackIds(session, {tracks.front().getId()}) };
auto similarTracks{ Track::findSimilarTrackIds(session, { tracks.front().getId() }) };
EXPECT_EQ(similarTracks.results.size(), tracks.size() - 1);
for (const TrackId similarTrackId : similarTracks.results)
EXPECT_TRUE(std::find_if(std::next(std::cbegin(tracks), 1), std::cend(tracks), [&](const auto& track) { return similarTrackId == track.getId(); }) != std::cend(tracks));
@@ -610,11 +607,11 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster.getId()})) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster.getId() })) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist.getId());
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);
EXPECT_EQ(releases.results.front(), release.getId());
@@ -645,7 +642,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
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);
EXPECT_EQ(releases.results.front(), release.getId());
@@ -790,24 +787,24 @@ namespace lms::db::tests
}
{
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist}) };
auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Artist }) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist2.getId());
}
{
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::ReleaseArtist}) };
auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::ReleaseArtist }) };
EXPECT_EQ(artists.results.size(), 0);
}
{
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist}) };
auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Artist, TrackArtistLinkType::ReleaseArtist }) };
ASSERT_EQ(artists.results.size(), 1);
EXPECT_EQ(artists.results.front(), artist2.getId());
}
{
auto artists{ artist1->findSimilarArtistIds({TrackArtistLinkType::Composer}) };
auto artists{ artist1->findSimilarArtistIds({ TrackArtistLinkType::Composer }) };
EXPECT_EQ(artists.results.size(), 0);
}
@@ -878,4 +875,4 @@ namespace lms::db::tests
}
}
}
}
} // namespace lms::db::tests
+24 -26
View File
@@ -109,13 +109,13 @@ namespace lms::db::tests
results.moreResults = false;
{
auto subRange{ results.getSubRange(Range {0, 0}) };
auto subRange{ results.getSubRange(Range{ 0, 0 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 0);
EXPECT_EQ(subRange.range, Range{});
}
{
auto subRange{ results.getSubRange(Range {0, 1}) };
auto subRange{ results.getSubRange(Range{ 0, 1 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 0);
}
@@ -130,28 +130,26 @@ namespace lms::db::tests
std::vector<Range> expectedSubRanges;
};
TestCase testCases[]
{
{Range{0, 0}, 1, {}},
{Range{1, 0}, 1, {}},
{Range{1, 1}, 1, { Range{ 1,1 } }},
{Range{1, 3}, 1, { Range{ 1,1 }, Range {2,1}, Range{3,1} }},
{Range{0, 100}, 100, { Range{0,100} }},
{Range{0, 50}, 100, { Range{0,50} }},
{Range{100, 200}, 100, { Range{100,100}, Range{200,100} }},
{Range{100, 101}, 100, { Range{100,100}, Range{200,1}}},
{Range{1000, 10}, 100, { Range{1000,10} }},
{Range{1, 100}, 50, { Range{1,50}, Range{51, 50} }},
TestCase testCases[]{
{ Range{ 0, 0 }, 1, {} },
{ Range{ 1, 0 }, 1, {} },
{ Range{ 1, 1 }, 1, { Range{ 1, 1 } } },
{ Range{ 1, 3 }, 1, { Range{ 1, 1 }, Range{ 2, 1 }, Range{ 3, 1 } } },
{ Range{ 0, 100 }, 100, { Range{ 0, 100 } } },
{ Range{ 0, 50 }, 100, { Range{ 0, 50 } } },
{ Range{ 100, 200 }, 100, { Range{ 100, 100 }, Range{ 200, 100 } } },
{ Range{ 100, 101 }, 100, { Range{ 100, 100 }, Range{ 200, 1 } } },
{ Range{ 1000, 10 }, 100, { Range{ 1000, 10 } } },
{ Range{ 1, 100 }, 50, { Range{ 1, 50 }, Range{ 51, 50 } } },
};
for (const TestCase& test : testCases)
{
std::vector<Range> subRanges;
foreachSubRange(test.range, test.subRangeSize, [&](Range subRange)
{
subRanges.push_back(subRange);
return true;
});
foreachSubRange(test.range, test.subRangeSize, [&](Range subRange) {
subRanges.push_back(subRange);
return true;
});
EXPECT_EQ(subRanges, test.expectedSubRanges) << ", test index = " << std::distance(std::cbegin(testCases), &test);
}
@@ -192,26 +190,26 @@ namespace lms::db::tests
results.moreResults = false;
{
auto subRange{ results.getSubRange(Range {0, 1}) };
auto subRange{ results.getSubRange(Range{ 0, 1 }) };
EXPECT_TRUE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 1);
EXPECT_EQ(subRange.results.front(), 5);
}
{
auto subRange{ results.getSubRange(Range {1, 1}) };
auto subRange{ results.getSubRange(Range{ 1, 1 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 1);
EXPECT_EQ(subRange.results.front(), 6);
}
{
auto subRange{ results.getSubRange(Range {0, 2}) };
auto subRange{ results.getSubRange(Range{ 0, 2 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 2);
EXPECT_EQ(subRange.results.front(), 5);
EXPECT_EQ(subRange.results.back(), 6);
}
{
auto subRange{ results.getSubRange(Range {}) };
auto subRange{ results.getSubRange(Range{}) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 2);
EXPECT_EQ(subRange.results.front(), 5);
@@ -220,7 +218,7 @@ namespace lms::db::tests
}
{
auto subRange{ results.getSubRange(Range {1, 0}) };
auto subRange{ results.getSubRange(Range{ 1, 0 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 1);
EXPECT_EQ(subRange.results.front(), 6);
@@ -228,11 +226,11 @@ namespace lms::db::tests
EXPECT_EQ(subRange.range, expectedRange);
}
{
auto subRange{ results.getSubRange(Range {3, 2}) };
auto subRange{ results.getSubRange(Range{ 3, 2 }) };
EXPECT_FALSE(subRange.moreResults);
ASSERT_EQ(subRange.results.size(), 0);
const Range expectedRange{ 2, 0 };
EXPECT_EQ(subRange.range, expectedRange);
}
}
}
} // namespace lms::db::tests
+6 -5
View File
@@ -42,14 +42,14 @@
namespace lms::db::tests
{
template <typename T>
template<typename T>
class [[nodiscard]] ScopedEntity
{
public:
using IdType = typename T::IdType;
template <typename... Args>
ScopedEntity(db::Session& session, Args&& ...args)
template<typename... Args>
ScopedEntity(db::Session& session, Args&&... args)
: _session{ session }
{
auto transaction{ _session.createWriteTransaction() };
@@ -113,7 +113,8 @@ namespace lms::db::tests
class ScopedFileDeleter final
{
public:
ScopedFileDeleter(const std::filesystem::path& path) : _path{ path } {}
ScopedFileDeleter(const std::filesystem::path& path)
: _path{ path } {}
~ScopedFileDeleter() { std::filesystem::remove(_path); }
private:
@@ -155,4 +156,4 @@ namespace lms::db::tests
public:
db::Session session{ _tmpDb->getDb() };
};
}
} // namespace lms::db::tests
+4 -4
View File
@@ -49,11 +49,11 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
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);
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);
}
}
@@ -74,7 +74,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
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);
EXPECT_EQ(releases.results.front(), release.getId());
@@ -101,7 +101,7 @@ namespace lms::db::tests
EXPECT_EQ(User::getCount(session), 1);
}
}
}
} // namespace lms::db::tests
int main(int argc, char** argv)
{
+45 -47
View File
@@ -17,9 +17,10 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Common.hpp"
#include "database/Listen.hpp"
#include "Common.hpp"
namespace lms::db::tests
{
using ScopedListen = ScopedEntity<db::Listen>;
@@ -35,7 +36,7 @@ namespace lms::db::tests
EXPECT_EQ(Listen::getCount(session), 0);
}
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } };
{
auto transaction{ session.createReadTransaction() };
@@ -45,7 +46,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
ScopedListen listen2{ session, user.get(), track.get(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{13, 0, 1}} };
ScopedListen listen2{ session, user.get(), track.get(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 13, 0, 1 } } };
EXPECT_EQ(Listen::getCount(session), 2);
}
@@ -61,7 +62,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } };
{
auto transaction{ session.createReadTransaction() };
@@ -95,9 +96,9 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 3}} };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 1}} };
ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime {Wt::WDate{2000, 1, 2}, Wt::WTime{12, 0, 2}} };
ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 3 } } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } } };
ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, Wt::WDateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 2 } } };
{
auto transaction{ session.createReadTransaction() };
@@ -114,8 +115,8 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime2{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 2} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
const Wt::WDateTime dateTime2{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 2 } };
ASSERT_GT(dateTime2, dateTime1);
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
@@ -147,7 +148,7 @@ namespace lms::db::tests
{
ScopedTrack track1{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
{
@@ -230,7 +231,7 @@ namespace lms::db::tests
ScopedArtist artist1{ session, "MyArtist1" };
ScopedTrack track2{ session };
ScopedArtist artist2{ session, "MyArtist2" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
{
auto transaction{ session.createWriteTransaction() };
@@ -296,7 +297,7 @@ namespace lms::db::tests
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedArtist artist{ session, "MyArtist" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedClusterType clusterType{ session, "MyType" };
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
@@ -340,7 +341,7 @@ namespace lms::db::tests
ScopedTrack track{ session };
ScopedArtist artist{ session, "MyArtist" };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime1{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
ScopedMediaLibrary library{ session };
ScopedMediaLibrary otherLibrary{ session };
@@ -405,7 +406,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedRelease release{ session, "MyRelease" };
{
auto transaction{ session.createWriteTransaction() };
@@ -456,7 +457,7 @@ namespace lms::db::tests
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedRelease release1{ session, "MyRelease1" };
ScopedRelease release2{ session, "MyRelease2" };
@@ -515,7 +516,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedClusterType clusterType{ session, "MyType" };
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
@@ -560,7 +561,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedRelease release{ session, "MyRelease" };
ScopedMediaLibrary library{ session };
ScopedMediaLibrary otherLibrary{ session };
@@ -617,7 +618,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
{
auto transaction{ session.createReadTransaction() };
@@ -663,7 +664,7 @@ namespace lms::db::tests
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedArtist artist{ session, "MyArtist" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
{
auto transaction{ session.createReadTransaction() };
@@ -717,7 +718,7 @@ namespace lms::db::tests
ScopedTrack track1{ session };
ScopedTrack track2{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -768,7 +769,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedClusterType clusterType{ session, "MyType" };
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
@@ -807,7 +808,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedMediaLibrary library{ session };
ScopedMediaLibrary otherLibrary{ session };
@@ -881,7 +882,7 @@ namespace lms::db::tests
EXPECT_EQ(artists.moreResults, false);
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -941,7 +942,7 @@ namespace lms::db::tests
ScopedArtist artist1{ session, "MyArtist1" };
ScopedTrack track2{ session };
ScopedArtist artist2{ session, "MyArtist2" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
{
auto transaction{ session.createWriteTransaction() };
@@ -1006,7 +1007,7 @@ namespace lms::db::tests
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
ScopedArtist artist{ session, "MyArtist" };
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedClusterType clusterType{ session, "MyType" };
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
@@ -1045,7 +1046,6 @@ namespace lms::db::tests
}
}
TEST_F(DatabaseFixture, Listen_getRecentArtists_mediaLibrary)
{
ScopedTrack track{ session };
@@ -1060,7 +1060,7 @@ namespace lms::db::tests
track.get().modify()->setMediaLibrary(library.get());
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1107,7 +1107,7 @@ namespace lms::db::tests
ASSERT_EQ(releases.results.size(), 0);
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1153,7 +1153,7 @@ namespace lms::db::tests
EXPECT_FALSE(listen);
}
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
{
@@ -1164,7 +1164,7 @@ namespace lms::db::tests
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime2{ Wt::WDate {1999, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime2{ Wt::WDate{ 1999, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime2 };
{
@@ -1175,7 +1175,7 @@ namespace lms::db::tests
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime3{ Wt::WDate {2001, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime3{ Wt::WDate{ 2001, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime3 };
{
@@ -1201,7 +1201,7 @@ namespace lms::db::tests
track2.get().modify()->setRelease(release2.get());
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1287,7 +1287,7 @@ namespace lms::db::tests
EXPECT_EQ(releases.results.size(), 0);
}
const Wt::WDateTime dateTime{ Wt::WDate{2000, 1, 2}, Wt::WTime{12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1334,7 +1334,7 @@ namespace lms::db::tests
track.get().modify()->setMediaLibrary(library.get());
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1377,7 +1377,7 @@ namespace lms::db::tests
ASSERT_EQ(tracks.results.size(), 0);
}
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1406,7 +1406,6 @@ namespace lms::db::tests
}
}
TEST_F(DatabaseFixture, Listen_getRecentTracks_mediaLibrary)
{
ScopedTrack track{ session };
@@ -1414,7 +1413,7 @@ namespace lms::db::tests
ScopedMediaLibrary library{ session };
ScopedMediaLibrary otherLibrary{ session };
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1458,7 +1457,7 @@ namespace lms::db::tests
EXPECT_EQ(count, 0);
}
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
{
@@ -1487,15 +1486,14 @@ namespace lms::db::tests
ScopedUser user{ session, "MyUser" };
ScopedRelease release{ session, "MyRelease" };
auto getReleaseListenCount{ [&]
{
auto getReleaseListenCount{ [&] {
auto transaction{ session.createReadTransaction() };
return Listen::getCount(session, user->getId(), release.getId());
} };
EXPECT_EQ(getReleaseListenCount(), 0);
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track1.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
EXPECT_EQ(getReleaseListenCount(), 0);
@@ -1540,7 +1538,7 @@ namespace lms::db::tests
EXPECT_FALSE(listen);
}
const Wt::WDateTime dateTime1{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime1{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime1 };
{
@@ -1551,7 +1549,7 @@ namespace lms::db::tests
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime2{ Wt::WDate {1999, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime2{ Wt::WDate{ 1999, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen2{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime2 };
{
@@ -1562,7 +1560,7 @@ namespace lms::db::tests
EXPECT_EQ(listen->getDateTime(), dateTime1);
}
const Wt::WDateTime dateTime3{ Wt::WDate {2001, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime3{ Wt::WDate{ 2001, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen3{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime3 };
{
@@ -1580,7 +1578,7 @@ namespace lms::db::tests
ScopedTrack track2{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen1{ session, user.lockAndGet(), track2.lockAndGet(), ScrobblingBackend::Internal, dateTime };
{
@@ -1646,7 +1644,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
ScopedUser user{ session, "MyUser" };
const Wt::WDateTime dateTime{ Wt::WDate {2000, 1, 2}, Wt::WTime {12,0, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 2000, 1, 2 }, Wt::WTime{ 12, 0, 1 } };
ScopedListen listen{ session, user.lockAndGet(), track.lockAndGet(), ScrobblingBackend::Internal, dateTime };
ScopedClusterType clusterType{ session, "MyType" };
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
@@ -1680,4 +1678,4 @@ namespace lms::db::tests
EXPECT_EQ(tracks.results[0], track.getId());
}
}
}
} // namespace lms::db::tests
+4 -4
View File
@@ -34,7 +34,7 @@ namespace lms::db::tests
session.execute(statement);
}
}
}
} // namespace
TEST(Database, migration)
{
@@ -263,7 +263,7 @@ CREATE INDEX starred_artist_user_scrobbler_idx ON starred_artist(user_id,scrobbl
CREATE INDEX starred_release_user_scrobbler_idx ON starred_release(user_id,scrobbler);
CREATE INDEX starred_track_user_scrobbler_idx ON starred_track(user_id,scrobbler);)" };
const std::string_view createDummyData{R"(
const std::string_view createDummyData{ R"(
-- Inserting artists
INSERT INTO artist (version, name, sort_name, mbid) VALUES
(1, 'Artist A', 'Artist A', 'mbid_artist_a'),
@@ -302,7 +302,7 @@ VALUES
INSERT INTO track_artist_link (version, type, name, track_id, artist_id)
VALUES
(1, 1, 'Artist A', 5, 1),
(2, 1, 'Artist B', 6, 2);)"};
(2, 1, 'Artist B', 6, 2);)" };
Session session{ db };
@@ -319,4 +319,4 @@ VALUES
// Now perform full migration
db.getTLSSession().migrateSchemaIfNeeded();
}
}
} // namespace lms::db::tests
+58 -62
View File
@@ -50,25 +50,24 @@ namespace lms::db::tests
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}) };
const auto releases{ Release::findIds(session, Release::FindParameters{}) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release.getId());
EXPECT_EQ(release->getDuration(), std::chrono::seconds{ 0 });
}
{
const auto releases{ Release::find(session, Release::FindParameters {}) };
const auto releases{ Release::find(session, Release::FindParameters{}) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front()->getId(), release.getId());
}
{
bool visited{};
Release::find(session, Release::FindParameters{}, [&](const Release::pointer& r)
{
visited = true;
EXPECT_EQ(r->getId(), release.getId());
});
Release::find(session, Release::FindParameters{}, [&](const Release::pointer& r) {
visited = true;
EXPECT_EQ(r->getId(), release.getId());
});
EXPECT_TRUE(visited);
}
}
@@ -101,10 +100,9 @@ namespace lms::db::tests
ReleaseId lastRetrievedId;
std::vector<Release::pointer> visitedReleases;
Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release)
{
visitedReleases.push_back(release);
});
Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release) {
visitedReleases.push_back(release);
});
ASSERT_EQ(visitedReleases.size(), 3);
EXPECT_EQ(visitedReleases[0]->getId(), release1.getId());
EXPECT_EQ(visitedReleases[1]->getId(), release2.getId());
@@ -117,10 +115,9 @@ namespace lms::db::tests
ReleaseId lastRetrievedId{ release1.getId() };
std::vector<Release::pointer> visitedReleases;
Release::find(session, lastRetrievedId, 1, [&](const Release::pointer& release)
{
visitedReleases.push_back(release);
});
Release::find(session, lastRetrievedId, 1, [&](const Release::pointer& release) {
visitedReleases.push_back(release);
});
ASSERT_EQ(visitedReleases.size(), 1);
EXPECT_EQ(visitedReleases[0]->getId(), release2.getId());
EXPECT_EQ(lastRetrievedId, release2.getId());
@@ -131,10 +128,9 @@ namespace lms::db::tests
ReleaseId lastRetrievedId{ release1.getId() };
std::vector<Release::pointer> visitedReleases;
Release::find(session, lastRetrievedId, 0, [&](const Release::pointer& release)
{
visitedReleases.push_back(release);
});
Release::find(session, lastRetrievedId, 0, [&](const Release::pointer& release) {
visitedReleases.push_back(release);
});
ASSERT_EQ(visitedReleases.size(), 0);
EXPECT_EQ(lastRetrievedId, release1.getId());
}
@@ -144,10 +140,11 @@ namespace lms::db::tests
ReleaseId lastRetrievedId;
std::vector<Release::pointer> visitedReleases;
Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release)
{
Release::find(
session, lastRetrievedId, 10, [&](const Release::pointer& release) {
visitedReleases.push_back(release);
}, otherLibrary.getId());
},
otherLibrary.getId());
ASSERT_EQ(visitedReleases.size(), 0);
EXPECT_EQ(lastRetrievedId, ReleaseId{});
}
@@ -157,10 +154,11 @@ namespace lms::db::tests
ReleaseId lastRetrievedId;
std::vector<Release::pointer> visitedReleases;
Release::find(session, lastRetrievedId, 10, [&](const Release::pointer& release)
{
Release::find(
session, lastRetrievedId, 10, [&](const Release::pointer& release) {
visitedReleases.push_back(release);
}, library.getId());
},
library.getId());
ASSERT_EQ(visitedReleases.size(), 1);
EXPECT_EQ(visitedReleases[0]->getId(), release2.getId());
EXPECT_EQ(lastRetrievedId, release2.getId());
@@ -185,7 +183,7 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
EXPECT_EQ(Release::findOrphanIds(session).results.size(), 0);
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release.getId())) };
ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track.getId());
}
@@ -218,7 +216,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release.getId())) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release.getId())) };
EXPECT_EQ(tracks.results.size(), 0);
auto releases{ Release::findOrphanIds(session) };
@@ -318,34 +316,34 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Release"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "Release" })) };
EXPECT_EQ(releases.results.size(), 6);
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease" })) };
ASSERT_EQ(releases.results.size(), 5);
EXPECT_TRUE(std::none_of(std::cbegin(releases.results), std::cend(releases.results), [&](const ReleaseId releaseId) { return releaseId == release6.getId(); }));
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease%" })) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results[0], release2.getId());
EXPECT_EQ(releases.results[1], release4.getId());
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"%MyRelease"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "%MyRelease" })) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results[0], release3.getId());
EXPECT_EQ(releases.results[1], release5.getId());
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"Foo%MyRelease"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "Foo%MyRelease" })) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results[0], release5.getId());
}
{
const auto releases{ Release::findIds(session, Release::FindParameters {}.setKeywords({"MyRelease%Foo"})) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setKeywords({ "MyRelease%Foo" })) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results[0], release4.getId());
}
@@ -476,13 +474,13 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release)) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release1.getId()).setSortMethod(TrackSortMethod::Release)) };
EXPECT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results.front(), track1A.getId());
}
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release)) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setRelease(release2.getId()).setSortMethod(TrackSortMethod::Release)) };
EXPECT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results.front(), track2B.getId());
}
@@ -493,8 +491,8 @@ namespace lms::db::tests
{
ScopedRelease release1{ session, "MyRelease1" };
ScopedRelease release2{ session, "MyRelease2" };
const Wt::WDate release1Date{ Wt::WDate {1994, 2, 3} };
const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} };
const Wt::WDate release1Date{ Wt::WDate{ 1994, 2, 3 } };
const Wt::WDate release1OriginalDate{ Wt::WDate{ 1993, 4, 5 } };
ScopedTrack track1A{ session };
ScopedTrack track1B{ session };
@@ -504,7 +502,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(0, 3000))) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(0, 3000))) };
EXPECT_EQ(releases.results.size(), 0);
}
@@ -528,7 +526,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(1950, 2000))) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1950, 2000))) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release1.getId());
@@ -556,7 +554,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(0, 3000))) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(0, 3000))) };
EXPECT_EQ(releases.results.size(), 0);
}
@@ -568,7 +566,6 @@ namespace lms::db::tests
track2A.get().modify()->setRelease(release2.get());
track2B.get().modify()->setRelease(release2.get());
track1A.get().modify()->setYear(release1Year);
track1B.get().modify()->setYear(release1Year);
track1A.get().modify()->setOriginalYear(release1OriginalYear);
@@ -581,7 +578,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto releases{ Release::findIds(session, Release::FindParameters {}.setDateRange(DateRange::fromYearRange(1950, 2000))) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setDateRange(DateRange::fromYearRange(1950, 2000))) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release1.getId());
@@ -599,7 +596,7 @@ namespace lms::db::tests
ScopedRelease release{ session, "MyRelease" };
ScopedTrack track{ session };
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 1 }, Wt::WTime{ 12, 30, 20 } };
{
auto transaction{ session.createWriteTransaction() };
@@ -609,19 +606,19 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}) };
const auto releases{ Release::findIds(session, Release::FindParameters{}) };
EXPECT_EQ(releases.results.size(), 1);
}
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setWrittenAfter(dateTime.addSecs(-1))) };
EXPECT_EQ(releases.results.size(), 1);
}
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setWrittenAfter(dateTime.addSecs(+1))) };
EXPECT_EQ(releases.results.size(), 0);
}
}
@@ -640,7 +637,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist })) };
EXPECT_EQ(releases.results.size(), 0);
releases = Release::findIds(session, Release::FindParameters{}.setArtist(artist2.getId(), { TrackArtistLinkType::Artist }));
@@ -651,7 +648,7 @@ namespace lms::db::tests
auto transaction{ session.createWriteTransaction() };
TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist);
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId(), {TrackArtistLinkType::Artist})) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setArtist(artist.getId(), { TrackArtistLinkType::Artist })) };
ASSERT_EQ(releases.results.size(), 1);
EXPECT_EQ(releases.results.front(), release.getId());
@@ -810,11 +807,11 @@ namespace lms::db::tests
TEST_F(DatabaseFixture, Release_sortMethod)
{
ScopedRelease release1{ session, "MyRelease1" };
const Wt::WDate release1Date{ Wt::WDate {2000, 2, 3} };
const Wt::WDate release1OriginalDate{ Wt::WDate {1993, 4, 5} };
const Wt::WDate release1Date{ Wt::WDate{ 2000, 2, 3 } };
const Wt::WDate release1OriginalDate{ Wt::WDate{ 1993, 4, 5 } };
ScopedRelease release2{ session, "MyRelease2" };
const Wt::WDate release2Date{ Wt::WDate {1994, 2, 3} };
const Wt::WDate release2Date{ Wt::WDate{ 1994, 2, 3 } };
ScopedTrack track1{ session };
ScopedTrack track2{ session };
@@ -836,7 +833,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Name)) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Name)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results.front(), release1.getId());
EXPECT_EQ(releases.results.back(), release2.getId());
@@ -845,14 +842,14 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Random)) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Random)) };
ASSERT_EQ(releases.results.size(), 2);
}
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::Date)) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::Date)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results.front(), release2.getId());
EXPECT_EQ(releases.results.back(), release1.getId());
@@ -861,7 +858,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDate)) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::OriginalDate)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results.front(), release1.getId());
EXPECT_EQ(releases.results.back(), release2.getId());
@@ -869,7 +866,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto releases{ Release::findIds(session, Release::FindParameters {}.setSortMethod(ReleaseSortMethod::OriginalDateDesc)) };
const auto releases{ Release::findIds(session, Release::FindParameters{}.setSortMethod(ReleaseSortMethod::OriginalDateDesc)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results.front(), release2.getId());
EXPECT_EQ(releases.results.back(), release1.getId());
@@ -883,11 +880,10 @@ namespace lms::db::tests
ScopedTrack track2{ session };
ScopedTrack track3{ session };
auto checkExpectedBitrate = [&](std::size_t bitrate)
{
auto transaction{ session.createReadTransaction() };
EXPECT_EQ(release1->getMeanBitrate(), bitrate);
};
auto checkExpectedBitrate = [&](std::size_t bitrate) {
auto transaction{ session.createReadTransaction() };
EXPECT_EQ(release1->getMeanBitrate(), bitrate);
};
checkExpectedBitrate(0);
@@ -938,4 +934,4 @@ namespace lms::db::tests
EXPECT_EQ(release3->getTrackCount(), 0);
}
}
}
} // namespace lms::db::tests
+10 -9
View File
@@ -17,9 +17,10 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Common.hpp"
#include "database/StarredArtist.hpp"
#include "Common.hpp"
namespace lms::db::tests
{
using ScopedStarredArtist = ScopedEntity<db::StarredArtist>;
@@ -37,7 +38,7 @@ namespace lms::db::tests
EXPECT_FALSE(starredArtist);
EXPECT_EQ(StarredArtist::getCount(session), 0);
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
EXPECT_EQ(artists.results.size(), 1);
}
@@ -53,7 +54,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
auto artists{ Artist::findIds(session, Artist::FindParameters{}) };
EXPECT_EQ(artists.results.size(), 1);
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
@@ -96,7 +97,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
auto artists{ Artist::findIds(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);
starredArtist.get().modify()->setSyncState(SyncState::PendingRemove);
@@ -114,12 +115,12 @@ namespace lms::db::tests
ScopedStarredArtist starredArtist1{ session, artist1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
ScopedStarredArtist starredArtist2{ session, artist2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } };
{
auto transaction{ session.createReadTransaction() };
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
auto artists{ Artist::find(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(artists.results.size(), 2);
}
@@ -129,7 +130,7 @@ namespace lms::db::tests
starredArtist1.get().modify()->setDateTime(dateTime);
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(-1));
auto artists{ Artist::findIds(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);
EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId());
EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId());
@@ -140,10 +141,10 @@ namespace lms::db::tests
starredArtist1.get().modify()->setDateTime(dateTime);
starredArtist2.get().modify()->setDateTime(dateTime.addSecs(1));
auto artists{ Artist::findIds(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);
EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId());
EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId());
}
}
}
} // namespace lms::db::tests
+10 -9
View File
@@ -17,9 +17,10 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Common.hpp"
#include "database/StarredRelease.hpp"
#include "Common.hpp"
namespace lms::db::tests
{
using ScopedStarredRelease = ScopedEntity<db::StarredRelease>;
@@ -37,7 +38,7 @@ namespace lms::db::tests
EXPECT_FALSE(starredRelease);
EXPECT_EQ(StarredRelease::getCount(session), 0);
auto releases{ Release::find(session, Release::FindParameters {}) };
auto releases{ Release::find(session, Release::FindParameters{}) };
EXPECT_EQ(releases.results.size(), 1);
}
@@ -53,7 +54,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto releases{ Release::find(session, Release::FindParameters {}) };
auto releases{ Release::find(session, Release::FindParameters{}) };
EXPECT_EQ(releases.results.size(), 1);
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
@@ -85,7 +86,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
auto releases{ Release::find(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
auto releases{ Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(releases.results.size(), 1);
starredRelease.get().modify()->setSyncState(SyncState::PendingRemove);
@@ -103,12 +104,12 @@ namespace lms::db::tests
ScopedStarredRelease starredRelease1{ session, release1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
ScopedStarredRelease starredRelease2{ session, release2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } };
{
auto transaction{ session.createReadTransaction() };
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(releases.results.size(), 2);
}
@@ -118,7 +119,7 @@ namespace lms::db::tests
starredRelease1.get().modify()->setDateTime(dateTime);
starredRelease2.get().modify()->setDateTime(dateTime.addSecs(-1));
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results[0], starredRelease1->getRelease()->getId());
EXPECT_EQ(releases.results[1], starredRelease2->getRelease()->getId());
@@ -129,10 +130,10 @@ namespace lms::db::tests
starredRelease1.get().modify()->setDateTime(dateTime);
starredRelease2.get().modify()->setDateTime(dateTime.addSecs(1));
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
auto releases{ Release::findIds(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(ReleaseSortMethod::StarredDateDesc)) };
ASSERT_EQ(releases.results.size(), 2);
EXPECT_EQ(releases.results[0], starredRelease2->getRelease()->getId());
EXPECT_EQ(releases.results[1], starredRelease1->getRelease()->getId());
}
}
}
} // namespace lms::db::tests
+10 -9
View File
@@ -17,9 +17,10 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Common.hpp"
#include "database/StarredTrack.hpp"
#include "Common.hpp"
namespace lms::db::tests
{
using ScopedStarredTrack = ScopedEntity<db::StarredTrack>;
@@ -37,7 +38,7 @@ namespace lms::db::tests
EXPECT_FALSE(starredTrack);
EXPECT_EQ(StarredTrack::getCount(session), 0);
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
auto tracks{ Track::findIds(session, Track::FindParameters{}) };
EXPECT_EQ(tracks.results.size(), 1);
}
@@ -53,7 +54,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
auto tracks{ Track::findIds(session, Track::FindParameters{}) };
EXPECT_EQ(tracks.results.size(), 1);
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
@@ -85,7 +86,7 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(tracks.results.size(), 1);
starredTrack.get().modify()->setSyncState(SyncState::PendingRemove);
@@ -103,12 +104,12 @@ namespace lms::db::tests
ScopedStarredTrack starredTrack1{ session, track1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
ScopedStarredTrack starredTrack2{ session, track2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 2 }, Wt::WTime{ 12, 30, 1 } };
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
EXPECT_EQ(tracks.results.size(), 2);
}
@@ -118,7 +119,7 @@ namespace lms::db::tests
starredTrack1.get().modify()->setDateTime(dateTime);
starredTrack2.get().modify()->setDateTime(dateTime.addSecs(-1));
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
ASSERT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results[0], starredTrack1->getTrack()->getId());
EXPECT_EQ(tracks.results[1], starredTrack2->getTrack()->getId());
@@ -129,10 +130,10 @@ namespace lms::db::tests
starredTrack1.get().modify()->setDateTime(dateTime);
starredTrack2.get().modify()->setDateTime(dateTime.addSecs(1));
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal).setSortMethod(TrackSortMethod::StarredDateDesc)) };
ASSERT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results[0], starredTrack2->getTrack()->getId());
EXPECT_EQ(tracks.results[1], starredTrack1->getTrack()->getId());
}
}
}
} // namespace lms::db::tests
+31 -34
View File
@@ -34,7 +34,7 @@ namespace lms::db::tests
{
bool visited{};
Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) {visited = true;});
Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) { visited = true; });
EXPECT_FALSE(visited);
}
}
@@ -53,11 +53,10 @@ namespace lms::db::tests
{
bool visited{};
Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t)
{
visited = true;
EXPECT_EQ(t->getId(), track.getId());
});
Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t) {
visited = true;
EXPECT_EQ(t->getId(), track.getId());
});
EXPECT_TRUE(visited);
}
}
@@ -81,10 +80,9 @@ namespace lms::db::tests
TrackId lastRetrievedTrackId;
std::vector<Track::pointer> visitedTracks;
Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track)
{
visitedTracks.push_back(track);
});
Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) {
visitedTracks.push_back(track);
});
ASSERT_EQ(visitedTracks.size(), 3);
EXPECT_EQ(visitedTracks[0]->getId(), track1.getId());
EXPECT_EQ(visitedTracks[1]->getId(), track2.getId());
@@ -97,10 +95,9 @@ namespace lms::db::tests
TrackId lastRetrievedTrackId{ track1.getId() };
std::vector<Track::pointer> visitedTracks;
Track::find(session, lastRetrievedTrackId, 1, [&](const Track::pointer& track)
{
visitedTracks.push_back(track);
});
Track::find(session, lastRetrievedTrackId, 1, [&](const Track::pointer& track) {
visitedTracks.push_back(track);
});
ASSERT_EQ(visitedTracks.size(), 1);
EXPECT_EQ(visitedTracks[0]->getId(), track2.getId());
EXPECT_EQ(lastRetrievedTrackId, track2.getId());
@@ -111,10 +108,9 @@ namespace lms::db::tests
TrackId lastRetrievedTrackId{ track1.getId() };
std::vector<Track::pointer> visitedTracks;
Track::find(session, lastRetrievedTrackId, 0, [&](const Track::pointer& track)
{
visitedTracks.push_back(track);
});
Track::find(session, lastRetrievedTrackId, 0, [&](const Track::pointer& track) {
visitedTracks.push_back(track);
});
ASSERT_EQ(visitedTracks.size(), 0);
EXPECT_EQ(lastRetrievedTrackId, track1.getId());
}
@@ -124,10 +120,11 @@ namespace lms::db::tests
TrackId lastRetrievedTrackId{};
std::vector<Track::pointer> visitedTracks;
Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track)
{
Track::find(
session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) {
visitedTracks.push_back(track);
}, otherLibrary.getId());
},
otherLibrary.getId());
ASSERT_EQ(visitedTracks.size(), 0);
EXPECT_EQ(lastRetrievedTrackId, TrackId{});
}
@@ -137,10 +134,11 @@ namespace lms::db::tests
TrackId lastRetrievedTrackId{};
std::vector<Track::pointer> visitedTracks;
Track::find(session, lastRetrievedTrackId, 10, [&](const Track::pointer& track)
{
Track::find(
session, lastRetrievedTrackId, 10, [&](const Track::pointer& track) {
visitedTracks.push_back(track);
}, library.getId());
},
library.getId());
ASSERT_EQ(visitedTracks.size(), 1);
EXPECT_EQ(visitedTracks[0]->getId(), track2.getId());
EXPECT_EQ(lastRetrievedTrackId, track2.getId());
@@ -235,22 +233,22 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"Track"})) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "Track" })) };
EXPECT_EQ(tracks.results.size(), 6);
}
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack"})) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "MyTrack" })) };
EXPECT_EQ(tracks.results.size(), 5);
EXPECT_TRUE(std::none_of(std::cbegin(tracks.results), std::cend(tracks.results), [&](const TrackId trackId) { return trackId == track6.getId(); }));
}
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"MyTrack%"})) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "MyTrack%" })) };
ASSERT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results[0], track2.getId());
EXPECT_EQ(tracks.results[1], track3.getId());
}
{
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"%MyTrack"})) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setKeywords({ "%MyTrack" })) };
ASSERT_EQ(tracks.results.size(), 2);
EXPECT_EQ(tracks.results[0], track4.getId());
EXPECT_EQ(tracks.results[1], track5.getId());
@@ -300,7 +298,7 @@ namespace lms::db::tests
{
ScopedTrack track{ session };
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
const Wt::WDateTime dateTime{ Wt::WDate{ 1950, 1, 1 }, Wt::WTime{ 12, 30, 20 } };
{
auto transaction{ session.createWriteTransaction() };
@@ -309,19 +307,19 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters {}) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}) };
EXPECT_EQ(tracks.results.size(), 1);
}
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(-1))) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setWrittenAfter(dateTime.addSecs(-1))) };
EXPECT_EQ(tracks.results.size(), 1);
}
{
auto transaction{ session.createReadTransaction() };
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setWrittenAfter(dateTime.addSecs(+1))) };
EXPECT_EQ(tracks.results.size(), 0);
}
}
@@ -343,7 +341,6 @@ namespace lms::db::tests
}
}
TEST_F(DatabaseFixture, Track_audioProperties)
{
ScopedTrack track{ session };
@@ -366,4 +363,4 @@ namespace lms::db::tests
EXPECT_EQ(track->getSampleRate(), 44100);
}
}
}
} // namespace lms::db::tests
+1 -1
View File
@@ -64,4 +64,4 @@ namespace lms::db::tests
EXPECT_EQ(userBookmark->getComment(), "MyComment");
}
}
}
} // namespace lms::db::tests
+1 -1
View File
@@ -46,4 +46,4 @@ namespace lms::db::tests
EXPECT_EQ(allTrackFeatures.results.front(), trackFeatures.getId());
}
}
}
} // namespace lms::db::tests
+19 -21
View File
@@ -49,7 +49,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setTrackList(trackList1.getId())) };
EXPECT_EQ(tracks.results.size(), 0);
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
@@ -65,7 +65,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
auto tracks{ Track::findIds(session, Track::FindParameters{}.setTrackList(trackList1.getId())) };
ASSERT_EQ(tracks.results.size(), 1);
EXPECT_EQ(tracks.results.front(), track.getId());
@@ -84,7 +84,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::Name)) };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::Name)) };
ASSERT_EQ(trackLists.results.size(), 2);
EXPECT_EQ(trackLists.results[0], trackList1.getId());
EXPECT_EQ(trackLists.results[1], trackList2.getId());
@@ -93,14 +93,14 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} });
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} });
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 1 } });
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 2 } });
}
{
auto transaction{ session.createReadTransaction() };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
ASSERT_EQ(trackLists.results.size(), 2);
EXPECT_EQ(trackLists.results[0], trackList2.getId());
EXPECT_EQ(trackLists.results[1], trackList1.getId());
@@ -109,14 +109,14 @@ namespace lms::db::tests
{
auto transaction{ session.createWriteTransaction() };
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,2} });
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate {1900,1,1} });
trackList1.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 2 } });
trackList2.get().modify()->setLastModifiedDateTime(Wt::WDateTime{ Wt::WDate{ 1900, 1, 1 } });
}
{
auto transaction{ session.createReadTransaction() };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
const auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setSortMethod(TrackListSortMethod::LastModifiedDesc)) };
ASSERT_EQ(trackLists.results.size(), 2);
EXPECT_EQ(trackLists.results[0], trackList1.getId());
EXPECT_EQ(trackLists.results[1], trackList2.getId());
@@ -170,10 +170,9 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
std::vector<TrackListId> visitedTrackLists;
TrackList::find(session, TrackList::FindParameters{}, [&](const TrackList::pointer& trackList)
{
visitedTrackLists.push_back(trackList->getId());
});
TrackList::find(session, TrackList::FindParameters{}, [&](const TrackList::pointer& trackList) {
visitedTrackLists.push_back(trackList->getId());
});
ASSERT_EQ(visitedTrackLists.size(), 2);
EXPECT_EQ(visitedTrackLists[0], trackList1->getId());
EXPECT_EQ(visitedTrackLists[1], trackList2->getId());
@@ -182,10 +181,9 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
std::vector<TrackListId> visitedTrackLists;
TrackList::find(session, TrackList::FindParameters{}.setMediaLibrary(library->getId()), [&](const TrackList::pointer& trackList)
{
visitedTrackLists.push_back(trackList->getId());
});
TrackList::find(session, TrackList::FindParameters{}.setMediaLibrary(library->getId()), [&](const TrackList::pointer& trackList) {
visitedTrackLists.push_back(trackList->getId());
});
ASSERT_EQ(visitedTrackLists.size(), 1);
EXPECT_EQ(visitedTrackLists[0], trackList2->getId());
}
@@ -203,7 +201,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster.getId()})) };
auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster.getId() })) };
EXPECT_EQ(trackLists.results.size(), 0);
}
@@ -217,7 +215,7 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters(std::initializer_list<ClusterId>{cluster.getId()})) };
auto trackLists{ TrackList::find(session, TrackList::FindParameters{}.setClusters(std::initializer_list<ClusterId>{ cluster.getId() })) };
ASSERT_EQ(trackLists.results.size(), 1);
EXPECT_EQ(trackLists.results.front(), trackList1.getId());
}
@@ -257,9 +255,9 @@ namespace lms::db::tests
{
auto transaction{ session.createReadTransaction() };
auto entries{ trackList.get()->getEntries(Range {1, 1}) };
auto entries{ trackList.get()->getEntries(Range{ 1, 1 }) };
ASSERT_EQ(entries.results.size(), 1);
EXPECT_EQ(entries.results[0]->getTrack()->getId(), track2.getId());
}
}
}
} // namespace lms::db::tests
+7 -9
View File
@@ -27,10 +27,9 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
bool visited{};
User::find(session, User::FindParameters{}, [&](const User::pointer&)
{
visited = true;
});
User::find(session, User::FindParameters{}, [&](const User::pointer&) {
visited = true;
});
EXPECT_FALSE(visited);
}
@@ -41,13 +40,12 @@ namespace lms::db::tests
auto transaction{ session.createReadTransaction() };
std::vector<UserId> visitedUsers;
User::find(session, User::FindParameters{}, [&](const User::pointer& user)
{
visitedUsers.push_back(user->getId());
});
User::find(session, User::FindParameters{}, [&](const User::pointer& user) {
visitedUsers.push_back(user->getId());
});
EXPECT_EQ(visitedUsers.size(), 2);
EXPECT_EQ(visitedUsers[0], user1->getId());
EXPECT_EQ(visitedUsers[1], user2->getId());
}
}
}
} // namespace lms::db::tests