Chaned the way the inner dbo session is accessed + added exec wrappers for queries

This commit is contained in:
emeric
2024-03-31 13:13:01 +02:00
parent 4ba8330194
commit 418286a1f2
19 changed files with 386 additions and 423 deletions
+18 -19
View File
@@ -41,7 +41,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
// TODO remove distinct and use group by // TODO remove distinct and use group by
auto query{ session.getDboSession().query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM artist a") }; auto query{ session.getDboSession()->query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM artist a") };
if (params.sortMethod == ArtistSortMethod::LastWritten if (params.sortMethod == ArtistSortMethod::LastWritten
|| params.writtenAfter.isValid() || params.writtenAfter.isValid()
|| params.linkType || params.linkType
@@ -175,21 +175,21 @@ namespace lms::db
Artist::pointer Artist::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID) Artist::pointer Artist::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID)
{ {
return session.getDboSession().add(std::unique_ptr<Artist>{ new Artist{ name, MBID } }); return session.getDboSession()->add(std::unique_ptr<Artist>{ new Artist{ name, MBID } });
} }
std::size_t Artist::getCount(Session& session) std::size_t Artist::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM artist"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM artist"));
} }
void Artist::find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function<void(const Artist::pointer&)>& func, MediaLibraryId library) void Artist::find(Session& session, ArtistId& lastRetrievedArtist, std::size_t count, const std::function<void(const Artist::pointer&)>& func, MediaLibraryId library)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a") auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Artist>>("SELECT a FROM artist a")
.orderBy("a.id") .orderBy("a.id")
.where("a.id > ?").bind(lastRetrievedArtist) .where("a.id > ?").bind(lastRetrievedArtist)
.limit(static_cast<int>(count)) }; .limit(static_cast<int>(count)) };
@@ -201,7 +201,7 @@ namespace lms::db
query.where("t.media_library_id = ?").bind(library); query.where("t.media_library_id = ?").bind(library);
} }
auto collection{ query.resultList() }; auto collection{ utils::execMultiResultQuery(query) };
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult) for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
@@ -214,9 +214,9 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res = session.getDboSession().find<Artist>() Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res{ utils::execMultiResultQuery(session.getDboSession()->find<Artist>()
.where("name = ?").bind(std::string{ name, 0, _maxNameLength }) .where("name = ?").bind(std::string{ name, 0, _maxNameLength })
.orderBy("LENGTH(mbid) DESC"); // put mbid entries first .orderBy("LENGTH(mbid) DESC")) }; // put mbid entries first
return std::vector<Artist::pointer>(res.begin(), res.end()); return std::vector<Artist::pointer>(res.begin(), res.end());
} }
@@ -224,27 +224,26 @@ namespace lms::db
Artist::pointer Artist::find(Session& session, const core::UUID& mbid) Artist::pointer Artist::find(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Artist>().where("mbid = ?").bind(std::string{ mbid.getAsString() }).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<Artist>().where("mbid = ?").bind(std::string{ mbid.getAsString() }));
} }
Artist::pointer Artist::find(Session& session, ArtistId id) Artist::pointer Artist::find(Session& session, ArtistId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Artist>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<Artist>().where("id = ?").bind(id));
} }
bool Artist::exists(Session& session, ArtistId id) bool Artist::exists(Session& session, ArtistId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT 1 FROM artist").where("id = ?").bind(id).resultValue() == 1; return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 FROM artist").where("id = ?").bind(id)) == 1;
} }
RangeResults<ArtistId> Artist::findOrphanIds(Session& session, std::optional<Range> range) RangeResults<ArtistId> Artist::findOrphanIds(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ArtistId>("SELECT DISTINCT a.id FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)") }; auto query{ session.getDboSession()->query<ArtistId>("SELECT DISTINCT a.id FROM artist a WHERE NOT EXISTS(SELECT 1 FROM track t INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id WHERE t.id = t_a_l.track_id)") };
return utils::execQuery<ArtistId>(query, range); return utils::execRangeQuery<ArtistId>(query, range);
} }
RangeResults<ArtistId> Artist::findIds(Session& session, const FindParameters& params) RangeResults<ArtistId> Artist::findIds(Session& session, const FindParameters& params)
@@ -252,7 +251,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<ArtistId>(session, params) }; auto query{ createQuery<ArtistId>(session, params) };
return utils::execQuery<ArtistId>(query, params.range); return utils::execRangeQuery<ArtistId>(query, params.range);
} }
RangeResults<Artist::pointer> Artist::find(Session& session, const FindParameters& params) RangeResults<Artist::pointer> Artist::find(Session& session, const FindParameters& params)
@@ -260,7 +259,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) }; auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) };
return utils::execQuery<Artist::pointer>(query, params.range); return utils::execRangeQuery<Artist::pointer>(query, params.range);
} }
void Artist::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func) void Artist::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func)
@@ -268,7 +267,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) }; auto query{ createQuery<Wt::Dbo::ptr<Artist>>(session, params) };
utils::execQuery(query, params.range, func); utils::execRangeQuery(query, params.range, func);
} }
RangeResults<ArtistId> Artist::findSimilarArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes, std::optional<Range> range) const RangeResults<ArtistId> Artist::findSimilarArtistIds(core::EnumSet<TrackArtistLinkType> artistLinkTypes, std::optional<Range> range) const
@@ -315,7 +314,7 @@ namespace lms::db
for (const TrackArtistLinkType type : artistLinkTypes) for (const TrackArtistLinkType type : artistLinkTypes)
query.bind(type); query.bind(type);
return utils::execQuery<ArtistId>(query, range); return utils::execRangeQuery<ArtistId>(query, range);
} }
std::vector<std::vector<Cluster::pointer>> Artist::getClusterGroups(std::vector<ClusterTypeId> clusterTypeIds, std::size_t size) const std::vector<std::vector<Cluster::pointer>> Artist::getClusterGroups(std::vector<ClusterTypeId> clusterTypeIds, std::size_t size) const
@@ -338,12 +337,12 @@ namespace lms::db
oss << " " << where.get(); oss << " " << where.get();
oss << "GROUP BY c.id ORDER BY COUNT(DISTINCT c.id) DESC"; oss << "GROUP BY c.id ORDER BY COUNT(DISTINCT c.id) DESC";
Wt::Dbo::Query<Wt::Dbo::ptr<Cluster>> query = session()->query<Wt::Dbo::ptr<Cluster>>(oss.str()); Wt::Dbo::Query<Wt::Dbo::ptr<Cluster>> query{ session()->query<Wt::Dbo::ptr<Cluster>>(oss.str()) };
for (const std::string& bindArg : where.getBindArgs()) for (const std::string& bindArg : where.getBindArgs())
query.bind(bindArg); query.bind(bindArg);
Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> queryRes = query; Wt::Dbo::collection<Wt::Dbo::ptr<Cluster>> queryRes{ utils::execMultiResultQuery(query) };
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
for (const Cluster::pointer& cluster : queryRes) for (const Cluster::pointer& cluster : queryRes)
+21 -25
View File
@@ -24,38 +24,34 @@
#include "database/User.hpp" #include "database/User.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
AuthToken::AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user) AuthToken::AuthToken(std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user)
: _value {value} : _value{ value }
, _expiry {expiry} , _expiry{ expiry }
, _user {getDboPtr(user)} , _user{ getDboPtr(user) }
{ {
} }
AuthToken::pointer AuthToken::pointer AuthToken::create(Session& session, std::string_view value, const Wt::WDateTime& expiry, ObjectPtr<User> user)
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 void AuthToken::removeExpiredTokens(Session& session, const Wt::WDateTime& now)
AuthToken::removeExpiredTokens(Session& session, const Wt::WDateTime& now) {
{ session.checkWriteTransaction();
session.checkWriteTransaction();
session.getDboSession().execute("DELETE FROM auth_token WHERE expiry < ?").bind(now); session.getDboSession()->execute("DELETE FROM auth_token WHERE expiry < ?").bind(now);
} }
AuthToken::pointer AuthToken::pointer AuthToken::find(Session& session, std::string_view value)
AuthToken::find(Session& session, std::string_view value) {
{ session.checkReadTransaction();
session.checkReadTransaction();
return session.getDboSession().find<AuthToken>() return utils::execSingleResultQuery(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value));
.where("value = ?").bind(value) }
.resultValue();
}
} }
+27 -29
View File
@@ -38,7 +38,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM cluster c") }; auto query{ session.getDboSession()->query<ResultType>("SELECT DISTINCT " + std::string{ itemToSelect } + " FROM cluster c") };
if (params.track.isValid() || params.release.isValid()) if (params.track.isValid() || params.release.isValid())
{ {
@@ -86,14 +86,14 @@ namespace lms::db
Cluster::pointer Cluster::create(Session& session, ObjectPtr<ClusterType> type, std::string_view name) 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) std::size_t Cluster::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM cluster"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM cluster"));
} }
RangeResults<ClusterId> Cluster::findIds(Session& session, const FindParameters& params) RangeResults<ClusterId> Cluster::findIds(Session& session, const FindParameters& params)
@@ -101,7 +101,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<ClusterId>(session, params) }; auto query{ createQuery<ClusterId>(session, params) };
return utils::execQuery<ClusterId>(query, params.range); return utils::execRangeQuery<ClusterId>(query, params.range);
} }
RangeResults<Cluster::pointer> Cluster::find(Session& session, const FindParameters& params) RangeResults<Cluster::pointer> Cluster::find(Session& session, const FindParameters& params)
@@ -109,38 +109,38 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Cluster>>(session, params) }; auto query{ createQuery<Wt::Dbo::ptr<Cluster>>(session, params) };
return utils::execQuery<Cluster::pointer>(query, params.range); return utils::execRangeQuery<Cluster::pointer>(query, params.range);
} }
RangeResults<ClusterId> Cluster::findOrphanIds(Session& session, std::optional<Range> range) RangeResults<ClusterId> Cluster::findOrphanIds(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ClusterId>("SELECT DISTINCT c.id FROM cluster c WHERE NOT EXISTS(SELECT 1 FROM track_cluster t_c WHERE t_c.cluster_id = c.id)") }; auto query{ session.getDboSession()->query<ClusterId>("SELECT DISTINCT c.id FROM cluster c WHERE NOT EXISTS(SELECT 1 FROM track_cluster t_c WHERE t_c.cluster_id = c.id)") };
return utils::execQuery<ClusterId>(query, range); return utils::execRangeQuery<ClusterId>(query, range);
} }
Cluster::pointer Cluster::find(Session& session, ClusterId id) Cluster::pointer Cluster::find(Session& session, ClusterId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Cluster>().where("id = ?").bind(id).resultValue(); return session.getDboSession()->find<Cluster>().where("id = ?").bind(id).resultValue();
} }
std::size_t Cluster::computeTrackCount(Session& session, ClusterId id) std::size_t Cluster::computeTrackCount(Session& session, ClusterId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id") return utils::execSingleResultQuery(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).resultValue(); .where("t_c.cluster_id = ?").bind(id));
} }
std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id) std::size_t Cluster::computeReleaseCount(Session& session, ClusterId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return 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") return utils::execSingleResultQuery(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).resultValue(); .where("t_c.cluster_id = ?").bind(id));
} }
void Cluster::addTrack(ObjectPtr<Track> track) void Cluster::addTrack(ObjectPtr<Track> track)
@@ -155,7 +155,7 @@ namespace lms::db
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") 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()) }; .where("c.id = ?").bind(getId()) };
return utils::execQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
ClusterType::ClusterType(std::string_view name) ClusterType::ClusterType(std::string_view name)
@@ -165,61 +165,60 @@ namespace lms::db
ClusterType::pointer ClusterType::create(Session& session, std::string_view name) 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) std::size_t ClusterType::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM cluster_type"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM cluster_type"));
} }
RangeResults<ClusterTypeId> ClusterType::findOrphanIds(Session& session, std::optional<Range> range) RangeResults<ClusterTypeId> ClusterType::findOrphanIds(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ClusterTypeId>( auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT c_t.id from cluster_type c_t" "SELECT c_t.id from cluster_type c_t"
" LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id") " LEFT OUTER JOIN cluster c ON c_t.id = c.cluster_type_id")
.where("c.id IS NULL") }; .where("c.id IS NULL") };
return utils::execQuery<ClusterTypeId>(query, range); return utils::execRangeQuery<ClusterTypeId>(query, range);
} }
RangeResults<ClusterTypeId> ClusterType::findUsed(Session& session, std::optional<Range> range) RangeResults<ClusterTypeId> ClusterType::findUsed(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ClusterTypeId>( auto query{ session.getDboSession()->query<ClusterTypeId>(
"SELECT DISTINCT c_t.id from cluster_type c_t") "SELECT DISTINCT c_t.id from cluster_type c_t")
.join("cluster c ON c_t.id = c.cluster_type_id") }; .join("cluster c ON c_t.id = c.cluster_type_id") };
return utils::execQuery<ClusterTypeId>(query, range); return utils::execRangeQuery<ClusterTypeId>(query, range);
} }
ClusterType::pointer ClusterType::find(Session& session, std::string_view name) ClusterType::pointer ClusterType::find(Session& session, std::string_view name)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<ClusterType>().where("name = ?").bind(std::string{ name }).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<ClusterType>().where("name = ?").bind(std::string{ name }));
} }
ClusterType::pointer ClusterType::find(Session& session, ClusterTypeId id) ClusterType::pointer ClusterType::find(Session& session, ClusterTypeId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<ClusterType>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<ClusterType>().where("id = ?").bind(id));
} }
RangeResults<ClusterTypeId> ClusterType::findIds(Session& session, std::optional<Range> range) RangeResults<ClusterTypeId> ClusterType::findIds(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ClusterTypeId>("SELECT id from cluster_type") }; auto query{ session.getDboSession()->query<ClusterTypeId>("SELECT id from cluster_type") };
return utils::execQuery<ClusterTypeId>(query, range); return utils::execRangeQuery<ClusterTypeId>(query, range);
} }
Cluster::pointer ClusterType::getCluster(const std::string& name) const Cluster::pointer ClusterType::getCluster(const std::string& name) const
@@ -227,9 +226,9 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
return session()->find<Cluster>() return utils::execSingleResultQuery(session()->find<Cluster>()
.where("name = ?").bind(name) .where("name = ?").bind(name)
.where("cluster_type_id = ?").bind(getId()).resultValue(); .where("cluster_type_id = ?").bind(getId()));
} }
std::vector<Cluster::pointer> ClusterType::getClusters() const std::vector<Cluster::pointer> ClusterType::getClusters() const
@@ -237,10 +236,9 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
auto res = session()->find<Cluster>() auto res {utils::execMultiResultQuery(session()->find<Cluster>()
.where("cluster_type_id = ?").bind(getId()) .where("cluster_type_id = ?").bind(getId())
.orderBy("name") .orderBy("name"))};
.resultList();
return std::vector<Cluster::pointer>(res.begin(), res.end()); return std::vector<Cluster::pointer>(res.begin(), res.end());
} }
+33 -38
View File
@@ -29,9 +29,9 @@ namespace lms::db
{ {
namespace namespace
{ {
Wt::Dbo::Query<ArtistId> createArtistsQuery(Wt::Dbo::Session& session, const Listen::ArtistStatsFindParameters& params) Wt::Dbo::Query<ArtistId> createArtistsQuery(Session& session, const Listen::ArtistStatsFindParameters& params)
{ {
auto query{ session.query<ArtistId>("SELECT a.id from artist a") auto query{ session.getDboSession()->query<ArtistId>("SELECT a.id from artist a")
.join("track t ON t.id = t_a_l.track_id") .join("track t ON t.id = t_a_l.track_id")
.join("track_artist_link t_a_l ON t_a_l.artist_id = a.id") .join("track_artist_link t_a_l ON t_a_l.artist_id = a.id")
.join("listen l ON l.track_id = t.id") }; .join("listen l ON l.track_id = t.id") };
@@ -75,9 +75,9 @@ namespace lms::db
return query; return query;
} }
Wt::Dbo::Query<ReleaseId> createReleasesQuery(Wt::Dbo::Session& session, const Listen::StatsFindParameters& params) Wt::Dbo::Query<ReleaseId> createReleasesQuery(Session& session, const Listen::StatsFindParameters& params)
{ {
auto query{ session.query<ReleaseId>("SELECT r.id from release r") auto query{ session.getDboSession()->query<ReleaseId>("SELECT r.id from release r")
.join("track t ON t.release_id = r.id") .join("track t ON t.release_id = r.id")
.join("listen l ON l.track_id = t.id") }; .join("listen l ON l.track_id = t.id") };
@@ -120,9 +120,9 @@ namespace lms::db
return query; return query;
} }
Wt::Dbo::Query<TrackId> createTracksQuery(Wt::Dbo::Session& session, const Listen::StatsFindParameters& params) Wt::Dbo::Query<TrackId> createTracksQuery(Session& session, const Listen::StatsFindParameters& params)
{ {
auto query{ session.query<TrackId>("SELECT t.id from track t") auto query{ session.getDboSession()->query<TrackId>("SELECT t.id from track t")
.join("listen l ON l.track_id = t.id") }; .join("listen l ON l.track_id = t.id") };
if (params.user.isValid()) if (params.user.isValid())
@@ -174,26 +174,26 @@ namespace lms::db
Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime) Listen::pointer Listen::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> track, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
{ {
session.checkWriteTransaction(); 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) std::size_t Listen::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM listen"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM listen"));
} }
Listen::pointer Listen::find(Session& session, ListenId id) Listen::pointer Listen::find(Session& session, ListenId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Listen>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<Listen>().where("id = ?").bind(id));
} }
RangeResults<ListenId> Listen::find(Session& session, const FindParameters& parameters) RangeResults<ListenId> Listen::find(Session& session, const FindParameters& parameters)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ListenId>("SELECT id FROM listen") auto query{ session.getDboSession()->query<ListenId>("SELECT id FROM listen")
.orderBy("date_time") }; .orderBy("date_time") };
if (parameters.user.isValid()) if (parameters.user.isValid())
@@ -205,100 +205,98 @@ namespace lms::db
if (parameters.syncState) if (parameters.syncState)
query.where("sync_state = ?").bind(*parameters.syncState); query.where("sync_state = ?").bind(*parameters.syncState);
return utils::execQuery<ListenId>(query, parameters.range); return utils::execRangeQuery<ListenId>(query, parameters.range);
} }
Listen::pointer Listen::find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime) Listen::pointer Listen::find(Session& session, UserId userId, TrackId trackId, ScrobblingBackend backend, const Wt::WDateTime& dateTime)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Listen>() return utils::execSingleResultQuery(session.getDboSession()->find<Listen>()
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId) .where("track_id = ?").bind(trackId)
.where("backend = ?").bind(backend) .where("backend = ?").bind(backend)
.where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())) .where("date_time = ?").bind(Wt::WDateTime::fromTime_t(dateTime.toTime_t())));
.resultValue();
} }
RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params) RangeResults<ArtistId> Listen::getTopArtists(Session& session, const ArtistStatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createArtistsQuery(session.getDboSession(), params) }; auto query{ createArtistsQuery(session, params) };
auto collection{ query auto collection{ query
.orderBy("COUNT(a.id) DESC") .orderBy("COUNT(a.id) DESC")
.groupBy("a.id") }; .groupBy("a.id") };
return utils::execQuery<ArtistId>(query, params.range); return utils::execRangeQuery<ArtistId>(query, params.range);
} }
RangeResults<ReleaseId> Listen::getTopReleases(Session& session, const StatsFindParameters& params) RangeResults<ReleaseId> Listen::getTopReleases(Session& session, const StatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createReleasesQuery(session.getDboSession(), params) auto query{ createReleasesQuery(session, params)
.orderBy("COUNT(r.id) DESC") .orderBy("COUNT(r.id) DESC")
.groupBy("r.id") }; .groupBy("r.id") };
return utils::execQuery<ReleaseId>(query, params.range); return utils::execRangeQuery<ReleaseId>(query, params.range);
} }
RangeResults<TrackId> Listen::getTopTracks(Session& session, const StatsFindParameters& params) RangeResults<TrackId> Listen::getTopTracks(Session& session, const StatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createTracksQuery(session.getDboSession(), params) auto query{ createTracksQuery(session, params)
.orderBy("COUNT(t.id) DESC") .orderBy("COUNT(t.id) DESC")
.groupBy("t.id") }; .groupBy("t.id") };
return utils::execQuery<TrackId>(query, params.range); return utils::execRangeQuery<TrackId>(query, params.range);
} }
RangeResults<ArtistId> Listen::getRecentArtists(Session& session, const ArtistStatsFindParameters& params) RangeResults<ArtistId> Listen::getRecentArtists(Session& session, const ArtistStatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createArtistsQuery(session.getDboSession(), params) 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") }; .orderBy("l.date_time DESC") };
return utils::execQuery<ArtistId>(query, params.range); return utils::execRangeQuery<ArtistId>(query, params.range);
} }
RangeResults<ReleaseId> Listen::getRecentReleases(Session& session, const StatsFindParameters& params) RangeResults<ReleaseId> Listen::getRecentReleases(Session& session, const StatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createReleasesQuery(session.getDboSession(), params) 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") }; .orderBy("l.date_time DESC") };
return utils::execQuery<ReleaseId>(query, params.range); return utils::execRangeQuery<ReleaseId>(query, params.range);
} }
RangeResults<TrackId> Listen::getRecentTracks(Session& session, const StatsFindParameters& params) RangeResults<TrackId> Listen::getRecentTracks(Session& session, const StatsFindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createTracksQuery(session.getDboSession(), params) 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") }; .orderBy("l.date_time DESC") };
return utils::execQuery<TrackId>(query, params.range); return utils::execRangeQuery<TrackId>(query, params.range);
} }
std::size_t Listen::getCount(Session& session, UserId userId, TrackId trackId) std::size_t Listen::getCount(Session& session, UserId userId, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) from listen l") return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l")
.join("user u ON u.id = l.user_id") .join("user u ON u.id = l.user_id")
.where("l.track_id = ?").bind(trackId) .where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId) .where("l.user_id = ?").bind(userId)
.where("l.backend = u.scrobbling_backend") .where("l.backend = u.scrobbling_backend"));
.resultValue();
} }
std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId) std::size_t Listen::getCount(Session& session, UserId userId, ReleaseId releaseId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>( return utils::execSingleResultQuery(session.getDboSession()->query<int>(
"SELECT IFNULL(MIN(count_result), 0)" "SELECT IFNULL(MIN(count_result), 0)"
" FROM (" " FROM ("
" SELECT COUNT(l.track_id) AS count_result" " SELECT COUNT(l.track_id) AS count_result"
@@ -308,8 +306,7 @@ namespace lms::db
" GROUP BY t.id)") " GROUP BY t.id)")
.bind(userId) .bind(userId)
.bind(userId) .bind(userId)
.bind(releaseId) .bind(releaseId));
.resultValue();
} }
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId) Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, ReleaseId releaseId)
@@ -317,26 +314,24 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") return utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.join("track t ON l.track_id = t.id") .join("track t ON l.track_id = t.id")
.where("t.release_id = ?").bind(releaseId) .where("t.release_id = ?").bind(releaseId)
.where("l.user_id = ?").bind(userId) .where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) .where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC") .orderBy("l.date_time DESC")
.limit(1) .limit(1));
.resultValue();
} }
Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId) Listen::pointer Listen::getMostRecentListen(Session& session, UserId userId, ScrobblingBackend backend, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return session.getDboSession().query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") return utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l")
.where("l.track_id = ?").bind(trackId) .where("l.track_id = ?").bind(trackId)
.where("l.user_id = ?").bind(userId) .where("l.user_id = ?").bind(userId)
.where("l.backend = ?").bind(backend) .where("l.backend = ?").bind(backend)
.orderBy("l.date_time DESC") .orderBy("l.date_time DESC")
.limit(1) .limit(1));
.resultValue();
} }
} // namespace lms::db } // namespace lms::db
+7 -6
View File
@@ -25,6 +25,7 @@
#include "IdTypeTraits.hpp" #include "IdTypeTraits.hpp"
#include "PathTraits.hpp" #include "PathTraits.hpp"
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
@@ -36,42 +37,42 @@ namespace lms::db
MediaLibrary::pointer MediaLibrary::create(Session& session, const std::filesystem::path& p, std::string_view name) MediaLibrary::pointer MediaLibrary::create(Session& session, const std::filesystem::path& p, std::string_view name)
{ {
return session.getDboSession().add(std::unique_ptr<MediaLibrary>{ new MediaLibrary{ p, name } }); return session.getDboSession()->add(std::unique_ptr<MediaLibrary>{ new MediaLibrary{ p, name } });
} }
std::size_t MediaLibrary::getCount(Session& session) std::size_t MediaLibrary::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM media_library"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM media_library"));
} }
MediaLibrary::pointer MediaLibrary::find(Session& session, MediaLibraryId id) MediaLibrary::pointer MediaLibrary::find(Session& session, MediaLibraryId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<MediaLibrary>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("id = ?").bind(id));
} }
MediaLibrary::pointer MediaLibrary::find(Session& session, std::string_view name) MediaLibrary::pointer MediaLibrary::find(Session& session, std::string_view name)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<MediaLibrary>().where("name = ?").bind(name).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("name = ?").bind(name));
} }
MediaLibrary::pointer MediaLibrary::find(Session& session, const std::filesystem::path& p) MediaLibrary::pointer MediaLibrary::find(Session& session, const std::filesystem::path& p)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<MediaLibrary>().where("path = ?").bind(p).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("path = ?").bind(p));
} }
void MediaLibrary::find(Session& session, std::function<void(const MediaLibrary::pointer&)> func) void MediaLibrary::find(Session& session, std::function<void(const MediaLibrary::pointer&)> func)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto results{ session.getDboSession().find<MediaLibrary>().resultList() }; auto results{ utils::execMultiResultQuery(session.getDboSession()->find<MediaLibrary>()) };
for (const auto& result : results) for (const auto& result : results)
func(result); func(result);
} }
+87 -87
View File
@@ -43,9 +43,9 @@ namespace lms::db
{ {
session.checkWriteTransaction(); session.checkWriteTransaction();
pointer versionInfo{ session.getDboSession().find<VersionInfo>() }; pointer versionInfo{ session.getDboSession()->find<VersionInfo>() };
if (!versionInfo) if (!versionInfo)
return session.getDboSession().add(std::make_unique<VersionInfo>()); return session.getDboSession()->add(std::make_unique<VersionInfo>());
return versionInfo; return versionInfo;
} }
@@ -54,7 +54,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<VersionInfo>(); return session.getDboSession()->find<VersionInfo>();
} }
} }
@@ -85,7 +85,7 @@ namespace lms::db::Migration
{ {
// remove name from track_artist_link // remove name from track_artist_link
// Drop Auth mode // Drop Auth mode
session.getDboSession().execute(R"( session.getDboSession()->execute(R"(
CREATE TABLE IF NOT EXISTS "track_artist_link_backup" ( CREATE TABLE IF NOT EXISTS "track_artist_link_backup" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
@@ -96,49 +96,49 @@ CREATE TABLE IF NOT EXISTS "track_artist_link_backup" (
constraint "fk_track_artist_link_artist" foreign key ("artist_id") references "artist" ("id") on delete cascade deferrable initially deferred constraint "fk_track_artist_link_artist" foreign key ("artist_id") references "artist" ("id") on delete cascade deferrable initially deferred
); );
))"); ))");
session.getDboSession().execute("INSERT INTO track_artist_link_backup SELECT id, version, type, track_id, artist_id FROM track_artist_link"); session.getDboSession()->execute("INSERT INTO track_artist_link_backup SELECT id, version, type, track_id, artist_id FROM track_artist_link");
session.getDboSession().execute("DROP TABLE track_artist_link"); session.getDboSession()->execute("DROP TABLE track_artist_link");
session.getDboSession().execute("ALTER TABLE track_artist_link_backup RENAME TO track_artist_link"); session.getDboSession()->execute("ALTER TABLE track_artist_link_backup RENAME TO track_artist_link");
} }
static void migrateFromV34(Session& session) static void migrateFromV34(Session& session)
{ {
// Add scrobbling state // Add scrobbling state
// By default, everything needs to be sent // 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_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_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_track ADD scrobbling_state INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*ScrobblingState::PendingAdd*/0)) + ")");
} }
static void migrateFromV35(Session& session) static void migrateFromV35(Session& session)
{ {
// Add creattion/last modif date time for tracklists // Add creattion/last modif date time for tracklists
session.getDboSession().execute("ALTER TABLE tracklist ADD creation_date_time TEXT"); session.getDboSession()->execute("ALTER TABLE tracklist ADD creation_date_time TEXT");
session.getDboSession().execute("ALTER TABLE tracklist ADD last_modified_date_time TEXT"); session.getDboSession()->execute("ALTER TABLE tracklist ADD last_modified_date_time TEXT");
} }
static void migrateFromV36(Session& session) static void migrateFromV36(Session& session)
{ {
// Increased precision for track durations (now in milliseconds instead of secodns) // Increased precision for track durations (now in milliseconds instead of secodns)
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV37(Session& session) static void migrateFromV37(Session& session)
{ {
// Support Performer tags (via subtypes) // Support Performer tags (via subtypes)
session.getDboSession().execute("ALTER TABLE track_artist_link ADD subtype TEXT"); session.getDboSession()->execute("ALTER TABLE track_artist_link ADD subtype TEXT");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV38(Session& session) static void migrateFromV38(Session& session)
{ {
// migrate release-specific tags from Track to Release // migrate release-specific tags from Track to Release
session.getDboSession().execute("ALTER TABLE release ADD total_disc INTEGER"); session.getDboSession()->execute("ALTER TABLE release ADD total_disc INTEGER");
session.getDboSession().execute(R"( session.getDboSession()->execute(R"(
CREATE TABLE IF NOT EXISTS "track_backup" ( CREATE TABLE IF NOT EXISTS "track_backup" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
@@ -165,177 +165,177 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
constraint "fk_track_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred constraint "fk_track_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred
); );
))"); ))");
session.getDboSession().execute("INSERT INTO track_backup SELECT id, version, scan_version, track_number, disc_number, total_track, disc_subtitle, name, duration, date, original_date, file_path, file_last_write, file_added, has_cover, mbid, recording_mbid, copyright, copyright_url, track_replay_gain, release_replay_gain, release_id FROM track"); session.getDboSession()->execute("INSERT INTO track_backup SELECT id, version, scan_version, track_number, disc_number, total_track, disc_subtitle, name, duration, date, original_date, file_path, file_last_write, file_added, has_cover, mbid, recording_mbid, copyright, copyright_url, track_replay_gain, release_replay_gain, release_id FROM track");
session.getDboSession().execute("DROP TABLE track"); session.getDboSession()->execute("DROP TABLE track");
session.getDboSession().execute("ALTER TABLE track_backup RENAME TO track"); session.getDboSession()->execute("ALTER TABLE track_backup RENAME TO track");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV39(Session& session) static void migrateFromV39(Session& session)
{ {
// add release type // add release type
session.getDboSession().execute("ALTER TABLE release ADD primary_type INTEGER"); session.getDboSession()->execute("ALTER TABLE release ADD primary_type INTEGER");
session.getDboSession().execute("ALTER TABLE release ADD secondary_types INTEGER"); session.getDboSession()->execute("ALTER TABLE release ADD secondary_types INTEGER");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV40(Session& session) static void migrateFromV40(Session& session)
{ {
// add artist_display_name in Release and Track // add artist_display_name in Release and Track
session.getDboSession().execute("ALTER TABLE release ADD artist_display_name TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE release ADD artist_display_name TEXT NOT NULL DEFAULT ''");
session.getDboSession().execute("ALTER TABLE track ADD artist_display_name TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE track ADD artist_display_name TEXT NOT NULL DEFAULT ''");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV41(Session& session) static void migrateFromV41(Session& session)
{ {
// add artist_display_name in Release and Track // add artist_display_name in Release and Track
session.getDboSession().execute("ALTER TABLE user RENAME COLUMN subsonic_transcode_format TO subsonic_default_transcode_format"); session.getDboSession()->execute("ALTER TABLE user RENAME COLUMN subsonic_transcode_format TO subsonic_default_transcode_format");
session.getDboSession().execute("ALTER TABLE user RENAME COLUMN subsonic_transcode_bitrate TO subsonic_default_transcode_bitrate"); session.getDboSession()->execute("ALTER TABLE user RENAME COLUMN subsonic_transcode_bitrate TO subsonic_default_transcode_bitrate");
session.getDboSession().execute("ALTER TABLE user DROP COLUMN subsonic_transcode_enable"); session.getDboSession()->execute("ALTER TABLE user DROP COLUMN subsonic_transcode_enable");
} }
static void migrateFromV42(Session& session) static void migrateFromV42(Session& session)
{ {
session.getDboSession().execute("DROP INDEX IF EXISTS listen_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS listen_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS listen_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS listen_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS listen_user_track_scrobbler_date_time_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS listen_user_track_scrobbler_date_time_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_artist_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_artist_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_artist_artist_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_artist_artist_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_release_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_release_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_release_release_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_release_release_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_track_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_track_user_scrobbler_idx");
session.getDboSession().execute("DROP INDEX IF EXISTS starred_track_track_user_scrobbler_idx"); session.getDboSession()->execute("DROP INDEX IF EXISTS starred_track_track_user_scrobbler_idx");
// New feedback service that now handles the star/unstar stuff (that was previously handled by the scrobbling service) // New feedback service that now handles the star/unstar stuff (that was previously handled by the scrobbling service)
session.getDboSession().execute("ALTER TABLE user RENAME COLUMN scrobbler TO scrobbling_backend"); session.getDboSession()->execute("ALTER TABLE user RENAME COLUMN scrobbler TO scrobbling_backend");
session.getDboSession().execute("ALTER TABLE user ADD feedback_backend INTEGER"); session.getDboSession()->execute("ALTER TABLE user ADD feedback_backend INTEGER");
session.getDboSession().execute("ALTER TABLE listen RENAME COLUMN scrobbler TO backend"); session.getDboSession()->execute("ALTER TABLE listen RENAME COLUMN scrobbler TO backend");
session.getDboSession().execute("ALTER TABLE listen RENAME COLUMN scrobbling_state TO sync_state"); session.getDboSession()->execute("ALTER TABLE listen RENAME COLUMN scrobbling_state TO sync_state");
session.getDboSession().execute("ALTER TABLE starred_artist RENAME COLUMN scrobbler TO backend"); session.getDboSession()->execute("ALTER TABLE starred_artist RENAME COLUMN scrobbler TO backend");
session.getDboSession().execute("ALTER TABLE starred_artist RENAME COLUMN scrobbling_state TO sync_state"); session.getDboSession()->execute("ALTER TABLE starred_artist RENAME COLUMN scrobbling_state TO sync_state");
session.getDboSession().execute("ALTER TABLE starred_release RENAME COLUMN scrobbler TO backend"); session.getDboSession()->execute("ALTER TABLE starred_release RENAME COLUMN scrobbler TO backend");
session.getDboSession().execute("ALTER TABLE starred_release RENAME COLUMN scrobbling_state TO sync_state"); session.getDboSession()->execute("ALTER TABLE starred_release RENAME COLUMN scrobbling_state TO sync_state");
session.getDboSession().execute("ALTER TABLE starred_track RENAME COLUMN scrobbler TO backend"); session.getDboSession()->execute("ALTER TABLE starred_track RENAME COLUMN scrobbler TO backend");
session.getDboSession().execute("ALTER TABLE starred_track RENAME COLUMN scrobbling_state TO sync_state"); session.getDboSession()->execute("ALTER TABLE starred_track RENAME COLUMN scrobbling_state TO sync_state");
session.getDboSession().execute("UPDATE user SET feedback_backend = scrobbling_backend"); session.getDboSession()->execute("UPDATE user SET feedback_backend = scrobbling_backend");
} }
static void migrateFromV43(Session& session) static void migrateFromV43(Session& session)
{ {
// add counts in genre table // add counts in genre table
session.getDboSession().execute("ALTER TABLE cluster ADD track_count INTEGER"); session.getDboSession()->execute("ALTER TABLE cluster ADD track_count INTEGER");
session.getDboSession().execute("ALTER TABLE cluster ADD release_count INTEGER"); session.getDboSession()->execute("ALTER TABLE cluster ADD release_count INTEGER");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
static void migrateFromV44(Session& session) static void migrateFromV44(Session& session)
{ {
// add bitrate // add bitrate
session.getDboSession().execute("ALTER TABLE track ADD bitrate INTEGER NOT NULL DEFAULT 0"); session.getDboSession()->execute("ALTER TABLE track ADD bitrate INTEGER NOT NULL DEFAULT 0");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV45(Session& session) void migrateFromV45(Session& session)
{ {
// add subsonic_enable_transcoding_by_default, default is disabled // 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) void migrateFromV46(Session& session)
{ {
// add extra tags to parse // add extra tags to parse
session.getDboSession().execute(R"(CREATE TABLE IF NOT EXISTS "cluster_type_backup" ( session.getDboSession()->execute(R"(CREATE TABLE IF NOT EXISTS "cluster_type_backup" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
"name" text not null "name" text not null
);)"); );)");
session.getDboSession().execute("INSERT INTO cluster_type_backup SELECT id, version, name FROM cluster_type"); session.getDboSession()->execute("INSERT INTO cluster_type_backup SELECT id, version, name FROM cluster_type");
session.getDboSession().execute("DROP TABLE cluster_type"); session.getDboSession()->execute("DROP TABLE cluster_type");
session.getDboSession().execute("ALTER TABLE cluster_type_backup RENAME TO cluster_type"); session.getDboSession()->execute("ALTER TABLE cluster_type_backup RENAME TO cluster_type");
session.getDboSession().execute("ALTER TABLE scan_settings ADD COLUMN extra_tags_to_scan TEXT"); session.getDboSession()->execute("ALTER TABLE scan_settings ADD COLUMN extra_tags_to_scan TEXT");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV47(Session& session) void migrateFromV47(Session& session)
{ {
// release type, new way // release type, new way
session.getDboSession().execute("ALTER TABLE release DROP primary_type"); session.getDboSession()->execute("ALTER TABLE release DROP primary_type");
session.getDboSession().execute("ALTER TABLE release DROP secondary_types"); session.getDboSession()->execute("ALTER TABLE release DROP secondary_types");
session.getDboSession().execute(R"(CREATE TABLE IF NOT EXISTS "release_type" ( session.getDboSession()->execute(R"(CREATE TABLE IF NOT EXISTS "release_type" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
"name" text not null))"); "name" text not null))");
session.getDboSession().execute(R"(CREATE TABLE IF NOT EXISTS "release_release_type" ( session.getDboSession()->execute(R"(CREATE TABLE IF NOT EXISTS "release_release_type" (
"release_type_id" bigint, "release_type_id" bigint,
"release_id" bigint, "release_id" bigint,
primary key ("release_type_id", "release_id"), primary key ("release_type_id", "release_id"),
constraint "fk_release_release_type_key1" foreign key ("release_type_id") references "release_type" ("id") on delete cascade deferrable initially deferred, constraint "fk_release_release_type_key1" foreign key ("release_type_id") references "release_type" ("id") on delete cascade deferrable initially deferred,
constraint "fk_release_release_type_key2" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred constraint "fk_release_release_type_key2" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred
))"); ))");
session.getDboSession().execute(R"(CREATE INDEX "release_release_type_release_type" on "release_release_type" ("release_type_id"))"); session.getDboSession()->execute(R"(CREATE INDEX "release_release_type_release_type" on "release_release_type" ("release_type_id"))");
session.getDboSession().execute(R"(CREATE INDEX "release_release_type_release" on "release_release_type" ("release_id"))"); session.getDboSession()->execute(R"(CREATE INDEX "release_release_type_release" on "release_release_type" ("release_id"))");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV48(Session& session) void migrateFromV48(Session& session)
{ {
// Regression for the extra tags not being parsed // Regression for the extra tags not being parsed
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV49(Session& session) void migrateFromV49(Session& session)
{ {
// Add year / originalYear fields, as date / originalDate are not enough (we don't want a wrong date but year or nothing) // Add year / originalYear fields, as date / originalDate are not enough (we don't want a wrong date but year or nothing)
session.getDboSession().execute("ALTER TABLE track ADD year INTEGER"); session.getDboSession()->execute("ALTER TABLE track ADD year INTEGER");
session.getDboSession().execute("ALTER TABLE track ADD original_year INTEGER"); session.getDboSession()->execute("ALTER TABLE track ADD original_year INTEGER");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV50(Session& session) void migrateFromV50(Session& session)
{ {
// MediaLibrary support // MediaLibrary support
session.getDboSession().execute(R"(CREATE TABLE IF NOT EXISTS "media_library" ( session.getDboSession()->execute(R"(CREATE TABLE IF NOT EXISTS "media_library" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
"path" text not null, "path" text not null,
"name" text not null "name" text not null
))"); ))");
const int scanSettingsId{ session.getDboSession().query<int>("SELECT id FROM scan_settings") }; const int scanSettingsId{ session.getDboSession()->query<int>("SELECT id FROM scan_settings") };
// Convert the existing media_directory in the scan_settings table to a media_library with id '1' // Convert the existing media_directory in the scan_settings table to a media_library with id '1'
session.getDboSession().execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name") session.getDboSession()->execute(R"(INSERT INTO "media_library" ("id", "version", "path", "name")
SELECT 1, 0, s_s.media_directory, "Main" SELECT 1, 0, s_s.media_directory, "Main"
FROM scan_settings s_s FROM scan_settings s_s
WHERE id = ?)").bind(scanSettingsId); WHERE id = ?)").bind(scanSettingsId);
// Remove the outdated column in scan_settings // Remove the outdated column in scan_settings
session.getDboSession().execute("ALTER TABLE scan_settings DROP media_directory"); session.getDboSession()->execute("ALTER TABLE scan_settings DROP media_directory");
// Add the media_library column in tracks, with id '1' // Add the media_library column in tracks, with id '1'
session.getDboSession().execute(R"( session.getDboSession()->execute(R"(
CREATE TABLE IF NOT EXISTS "track_backup" ( CREATE TABLE IF NOT EXISTS "track_backup" (
"id" integer primary key autoincrement, "id" integer primary key autoincrement,
"version" integer not null, "version" integer not null,
@@ -369,7 +369,7 @@ CREATE TABLE IF NOT EXISTS "track_backup" (
))"); ))");
// Migrate data, with the new media_library_id field set to 1 // Migrate data, with the new media_library_id field set to 1
session.getDboSession().execute(R"(INSERT INTO track_backup session.getDboSession()->execute(R"(INSERT INTO track_backup
SELECT SELECT
id, id,
version, version,
@@ -399,33 +399,33 @@ SELECT
release_id, release_id,
1 1
FROM track)"); FROM track)");
session.getDboSession().execute("DROP TABLE track"); session.getDboSession()->execute("DROP TABLE track");
session.getDboSession().execute("ALTER TABLE track_backup RENAME TO track"); session.getDboSession()->execute("ALTER TABLE track_backup RENAME TO track");
} }
void migrateFromV51(Session& session) void migrateFromV51(Session& session)
{ {
// Add custom artist tag delimiters, no need to rescan since it has no effect when empty // Add custom artist tag delimiters, no need to rescan since it has no effect when empty
session.getDboSession().execute("ALTER TABLE scan_settings ADD artist_tag_delimiters TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE scan_settings ADD artist_tag_delimiters TEXT NOT NULL DEFAULT ''");
session.getDboSession().execute("ALTER TABLE scan_settings ADD default_tag_delimiters TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE scan_settings ADD default_tag_delimiters TEXT NOT NULL DEFAULT ''");
} }
void migrateFromV52(Session& session) void migrateFromV52(Session& session)
{ {
// Add sort name for releases // Add sort name for releases
session.getDboSession().execute("ALTER TABLE release ADD sort_name TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE release ADD sort_name TEXT NOT NULL DEFAULT ''");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void migrateFromV53(Session& session) void migrateFromV53(Session& session)
{ {
// Add release group mbid // Add release group mbid
session.getDboSession().execute("ALTER TABLE release ADD group_mbid TEXT NOT NULL DEFAULT ''"); session.getDboSession()->execute("ALTER TABLE release ADD group_mbid TEXT NOT NULL DEFAULT ''");
// Just increment the scan version of the settings to make the next scheduled scan rescan everything // Just increment the scan version of the settings to make the next scheduled scan rescan everything
session.getDboSession().execute("UPDATE scan_settings SET scan_version = scan_version + 1"); session.getDboSession()->execute("UPDATE scan_settings SET scan_version = scan_version + 1");
} }
void doDbMigration(Session& session) void doDbMigration(Session& session)
+50 -69
View File
@@ -40,7 +40,7 @@ namespace lms::db
template <typename ResultType> template <typename ResultType>
Wt::Dbo::Query<ResultType> createQuery(Session& session, std::string_view itemToSelect, const Release::FindParameters& params) 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") }; auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " from release r") };
if (params.sortMethod == ReleaseSortMethod::ArtistNameThenName if (params.sortMethod == ReleaseSortMethod::ArtistNameThenName
|| params.sortMethod == ReleaseSortMethod::LastWritten || params.sortMethod == ReleaseSortMethod::LastWritten
@@ -206,27 +206,23 @@ namespace lms::db
ReleaseType::pointer ReleaseType::create(Session& session, std::string_view name) 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) ReleaseType::pointer ReleaseType::find(Session& session, ReleaseTypeId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession() return utils::execSingleResultQuery(session.getDboSession()->find<ReleaseType>()
.find<ReleaseType>() .where("id = ?").bind(id));
.where("id = ?").bind(id)
.resultValue();
} }
ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name) ReleaseType::pointer ReleaseType::find(Session& session, std::string_view name)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession() return utils::execSingleResultQuery(session.getDboSession()->find<ReleaseType>()
.find<ReleaseType>() .where("name = ?").bind(name));
.where("name = ?").bind(name)
.resultValue();
} }
Release::Release(const std::string& name, const std::optional<core::UUID>& MBID) Release::Release(const std::string& name, const std::optional<core::UUID>& MBID)
@@ -237,19 +233,17 @@ namespace lms::db
Release::pointer Release::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID) Release::pointer Release::create(Session& session, const std::string& name, const std::optional<core::UUID>& MBID)
{ {
return session.getDboSession().add(std::unique_ptr<Release> {new Release{ name, MBID }}); 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) std::vector<Release::pointer> Release::find(Session& session, const std::string& name, const std::filesystem::path& releaseDirectory)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ session.getDboSession() auto res{ utils::execMultiResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r")
.query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r")
.join("track t ON t.release_id = r.id") .join("track t ON t.release_id = r.id")
.where("r.name = ?").bind(std::string(name, 0, _maxNameLength)) .where("r.name = ?").bind(std::string(name, 0, _maxNameLength))
.where("t.file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%") .where("t.file_path LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind(utils::escapeLikeKeyword(releaseDirectory.string()) + "%"))};
.resultList() };
return std::vector<Release::pointer>(res.begin(), res.end()); return std::vector<Release::pointer>(res.begin(), res.end());
} }
@@ -258,48 +252,44 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession() return utils::execSingleResultQuery(session.getDboSession()->find<Release>()
.find<Release>() .where("mbid = ?").bind(mbid.getAsString()));
.where("mbid = ?").bind(std::string{ mbid.getAsString() })
.resultValue();;
} }
Release::pointer Release::find(Session& session, ReleaseId id) Release::pointer Release::find(Session& session, ReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession() return utils::execSingleResultQuery(session.getDboSession()->find<Release>()
.find<Release>() .where("id = ?").bind(id));
.where("id = ?").bind(id)
.resultValue();
} }
bool Release::exists(Session& session, ReleaseId id) bool Release::exists(Session& session, ReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT 1 FROM release").where("id = ?").bind(id).resultValue() == 1; return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 FROM release").where("id = ?").bind(id)) == 1;
} }
std::size_t Release::getCount(Session& session) std::size_t Release::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM release"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM release"));
} }
RangeResults<ReleaseId> Release::findOrphanIds(Session& session, std::optional<Range> range) RangeResults<ReleaseId> Release::findOrphanIds(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ReleaseId>("select r.id from release r LEFT OUTER JOIN Track t ON r.id = t.release_id WHERE t.id IS NULL") }; auto query{ session.getDboSession()->query<ReleaseId>("select r.id from release r LEFT OUTER JOIN Track t ON r.id = t.release_id WHERE t.id IS NULL") };
return utils::execQuery<ReleaseId>(query, range); return utils::execRangeQuery<ReleaseId>(query, range);
} }
void Release::find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library) void Release::find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r") auto query{ session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT r FROM release r")
.orderBy("r.id") .orderBy("r.id")
.where("r.id > ?").bind(lastRetrievedRelease) .where("r.id > ?").bind(lastRetrievedRelease)
.limit(static_cast<int>(count)) }; .limit(static_cast<int>(count)) };
@@ -310,7 +300,7 @@ namespace lms::db
query.where("t.media_library_id = ?").bind(library); query.where("t.media_library_id = ?").bind(library);
} }
auto collection{ query.resultList() }; auto collection{ utils::execMultiResultQuery(query) };
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult) for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
@@ -324,7 +314,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) }; auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) };
return utils::execQuery<pointer>(query, params.range); return utils::execRangeQuery<pointer>(query, params.range);
} }
void Release::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func) void Release::find(Session& session, const FindParameters& params, std::function<void(const pointer&)> func)
@@ -332,7 +322,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) }; auto query{ createQuery<Wt::Dbo::ptr<Release>>(session, "DISTINCT r", params) };
utils::execQuery<pointer>(query, params.range, func); utils::execRangeQuery<pointer>(query, params.range, func);
} }
RangeResults<ReleaseId> Release::findIds(Session& session, const FindParameters& params) RangeResults<ReleaseId> Release::findIds(Session& session, const FindParameters& params)
@@ -340,23 +330,23 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<ReleaseId>(session, "DISTINCT r.id", params) }; auto query{ createQuery<ReleaseId>(session, "DISTINCT r.id", params) };
return utils::execQuery<ReleaseId>(query, params.range); return utils::execRangeQuery<ReleaseId>(query, params.range);
} }
std::size_t Release::getCount(Session& session, const FindParameters& params) std::size_t Release::getCount(Session& session, const FindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return createQuery<int>(session, "COUNT(DISTINCT r.id)", params).resultValue(); return utils::execSingleResultQuery(createQuery<int>(session, "COUNT(DISTINCT r.id)", params));
} }
std::size_t Release::getDiscCount() const std::size_t Release::getDiscCount() const
{ {
assert(session()); assert(session());
int res{ session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t") int res{ utils::execSingleResultQuery(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t")
.join("release r ON r.id = t.release_id") .join("release r ON r.id = t.release_id")
.where("r.id = ?") .where("r.id = ?")
.bind(getId()) }; .bind(getId())) };
return res; return res;
} }
@@ -365,12 +355,11 @@ namespace lms::db
{ {
assert(session()); assert(session());
using ResultType = std::tuple<int, std::string>; using ResultType = std::tuple<int, std::string>;
auto results{ session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t") auto results{ utils::execMultiResultQuery(session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t")
.join("release r ON r.id = t.release_id") .join("release r ON r.id = t.release_id")
.where("r.id = ?") .where("r.id = ?")
.orderBy("disc_number") .orderBy("disc_number")
.bind(getId()) .bind(getId()))};
.resultList() };
std::vector<DiscInfo> discs; std::vector<DiscInfo> discs;
for (const auto& res : results) for (const auto& res : results)
@@ -395,12 +384,11 @@ namespace lms::db
const char* field{ original ? "original_date" : "date" }; const char* field{ original ? "original_date" : "date" };
auto dates{ session()->query<Wt::WDate>( auto dates{ utils::execMultiResultQuery(session()->query<Wt::WDate>(
std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id") std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?") .where("r.id = ?")
.groupBy(field) .groupBy(field)
.bind(getId()) .bind(getId())) };
.resultList() };
// various dates => invalid date // various dates => invalid date
if (dates.empty() || dates.size() > 1) if (dates.empty() || dates.size() > 1)
@@ -425,14 +413,14 @@ namespace lms::db
const char* field{ original ? "original_year" : "year" }; const char* field{ original ? "original_year" : "year" };
auto years{ session()->query<std::optional<int>>( auto years{ utils::execMultiResultQuery(session()->query<std::optional<int>>(
std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id") std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId()) .where("r.id = ?").bind(getId())
.groupBy(field) .groupBy(field)) };
.resultList() };
// various years => invalid years // various years => invalid years
if (years.empty() || years.size() > 1) const std::size_t count{ years.size() };
if (count == 0 || count > 1)
return std::nullopt; return std::nullopt;
return years.front(); return years.front();
@@ -442,11 +430,11 @@ namespace lms::db
{ {
assert(session()); assert(session());
Wt::Dbo::collection<std::string> copyrights = session()->query<std::string> Wt::Dbo::collection<std::string> copyrights{ utils::execMultiResultQuery(session()->query<std::string>
("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id") ("SELECT copyright FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?") .where("r.id = ?")
.groupBy("copyright") .groupBy("copyright")
.bind(getId()); .bind(getId())) };
std::vector<std::string> values(copyrights.begin(), copyrights.end()); std::vector<std::string> values(copyrights.begin(), copyrights.end());
@@ -454,17 +442,17 @@ namespace lms::db
if (values.empty() || values.size() > 1 || values.front().empty()) if (values.empty() || values.size() > 1 || values.front().empty())
return std::nullopt; return std::nullopt;
return values.front(); return std::move(values.front());
} }
std::optional<std::string> Release::getCopyrightURL() const std::optional<std::string> Release::getCopyrightURL() const
{ {
assert(session()); assert(session());
Wt::Dbo::collection<std::string> copyrights = session()->query<std::string> Wt::Dbo::collection<std::string> copyrights {utils::execMultiResultQuery(session()->query<std::string>
("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id") ("SELECT copyright_url FROM track t INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId()) .where("r.id = ?").bind(getId())
.groupBy("copyright_url"); .groupBy("copyright_url")) };
std::vector<std::string> values(copyrights.begin(), copyrights.end()); std::vector<std::string> values(copyrights.begin(), copyrights.end());
@@ -472,31 +460,29 @@ namespace lms::db
if (values.empty() || values.size() > 1 || values.front().empty()) if (values.empty() || values.size() > 1 || values.front().empty())
return std::nullopt; return std::nullopt;
return values.front(); return std::move(values.front());
} }
std::size_t Release::getMeanBitrate() const std::size_t Release::getMeanBitrate() const
{ {
assert(session()); assert(session());
return session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t") return utils::execSingleResultQuery(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t")
.where("release_id = ?").bind(getId()) .where("release_id = ?").bind(getId())
.where("bitrate > 0") .where("bitrate > 0"));
.resultValue();
} }
std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const std::vector<Artist::pointer> Release::getArtists(TrackArtistLinkType linkType) const
{ {
assert(session()); assert(session());
auto res{ session()->query<Wt::Dbo::ptr<Artist>>( auto res{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Artist>>(
"SELECT DISTINCT a FROM artist a" "SELECT DISTINCT a FROM artist a"
" INNER JOIN track_artist_link t_a_l ON t_a_l.artist_id = a.id" " 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 t ON t.id = t_a_l.track_id"
" INNER JOIN release r ON r.id = t.release_id") " INNER JOIN release r ON r.id = t.release_id")
.where("r.id = ?").bind(getId()) .where("r.id = ?").bind(getId())
.where("t_a_l.type = ?").bind(linkType) .where("t_a_l.type = ?").bind(linkType))};
.resultList() };
return std::vector<Artist::pointer>(res.begin(), res.end()); return std::vector<Artist::pointer>(res.begin(), res.end());
} }
@@ -506,7 +492,7 @@ namespace lms::db
assert(session()); assert(session());
// Select the similar releases using the 5 most used clusters of the release // Select the similar releases using the 5 most used clusters of the release
auto res{ session()->query<Wt::Dbo::ptr<Release>>( auto res{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Release>>(
"SELECT r FROM release r" "SELECT r FROM release r"
" INNER JOIN track t ON t.release_id = r.id" " INNER JOIN track t ON t.release_id = r.id"
" 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"
@@ -524,8 +510,7 @@ namespace lms::db
.groupBy("r.id") .groupBy("r.id")
.orderBy("COUNT(*) DESC, RANDOM()") .orderBy("COUNT(*) DESC, RANDOM()")
.limit(count ? static_cast<int>(*count) : -1) .limit(count ? static_cast<int>(*count) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) .offset(offset ? static_cast<int>(*offset) : -1))};
.resultList() };
return std::vector<pointer>(res.begin(), res.end()); return std::vector<pointer>(res.begin(), res.end());
} }
@@ -572,20 +557,16 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
Wt::Dbo::Query<milli> query{ session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN release r ON t.release_id = r.id") return utils::execSingleResultQuery(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN release r ON t.release_id = r.id")
.where("r.id = ?").bind(getId()) }; .where("r.id = ?").bind(getId()));
return query.resultValue();
} }
Wt::WDateTime Release::getLastWritten() const Wt::WDateTime Release::getLastWritten() const
{ {
assert(session()); assert(session());
Wt::Dbo::Query<Wt::WDateTime> query{ session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t INNER JOIN release r ON t.release_id = r.id") return utils::execSingleResultQuery(session()->query<Wt::WDateTime>("SELECT COALESCE(MAX(file_last_write), '1970-01-01T00:00:00') FROM track t INNER JOIN release r ON t.release_id = r.id")
.where("r.id = ?").bind(getId()) }; .where("r.id = ?").bind(getId()));
return query.resultValue();
} }
std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const std::vector<std::vector<Cluster::pointer>> Release::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
@@ -612,7 +593,7 @@ namespace lms::db
for (const std::string& bindArg : where.getBindArgs()) for (const std::string& bindArg : where.getBindArgs())
query.bind(bindArg); query.bind(bindArg);
auto queryRes{ query.resultList() }; auto queryRes{ utils::execMultiResultQuery(query) };
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes) for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes)
+3 -2
View File
@@ -24,6 +24,7 @@
#include "database/MediaLibrary.hpp" #include "database/MediaLibrary.hpp"
#include "database/Session.hpp" #include "database/Session.hpp"
#include "core/String.hpp" #include "core/String.hpp"
#include "Utils.hpp"
namespace lms::db namespace lms::db
{ {
@@ -34,14 +35,14 @@ namespace lms::db
if (pointer settings{ get(session) }) if (pointer settings{ get(session) })
return; return;
session.getDboSession().add(std::make_unique<ScanSettings>()); session.getDboSession()->add(std::make_unique<ScanSettings>());
} }
ScanSettings::pointer ScanSettings::get(Session& session) ScanSettings::pointer ScanSettings::get(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<ScanSettings>().resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<ScanSettings>());
} }
std::vector<std::filesystem::path> ScanSettings::getAudioFileExtensions() const std::vector<std::filesystem::path> ScanSettings::getAudioFileExtensions() const
+7 -9
View File
@@ -38,40 +38,38 @@ namespace lms::db
StarredArtist::pointer StarredArtist::create(Session& session, ObjectPtr<Artist> artist, ObjectPtr<User> user, FeedbackBackend backend) 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) std::size_t StarredArtist::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM starred_artist"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM starred_artist"));
} }
StarredArtist::pointer StarredArtist::find(Session& session, StarredArtistId id) StarredArtist::pointer StarredArtist::find(Session& session, StarredArtistId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredArtist>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<StarredArtist>().where("id = ?").bind(id));
} }
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId) StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a") return utils::execSingleResultQuery(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") .join("user u ON u.id = s_a.user_id")
.where("s_a.artist_id = ?").bind(artistId) .where("s_a.artist_id = ?").bind(artistId)
.where("s_a.user_id = ?").bind(userId) .where("s_a.user_id = ?").bind(userId)
.where("s_a.backend = u.feedback_backend") .where("s_a.backend = u.feedback_backend"));
.resultValue();
} }
StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend) StarredArtist::pointer StarredArtist::find(Session& session, ArtistId artistId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredArtist>() return utils::execSingleResultQuery(session.getDboSession()->find<StarredArtist>()
.where("artist_id = ?").bind(artistId) .where("artist_id = ?").bind(artistId)
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend) .where("backend = ?").bind(backend));
.resultValue();
} }
void StarredArtist::setDateTime(const Wt::WDateTime& dateTime) void StarredArtist::setDateTime(const Wt::WDateTime& dateTime)
+7 -9
View File
@@ -38,40 +38,38 @@ namespace lms::db
StarredRelease::pointer StarredRelease::create(Session& session, ObjectPtr<Release> release, ObjectPtr<User> user, FeedbackBackend backend) 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) std::size_t StarredRelease::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM starred_release"); return session.getDboSession()->query<int>("SELECT COUNT(*) FROM starred_release");
} }
StarredRelease::pointer StarredRelease::find(Session& session, StarredReleaseId id) StarredRelease::pointer StarredRelease::find(Session& session, StarredReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredRelease>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<StarredRelease>().where("id = ?").bind(id));
} }
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId) StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r") return utils::execSingleResultQuery(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") .join("user u ON u.id = s_r.user_id")
.where("s_r.release_id = ?").bind(releaseId) .where("s_r.release_id = ?").bind(releaseId)
.where("s_r.user_id = ?").bind(userId) .where("s_r.user_id = ?").bind(userId)
.where("s_r.backend = u.feedback_backend") .where("s_r.backend = u.feedback_backend"));
.resultValue();
} }
StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend) StarredRelease::pointer StarredRelease::find(Session& session, ReleaseId releaseId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredRelease>() return utils::execSingleResultQuery(session.getDboSession()->find<StarredRelease>()
.where("release_id = ?").bind(releaseId) .where("release_id = ?").bind(releaseId)
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend) .where("backend = ?").bind(backend));
.resultValue();
} }
void StarredRelease::setDateTime(const Wt::WDateTime& dateTime) void StarredRelease::setDateTime(const Wt::WDateTime& dateTime)
+11 -14
View File
@@ -38,56 +38,53 @@ namespace lms::db
StarredTrack::pointer StarredTrack::create(Session& session, ObjectPtr<Track> track, ObjectPtr<User> user, FeedbackBackend backend) 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) std::size_t StarredTrack::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM starred_track"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM starred_track"));
} }
StarredTrack::pointer StarredTrack::find(Session& session, StarredTrackId id) StarredTrack::pointer StarredTrack::find(Session& session, StarredTrackId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredTrack>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<StarredTrack>().where("id = ?").bind(id));
} }
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId) StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t") return utils::execSingleResultQuery(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") .join("user u ON u.id = s_t.user_id")
.where("s_t.track_id = ?").bind(trackId) .where("s_t.track_id = ?").bind(trackId)
.where("s_t.user_id = ?").bind(userId) .where("s_t.user_id = ?").bind(userId)
.where("s_t.backend = u.feedback_backend") .where("s_t.backend = u.feedback_backend"));
.resultValue();
} }
StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) StarredTrack::pointer StarredTrack::find(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<StarredTrack>() return utils::execSingleResultQuery(session.getDboSession()->find<StarredTrack>()
.where("track_id = ?").bind(trackId) .where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend) .where("backend = ?").bind(backend));
.resultValue();
} }
bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{ {
return session.getDboSession().query<int>("SELECT 1 from starred_track") return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 from starred_track")
.where("track_id = ?").bind(trackId) .where("track_id = ?").bind(trackId)
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("backend = ?").bind(backend) .where("backend = ?").bind(backend));
.resultValue() == 1;
} }
RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params) RangeResults<StarredTrackId> StarredTrack::find(Session& session, const FindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<StarredTrackId>("SELECT DISTINCT s_t.id FROM starred_track s_t") }; auto query{ session.getDboSession()->query<StarredTrackId>("SELECT DISTINCT s_t.id FROM starred_track s_t") };
if (params.backend) if (params.backend)
query.where("s_t.backend = ?").bind(*params.backend); query.where("s_t.backend = ?").bind(*params.backend);
@@ -96,7 +93,7 @@ namespace lms::db
if (params.user.isValid()) if (params.user.isValid())
query.where("s_t.user_id = ?").bind(params.user); query.where("s_t.user_id = ?").bind(params.user);
return utils::execQuery<StarredTrackId>(query, params.range); return utils::execRangeQuery<StarredTrackId>(query, params.range);
} }
void StarredTrack::setDateTime(const Wt::WDateTime& dateTime) void StarredTrack::setDateTime(const Wt::WDateTime& dateTime)
+30 -34
View File
@@ -45,7 +45,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<ResultType>("SELECT " + std::string{ itemToSelect } + " FROM track t") }; auto query{ session.getDboSession()->query<ResultType>("SELECT " + std::string{ itemToSelect } + " FROM track t") };
assert(params.keywords.empty() || params.name.empty()); assert(params.keywords.empty() || params.name.empty());
for (std::string_view keyword : params.keywords) for (std::string_view keyword : params.keywords)
@@ -202,37 +202,36 @@ namespace lms::db
Track::pointer Track::create(Session& session, const std::filesystem::path& p) Track::pointer Track::create(Session& session, const std::filesystem::path& p)
{ {
return session.getDboSession().add(std::unique_ptr<Track> {new Track{ p }}); return session.getDboSession()->add(std::unique_ptr<Track> {new Track{ p }});
} }
std::size_t Track::getCount(Session& session) std::size_t Track::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM track"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track"));
} }
Track::pointer Track::findByPath(Session& session, const std::filesystem::path& p) Track::pointer Track::findByPath(Session& session, const std::filesystem::path& p)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Track>().where("file_path = ?").bind(p.string()).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<Track>().where("file_path = ?").bind(p.string()));
} }
Track::pointer Track::find(Session& session, TrackId id) Track::pointer Track::find(Session& session, TrackId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<Track>() return utils::execSingleResultQuery(session.getDboSession()->find<Track>()
.where("id = ?").bind(id) .where("id = ?").bind(id));
.resultValue();
} }
void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library) void Track::find(Session& session, TrackId& lastRetrievedTrack, std::size_t count, const std::function<void(const Track::pointer&)>& func, MediaLibraryId library)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().find<Track>() auto query{ session.getDboSession()->find<Track>()
.orderBy("id") .orderBy("id")
.where("id > ?").bind(lastRetrievedTrack) .where("id > ?").bind(lastRetrievedTrack)
.limit(static_cast<int>(count)) }; .limit(static_cast<int>(count)) };
@@ -240,7 +239,7 @@ namespace lms::db
if (library.isValid()) if (library.isValid())
query.where("media_library_id = ?").bind(library); query.where("media_library_id = ?").bind(library);
auto collection{query.resultList()}; auto collection{ utils::execMultiResultQuery(query) };
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult) for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
@@ -253,16 +252,15 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT 1 from track").where("id = ?").bind(id).resultValue() == 1; return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 from track").where("id = ?").bind(id)) == 1;
} }
std::vector<Track::pointer> Track::findByMBID(Session& session, const core::UUID& mbid) std::vector<Track::pointer> Track::findByMBID(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ session.getDboSession().find<Track>() auto res{ utils::execMultiResultQuery(session.getDboSession()->find<Track>()
.where("mbid = ?").bind(std::string {mbid.getAsString()}) .where("mbid = ?").bind(std::string {mbid.getAsString()})) };
.resultList() };
return std::vector<Track::pointer>(res.begin(), res.end()); return std::vector<Track::pointer>(res.begin(), res.end());
} }
@@ -271,9 +269,8 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ session.getDboSession().find<Track>() auto res{ utils::execMultiResultQuery(session.getDboSession()->find<Track>()
.where("recording_mbid = ?").bind(std::string {mbid.getAsString()}) .where("recording_mbid = ?").bind(std::string {mbid.getAsString()})) };
.resultList() };
return std::vector<Track::pointer>(res.begin(), res.end()); return std::vector<Track::pointer>(res.begin(), res.end());
} }
@@ -284,9 +281,9 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
// TODO Dbo traits on filesystem // TODO Dbo traits on filesystem
auto query{ session.getDboSession().query<QueryResultType>("SELECT id, file_path FROM track") }; auto query{ session.getDboSession()->query<QueryResultType>("SELECT id, file_path FROM track") };
RangeResults<QueryResultType> queryResults{ utils::execQuery<QueryResultType>(query, range) }; RangeResults<QueryResultType> queryResults{ utils::execRangeQuery<QueryResultType>(query, range) };
RangeResults<PathResult> res; RangeResults<PathResult> res;
res.range = queryResults.range; res.range = queryResults.range;
@@ -306,21 +303,21 @@ namespace lms::db
{ {
session.checkReadTransaction(); 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)") 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") }; .orderBy("track.release_id,track.disc_number,track.track_number,track.mbid") };
return utils::execQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
RangeResults<TrackId> Track::findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range) RangeResults<TrackId> Track::findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<TrackId>("SELECT t.id FROM track t") auto query{ session.getDboSession()->query<TrackId>("SELECT t.id FROM track t")
.where("LENGTH(t.recording_mbid) > 0") .where("LENGTH(t.recording_mbid) > 0")
.where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") }; .where("NOT EXISTS (SELECT * FROM track_features t_f WHERE t_f.track_id = t.id)") };
return utils::execQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
std::vector<Cluster::pointer> Track::getClusters() const std::vector<Cluster::pointer> Track::getClusters() const
@@ -332,10 +329,9 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto res{ session()->query<ClusterId> auto res{ utils::execMultiResultQuery(session()->query<ClusterId>
("SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id INNER JOIN track t ON t.id = t_c.track_id") ("SELECT DISTINCT c.id FROM cluster c INNER JOIN track_cluster t_c ON t_c.cluster_id = c.id INNER JOIN track t ON t.id = t_c.track_id")
.where("t.id = ?").bind(getId()) .where("t.id = ?").bind(getId())) };
.resultList() };
return std::vector<ClusterId>(res.begin(), res.end()); return std::vector<ClusterId>(res.begin(), res.end());
} }
@@ -345,7 +341,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<TrackId>(session, parameters) }; auto query{ createQuery<TrackId>(session, parameters) };
return utils::execQuery<TrackId>(query, parameters.range); return utils::execRangeQuery<TrackId>(query, parameters.range);
} }
RangeResults<Track::pointer> Track::find(Session& session, const FindParameters& parameters) RangeResults<Track::pointer> Track::find(Session& session, const FindParameters& parameters)
@@ -353,7 +349,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, parameters) }; auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, parameters) };
return utils::execQuery<Track::pointer>(query, parameters.range); return utils::execRangeQuery<Track::pointer>(query, parameters.range);
} }
void Track::find(Session& session, const FindParameters& params, std::function<void(const Track::pointer&)> func) void Track::find(Session& session, const FindParameters& params, std::function<void(const Track::pointer&)> func)
@@ -361,7 +357,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)}; auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)};
utils::execQuery(query, params.range, func); utils::execRangeQuery(query, params.range, func);
} }
void Track::find(Session& session, const FindParameters& params, bool& moreResults, std::function<void(const Track::pointer&)> func) void Track::find(Session& session, const FindParameters& params, bool& moreResults, std::function<void(const Track::pointer&)> func)
@@ -369,7 +365,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)}; auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params)};
utils::execQuery(query, params.range, moreResults, func); utils::execRangeQuery(query, params.range, moreResults, func);
} }
RangeResults<TrackId> Track::findSimilarTrackIds(Session& session, const std::vector<TrackId>& tracks, std::optional<Range> range) RangeResults<TrackId> Track::findSimilarTrackIds(Session& session, const std::vector<TrackId>& tracks, std::optional<Range> range)
@@ -385,7 +381,7 @@ namespace lms::db
oss << "?"; oss << "?";
} }
auto query{ session.getDboSession().query<TrackId>( auto query{ session.getDboSession()->query<TrackId>(
"SELECT t.id FROM track t" "SELECT 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"
" 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_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() + "))"
@@ -399,7 +395,7 @@ namespace lms::db
for (TrackId trackId : tracks) for (TrackId trackId : tracks)
query.bind(trackId); query.bind(trackId);
return utils::execQuery<TrackId>(query, range); return utils::execRangeQuery<TrackId>(query, range);
} }
void Track::clearArtistLinks() void Track::clearArtistLinks()
@@ -460,7 +456,7 @@ namespace lms::db
query.where("t.id = ?").bind(getId()); query.where("t.id = ?").bind(getId());
auto res{ query.resultList() }; auto res{ utils::execMultiResultQuery(query) };
return std::vector<Artist::pointer>(std::begin(res), std::end(res)); return std::vector<Artist::pointer>(std::begin(res), std::end(res));
} }
@@ -496,7 +492,7 @@ namespace lms::db
query.where("t.id = ?").bind(getId()); query.where("t.id = ?").bind(getId());
auto res{ query.resultList() }; auto res{ utils::execMultiResultQuery(query) };
return std::vector<ArtistId>(std::cbegin(res), std::cend(res)); return std::vector<ArtistId>(std::cbegin(res), std::cend(res));
} }
@@ -530,7 +526,7 @@ namespace lms::db
for (const std::string& bindArg : where.getBindArgs()) for (const std::string& bindArg : where.getBindArgs())
query.bind(bindArg); query.bind(bindArg);
auto queryRes{ query.resultList() }; auto queryRes{ utils::execMultiResultQuery(query) };
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clusters;
for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes) for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes)
+8 -10
View File
@@ -34,7 +34,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<TrackArtistLinkId>("SELECT DISTINCT t_a_l.id FROM track_artist_link t_a_l") }; auto query{ session.getDboSession()->query<TrackArtistLinkId>("SELECT DISTINCT t_a_l.id FROM track_artist_link t_a_l") };
if (params.linkType) if (params.linkType)
query.where("t_a_l.type = ?").bind(*params.linkType); query.where("t_a_l.type = ?").bind(*params.linkType);
@@ -67,8 +67,8 @@ namespace lms::db
{ {
session.checkWriteTransaction(); session.checkWriteTransaction();
TrackArtistLink::pointer res{ session.getDboSession().add(std::make_unique<TrackArtistLink>(track, artist, type, subType)) }; TrackArtistLink::pointer res{ session.getDboSession()->add(std::make_unique<TrackArtistLink>(track, artist, type, subType)) };
session.getDboSession().flush(); session.getDboSession()->flush();
return res; return res;
} }
@@ -76,7 +76,7 @@ namespace lms::db
TrackArtistLink::pointer TrackArtistLink::find(Session& session, TrackArtistLinkId id) TrackArtistLink::pointer TrackArtistLink::find(Session& session, TrackArtistLinkId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackArtistLink>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<TrackArtistLink>().where("id = ?").bind(id));
} }
RangeResults<TrackArtistLinkId> TrackArtistLink::find(Session& session, const FindParameters& params) RangeResults<TrackArtistLinkId> TrackArtistLink::find(Session& session, const FindParameters& params)
@@ -84,14 +84,14 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery(session, params) }; auto query{ createQuery(session, params) };
return utils::execQuery<TrackArtistLinkId>(query, params.range); return utils::execRangeQuery<TrackArtistLinkId>(query, params.range);
} }
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session) core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ session.getDboSession().query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link").resultList() }; auto res{ utils::execMultiResultQuery(session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")) };
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res)); return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
} }
@@ -100,10 +100,8 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ session.getDboSession() auto res{ utils::execMultiResultQuery(session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")
.query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link") .where("artist_id = ?").bind(artistId)) };
.where("artist_id = ?").bind(artistId)
.resultList() };
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res)); return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res));
} }
+8 -10
View File
@@ -35,43 +35,41 @@ namespace lms::db
TrackBookmark::pointer TrackBookmark::create(Session& session, ObjectPtr<User> user, ObjectPtr<Track> 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) std::size_t TrackBookmark::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM track_bookmark"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_bookmark"));
} }
RangeResults<TrackBookmarkId> TrackBookmark::find(Session& session, UserId userId, std::optional<Range> range) RangeResults<TrackBookmarkId> TrackBookmark::find(Session& session, UserId userId, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<TrackBookmarkId>("SELECT id from track_bookmark") auto query{ session.getDboSession()->query<TrackBookmarkId>("SELECT id from track_bookmark")
.where("user_id = ?").bind(userId) }; .where("user_id = ?").bind(userId) };
return utils::execQuery<TrackBookmarkId>(query, range); return utils::execRangeQuery<TrackBookmarkId>(query, range);
} }
TrackBookmark::pointer TrackBookmark::find(Session& session, UserId userId, TrackId trackId) TrackBookmark::pointer TrackBookmark::find(Session& session, UserId userId, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackBookmark>() return utils::execSingleResultQuery(session.getDboSession()->find<TrackBookmark>()
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId) .where("track_id = ?").bind(trackId));
.resultValue();
} }
TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id) TrackBookmark::pointer TrackBookmark::find(Session& session, TrackBookmarkId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackBookmark>() return utils::execSingleResultQuery(session.getDboSession()->find<TrackBookmark>()
.where("id = ?").bind(id) .where("id = ?").bind(id));
.resultValue();
} }
} // namespace lms::db } // namespace lms::db
+8 -10
View File
@@ -38,41 +38,39 @@ namespace lms::db {
TrackFeatures::pointer TrackFeatures::create(Session& session, ObjectPtr<Track> track, const std::string& jsonEncodedFeatures) 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) std::size_t TrackFeatures::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM track_features"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_features"));
} }
TrackFeatures::pointer TrackFeatures::find(Session& session, TrackFeaturesId id) TrackFeatures::pointer TrackFeatures::find(Session& session, TrackFeaturesId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackFeatures>() return utils::execSingleResultQuery(session.getDboSession()->find<TrackFeatures>()
.where("id = ?").bind(id) .where("id = ?").bind(id));
.resultValue();
} }
TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId) TrackFeatures::pointer TrackFeatures::find(Session& session, TrackId trackId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackFeatures>() return utils::execSingleResultQuery(session.getDboSession()->find<TrackFeatures>()
.where("track_id = ?").bind(trackId) .where("track_id = ?").bind(trackId));
.resultValue();
} }
RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range) RangeResults<TrackFeaturesId> TrackFeatures::find(Session& session, std::optional<Range> range)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<TrackFeaturesId>("SELECT id from track_features") }; auto query{ session.getDboSession()->query<TrackFeaturesId>("SELECT id from track_features") };
return utils::execQuery<TrackFeaturesId>(query, range); return utils::execRangeQuery<TrackFeaturesId>(query, range);
} }
FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const FeatureValues TrackFeatures::getFeatureValues(const FeatureName& featureNode) const
+21 -26
View File
@@ -48,14 +48,14 @@ namespace lms::db
TrackList::pointer TrackList::create(Session& session, std::string_view name, TrackListType type, bool isPublic, ObjectPtr<User> user) 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) std::size_t TrackList::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM tracklist"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM tracklist"));
} }
@@ -64,17 +64,17 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
assert(userId.isValid()); assert(userId.isValid());
return session.getDboSession().find<TrackList>() return utils::execSingleResultQuery(session.getDboSession()->find<TrackList>()
.where("name = ?").bind(name) .where("name = ?").bind(name)
.where("type = ?").bind(type) .where("type = ?").bind(type)
.where("user_id = ?").bind(userId).resultValue(); .where("user_id = ?").bind(userId));
} }
RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params) RangeResults<TrackListId> TrackList::find(Session& session, const FindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<TrackListId>("SELECT DISTINCT t_l.id FROM tracklist t_l") }; auto query{ session.getDboSession()->query<TrackListId>("SELECT DISTINCT t_l.id FROM tracklist t_l") };
if (params.user.isValid()) if (params.user.isValid())
query.where("t_l.user_id = ?").bind(params.user); query.where("t_l.user_id = ?").bind(params.user);
@@ -117,14 +117,14 @@ namespace lms::db
break; break;
} }
return utils::execQuery<TrackListId>(query, params.range); return utils::execRangeQuery<TrackListId>(query, params.range);
} }
TrackList::pointer TrackList::find(Session& session, TrackListId id) TrackList::pointer TrackList::find(Session& session, TrackListId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackList>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<TrackList>().where("id = ?").bind(id));
} }
bool TrackList::isEmpty() const bool TrackList::isEmpty() const
@@ -156,29 +156,27 @@ namespace lms::db
.where("tracklist_id = ?").bind(getId()) .where("tracklist_id = ?").bind(getId())
.orderBy("id") }; .orderBy("id") };
return utils::execQuery<TrackListEntry::pointer>(query, range); return utils::execRangeQuery<TrackListEntry::pointer>(query, range);
} }
TrackListEntry::pointer TrackList::getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const TrackListEntry::pointer TrackList::getEntryByTrackAndDateTime(ObjectPtr<Track> track, const Wt::WDateTime& dateTime) const
{ {
assert(session()); assert(session());
return session()->find<TrackListEntry>() return utils::execSingleResultQuery(session()->find<TrackListEntry>()
.where("tracklist_id = ?").bind(getId()) .where("tracklist_id = ?").bind(getId())
.where("track_id = ?").bind(track->getId()) .where("track_id = ?").bind(track->getId())
.where("date_time = ?").bind(utils::normalizeDateTime(dateTime)) .where("date_time = ?").bind(utils::normalizeDateTime(dateTime)));
.resultValue();
} }
std::vector<Cluster::pointer> TrackList::getClusters() const std::vector<Cluster::pointer> TrackList::getClusters() const
{ {
assert(session()); assert(session());
auto res{ 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") auto res{ utils::execMultiResultQuery(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()) .where("p.id = ?").bind(getId())
.groupBy("c.id") .groupBy("c.id")
.orderBy("COUNT(c.id) DESC") .orderBy("COUNT(c.id) DESC")) };
.resultList() };
return std::vector<Cluster::pointer>(res.begin(), res.end()); return std::vector<Cluster::pointer>(res.begin(), res.end());
} }
@@ -218,7 +216,7 @@ namespace lms::db
query.groupBy("c.id"); query.groupBy("c.id");
query.orderBy("COUNT(c.id) DESC"); query.orderBy("COUNT(c.id) DESC");
auto queryRes{ query.resultList() }; auto queryRes{ utils::execMultiResultQuery(query) };
std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType; std::map<ClusterTypeId, std::vector<Cluster::pointer>> clustersByType;
for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes) for (const Wt::Dbo::ptr<Cluster>& cluster : queryRes)
@@ -237,7 +235,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto res{ session()->query<Wt::Dbo::ptr<Track>>( auto res{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Track>>(
"SELECT t FROM track t" "SELECT t 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"
" WHERE " " WHERE "
@@ -249,8 +247,7 @@ namespace lms::db
.groupBy("t.id") .groupBy("t.id")
.orderBy("COUNT(*) DESC, RANDOM()") .orderBy("COUNT(*) DESC, RANDOM()")
.limit(size ? static_cast<int>(*size) : -1) .limit(size ? static_cast<int>(*size) : -1)
.offset(offset ? static_cast<int>(*offset) : -1) .offset(offset ? static_cast<int>(*offset) : -1))};
.resultList() };
return std::vector<Track::pointer>(res.begin(), res.end()); return std::vector<Track::pointer>(res.begin(), res.end());
} }
@@ -259,8 +256,8 @@ namespace lms::db
{ {
assert(session()); assert(session());
Wt::Dbo::collection<TrackId> res = session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id") auto res {utils::execMultiResultQuery(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()); .where("p.id = ?").bind(getId())) };
return std::vector<TrackId>(res.begin(), res.end()); return std::vector<TrackId>(res.begin(), res.end());
} }
@@ -271,10 +268,8 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
Wt::Dbo::Query<milli> query{ session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id") return utils::execSingleResultQuery(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()) }; .where("p_e.tracklist_id = ?").bind(getId()));
return query.resultValue();
} }
void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime) void TrackList::setLastModifiedDateTime(const Wt::WDateTime& dateTime)
@@ -293,7 +288,7 @@ namespace lms::db
TrackListEntry::pointer TrackListEntry::create(Session& session, ObjectPtr<Track> track, ObjectPtr<TrackList> tracklist, const Wt::WDateTime& dateTime) 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() void TrackListEntry::onPostCreated()
@@ -310,6 +305,6 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<TrackListEntry>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<TrackListEntry>().where("id = ?").bind(id));
} }
} // namespace lms::db } // namespace lms::db
+10 -11
View File
@@ -28,8 +28,8 @@
#include "StringViewTraits.hpp" #include "StringViewTraits.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace lms::db { namespace lms::db
{
User::User(std::string_view loginName) User::User(std::string_view loginName)
: _loginName{ loginName } : _loginName{ loginName }
{ {
@@ -37,47 +37,46 @@ namespace lms::db {
User::pointer User::create(Session& session, std::string_view loginName) 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) std::size_t User::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().query<int>("SELECT COUNT(*) FROM user"); return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM user"));
} }
RangeResults<UserId> User::find(Session& session, const FindParameters& params) RangeResults<UserId> User::find(Session& session, const FindParameters& params)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ session.getDboSession().query<UserId>("SELECT id FROM user") }; auto query{ session.getDboSession()->query<UserId>("SELECT id FROM user") };
if (params.scrobblingBackend) if (params.scrobblingBackend)
query.where("scrobbling_backend = ?").bind(*params.scrobblingBackend); query.where("scrobbling_backend = ?").bind(*params.scrobblingBackend);
if (params.feedbackBackend) if (params.feedbackBackend)
query.where("feedback_backend = ?").bind(*params.feedbackBackend); query.where("feedback_backend = ?").bind(*params.feedbackBackend);
return utils::execQuery<UserId>(query, params.range); return utils::execRangeQuery<UserId>(query, params.range);
} }
User::pointer User::findDemoUser(Session& session) User::pointer User::findDemoUser(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return session.getDboSession().find<User>().where("type = ?").bind(UserType::DEMO).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<User>().where("type = ?").bind(UserType::DEMO));
} }
User::pointer User::find(Session& session, UserId id) User::pointer User::find(Session& session, UserId id)
{ {
return session.getDboSession().find<User>().where("id = ?").bind(id).resultValue(); return utils::execSingleResultQuery(session.getDboSession()->find<User>().where("id = ?").bind(id));
} }
User::pointer User::find(Session& session, std::string_view name) User::pointer User::find(Session& session, std::string_view name)
{ {
return session.getDboSession().find<User>() return utils::execSingleResultQuery(session.getDboSession()->find<User>()
.where("login_name = ?").bind(name) .where("login_name = ?").bind(name));
.resultValue();
} }
void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate) void User::setSubsonicDefaultTranscodingOutputBitrate(Bitrate bitrate)
+24 -10
View File
@@ -45,11 +45,23 @@ namespace lms::db::utils
} }
} }
template <typename ResultType, typename Query> template <typename Query>
RangeResults<ResultType> execQuery(Query& query, std::optional<Range> range) auto execSingleResultQuery(const Query& query)
{ {
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRange"); LMS_SCOPED_TRACE_DETAILED("Database", "ExecSingleResultQuery");
return query.resultValue();
}
template <typename Query>
auto execMultiResultQuery(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED("Database", "ExecMultiResultQuery");
return query.resultList();
}
template <typename ResultType, typename Query>
RangeResults<ResultType> execRangeQuery(Query& query, std::optional<Range> range)
{
RangeResults<ResultType> res; RangeResults<ResultType> res;
if (range) if (range)
@@ -60,7 +72,7 @@ namespace lms::db::utils
res.results.reserve(range->size); res.results.reserve(range->size);
} }
auto collection{ query.resultList() }; auto collection{ execMultiResultQuery(query) };
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult) for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
if (range && res.results.size() == range->size) if (range && res.results.size() == range->size)
@@ -78,20 +90,21 @@ namespace lms::db::utils
} }
template <typename ResultType, typename Query> template <typename ResultType, typename Query>
void execQuery(Query& query, std::optional<Range> range, std::function<void(const ResultType&)> func) void execRangeQuery(Query& query, std::optional<Range> range, const std::function<void(const ResultType&)>& func)
{ {
if (range) if (range)
applyRange(query, range); applyRange(query, range);
for (const auto& res : query.resultList()) auto collection{ execMultiResultQuery(query) };
for (const auto& res : collection)
{ {
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryResult"); LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach");
func(res); func(res);
} }
} }
template <typename ResultType, typename Query> template <typename ResultType, typename Query>
void execQuery(Query& query, std::optional<Range> range, bool& moreResults, std::function<void(const ResultType&)> func) void execRangeQuery(Query& query, std::optional<Range> range, bool& moreResults, const std::function<void(const ResultType&)>& func)
{ {
if (range) if (range)
applyRange(query, Range{ range->offset, range->size + 1 }); applyRange(query, Range{ range->offset, range->size + 1 });
@@ -99,7 +112,8 @@ namespace lms::db::utils
moreResults = false; moreResults = false;
std::size_t count{}; std::size_t count{};
for (const auto& res : query.resultList()) auto collection{ execMultiResultQuery(query) };
for (const auto& res : collection)
{ {
if (range && (count++ == static_cast<std::size_t>(range->size))) if (range && (count++ == static_cast<std::size_t>(range->size)))
{ {
@@ -107,7 +121,7 @@ namespace lms::db::utils
break; break;
} }
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryResult"); LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach");
func(res); func(res);
} }
} }
@@ -41,8 +41,8 @@ namespace lms::db
WriteTransaction(const WriteTransaction&) = delete; WriteTransaction(const WriteTransaction&) = delete;
WriteTransaction& operator=(const WriteTransaction&) = delete; WriteTransaction& operator=(const WriteTransaction&) = delete;
std::unique_lock<core::RecursiveSharedMutex> _lock; const std::unique_lock<core::RecursiveSharedMutex> _lock;
core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "WriteTransaction" }; // before actual transaction
Wt::Dbo::Transaction _transaction; Wt::Dbo::Transaction _transaction;
}; };
@@ -58,7 +58,7 @@ namespace lms::db
ReadTransaction(const ReadTransaction&) = delete; ReadTransaction(const ReadTransaction&) = delete;
ReadTransaction& operator=(const ReadTransaction&) = delete; ReadTransaction& operator=(const ReadTransaction&) = delete;
core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction const core::tracing::ScopedTrace _trace{ "Database", core::tracing::Level::Detailed, "ReadTransaction" }; // before actual transaction
Wt::Dbo::Transaction _transaction; Wt::Dbo::Transaction _transaction;
}; };
@@ -89,7 +89,8 @@ namespace lms::db
void prepareTables(); // need to run only once at startup void prepareTables(); // need to run only once at startup
Wt::Dbo::Session& getDboSession() { return _session; } // returning a ptr here to ease further wrapping using operator->
Wt::Dbo::Session* getDboSession() { return &_session; }
Db& getDb() { return _db; } Db& getDb() { return _db; }
template <typename Object, typename... Args> template <typename Object, typename... Args>
@@ -98,7 +99,7 @@ namespace lms::db
checkWriteTransaction(); checkWriteTransaction();
typename Object::pointer res{ Object::create(*this, std::forward<Args>(args)...) }; typename Object::pointer res{ Object::create(*this, std::forward<Args>(args)...) };
getDboSession().flush(); getDboSession()->flush();
if (res->hasOnPostCreated()) if (res->hasOnPostCreated())
res.modify()->onPostCreated(); res.modify()->onPostCreated();