/* * Copyright (C) 2013-2016 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/objects/TrackArtistLink.hpp" #include #include "core/ILogger.hpp" #include "core/String.hpp" #include "database/Session.hpp" #include "database/objects/Artist.hpp" #include "database/objects/Genre.hpp" #include "database/objects/Grouping.hpp" #include "database/objects/Language.hpp" #include "database/objects/Mood.hpp" #include "database/objects/Track.hpp" #include "Utils.hpp" #include "traits/IdTypeTraits.hpp" DBO_INSTANTIATE_TEMPLATES(lms::db::TrackArtistLink) namespace lms::db { namespace { Wt::Dbo::Query> createQuery(Session& session, const TrackArtistLink::FindParameters& params) { session.checkReadTransaction(); auto query{ session.getDboSession()->query>("SELECT t_a_l FROM track_artist_link t_a_l") }; if (params.linkType) query.where("t_a_l.type = ?").bind(*params.linkType); if (params.track.isValid()) query.where("t_a_l.track_id = ?").bind(params.track); if (params.artist.isValid()) query.where("t_a_l.artist_id = ?").bind(params.artist); if (params.release.isValid() || params.sortMethod == TrackArtistLinkSortMethod::OriginalDateDesc) { query.join("track t ON t.id = t_a_l.track_id"); if (params.release.isValid()) query.where("t.release_id = ?").bind(params.release); } if (params.mbidMatched) query.where("t_a_l.artist_mbid_matched = ?").bind(*params.mbidMatched); switch (params.sortMethod) { case TrackArtistLinkSortMethod::None: break; case TrackArtistLinkSortMethod::OriginalDateDesc: query.orderBy("COALESCE(t.original_date, t.date) DESC"); break; } return query; } } // namespace TrackArtistLink::TrackArtistLink(const ObjectPtr& track, const ObjectPtr& artist, TrackArtistLinkType type, std::string_view subType, bool artistMBIDMatched) : _type{ type } , _subType{ subType } , _artistMBIDMatched{ artistMBIDMatched } , _track{ getDboPtr(track) } , _artist{ getDboPtr(artist) } { } TrackArtistLink::pointer TrackArtistLink::create(Session& session, const ObjectPtr& track, const ObjectPtr& artist, TrackArtistLinkType type, std::string_view subType, bool artistMBIDMatched) { session.checkWriteTransaction(); return session.getDboSession()->add(std::make_unique(track, artist, type, subType, artistMBIDMatched)); } TrackArtistLink::pointer TrackArtistLink::create(Session& session, const ObjectPtr& track, const ObjectPtr& artist, TrackArtistLinkType type, bool artistMBIDMatched) { return create(session, track, artist, type, std::string_view{}, artistMBIDMatched); } std::size_t TrackArtistLink::getCount(Session& session) { session.checkReadTransaction(); return utils::fetchQuerySingleResult(session.getDboSession()->query("SELECT COUNT(*) FROM track_artist_link")); } TrackArtistLink::pointer TrackArtistLink::find(Session& session, TrackArtistLinkId id) { session.checkReadTransaction(); return utils::fetchQuerySingleResult(session.getDboSession()->query>("SELECT t_a_l from track_artist_link t_a_l").where("t_a_l.id = ?").bind(id)); } void TrackArtistLink::find(Session& session, TrackId trackId, const std::function& artist)>& func) { session.checkReadTransaction(); using ResultType = std::tuple, Wt::Dbo::ptr>; const auto query{ session.getDboSession()->query("SELECT t_a_l, a FROM track_artist_link t_a_l").join("artist a ON t_a_l.artist_id = a.id").where("t_a_l.track_id = ?").bind(trackId) }; utils::forEachQueryResult(query, [&](const ResultType& result) { func(std::get>(result), std::get>(result)); }); } void TrackArtistLink::find(Session& session, const FindParameters& params, const std::function& func) { auto query{ createQuery(session, params) }; utils::forEachQueryRangeResult(query, params.range, func); } core::EnumSet TrackArtistLink::findUsedTypes(Session& session, ArtistId artistId) { session.checkReadTransaction(); const auto query{ session.getDboSession()->query("SELECT DISTINCT type from track_artist_link").where("artist_id = ?").bind(artistId) }; core::EnumSet res; utils::forEachQueryResult(query, [&](TrackArtistLinkType linkType) { res.insert(linkType); }); return res; } void TrackArtistLink::findArtistNameNoLongerMatch(Session& session, std::optional range, const std::function& func) { session.checkReadTransaction(); auto query{ session.getDboSession()->query>("SELECT t_a_l FROM track_artist_link t_a_l") }; query.join("artist a ON t_a_l.artist_id = a.id"); query.where("t_a_l.artist_mbid_matched = FALSE"); query.where("t_a_l.artist_name <> a.name"); utils::applyRange(query, range); utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) { func(link); }); } void TrackArtistLink::findWithArtistNameAmbiguity(Session& session, std::optional range, bool allowArtistMBIDFallback, const std::function& func) { session.checkReadTransaction(); auto query{ session.getDboSession()->query>("SELECT t_a_l FROM track_artist_link t_a_l") }; query.join("artist a ON t_a_l.artist_id = a.id"); query.where("t_a_l.artist_mbid_matched = FALSE"); if (!allowArtistMBIDFallback) { query.where("a.mbid IS NOT NULL"); } else { query.where(R"( (a.mbid IS NOT NULL AND EXISTS (SELECT 1 FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL AND a2.mbid <> a.mbid)) OR (a.mbid IS NULL AND (SELECT COUNT(*) FROM artist a2 WHERE a2.name = a.name AND a2.mbid IS NOT NULL) = 1))"); } utils::applyRange(query, range); utils::forEachQueryResult(query, [&](const TrackArtistLink::pointer& link) { func(link); }); } void TrackArtistLink::setArtist(ObjectPtr artist) { _artist = getDboPtr(artist); } void TrackArtistLink::setArtistName(std::string_view artistName) { _artistName = core::stringUtils::utf8Truncate(artistName, Artist::maxNameLength); LMS_LOG_IF(DB, WARNING, artistName.size() > Artist::maxNameLength, "Artist link name too long, truncated to '" << _artistName << "'"); } void TrackArtistLink::setArtistSortName(std::string_view artistSortName) { _artistSortName = core::stringUtils::utf8Truncate(artistSortName, Artist::maxNameLength); LMS_LOG_IF(DB, WARNING, artistSortName.size() > Artist::maxNameLength, "Artist link sort name too long, truncated to '" << _artistSortName << "'"); } } // namespace lms::db