use sled::Tree;
use crate::{
database::{
CompareAndSwapTransaction, CompareAndSwapValue, Createable, DatabaseEntry, DatabaseError,
Patchable, artist_tree, patch_option_replace, patch_replace, serialize_to_ivec,
},
library::{
artist::{Artist, ArtistId},
cover_art::CoverArt,
track::Track,
},
};
impl std::hash::Hash for Artist {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write(self.id.as_bytes());
}
}
impl PartialEq for Artist {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
}
}
impl Eq for Artist {}
impl DatabaseEntry for Artist {
type Id = ArtistId;
const VERSION_NUMBER: u32 = 1;
fn tree() -> Tree {
artist_tree()
}
fn id(&self) -> Self::Id {
self.id
}
}
pub struct PatchArtist {
pub cover_art: Option<CoverArt>,
pub description: Option<String>,
pub name: Option<String>,
}
impl Patchable<PatchArtist> for Artist {
fn patch(&mut self, patch: PatchArtist) {
patch_option_replace(&mut self.cover_art, patch.cover_art);
patch_option_replace(&mut self.description, patch.description);
patch_replace(&mut self.name, patch.name);
}
}
impl From<Artist> for PatchArtist {
fn from(value: Artist) -> Self {
PatchArtist {
cover_art: value.cover_art,
description: value.description,
name: Some(value.name),
}
}
}
impl Patchable<Self> for Artist {
fn patch(&mut self, patch: Self) {
self.patch(PatchArtist::from(patch));
}
}
impl std::ops::Deref for Artist {
type Target = ArtistId;
fn deref(&self) -> &Self::Target {
&self.id
}
}
pub struct ArtistCreateArgs {
pub name: String,
pub tracks: Vec<Track>,
}
impl ArtistCreateArgs {
#[must_use]
pub fn new(name: String, tracks: Vec<Track>) -> Self {
Self { name, tracks }
}
}
impl Createable for Artist {
type CreateArgs = ArtistCreateArgs;
fn create(
cas_tx: &mut CompareAndSwapTransaction,
args: Self::CreateArgs,
) -> Result<Self, DatabaseError> {
let artist = Artist::new(args.name).ok_or(DatabaseError::InvalidInput("Artist name cannot be empty".to_string()))?;
if Artist::db_check(artist.id())? {
return Err(DatabaseError::AlreadyInDatabase);
}
let artists_requests = cas_tx.get_or_new_request(Self::tree());
artists_requests.swaps.insert(
*artist.id().as_bytes(),
CompareAndSwapValue {
old: None,
new: Some(serialize_to_ivec(&artist)),
},
);
let track_requests = cas_tx.get_or_new_request(Track::tree());
args.tracks
.into_iter()
.try_for_each(|mut track| -> Result<(), DatabaseError> {
let old_ivec = serialize_to_ivec(&track);
track.metadata.artists.add_artist(artist.id());
track_requests.swaps.insert(
*track.id().as_bytes(),
CompareAndSwapValue {
old: Some(old_ivec),
new: Some(serialize_to_ivec(&track)),
},
);
Ok(())
})?;
Ok(artist)
}
}