/*
* Copyright (C) 2014 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see .
*/
#include "database/TrackList.hpp"
#include
#include "database/Cluster.hpp"
#include "database/PlayListFile.hpp"
#include "database/Session.hpp"
#include "database/Track.hpp"
#include "database/User.hpp"
#include "SqlQuery.hpp"
#include "Utils.hpp"
#include "traits/IdTypeTraits.hpp"
#include "traits/StringViewTraits.hpp"
namespace lms::db
{
namespace
{
template
Wt::Dbo::Query createQuery(Session& session, std::string_view itemToSelect, const TrackList::FindParameters& params)
{
assert(!params.user.isValid() || !params.excludedUser.isValid());
auto query{ session.getDboSession()->query("SELECT " + std::string{ itemToSelect } + " FROM tracklist t_l") };
if (!params.filters.clusters.empty()
|| params.filters.mediaLibrary.isValid()
|| params.filters.label.isValid())
{
query.join("tracklist_entry t_l_e ON t_l_e.tracklist_id = t_l.id");
query.groupBy("t_l.id");
}
for (std::string_view keyword : params.keywords)
query.where("t_l.name LIKE ? ESCAPE '" ESCAPE_CHAR_STR "'").bind("%" + utils::escapeLikeKeyword(keyword) + "%");
if (params.filters.mediaLibrary.isValid()
|| params.filters.label.isValid()
|| params.filters.releaseType.isValid())
{
query.join("track t ON t.id = t_l_e.track_id");
if (params.filters.mediaLibrary.isValid())
query.where("t.media_library_id = ?").bind(params.filters.mediaLibrary);
if (params.filters.label.isValid())
{
query.join("release_label r_l ON r_l.release_id = t.release_id");
query.where("r_l.label_id = ?").bind(params.filters.label);
}
if (params.filters.releaseType.isValid())
{
query.join("release_release_type r_r_t ON r_r_t.release_id = t.release_id");
query.where("r_r_t.release_type_id = ?").bind(params.filters.releaseType);
}
}
if (params.user.isValid())
query.where("t_l.user_id = ?").bind(params.user);
else if (params.excludedUser.isValid())
query.where("t_l.user_id <> ? OR t_l.user_id IS NULL").bind(params.excludedUser);
if (params.type)
query.where("t_l.type = ?").bind(*params.type);
if (params.visibility)
query.where("t_l.visibility = ?").bind(*params.visibility);
if (!params.filters.clusters.empty())
{
std::ostringstream oss;
oss << "t_l_e.track_id IN (SELECT DISTINCT t.id FROM track t"
" INNER JOIN track_cluster t_c ON t_c.track_id = t.id"
" INNER JOIN cluster c ON c.id = t_c.cluster_id";
WhereClause clusterClause;
for (const ClusterId clusterId : params.filters.clusters)
{
clusterClause.Or(WhereClause("c.id = ?"));
query.bind(clusterId);
}
oss << " " << clusterClause.get();
oss << " GROUP BY t.id HAVING COUNT(*) = " << params.filters.clusters.size() << ")";
query.where(oss.str());
}
switch (params.sortMethod)
{
case TrackListSortMethod::None:
break;
case TrackListSortMethod::Name:
query.orderBy("t_l.name COLLATE NOCASE");
break;
case TrackListSortMethod::LastModifiedDesc:
query.orderBy("t_l.last_modified_date_time DESC");
break;
}
return query;
}
template
Wt::Dbo::Query createQuery(Session& session, const TrackList::FindParameters& params)
{
std::string_view itemToSelect;
if constexpr (std::is_same_v)
itemToSelect = "t_l.id";
else if constexpr (std::is_same_v>)
itemToSelect = "t_l";
else
static_assert("Unhandled type");
return createQuery(session, itemToSelect, params);
}
} // namespace
TrackList::TrackList(std::string_view name, TrackListType type)
: _name{ name }
, _type{ type }
, _creationDateTime{ utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
, _lastModifiedDateTime{ utils::normalizeDateTime(Wt::WDateTime::currentDateTime()) }
{
}
TrackList::pointer TrackList::create(Session& session, std::string_view name, TrackListType type)
{
return session.getDboSession()->add(std::unique_ptr{ new TrackList{ name, type } });
}
std::size_t TrackList::getCount(Session& session)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(*) FROM tracklist"));
}
TrackList::pointer TrackList::find(Session& session, std::string_view name, TrackListType type, UserId userId)
{
session.checkReadTransaction();
assert(userId.isValid());
return utils::fetchQuerySingleResult(session.getDboSession()->query>("select t_l from tracklist t_l").where("t_l.name = ?").bind(name).where("t_l.type = ?").bind(type).where("t_l.user_id = ?").bind(userId));
}
RangeResults TrackList::find(Session& session, const FindParameters& params)
{
session.checkReadTransaction();
auto query{ createQuery(session, params) };
return utils::execRangeQuery(query, params.range);
}
void TrackList::find(Session& session, const FindParameters& params, const std::function& func)
{
session.checkReadTransaction();
auto query{ createQuery>(session, params) };
utils::forEachQueryRangeResult(query, params.range, func);
}
TrackList::pointer TrackList::find(Session& session, TrackListId id)
{
session.checkReadTransaction();
return utils::fetchQuerySingleResult(session.getDboSession()->query>("select t_l from tracklist t_l").where("t_l.id = ?").bind(id));
}
bool TrackList::isEmpty() const
{
return _entries.empty();
}
std::size_t TrackList::getCount() const
{
return _entries.size();
}
TrackListEntry::pointer TrackList::getEntry(std::size_t pos) const
{
TrackListEntry::pointer res;
auto entries = getEntries(Range{ pos, 1 });
if (!entries.results.empty())
res = entries.results.front();
return res;
}
RangeResults> TrackList::getEntries(std::optional range) const
{
assert(session());
auto query{ session()->find().where("tracklist_id = ?").bind(getId()).orderBy("id") };
return utils::execRangeQuery(query, range);
}
TrackListEntry::pointer TrackList::getEntryByTrackAndDateTime(ObjectPtr