Reworked internal namespaces
This commit is contained in:
@@ -37,7 +37,7 @@ target_link_libraries(lmsdatabase PRIVATE
|
||||
)
|
||||
|
||||
target_link_libraries(lmsdatabase PUBLIC
|
||||
lmsutils
|
||||
lmscore
|
||||
std::filesystem
|
||||
Wt::Dbo
|
||||
)
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -67,16 +67,16 @@ namespace Database
|
||||
for (std::string_view keyword : params.keywords)
|
||||
{
|
||||
clauses.push_back("a.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'");
|
||||
query.bind("%" + Utils::escapeLikeKeyword(keyword) + "%");
|
||||
query.bind("%" + utils::escapeLikeKeyword(keyword) + "%");
|
||||
}
|
||||
|
||||
for (std::string_view keyword : params.keywords)
|
||||
{
|
||||
sortClauses.push_back("a.sort_name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'");
|
||||
query.bind("%" + Utils::escapeLikeKeyword(keyword) + "%");
|
||||
query.bind("%" + utils::escapeLikeKeyword(keyword) + "%");
|
||||
}
|
||||
|
||||
query.where("(" + StringUtils::joinStrings(clauses, " AND ") + ") OR (" + StringUtils::joinStrings(sortClauses, " AND ") + ")");
|
||||
query.where("(" + core::stringUtils::joinStrings(clauses, " AND ") + ") OR (" + core::stringUtils::joinStrings(sortClauses, " AND ") + ")");
|
||||
}
|
||||
|
||||
if (params.starringUser.isValid())
|
||||
@@ -165,16 +165,16 @@ namespace Database
|
||||
}
|
||||
}
|
||||
|
||||
Artist::Artist(const std::string& name, const std::optional<UUID>& MBID)
|
||||
Artist::Artist(const std::string& name, const std::optional<core::UUID>& MBID)
|
||||
: _name{ std::string(name, 0 , _maxNameLength) },
|
||||
_sortName{ _name },
|
||||
_MBID{ MBID ? MBID->getAsString() : "" }
|
||||
{
|
||||
}
|
||||
|
||||
Artist::pointer Artist::create(Session& session, const std::string& name, const std::optional<UUID>& MBID)
|
||||
Artist::pointer Artist::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID)
|
||||
{
|
||||
return session.getDboSession().add(std::unique_ptr<Artist> {new Artist{ name, MBID }});
|
||||
return session.getDboSession().add(std::unique_ptr<Artist>{ new Artist{ name, MBID } });
|
||||
}
|
||||
|
||||
std::size_t Artist::getCount(Session& session)
|
||||
@@ -195,7 +195,7 @@ namespace Database
|
||||
return std::vector<Artist::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
Artist::pointer Artist::find(Session& session, const UUID& mbid)
|
||||
Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
return session.getDboSession().find<Artist>().where("mbid = ?").bind(std::string{ mbid.getAsString() }).resultValue();
|
||||
@@ -218,7 +218,7 @@ namespace Database
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
auto query{ session.getDboSession().query<ArtistId>("SELECT DISTINCT a.id FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)") };
|
||||
return Utils::execQuery<ArtistId>(query, range);
|
||||
return utils::execQuery<ArtistId>(query, range);
|
||||
}
|
||||
|
||||
RangeResults<ArtistId> Artist::findIds(Session& session, const FindParameters& params)
|
||||
@@ -226,7 +226,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<ArtistId>(session, params) };
|
||||
return Utils::execQuery<ArtistId>(query, params.range);
|
||||
return utils::execQuery<ArtistId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<Artist::pointer> Artist::find(Session& session, const FindParameters& params)
|
||||
@@ -234,7 +234,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) };
|
||||
return Utils::execQuery<Artist::pointer>(query, params.range);
|
||||
return utils::execQuery<Artist::pointer>(query, params.range);
|
||||
}
|
||||
|
||||
void Artist::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func)
|
||||
@@ -242,10 +242,10 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) };
|
||||
Utils::execQuery(query, params.range, func);
|
||||
utils::execQuery(query, params.range, func);
|
||||
}
|
||||
|
||||
RangeResults<ArtistId> Artist::findSimilarArtistIds(EnumSet<TrackArtistLinkType> artistLinkTypes, std::optional<Range> range) const
|
||||
RangeResults<ArtistId> Artist::findSimilarArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes, std::optional<Range> range) const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace Database
|
||||
for (TrackArtistLinkType type : artistLinkTypes)
|
||||
query.bind(type);
|
||||
|
||||
return Utils::execQuery<ArtistId>(query, range);
|
||||
return utils::execQuery<ArtistId>(query, range);
|
||||
}
|
||||
|
||||
std::vector<std::vector<Cluster::pointer>> Artist::getClusterGroups(std::vector<ClusterTypeId> clusterTypeIds, std::size_t size) const
|
||||
@@ -338,4 +338,4 @@ namespace Database
|
||||
_sortName = std::string(sortName, 0, _maxNameLength);
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
AuthToken::AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "SqlQuery.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -101,7 +101,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
auto query{ createQuery<ClusterId>(session, params) };
|
||||
|
||||
return Utils::execQuery<ClusterId>(query, params.range);
|
||||
return utils::execQuery<ClusterId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<Cluster::pointer> Cluster::find(Session& session, const FindParameters& params)
|
||||
@@ -109,7 +109,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Cluster>>(session, params) };
|
||||
|
||||
return Utils::execQuery<Cluster::pointer>(query, params.range);
|
||||
return utils::execQuery<Cluster::pointer>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<ClusterId> Cluster::findOrphanIds(Session& session, std::optional<Range> range)
|
||||
@@ -117,7 +117,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
auto query{ session.getDboSession().query<ClusterId>("SELECT DISTINCT c.id FROM cluster c WHERE NOT EXISTS(SELECT 1 FROM track_cluster t_c WHERE t_c.cluster_id = c.id)") };
|
||||
|
||||
return Utils::execQuery<ClusterId>(query, range);
|
||||
return utils::execQuery<ClusterId>(query, range);
|
||||
}
|
||||
|
||||
Cluster::pointer Cluster::find(Session& session, ClusterId id)
|
||||
@@ -155,7 +155,7 @@ namespace Database
|
||||
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::execQuery<TrackId>(query, range);
|
||||
return utils::execQuery<TrackId>(query, range);
|
||||
}
|
||||
|
||||
ClusterType::ClusterType(std::string_view name)
|
||||
@@ -185,7 +185,7 @@ namespace Database
|
||||
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
|
||||
.where("c.id IS NULL") };
|
||||
|
||||
return Utils::execQuery<ClusterTypeId>(query, range);
|
||||
return utils::execQuery<ClusterTypeId>(query, range);
|
||||
}
|
||||
|
||||
RangeResults<ClusterTypeId> ClusterType::findUsed(Session& session, std::optional<Range> range)
|
||||
@@ -196,7 +196,7 @@ namespace Database
|
||||
"SELECT DISTINCT c_t.id from cluster_type c_t")
|
||||
.join("cluster c ON c_t.id = c.cluster_type_id") };
|
||||
|
||||
return Utils::execQuery<ClusterTypeId>(query, range);
|
||||
return utils::execQuery<ClusterTypeId>(query, range);
|
||||
}
|
||||
|
||||
ClusterType::pointer ClusterType::find(Session& session, std::string_view name)
|
||||
@@ -219,7 +219,7 @@ namespace Database
|
||||
|
||||
auto query{ session.getDboSession().query<ClusterTypeId>("SELECT id from cluster_type") };
|
||||
|
||||
return Utils::execQuery<ClusterTypeId>(query, range);
|
||||
return utils::execQuery<ClusterTypeId>(query, range);
|
||||
}
|
||||
|
||||
Cluster::pointer ClusterType::getCluster(const std::string& name) const
|
||||
@@ -244,4 +244,4 @@ namespace Database
|
||||
|
||||
return std::vector<Cluster::pointer>(res.begin(), res.end());
|
||||
}
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/IConfig.hpp"
|
||||
#include "utils/Service.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/IConfig.hpp"
|
||||
#include "core/Service.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -89,7 +89,7 @@ namespace Database
|
||||
LMS_LOG(DB, INFO, "Creating connection pool on file " << dbPath.string());
|
||||
|
||||
auto connection{ std::make_unique<Connection>(dbPath.string()) };
|
||||
if (IConfig * config{ Service<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) };
|
||||
@@ -138,4 +138,4 @@ namespace Database
|
||||
return _connection.get();
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -22,22 +22,22 @@
|
||||
#include <type_traits>
|
||||
#include <Wt/Dbo/StdSqlTraits.h>
|
||||
|
||||
#include "utils/EnumSet.hpp"
|
||||
#include "core/EnumSet.hpp"
|
||||
|
||||
namespace Wt::Dbo
|
||||
{
|
||||
template<typename T>
|
||||
struct sql_value_traits<EnumSet<T>, void> : public sql_value_traits<long long>
|
||||
struct sql_value_traits<lms::core::EnumSet<T>, void> : public sql_value_traits<long long>
|
||||
{
|
||||
using ValueType = typename EnumSet<T>::ValueType;
|
||||
using ValueType = typename lms::core::EnumSet<T>::ValueType;
|
||||
static_assert(sizeof(long long) > sizeof(ValueType));
|
||||
|
||||
static void bind(EnumSet<T> v, SqlStatement* statement, int column, int size)
|
||||
static void bind(lms::core::EnumSet<T> v, SqlStatement* statement, int column, int size)
|
||||
{
|
||||
sql_value_traits<long long>::bind(static_cast<long long>(v.getBitfield()), statement, column, size);
|
||||
}
|
||||
|
||||
static bool read(EnumSet<T>& v, SqlStatement* statement, int column, int size)
|
||||
static bool read(lms::core::EnumSet<T>& v, SqlStatement* statement, int column, int size)
|
||||
{
|
||||
long long val;
|
||||
if (sql_value_traits<long long>::read(val, statement, column, size))
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
namespace Wt::Dbo
|
||||
{
|
||||
template<typename T>
|
||||
struct sql_value_traits<T, typename std::enable_if<std::is_base_of<Database::IdType, T>::value>::type>
|
||||
struct sql_value_traits<T, typename std::enable_if<std::is_base_of<lms::db::IdType, T>::value>::type>
|
||||
{
|
||||
static_assert(!std::is_same_v<Database::IdType, T>, "Cannot use IdType, use derived types");
|
||||
static_assert(!std::is_same_v<lms::db::IdType, T>, "Cannot use IdType, use derived types");
|
||||
static const bool specialized = true;
|
||||
|
||||
static std::string type(SqlConnection* conn, int size)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "SqlQuery.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -205,7 +205,7 @@ namespace Database
|
||||
if (parameters.syncState)
|
||||
query.where("sync_state = ?").bind(*parameters.syncState);
|
||||
|
||||
return Utils::execQuery<ListenId>(query, parameters.range);
|
||||
return utils::execQuery<ListenId>(query, parameters.range);
|
||||
}
|
||||
|
||||
Listen::pointer Listen::find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
|
||||
@@ -229,7 +229,7 @@ namespace Database
|
||||
.orderBy("COUNT(a.id) DESC")
|
||||
.groupBy("a.id") };
|
||||
|
||||
return Utils::execQuery<ArtistId>(query, params.range);
|
||||
return utils::execQuery<ArtistId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<ReleaseId> Listen::getTopReleases(Session& session, const StatsFindParameters& params)
|
||||
@@ -239,7 +239,7 @@ namespace Database
|
||||
.orderBy("COUNT(r.id) DESC")
|
||||
.groupBy("r.id") };
|
||||
|
||||
return Utils::execQuery<ReleaseId>(query, params.range);
|
||||
return utils::execQuery<ReleaseId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<TrackId> Listen::getTopTracks(Session& session, const StatsFindParameters& params)
|
||||
@@ -249,7 +249,7 @@ namespace Database
|
||||
.orderBy("COUNT(t.id) DESC")
|
||||
.groupBy("t.id") };
|
||||
|
||||
return Utils::execQuery<TrackId>(query, params.range);
|
||||
return utils::execQuery<TrackId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<ArtistId> Listen::getRecentArtists(Session& session, const ArtistStatsFindParameters& params)
|
||||
@@ -259,7 +259,7 @@ namespace Database
|
||||
.groupBy("a.id").having("l.date_time = MAX(l.date_time)")
|
||||
.orderBy("l.date_time DESC") };
|
||||
|
||||
return Utils::execQuery<ArtistId>(query, params.range);
|
||||
return utils::execQuery<ArtistId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<ReleaseId> Listen::getRecentReleases(Session& session, const StatsFindParameters& params)
|
||||
@@ -269,7 +269,7 @@ namespace Database
|
||||
.groupBy("r.id").having("l.date_time = MAX(l.date_time)")
|
||||
.orderBy("l.date_time DESC") };
|
||||
|
||||
return Utils::execQuery<ReleaseId>(query, params.range);
|
||||
return utils::execQuery<ReleaseId>(query, params.range);
|
||||
}
|
||||
|
||||
RangeResults<TrackId> Listen::getRecentTracks(Session& session, const StatsFindParameters& params)
|
||||
@@ -279,7 +279,7 @@ namespace Database
|
||||
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
|
||||
.orderBy("l.date_time DESC") };
|
||||
|
||||
return Utils::execQuery<TrackId>(query, params.range);
|
||||
return utils::execQuery<TrackId>(query, params.range);
|
||||
}
|
||||
|
||||
std::size_t Listen::getCount(Session& session, UserId userId, TrackId trackId)
|
||||
@@ -339,4 +339,4 @@ namespace Database
|
||||
.limit(1)
|
||||
.resultValue();
|
||||
}
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "PathTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name)
|
||||
: _path{ p },
|
||||
@@ -75,4 +75,4 @@ namespace Database
|
||||
for (const auto& result : results)
|
||||
func(result);
|
||||
}
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#include "database/ScanSettings.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/Exception.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -58,7 +58,7 @@ namespace Database
|
||||
}
|
||||
}
|
||||
|
||||
namespace Database::Migration
|
||||
namespace lms::db::Migration
|
||||
{
|
||||
class ScopedNoForeignKeys
|
||||
{
|
||||
@@ -473,14 +473,14 @@ SELECT
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LMS_LOG(DB, ERROR, "Cannot get database version info: " << e.what());
|
||||
throw LmsException{ outdatedMsg };
|
||||
throw core::LmsException{ outdatedMsg };
|
||||
}
|
||||
|
||||
if (version > LMS_DATABASE_VERSION)
|
||||
throw LmsException{ "Server binary outdated, please upgrade it to handle this database" };
|
||||
throw core::LmsException{ "Server binary outdated, please upgrade it to handle this database" };
|
||||
|
||||
if (version < migrationFunctions.begin()->first)
|
||||
throw LmsException{ outdatedMsg };
|
||||
throw core::LmsException{ outdatedMsg };
|
||||
|
||||
while (version < LMS_DATABASE_VERSION)
|
||||
{
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "EnumSetTraits.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -76,7 +76,7 @@ namespace Database
|
||||
}
|
||||
|
||||
for (std::string_view keyword : params.keywords)
|
||||
query.where("r.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + Utils::escapeLikeKeyword(keyword) + "%");
|
||||
query.where("r.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");
|
||||
|
||||
if (params.starringUser.isValid())
|
||||
{
|
||||
@@ -227,13 +227,13 @@ namespace Database
|
||||
.resultValue();
|
||||
}
|
||||
|
||||
Release::Release(const std::string& name, const std::optional<UUID>& MBID)
|
||||
Release::Release(const std::string& name, const std::optional<core::UUID>& MBID)
|
||||
: _name{ std::string(name, 0 , _maxNameLength) },
|
||||
_MBID{ MBID ? MBID->getAsString() : "" }
|
||||
{
|
||||
}
|
||||
|
||||
Release::pointer Release::create(Session& session, const std::string& name, const std::optional<UUID>& MBID)
|
||||
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 }});
|
||||
}
|
||||
@@ -246,13 +246,13 @@ namespace Database
|
||||
.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.file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(Utils::escapeLikeKeyword(releaseDirectory.string()) + "%")
|
||||
.where("t.file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%")
|
||||
.resultList() };
|
||||
|
||||
return std::vector<Release::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
Release::pointer Release::find(Session& session, const UUID& mbid)
|
||||
Release::pointer Release::find(Session& session, const core::UUID& mbid)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
@@ -290,7 +290,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ session.getDboSession().query<ReleaseId>("select r.id from release r LEFT OUTER JOIN Track t ON r.id = t.release_id WHERE t.id IS NULL") };
|
||||
return Utils::execQuery<ReleaseId>(query, range);
|
||||
return utils::execQuery<ReleaseId>(query, range);
|
||||
}
|
||||
|
||||
RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params)
|
||||
@@ -298,7 +298,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) };
|
||||
return Utils::execQuery<pointer>(query, params.range);
|
||||
return utils::execQuery<pointer>(query, params.range);
|
||||
}
|
||||
|
||||
void Release::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func)
|
||||
@@ -306,7 +306,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) };
|
||||
Utils::execQuery<pointer>(query, params.range, func);
|
||||
utils::execQuery<pointer>(query, params.range, func);
|
||||
}
|
||||
|
||||
RangeResults<ReleaseId> Release::findIds(Session& session, const FindParameters& params)
|
||||
@@ -314,7 +314,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<ReleaseId>(session, "DISTINCT r.id", params) };
|
||||
return Utils::execQuery<ReleaseId>(query, params.range);
|
||||
return utils::execQuery<ReleaseId>(query, params.range);
|
||||
}
|
||||
|
||||
std::size_t Release::getCount(Session& session, const FindParameters& params)
|
||||
@@ -602,4 +602,4 @@ namespace Database
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#include "database/MediaLibrary.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "utils/String.hpp"
|
||||
#include "core/String.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
void ScanSettings::init(Session& session)
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace Database
|
||||
|
||||
std::vector<std::filesystem::path> ScanSettings::getAudioFileExtensions() const
|
||||
{
|
||||
const auto extensions{ StringUtils::splitString(_audioFileExtensions, ' ') };
|
||||
const auto extensions{ core::stringUtils::splitString(_audioFileExtensions, ' ') };
|
||||
|
||||
std::vector<std::filesystem::path> res(std::cbegin(extensions), std::cend(extensions));
|
||||
std::sort(std::begin(res), std::end(res));
|
||||
@@ -57,22 +57,22 @@ namespace Database
|
||||
|
||||
std::vector<std::string_view> ScanSettings::getExtraTagsToScan() const
|
||||
{
|
||||
return StringUtils::splitString(_extraTagsToScan, ';');
|
||||
return core::stringUtils::splitString(_extraTagsToScan, ';');
|
||||
}
|
||||
|
||||
std::vector<std::string> ScanSettings::getArtistTagDelimiters() const
|
||||
{
|
||||
return StringUtils::splitEscapedStrings(_artistTagDelimiters, ';', '\\');
|
||||
return core::stringUtils::splitEscapedStrings(_artistTagDelimiters, ';', '\\');
|
||||
}
|
||||
|
||||
std::vector<std::string> ScanSettings::getDefaultTagDelimiters() const
|
||||
{
|
||||
return StringUtils::splitEscapedStrings(_defaultTagDelimiters, ';', '\\');
|
||||
return core::stringUtils::splitEscapedStrings(_defaultTagDelimiters, ';', '\\');
|
||||
}
|
||||
|
||||
void ScanSettings::setExtraTagsToScan(const std::vector<std::string_view>& extraTags)
|
||||
{
|
||||
std::string newTagsToScan{ StringUtils::joinStrings(extraTags, ";") };
|
||||
std::string newTagsToScan{ core::stringUtils::joinStrings(extraTags, ";") };
|
||||
if (newTagsToScan != _extraTagsToScan)
|
||||
incScanVersion();
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace Database
|
||||
|
||||
void ScanSettings::setArtistTagDelimiters(std::span<const std::string_view> delimiters)
|
||||
{
|
||||
std::string tagDelimiters{ StringUtils::escapeAndJoinStrings(delimiters, ';', '\\') };
|
||||
std::string tagDelimiters{ core::stringUtils::escapeAndJoinStrings(delimiters, ';', '\\') };
|
||||
if (tagDelimiters != _artistTagDelimiters)
|
||||
{
|
||||
_artistTagDelimiters.swap(tagDelimiters);
|
||||
@@ -91,7 +91,7 @@ namespace Database
|
||||
|
||||
void ScanSettings::setDefaultTagDelimiters(std::span<const std::string_view> delimiters)
|
||||
{
|
||||
std::string tagDelimiters{ StringUtils::escapeAndJoinStrings(delimiters, ';', '\\') };
|
||||
std::string tagDelimiters{ core::stringUtils::escapeAndJoinStrings(delimiters, ';', '\\') };
|
||||
if (tagDelimiters != _defaultTagDelimiters)
|
||||
{
|
||||
_defaultTagDelimiters.swap(tagDelimiters);
|
||||
@@ -103,4 +103,4 @@ namespace Database
|
||||
{
|
||||
_scanVersion += 1;
|
||||
}
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "utils/ITraceLogger.hpp"
|
||||
#include "core/Exception.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "core/ITraceLogger.hpp"
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/AuthToken.hpp"
|
||||
@@ -47,10 +47,9 @@
|
||||
#include "PathTraits.hpp"
|
||||
#include "Migration.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
WriteTransaction::WriteTransaction(RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
|
||||
WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
|
||||
: _lock{ mutex },
|
||||
_transaction{ session }
|
||||
{
|
||||
@@ -210,4 +209,4 @@ namespace Database
|
||||
LMS_LOG(DB, INFO, "Database optimizing complete");
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
+127
-138
@@ -23,177 +23,166 @@
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
|
||||
WhereClause&
|
||||
WhereClause::And(const WhereClause& otherClause)
|
||||
namespace lms::db
|
||||
{
|
||||
if (!otherClause._clause.empty()) {
|
||||
if (!_clause.empty())
|
||||
_clause += " AND ";
|
||||
_clause += "(" + otherClause._clause + ")";
|
||||
WhereClause& WhereClause::And(const WhereClause& otherClause)
|
||||
{
|
||||
if (!otherClause._clause.empty()) {
|
||||
if (!_clause.empty())
|
||||
_clause += " AND ";
|
||||
_clause += "(" + otherClause._clause + ")";
|
||||
|
||||
// Add associated bind args
|
||||
for (const std::string& otherBindArg : otherClause._bindArgs)
|
||||
{
|
||||
_bindArgs.push_back(otherBindArg);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
// Add associated bind args
|
||||
for (const std::string& otherBindArg : otherClause._bindArgs)
|
||||
{
|
||||
_bindArgs.push_back(otherBindArg);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
WhereClause&
|
||||
WhereClause::Or(const WhereClause& otherClause)
|
||||
{
|
||||
if (!otherClause._clause.empty()) {
|
||||
if (!_clause.empty())
|
||||
_clause += " OR ";
|
||||
_clause += "(" + otherClause._clause + ")";
|
||||
WhereClause& WhereClause::Or(const WhereClause& otherClause)
|
||||
{
|
||||
if (!otherClause._clause.empty()) {
|
||||
if (!_clause.empty())
|
||||
_clause += " OR ";
|
||||
_clause += "(" + otherClause._clause + ")";
|
||||
|
||||
// Add associated bind args
|
||||
for (const std::string& otherBindArg : otherClause._bindArgs)
|
||||
{
|
||||
_bindArgs.push_back(otherBindArg);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
// Add associated bind args
|
||||
for (const std::string& otherBindArg : otherClause._bindArgs)
|
||||
{
|
||||
_bindArgs.push_back(otherBindArg);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
WhereClause::get() const
|
||||
{
|
||||
if (!_clause.empty())
|
||||
return "WHERE " + _clause;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
std::string WhereClause::get() const
|
||||
{
|
||||
if (!_clause.empty())
|
||||
return "WHERE " + _clause;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
WhereClause&
|
||||
WhereClause::bind(std::string_view bindArg)
|
||||
{
|
||||
assert(_bindArgs.size() < static_cast<std::size_t>(std::count(_clause.begin(), _clause.end(), '?')));
|
||||
WhereClause& WhereClause::bind(std::string_view bindArg)
|
||||
{
|
||||
assert(_bindArgs.size() < static_cast<std::size_t>(std::count(_clause.begin(), _clause.end(), '?')));
|
||||
|
||||
_bindArgs.push_back(std::string{ bindArg });
|
||||
_bindArgs.push_back(std::string{ bindArg });
|
||||
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
InnerJoinClause::InnerJoinClause(const std::string& clause)
|
||||
:_clause(clause)
|
||||
{
|
||||
}
|
||||
InnerJoinClause::InnerJoinClause(const std::string& clause)
|
||||
:_clause(clause)
|
||||
{
|
||||
}
|
||||
|
||||
InnerJoinClause&
|
||||
InnerJoinClause::And(const InnerJoinClause& clause)
|
||||
{
|
||||
if (!_clause.empty())
|
||||
_clause += " ";
|
||||
InnerJoinClause& InnerJoinClause::And(const InnerJoinClause& clause)
|
||||
{
|
||||
if (!_clause.empty())
|
||||
_clause += " ";
|
||||
|
||||
_clause += "INNER JOIN " + clause._clause;
|
||||
_clause += "INNER JOIN " + clause._clause;
|
||||
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SelectStatement::SelectStatement(const std::string& statement)
|
||||
{
|
||||
And(statement);
|
||||
}
|
||||
SelectStatement::SelectStatement(const std::string& statement)
|
||||
{
|
||||
And(statement);
|
||||
}
|
||||
|
||||
SelectStatement&
|
||||
SelectStatement::And(const std::string& statement)
|
||||
{
|
||||
_statement.push_back(statement);
|
||||
SelectStatement& SelectStatement::And(const std::string& statement)
|
||||
{
|
||||
_statement.push_back(statement);
|
||||
|
||||
std::sort(_statement.begin(), _statement.end());
|
||||
_statement.erase(std::unique(_statement.begin(), _statement.end()), _statement.end());
|
||||
std::sort(_statement.begin(), _statement.end());
|
||||
_statement.erase(std::unique(_statement.begin(), _statement.end()), _statement.end());
|
||||
|
||||
return *this;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
SelectStatement::get() const
|
||||
{
|
||||
std::string res = "SELECT ";
|
||||
std::string SelectStatement::get() const
|
||||
{
|
||||
std::string res = "SELECT ";
|
||||
|
||||
for (auto it = _statement.begin(); it != _statement.end(); ++it)
|
||||
{
|
||||
if (it != _statement.begin())
|
||||
res += ",";
|
||||
res += *it;
|
||||
}
|
||||
for (auto it = _statement.begin(); it != _statement.end(); ++it)
|
||||
{
|
||||
if (it != _statement.begin())
|
||||
res += ",";
|
||||
res += *it;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
GroupByStatement& GroupByStatement::And(const GroupByStatement& statement)
|
||||
{
|
||||
if (_statement.empty() && !statement._statement.empty())
|
||||
_statement = "GROUP BY ";
|
||||
else if (!_statement.empty() && !statement._statement.empty())
|
||||
_statement += ",";
|
||||
|
||||
_statement += statement._statement;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GroupByStatement&
|
||||
GroupByStatement::And(const GroupByStatement& statement)
|
||||
{
|
||||
if( _statement.empty() && !statement._statement.empty())
|
||||
_statement = "GROUP BY ";
|
||||
else if (!_statement.empty() && !statement._statement.empty())
|
||||
_statement += ",";
|
||||
FromClause::FromClause(const std::string& clause)
|
||||
{
|
||||
_clause.push_back(clause);
|
||||
}
|
||||
|
||||
_statement += statement._statement;
|
||||
return *this;
|
||||
}
|
||||
FromClause& FromClause::And(const FromClause& clause)
|
||||
{
|
||||
for (const std::string& fromClause : clause._clause)
|
||||
{
|
||||
_clause.push_back(fromClause);
|
||||
}
|
||||
|
||||
FromClause::FromClause(const std::string& clause)
|
||||
{
|
||||
_clause.push_back(clause);
|
||||
}
|
||||
std::sort(_clause.begin(), _clause.end());
|
||||
_clause.erase(std::unique(_clause.begin(), _clause.end()), _clause.end());
|
||||
|
||||
FromClause&
|
||||
FromClause::And(const FromClause& clause)
|
||||
{
|
||||
for (const std::string& fromClause : clause._clause)
|
||||
{
|
||||
_clause.push_back(fromClause);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::sort(_clause.begin(), _clause.end());
|
||||
_clause.erase(std::unique(_clause.begin(), _clause.end()), _clause.end());
|
||||
std::string FromClause::get() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
return *this;
|
||||
}
|
||||
if (!_clause.empty())
|
||||
{
|
||||
oss << "FROM ";
|
||||
for (auto it = _clause.begin(); it != _clause.end(); ++it) {
|
||||
if (it != _clause.begin())
|
||||
oss << ",";
|
||||
|
||||
std::string
|
||||
FromClause::get() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << *it;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_clause.empty())
|
||||
{
|
||||
oss << "FROM ";
|
||||
for (auto it = _clause.begin(); it != _clause.end(); ++it) {
|
||||
if (it != _clause.begin())
|
||||
oss << ",";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
oss << *it;
|
||||
}
|
||||
}
|
||||
std::string SqlQuery::get() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
oss << _selectStatement.get();
|
||||
|
||||
std::string
|
||||
SqlQuery::get() const
|
||||
{
|
||||
std::ostringstream oss;
|
||||
if (!_fromClause.get().empty())
|
||||
oss << " " << _fromClause.get();
|
||||
|
||||
oss << _selectStatement.get();
|
||||
if (!_innerJoinClause.get().empty())
|
||||
oss << " " << _innerJoinClause.get();
|
||||
|
||||
if (!_fromClause.get().empty())
|
||||
oss << " " << _fromClause.get();
|
||||
if (!_whereClause.get().empty())
|
||||
oss << " " << _whereClause.get();
|
||||
|
||||
if (!_innerJoinClause.get().empty())
|
||||
oss << " " << _innerJoinClause.get();
|
||||
|
||||
if (!_whereClause.get().empty())
|
||||
oss << " " << _whereClause.get();
|
||||
|
||||
if (!_groupByStatement.get().empty())
|
||||
oss << " " << _groupByStatement.get();
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
if (!_groupByStatement.get().empty())
|
||||
oss << " " << _groupByStatement.get();
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
}
|
||||
@@ -22,102 +22,103 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
class WhereClause
|
||||
namespace lms::db
|
||||
{
|
||||
public:
|
||||
WhereClause() {}
|
||||
WhereClause(const std::string& clause) { _clause = clause; }
|
||||
class WhereClause
|
||||
{
|
||||
public:
|
||||
WhereClause() {}
|
||||
WhereClause(const std::string& clause) { _clause = clause; }
|
||||
|
||||
WhereClause& And(const WhereClause& clause);
|
||||
WhereClause& Or(const WhereClause& clause);
|
||||
WhereClause& And(const WhereClause& clause);
|
||||
WhereClause& Or(const WhereClause& clause);
|
||||
|
||||
// Arguments binding (for each '?' in where clause)
|
||||
WhereClause& bind(std::string_view arg);
|
||||
// Arguments binding (for each '?' in where clause)
|
||||
WhereClause& bind(std::string_view arg);
|
||||
|
||||
std::string get() const;
|
||||
const std::vector<std::string>& getBindArgs() const {return _bindArgs;}
|
||||
std::string get() const;
|
||||
const std::vector<std::string>& getBindArgs() const { return _bindArgs; }
|
||||
|
||||
private:
|
||||
std::string _clause; // WHERE clause
|
||||
std::vector<std::string> _bindArgs;
|
||||
};
|
||||
private:
|
||||
std::string _clause; // WHERE clause
|
||||
std::vector<std::string> _bindArgs;
|
||||
};
|
||||
|
||||
class InnerJoinClause
|
||||
{
|
||||
public:
|
||||
InnerJoinClause() {}
|
||||
InnerJoinClause(const std::string& clause);
|
||||
class InnerJoinClause
|
||||
{
|
||||
public:
|
||||
InnerJoinClause() {}
|
||||
InnerJoinClause(const std::string& clause);
|
||||
|
||||
InnerJoinClause& And(const InnerJoinClause& clause);
|
||||
std::string get() const { return _clause;}
|
||||
InnerJoinClause& And(const InnerJoinClause& clause);
|
||||
std::string get() const { return _clause; }
|
||||
|
||||
private:
|
||||
std::string _clause;
|
||||
};
|
||||
private:
|
||||
std::string _clause;
|
||||
};
|
||||
|
||||
class GroupByStatement
|
||||
{
|
||||
public:
|
||||
GroupByStatement() {}
|
||||
GroupByStatement(const std::string& statement) { _statement = statement; }
|
||||
class GroupByStatement
|
||||
{
|
||||
public:
|
||||
GroupByStatement() {}
|
||||
GroupByStatement(const std::string& statement) { _statement = statement; }
|
||||
|
||||
GroupByStatement& And(const GroupByStatement& statement);
|
||||
GroupByStatement& And(const GroupByStatement& statement);
|
||||
|
||||
std::string get() const {return _statement;}
|
||||
std::string get() const { return _statement; }
|
||||
|
||||
private:
|
||||
std::string _statement; // SELECT statement
|
||||
};
|
||||
private:
|
||||
std::string _statement; // SELECT statement
|
||||
};
|
||||
|
||||
class SelectStatement
|
||||
{
|
||||
public:
|
||||
SelectStatement() {};
|
||||
SelectStatement(const std::string& item);
|
||||
class SelectStatement
|
||||
{
|
||||
public:
|
||||
SelectStatement() {};
|
||||
SelectStatement(const std::string& item);
|
||||
|
||||
SelectStatement& And(const std::string& item);
|
||||
SelectStatement& And(const std::string& item);
|
||||
|
||||
std::string get() const;
|
||||
std::string get() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> _statement;
|
||||
};
|
||||
private:
|
||||
std::vector<std::string> _statement;
|
||||
};
|
||||
|
||||
class FromClause
|
||||
{
|
||||
public:
|
||||
FromClause() {}
|
||||
FromClause(const std::string& clause);
|
||||
class FromClause
|
||||
{
|
||||
public:
|
||||
FromClause() {}
|
||||
FromClause(const std::string& clause);
|
||||
|
||||
FromClause& And(const FromClause& clause);
|
||||
FromClause& And(const FromClause& clause);
|
||||
|
||||
std::string get() const;
|
||||
std::string get() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> _clause;
|
||||
};
|
||||
private:
|
||||
std::vector<std::string> _clause;
|
||||
};
|
||||
|
||||
class SqlQuery
|
||||
{
|
||||
public:
|
||||
SelectStatement& select() { 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; }
|
||||
InnerJoinClause& innerJoin() { return _innerJoinClause; }
|
||||
WhereClause& where() { return _whereClause; }
|
||||
const WhereClause& where() const { return _whereClause; }
|
||||
GroupByStatement& groupBy() { return _groupByStatement; }
|
||||
const GroupByStatement& groupBy() const { return _groupByStatement; }
|
||||
class SqlQuery
|
||||
{
|
||||
public:
|
||||
SelectStatement& select() { 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; }
|
||||
InnerJoinClause& innerJoin() { return _innerJoinClause; }
|
||||
WhereClause& where() { return _whereClause; }
|
||||
const WhereClause& where() const { return _whereClause; }
|
||||
GroupByStatement& groupBy() { return _groupByStatement; }
|
||||
const GroupByStatement& groupBy() const { return _groupByStatement; }
|
||||
|
||||
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
|
||||
};
|
||||
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
|
||||
};
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
StarredArtist::StarredArtist(ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend backend)
|
||||
: _backend{ backend }
|
||||
@@ -76,6 +76,6 @@ namespace Database
|
||||
|
||||
void StarredArtist::setDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
_dateTime = Utils::normalizeDateTime(dateTime);
|
||||
_dateTime = utils::normalizeDateTime(dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
StarredRelease::StarredRelease(ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend)
|
||||
: _backend{ backend }
|
||||
@@ -76,6 +76,6 @@ namespace Database
|
||||
|
||||
void StarredRelease::setDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
_dateTime = Utils::normalizeDateTime(dateTime);
|
||||
_dateTime = utils::normalizeDateTime(dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
StarredTrack::StarredTrack(ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend)
|
||||
: _backend{ backend }
|
||||
@@ -96,11 +96,11 @@ namespace Database
|
||||
if (params.user.isValid())
|
||||
query.where("s_t.user_id = ?").bind(params.user);
|
||||
|
||||
return Utils::execQuery<StarredTrackId>(query, params.range);
|
||||
return utils::execQuery<StarredTrackId>(query, params.range);
|
||||
}
|
||||
|
||||
void StarredTrack::setDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
_dateTime = Utils::normalizeDateTime(dateTime);
|
||||
_dateTime = utils::normalizeDateTime(dateTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,14 +29,14 @@
|
||||
#include "database/TrackFeatures.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/User.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "SqlQuery.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -49,7 +49,7 @@ namespace Database
|
||||
|
||||
assert(params.keywords.empty() || params.name.empty());
|
||||
for (std::string_view keyword : params.keywords)
|
||||
query.where("t.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + Utils::escapeLikeKeyword(keyword) + "%");
|
||||
query.where("t.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");
|
||||
|
||||
if (!params.name.empty())
|
||||
query.where("t.name = ?").bind(params.name);
|
||||
@@ -235,7 +235,7 @@ namespace Database
|
||||
return session.getDboSession().query<int>("SELECT 1 from track").where("id = ?").bind(id).resultValue() == 1;
|
||||
}
|
||||
|
||||
std::vector<Track::pointer> Track::findByMBID(Session& session, const UUID& mbid)
|
||||
std::vector<Track::pointer> Track::findByMBID(Session& session, const core::UUID& mbid)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
@@ -246,7 +246,7 @@ namespace Database
|
||||
return std::vector<Track::pointer>(res.begin(), res.end());
|
||||
}
|
||||
|
||||
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const UUID& mbid)
|
||||
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
@@ -265,7 +265,7 @@ namespace Database
|
||||
// TODO Dbo traits on filesystem
|
||||
auto query{ session.getDboSession().query<QueryResultType>("SELECT id, file_path FROM track") };
|
||||
|
||||
RangeResults<QueryResultType> queryResults{ Utils::execQuery<QueryResultType>(query, range) };
|
||||
RangeResults<QueryResultType> queryResults{ utils::execQuery<QueryResultType>(query, range) };
|
||||
|
||||
RangeResults<PathResult> res;
|
||||
res.range = queryResults.range;
|
||||
@@ -288,7 +288,7 @@ namespace Database
|
||||
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::execQuery<TrackId>(query, range);
|
||||
return utils::execQuery<TrackId>(query, range);
|
||||
}
|
||||
|
||||
RangeResults<TrackId> Track::findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range)
|
||||
@@ -299,7 +299,7 @@ namespace Database
|
||||
.where("LENGTH(t.recording_mbid) > 0")
|
||||
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
|
||||
|
||||
return Utils::execQuery<TrackId>(query, range);
|
||||
return utils::execQuery<TrackId>(query, range);
|
||||
}
|
||||
|
||||
std::vector<Cluster::pointer> Track::getClusters() const
|
||||
@@ -324,7 +324,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<TrackId>(session, parameters) };
|
||||
return Utils::execQuery<TrackId>(query, parameters.range);
|
||||
return utils::execQuery<TrackId>(query, parameters.range);
|
||||
}
|
||||
|
||||
RangeResults<Track::pointer> Track::find(Session& session, const FindParameters& parameters)
|
||||
@@ -332,7 +332,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, parameters) };
|
||||
return Utils::execQuery<Track::pointer>(query, parameters.range);
|
||||
return utils::execQuery<Track::pointer>(query, parameters.range);
|
||||
}
|
||||
|
||||
void Track::find(Session& session, const FindParameters& params, std::function<void(const Track::pointer&)> func)
|
||||
@@ -340,7 +340,7 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)};
|
||||
Utils::execQuery(query, params.range, func);
|
||||
utils::execQuery(query, params.range, func);
|
||||
}
|
||||
|
||||
RangeResults<TrackId> Track::findSimilarTrackIds(Session& session, const std::vector<TrackId>& tracks, std::optional<Range> range)
|
||||
@@ -370,7 +370,7 @@ namespace Database
|
||||
for (TrackId trackId : tracks)
|
||||
query.bind(trackId);
|
||||
|
||||
return Utils::execQuery<TrackId>(query, range);
|
||||
return utils::execQuery<TrackId>(query, range);
|
||||
}
|
||||
|
||||
void Track::clearArtistLinks()
|
||||
@@ -400,7 +400,7 @@ namespace Database
|
||||
return _copyrightURL != "" ? std::make_optional<std::string>(_copyrightURL) : std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<Artist::pointer> Track::getArtists(EnumSet<TrackArtistLinkType> linkTypes) const
|
||||
std::vector<Artist::pointer> Track::getArtists(core::EnumSet<TrackArtistLinkType> linkTypes) const
|
||||
{
|
||||
assert(session());
|
||||
|
||||
@@ -435,7 +435,7 @@ namespace Database
|
||||
return std::vector<Artist::pointer>(std::begin(res), std::end(res));
|
||||
}
|
||||
|
||||
std::vector<ArtistId> Track::getArtistIds(EnumSet<TrackArtistLinkType> linkTypes) const
|
||||
std::vector<ArtistId> Track::getArtistIds(core::EnumSet<TrackArtistLinkType> linkTypes) const
|
||||
{
|
||||
assert(self());
|
||||
assert(session());
|
||||
@@ -544,4 +544,4 @@ namespace Database
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
namespace
|
||||
{
|
||||
@@ -84,19 +84,19 @@ namespace Database
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto query{ createQuery(session, params) };
|
||||
return Utils::execQuery<TrackArtistLinkId>(query, params.range);
|
||||
return utils::execQuery<TrackArtistLinkId>(query, params.range);
|
||||
}
|
||||
|
||||
EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session)
|
||||
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
auto res{ session.getDboSession().query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link").resultList() };
|
||||
|
||||
return EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
|
||||
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
|
||||
}
|
||||
|
||||
EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId)
|
||||
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId)
|
||||
{
|
||||
session.checkReadTransaction();
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Database
|
||||
.where("artist_id = ?").bind(artistId)
|
||||
.resultList() };
|
||||
|
||||
return EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
|
||||
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
TrackBookmark::TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track)
|
||||
: _user{ getDboPtr(user) },
|
||||
_track{ getDboPtr(track) }
|
||||
@@ -52,7 +52,7 @@ namespace Database {
|
||||
auto query{ session.getDboSession().query<TrackBookmarkId>("SELECT id from track_bookmark")
|
||||
.where("user_id = ?").bind(userId) };
|
||||
|
||||
return Utils::execQuery<TrackBookmarkId>(query, range);
|
||||
return utils::execQuery<TrackBookmarkId>(query, range);
|
||||
}
|
||||
|
||||
TrackBookmark::pointer TrackBookmark::find(Session& session, UserId userId, TrackId trackId)
|
||||
@@ -74,5 +74,5 @@ namespace Database {
|
||||
.resultValue();
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database {
|
||||
namespace lms::db {
|
||||
|
||||
TrackFeatures::TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
|
||||
: _data{ jsonEncodedFeatures },
|
||||
@@ -72,7 +72,7 @@ namespace Database {
|
||||
|
||||
auto query{ session.getDboSession().query<TrackFeaturesId>("SELECT id from track_features") };
|
||||
|
||||
return Utils::execQuery<TrackFeaturesId>(query, range);
|
||||
return utils::execQuery<TrackFeaturesId>(query, range);
|
||||
}
|
||||
|
||||
FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const
|
||||
@@ -118,4 +118,4 @@ namespace Database {
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
|
||||
#include "database/Artist.hpp"
|
||||
#include "database/Cluster.hpp"
|
||||
@@ -33,14 +33,14 @@
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
|
||||
: _name{ name }
|
||||
, _type{ type }
|
||||
, _isPublic{ isPublic }
|
||||
, _creationDateTime{ Utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
|
||||
, _lastModifiedDateTime{ Utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
|
||||
, _creationDateTime{ utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
|
||||
, _lastModifiedDateTime{ utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
|
||||
, _user{ getDboPtr(user) }
|
||||
{
|
||||
assert(user);
|
||||
@@ -117,7 +117,7 @@ namespace Database
|
||||
break;
|
||||
}
|
||||
|
||||
return Utils::execQuery<TrackListId>(query, params.range);
|
||||
return utils::execQuery<TrackListId>(query, params.range);
|
||||
}
|
||||
|
||||
TrackList::pointer TrackList::find(Session& session, TrackListId id)
|
||||
@@ -170,7 +170,7 @@ namespace Database
|
||||
return session()->find<TrackListEntry>()
|
||||
.where("tracklist_id = ?").bind(getId())
|
||||
.where("track_id = ?").bind(track->getId())
|
||||
.where("date_time = ?").bind(Utils::normalizeDateTime(dateTime))
|
||||
.where("date_time = ?").bind(utils::normalizeDateTime(dateTime))
|
||||
.resultValue();
|
||||
}
|
||||
|
||||
@@ -294,11 +294,11 @@ namespace Database
|
||||
|
||||
void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
_lastModifiedDateTime = Utils::normalizeDateTime(dateTime);
|
||||
_lastModifiedDateTime = utils::normalizeDateTime(dateTime);
|
||||
}
|
||||
|
||||
TrackListEntry::TrackListEntry(ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime)
|
||||
: _dateTime{ Utils::normalizeDateTime(dateTime) }
|
||||
: _dateTime{ utils::normalizeDateTime(dateTime) }
|
||||
, _track{ getDboPtr(track) }
|
||||
, _tracklist{ getDboPtr(tracklist) }
|
||||
{
|
||||
@@ -313,12 +313,12 @@ namespace Database
|
||||
|
||||
void TrackListEntry::onPostCreated()
|
||||
{
|
||||
_tracklist.modify()->setLastModifiedDateTime(Utils::normalizeDateTime(Wt::WDateTime::currentDateTime()));
|
||||
_tracklist.modify()->setLastModifiedDateTime(utils::normalizeDateTime(Wt::WDateTime::currentDateTime()));
|
||||
}
|
||||
|
||||
void TrackListEntry::onPreRemove()
|
||||
{
|
||||
_tracklist.modify()->setLastModifiedDateTime(Utils::normalizeDateTime(Wt::WDateTime::currentDateTime()));
|
||||
_tracklist.modify()->setLastModifiedDateTime(utils::normalizeDateTime(Wt::WDateTime::currentDateTime()));
|
||||
}
|
||||
|
||||
TrackListEntry::pointer TrackListEntry::getById(Session& session, TrackListEntryId id)
|
||||
@@ -327,5 +327,4 @@ namespace Database
|
||||
|
||||
return session.getDboSession().find<TrackListEntry>().where("id = ?").bind(id).resultValue();
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#define LMS_CHECK_TRANSACTION_ACCESSES 0
|
||||
#endif
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
#if LMS_CHECK_TRANSACTION_ACCESSES
|
||||
namespace
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
static const std::set<Bitrate> allowedAudioBitrates
|
||||
{
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include "database/Release.hpp"
|
||||
#include "database/Session.hpp"
|
||||
#include "database/Track.hpp"
|
||||
#include "utils/ILogger.hpp"
|
||||
#include "core/ILogger.hpp"
|
||||
#include "IdTypeTraits.hpp"
|
||||
#include "StringViewTraits.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
namespace Database {
|
||||
namespace lms::db {
|
||||
|
||||
User::User(std::string_view loginName)
|
||||
: _loginName{ loginName }
|
||||
@@ -58,7 +58,7 @@ namespace Database {
|
||||
if (params.feedbackBackend)
|
||||
query.where("feedback_backend = ?").bind(*params.feedbackBackend);
|
||||
|
||||
return Utils::execQuery<UserId>(query, params.range);
|
||||
return utils::execQuery<UserId>(query, params.range);
|
||||
}
|
||||
|
||||
User::pointer User::findDemoUser(Session& session)
|
||||
@@ -91,4 +91,4 @@ namespace Database {
|
||||
_authTokens.clear();
|
||||
}
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -19,21 +19,19 @@
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include "utils/String.hpp"
|
||||
#include "core/String.hpp"
|
||||
|
||||
namespace Database::Utils
|
||||
namespace lms::db::utils
|
||||
{
|
||||
std::string
|
||||
escapeLikeKeyword(std::string_view keyword)
|
||||
{
|
||||
return StringUtils::escapeString(keyword, "%_", escapeChar);
|
||||
}
|
||||
std::string escapeLikeKeyword(std::string_view keyword)
|
||||
{
|
||||
return core::stringUtils::escapeString(keyword, "%_", escapeChar);
|
||||
}
|
||||
|
||||
Wt::WDateTime
|
||||
normalizeDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
// force second resolution
|
||||
return Wt::WDateTime::fromTime_t(dateTime.toTime_t());
|
||||
}
|
||||
} // namespace Database::Utils
|
||||
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime)
|
||||
{
|
||||
// force second resolution
|
||||
return Wt::WDateTime::fromTime_t(dateTime.toTime_t());
|
||||
}
|
||||
} // namespace lms::db::Utils
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include "database/Types.hpp"
|
||||
#include "utils/ITraceLogger.hpp"
|
||||
#include "core/ITraceLogger.hpp"
|
||||
|
||||
namespace Database::Utils
|
||||
namespace lms::db::utils
|
||||
{
|
||||
#define ESCAPE_CHAR_STR "\\"
|
||||
static inline constexpr char escapeChar{ '\\' };
|
||||
@@ -86,5 +86,5 @@ namespace Database::Utils
|
||||
}
|
||||
|
||||
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime);
|
||||
} // namespace Database::Utils
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include <Wt/WDateTime.h>
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "core/UUID.hpp"
|
||||
#include "database/ArtistId.hpp"
|
||||
#include "database/ClusterId.hpp"
|
||||
#include "database/MediaLibraryId.hpp"
|
||||
@@ -35,10 +37,8 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
#include "database/TrackId.hpp"
|
||||
#include "utils/EnumSet.hpp"
|
||||
#include "utils/UUID.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
class Cluster;
|
||||
@@ -83,7 +83,7 @@ namespace Database
|
||||
|
||||
// Accessors
|
||||
static std::size_t getCount(Session& session);
|
||||
static pointer find(Session& session, const UUID& MBID);
|
||||
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 RangeResults<pointer> find(Session& session, const FindParameters& parameters);
|
||||
@@ -95,10 +95,10 @@ namespace Database
|
||||
// Accessors
|
||||
const std::string& getName() const { return _name; }
|
||||
const std::string& getSortName() const { return _sortName; }
|
||||
std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); }
|
||||
std::optional<core::UUID> getMBID() const { return core::UUID::fromString(_MBID); }
|
||||
|
||||
// No artistLinkTypes means get them all
|
||||
RangeResults<ArtistId> findSimilarArtistIds(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
|
||||
@@ -106,7 +106,7 @@ namespace Database
|
||||
std::vector<std::vector<ObjectPtr<Cluster>>> getClusterGroups(std::vector<ClusterTypeId> clusterTypeIds, std::size_t size) const;
|
||||
|
||||
void setName(std::string_view name) { _name = name; }
|
||||
void setMBID(const std::optional<UUID>& mbid) { _MBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setMBID(const std::optional<core::UUID>& mbid) { _MBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setSortName(const std::string& sortName);
|
||||
|
||||
template<class Action>
|
||||
@@ -125,8 +125,8 @@ namespace Database
|
||||
|
||||
friend class Session;
|
||||
// Create
|
||||
Artist(const std::string& name, const std::optional<UUID>& MBID = {});
|
||||
static pointer create(Session& session, const std::string& name, const std::optional<UUID>& UUID = {});
|
||||
Artist(const std::string& name, const std::optional<core::UUID>& MBID = {});
|
||||
static pointer create(Session& session, const std::string& name, const std::optional<core::UUID>& UUID = {});
|
||||
|
||||
std::string _name;
|
||||
std::string _sortName;
|
||||
@@ -136,5 +136,5 @@ namespace Database
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<StarredArtist>> _starredArtists; // starred entries for this artist
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "database/AuthTokenId.hpp"
|
||||
#include "database/Object.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "database/TrackId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class Track;
|
||||
class ClusterType;
|
||||
class Session;
|
||||
@@ -149,5 +149,5 @@ namespace Database {
|
||||
Wt::Dbo::collection< Wt::Dbo::ptr<Cluster> > _clusters;
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
|
||||
#include <Wt/Dbo/SqlConnectionPool.h>
|
||||
|
||||
#include "utils/RecursiveSharedMutex.hpp"
|
||||
|
||||
namespace Database {
|
||||
#include "core/RecursiveSharedMutex.hpp"
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
class Db
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace Database {
|
||||
|
||||
friend class Session;
|
||||
|
||||
RecursiveSharedMutex& getMutex() { return _sharedMutex; }
|
||||
core::RecursiveSharedMutex& getMutex() { return _sharedMutex; }
|
||||
Wt::Dbo::SqlConnectionPool& getConnectionPool() { return *_connectionPool; }
|
||||
|
||||
class ScopedConnection
|
||||
@@ -62,13 +62,11 @@ namespace Database {
|
||||
std::unique_ptr<Wt::Dbo::SqlConnection> _connection;
|
||||
};
|
||||
|
||||
RecursiveSharedMutex _sharedMutex;
|
||||
core::RecursiveSharedMutex _sharedMutex;
|
||||
std::unique_ptr<Wt::Dbo::SqlConnectionPool> _connectionPool;
|
||||
|
||||
std::mutex _tlsSessionsMutex;
|
||||
std::vector<std::unique_ptr<Session>> _tlsSessions;
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <functional>
|
||||
#include <Wt/Dbo/ptr.h>
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class IdType
|
||||
{
|
||||
@@ -49,7 +49,7 @@ namespace Database
|
||||
};
|
||||
|
||||
#define LMS_DECLARE_IDTYPE(name) \
|
||||
namespace Database { \
|
||||
namespace lms::db { \
|
||||
class name : public IdType \
|
||||
{ \
|
||||
public: \
|
||||
@@ -59,14 +59,14 @@ namespace Database
|
||||
namespace std \
|
||||
{ \
|
||||
template<> \
|
||||
class hash<Database::name> \
|
||||
class hash<lms::db::name> \
|
||||
{ \
|
||||
public: \
|
||||
size_t operator()(Database::name id) const \
|
||||
size_t operator()(lms::db::name id) const \
|
||||
{ \
|
||||
return std::hash<Database::name::ValueType>()(id.getValue()); \
|
||||
return std::hash<lms::db::name::ValueType>()(id.getValue()); \
|
||||
} \
|
||||
}; \
|
||||
} // ns std
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -34,9 +34,8 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
|
||||
class Session;
|
||||
class Track;
|
||||
class User;
|
||||
@@ -135,5 +134,5 @@ namespace Database
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "database/MediaLibraryId.hpp"
|
||||
#include "database/Object.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
|
||||
@@ -63,11 +63,11 @@ namespace Database
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ::Database::Session;
|
||||
friend class Session;
|
||||
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;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "database/IdType.hpp"
|
||||
#include "database/TransactionChecker.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
template <typename T>
|
||||
class ObjectPtr
|
||||
@@ -57,8 +57,8 @@ namespace Database
|
||||
template <typename T, typename ObjectIdType>
|
||||
class Object : public Wt::Dbo::Dbo<T>
|
||||
{
|
||||
static_assert(std::is_base_of_v<Database::IdType, ObjectIdType>);
|
||||
static_assert(!std::is_same_v<Database::IdType, ObjectIdType>);
|
||||
static_assert(std::is_base_of_v<db::IdType, ObjectIdType>);
|
||||
static_assert(!std::is_same_v<db::IdType, ObjectIdType>);
|
||||
|
||||
public:
|
||||
using pointer = ObjectPtr<T>;
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <Wt/WDateTime.h>
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "core/UUID.hpp"
|
||||
#include "database/ArtistId.hpp"
|
||||
#include "database/ClusterId.hpp"
|
||||
#include "database/MediaLibraryId.hpp"
|
||||
@@ -36,10 +38,8 @@
|
||||
#include "database/ReleaseTypeId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
#include "utils/EnumSet.hpp"
|
||||
#include "utils/UUID.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Artist;
|
||||
class Cluster;
|
||||
@@ -91,8 +91,8 @@ namespace Database
|
||||
UserId starringUser; // only releases starred by this user
|
||||
std::optional<FeedbackBackend> feedbackBackend; // and for this backend
|
||||
ArtistId artist; // only releases that involved this user
|
||||
EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
|
||||
EnumSet<TrackArtistLinkType> excludedTrackArtistLinkTypes; // but not for these link types
|
||||
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
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace Database
|
||||
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, EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}, EnumSet<TrackArtistLinkType> _excludedTrackArtistLinkTypes = {})
|
||||
FindParameters& setArtist(ArtistId _artist, core::EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}, core::EnumSet<TrackArtistLinkType> _excludedTrackArtistLinkTypes = {})
|
||||
{
|
||||
artist = _artist;
|
||||
trackArtistLinkTypes = _trackArtistLinkTypes;
|
||||
@@ -119,7 +119,7 @@ namespace Database
|
||||
// Accessors
|
||||
static std::size_t getCount(Session& session);
|
||||
static bool exists(Session& session, ReleaseId id);
|
||||
static pointer find(Session& session, const UUID& MBID);
|
||||
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 RangeResults<pointer> find(Session& session, const FindParameters& parameters);
|
||||
@@ -145,8 +145,8 @@ namespace Database
|
||||
// Accessors
|
||||
std::string_view getName() const { return _name; }
|
||||
std::string_view getSortName() const { return _sortName; }
|
||||
std::optional<UUID> getMBID() const { return UUID::fromString(_MBID); }
|
||||
std::optional<UUID> getGroupMBID() const { return UUID::fromString(_groupMBID); }
|
||||
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;
|
||||
@@ -160,8 +160,8 @@ namespace Database
|
||||
// Setters
|
||||
void setName(std::string_view name) { _name = name; }
|
||||
void setSortName(std::string_view sortName) { _sortName = sortName; }
|
||||
void setMBID(const std::optional<UUID>& mbid) { _MBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setGroupMBID(const std::optional<UUID>& mbid) { _groupMBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setMBID(const std::optional<core::UUID>& mbid) { _MBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setGroupMBID(const std::optional<core::UUID>& mbid) { _groupMBID = mbid ? mbid->getAsString() : ""; }
|
||||
void setTotalDisc(std::optional<int> totalDisc) { _totalDisc = totalDisc; }
|
||||
void setArtistDisplayName(std::string_view name) { _artistDisplayName = name; }
|
||||
void clearReleaseTypes();
|
||||
@@ -188,8 +188,8 @@ namespace Database
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
Release(const std::string& name, const std::optional<UUID>& MBID = {});
|
||||
static pointer create(Session& session, const std::string& name, const std::optional<UUID>& MBID = {});
|
||||
Release(const std::string& name, const std::optional<core::UUID>& MBID = {});
|
||||
static pointer create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID = {});
|
||||
|
||||
Wt::WDate getDate(bool original) const;
|
||||
std::optional<int> getYear(bool original) const;
|
||||
@@ -207,4 +207,4 @@ namespace Database
|
||||
Wt::Dbo::collection<Wt::Dbo::ptr<ReleaseType>> _releaseTypes; // Release types
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(ReleaseId)
|
||||
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(ReleaseTypeId)
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
LMS_DECLARE_IDTYPE(ScanSettingsId)
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
|
||||
@@ -104,4 +104,4 @@ namespace Database
|
||||
std::string _artistTagDelimiters;
|
||||
std::string _defaultTagDelimiters;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/Dbo/SqlConnectionPool.h>
|
||||
|
||||
#include "utils/ITraceLogger.hpp"
|
||||
#include "utils/RecursiveSharedMutex.hpp"
|
||||
#include "core/ITraceLogger.hpp"
|
||||
#include "core/RecursiveSharedMutex.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/TransactionChecker.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class WriteTransaction
|
||||
{
|
||||
@@ -36,13 +36,13 @@ namespace Database
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
WriteTransaction(RecursiveSharedMutex& mutex, Wt::Dbo::Session& session);
|
||||
WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session);
|
||||
|
||||
WriteTransaction(const WriteTransaction&) = delete;
|
||||
WriteTransaction& operator=(const WriteTransaction&) = delete;
|
||||
|
||||
std::unique_lock<RecursiveSharedMutex> _lock;
|
||||
tracing::ScopedTrace _trace{ "Database", tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction
|
||||
std::unique_lock<core::RecursiveSharedMutex> _lock;
|
||||
core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction
|
||||
Wt::Dbo::Transaction _transaction;
|
||||
};
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Database
|
||||
ReadTransaction(const ReadTransaction&) = delete;
|
||||
ReadTransaction& operator=(const ReadTransaction&) = delete;
|
||||
|
||||
tracing::ScopedTrace _trace{ "Database", tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction
|
||||
core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction
|
||||
Wt::Dbo::Transaction _transaction;
|
||||
};
|
||||
|
||||
@@ -103,4 +103,4 @@ namespace Database
|
||||
Db& _db;
|
||||
Wt::Dbo::Session _session;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Artist;
|
||||
class Session;
|
||||
@@ -79,5 +79,5 @@ namespace Database
|
||||
Wt::Dbo::ptr<Artist> _artist;
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(StarredArtistId)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Release;
|
||||
class Session;
|
||||
@@ -79,5 +79,5 @@ namespace Database
|
||||
Wt::Dbo::ptr<Release> _release;
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(StarredReleaseId)
|
||||
|
||||
|
||||
@@ -22,14 +22,14 @@
|
||||
#include <Wt/WDateTime.h>
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "database/TrackId.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/StarredTrackId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
#include "utils/EnumSet.hpp"
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Track;
|
||||
class Session;
|
||||
@@ -94,5 +94,5 @@ namespace Database
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
};
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(StarredTrackId)
|
||||
|
||||
|
||||
@@ -32,9 +32,8 @@
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/Dbo/WtSqlTraits.h>
|
||||
|
||||
#include "utils/EnumSet.hpp"
|
||||
#include "utils/UUID.hpp"
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "core/UUID.hpp"
|
||||
#include "database/ArtistId.hpp"
|
||||
#include "database/ClusterId.hpp"
|
||||
#include "database/MediaLibraryId.hpp"
|
||||
@@ -45,8 +44,8 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class Artist;
|
||||
class Cluster;
|
||||
class ClusterType;
|
||||
@@ -72,7 +71,7 @@ namespace Database {
|
||||
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
|
||||
EnumSet<TrackArtistLinkType> trackArtistLinkTypes; // and for these link types
|
||||
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
|
||||
@@ -88,8 +87,8 @@ namespace Database {
|
||||
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, EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artist = _artist; trackArtistLinkTypes = _trackArtistLinkTypes; return *this; }
|
||||
FindParameters& setArtistName(std::string_view _artistName, EnumSet<TrackArtistLinkType> _trackArtistLinkTypes = {}) { artistName = _artistName; trackArtistLinkTypes = _trackArtistLinkTypes; 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; }
|
||||
@@ -112,8 +111,8 @@ namespace Database {
|
||||
static pointer findByPath(Session& session, const std::filesystem::path& p);
|
||||
static pointer find(Session& session, TrackId id);
|
||||
static bool exists(Session& session, TrackId id);
|
||||
static std::vector<pointer> findByRecordingMBID(Session& session, const UUID& MBID);
|
||||
static std::vector<pointer> findByMBID(Session& session, const UUID& MBID);
|
||||
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);
|
||||
@@ -140,8 +139,8 @@ namespace Database {
|
||||
void setOriginalDate(const Wt::WDate& date) { _originalDate = date; }
|
||||
void setOriginalYear(std::optional<int> year) { _originalYear = year; }
|
||||
void setHasCover(bool hasCover) { _hasCover = hasCover; }
|
||||
void setTrackMBID(const std::optional<UUID>& MBID) { _trackMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setRecordingMBID(const std::optional<UUID>& MBID) { _recordingMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setTrackMBID(const std::optional<core::UUID>& MBID) { _trackMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setRecordingMBID(const std::optional<core::UUID>& MBID) { _recordingMBID = MBID ? MBID->getAsString() : ""; }
|
||||
void setCopyright(const std::string& copyright) { _copyright = std::string(copyright, 0, _maxCopyrightLength); }
|
||||
void setCopyrightURL(const std::string& copyrightURL) { _copyrightURL = std::string(copyrightURL, 0, _maxCopyrightURLLength); }
|
||||
void setTrackReplayGain(std::optional<float> replayGain) { _trackReplayGain = replayGain; }
|
||||
@@ -170,16 +169,16 @@ namespace Database {
|
||||
Wt::WDateTime getLastWriteTime() const { return _fileLastWrite; }
|
||||
Wt::WDateTime getAddedTime() const { return _fileAdded; }
|
||||
bool hasCover() const { return _hasCover; }
|
||||
std::optional<UUID> getTrackMBID() const { return UUID::fromString(_trackMBID); }
|
||||
std::optional<UUID> getRecordingMBID() const { return UUID::fromString(_recordingMBID); }
|
||||
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(EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means all
|
||||
std::vector<ArtistId> getArtistIds(EnumSet<TrackArtistLinkType> artistLinkTypes) const; // no type means 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;
|
||||
@@ -221,7 +220,7 @@ namespace Database {
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ::Database::Session;
|
||||
friend class Session;
|
||||
Track(const std::filesystem::path& p);
|
||||
static pointer create(Session& session, const std::filesystem::path& p);
|
||||
|
||||
@@ -268,7 +267,6 @@ namespace Database {
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const TrackInfo& trackInfo);
|
||||
}
|
||||
|
||||
} // namespace database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
|
||||
#include "core/EnumSet.hpp"
|
||||
#include "database/ArtistId.hpp"
|
||||
#include "database/IdType.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/ReleaseId.hpp"
|
||||
#include "database/TrackId.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "utils/EnumSet.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackArtistLinkId)
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Artist;
|
||||
class Session;
|
||||
@@ -65,8 +65,8 @@ namespace Database
|
||||
static RangeResults<TrackArtistLinkId> find(Session& session, const FindParameters& parameters);
|
||||
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 EnumSet<TrackArtistLinkType> findUsedTypes(Session& session);
|
||||
static EnumSet<TrackArtistLinkType> findUsedTypes(Session& session, ArtistId _artist);
|
||||
static core::EnumSet<TrackArtistLinkType> findUsedTypes(Session& session);
|
||||
static core::EnumSet<TrackArtistLinkType> findUsedTypes(Session& session, ArtistId _artist);
|
||||
|
||||
ObjectPtr<Track> getTrack() const { return _track; }
|
||||
ObjectPtr<Artist> getArtist() const { return _artist; }
|
||||
|
||||
@@ -32,56 +32,54 @@
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackBookmarkId)
|
||||
|
||||
namespace Database {
|
||||
|
||||
class Session;
|
||||
class Track;
|
||||
class User;
|
||||
|
||||
class TrackBookmark final : public Object<TrackBookmark, TrackBookmarkId>
|
||||
namespace lms::db
|
||||
{
|
||||
public:
|
||||
TrackBookmark () = default;
|
||||
class Session;
|
||||
class Track;
|
||||
class User;
|
||||
|
||||
// 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);
|
||||
class TrackBookmark final : public Object<TrackBookmark, TrackBookmarkId>
|
||||
{
|
||||
public:
|
||||
TrackBookmark() = default;
|
||||
|
||||
// Setters
|
||||
void setOffset(std::chrono::milliseconds offset) { _offset = offset; }
|
||||
void setComment(std::string_view comment) { _comment = comment; }
|
||||
// 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);
|
||||
|
||||
// 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; }
|
||||
// Setters
|
||||
void setOffset(std::chrono::milliseconds offset) { _offset = offset; }
|
||||
void setComment(std::string_view comment) { _comment = comment; }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _offset, "offset");
|
||||
Wt::Dbo::field(a, _comment, "comment");
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
// 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; }
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track);
|
||||
static pointer create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track);
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _offset, "offset");
|
||||
Wt::Dbo::field(a, _comment, "comment");
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
Wt::Dbo::belongsTo(a, _user, "user", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
|
||||
static const std::size_t _maxCommentLength = 128;
|
||||
private:
|
||||
friend class Session;
|
||||
TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track);
|
||||
static pointer create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track);
|
||||
|
||||
std::chrono::duration<int, std::milli> _offset;
|
||||
std::string _comment;
|
||||
static const std::size_t _maxCommentLength = 128;
|
||||
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
};
|
||||
|
||||
} // namespace database
|
||||
std::chrono::duration<int, std::milli> _offset;
|
||||
std::string _comment;
|
||||
|
||||
Wt::Dbo::ptr<User> _user;
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
};
|
||||
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -34,49 +34,46 @@
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackFeaturesId)
|
||||
|
||||
namespace Database {
|
||||
|
||||
class Session;
|
||||
class Track;
|
||||
|
||||
using FeatureName = std::string;
|
||||
using FeatureValues = std::vector<double>;
|
||||
using FeatureValuesMap = std::unordered_map<FeatureName, FeatureValues>;
|
||||
|
||||
class TrackFeatures final : public Object<TrackFeatures, TrackFeaturesId>
|
||||
namespace lms::db
|
||||
{
|
||||
public:
|
||||
TrackFeatures() = default;
|
||||
class Session;
|
||||
class Track;
|
||||
|
||||
// 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);
|
||||
using FeatureName = std::string;
|
||||
using FeatureValues = std::vector<double>;
|
||||
using FeatureValuesMap = std::unordered_map<FeatureName, FeatureValues>;
|
||||
|
||||
FeatureValues getFeatureValues(const FeatureName& feature) const;
|
||||
FeatureValuesMap getFeatureValuesMap(const std::unordered_set<FeatureName>& featureNames) const;
|
||||
class TrackFeatures final : public Object<TrackFeatures, TrackFeaturesId>
|
||||
{
|
||||
public:
|
||||
TrackFeatures() = default;
|
||||
|
||||
// Accessors
|
||||
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
||||
// 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);
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _data, "data");
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
FeatureValues getFeatureValues(const FeatureName& feature) const;
|
||||
FeatureValuesMap getFeatureValuesMap(const std::unordered_set<FeatureName>& featureNames) const;
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures);
|
||||
static pointer create(Session& session, ObjectPtr<Track> track, const std::string& jsonEncodedFeatures);
|
||||
// Accessors
|
||||
Wt::Dbo::ptr<Track> getTrack() const { return _track; }
|
||||
|
||||
std::string _data;
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
};
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
{
|
||||
Wt::Dbo::field(a, _data, "data");
|
||||
Wt::Dbo::belongsTo(a, _track, "track", Wt::Dbo::OnDeleteCascade);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Session;
|
||||
TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures);
|
||||
static pointer create(Session& session, ObjectPtr<Track> track, const std::string& jsonEncodedFeatures);
|
||||
|
||||
} // namespace database
|
||||
|
||||
std::string _data;
|
||||
Wt::Dbo::ptr<Track> _track;
|
||||
};
|
||||
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackId)
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class Artist;
|
||||
class Cluster;
|
||||
class ClusterType;
|
||||
@@ -168,5 +168,5 @@ namespace Database {
|
||||
Wt::Dbo::ptr<TrackList> _tracklist;
|
||||
};
|
||||
|
||||
} // namespace Database
|
||||
} // namespace lms::db
|
||||
|
||||
|
||||
@@ -23,4 +23,3 @@
|
||||
|
||||
LMS_DECLARE_IDTYPE(TrackListId)
|
||||
LMS_DECLARE_IDTYPE(TrackListEntryId)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <vector>
|
||||
#include <Wt/Dbo/Session.h>
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
class Session;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <functional>
|
||||
#include <Wt/WDate.h>
|
||||
|
||||
namespace Database
|
||||
namespace lms::db
|
||||
{
|
||||
// Caution: do not change enum values if they are set!
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
#include <Wt/Dbo/Dbo.h>
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
#include "core/UUID.hpp"
|
||||
#include "database/Object.hpp"
|
||||
#include "database/Types.hpp"
|
||||
#include "database/UserId.hpp"
|
||||
#include "utils/UUID.hpp"
|
||||
|
||||
namespace Database {
|
||||
|
||||
namespace lms::db
|
||||
{
|
||||
class AuthToken;
|
||||
class Session;
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Database {
|
||||
void setSubsonicArtistListMode(SubsonicArtistListMode mode) { _subsonicArtistListMode = mode; }
|
||||
void setFeedbackBackend(FeedbackBackend feedbackBackend) { _feedbackBackend = feedbackBackend; }
|
||||
void setScrobblingBackend(ScrobblingBackend scrobblingBackend) { _scrobblingBackend = scrobblingBackend; }
|
||||
void setListenBrainzToken(const std::optional<UUID>& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; }
|
||||
void setListenBrainzToken(const std::optional<core::UUID>& MBID) { _listenbrainzToken = MBID ? MBID->getAsString() : ""; }
|
||||
|
||||
// read
|
||||
bool isAdmin() const { return _type == UserType::ADMIN; }
|
||||
@@ -111,7 +111,7 @@ namespace Database {
|
||||
SubsonicArtistListMode getSubsonicArtistListMode() const { return _subsonicArtistListMode; }
|
||||
FeedbackBackend getFeedbackBackend() const { return _feedbackBackend; }
|
||||
ScrobblingBackend getScrobblingBackend() const { return _scrobblingBackend; }
|
||||
std::optional<UUID> getListenBrainzToken() const { return UUID::fromString(_listenbrainzToken); }
|
||||
std::optional<core::UUID> getListenBrainzToken() const { return core::UUID::fromString(_listenbrainzToken); }
|
||||
|
||||
template<class Action>
|
||||
void persist(Action& a)
|
||||
|
||||
@@ -22,4 +22,3 @@
|
||||
#include "database/IdType.hpp"
|
||||
|
||||
LMS_DECLARE_IDTYPE(UserId)
|
||||
|
||||
|
||||
+495
-495
File diff suppressed because it is too large
Load Diff
+769
-768
File diff suppressed because it is too large
Load Diff
+182
-180
@@ -36,199 +36,201 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
TmpDatabase::TmpDatabase()
|
||||
: _tmpFile{ std::tmpnam(nullptr) }
|
||||
, _fileDeleter{ _tmpFile }
|
||||
, _db{ _tmpFile }
|
||||
namespace lms::db::tests
|
||||
{
|
||||
}
|
||||
|
||||
Database::Db& TmpDatabase::getDb()
|
||||
{
|
||||
return _db;
|
||||
}
|
||||
|
||||
DatabaseFixture::~DatabaseFixture()
|
||||
{
|
||||
testDatabaseEmpty();
|
||||
}
|
||||
|
||||
void DatabaseFixture::SetUpTestCase()
|
||||
{
|
||||
_tmpDb = std::make_unique<TmpDatabase>();
|
||||
TmpDatabase::TmpDatabase()
|
||||
: _tmpFile{ std::tmpnam(nullptr) }
|
||||
, _fileDeleter{ _tmpFile }
|
||||
, _db{ _tmpFile }
|
||||
{
|
||||
Database::Session s{ _tmpDb->getDb() };
|
||||
s.prepareTables();
|
||||
s.analyze();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseFixture::TearDownTestCase()
|
||||
{
|
||||
_tmpDb.reset();
|
||||
}
|
||||
|
||||
void DatabaseFixture::testDatabaseEmpty()
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
EXPECT_EQ(Artist::getCount(session), 0);
|
||||
EXPECT_EQ(Cluster::getCount(session), 0);
|
||||
EXPECT_EQ(ClusterType::getCount(session), 0);
|
||||
EXPECT_EQ(Listen::getCount(session), 0);
|
||||
EXPECT_EQ(MediaLibrary::getCount(session), 0);
|
||||
EXPECT_EQ(Release::getCount(session), 0);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeEmpty)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 0 };
|
||||
results.results = {};
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
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}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeForeach)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
struct TestCase
|
||||
{
|
||||
Range range;
|
||||
std::size_t subRangeSize;
|
||||
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} }},
|
||||
};
|
||||
|
||||
for (const TestCase& test : testCases)
|
||||
{
|
||||
std::vector<Range> subRanges;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_IdType)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
{
|
||||
const IdType id{};
|
||||
EXPECT_FALSE(id.isValid());
|
||||
}
|
||||
|
||||
db::Db& TmpDatabase::getDb()
|
||||
{
|
||||
const IdType id{ 0 };
|
||||
EXPECT_TRUE(id.isValid());
|
||||
return _db;
|
||||
}
|
||||
|
||||
DatabaseFixture::~DatabaseFixture()
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 0 };
|
||||
EXPECT_EQ(id1, id2);
|
||||
testDatabaseEmpty();
|
||||
}
|
||||
|
||||
void DatabaseFixture::SetUpTestCase()
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 1 };
|
||||
EXPECT_NE(id1, id2);
|
||||
EXPECT_LT(id1, id2);
|
||||
EXPECT_GT(id2, id1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRange)
|
||||
{
|
||||
using namespace Database;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 2 };
|
||||
results.results = { 5, 6 };
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
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}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
}
|
||||
{
|
||||
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 {}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 2);
|
||||
EXPECT_EQ(subRange.results.front(), 5);
|
||||
EXPECT_EQ(subRange.results.back(), 6);
|
||||
EXPECT_EQ(subRange.range, results.range);
|
||||
_tmpDb = std::make_unique<TmpDatabase>();
|
||||
{
|
||||
db::Session s{ _tmpDb->getDb() };
|
||||
s.prepareTables();
|
||||
s.analyze();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseFixture::TearDownTestCase()
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {1, 0}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
const Range expectedRange{ 1, 1 };
|
||||
EXPECT_EQ(subRange.range, expectedRange);
|
||||
_tmpDb.reset();
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseFixture::testDatabaseEmpty()
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
EXPECT_EQ(Artist::getCount(session), 0);
|
||||
EXPECT_EQ(Cluster::getCount(session), 0);
|
||||
EXPECT_EQ(ClusterType::getCount(session), 0);
|
||||
EXPECT_EQ(Listen::getCount(session), 0);
|
||||
EXPECT_EQ(MediaLibrary::getCount(session), 0);
|
||||
EXPECT_EQ(Release::getCount(session), 0);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeEmpty)
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 0 };
|
||||
results.results = {};
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
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}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRangeForeach)
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
struct TestCase
|
||||
{
|
||||
Range range;
|
||||
std::size_t subRangeSize;
|
||||
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} }},
|
||||
};
|
||||
|
||||
for (const TestCase& test : testCases)
|
||||
{
|
||||
std::vector<Range> subRanges;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_IdType)
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
{
|
||||
const IdType id{};
|
||||
EXPECT_FALSE(id.isValid());
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id{ 0 };
|
||||
EXPECT_TRUE(id.isValid());
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 0 };
|
||||
EXPECT_EQ(id1, id2);
|
||||
}
|
||||
|
||||
{
|
||||
const IdType id1{ 0 };
|
||||
const IdType id2{ 1 };
|
||||
EXPECT_NE(id1, id2);
|
||||
EXPECT_LT(id1, id2);
|
||||
EXPECT_GT(id2, id1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Common_subRange)
|
||||
{
|
||||
using namespace db;
|
||||
|
||||
RangeResults<int> results;
|
||||
results.range = Range{ 0, 2 };
|
||||
results.results = { 5, 6 };
|
||||
results.moreResults = false;
|
||||
|
||||
{
|
||||
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}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
}
|
||||
{
|
||||
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 {}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 2);
|
||||
EXPECT_EQ(subRange.results.front(), 5);
|
||||
EXPECT_EQ(subRange.results.back(), 6);
|
||||
EXPECT_EQ(subRange.range, results.range);
|
||||
}
|
||||
|
||||
{
|
||||
auto subRange{ results.getSubRange(Range {1, 0}) };
|
||||
EXPECT_FALSE(subRange.moreResults);
|
||||
ASSERT_EQ(subRange.results.size(), 1);
|
||||
EXPECT_EQ(subRange.results.front(), 6);
|
||||
const Range expectedRange{ 1, 1 };
|
||||
EXPECT_EQ(subRange.range, expectedRange);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,117 +40,119 @@
|
||||
#include "database/Types.hpp"
|
||||
#include "database/User.hpp"
|
||||
|
||||
template <typename T>
|
||||
class [[nodiscard]] ScopedEntity
|
||||
namespace lms::db::tests
|
||||
{
|
||||
public:
|
||||
using IdType = typename T::IdType;
|
||||
|
||||
template <typename... Args>
|
||||
ScopedEntity(Database::Session& session, Args&& ...args)
|
||||
: _session{ session }
|
||||
template <typename T>
|
||||
class [[nodiscard]] ScopedEntity
|
||||
{
|
||||
auto transaction{ _session.createWriteTransaction() };
|
||||
public:
|
||||
using IdType = typename T::IdType;
|
||||
|
||||
auto entity{ _session.create<T>(std::forward<Args>(args)...) };
|
||||
EXPECT_TRUE(entity);
|
||||
_id = entity->getId();
|
||||
}
|
||||
template <typename... Args>
|
||||
ScopedEntity(db::Session& session, Args&& ...args)
|
||||
: _session{ session }
|
||||
{
|
||||
auto transaction{ _session.createWriteTransaction() };
|
||||
|
||||
~ScopedEntity()
|
||||
auto entity{ _session.create<T>(std::forward<Args>(args)...) };
|
||||
EXPECT_TRUE(entity);
|
||||
_id = entity->getId();
|
||||
}
|
||||
|
||||
~ScopedEntity()
|
||||
{
|
||||
auto transaction{ _session.createWriteTransaction() };
|
||||
|
||||
auto entity{ T::find(_session, _id) };
|
||||
// could not be here due to "on delete cascade" constraints...
|
||||
if (entity)
|
||||
entity.remove();
|
||||
}
|
||||
|
||||
ScopedEntity(const ScopedEntity&) = delete;
|
||||
ScopedEntity(ScopedEntity&&) = delete;
|
||||
ScopedEntity& operator=(const ScopedEntity&) = delete;
|
||||
ScopedEntity& operator=(ScopedEntity&&) = delete;
|
||||
|
||||
typename T::pointer lockAndGet()
|
||||
{
|
||||
auto transaction{ _session.createReadTransaction() };
|
||||
return get();
|
||||
}
|
||||
|
||||
typename T::pointer get()
|
||||
{
|
||||
_session.checkReadTransaction();
|
||||
|
||||
auto entity{ T::find(_session, _id) };
|
||||
EXPECT_TRUE(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
typename T::pointer operator->()
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
IdType getId() const { return _id; }
|
||||
|
||||
private:
|
||||
db::Session& _session;
|
||||
IdType _id{};
|
||||
};
|
||||
|
||||
using ScopedArtist = ScopedEntity<db::Artist>;
|
||||
using ScopedCluster = ScopedEntity<db::Cluster>;
|
||||
using ScopedClusterType = ScopedEntity<db::ClusterType>;
|
||||
using ScopedMediaLibrary = ScopedEntity<db::MediaLibrary>;
|
||||
using ScopedRelease = ScopedEntity<db::Release>;
|
||||
using ScopedTrack = ScopedEntity<db::Track>;
|
||||
using ScopedTrackList = ScopedEntity<db::TrackList>;
|
||||
using ScopedUser = ScopedEntity<db::User>;
|
||||
|
||||
class ScopedFileDeleter final
|
||||
{
|
||||
auto transaction{ _session.createWriteTransaction() };
|
||||
public:
|
||||
ScopedFileDeleter(const std::filesystem::path& path) : _path{ path } {}
|
||||
~ScopedFileDeleter() { std::filesystem::remove(_path); }
|
||||
|
||||
auto entity{ T::find(_session, _id) };
|
||||
// could not be here due to "on delete cascade" constraints...
|
||||
if (entity)
|
||||
entity.remove();
|
||||
}
|
||||
private:
|
||||
ScopedFileDeleter(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter(ScopedFileDeleter&&) = delete;
|
||||
ScopedFileDeleter operator=(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter operator=(ScopedFileDeleter&&) = delete;
|
||||
|
||||
ScopedEntity(const ScopedEntity&) = delete;
|
||||
ScopedEntity(ScopedEntity&&) = delete;
|
||||
ScopedEntity& operator=(const ScopedEntity&) = delete;
|
||||
ScopedEntity& operator=(ScopedEntity&&) = delete;
|
||||
const std::filesystem::path _path;
|
||||
};
|
||||
|
||||
typename T::pointer lockAndGet()
|
||||
class TmpDatabase final
|
||||
{
|
||||
auto transaction{ _session.createReadTransaction() };
|
||||
return get();
|
||||
}
|
||||
public:
|
||||
TmpDatabase();
|
||||
|
||||
typename T::pointer get()
|
||||
db::Db& getDb();
|
||||
|
||||
private:
|
||||
const std::filesystem::path _tmpFile;
|
||||
ScopedFileDeleter _fileDeleter;
|
||||
db::Db _db;
|
||||
};
|
||||
|
||||
class DatabaseFixture : public ::testing::Test
|
||||
{
|
||||
_session.checkReadTransaction();
|
||||
public:
|
||||
~DatabaseFixture();
|
||||
|
||||
auto entity{ T::find(_session, _id) };
|
||||
EXPECT_TRUE(entity);
|
||||
return entity;
|
||||
}
|
||||
public:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
typename T::pointer operator->()
|
||||
{
|
||||
return get();
|
||||
}
|
||||
private:
|
||||
void testDatabaseEmpty();
|
||||
|
||||
IdType getId() const { return _id; }
|
||||
|
||||
private:
|
||||
Database::Session& _session;
|
||||
IdType _id{};
|
||||
};
|
||||
|
||||
using ScopedArtist = ScopedEntity<Database::Artist>;
|
||||
using ScopedCluster = ScopedEntity<Database::Cluster>;
|
||||
using ScopedClusterType = ScopedEntity<Database::ClusterType>;
|
||||
using ScopedMediaLibrary = ScopedEntity<Database::MediaLibrary>;
|
||||
using ScopedRelease = ScopedEntity<Database::Release>;
|
||||
using ScopedTrack = ScopedEntity<Database::Track>;
|
||||
using ScopedTrackList = ScopedEntity<Database::TrackList>;
|
||||
using ScopedUser = ScopedEntity<Database::User>;
|
||||
|
||||
class ScopedFileDeleter final
|
||||
{
|
||||
public:
|
||||
ScopedFileDeleter(const std::filesystem::path& path) : _path{ path } {}
|
||||
~ScopedFileDeleter() { std::filesystem::remove(_path); }
|
||||
|
||||
private:
|
||||
ScopedFileDeleter(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter(ScopedFileDeleter&&) = delete;
|
||||
ScopedFileDeleter operator=(const ScopedFileDeleter&) = delete;
|
||||
ScopedFileDeleter operator=(ScopedFileDeleter&&) = delete;
|
||||
|
||||
const std::filesystem::path _path;
|
||||
};
|
||||
|
||||
class TmpDatabase final
|
||||
{
|
||||
public:
|
||||
TmpDatabase();
|
||||
|
||||
Database::Db& getDb();
|
||||
|
||||
private:
|
||||
const std::filesystem::path _tmpFile;
|
||||
ScopedFileDeleter _fileDeleter;
|
||||
Database::Db _db;
|
||||
};
|
||||
|
||||
class DatabaseFixture : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
~DatabaseFixture();
|
||||
|
||||
public:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
private:
|
||||
void testDatabaseEmpty();
|
||||
|
||||
static inline std::unique_ptr<TmpDatabase> _tmpDb{};
|
||||
|
||||
public:
|
||||
Database::Session session{ _tmpDb->getDb() };
|
||||
};
|
||||
static inline std::unique_ptr<TmpDatabase> _tmpDb{};
|
||||
|
||||
public:
|
||||
db::Session session{ _tmpDb->getDb() };
|
||||
};
|
||||
}
|
||||
@@ -21,84 +21,85 @@
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
constexpr std::size_t nbTracks{ 10 };
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedArtist artist{ session, "MyArtst" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
for (std::size_t i{}; i < nbTracks; ++i)
|
||||
TEST_F(DatabaseFixture, MultiTracksSingleArtistSingleRelease)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
constexpr std::size_t nbTracks{ 10 };
|
||||
std::list<ScopedTrack> tracks;
|
||||
ScopedArtist artist{ session, "MyArtst" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
for (std::size_t i{}; i < nbTracks; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
tracks.back().get().modify()->setRelease(release.get());
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
TrackArtistLink::create(session, tracks.back().get(), artist.get(), TrackArtistLinkType::Artist);
|
||||
tracks.back().get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
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())) };
|
||||
EXPECT_EQ(releaseTracks.results.size(), nbTracks);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(Release::findOrphanIds(session).results.empty());
|
||||
EXPECT_TRUE(Artist::findOrphanIds(session).results.empty());
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
auto artists{ release->getArtists() };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
ASSERT_EQ(artists.front()->getId(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleUser)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(User::find(session, User::FindParameters{}).results.empty());
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
const auto releaseTracks{ Track::find(session, Track::FindParameters {}.setRelease(release.getId())) };
|
||||
EXPECT_EQ(releaseTracks.results.size(), nbTracks);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackSingleReleaseSingleArtist)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto trackArtistLink{ TrackArtistLink::create(session, track.get(), artist.get(), TrackArtistLinkType::Artist) };
|
||||
track.get().modify()->setRelease(release.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setArtist(artist.getId())) };
|
||||
ASSERT_EQ(releases.results.size(), 1);
|
||||
EXPECT_EQ(releases.results.front(), release.getId());
|
||||
|
||||
auto artists{ release->getArtists() };
|
||||
ASSERT_EQ(artists.size(), 1);
|
||||
ASSERT_EQ(artists.front()->getId(), artist.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleUser)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_TRUE(User::find(session, User::FindParameters{}).results.empty());
|
||||
EXPECT_EQ(User::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(User::find(session, User::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(User::getCount(session), 1);
|
||||
EXPECT_EQ(User::find(session, User::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(User::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,4 +107,4 @@ int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
||||
+1525
-1525
File diff suppressed because it is too large
Load Diff
+763
-761
File diff suppressed because it is too large
Load Diff
@@ -20,129 +20,130 @@
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredArtist.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredArtist = ScopedEntity<Database::StarredArtist>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
using ScopedStarredArtist = ScopedEntity<db::StarredArtist>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
auto starredArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredArtist);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
auto starredArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredArtist);
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 0);
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist, Artist::pointer{});
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::Internal);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
}
|
||||
}
|
||||
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
TEST_F(DatabaseFixture, StarredArtist_PendingDestroy)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
EXPECT_EQ(StarredArtist::getCount(session), 1);
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
starredArtist.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist_dateTime)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedArtist artist1{ session, "MyArtist1" };
|
||||
ScopedArtist artist2{ session, "MyArtist2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
ScopedStarredArtist starredArtist1{ session, artist1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredArtist starredArtist2{ session, artist2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist, Artist::pointer{});
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::Internal);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
auto gotArtist{ StarredArtist::find(session, artist->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotArtist->getId(), starredArtist->getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist_PendingDestroy)
|
||||
{
|
||||
ScopedArtist artist{ session, "MyArtist" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredArtist starredArtist{ session, artist.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto artists{ Artist::findIds(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 1);
|
||||
|
||||
starredArtist.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
artists = Artist::findIds(session, Artist::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(artists.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredArtist_dateTime)
|
||||
{
|
||||
ScopedArtist artist1{ session, "MyArtist1" };
|
||||
ScopedArtist artist2{ session, "MyArtist2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
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} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto artists{ Artist::find(session, Artist::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(artists.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist1->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist2->getArtist()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(artists.results.size(), 2);
|
||||
EXPECT_EQ(artists.results[0], starredArtist2->getArtist()->getId());
|
||||
EXPECT_EQ(artists.results[1], starredArtist1->getArtist()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,118 +20,119 @@
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredRelease.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredRelease = ScopedEntity<Database::StarredRelease>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
using ScopedStarredRelease = ScopedEntity<db::StarredRelease>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
auto starredRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredRelease);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
auto starredRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredRelease);
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 0);
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotRelease->getId(), starredRelease->getId());
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredRelease::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
TEST_F(DatabaseFixture, Starredrelease_PendingDestroy)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotRelease->getId(), starredRelease->getId());
|
||||
EXPECT_EQ(StarredRelease::getCount(session), 1);
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
starredRelease.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease_dateTime)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
ScopedStarredRelease starredRelease1{ session, release1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredRelease starredRelease2{ session, release2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease1->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease2->getRelease()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease2->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease1->getRelease()->getId());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredRelease::find(session, release->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredRelease::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Starredrelease_PendingDestroy)
|
||||
{
|
||||
ScopedRelease release{ session, "MyRelease" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredRelease starredRelease{ session, release.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto releases{ Release::find(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 1);
|
||||
|
||||
starredRelease.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
releases = Release::find(session, Release::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(releases.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredRelease_dateTime)
|
||||
{
|
||||
ScopedRelease release1{ session, "MyRelease1" };
|
||||
ScopedRelease release2{ session, "MyRelease2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
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} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto releases{ Release::findIds(session, Release::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(releases.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease1->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease2->getRelease()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(releases.results.size(), 2);
|
||||
EXPECT_EQ(releases.results[0], starredRelease2->getRelease()->getId());
|
||||
EXPECT_EQ(releases.results[1], starredRelease1->getRelease()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,118 +20,119 @@
|
||||
#include "Common.hpp"
|
||||
#include "database/StarredTrack.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
using ScopedStarredTrack = ScopedEntity<Database::StarredTrack>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
using ScopedStarredTrack = ScopedEntity<db::StarredTrack>;
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack)
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedUser user2{ session, "MyUser2" };
|
||||
|
||||
auto starredTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredTrack);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
auto starredTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_FALSE(starredTrack);
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 0);
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotTrack->getId(), starredTrack->getId());
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredTrack::find(session, track->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredTrack::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
TEST_F(DatabaseFixture, Starredtrack_PendingDestroy)
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
auto gotTrack{ StarredTrack::find(session, track->getId(), user->getId(), FeedbackBackend::Internal) };
|
||||
EXPECT_EQ(gotTrack->getId(), starredTrack->getId());
|
||||
EXPECT_EQ(StarredTrack::getCount(session), 1);
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
starredTrack.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack_dateTime)
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
ScopedStarredTrack starredTrack1{ session, track1.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
ScopedStarredTrack starredTrack2{ session, track2.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 2}, Wt::WTime {12, 30, 1} };
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user2.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack1->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack2->getTrack()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack2->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack1->getTrack()->getId());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
user.get().modify()->setFeedbackBackend(FeedbackBackend::ListenBrainz);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto gotRelease{ StarredTrack::find(session, track->getId(), user->getId()) };
|
||||
EXPECT_EQ(gotRelease, StarredTrack::pointer{});
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Starredtrack_PendingDestroy)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedStarredTrack starredTrack{ session, track.lockAndGet(), user.lockAndGet(), FeedbackBackend::Internal };
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
|
||||
starredTrack.get().modify()->setSyncState(SyncState::PendingRemove);
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setStarringUser(user.getId(), FeedbackBackend::Internal));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, StarredTrack_dateTime)
|
||||
{
|
||||
ScopedTrack track1{ session, "MyTrack1" };
|
||||
ScopedTrack track2{ session, "MyTrack2" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
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} };
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setStarringUser(user.getId(), FeedbackBackend::Internal)) };
|
||||
EXPECT_EQ(tracks.results.size(), 2);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack1->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack2->getTrack()->getId());
|
||||
}
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
|
||||
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)) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], starredTrack2->getTrack()->getId());
|
||||
EXPECT_EQ(tracks.results[1], starredTrack1->getTrack()->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
+193
-193
@@ -21,224 +21,224 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, Track)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
TEST_F(DatabaseFixture, Track)
|
||||
{
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::findIds(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_FALSE(Track::exists(session, 0));
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) {visited = true;});
|
||||
EXPECT_FALSE(visited);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(Track::getCount(session), 1);
|
||||
EXPECT_TRUE(Track::exists(session, track.getId()));
|
||||
auto myTrack{ Track::find(session, track.getId()) };
|
||||
ASSERT_TRUE(myTrack);
|
||||
EXPECT_EQ(myTrack->getId(), track.getId());
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t)
|
||||
{
|
||||
visited = true;
|
||||
EXPECT_EQ(t->getId(), track.getId());
|
||||
});
|
||||
EXPECT_TRUE(visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_MediaLibrary)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
ScopedMediaLibrary library{ session };
|
||||
ScopedMediaLibrary otherLibrary{ session };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setMediaLibrary(library.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(library->getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(otherLibrary->getId())) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_noMediaLibrary)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
MediaLibrary::pointer mediaLibrary{ track->getMediaLibrary() };
|
||||
EXPECT_EQ(mediaLibrary, MediaLibrary::pointer{});
|
||||
EXPECT_FALSE(mediaLibrary);
|
||||
EXPECT_TRUE(!mediaLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackNotExists)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_FALSE(Track::exists(session, TrackId{ 42 }));
|
||||
EXPECT_EQ(Track::find(session, TrackId{ 42 }), Track::pointer{});
|
||||
EXPECT_FALSE(Track::find(session, TrackId{ 42 }));
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::findIds(session, Track::FindParameters{}).results.size(), 0);
|
||||
EXPECT_EQ(Track::getCount(session), 0);
|
||||
EXPECT_FALSE(Track::exists(session, 0));
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer&) {visited = true;});
|
||||
EXPECT_FALSE(visited);
|
||||
auto track{ Track::find(session, TrackId{ 42 }) };
|
||||
EXPECT_TRUE(!track);
|
||||
EXPECT_FALSE(track);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracks)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 1);
|
||||
EXPECT_EQ(Track::getCount(session), 1);
|
||||
EXPECT_TRUE(Track::exists(session, track.getId()));
|
||||
auto myTrack{ Track::find(session, track.getId()) };
|
||||
ASSERT_TRUE(myTrack);
|
||||
EXPECT_EQ(myTrack->getId(), track.getId());
|
||||
ScopedTrack track1{ session, "MyTrackFile1" };
|
||||
ScopedTrack track2{ session, "MyTrackFile2" };
|
||||
|
||||
{
|
||||
bool visited{};
|
||||
Track::find(session, Track::FindParameters{}, [&](const Track::pointer& t)
|
||||
{
|
||||
visited = true;
|
||||
EXPECT_EQ(t->getId(), track.getId());
|
||||
});
|
||||
EXPECT_TRUE(visited);
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(track1.getId() != track2.getId());
|
||||
EXPECT_TRUE(track1.get() != track2.get());
|
||||
EXPECT_FALSE(track1.get() == track2.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_MediaLibrary)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
ScopedMediaLibrary library{ session };
|
||||
ScopedMediaLibrary otherLibrary{ session };
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksSearchByFilter)
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setMediaLibrary(library.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(library->getId()))};
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters{}.setMediaLibrary(otherLibrary->getId()))};
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_noMediaLibrary)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrackFile" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
MediaLibrary::pointer mediaLibrary{ track->getMediaLibrary() };
|
||||
EXPECT_EQ(mediaLibrary, MediaLibrary::pointer{});
|
||||
EXPECT_FALSE(mediaLibrary);
|
||||
EXPECT_TRUE(!mediaLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackNotExists)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_FALSE(Track::exists(session, TrackId{ 42 }));
|
||||
EXPECT_EQ(Track::find(session, TrackId{ 42 }), Track::pointer{});
|
||||
EXPECT_FALSE(Track::find(session, TrackId{ 42 }));
|
||||
EXPECT_EQ(Track::find(session, Track::FindParameters{}).results.size(), 0);
|
||||
{
|
||||
auto track{ Track::find(session, TrackId{ 42 }) };
|
||||
EXPECT_TRUE(!track);
|
||||
EXPECT_FALSE(track);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracks)
|
||||
{
|
||||
ScopedTrack track1{ session, "MyTrackFile1" };
|
||||
ScopedTrack track2{ session, "MyTrackFile2" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_TRUE(track1.getId() != track2.getId());
|
||||
EXPECT_TRUE(track1.get() != track2.get());
|
||||
EXPECT_FALSE(track1.get() == track2.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, MultipleTracksSearchByFilter)
|
||||
{
|
||||
ScopedTrack track1{ session, "" };
|
||||
ScopedTrack track2{ session, "" };
|
||||
ScopedTrack track3{ session, "" };
|
||||
ScopedTrack track4{ session, "" };
|
||||
ScopedTrack track5{ session, "" };
|
||||
ScopedTrack track6{ session, "" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track1.get().modify()->setName("MyTrack");
|
||||
track2.get().modify()->setName("MyTrack%");
|
||||
track3.get().modify()->setName("MyTrack%Foo");
|
||||
track4.get().modify()->setName("%MyTrack");
|
||||
track5.get().modify()->setName("Foo%MyTrack");
|
||||
track6.get().modify()->setName("M_Track");
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedTrack track1{ session, "" };
|
||||
ScopedTrack track2{ session, "" };
|
||||
ScopedTrack track3{ session, "" };
|
||||
ScopedTrack track4{ session, "" };
|
||||
ScopedTrack track5{ session, "" };
|
||||
ScopedTrack track6{ session, "" };
|
||||
|
||||
{
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setKeywords({"Track"})) };
|
||||
EXPECT_EQ(tracks.results.size(), 6);
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track1.get().modify()->setName("MyTrack");
|
||||
track2.get().modify()->setName("MyTrack%");
|
||||
track3.get().modify()->setName("MyTrack%Foo");
|
||||
track4.get().modify()->setName("%MyTrack");
|
||||
track5.get().modify()->setName("Foo%MyTrack");
|
||||
track6.get().modify()->setName("M_Track");
|
||||
}
|
||||
|
||||
{
|
||||
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(); }));
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
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"})) };
|
||||
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%"})) };
|
||||
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"})) };
|
||||
ASSERT_EQ(tracks.results.size(), 2);
|
||||
EXPECT_EQ(tracks.results[0], track4.getId());
|
||||
EXPECT_EQ(tracks.results[1], track5.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_date)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
const Wt::WDate date{ 1995, 5, 5 };
|
||||
const Wt::WDate originalDate{ 1994, 2, 2 };
|
||||
{
|
||||
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());
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getOriginalYear(), std::nullopt);
|
||||
}
|
||||
|
||||
{
|
||||
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());
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setDate(date);
|
||||
track.get().modify()->setOriginalDate(originalDate);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getOriginalYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getDate(), date);
|
||||
EXPECT_EQ(track->getOriginalDate(), originalDate);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setYear(date.year());
|
||||
track.get().modify()->setOriginalYear(originalDate.year());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), date.year());
|
||||
EXPECT_EQ(track->getOriginalYear(), originalDate.year());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_date)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
const Wt::WDate date{ 1995, 5, 5 };
|
||||
const Wt::WDate originalDate{ 1994, 2, 2 };
|
||||
TEST_F(DatabaseFixture, Track_writtenAfter)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getOriginalYear(), std::nullopt);
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setLastWriteTime(dateTime);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
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))) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setDate(date);
|
||||
track.get().modify()->setOriginalDate(originalDate);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getOriginalYear(), std::nullopt);
|
||||
EXPECT_EQ(track->getDate(), date);
|
||||
EXPECT_EQ(track->getOriginalDate(), originalDate);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setYear(date.year());
|
||||
track.get().modify()->setOriginalYear(originalDate.year());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(track->getYear(), date.year());
|
||||
EXPECT_EQ(track->getOriginalYear(), originalDate.year());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, Track_writtenAfter)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
const Wt::WDateTime dateTime{ Wt::WDate {1950, 1, 1}, Wt::WTime {12, 30, 20} };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
track.get().modify()->setLastWriteTime(dateTime);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
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))) };
|
||||
EXPECT_EQ(tracks.results.size(), 1);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
const auto tracks{ Track::findIds(session, Track::FindParameters {}.setWrittenAfter(dateTime.addSecs(+1))) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,46 +21,47 @@
|
||||
|
||||
#include "database/TrackBookmark.hpp"
|
||||
|
||||
using ScopedTrackBookmark = ScopedEntity<Database::TrackBookmark>;
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, TrackBookmark)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedTrack track {session, "MyTrack"};
|
||||
ScopedUser user {session, "MyUser"};
|
||||
using ScopedTrackBookmark = ScopedEntity<db::TrackBookmark>;
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
}
|
||||
TEST_F(DatabaseFixture, TrackBookmark)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
ScopedTrackBookmark bookmark {session, user.lockAndGet(), track.lockAndGet()};
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
ScopedTrackBookmark bookmark{ session, user.lockAndGet(), track.lockAndGet() };
|
||||
|
||||
bookmark.get().modify()->setComment("MyComment");
|
||||
bookmark.get().modify()->setOffset(std::chrono::milliseconds {5});
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
bookmark.get().modify()->setComment("MyComment");
|
||||
bookmark.get().modify()->setOffset(std::chrono::milliseconds{ 5 });
|
||||
}
|
||||
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 1);
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
const auto bookmarks {TrackBookmark::find(session, user.getId())};
|
||||
ASSERT_EQ(bookmarks.results.size(), 1);
|
||||
EXPECT_EQ(bookmarks.results.front(), bookmark.getId());
|
||||
}
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
EXPECT_EQ(TrackBookmark::getCount(session), 1);
|
||||
|
||||
auto userBookmark {TrackBookmark::find(session, user.getId(), track.getId())};
|
||||
ASSERT_TRUE(userBookmark);
|
||||
EXPECT_EQ(userBookmark, bookmark.get());
|
||||
const auto bookmarks{ TrackBookmark::find(session, user.getId()) };
|
||||
ASSERT_EQ(bookmarks.results.size(), 1);
|
||||
EXPECT_EQ(bookmarks.results.front(), bookmark.getId());
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
EXPECT_EQ(userBookmark->getOffset(), std::chrono::milliseconds {5});
|
||||
EXPECT_EQ(userBookmark->getComment(), "MyComment");
|
||||
}
|
||||
}
|
||||
auto userBookmark{ TrackBookmark::find(session, user.getId(), track.getId()) };
|
||||
ASSERT_TRUE(userBookmark);
|
||||
EXPECT_EQ(userBookmark, bookmark.get());
|
||||
|
||||
EXPECT_EQ(userBookmark->getOffset(), std::chrono::milliseconds{ 5 });
|
||||
EXPECT_EQ(userBookmark->getComment(), "MyComment");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,28 +21,29 @@
|
||||
|
||||
#include "database/TrackFeatures.hpp"
|
||||
|
||||
using ScopedTrackFeatures = ScopedEntity<Database::TrackFeatures>;
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, TrackFeatures)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedTrack track {session, "MyTrack"};
|
||||
ScopedUser user {session, "MyUser"};
|
||||
using ScopedTrackFeatures = ScopedEntity<db::TrackFeatures>;
|
||||
|
||||
{
|
||||
auto transaction {session.createReadTransaction()};
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 0);
|
||||
}
|
||||
TEST_F(DatabaseFixture, TrackFeatures)
|
||||
{
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
|
||||
ScopedTrackFeatures trackFeatures {session, track.lockAndGet(), ""};
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction {session.createWriteTransaction()};
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 1);
|
||||
ScopedTrackFeatures trackFeatures{ session, track.lockAndGet(), "" };
|
||||
|
||||
auto allTrackFeatures {TrackFeatures::find(session)};
|
||||
ASSERT_EQ(allTrackFeatures.results.size(), 1);
|
||||
EXPECT_EQ(allTrackFeatures.results.front(), trackFeatures.getId());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
EXPECT_EQ(TrackFeatures::getCount(session), 1);
|
||||
|
||||
auto allTrackFeatures{ TrackFeatures::find(session) };
|
||||
ASSERT_EQ(allTrackFeatures.results.size(), 1);
|
||||
EXPECT_EQ(allTrackFeatures.results.front(), trackFeatures.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,204 +21,205 @@
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
using namespace Database;
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList)
|
||||
namespace lms::db::tests
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
TEST_F(DatabaseFixture, SingleTrackList)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 0);
|
||||
}
|
||||
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrack)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
EXPECT_EQ(TrackList::getCount(session), 1);
|
||||
}
|
||||
}
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrack)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
|
||||
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()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackList_SortMethod)
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
{
|
||||
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} });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
{
|
||||
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} });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListMultipleTrack)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
std::list<ScopedTrack> tracks;
|
||||
|
||||
auto tracks{ Track::findIds(session, Track::FindParameters {}.setTrackList(trackList1.getId())) };
|
||||
ASSERT_EQ(tracks.results.size(), 1);
|
||||
EXPECT_EQ(tracks.results.front(), track.getId());
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
tracks = Track::findIds(session, Track::FindParameters{}.setTrackList(trackList2.getId()));
|
||||
EXPECT_EQ(tracks.results.size(), 0);
|
||||
}
|
||||
}
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(tracks.back().get(), trackList.get());
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, TrackList_SortMethod)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ASSERT_EQ(trackList->getCount(), tracks.size());
|
||||
const auto trackIds{ trackList->getTrackIds() };
|
||||
ASSERT_EQ(trackIds.size(), tracks.size());
|
||||
|
||||
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());
|
||||
// Same order
|
||||
std::size_t i{};
|
||||
for (const ScopedTrack& track : tracks)
|
||||
EXPECT_EQ(track.getId(), trackIds[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrackWithCluster)
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
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() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
EXPECT_EQ(trackLists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(trackLists.results.size(), 1);
|
||||
EXPECT_EQ(trackLists.results.front(), trackList1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList_getEntries)
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack" };
|
||||
|
||||
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());
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track1.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries.front()->getTrack()->getId(), track1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track2.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 2);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track1.getId());
|
||||
EXPECT_EQ(entries[1]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries(Range {1, 1}) };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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} });
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListMultipleTrack)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MytrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
std::list<ScopedTrack> tracks;
|
||||
|
||||
for (std::size_t i{}; i < 10; ++i)
|
||||
{
|
||||
tracks.emplace_back(session, "MyTrack" + std::to_string(i));
|
||||
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(tracks.back().get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
ASSERT_EQ(trackList->getCount(), tracks.size());
|
||||
const auto trackIds{ trackList->getTrackIds() };
|
||||
ASSERT_EQ(trackIds.size(), tracks.size());
|
||||
|
||||
// Same order
|
||||
std::size_t i{};
|
||||
for (const ScopedTrack& track : tracks)
|
||||
EXPECT_EQ(track.getId(), trackIds[i++]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackListSingleTrackWithCluster)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList1{ session, "MyTrackList1", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrackList trackList2{ session, "MyTrackList2", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedClusterType clusterType{ session, "MyClusterType" };
|
||||
ScopedCluster cluster{ session, clusterType.lockAndGet(), "MyCluster" };
|
||||
ScopedTrack track{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
EXPECT_EQ(trackLists.results.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
|
||||
session.create<TrackListEntry>(track.get(), trackList1.get());
|
||||
cluster.get().modify()->addTrack(track.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
|
||||
auto trackLists{ TrackList::find(session, TrackList::FindParameters {}.setClusters({cluster.getId()})) };
|
||||
ASSERT_EQ(trackLists.results.size(), 1);
|
||||
EXPECT_EQ(trackLists.results.front(), trackList1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DatabaseFixture, SingleTrackList_getEntries)
|
||||
{
|
||||
ScopedUser user{ session, "MyUser" };
|
||||
ScopedTrackList trackList{ session, "MyTrackList", TrackListType::Playlist, false, user.lockAndGet() };
|
||||
ScopedTrack track1{ session, "MyTrack" };
|
||||
ScopedTrack track2{ session, "MyTrack" };
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track1.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries.front()->getTrack()->getId(), track1.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createWriteTransaction() };
|
||||
session.create<TrackListEntry>(track2.get(), trackList.get());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries() };
|
||||
ASSERT_EQ(entries.size(), 2);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track1.getId());
|
||||
EXPECT_EQ(entries[1]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
|
||||
{
|
||||
auto transaction{ session.createReadTransaction() };
|
||||
auto entries{ trackList.get()->getEntries(Range {1, 1}) };
|
||||
ASSERT_EQ(entries.size(), 1);
|
||||
EXPECT_EQ(entries[0]->getTrack()->getId(), track2.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user