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 <set>
24 
25 #include <Wt/WDateTime.h>
26 #include <Wt/Dbo/Dbo.h>
27 
28 #include "utils/UUID.hpp"
29 #include "Types.hpp"
30 
31 namespace Database
32 {
33 
34 class Artist;
35 class Cluster;
36 class ClusterType;
37 class Release;
38 class Session;
39 class Track;
40 class User;
41 
42 class Release : public Wt::Dbo::Dbo<Release>
43 {
44 	public:
45 
46 		using pointer = Wt::Dbo::ptr<Release>;
47 
Release()48 		Release() {}
49 		Release(const std::string& name, const std::optional<UUID>& MBID = {});
50 
51 		// Accessors
52 		static std::size_t		getCount(Session& session);
53 		static pointer			getByMBID(Session& session, const UUID& MBID);
54 		static std::vector<pointer>	getByName(Session& session, const std::string& name);
55 		static pointer			getById(Session& session, IdType id);
56 		static std::vector<pointer>	getAllOrphans(Session& session); // no track related
57 		static std::vector<pointer>	getAll(Session& session, std::optional<Range> range = std::nullopt);
58 		static std::vector<IdType>	getAllIds(Session& session);
59 		static std::vector<pointer>	getAllOrderedByArtist(Session& session, std::optional<std::size_t> offset = {}, std::optional<std::size_t> size = {});
60 		static std::vector<pointer>	getAllRandom(Session& session, const std::set<IdType>& clusters, std::optional<std::size_t> size = {});
61 		static std::vector<IdType>	getAllIdsRandom(Session& session, const std::set<IdType>& clusters, std::optional<std::size_t> size = {});
62 		static std::vector<pointer>	getLastWritten(Session& session, std::optional<Wt::WDateTime> after, const std::set<IdType>& clusters, std::optional<Range> range, bool& moreResults);
63 		static std::vector<pointer>	getByYear(Session& session, int yearFrom, int yearTo, std::optional<Range> range = std::nullopt);
64 		static std::vector<pointer> getStarred(Session& session, Wt::Dbo::ptr<User> user, const std::set<IdType>& clusters, std::optional<Range> range, bool& moreResults);
65 
66 		static std::vector<pointer>	getByClusters(Session& session, const std::set<IdType>& clusters);
67 		static std::vector<pointer>	getByFilter(Session& session,
68 							const std::set<IdType>& clusters,		// if non empty, at least one release that belongs to these clusters
69 							const std::vector<std::string>& keywords,	// if non empty, name must match all of these keywords
70 							std::optional<Range> range,
71 							bool& moreExpected);
72 		static std::vector<IdType>	getAllIdsWithClusters(Session& session, std::optional<std::size_t> limit = {});
73 
74 		std::vector<Wt::Dbo::ptr<Track>> getTracks(const std::set<IdType>& clusters = std::set<IdType>()) const;
75 		std::size_t			getTracksCount() const;
76 		Wt::Dbo::ptr<Track>			getFirstTrack() const;
77 
78 		// Get the cluster of the tracks that belong to this release
79 		// Each clusters are grouped by cluster type, sorted by the number of occurence (max to min)
80 		// size is the max number of cluster per cluster type
81 		std::vector<std::vector<Wt::Dbo::ptr<Cluster>>> getClusterGroups(std::vector<Wt::Dbo::ptr<ClusterType>> clusterTypes, std::size_t size) const;
82 
83 		// Create
84 		static pointer create(Session& session, const std::string& name, const std::optional<UUID>& MBID = {});
85 
86 		// Utility functions
87 		std::optional<int> getReleaseYear(bool originalDate = false) const; // 0 if unknown or various
88 		std::optional<std::string> getCopyright() const;
89 		std::optional<std::string> getCopyrightURL() const;
90 
91 		// Accessors
getName() const92 		const std::string&		getName() const		{ return _name; }
getMBID() const93 		std::optional<UUID>		getMBID() const		{ return UUID::fromString(_MBID); }
94 		std::optional<std::size_t>	getTotalTrack() const;
95 		std::optional<std::size_t>	getTotalDisc() const;
96 		std::chrono::milliseconds	getDuration() const;
97 		Wt::WDateTime				getLastWritten() const;
98 
99 		// Get the artists of this release
100 		std::vector<Wt::Dbo::ptr<Artist> > getArtists(TrackArtistLinkType type = TrackArtistLinkType::Artist) const;
getReleaseArtists() const101 		std::vector<Wt::Dbo::ptr<Artist> > getReleaseArtists() const { return getArtists(TrackArtistLinkType::ReleaseArtist); }
102 		bool hasVariousArtists() const;
103 		std::vector<pointer>		getSimilarReleases(std::optional<std::size_t> offset = {}, std::optional<std::size_t> count = {}) const;
104 
setName(std::string_view name)105 		void setName(std::string_view name)		{ _name = name; }
setMBID(const std::optional<UUID> & mbid)106 		void setMBID(const std::optional<UUID>& mbid)	{ _MBID = mbid ? mbid->getAsString() : ""; }
107 
108 		template<class Action>
persist(Action & a)109 			void persist(Action& a)
110 			{
111 				Wt::Dbo::field(a, _name, "name");
112 				Wt::Dbo::field(a, _MBID, "mbid");
113 
114 				Wt::Dbo::hasMany(a, _tracks, Wt::Dbo::ManyToOne, "release");
115 				Wt::Dbo::hasMany(a, _starringUsers, Wt::Dbo::ManyToMany, "user_release_starred", "", Wt::Dbo::OnDeleteCascade);
116 			}
117 
118 	private:
119 		static const std::size_t _maxNameLength {128};
120 
121 		std::string	_name;
122 		std::string	_MBID;
123 
124 		Wt::Dbo::collection<Wt::Dbo::ptr<Track>>	_tracks; // Tracks in the release
125 		Wt::Dbo::collection<Wt::Dbo::ptr<User>>		_starringUsers; // Users that starred this release
126 };
127 
128 } // namespace Database
129 
130 
131