use std::cmp::Ordering;
use std::fmt;
use crate::types::{BaseObject, BaseResponse, RankAttr, TrackImage};
use serde::{Deserialize, Serialize};
use crate::types::utils::u32_from_str;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct TopAlbum {
pub name: String,
pub artist: BaseObject,
pub mbid: String,
pub url: String,
#[serde(deserialize_with = "u32_from_str")]
pub playcount: u32,
pub image: Vec<TrackImage>,
#[serde(rename = "@attr")]
pub attr: RankAttr,
}
impl fmt::Display for TopAlbum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"#{} - {} by {} ({} plays)",
self.attr.rank, self.name, self.artist.name, self.playcount
)
}
}
impl PartialEq for TopAlbum {
fn eq(&self, other: &Self) -> bool {
self.playcount == other.playcount
}
}
impl Eq for TopAlbum {}
impl PartialOrd for TopAlbum {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for TopAlbum {
fn cmp(&self, other: &Self) -> Ordering {
self.playcount.cmp(&other.playcount)
}
}
#[cfg(feature = "sqlite")]
impl crate::sqlite::SqliteExportable for TopAlbum {
fn table_name() -> &'static str {
"top_albums"
}
fn create_table_sql() -> &'static str {
"CREATE TABLE IF NOT EXISTS top_albums (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
mbid TEXT NOT NULL,
url TEXT NOT NULL,
artist TEXT NOT NULL,
playcount INTEGER NOT NULL,
rank INTEGER NOT NULL
)"
}
fn insert_sql() -> &'static str {
"INSERT INTO top_albums (name, mbid, url, artist, playcount, rank)
VALUES (?1, ?2, ?3, ?4, ?5, ?6)"
}
fn bind_and_execute(&self, stmt: &mut rusqlite::Statement<'_>) -> rusqlite::Result<usize> {
let rank: u32 = self.attr.rank.parse().unwrap_or_default();
stmt.execute(rusqlite::params![
self.name,
self.mbid,
self.url,
self.artist.name,
self.playcount,
rank,
])
}
}
#[cfg(feature = "sqlite")]
impl crate::sqlite::SqliteLoadable for TopAlbum {
fn select_sql() -> &'static str {
"SELECT name, mbid, url, artist, playcount, rank
FROM top_albums
ORDER BY rank ASC"
}
fn from_row(row: &rusqlite::Row<'_>) -> rusqlite::Result<Self> {
Ok(Self {
name: row.get(0)?,
mbid: row.get(1)?,
url: row.get(2)?,
artist: crate::types::BaseObject {
name: row.get(3)?,
mbid: String::new(),
url: String::new(),
},
playcount: row.get(4)?,
attr: crate::types::RankAttr {
rank: row.get::<_, u32>(5)?.to_string(),
},
image: vec![],
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct TopAlbums {
pub album: Vec<TopAlbum>,
#[serde(rename = "@attr")]
pub attr: BaseResponse,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[non_exhaustive]
pub struct UserTopAlbums {
pub topalbums: TopAlbums,
}