1 /*
2  * Copyright (C) 2015 Emeric Poupon
3  *
4  * This file is part of LMS.
5  *
6  * LMS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * LMS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with LMS.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #pragma once
21 
22 #include <optional>
23 #include <string>
24 #include <unordered_set>
25 #include <vector>
26 
27 #include <Wt/WDateTime.h>
28 #include <Wt/Dbo/Dbo.h>
29 
30 #include "utils/EnumSet.hpp"
31 #include "utils/UUID.hpp"
32 
33 #include "Types.hpp"
34 
35 namespace Database
36 {
37 
38 class Cluster;
39 class ClusterType;
40 class Release;
41 class Session;
42 class Track;
43 class TrackArtistLink;
44 class User;
45 
46 class Artist : public Wt::Dbo::Dbo<Artist>
47 {
48 	public:
49 
50 		enum class SortMethod
51 		{
52 			None,
53 			ByName,
54 			BySortName,
55 		};
56 
57 		using pointer = Wt::Dbo::ptr<Artist>;
58 
Artist()59 		Artist() {}
60 		Artist(const std::string& name, const std::optional<UUID>& MBID = {});
61 
62 		// Accessors
63 		static pointer			getByMBID(Session& session, const UUID& MBID);
64 		static pointer			getById(Session& session, IdType id);
65 		static std::vector<pointer>	getByName(Session& session, const std::string& name);		// exact match on name field
66 		static std::vector<pointer> 	getByClusters(Session& session,
67 								const std::set<IdType>& clusters,		// at least one track that belongs to  these clusters
68 								SortMethod sortMethod
69 								);
70 		static std::vector<pointer> 	getByFilter(Session& session,
71 								const std::set<IdType>& clusters,		// if non empty, at least one artist that belongs to these clusters
72 								const std::vector<std::string>& keywords,	// if non empty, name must match all of these keywords (name + sort name fields)
73 								std::optional<TrackArtistLinkType> linkType, 	// if set, only artists that have produced at least one track with this link type
74 								SortMethod sortMethod,
75 								std::optional<Range> range,
76 								bool& moreExpected);
77 
78 		static std::vector<pointer>	getAll(Session& session);
79 		static std::vector<pointer>	getAll(Session& session, SortMethod sortMethod);
80 		static std::vector<pointer>	getAll(Session& session, SortMethod sortMethod, std::optional<Range> range, bool& moreResults);
81 		static std::vector<IdType>	getAllIds(Session& session);
82 		static std::vector<IdType>	getAllIdsRandom(Session& session, const std::set<IdType>& clusters, std::optional<TrackArtistLinkType> linkType, std::optional<std::size_t> size = {});
83 		static std::vector<pointer>	getAllOrphans(Session& session); // No track related
84 		static std::vector<pointer>	getLastWritten(Session& session,
85 								std::optional<Wt::WDateTime> after,
86 								const std::set<IdType>& clusters,
87 								std::optional<TrackArtistLinkType> linkType, 	// if set, only artists that have produced at least one track with this link type
88 								std::optional<Range>,
89 								bool& moreResults);
90 		static std::vector<IdType>	getAllIdsWithClusters(Session& session, std::optional<std::size_t> limit = {});
91 		static std::vector<pointer>	getStarred(Session& session,
92 								Wt::Dbo::ptr<User> user,
93 								const std::set<IdType>& clusters,
94 								std::optional<TrackArtistLinkType> linkType, 	// if set, only artists that have produced at least one track with this link type
95 								SortMethod sortMethod,
96 								std::optional<Range>, bool& moreResults);
97 
98 		// Accessors
getName() const99 		const std::string&	getName() const { return _name; }
getSortName() const100 		const std::string&	getSortName() const { return _sortName; }
getMBID() const101 		std::optional<UUID>	getMBID() const { return UUID::fromString(_MBID); }
102 
103 		std::vector<Wt::Dbo::ptr<Release>>	getReleases(const std::set<IdType>& clusterIds = {}) const; // if non empty, get the releases that match all these clusters
104 		std::size_t				getReleaseCount() const;
105 		std::vector<Wt::Dbo::ptr<Track>>	getTracks(std::optional<TrackArtistLinkType> linkType = {}) const;
106 		std::vector<Wt::Dbo::ptr<Track>>	getTracksWithRelease(std::optional<TrackArtistLinkType> linkType = {}) const;
107 		std::vector<Wt::Dbo::ptr<Track>>	getRandomTracks(std::optional<std::size_t> count) const;
108 
109 		// No artistLinkTypes means get them all
110 		std::vector<pointer>				getSimilarArtists(EnumSet<TrackArtistLinkType> artistLinkTypes = {}, std::optional<Range> range = std::nullopt) const;
111 
112 		// Get the cluster of the tracks made by this artist
113 		// Each clusters are grouped by cluster type, sorted by the number of occurence
114 		// size is the max number of cluster per cluster type
115 		std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
116 
setName(std::string_view name)117 		void setName(std::string_view name)		{ _name  = name; }
setMBID(const std::optional<UUID> & mbid)118 		void setMBID(const std::optional<UUID>& mbid)	{ _MBID = mbid ? mbid->getAsString() : ""; }
119 		void setSortName(const std::string& sortName);
120 
121 		// Create
122 		static pointer create(Session& session, const std::string& name, const std::optional<UUID>& UUID = {});
123 
124 		template<class Action>
persist(Action & a)125 			void persist(Action& a)
126 			{
127 				Wt::Dbo::field(a, _name, "name");
128 				Wt::Dbo::field(a, _sortName, "sort_name");
129 				Wt::Dbo::field(a, _MBID, "mbid");
130 
131 				Wt::Dbo::hasMany(a, _trackArtistLinks, Wt::Dbo::ManyToOne, "artist");
132 				Wt::Dbo::hasMany(a, _starringUsers, Wt::Dbo::ManyToMany, "user_release_starred", "", Wt::Dbo::OnDeleteCascade);
133 			}
134 
135 	private:
136 
137 		static const std::size_t _maxNameLength = 128;
138 
139 		std::string _name;
140 		std::string _sortName;
141 		std::string _MBID;	// Musicbrainz Identifier
142 
143 		Wt::Dbo::collection<Wt::Dbo::ptr<TrackArtistLink>> _trackArtistLinks; // Tracks involving this artist
144 		Wt::Dbo::collection<Wt::Dbo::ptr<User>>		_starringUsers; // Users that starred this artist
145 };
146 
147 } // namespace Database
148 
149