Tracing: added some more details for db operations

This commit is contained in:
emeric
2024-04-01 20:27:52 +02:00
parent 284dc58fce
commit 741f0e12ed
19 changed files with 275 additions and 244 deletions
+13 -20
View File
@@ -182,7 +182,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM artist")); return utils::fetchQuerySingleResult(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)
@@ -201,43 +201,38 @@ namespace lms::db
query.where("t.media_library_id = ?").bind(library); query.where("t.media_library_id = ?").bind(library);
} }
auto collection{ utils::execMultiResultQuery(query) }; utils::forEachQueryResult(query, [&](const Artist::pointer& artist)
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach"); func(artist);
func(*itResult); lastRetrievedArtist = artist->getId();
lastRetrievedArtist = (*itResult)->getId(); });
}
} }
std::vector<Artist::pointer> Artist::find(Session& session, std::string_view name) std::vector<Artist::pointer> Artist::find(Session& session, std::string_view name)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
Wt::Dbo::collection<Wt::Dbo::ptr<Artist>> res{ utils::execMultiResultQuery(session.getDboSession()->find<Artist>() return utils::fetchQueryResults<Artist::pointer>(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());
} }
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 utils::execSingleResultQuery(session.getDboSession()->find<Artist>().where("mbid = ?").bind(std::string{ mbid.getAsString() })); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<Artist>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 FROM artist").where("id = ?").bind(id)) == 1; return utils::fetchQuerySingleResult(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)
@@ -268,7 +263,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::execRangeQuery(query, params.range, func); utils::forEachQueryRangeResult(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
@@ -343,14 +338,12 @@ namespace lms::db
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{ 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) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{ {
if (clustersByType[cluster->getType()->getId()].size() < size) if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster); clustersByType[cluster->getType()->getId()].push_back(cluster);
} });
std::vector<std::vector<Cluster::pointer>> res; std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [clusterTypeId, clusters] : clustersByType) for (const auto& [clusterTypeId, clusters] : clustersByType)
+1 -2
View File
@@ -28,7 +28,6 @@
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 }
@@ -52,6 +51,6 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value)); return utils::fetchQuerySingleResult(session.getDboSession()->find<AuthToken>().where("value = ?").bind(value));
} }
} }
+10 -12
View File
@@ -93,7 +93,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM cluster")); return utils::fetchQuerySingleResult(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)
@@ -124,14 +124,14 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<Cluster>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(session.getDboSession()->find<Cluster>().where("id = ?").bind(id));
} }
std::size_t Cluster::computeTrackCount(Session& session, ClusterId id) std::size_t Cluster::computeTrackCount(Session& session, ClusterId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
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") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(t.id) FROM track t INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id)); .where("t_c.cluster_id = ?").bind(id));
} }
@@ -139,7 +139,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
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") return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(DISTINCT r.id) FROM release r INNER JOIN track t on t.release_id = r.id INNER JOIN track_cluster t_c ON t_c.track_id = t.id")
.where("t_c.cluster_id = ?").bind(id)); .where("t_c.cluster_id = ?").bind(id));
} }
@@ -172,7 +172,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM cluster_type")); return utils::fetchQuerySingleResult(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)
@@ -202,14 +202,14 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<ClusterType>().where("name = ?").bind(std::string{ name })); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<ClusterType>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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)
@@ -226,7 +226,7 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
return utils::execSingleResultQuery(session()->find<Cluster>() return utils::fetchQuerySingleResult(session()->find<Cluster>()
.where("name = ?").bind(name) .where("name = ?").bind(name)
.where("cluster_type_id = ?").bind(getId())); .where("cluster_type_id = ?").bind(getId()));
} }
@@ -236,10 +236,8 @@ namespace lms::db
assert(self()); assert(self());
assert(session()); assert(session());
auto res{ utils::execMultiResultQuery(session()->find<Cluster>() return utils::fetchQueryResults<Cluster::pointer>(session()->find<Cluster>()
.where("cluster_type_id = ?").bind(getId()) .where("cluster_type_id = ?").bind(getId())
.orderBy("name")) }; .orderBy("name"));
return std::vector<Cluster::pointer>(res.begin(), res.end());
} }
} // namespace lms::db } // namespace lms::db
+7 -7
View File
@@ -180,13 +180,13 @@ namespace lms::db
std::size_t Listen::getCount(Session& session) std::size_t Listen::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM listen")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<Listen>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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)
@@ -212,7 +212,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<Listen>() return utils::fetchQuerySingleResult(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)
@@ -285,7 +285,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) from listen l") return utils::fetchQuerySingleResult(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)
@@ -296,7 +296,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>( return utils::fetchQuerySingleResult(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"
@@ -314,7 +314,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") return utils::fetchQuerySingleResult(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)
@@ -327,7 +327,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
// TODO not pending remove? // TODO not pending remove?
return utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Listen>>("SELECT l from listen l") return utils::fetchQuerySingleResult(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)
+8 -7
View File
@@ -44,36 +44,37 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM media_library")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("name = ?").bind(name)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<MediaLibrary>().where("path = ?").bind(p)); return utils::fetchQuerySingleResult(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{ utils::execMultiResultQuery(session.getDboSession()->find<MediaLibrary>()) }; utils::forEachQueryResult(session.getDboSession()->find<MediaLibrary>(), [&](const MediaLibrary::pointer& mediaLibrary)
for (const auto& result : results) {
func(result); func(mediaLibrary);
});
} }
} // namespace lms::db } // namespace lms::db
+53 -55
View File
@@ -213,7 +213,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<ReleaseType>() return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("id = ?").bind(id)); .where("id = ?").bind(id));
} }
@@ -221,7 +221,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<ReleaseType>() return utils::fetchQuerySingleResult(session.getDboSession()->find<ReleaseType>()
.where("name = ?").bind(name)); .where("name = ?").bind(name));
} }
@@ -240,19 +240,17 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ utils::execMultiResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r") return utils::fetchQueryResults<Release::pointer>(session.getDboSession()->query<Wt::Dbo::ptr<Release>>("SELECT DISTINCT r from release r")
.join("track t ON t.release_id = r.id") .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()) + "%"));
return std::vector<Release::pointer>(res.begin(), res.end());
} }
Release::pointer Release::find(Session& session, const core::UUID& mbid) Release::pointer Release::find(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<Release>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("mbid = ?").bind(mbid.getAsString())); .where("mbid = ?").bind(mbid.getAsString()));
} }
@@ -260,21 +258,21 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<Release>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Release>()
.where("id = ?").bind(id)); .where("id = ?").bind(id));
} }
bool Release::exists(Session& session, ReleaseId id) bool Release::exists(Session& session, ReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 FROM release").where("id = ?").bind(id)) == 1; return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM release")); return utils::fetchQuerySingleResult(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)
@@ -300,13 +298,11 @@ namespace lms::db
query.where("t.media_library_id = ?").bind(library); query.where("t.media_library_id = ?").bind(library);
} }
auto collection{ utils::execMultiResultQuery(query) }; utils::forEachQueryResult(query, [&](const Release::pointer& release)
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach"); func(release);
func(*itResult); lastRetrievedRelease = release->getId();
lastRetrievedRelease = (*itResult)->getId(); });
}
} }
RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params) RangeResults<Release::pointer> Release::find(Session& session, const FindParameters& params)
@@ -317,12 +313,12 @@ namespace lms::db
return utils::execRangeQuery<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, const std::function<void(const pointer&)>& func)
{ {
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::execRangeQuery<pointer>(query, params.range, func); utils::forEachQueryRangeResult(query, params.range, func);
} }
RangeResults<ReleaseId> Release::findIds(Session& session, const FindParameters& params) RangeResults<ReleaseId> Release::findIds(Session& session, const FindParameters& params)
@@ -337,13 +333,13 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(createQuery<int>(session, "COUNT(DISTINCT r.id)", params)); return utils::fetchQuerySingleResult(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{ utils::execSingleResultQuery(session()->query<int>("SELECT COUNT(DISTINCT disc_number) FROM track t") int res{ utils::fetchQuerySingleResult(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())) };
@@ -354,16 +350,20 @@ namespace lms::db
std::vector<DiscInfo> Release::getDiscs() const std::vector<DiscInfo> Release::getDiscs() const
{ {
assert(session()); assert(session());
using ResultType = std::tuple<int, std::string>; using ResultType = std::tuple<int, std::string>;
auto results{ utils::execMultiResultQuery(session()->query<ResultType>("SELECT DISTINCT disc_number, disc_subtitle FROM track t") const auto query{ 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()) };
std::vector<DiscInfo> discs; std::vector<DiscInfo> discs;
for (const auto& res : results) utils::forEachQueryResult(query, [&](ResultType&& res)
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::get<std::string>(res) }); {
discs.emplace_back(DiscInfo{ static_cast<std::size_t>(std::get<int>(res)), std::move(std::get<std::string>(res)) });
});
return discs; return discs;
} }
@@ -383,13 +383,13 @@ namespace lms::db
assert(session()); assert(session());
const char* field{ original ? "original_date" : "date" }; const char* field{ original ? "original_date" : "date" };
auto query{ (session()->query<Wt::WDate>(std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id")
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")
.where("r.id = ?") .where("r.id = ?")
.groupBy(field) .groupBy(field)
.bind(getId())) }; .bind(getId())) };
const auto dates{ utils::fetchQueryResults(query) };
// various dates => invalid date // various dates => invalid date
if (dates.empty() || dates.size() > 1) if (dates.empty() || dates.size() > 1)
return {}; return {};
@@ -412,11 +412,11 @@ namespace lms::db
assert(session()); assert(session());
const char* field{ original ? "original_year" : "year" }; const char* field{ original ? "original_year" : "year" };
auto query{ session()->query<std::optional<int>>(std::string {"SELECT "} + "t." + field + " FROM track t INNER JOIN release r ON r.id = t.release_id")
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")
.where("r.id = ?").bind(getId()) .where("r.id = ?").bind(getId())
.groupBy(field)) }; .groupBy(field) };
const auto years{ utils::fetchQueryResults(query) };
// various years => invalid years // various years => invalid years
const std::size_t count{ years.size() }; const std::size_t count{ years.size() };
@@ -430,44 +430,43 @@ namespace lms::db
{ {
assert(session()); assert(session());
Wt::Dbo::collection<std::string> copyrights{ utils::execMultiResultQuery(session()->query<std::string> auto query{ 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()); const auto copyrights{ utils::fetchQueryResults(query) };
// various copyrights => no copyright // various copyrights => no copyright
if (values.empty() || values.size() > 1 || values.front().empty()) if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty())
return std::nullopt; return std::nullopt;
return std::move(values.front()); return std::move(copyrights.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 {utils::execMultiResultQuery(session()->query<std::string> const auto query{ 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()); const auto copyrights{ utils::fetchQueryResults(query) };
// various copyright URLs => no copyright URL // various copyright URLs => no copyright URL
if (values.empty() || values.size() > 1 || values.front().empty()) if (copyrights.empty() || copyrights.size() > 1 || copyrights.front().empty())
return std::nullopt; return std::nullopt;
return std::move(values.front()); return std::move(copyrights.front());
} }
std::size_t Release::getMeanBitrate() const std::size_t Release::getMeanBitrate() const
{ {
assert(session()); assert(session());
return utils::execSingleResultQuery(session()->query<int>("SELECT COALESCE(AVG(t.bitrate), 0) FROM track t") return utils::fetchQuerySingleResult(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"));
} }
@@ -476,15 +475,15 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto res{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Artist>>( const auto query{ 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) };
return std::vector<Artist::pointer>(res.begin(), res.end()); return utils::fetchQueryResults<Artist::pointer>(query);
} }
std::vector<Release::pointer> Release::getSimilarReleases(std::optional<std::size_t> offset, std::optional<std::size_t> count) const std::vector<Release::pointer> Release::getSimilarReleases(std::optional<std::size_t> offset, std::optional<std::size_t> count) const
@@ -492,7 +491,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{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Release>>( auto query{ 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"
@@ -510,9 +509,9 @@ 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) };
return std::vector<pointer>(res.begin(), res.end()); return utils::fetchQueryResults<Release::pointer>(query);
} }
void Release::clearReleaseTypes() void Release::clearReleaseTypes()
@@ -538,6 +537,7 @@ namespace lms::db
std::vector<ObjectPtr<ReleaseType>> Release::getReleaseTypes() const std::vector<ObjectPtr<ReleaseType>> Release::getReleaseTypes() const
{ {
// TODO remove?
return std::vector<ObjectPtr<ReleaseType>>(_releaseTypes.begin(), _releaseTypes.end()); return std::vector<ObjectPtr<ReleaseType>>(_releaseTypes.begin(), _releaseTypes.end());
} }
@@ -557,7 +557,7 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
return utils::execSingleResultQuery(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN release r ON t.release_id = r.id") return utils::fetchQuerySingleResult(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()));
} }
@@ -565,7 +565,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
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") return utils::fetchQuerySingleResult(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()));
} }
@@ -593,14 +593,12 @@ 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{ 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) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{ {
if (clustersByType[cluster->getType()->getId()].size() < size) if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster); clustersByType[cluster->getType()->getId()].push_back(cluster);
} });
std::vector<std::vector<Cluster::pointer>> res; std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [clusterTypeId, clusters] : clustersByType) for (const auto& [clusterTypeId, clusters] : clustersByType)
+1 -1
View File
@@ -42,7 +42,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<ScanSettings>()); return utils::fetchQuerySingleResult(session.getDboSession()->find<ScanSettings>());
} }
std::vector<std::filesystem::path> ScanSettings::getAudioFileExtensions() const std::vector<std::filesystem::path> ScanSettings::getAudioFileExtensions() const
+4 -4
View File
@@ -44,19 +44,19 @@ namespace lms::db
std::size_t StarredArtist::getCount(Session& session) std::size_t StarredArtist::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM starred_artist")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<StarredArtist>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredArtist>>("SELECT s_a from starred_artist s_a")
.join("user u ON u.id = s_a.user_id") .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)
@@ -66,7 +66,7 @@ namespace lms::db
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 utils::execSingleResultQuery(session.getDboSession()->find<StarredArtist>() return utils::fetchQuerySingleResult(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));
+3 -3
View File
@@ -50,13 +50,13 @@ namespace lms::db
StarredRelease::pointer StarredRelease::find(Session& session, StarredReleaseId id) StarredRelease::pointer StarredRelease::find(Session& session, StarredReleaseId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<StarredRelease>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredRelease>>("SELECT s_r from starred_release s_r")
.join("user u ON u.id = s_r.user_id") .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)
@@ -66,7 +66,7 @@ namespace lms::db
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 utils::execSingleResultQuery(session.getDboSession()->find<StarredRelease>() return utils::fetchQuerySingleResult(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));
+5 -5
View File
@@ -44,19 +44,19 @@ namespace lms::db
std::size_t StarredTrack::getCount(Session& session) std::size_t StarredTrack::getCount(Session& session)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM starred_track")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<StarredTrack>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t") return utils::fetchQuerySingleResult(session.getDboSession()->query<Wt::Dbo::ptr<StarredTrack>>("SELECT s_t from starred_track s_t")
.join("user u ON u.id = s_t.user_id") .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)
@@ -66,7 +66,7 @@ namespace lms::db
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 utils::execSingleResultQuery(session.getDboSession()->find<StarredTrack>() return utils::fetchQuerySingleResult(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));
@@ -74,7 +74,7 @@ namespace lms::db
bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend) bool StarredTrack::exists(Session& session, TrackId trackId, UserId userId, FeedbackBackend backend)
{ {
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 from starred_track") return utils::fetchQuerySingleResult(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));
+23 -34
View File
@@ -209,21 +209,21 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<Track>().where("file_path = ?").bind(p.string())); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<Track>() return utils::fetchQuerySingleResult(session.getDboSession()->find<Track>()
.where("id = ?").bind(id)); .where("id = ?").bind(id));
} }
@@ -239,41 +239,34 @@ 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{ utils::execMultiResultQuery(query) }; utils::forEachQueryResult(query, [&](const Track::pointer& track)
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult)
{ {
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach"); func(track);
func(*itResult); lastRetrievedTrack = track->getId();
lastRetrievedTrack = (*itResult)->getId(); });
}
} }
bool Track::exists(Session& session, TrackId id) bool Track::exists(Session& session, TrackId id)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT 1 from track").where("id = ?").bind(id)) == 1; return utils::fetchQuerySingleResult(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{ utils::execMultiResultQuery(session.getDboSession()->find<Track>() return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("mbid = ?").bind(std::string {mbid.getAsString()})) }; .where("mbid = ?").bind(mbid.getAsString()));
return std::vector<Track::pointer>(res.begin(), res.end());
} }
std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid) std::vector<Track::pointer> Track::findByRecordingMBID(Session& session, const core::UUID& mbid)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ utils::execMultiResultQuery(session.getDboSession()->find<Track>() return utils::fetchQueryResults<Track::pointer>(session.getDboSession()->find<Track>()
.where("recording_mbid = ?").bind(std::string {mbid.getAsString()})) }; .where("recording_mbid = ?").bind(mbid.getAsString()));
return std::vector<Track::pointer>(res.begin(), res.end());
} }
RangeResults<Track::PathResult> Track::findPaths(Session& session, std::optional<Range> range) RangeResults<Track::PathResult> Track::findPaths(Session& session, std::optional<Range> range)
@@ -330,11 +323,11 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto res{ utils::execMultiResultQuery(session()->query<ClusterId> const auto query{ 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()) };
return std::vector<ClusterId>(res.begin(), res.end()); return utils::fetchQueryResults(query);
} }
RangeResults<TrackId> Track::findIds(Session& session, const FindParameters& parameters) RangeResults<TrackId> Track::findIds(Session& session, const FindParameters& parameters)
@@ -353,20 +346,20 @@ namespace lms::db
return utils::execRangeQuery<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, const std::function<void(const Track::pointer&)>& func)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params) }; auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params) };
utils::execRangeQuery(query, params.range, func); utils::forEachQueryRangeResult(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, const std::function<void(const Track::pointer&)>& func)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params) }; auto query{ createQuery<Wt::Dbo::ptr<Track>>(session, params) };
utils::execRangeQuery(query, params.range, moreResults, func); utils::forEachQueryRangeResult(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)
@@ -457,8 +450,7 @@ namespace lms::db
query.where("t.id = ?").bind(getId()); query.where("t.id = ?").bind(getId());
auto res{ utils::execMultiResultQuery(query) }; return utils::fetchQueryResults<Artist::pointer>(query);
return std::vector<Artist::pointer>(std::begin(res), std::end(res));
} }
std::vector<ArtistId> Track::getArtistIds(core::EnumSet<TrackArtistLinkType> linkTypes) const std::vector<ArtistId> Track::getArtistIds(core::EnumSet<TrackArtistLinkType> linkTypes) const
@@ -493,8 +485,7 @@ namespace lms::db
query.where("t.id = ?").bind(getId()); query.where("t.id = ?").bind(getId());
auto res{ utils::execMultiResultQuery(query) }; return utils::fetchQueryResults(query);
return std::vector<ArtistId>(std::cbegin(res), std::cend(res));
} }
std::vector<TrackArtistLink::pointer> Track::getArtistLinks() const std::vector<TrackArtistLink::pointer> Track::getArtistLinks() const
@@ -527,14 +518,12 @@ 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{ 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) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{ {
if (clusters[cluster->getType()->getId()].size() < size) if (clusters[cluster->getType()->getId()].size() < size)
clusters[cluster->getType()->getId()].push_back(cluster); clusters[cluster->getType()->getId()].push_back(cluster);
} });
std::vector<std::vector<Cluster::pointer>> res; std::vector<std::vector<Cluster::pointer>> res;
for (const auto& [type, clusters] : clusters) for (const auto& [type, clusters] : clusters)
+16 -7
View File
@@ -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 utils::execSingleResultQuery(session.getDboSession()->find<TrackArtistLink>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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)
@@ -91,19 +91,28 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ utils::execMultiResultQuery(session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")) }; const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link") };
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res)); core::EnumSet<TrackArtistLinkType> res;
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType)
{
res.insert(linkType);
});
return res;
} }
core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId) core::EnumSet<TrackArtistLinkType> TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId)
{ {
session.checkReadTransaction(); session.checkReadTransaction();
auto res{ utils::execMultiResultQuery(session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link") const auto query{ session.getDboSession()->query<TrackArtistLinkType>("SELECT DISTINCT type from track_artist_link")
.where("artist_id = ?").bind(artistId)) }; .where("artist_id = ?").bind(artistId) };
return core::EnumSet<TrackArtistLinkType>(std::begin(res), std::end(res)); core::EnumSet<TrackArtistLinkType> res;
utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType)
{
res.insert(linkType);
});
return res;
} }
} }
+3 -3
View File
@@ -42,7 +42,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_bookmark")); return utils::fetchQuerySingleResult(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)
@@ -59,7 +59,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<TrackBookmark>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("user_id = ?").bind(userId) .where("user_id = ?").bind(userId)
.where("track_id = ?").bind(trackId)); .where("track_id = ?").bind(trackId));
} }
@@ -68,7 +68,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<TrackBookmark>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackBookmark>()
.where("id = ?").bind(id)); .where("id = ?").bind(id));
} }
+3 -3
View File
@@ -45,14 +45,14 @@ namespace lms::db {
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM track_features")); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<TrackFeatures>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("id = ?").bind(id)); .where("id = ?").bind(id));
} }
@@ -60,7 +60,7 @@ namespace lms::db {
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<TrackFeatures>() return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackFeatures>()
.where("track_id = ?").bind(trackId)); .where("track_id = ?").bind(trackId));
} }
+17 -19
View File
@@ -55,7 +55,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM tracklist")); return utils::fetchQuerySingleResult(session.getDboSession()->query<int>("SELECT COUNT(*) FROM tracklist"));
} }
@@ -64,7 +64,7 @@ namespace lms::db
session.checkReadTransaction(); session.checkReadTransaction();
assert(userId.isValid()); assert(userId.isValid());
return utils::execSingleResultQuery(session.getDboSession()->find<TrackList>() return utils::fetchQuerySingleResult(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)); .where("user_id = ?").bind(userId));
@@ -124,7 +124,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<TrackList>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackList>().where("id = ?").bind(id));
} }
bool TrackList::isEmpty() const bool TrackList::isEmpty() const
@@ -163,7 +163,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
return utils::execSingleResultQuery(session()->find<TrackListEntry>() return utils::fetchQuerySingleResult(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)));
@@ -173,12 +173,12 @@ namespace lms::db
{ {
assert(session()); assert(session());
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") const auto query{ session()->query<Wt::Dbo::ptr<Cluster>>("SELECT c from cluster c INNER JOIN track t ON c.id = t_c.cluster_id INNER JOIN track_cluster t_c ON t_c.track_id = t.id INNER JOIN tracklist_entry p_e ON p_e.track_id = t.id INNER JOIN tracklist p ON p.id = p_e.tracklist_id")
.where("p.id = ?").bind(getId()) .where("p.id = ?").bind(getId())
.groupBy("c.id") .groupBy("c.id")
.orderBy("COUNT(c.id) DESC")) }; .orderBy("COUNT(c.id) DESC") };
return std::vector<Cluster::pointer>(res.begin(), res.end()); return utils::fetchQueryResults<Cluster::pointer>(query);
} }
std::vector<std::vector<Cluster::pointer>> TrackList::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const std::vector<std::vector<Cluster::pointer>> TrackList::getClusterGroups(const std::vector<ClusterTypeId>& clusterTypeIds, std::size_t size) const
@@ -216,14 +216,12 @@ 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{ 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) utils::forEachQueryResult(query, [&](const Cluster::pointer& cluster)
{ {
if (clustersByType[cluster->getType()->getId()].size() < size) if (clustersByType[cluster->getType()->getId()].size() < size)
clustersByType[cluster->getType()->getId()].push_back(cluster); clustersByType[cluster->getType()->getId()].push_back(cluster);
} });
for (const auto& [clusterTypeId, clusters] : clustersByType) for (const auto& [clusterTypeId, clusters] : clustersByType)
res.push_back(clusters); res.push_back(clusters);
@@ -235,7 +233,7 @@ namespace lms::db
{ {
assert(session()); assert(session());
auto res{ utils::execMultiResultQuery(session()->query<Wt::Dbo::ptr<Track>>( auto query{ 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 "
@@ -247,19 +245,19 @@ 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) };
return std::vector<Track::pointer>(res.begin(), res.end()); return utils::fetchQueryResults<Track::pointer>(query);
} }
std::vector<TrackId> TrackList::getTrackIds() const std::vector<TrackId> TrackList::getTrackIds() const
{ {
assert(session()); assert(session());
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") auto query{ session()->query<TrackId>("SELECT p_e.track_id from tracklist_entry p_e INNER JOIN tracklist p ON p_e.tracklist_id = p.id")
.where("p.id = ?").bind(getId())) }; .where("p.id = ?").bind(getId()) };
return std::vector<TrackId>(res.begin(), res.end()); return utils::fetchQueryResults(query);
} }
std::chrono::milliseconds TrackList::getDuration() const std::chrono::milliseconds TrackList::getDuration() const
@@ -268,7 +266,7 @@ namespace lms::db
using milli = std::chrono::duration<int, std::milli>; using milli = std::chrono::duration<int, std::milli>;
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") return utils::fetchQuerySingleResult(session()->query<milli>("SELECT COALESCE(SUM(duration), 0) FROM track t INNER JOIN tracklist_entry p_e ON t.id = p_e.track_id")
.where("p_e.tracklist_id = ?").bind(getId())); .where("p_e.tracklist_id = ?").bind(getId()));
} }
@@ -305,6 +303,6 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<TrackListEntry>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(session.getDboSession()->find<TrackListEntry>().where("id = ?").bind(id));
} }
} // namespace lms::db } // namespace lms::db
+4 -4
View File
@@ -44,7 +44,7 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->query<int>("SELECT COUNT(*) FROM user")); return utils::fetchQuerySingleResult(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)
@@ -65,17 +65,17 @@ namespace lms::db
{ {
session.checkReadTransaction(); session.checkReadTransaction();
return utils::execSingleResultQuery(session.getDboSession()->find<User>().where("type = ?").bind(UserType::DEMO)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<User>().where("id = ?").bind(id)); return utils::fetchQuerySingleResult(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 utils::execSingleResultQuery(session.getDboSession()->find<User>() return utils::fetchQuerySingleResult(session.getDboSession()->find<User>()
.where("login_name = ?").bind(name)); .where("login_name = ?").bind(name));
} }
+79 -33
View File
@@ -45,22 +45,74 @@ namespace lms::db::utils
} }
} }
template <typename Query> template <typename T>
auto execSingleResultQuery(const Query& query) auto fetchFirstResult(const Wt::Dbo::collection<T>& collection)
{ {
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ExecSingleResultQuery", "Query", query.asString()); LMS_SCOPED_TRACE_DETAILED("Database", "FetchFirstResult");
return collection.begin();
}
template <typename T>
void fetchNextResult(typename Wt::Dbo::collection<T>::const_iterator& it)
{
LMS_SCOPED_TRACE_DETAILED("Database", "FetchNextResult");
it++;
}
template <typename T, typename Func>
void forEachResult(const Wt::Dbo::collection<T>& collection, Func&& func)
{
typename Wt::Dbo::collection<T>::const_iterator it{ fetchFirstResult(collection) };
while (it != collection.end())
{
func(*it);
fetchNextResult<T>(it);
}
}
template <typename T>
struct QueryResultType;
template <class ResultType, typename BindStrategy>
struct QueryResultType<Wt::Dbo::Query<ResultType, BindStrategy>>
{
using type = ResultType;
};
template <typename Query, typename UnaryFunc>
void forEachQueryResult(const Query& query, UnaryFunc&& func)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ForEachQueryResult", "Query", query.asString());
forEachResult(query.resultList(), std::forward<UnaryFunc>(func));
}
template <typename T, typename Query>
std::vector<T> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
auto collection{ query.resultList() };
return std::vector<T>(collection.begin(), collection.end());
}
template <typename Query>
std::vector<typename QueryResultType<Query>::type> fetchQueryResults(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQueryResults", "Query", query.asString());
auto collection{ query.resultList() };
return std::vector<typename QueryResultType<Query>::type>(collection.begin(), collection.end());
}
template <typename Query>
auto fetchQuerySingleResult(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "FetchQuerySingleResult", "Query", query.asString());
return query.resultValue(); return query.resultValue();
} }
template <typename Query>
auto execMultiResultQuery(const Query& query)
{
LMS_SCOPED_TRACE_DETAILED_WITH_ARG("Database", "ExecMultiResultQuery", "Query", query.asString());
return query.resultList();
}
template <typename ResultType, typename Query> template <typename ResultType, typename Query>
RangeResults<ResultType> execRangeQuery(Query& query, std::optional<Range> range) RangeResults<ResultType> execRangeQuery(Query& query, const std::optional<Range> range)
{ {
RangeResults<ResultType> res; RangeResults<ResultType> res;
@@ -72,16 +124,12 @@ namespace lms::db::utils
res.results.reserve(range->size); res.results.reserve(range->size);
} }
auto collection{ execMultiResultQuery(query) }; // TODO optim useless last copy
for (auto itResult{ collection.begin() }; itResult != collection.end(); ++itResult) res.results = utils::fetchQueryResults<ResultType>(query);
{ if (range && (res.results.size() == range->size + 1))
if (range && res.results.size() == range->size)
{ {
res.moreResults = true; res.moreResults = true;
break; res.results.pop_back();
}
res.results.push_back(std::move(*itResult));
} }
res.range.size = res.results.size(); res.range.size = res.results.size();
@@ -89,31 +137,29 @@ namespace lms::db::utils
return res; return res;
} }
template <typename ResultType, typename Query> template <typename Query, typename UnaryFunc>
void execRangeQuery(Query& query, std::optional<Range> range, const std::function<void(const ResultType&)>& func) void forEachQueryRangeResult(Query& query, std::optional<Range> range, UnaryFunc&& func)
{ {
if (range) if (range)
applyRange(query, range); applyRange(query, range);
auto collection{ execMultiResultQuery(query) }; forEachQueryResult(query, std::forward<UnaryFunc>(func));
for (const auto& res : collection)
{
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach");
func(res);
}
} }
template <typename ResultType, typename Query> template <typename Query, typename UnaryFunc>
void execRangeQuery(Query& query, std::optional<Range> range, bool& moreResults, const std::function<void(const ResultType&)>& func) void forEachQueryRangeResult(Query& query, std::optional<Range> range, bool& moreResults, UnaryFunc&& func)
{ {
using ResultType = typename QueryResultType<Query>::type;
if (range) if (range)
applyRange(query, Range{ range->offset, range->size + 1 }); applyRange(query, Range{ range->offset, range->size + 1 });
moreResults = false; moreResults = false;
std::size_t count{}; std::size_t count{};
auto collection{ execMultiResultQuery(query) }; const auto collection{ query.resultList() };
for (const auto& res : collection) auto it{ fetchFirstResult(collection) };
while (it != collection.end())
{ {
if (range && (count++ == static_cast<std::size_t>(range->size))) if (range && (count++ == static_cast<std::size_t>(range->size)))
{ {
@@ -121,8 +167,8 @@ namespace lms::db::utils
break; break;
} }
LMS_SCOPED_TRACE_DETAILED("Database", "ExecQueryRangeForEach"); func(*it);
func(res); fetchNextResult<ResultType>(it);
} }
} }
@@ -124,7 +124,7 @@ namespace lms::db
static pointer find(Session& session, ReleaseId id); static pointer find(Session& session, ReleaseId id);
static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library = {}); static void find(Session& session, ReleaseId& lastRetrievedRelease, std::size_t count, const std::function<void(const Release::pointer&)>& func, MediaLibraryId library = {});
static RangeResults<pointer> find(Session& session, const FindParameters& parameters); static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, std::function<void(const pointer&)> func); static void find(Session& session, const FindParameters& parameters, const std::function<void(const pointer&)>& func);
static RangeResults<ReleaseId> findIds(Session& session, const FindParameters& parameters); static RangeResults<ReleaseId> findIds(Session& session, const FindParameters& parameters);
static std::size_t getCount(Session& session, const FindParameters& parameters); static std::size_t getCount(Session& session, const FindParameters& parameters);
static RangeResults<ReleaseId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // not track related static RangeResults<ReleaseId> findOrphanIds(Session& session, std::optional<Range> range = std::nullopt); // not track related
+2 -2
View File
@@ -118,8 +118,8 @@ namespace lms::db
static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters); static RangeResults<TrackId> findIds(Session& session, const FindParameters& parameters);
static RangeResults<pointer> find(Session& session, const FindParameters& parameters); static RangeResults<pointer> find(Session& session, const FindParameters& parameters);
static void find(Session& session, const FindParameters& parameters, std::function<void(const Track::pointer&)> func); static void find(Session& session, const FindParameters& parameters, const std::function<void(const Track::pointer&)>& func);
static void find(Session& session, const FindParameters& parameters, bool& moreResults, std::function<void(const Track::pointer&)> func); static void find(Session& session, const FindParameters& parameters, bool& moreResults, const std::function<void(const Track::pointer&)>& func);
static RangeResults<PathResult> findPaths(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<PathResult> findPaths(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<TrackId> findIdsTrackMBIDDuplicates(Session& session, std::optional<Range> range = std::nullopt);
static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt); static RangeResults<TrackId> findIdsWithRecordingMBIDAndMissingFeatures(Session& session, std::optional<Range> range = std::nullopt);