lastfm_client/types/
albums.rs1use std::cmp::Ordering;
2use std::fmt;
3
4use crate::types::{BaseObject, BaseResponse, RankAttr, TrackImage};
5use serde::{Deserialize, Serialize};
6
7use crate::types::utils::u32_from_str;
8
9#[derive(Serialize, Deserialize, Debug, Clone)]
13#[non_exhaustive]
14pub struct TopAlbum {
15 pub name: String,
17 pub artist: BaseObject,
19 pub mbid: String,
21 pub url: String,
23 #[serde(deserialize_with = "u32_from_str")]
25 pub playcount: u32,
26 pub image: Vec<TrackImage>,
28 #[serde(rename = "@attr")]
30 pub attr: RankAttr,
31}
32
33impl fmt::Display for TopAlbum {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(
36 f,
37 "#{} - {} by {} ({} plays)",
38 self.attr.rank, self.name, self.artist.name, self.playcount
39 )
40 }
41}
42
43impl PartialEq for TopAlbum {
44 fn eq(&self, other: &Self) -> bool {
45 self.playcount == other.playcount
46 }
47}
48
49impl Eq for TopAlbum {}
50
51impl PartialOrd for TopAlbum {
52 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
53 Some(self.cmp(other))
54 }
55}
56
57impl Ord for TopAlbum {
58 fn cmp(&self, other: &Self) -> Ordering {
59 self.playcount.cmp(&other.playcount)
60 }
61}
62
63#[cfg(feature = "sqlite")]
66impl crate::sqlite::SqliteExportable for TopAlbum {
67 fn table_name() -> &'static str {
68 "top_albums"
69 }
70
71 fn create_table_sql() -> &'static str {
72 "CREATE TABLE IF NOT EXISTS top_albums (
73 id INTEGER PRIMARY KEY AUTOINCREMENT,
74 name TEXT NOT NULL,
75 mbid TEXT NOT NULL,
76 url TEXT NOT NULL,
77 artist TEXT NOT NULL,
78 playcount INTEGER NOT NULL,
79 rank INTEGER NOT NULL
80 )"
81 }
82
83 fn insert_sql() -> &'static str {
84 "INSERT INTO top_albums (name, mbid, url, artist, playcount, rank)
85 VALUES (?1, ?2, ?3, ?4, ?5, ?6)"
86 }
87
88 fn bind_and_execute(&self, stmt: &mut rusqlite::Statement<'_>) -> rusqlite::Result<usize> {
89 let rank: u32 = self.attr.rank.parse().unwrap_or_default();
90 stmt.execute(rusqlite::params![
91 self.name,
92 self.mbid,
93 self.url,
94 self.artist.name,
95 self.playcount,
96 rank,
97 ])
98 }
99}
100
101#[cfg(feature = "sqlite")]
104impl crate::sqlite::SqliteLoadable for TopAlbum {
105 fn select_sql() -> &'static str {
106 "SELECT name, mbid, url, artist, playcount, rank
108 FROM top_albums
109 ORDER BY rank ASC"
110 }
111
112 fn from_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<Self> {
113 Ok(Self {
114 name: row.get(0)?,
115 mbid: row.get(1)?,
116 url: row.get(2)?,
117 artist: crate::types::BaseObject {
118 name: row.get(3)?,
119 mbid: String::new(),
120 url: String::new(),
121 },
122 playcount: row.get(4)?,
123 attr: crate::types::RankAttr {
124 rank: row.get::<_, u32>(5)?.to_string(),
125 },
126 image: vec![],
128 })
129 }
130}
131
132#[derive(Serialize, Deserialize, Debug, Clone)]
134#[non_exhaustive]
135pub struct TopAlbums {
136 pub album: Vec<TopAlbum>,
138 #[serde(rename = "@attr")]
140 pub attr: BaseResponse,
141}
142
143#[derive(Serialize, Deserialize, Debug, Clone)]
145#[non_exhaustive]
146pub struct UserTopAlbums {
147 pub topalbums: TopAlbums,
149}