Auto reformatted the base, ref #470

This commit is contained in:
emeric
2024-05-24 23:31:52 +02:00
parent 83b868673c
commit 39941d90a3
460 changed files with 8583 additions and 8514 deletions
+42 -49
View File
@@ -20,22 +20,23 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
#include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Artist::FindParameters& params)
{
session.checkReadTransaction();
@@ -97,21 +98,25 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_artist s_a ON s_a.artist_id = a.id")
.where("s_a.user_id = ?").bind(params.starringUser)
.where("s_a.backend = ?").bind(*params.feedbackBackend)
.where("s_a.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_a.user_id = ?")
.bind(params.starringUser)
.where("s_a.backend = ?")
.bind(*params.feedbackBackend)
.where("s_a.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.clusters.size() == 1)
{
query.join("track_cluster t_c ON t_c.track_id = t_a_l.track_id")
.where("t_c.cluster_id = ?").bind(params.clusters.front());
.where("t_c.cluster_id = ?")
.bind(params.clusters.front());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -159,7 +164,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Artist::FindParameters& params)
{
std::string_view itemToSelect;
@@ -173,12 +178,12 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Artist::Artist(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) },
_sortName{ _name },
_MBID{ MBID ? MBID->getAsString() : "" }
: _name{ std::string(name, 0, _maxNameLength) }
, _sortName{ _name }
, _MBID{ MBID ? MBID->getAsString() : "" }
{
}
@@ -198,10 +203,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a")
.orderBy("a.id")
.where("a.id > ?").bind(lastRetrievedArtist)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a").orderBy("a.id").where("a.id > ?").bind(lastRetrievedArtist).limit(static_cast<int>(count)) };
if (library.isValid())
{
@@ -209,20 +211,17 @@ namespace lms::db
query.where("EXISTS (SELECT 1 FROM track_artist_link t_a_l JOIN track t ON t.id = t_a_l.track_id WHERE t_a_l.artist_id = a.id AND t.media_library_id = ?)").bind(library);
}
utils::forEachQueryResult(query, [&](const Artist::pointer& artist)
{
func(artist);
lastRetrievedArtist = artist->getId();
});
utils::forEachQueryResult(query, [&](const Artist::pointer& artist) {
func(artist);
lastRetrievedArtist = artist->getId();
});
}
std::vector<Artist::pointer> Artist::find(Session& session, std::string_view name)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>()
.where("name = ?").bind(std::string{ name, 0, _maxNameLength })
.orderBy("LENGTH(mbid) DESC")); // put mbid entries first
return utils::fetchQueryResults<Artist::pointer>(session.getDboSession()->find<Artist>().where("name = ?").bind(std::string{ name, 0, _maxNameLength }).orderBy("LENGTH(mbid) DESC")); // put mbid entries first
}
Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
@@ -279,19 +278,18 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT a.id FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN artist a ON a.id = t_a_l.artist_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" WHERE a.id = ?)"
" AND a.id <> ?";
oss << "SELECT a.id FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN artist a ON a.id = t_a_l.artist_id"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" WHERE a.id = ?)"
" AND a.id <> ?";
if (!artistLinkTypes.empty())
{
@@ -309,11 +307,7 @@ namespace lms::db
oss << ")";
}
auto query{ session()->query<ArtistId>(oss.str())
.bind(getId())
.bind(getId())
.groupBy("a.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
auto query{ session()->query<ArtistId>(oss.str()).bind(getId()).bind(getId()).groupBy("a.id").orderBy("COUNT(*) DESC, RANDOM()") };
for (const TrackArtistLinkType type : artistLinkTypes)
query.bind(type);
@@ -347,11 +341,10 @@ namespace lms::db
query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [clusterTypeId, clusters] : clustersByType)
+5 -3
View File
@@ -20,10 +20,12 @@
#include "database/AuthToken.hpp"
#include <Wt/Dbo/WtSqlTraits.h>
#include "database/Session.hpp"
#include "database/User.hpp"
#include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
namespace lms::db
@@ -37,7 +39,7 @@ namespace lms::db
AuthToken::pointer AuthToken::create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user)
{
return session.getDboSession()->add(std::unique_ptr<AuthToken> {new AuthToken{ value, expiry, user }});
return session.getDboSession()->add(std::unique_ptr<AuthToken>{ new AuthToken{ value, expiry, user } });
}
void AuthToken::removeExpiredTokens(Session& session, const Wt::WDateTime& now)
@@ -53,4 +55,4 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value));
}
}
} // namespace lms::db
+20 -26
View File
@@ -25,16 +25,17 @@
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Cluster::FindParameters& params)
{
session.checkReadTransaction();
@@ -44,7 +45,7 @@ namespace lms::db
if (params.track.isValid() || params.release.isValid())
query.join("track_cluster t_c ON t_c.cluster_id = c.id");
if (!params.clusterTypeName.empty())
query.join("cluster_type c_t ON c_t.id = c.cluster_type_id");
@@ -77,7 +78,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Cluster::FindParameters& params)
{
std::string_view itemToSelect;
@@ -91,17 +92,17 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Cluster::Cluster(ObjectPtr<ClusterType> type, std::string_view name)
: _name{ std::string {name, 0, _maxNameLength} },
_clusterType{ getDboPtr(type) }
: _name{ std::string{ name, 0, _maxNameLength } }
, _clusterType{ getDboPtr(type) }
{
}
Cluster::pointer Cluster::create(Session& session, ObjectPtr<ClusterType> type, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<Cluster> {new Cluster{ type, name }});
return session.getDboSession()->add(std::unique_ptr<Cluster>{ new Cluster{ type, name } });
}
std::size_t Cluster::getCount(Session& session)
@@ -154,16 +155,14 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
}
std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("t_c.cluster_id = ?").bind(id));
}
void Cluster::addTrack(ObjectPtr<Track> track)
@@ -175,8 +174,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("c.id = ?").bind(getId()) };
auto query{ session()->query<TrackId>("SELECT t.id FROM track t INNER JOIN cluster c ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id").where("c.id = ?").bind(getId()) };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -188,7 +186,7 @@ namespace lms::db
ClusterType::pointer ClusterType::create(Session& session, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<ClusterType> {new ClusterType{ name }});
return session.getDboSession()->add(std::unique_ptr<ClusterType>{ new ClusterType{ name } });
}
std::size_t ClusterType::getCount(Session& session)
@@ -203,9 +201,9 @@ namespace lms::db
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT c_t.id from cluster_type c_t"
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
.where("c.id IS NULL") };
"SELECT c_t.id from cluster_type c_t"
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
.where("c.id IS NULL") };
return utils::execRangeQuery<ClusterTypeId>(query, range);
}
@@ -215,8 +213,8 @@ namespace lms::db
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT DISTINCT c_t.id from cluster_type c_t")
.join("cluster c ON c_t.id = c.cluster_type_id") };
"SELECT DISTINCT c_t.id from cluster_type c_t")
.join("cluster c ON c_t.id = c.cluster_type_id") };
return utils::execRangeQuery<ClusterTypeId>(query, range);
}
@@ -255,9 +253,7 @@ namespace lms::db
assert(self());
assert(session());
return utils::fetchQuerySingleResult(session()->find<Cluster>()
.where("name = ?").bind(name)
.where("cluster_type_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->find<Cluster>().where("name = ?").bind(name).where("cluster_type_id = ?").bind(getId()));
}
std::vector<Cluster::pointer> ClusterType::getClusters() const
@@ -265,8 +261,6 @@ namespace lms::db
assert(self());
assert(session());
return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>()
.where("cluster_type_id = ?").bind(getId())
.orderBy("name"));
return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>().where("cluster_type_id = ?").bind(getId()).orderBy("name"));
}
} // namespace lms::db
+4 -4
View File
@@ -22,12 +22,12 @@
#include <Wt/Dbo/FixedSqlConnectionPool.h>
#include <Wt/Dbo/backend/Sqlite3.h>
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/IConfig.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "core/Service.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
namespace lms::db
{
@@ -68,7 +68,7 @@ namespace lms::db
std::filesystem::path _dbPath;
};
}
} // namespace
// Session living class handling the database and the login
Db::Db(const std::filesystem::path& dbPath, std::size_t connectionCount)
@@ -76,7 +76,7 @@ namespace lms::db
LMS_LOG(DB, INFO, "Creating connection pool on file " << dbPath.string());
auto connection{ std::make_unique<Connection>(dbPath.string()) };
if (core::IConfig * config{ core::Service<core::IConfig>::get() })// may not be here on testU
if (core::IConfig * config{ core::Service<core::IConfig>::get() }) // may not be here on testU
connection->setProperty("show-queries", config->getBool("db-show-queries", false) ? "true" : "false");
auto connectionPool{ std::make_unique<Wt::Dbo::FixedSqlConnectionPool>(std::move(connection), connectionCount) };
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h>
#include "core/EnumSet.hpp"
@@ -49,5 +50,4 @@ namespace Wt::Dbo
return false;
}
};
}
} // namespace Wt::Dbo
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <type_traits>
#include <Wt/Dbo/StdSqlTraits.h>
#include "database/Types.hpp"
@@ -55,5 +56,4 @@ namespace Wt::Dbo
return false;
}
};
}
} // namespace Wt::Dbo
+41 -59
View File
@@ -21,6 +21,7 @@
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
@@ -31,9 +32,7 @@ namespace lms::db
{
Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params)
{
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t_a_l.track_id") };
auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a").join("track_artist_link t_a_l ON t_a_l.artist_id = a.id").join("listen l ON l.track_id = t_a_l.track_id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -56,7 +55,7 @@ namespace lms::db
{
std::ostringstream oss;
oss << "a.id IN (SELECT DISTINCT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t_a_l.track_id";
WhereClause clusterClause;
for (auto id : params.clusters)
@@ -96,9 +95,7 @@ namespace lms::db
Wt::Dbo::Query<ReleaseId> createReleasesQuery(Session& session, const Listen::StatsFindParameters& params)
{
auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r")
.join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id") };
auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r").join("track t ON t.release_id = r.id").join("listen l ON l.track_id = t.id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -109,7 +106,8 @@ namespace lms::db
if (params.artist.isValid())
{
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist);
.where("t_a_l.artist_id = ?")
.bind(params.artist);
}
if (params.library.isValid())
@@ -119,9 +117,9 @@ namespace lms::db
{
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (ClusterId id : params.clusters)
@@ -144,8 +142,7 @@ namespace lms::db
Wt::Dbo::Query<TrackId> createTracksQuery(Session& session, const Listen::StatsFindParameters& params)
{
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t")
.join("listen l ON l.track_id = t.id") };
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t").join("listen l ON l.track_id = t.id") };
if (params.user.isValid())
query.where("l.user_id = ?").bind(params.user);
@@ -156,7 +153,8 @@ namespace lms::db
if (params.artist.isValid())
{
query.join("track_artist_link t_a_l ON t_a_l.track_id = t.id")
.where("t_a_l.artist_id = ?").bind(params.artist);
.where("t_a_l.artist_id = ?")
.bind(params.artist);
}
if (params.library.isValid())
@@ -166,8 +164,8 @@ namespace lms::db
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
WhereClause clusterClause;
for (auto id : params.clusters)
@@ -187,19 +185,20 @@ namespace lms::db
return query;
}
}
} // namespace
Listen::Listen(ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
: _dateTime{ Wt::WDateTime::fromTime_t(dateTime.toTime_t()) }
, _backend{ backend }
, _user{ getDboPtr(user) }
, _track{ getDboPtr(track) }
{}
{
}
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
{
session.checkWriteTransaction();
return session.getDboSession()->add(std::unique_ptr<Listen> {new Listen{ user, track, backend, dateTime }});
return session.getDboSession()->add(std::unique_ptr<Listen>{ new Listen{ user, track, backend, dateTime } });
}
std::size_t Listen::getCount(Session& session)
@@ -218,8 +217,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen")
.orderBy("date_time") };
auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen").orderBy("date_time") };
if (parameters.user.isValid())
query.where("user_id = ?").bind(parameters.user);
@@ -237,11 +235,7 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>()
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId)
.where("backend = ?").bind(backend)
.where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Listen>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId).where("backend = ?").bind(backend).where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
}
RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params)
@@ -250,8 +244,8 @@ namespace lms::db
auto query{ createArtistsQuery(session, params) };
auto collection{ query
.orderBy("COUNT(a.id) DESC")
.groupBy("a.id") };
.orderBy("COUNT(a.id) DESC")
.groupBy("a.id") };
return utils::execRangeQuery<ArtistId>(query, params.range);
}
@@ -280,7 +274,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createArtistsQuery(session, params)
.groupBy("a.id").having("l.date_time = MAX(l.date_time)")
.groupBy("a.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<ArtistId>(query, params.range);
@@ -290,7 +285,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createReleasesQuery(session, params)
.groupBy("r.id").having("l.date_time = MAX(l.date_time)")
.groupBy("r.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<ReleaseId>(query, params.range);
@@ -300,7 +296,8 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ createTracksQuery(session, params)
.groupBy("t.id").having("l.date_time = MAX(l.date_time)")
.groupBy("t.id")
.having("l.date_time = MAX(l.date_time)")
.orderBy("l.date_time DESC") };
return utils::execRangeQuery<TrackId>(query, params.range);
@@ -310,11 +307,7 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l")
.join("user u ON u.id = l.user_id")
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = u.scrobbling_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l").join("user u ON u.id = l.user_id").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = u.scrobbling_backend"));
}
std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId)
@@ -322,16 +315,16 @@ namespace lms::db
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>(
"SELECT IFNULL(MIN(count_result), 0)"
" FROM ("
" SELECT COUNT(l.track_id) AS count_result"
" FROM track t"
" LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?"
" WHERE t.release_id = ?"
" GROUP BY t.id)")
.bind(userId)
.bind(userId)
.bind(releaseId));
"SELECT IFNULL(MIN(count_result), 0)"
" FROM ("
" SELECT COUNT(l.track_id) AS count_result"
" FROM track t"
" LEFT JOIN listen l ON t.id = l.track_id AND l.backend = (SELECT scrobbling_backend FROM user WHERE id = ?) AND l.user_id = ?"
" WHERE t.release_id = ?"
" GROUP BY t.id)")
.bind(userId)
.bind(userId)
.bind(releaseId));
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
@@ -339,24 +332,13 @@ namespace lms::db
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.join("track t ON l.track_id = t.id")
.where("t.release_id = ?").bind(releaseId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC")
.limit(1));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").join("track t ON l.track_id = t.id").where("t.release_id = ?").bind(releaseId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
}
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
{
session.checkReadTransaction();
// TODO not pending remove?
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC")
.limit(1));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l").where("l.track_id = ?").bind(trackId).where("l.user_id = ?").bind(userId).where("l.backend = ?").bind(backend).orderBy("l.date_time DESC").limit(1));
}
} // namespace lms::db
+6 -6
View File
@@ -22,6 +22,7 @@
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "IdTypeTraits.hpp"
#include "PathTraits.hpp"
#include "StringViewTraits.hpp"
@@ -30,8 +31,8 @@
namespace lms::db
{
MediaLibrary::MediaLibrary(const std::filesystem::path& p, std::string_view name)
: _path{ p },
_name{ std::string {name, 0, maxNameLength} }
: _path{ p }
, _name{ std::string{ name, 0, maxNameLength } }
{
}
@@ -72,9 +73,8 @@ namespace lms::db
{
session.checkReadTransaction();
utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary)
{
func(mediaLibrary);
});
utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary) {
func(mediaLibrary);
});
}
} // namespace lms::db
+44 -40
View File
@@ -21,13 +21,14 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Db.hpp"
#include "database/ScanSettings.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "Utils.hpp"
namespace lms::db
@@ -39,7 +40,8 @@ namespace lms::db
VersionInfo::VersionInfo()
: _version{ LMS_DATABASE_VERSION }
{}
{
}
VersionInfo::pointer VersionInfo::getOrCreate(Session& session)
{
@@ -58,14 +60,15 @@ namespace lms::db
return utils::fetchQuerySingleResult(session.getDboSession()->find<VersionInfo>());
}
}
} // namespace lms::db
namespace lms::db::Migration
{
class ScopedNoForeignKeys
{
public:
ScopedNoForeignKeys(Db& db) : _db{ db }
ScopedNoForeignKeys(Db& db)
: _db{ db }
{
_db.executeSql("PRAGMA foreign_keys=OFF");
}
@@ -73,6 +76,7 @@ namespace lms::db::Migration
{
_db.executeSql("PRAGMA foreign_keys=ON");
}
private:
ScopedNoForeignKeys(const ScopedNoForeignKeys&) = delete;
ScopedNoForeignKeys(ScopedNoForeignKeys&&) = delete;
@@ -106,9 +110,9 @@ CREATE TABLE IF NOT EXISTS "track_artist_link_backup" (
{
// Add scrobbling state
// By default, everything needs to be sent
session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_artist ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_release ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
session.getDboSession()->execute("ALTER TABLE starred_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/ 0)) + ")");
}
static void migrateFromV35(Session& session)
@@ -251,7 +255,7 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
void migrateFromV45(Session& session)
{
// add subsonic_enable_transcoding_by_default, default is disabled
session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultSubsonicEnableTranscodingByDefault*/0)) + ")");
session.getDboSession()->execute("ALTER TABLE user ADD subsonic_enable_transcoding_by_default INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultSubsonicEnableTranscodingByDefault*/ 0)) + ")");
}
void migrateFromV46(Session& session)
@@ -330,7 +334,8 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name")
SELECT 1, 0, s_s.media_directory, "Main"
FROM scan_settings s_s
WHERE id = ?)").bind(scanSettingsId);
WHERE id = ?)")
.bind(scanSettingsId);
// Remove the outdated column in scan_settings
session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory");
@@ -479,34 +484,33 @@ SELECT
using MigrationFunction = std::function<void(Session&)>;
const std::map<unsigned, MigrationFunction> migrationFunctions
{
{33, migrateFromV33},
{34, migrateFromV34},
{35, migrateFromV35},
{36, migrateFromV36},
{37, migrateFromV37},
{38, migrateFromV38},
{39, migrateFromV39},
{40, migrateFromV40},
{41, migrateFromV41},
{42, migrateFromV42},
{43, migrateFromV43},
{44, migrateFromV44},
{45, migrateFromV45},
{46, migrateFromV46},
{47, migrateFromV47},
{48, migrateFromV48},
{49, migrateFromV49},
{50, migrateFromV50},
{51, migrateFromV51},
{52, migrateFromV52},
{53, migrateFromV53},
{54, migrateFromV54},
{55, migrateFromV55},
{56, migrateFromV56},
{57, migrateFromV57},
{58, migrateFromV58},
const std::map<unsigned, MigrationFunction> migrationFunctions{
{ 33, migrateFromV33 },
{ 34, migrateFromV34 },
{ 35, migrateFromV35 },
{ 36, migrateFromV36 },
{ 37, migrateFromV37 },
{ 38, migrateFromV38 },
{ 39, migrateFromV39 },
{ 40, migrateFromV40 },
{ 41, migrateFromV41 },
{ 42, migrateFromV42 },
{ 43, migrateFromV43 },
{ 44, migrateFromV44 },
{ 45, migrateFromV45 },
{ 46, migrateFromV46 },
{ 47, migrateFromV47 },
{ 48, migrateFromV48 },
{ 49, migrateFromV49 },
{ 50, migrateFromV50 },
{ 51, migrateFromV51 },
{ 52, migrateFromV52 },
{ 53, migrateFromV53 },
{ 54, migrateFromV54 },
{ 55, migrateFromV55 },
{ 56, migrateFromV56 },
{ 57, migrateFromV57 },
{ 58, migrateFromV58 },
};
bool migrationPerformed{};
@@ -550,4 +554,4 @@ SELECT
return migrationPerformed;
}
}
} // namespace lms::db::Migration
+1 -1
View File
@@ -54,4 +54,4 @@ namespace lms::db
{
bool doDbMigration(Session& session); // return true if migration was performed
}
}
} // namespace lms::db
+3 -3
View File
@@ -19,8 +19,9 @@
#pragma once
#include <string>
#include <filesystem>
#include <string>
#include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo
@@ -50,5 +51,4 @@ namespace Wt::Dbo
return true;
}
};
}
} // namespace Wt::Dbo
+72 -96
View File
@@ -21,15 +21,16 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "SqlQuery.hpp"
#include "EnumSetTraits.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
@@ -37,7 +38,7 @@ namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Release::FindParameters& params)
{
auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " from release r") };
@@ -63,7 +64,8 @@ namespace lms::db
{
query.join("release_release_type r_r_t ON r_r_t.release_id = r.id");
query.join("release_type r_t ON r_t.id = r_r_t.release_type_id")
.where("r_t.name = ?").bind(params.releaseType);
.where("r_t.name = ?")
.bind(params.releaseType);
}
if (params.writtenAfter.isValid())
@@ -82,9 +84,12 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_release s_r ON s_r.release_id = r.id")
.where("s_r.user_id = ?").bind(params.starringUser)
.where("s_r.backend = ?").bind(*params.feedbackBackend)
.where("s_r.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_r.user_id = ?")
.bind(params.starringUser)
.where("s_r.backend = ?")
.bind(*params.feedbackBackend)
.where("s_r.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.artist.isValid()
@@ -119,9 +124,9 @@ namespace lms::db
{
std::ostringstream oss;
oss << "r.id NOT IN (SELECT DISTINCT r.id FROM release r"
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" INNER JOIN track t ON t.release_id = r.id"
" WHERE (t_a_l.artist_id = ? AND (";
" INNER JOIN track_artist_link t_a_l ON t_a_l.track_id = t.id"
" INNER JOIN track t ON t.release_id = r.id"
" WHERE (t_a_l.artist_id = ? AND (";
query.bind(params.artist);
@@ -143,13 +148,14 @@ namespace lms::db
if (params.clusters.size() == 1)
{
query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front());
.where("t_c.cluster_id = ?")
.bind(params.clusters.front());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "r.id IN (SELECT DISTINCT t.release_id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -200,69 +206,62 @@ namespace lms::db
return query;
}
}
} // namespace
ReleaseType::ReleaseType(std::string_view name)
: _name{ std::string(name, 0 , _maxNameLength) }
: _name{ std::string(name, 0, _maxNameLength) }
{
}
ReleaseType::pointer ReleaseType::create(Session& session, std::string_view name)
{
return session.getDboSession()->add(std::unique_ptr<ReleaseType> {new ReleaseType{ name }});
return session.getDboSession()->add(std::unique_ptr<ReleaseType>{ new ReleaseType{ name } });
}
ReleaseType::pointer ReleaseType::find(Session& session, ReleaseTypeId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("id = ?").bind(id));
}
ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("name = ?").bind(name));
return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>().where("name = ?").bind(name));
}
Release::Release(const std::string& name, const std::optional<core::UUID>& MBID)
: _name{ std::string(name, 0 , _maxNameLength) },
_MBID{ MBID ? MBID->getAsString() : "" }
: _name{ std::string(name, 0, _maxNameLength) }
, _MBID{ MBID ? MBID->getAsString() : "" }
{
}
Release::pointer Release::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID)
{
return session.getDboSession()->add(std::unique_ptr<Release> {new Release{ name, MBID }});
return session.getDboSession()->add(std::unique_ptr<Release>{ new Release{ name, MBID } });
}
std::vector<Release::pointer> Release::find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r")
.join("track t ON t.release_id = r.id")
.where("r.name = ?").bind(std::string(name, 0, _maxNameLength))
.where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r").join("track t ON t.release_id = r.id").where("r.name = ?").bind(std::string(name, 0, _maxNameLength)).where("t.absolute_file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"));
}
Release::pointer Release::find(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("mbid = ?").bind(mbid.getAsString()));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("mbid = ?").bind(mbid.getAsString()));
}
Release::pointer Release::find(Session& session, ReleaseId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>().where("id = ?").bind(id));
}
bool Release::exists(Session& session, ReleaseId id)
@@ -290,10 +289,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r")
.orderBy("r.id")
.where("r.id > ?").bind(lastRetrievedRelease)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r").orderBy("r.id").where("r.id > ?").bind(lastRetrievedRelease).limit(static_cast<int>(count)) };
if (library.isValid())
{
@@ -301,11 +297,10 @@ namespace lms::db
query.where("EXISTS (SELECT 1 FROM track t WHERE t.release_id = r.id AND t.media_library_id = ?)").bind(library);
}
utils::forEachQueryResult(query, [&](const Release::pointer& release)
{
func(release);
lastRetrievedRelease = release->getId();
});
utils::forEachQueryResult(query, [&](const Release::pointer& release) {
func(release);
lastRetrievedRelease = release->getId();
});
}
RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params)
@@ -342,8 +337,7 @@ namespace lms::db
std::size_t Release::getDiscCount() const
{
assert(session());
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t")
.where("t.release_id = ?").bind(getId()))};
int res{ utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t").where("t.release_id = ?").bind(getId())) };
return res;
}
@@ -352,15 +346,12 @@ namespace lms::db
assert(session());
using ResultType = std::tuple<int, std::string>;
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t")
.where("t.release_id = ?").bind(getId())
.orderBy("disc_number")};
const auto query{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t").where("t.release_id = ?").bind(getId()).orderBy("disc_number") };
std::vector<DiscInfo> discs;
utils::forEachQueryResult(query, [&](ResultType&& res)
{
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
});
utils::forEachQueryResult(query, [&](ResultType&& res) {
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
});
return discs;
}
@@ -380,10 +371,7 @@ namespace lms::db
assert(session());
const char* field{ original ? "original_date" : "date" };
auto query{ (session()->query<Wt::WDate>(std::string {"SELECT "} + "t." + field + " FROM track t")
.where("t.release_id = ?")
.groupBy(field)
.bind(getId())) };
auto query{ (session()->query<Wt::WDate>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").groupBy(field).bind(getId())) };
const auto dates{ utils::fetchQueryResults(query) };
@@ -409,9 +397,7 @@ namespace lms::db
assert(session());
const char* field{ original ? "original_year" : "year" };
auto query{ session()->query<std::optional<int>>(std::string {"SELECT "} + "t." + field + " FROM track t")
.where("t.release_id = ?").bind(getId())
.groupBy(field) };
auto query{ session()->query<std::optional<int>>(std::string{ "SELECT " } + "t." + field + " FROM track t").where("t.release_id = ?").bind(getId()).groupBy(field) };
const auto years{ utils::fetchQueryResults(query) };
@@ -427,10 +413,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?")
.groupBy("copyright")
.bind(getId()) };
auto query{ session()->query<std::string>("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").groupBy("copyright").bind(getId()) };
const auto copyrights{ utils::fetchQueryResults(query) };
@@ -445,10 +428,7 @@ namespace lms::db
{
assert(session());
const auto query{ session()->query<std::string>
("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId())
.groupBy("copyright_url") };
const auto query{ session()->query<std::string>("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()).groupBy("copyright_url") };
const auto copyrights{ utils::fetchQueryResults(query) };
@@ -463,9 +443,7 @@ namespace lms::db
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t")
.where("release_id = ?").bind(getId())
.where("bitrate > 0"));
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t").where("release_id = ?").bind(getId()).where("bitrate > 0"));
}
std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const
@@ -473,12 +451,14 @@ namespace lms::db
assert(session());
const auto query{ session()->query<Wt::Dbo::ptr<Artist>>(
"SELECT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id")
.where("t.release_id = ?").bind(getId())
.where("+t_a_l.type = ?").bind(linkType) // adding + since the query planner does not a good job when analyze is not performed
.groupBy("a.id") };
"SELECT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id"
" INNER JOIN track t ON t.id = t_a_l.track_id")
.where("t.release_id = ?")
.bind(getId())
.where("+t_a_l.type = ?")
.bind(linkType) // adding + since the query planner does not a good job when analyze is not performed
.groupBy("a.id") };
return utils::fetchQueryResults<Artist::pointer>(query);
}
@@ -489,24 +469,23 @@ namespace lms::db
// Select the similar releases using the 5 most used clusters of the release
auto query{ session()->query<Wt::Dbo::ptr<Release>>(
"SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN "
"(SELECT DISTINCT c.id FROM cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN release r ON r.id = t.release_id"
" WHERE r.id = ?)"
" AND r.id <> ?"
)
.bind(getId())
.bind(getId())
.groupBy("r.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
"SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" t_c.cluster_id IN "
"(SELECT DISTINCT c.id FROM cluster c"
" INNER JOIN track t ON c.id = t_c.cluster_id"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN release r ON r.id = t.release_id"
" WHERE r.id = ?)"
" AND r.id <> ?")
.bind(getId())
.bind(getId())
.groupBy("r.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
return utils::fetchQueryResults<Release::pointer>(query);
}
@@ -530,8 +509,7 @@ namespace lms::db
std::size_t Release::getTrackCount() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN release r ON r.id = t.release_id").where("r.id = ?").bind(getId()));
}
std::vector<ReleaseType::pointer> Release::getReleaseTypes() const
@@ -556,16 +534,14 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t")
.where("t.release_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t").where("t.release_id = ?").bind(getId()));
}
Wt::WDateTime Release::getLastWritten() const
{
assert(session());
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t")
.where("t.release_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t").where("t.release_id = ?").bind(getId()));
}
std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
+2 -1
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/String.hpp"
#include "database/MediaLibrary.hpp"
#include "database/Session.hpp"
#include "core/String.hpp"
#include "Utils.hpp"
namespace lms::db
+6 -6
View File
@@ -22,7 +22,6 @@
#include "core/Exception.hpp"
#include "core/ILogger.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Artist.hpp"
#include "database/AuthToken.hpp"
#include "database/Cluster.hpp"
@@ -35,22 +34,23 @@
#include "database/StarredRelease.hpp"
#include "database/StarredTrack.hpp"
#include "database/Track.hpp"
#include "database/TrackBookmark.hpp"
#include "database/TrackArtistLink.hpp"
#include "database/TrackList.hpp"
#include "database/TrackBookmark.hpp"
#include "database/TrackFeatures.hpp"
#include "database/TrackList.hpp"
#include "database/TransactionChecker.hpp"
#include "database/User.hpp"
#include "EnumSetTraits.hpp"
#include "PathTraits.hpp"
#include "Migration.hpp"
#include "PathTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
WriteTransaction::WriteTransaction(core::RecursiveSharedMutex& mutex, Wt::Dbo::Session& session)
: _lock{ mutex },
_transaction{ session }
: _lock{ mutex }
, _transaction{ session }
{
#if LMS_CHECK_TRANSACTION_ACCESSES
TransactionChecker::pushWriteTransaction(_transaction.session());
+8 -5
View File
@@ -27,7 +27,8 @@ namespace lms::db
{
WhereClause& WhereClause::And(const WhereClause& otherClause)
{
if (!otherClause._clause.empty()) {
if (!otherClause._clause.empty())
{
if (!_clause.empty())
_clause += " AND ";
_clause += "(" + otherClause._clause + ")";
@@ -43,7 +44,8 @@ namespace lms::db
WhereClause& WhereClause::Or(const WhereClause& otherClause)
{
if (!otherClause._clause.empty()) {
if (!otherClause._clause.empty())
{
if (!_clause.empty())
_clause += " OR ";
_clause += "(" + otherClause._clause + ")";
@@ -75,7 +77,7 @@ namespace lms::db
}
InnerJoinClause::InnerJoinClause(const std::string& clause)
:_clause(clause)
: _clause(clause)
{
}
@@ -154,7 +156,8 @@ namespace lms::db
if (!_clause.empty())
{
oss << "FROM ";
for (auto it = _clause.begin(); it != _clause.end(); ++it) {
for (auto it = _clause.begin(); it != _clause.end(); ++it)
{
if (it != _clause.begin())
oss << ",";
@@ -185,4 +188,4 @@ namespace lms::db
return oss.str();
}
}
} // namespace lms::db
+23 -15
View File
@@ -19,8 +19,8 @@
#pragma once
#include <vector>
#include <string>
#include <vector>
namespace lms::db
{
@@ -40,8 +40,8 @@ namespace lms::db
const std::vector<std::string>& getBindArgs() const { return _bindArgs; }
private:
std::string _clause; // WHERE clause
std::vector<std::string> _bindArgs;
std::string _clause; // WHERE clause
std::vector<std::string> _bindArgs;
};
class InnerJoinClause
@@ -68,13 +68,13 @@ namespace lms::db
std::string get() const { return _statement; }
private:
std::string _statement; // SELECT statement
std::string _statement; // SELECT statement
};
class SelectStatement
{
public:
SelectStatement() {};
SelectStatement(){};
SelectStatement(const std::string& item);
SelectStatement& And(const std::string& item);
@@ -82,7 +82,7 @@ namespace lms::db
std::string get() const;
private:
std::vector<std::string> _statement;
std::vector<std::string> _statement;
};
class FromClause
@@ -96,16 +96,24 @@ namespace lms::db
std::string get() const;
private:
std::vector<std::string> _clause;
std::vector<std::string> _clause;
};
class SqlQuery
{
public:
SelectStatement& select() { return _selectStatement; }
SelectStatement& select(const std::string& statement) { _selectStatement = SelectStatement(statement); return _selectStatement; }
SelectStatement& select(const std::string& statement)
{
_selectStatement = SelectStatement(statement);
return _selectStatement;
}
FromClause& from() { return _fromClause; }
FromClause& from(const std::string& clause) { _whereClause = WhereClause(clause); return _fromClause; }
FromClause& from(const std::string& clause)
{
_whereClause = WhereClause(clause);
return _fromClause;
}
InnerJoinClause& innerJoin() { return _innerJoinClause; }
WhereClause& where() { return _whereClause; }
const WhereClause& where() const { return _whereClause; }
@@ -115,10 +123,10 @@ namespace lms::db
std::string get() const;
private:
SelectStatement _selectStatement; // SELECT statement
InnerJoinClause _innerJoinClause; // INNER JOIN
FromClause _fromClause; // FROM tables
WhereClause _whereClause; // WHERE clause
GroupByStatement _groupByStatement; // GROUP BY statement
SelectStatement _selectStatement; // SELECT statement
InnerJoinClause _innerJoinClause; // INNER JOIN
FromClause _fromClause; // FROM tables
WhereClause _whereClause; // WHERE clause
GroupByStatement _groupByStatement; // GROUP BY statement
};
}
} // namespace lms::db
+5 -11
View File
@@ -24,6 +24,7 @@
#include "database/Artist.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredArtist::pointer StarredArtist::create(Session& session, ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredArtist> {new StarredArtist{ artist, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredArtist>{ new StarredArtist{ artist, user, backend } });
}
std::size_t StarredArtist::getCount(Session& session)
@@ -56,24 +57,17 @@ namespace lms::db
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a")
.join("user u ON u.id = s_a.user_id")
.where("s_a.artist_id = ?").bind(artistId)
.where("s_a.user_id = ?").bind(userId)
.where("s_a.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a").join("user u ON u.id = s_a.user_id").where("s_a.artist_id = ?").bind(artistId).where("s_a.user_id = ?").bind(userId).where("s_a.backend = u.feedback_backend"));
}
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>()
.where("artist_id = ?").bind(artistId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredArtist>().where("artist_id = ?").bind(artistId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
void StarredArtist::setDateTime(const Wt::WDateTime& dateTime)
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+5 -11
View File
@@ -24,6 +24,7 @@
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredRelease::pointer StarredRelease::create(Session& session, ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredRelease>{new StarredRelease{ release, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredRelease>{ new StarredRelease{ release, user, backend } });
}
std::size_t StarredRelease::getCount(Session& session)
@@ -56,24 +57,17 @@ namespace lms::db
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r")
.join("user u ON u.id = s_r.user_id")
.where("s_r.release_id = ?").bind(releaseId)
.where("s_r.user_id = ?").bind(userId)
.where("s_r.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r").join("user u ON u.id = s_r.user_id").where("s_r.release_id = ?").bind(releaseId).where("s_r.user_id = ?").bind(userId).where("s_r.backend = u.feedback_backend"));
}
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>()
.where("release_id = ?").bind(releaseId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredRelease>().where("release_id = ?").bind(releaseId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
void StarredRelease::setDateTime(const Wt::WDateTime& dateTime)
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+7 -16
View File
@@ -21,9 +21,10 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "database/Track.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
@@ -38,7 +39,7 @@ namespace lms::db
StarredTrack::pointer StarredTrack::create(Session& session, ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend)
{
return session.getDboSession()->add(std::unique_ptr<StarredTrack> {new StarredTrack{ track, user, backend }});
return session.getDboSession()->add(std::unique_ptr<StarredTrack>{ new StarredTrack{ track, user, backend } });
}
std::size_t StarredTrack::getCount(Session& session)
@@ -56,28 +57,18 @@ namespace lms::db
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t")
.join("user u ON u.id = s_t.user_id")
.where("s_t.track_id = ?").bind(trackId)
.where("s_t.user_id = ?").bind(userId)
.where("s_t.backend = u.feedback_backend"));
return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t").join("user u ON u.id = s_t.user_id").where("s_t.track_id = ?").bind(trackId).where("s_t.user_id = ?").bind(userId).where("s_t.backend = u.feedback_backend"));
}
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>()
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->find<StarredTrack>().where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track")
.where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend));
return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT 1 from starred_track").where("track_id = ?").bind(trackId).where("user_id = ?").bind(userId).where("backend = ?").bind(backend));
}
RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params)
@@ -100,4 +91,4 @@ namespace lms::db
{
_dateTime = utils::normalizeDateTime(dateTime);
}
}
} // namespace lms::db
+2 -2
View File
@@ -20,6 +20,7 @@
#pragma once
#include <string_view>
#include <Wt/Dbo/SqlTraits.h>
namespace Wt::Dbo
@@ -32,5 +33,4 @@ namespace Wt::Dbo
statement->bind(column, std::string{ str });
}
};
}
} // namespace Wt::Dbo
+43 -53
View File
@@ -21,15 +21,15 @@
#include <Wt/Dbo/WtSqlTraits.h>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/MediaLibrary.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/TrackArtistLink.hpp"
#include "database/TrackFeatures.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "PathTraits.hpp"
@@ -41,7 +41,7 @@ namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Track::FindParameters& params)
{
session.checkReadTransaction();
@@ -62,22 +62,26 @@ namespace lms::db
{
assert(params.feedbackBackend);
query.join("starred_track s_t ON s_t.track_id = t.id")
.where("s_t.user_id = ?").bind(params.starringUser)
.where("s_t.backend = ?").bind(*params.feedbackBackend)
.where("s_t.sync_state <> ?").bind(SyncState::PendingRemove);
.where("s_t.user_id = ?")
.bind(params.starringUser)
.where("s_t.backend = ?")
.bind(*params.feedbackBackend)
.where("s_t.sync_state <> ?")
.bind(SyncState::PendingRemove);
}
if (params.clusters.size() == 1)
{
// optim
query.join("track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(params.clusters.front());
.where("t_c.cluster_id = ?")
.bind(params.clusters.front());
}
else if (params.clusters.size() > 1)
{
std::ostringstream oss;
oss << "t.id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -183,7 +187,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const Track::FindParameters& params)
{
std::string_view itemToSelect;
@@ -197,7 +201,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
Track::pointer Track::create(Session& session)
{
@@ -222,27 +226,22 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>().where("id = ?").bind(id));
}
void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library)
{
session.checkReadTransaction();
auto query{ session.getDboSession()->find<Track>()
.orderBy("id")
.where("id > ?").bind(lastRetrievedTrack)
.limit(static_cast<int>(count)) };
auto query{ session.getDboSession()->find<Track>().orderBy("id").where("id > ?").bind(lastRetrievedTrack).limit(static_cast<int>(count)) };
if (library.isValid())
query.where("media_library_id = ?").bind(library);
utils::forEachQueryResult(query, [&](const Track::pointer& track)
{
func(track);
lastRetrievedTrack = track->getId();
});
utils::forEachQueryResult(query, [&](const Track::pointer& track) {
func(track);
lastRetrievedTrack = track->getId();
});
}
bool Track::exists(Session& session, TrackId id)
@@ -256,24 +255,21 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("mbid = ?").bind(mbid.getAsString()));
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("mbid = ?").bind(mbid.getAsString()));
}
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
{
session.checkReadTransaction();
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("recording_mbid = ?").bind(mbid.getAsString()));
return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>().where("recording_mbid = ?").bind(mbid.getAsString()));
}
RangeResults<TrackId> Track::findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range)
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)")
.orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
auto query{ session.getDboSession()->query<TrackId>("SELECT track.id FROM track WHERE mbid in (SELECT mbid FROM track WHERE mbid <> '' GROUP BY mbid HAVING COUNT (*) > 1)").orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -282,9 +278,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t")
.where("LENGTH(t.recording_mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t").where("LENGTH(t.recording_mbid) > 0").where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
return utils::execRangeQuery<TrackId>(query, range);
}
@@ -298,10 +292,7 @@ namespace lms::db
{
assert(session());
const auto query{ session()->query<ClusterId>
("SELECT t_c.cluster_id FROM track_cluster t_c")
.where("t_c.track_id = ?").bind(getId())
.groupBy("t_c.cluster_id") };
const auto query{ session()->query<ClusterId>("SELECT t_c.cluster_id FROM track_cluster t_c").where("t_c.track_id = ?").bind(getId()).groupBy("t_c.cluster_id") };
return utils::fetchQueryResults(query);
}
@@ -352,12 +343,14 @@ namespace lms::db
}
auto query{ session.getDboSession()->query<TrackId>(
"SELECT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN (" + oss.str() + "))"
" AND t.id NOT IN (" + oss.str() + ")")
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
"SELECT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" AND t_c.cluster_id IN (SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id WHERE t_c.track_id IN ("
+ oss.str() + "))"
" AND t.id NOT IN ("
+ oss.str() + ")")
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") };
for (TrackId trackId : tracks)
query.bind(trackId);
@@ -412,10 +405,9 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT a from artist a"
" INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id"
" INNER JOIN track t ON t.id = t_a_l.track_id";
oss << "SELECT a from artist a"
" INNER JOIN track_artist_link t_a_l ON a.id = t_a_l.artist_id"
" INNER JOIN track t ON t.id = t_a_l.track_id";
if (!linkTypes.empty())
{
@@ -447,9 +439,8 @@ namespace lms::db
assert(session());
std::ostringstream oss;
oss <<
"SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track t ON t.id = t_a_l.track_id";
oss << "SELECT t_a_l.artist_id FROM track_artist_link t_a_l"
" INNER JOIN track t ON t.id = t_a_l.track_id";
if (!linkTypes.empty())
{
@@ -507,11 +498,10 @@ namespace lms::db
query.bind(bindArg);
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster);
});
std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [type, clusters] : clusters)
@@ -545,6 +535,6 @@ namespace lms::db
return os;
}
}
} // namespace Debug
} // namespace lms::db
+14 -20
View File
@@ -53,7 +53,7 @@ namespace lms::db
return query;
}
}
} // namespace
TrackArtistLink::TrackArtistLink(ObjectPtr<Track> track, ObjectPtr<Artist> artist, TrackArtistLinkType type, std::string_view subType)
: _type{ type }
@@ -83,40 +83,34 @@ namespace lms::db
{
session.checkReadTransaction();
using ResultType = std::tuple < Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>;
using ResultType = std::tuple<Wt::Dbo::ptr<TrackArtistLink>, Wt::Dbo::ptr<Artist>>;
const auto query{ session.getDboSession()->query<ResultType>("SELECT t_a_l, a FROM track_artist_link t_a_l")
.join("artist a ON t_a_l.artist_id = a.id")
.where("t_a_l.track_id = ?").bind(trackId) };
const auto query{ session.getDboSession()->query<ResultType>("SELECT t_a_l, a FROM track_artist_link t_a_l").join("artist a ON t_a_l.artist_id = a.id").where("t_a_l.track_id = ?").bind(trackId) };
utils::forEachQueryResult(query, [&](const ResultType& result)
{
func(std::get<Wt::Dbo::ptr<TrackArtistLink>>(result), std::get<Wt::Dbo::ptr<Artist>>(result));
});
utils::forEachQueryResult(query, [&](const ResultType& result) {
func(std::get<Wt::Dbo::ptr<TrackArtistLink>>(result), std::get<Wt::Dbo::ptr<Artist>>(result));
});
}
void TrackArtistLink::find(Session& session, const FindParameters& parameters, const std::function<void(const TrackArtistLink::pointer&)>& func)
{
const auto query{ createQuery(session, parameters) };
utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link)
{
func(link);
});
utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) {
func(link);
});
}
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId)
{
session.checkReadTransaction();
const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")
.where("artist_id = ?").bind(artistId) };
const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link").where("artist_id = ?").bind(artistId) };
core::EnumSet<TrackArtistLinkType> res;
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType)
{
res.insert(linkType);
});
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) {
res.insert(linkType);
});
return res;
}
}
} // namespace lms::db
+7 -11
View File
@@ -22,20 +22,21 @@
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
TrackBookmark::TrackBookmark(ObjectPtr<User> user, ObjectPtr<Track> track)
: _user{ getDboPtr(user) },
_track{ getDboPtr(track) }
: _user{ getDboPtr(user) }
, _track{ getDboPtr(track) }
{
}
TrackBookmark::pointer TrackBookmark::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track)
{
return session.getDboSession()->add(std::unique_ptr<TrackBookmark> {new TrackBookmark{ user, track }});
return session.getDboSession()->add(std::unique_ptr<TrackBookmark>{ new TrackBookmark{ user, track } });
}
std::size_t TrackBookmark::getCount(Session& session)
@@ -49,8 +50,7 @@ namespace lms::db
{
session.checkReadTransaction();
auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark")
.where("user_id = ?").bind(userId) };
auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark").where("user_id = ?").bind(userId) };
return utils::execRangeQuery<TrackBookmarkId>(query, range);
}
@@ -59,18 +59,14 @@ namespace lms::db
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("user_id = ?").bind(userId).where("track_id = ?").bind(trackId));
}
TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>().where("id = ?").bind(id));
}
} // namespace lms::db
+11 -11
View File
@@ -19,26 +19,28 @@
#include "database/TrackFeatures.hpp"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include "core/ILogger.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db {
namespace lms::db
{
TrackFeatures::TrackFeatures(ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
: _data{ jsonEncodedFeatures },
_track{ getDboPtr(track) }
: _data{ jsonEncodedFeatures }
, _track{ getDboPtr(track) }
{
}
TrackFeatures::pointer TrackFeatures::create(Session& session, ObjectPtr<Track> track, const std::string& jsonEncodedFeatures)
{
return session.getDboSession()->add(std::unique_ptr<TrackFeatures> {new TrackFeatures{ track, jsonEncodedFeatures }});
return session.getDboSession()->add(std::unique_ptr<TrackFeatures>{ new TrackFeatures{ track, jsonEncodedFeatures } });
}
std::size_t TrackFeatures::getCount(Session& session)
@@ -52,16 +54,14 @@ namespace lms::db {
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("id = ?").bind(id));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("id = ?").bind(id));
}
TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("track_id = ?").bind(trackId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>().where("track_id = ?").bind(trackId));
}
RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range)
@@ -75,7 +75,7 @@ namespace lms::db {
FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const
{
FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({featureNode}) };
FeatureValuesMap featuresValuesMap{ getFeatureValuesMap({ featureNode }) };
return std::move(featuresValuesMap[featureNode]);
}
+33 -47
View File
@@ -21,23 +21,23 @@
#include <cassert>
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Cluster.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/User.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "IdTypeTraits.hpp"
#include "SqlQuery.hpp"
#include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db
{
namespace
{
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const TrackList::FindParameters& params)
{
auto query{ session.getDboSession()->query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM tracklist t_l") };
@@ -61,8 +61,8 @@ namespace lms::db
{
std::ostringstream oss;
oss << "t_l_e.track_id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.clusters)
@@ -92,7 +92,7 @@ namespace lms::db
return query;
}
template <typename ResultType>
template<typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, const TrackList::FindParameters& params)
{
std::string_view itemToSelect;
@@ -106,7 +106,7 @@ namespace lms::db
return createQuery<ResultType>(session, itemToSelect, params);
}
}
} // namespace
TrackList::TrackList(std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
: _name{ name }
@@ -121,7 +121,7 @@ namespace lms::db
TrackList::pointer TrackList::create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user)
{
return session.getDboSession()->add(std::unique_ptr<TrackList> {new TrackList{ name, type, isPublic, user }});
return session.getDboSession()->add(std::unique_ptr<TrackList>{ new TrackList{ name, type, isPublic, user } });
}
std::size_t TrackList::getCount(Session& session)
@@ -136,10 +136,7 @@ namespace lms::db
session.checkReadTransaction();
assert(userId.isValid());
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>()
.where("name = ?").bind(name)
.where("type = ?").bind(type)
.where("user_id = ?").bind(userId));
return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>().where("name = ?").bind(name).where("type = ?").bind(type).where("user_id = ?").bind(userId));
}
RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params)
@@ -188,9 +185,7 @@ namespace lms::db
{
assert(session());
auto query{session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId())
.orderBy("id") };
auto query{ session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).orderBy("id") };
return utils::execRangeQuery<TrackListEntry::pointer>(query, range);
}
@@ -199,20 +194,14 @@ namespace lms::db
{
assert(session());
return utils::fetchQuerySingleResult(session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId())
.where("track_id = ?").bind(track->getId())
.where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
return utils::fetchQuerySingleResult(session()->find<TrackListEntry>().where("tracklist_id = ?").bind(getId()).where("track_id = ?").bind(track->getId()).where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
}
std::vector<Cluster::pointer> TrackList::getClusters() const
{
assert(session());
const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
.where("p.id = ?").bind(getId())
.groupBy("c.id")
.orderBy("COUNT(c.id) DESC") };
const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id").where("p.id = ?").bind(getId()).groupBy("c.id").orderBy("COUNT(c.id) DESC") };
return utils::fetchQueryResults<Cluster::pointer>(query);
}
@@ -232,7 +221,8 @@ namespace lms::db
.join("cluster_type c_type ON c.cluster_type_id = c_type.id")
.join("tracklist_entry t_l_e ON t_l_e.track_id = t.id")
.join("tracklist t_l ON t_l.id = t_l_e.tracklist_id")
.where("t_l.id = ?").bind(getId());
.where("t_l.id = ?")
.bind(getId());
{
std::ostringstream oss;
@@ -253,11 +243,10 @@ namespace lms::db
query.orderBy("COUNT(c.id) DESC");
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster) {
if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster);
});
for (const auto& [clusterTypeId, clusters] : clustersByType)
res.push_back(clusters);
@@ -270,18 +259,17 @@ namespace lms::db
assert(session());
auto query{ session()->query<Wt::Dbo::ptr<Track>>(
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))"
)
.bind(getId())
.bind(getId())
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
"SELECT t FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" WHERE "
" (t_c.cluster_id IN (SELECT DISTINCT c.id from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id WHERE p.id = ?)"
" AND t.id NOT IN (SELECT tracklist_t.id FROM track tracklist_t INNER JOIN tracklist_entry t_e ON t_e.track_id = tracklist_t.id WHERE t_e.tracklist_id = ?))")
.bind(getId())
.bind(getId())
.groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()")
.limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) };
return utils::fetchQueryResults<Track::pointer>(query);
}
@@ -290,8 +278,7 @@ namespace lms::db
{
assert(session());
auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
.where("p.id = ?").bind(getId()) };
auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id").where("p.id = ?").bind(getId()) };
return utils::fetchQueryResults(query);
}
@@ -302,8 +289,7 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>;
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id")
.where("p_e.tracklist_id = ?").bind(getId()));
return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id").where("p_e.tracklist_id = ?").bind(getId()));
}
void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime)
@@ -322,7 +308,7 @@ namespace lms::db
TrackListEntry::pointer TrackListEntry::create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime)
{
return session.getDboSession()->add(std::unique_ptr<TrackListEntry> {new TrackListEntry{ track, tracklist, dateTime }});
return session.getDboSession()->add(std::unique_ptr<TrackListEntry>{ new TrackListEntry{ track, tracklist, dateTime } });
}
void TrackListEntry::onPostCreated()
@@ -22,6 +22,7 @@
static_assert(LMS_CHECK_TRANSACTION_ACCESSES, "File should be excluded from build");
#include <cassert>
#include "database/Session.hpp"
namespace lms::db
@@ -35,7 +36,7 @@ namespace lms::db
};
static thread_local std::vector<StackEntry> transactionStack;
}
} // namespace
void TransactionChecker::pushWriteTransaction(Wt::Dbo::Session& session)
{
@@ -93,4 +94,4 @@ namespace lms::db
{
checkReadTransaction(*session.getDboSession());
}
}
} // namespace lms::db
+2 -4
View File
@@ -23,8 +23,7 @@
namespace lms::db
{
static const std::set<Bitrate> allowedAudioBitrates
{
static const std::set<Bitrate> allowedAudioBitrates{
64000,
96000,
128000,
@@ -47,5 +46,4 @@ namespace lms::db
{
return DateRange{ from, to };
}
}
} // namespace lms::db
+4 -4
View File
@@ -19,11 +19,12 @@
#include "database/User.hpp"
#include "core/ILogger.hpp"
#include "database/Artist.hpp"
#include "database/Release.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "core/ILogger.hpp"
#include "IdTypeTraits.hpp"
#include "StringViewTraits.hpp"
#include "Utils.hpp"
@@ -37,7 +38,7 @@ namespace lms::db
User::pointer User::create(Session& session, std::string_view loginName)
{
return session.getDboSession()->add(std::unique_ptr<User> {new User{ loginName }});
return session.getDboSession()->add(std::unique_ptr<User>{ new User{ loginName } });
}
std::size_t User::getCount(Session& session)
@@ -87,8 +88,7 @@ namespace lms::db
User::pointer User::find(Session& session, std::string_view name)
{
return utils::fetchQuerySingleResult(session.getDboSession()->find<User>()
.where("login_name = ?").bind(name));
return utils::fetchQuerySingleResult(session.getDboSession()->find<User>().where("login_name = ?").bind(name));
}
void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate)
+1 -2
View File
@@ -33,5 +33,4 @@ namespace lms::db::utils
// force second resolution
return Wt::WDateTime::fromTime_t(dateTime.toTime_t());
}
} // namespace lms::db::Utils
} // namespace lms::db::utils
+16 -16
View File
@@ -26,8 +26,8 @@
#include <Wt/Dbo/Dbo.h>
#include <Wt/WDateTime.h>
#include "database/Types.hpp"
#include "core/ITraceLogger.hpp"
#include "database/Types.hpp"
namespace lms::db::utils
{
@@ -35,7 +35,7 @@ namespace lms::db::utils
static inline constexpr char escapeChar{ '\\' };
std::string escapeLikeKeyword(std::string_view keywords);
template <typename Query>
template<typename Query>
void applyRange(Query& query, std::optional<Range> range)
{
if (range)
@@ -45,21 +45,21 @@ namespace lms::db::utils
}
}
template <typename T>
template<typename T>
auto fetchFirstResult(const Wt::Dbo::collection<T>& collection)
{
LMS_SCOPED_TRACE_DETAILED("Database", "FetchFirstResult");
return collection.begin();
}
template <typename T>
template<typename T>
void fetchNextResult(typename Wt::Dbo::collection<T>::const_iterator& it)
{
LMS_SCOPED_TRACE_DETAILED("Database", "FetchNextResult");
it++;
}
template <typename T, typename Func>
template<typename T, typename Func>
void forEachResult(const Wt::Dbo::collection<T>& collection, Func&& func)
{
typename Wt::Dbo::collection<T>::const_iterator it{ fetchFirstResult(collection) };
@@ -70,23 +70,23 @@ namespace lms::db::utils
}
}
template <typename T>
template<typename T>
struct QueryResultType;
template <class ResultType, typename BindStrategy>
template<class ResultType, typename BindStrategy>
struct QueryResultType<Wt::Dbo::Query<ResultType, BindStrategy>>
{
using type = ResultType;
};
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryResult(const Query& query, UnaryFunc&& func)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString());
forEachResult(query.resultList(), std::forward<UnaryFunc>(func));
}
template <typename T, typename Query>
template<typename T, typename Query>
std::vector<T> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -95,7 +95,7 @@ namespace lms::db::utils
return std::vector<T>(collection.begin(), collection.end());
}
template <typename Query>
template<typename Query>
std::vector<typename QueryResultType<Query>::type> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
@@ -103,15 +103,15 @@ namespace lms::db::utils
auto collection{ query.resultList() };
return std::vector<typename QueryResultType<Query>::type>(collection.begin(), collection.end());
}
template <typename Query>
template<typename Query>
auto fetchQuerySingleResult(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString());
return query.resultValue();
}
template <typename ResultType, typename Query>
template<typename ResultType, typename Query>
RangeResults<ResultType> execRangeQuery(Query& query, const std::optional<Range> range)
{
RangeResults<ResultType> res;
@@ -137,7 +137,7 @@ namespace lms::db::utils
return res;
}
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryRangeResult(Query& query, std::optional<Range> range, UnaryFunc&& func)
{
if (range)
@@ -146,7 +146,7 @@ namespace lms::db::utils
forEachQueryResult(query, std::forward<UnaryFunc>(func));
}
template <typename Query, typename UnaryFunc>
template<typename Query, typename UnaryFunc>
void forEachQueryRangeResult(Query& query, std::optional<Range> range, bool& moreResults, UnaryFunc&& func)
{
using ResultType = typename QueryResultType<Query>::type;
@@ -173,4 +173,4 @@ namespace lms::db::utils
}
Wt::WDateTime normalizeDateTime(const Wt::WDateTime& dateTime);
}
} // namespace lms::db::utils