Auto reformatted the base, ref #470
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) };
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,4 +54,4 @@ namespace lms::db
|
||||
{
|
||||
bool doDbMigration(Session& session); // return true if migration was performed
|
||||
}
|
||||
}
|
||||
} // namespace lms::db
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user