moosicbox_menu 0.1.0

MoosicBox menu package
Documentation
use moosicbox_core::sqlite::{
    db::DbError,
    models::{AlbumSource, ArtistSort},
};
use moosicbox_database::profiles::LibraryDatabase;
use moosicbox_library::{db::get_artists, models::LibraryArtist};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArtistsRequest {
    pub sources: Option<Vec<AlbumSource>>,
    pub sort: Option<ArtistSort>,
    pub filters: ArtistFilters,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ArtistFilters {
    pub name: Option<String>,
    pub search: Option<String>,
}

pub fn filter_artists(artists: Vec<LibraryArtist>, request: &ArtistsRequest) -> Vec<LibraryArtist> {
    artists
        .into_iter()
        .filter(|artist| {
            !request
                .filters
                .name
                .as_ref()
                .is_some_and(|s| !artist.title.to_lowercase().contains(s))
        })
        .filter(|artist| {
            !request.filters.search.as_ref().is_some_and(|s| {
                !(artist.title.to_lowercase().contains(s)
                    || artist.title.to_lowercase().contains(s))
            })
        })
        .collect()
}

pub fn sort_artists(
    mut artists: Vec<LibraryArtist>,
    request: &ArtistsRequest,
) -> Vec<LibraryArtist> {
    match request.sort {
        Some(ArtistSort::NameAsc) => artists.sort_by(|a, b| a.title.cmp(&b.title)),
        Some(ArtistSort::NameDesc) => artists.sort_by(|a, b| b.title.cmp(&a.title)),
        _ => (),
    }
    match request.sort {
        Some(ArtistSort::NameAsc) | None => {
            artists.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase()))
        }
        Some(ArtistSort::NameDesc) => {
            artists.sort_by(|a, b| b.title.to_lowercase().cmp(&a.title.to_lowercase()))
        }
    }

    artists
}

#[derive(Debug, Error)]
pub enum GetArtistsError {
    #[error(transparent)]
    DbError(#[from] DbError),
}

pub async fn get_all_artists(
    db: &LibraryDatabase,
    request: &ArtistsRequest,
) -> Result<Vec<LibraryArtist>, GetArtistsError> {
    let artists = get_artists(db).await?;

    Ok(sort_artists(filter_artists(artists, request), request))
}