Break down the musichoard files #165

Merged
wojtek merged 9 commits from 164---break-down-the-musichoard-files into main 2024-03-09 22:52:04 +01:00
8 changed files with 212 additions and 142 deletions
Showing only changes of commit 80415c085a - Show all commits

View File

@ -5,7 +5,7 @@ use structopt::{clap::AppSettings, StructOpt};
use musichoard::{ use musichoard::{
collection::{album::AlbumId, artist::ArtistId}, collection::{album::AlbumId, artist::ArtistId},
database::json::{backend::JsonDatabaseFileBackend, JsonDatabase}, database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
MusicHoard, MusicHoardBuilder, NoLibrary, IMusicHoardDatabase, MusicHoard, MusicHoardBuilder, NoLibrary,
}; };
type MH = MusicHoard<JsonDatabase<JsonDatabaseFileBackend>, NoLibrary>; type MH = MusicHoard<JsonDatabase<JsonDatabaseFileBackend>, NoLibrary>;

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::{ use crate::{
core::{ core::{
interface::{database::IDatabase, library::ILibrary}, interface::{database::IDatabase, library::ILibrary},
musichoard::{MusicHoard, NoDatabase, NoLibrary}, musichoard::{database::IMusicHoardDatabase, MusicHoard, NoDatabase, NoLibrary},
}, },
Error, Error,
}; };

View File

@ -9,16 +9,66 @@ use crate::core::{
musichoard::{base::IMusicHoardBasePrivate, Error, MusicHoard, NoDatabase}, musichoard::{base::IMusicHoardBasePrivate, Error, MusicHoard, NoDatabase},
}; };
impl<Library> MusicHoard<NoDatabase, Library> { pub trait IMusicHoardDatabase {
pub fn commit(&mut self) -> Result<(), Error> { fn reload_database(&mut self) -> Result<(), Error>;
self.collection = self.pre_commit.clone();
Ok(()) fn add_artist<IntoId: Into<ArtistId>>(&mut self, artist_id: IntoId) -> Result<(), Error>;
} fn remove_artist<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error>;
fn set_artist_sort<Id: AsRef<ArtistId>, IntoId: Into<ArtistId>>(
&mut self,
artist_id: Id,
artist_sort: IntoId,
) -> Result<(), Error>;
fn clear_artist_sort<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error>;
fn set_artist_musicbrainz<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
url: S,
) -> Result<(), Error>;
fn clear_artist_musicbrainz<Id: AsRef<ArtistId>>(&mut self, artist_id: Id)
-> Result<(), Error>;
fn add_to_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error>;
fn remove_from_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error>;
fn set_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error>;
fn clear_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
) -> Result<(), Error>;
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
seq: u8,
) -> Result<(), Error>;
fn clear_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
) -> Result<(), Error>;
} }
impl<Database: IDatabase, Library> MusicHoard<Database, Library> { impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database, Library> {
/// Load the database and merge with the in-memory collection. fn reload_database(&mut self) -> Result<(), Error> {
pub fn reload_database(&mut self) -> Result<(), Error> {
self.database_cache = self.database.load()?; self.database_cache = self.database.load()?;
Self::sort_albums_and_tracks(self.database_cache.iter_mut()); Self::sort_albums_and_tracks(self.database_cache.iter_mut());
@ -28,7 +78,146 @@ impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
Ok(()) Ok(())
} }
pub fn commit(&mut self) -> Result<(), Error> { fn add_artist<IntoId: Into<ArtistId>>(&mut self, artist_id: IntoId) -> Result<(), Error> {
let artist_id: ArtistId = artist_id.into();
self.update_collection(|collection| {
if Self::get_artist(collection, &artist_id).is_none() {
collection.push(Artist::new(artist_id));
Self::sort_artists(collection);
}
})
}
fn remove_artist<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error> {
self.update_collection(|collection| {
let index_opt = collection.iter().position(|a| &a.id == artist_id.as_ref());
if let Some(index) = index_opt {
collection.remove(index);
}
})
}
fn set_artist_sort<Id: AsRef<ArtistId>, IntoId: Into<ArtistId>>(
&mut self,
artist_id: Id,
artist_sort: IntoId,
) -> Result<(), Error> {
self.update_artist_and(
artist_id.as_ref(),
|artist| artist.set_sort_key(artist_sort),
|collection| Self::sort_artists(collection),
)
}
fn clear_artist_sort<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error> {
self.update_artist_and(
artist_id.as_ref(),
|artist| artist.clear_sort_key(),
|collection| Self::sort_artists(collection),
)
}
fn set_artist_musicbrainz<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
url: S,
) -> Result<(), Error> {
let mb = MusicBrainzUrl::artist_from_str(url)?;
self.update_artist(artist_id.as_ref(), |artist| artist.set_musicbrainz_url(mb))
}
fn clear_artist_musicbrainz<Id: AsRef<ArtistId>>(
&mut self,
artist_id: Id,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| artist.clear_musicbrainz_url())
}
fn add_to_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.add_to_property(property, values)
})
}
fn remove_from_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.remove_from_property(property, values)
})
}
fn set_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.set_property(property, values)
})
}
fn clear_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| artist.clear_property(property))
}
fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
seq: u8,
) -> Result<(), Error> {
self.update_album_and(
artist_id.as_ref(),
album_id.as_ref(),
|album| album.set_seq(AlbumSeq(seq)),
|artist| artist.albums.sort_unstable(),
|_| {},
)
}
fn clear_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
) -> Result<(), Error> {
self.update_album_and(
artist_id.as_ref(),
album_id.as_ref(),
|album| album.clear_seq(),
|artist| artist.albums.sort_unstable(),
|_| {},
)
}
}
pub trait IMusicHoardDatabasePrivate {
fn commit(&mut self) -> Result<(), Error>;
}
impl<Library> IMusicHoardDatabasePrivate for MusicHoard<NoDatabase, Library> {
fn commit(&mut self) -> Result<(), Error> {
self.collection = self.pre_commit.clone();
Ok(())
}
}
impl<Database: IDatabase, Library> IMusicHoardDatabasePrivate for MusicHoard<Database, Library> {
fn commit(&mut self) -> Result<(), Error> {
if self.collection != self.pre_commit { if self.collection != self.pre_commit {
if let Err(err) = self.database.save(&self.pre_commit) { if let Err(err) = self.database.save(&self.pre_commit) {
self.pre_commit = self.collection.clone(); self.pre_commit = self.collection.clone();
@ -38,7 +227,9 @@ impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
} }
Ok(()) Ok(())
} }
}
impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
fn update_collection<FnColl>(&mut self, fn_coll: FnColl) -> Result<(), Error> fn update_collection<FnColl>(&mut self, fn_coll: FnColl) -> Result<(), Error>
where where
FnColl: FnOnce(&mut Collection), FnColl: FnOnce(&mut Collection),
@ -92,132 +283,6 @@ impl<Database: IDatabase, Library> MusicHoard<Database, Library> {
fn_artist(artist); fn_artist(artist);
self.update_collection(fn_coll) self.update_collection(fn_coll)
} }
pub fn add_artist<IntoId: Into<ArtistId>>(&mut self, artist_id: IntoId) -> Result<(), Error> {
let artist_id: ArtistId = artist_id.into();
self.update_collection(|collection| {
if Self::get_artist(collection, &artist_id).is_none() {
collection.push(Artist::new(artist_id));
Self::sort_artists(collection);
}
})
}
pub fn remove_artist<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error> {
self.update_collection(|collection| {
let index_opt = collection.iter().position(|a| &a.id == artist_id.as_ref());
if let Some(index) = index_opt {
collection.remove(index);
}
})
}
pub fn set_artist_sort<Id: AsRef<ArtistId>, IntoId: Into<ArtistId>>(
&mut self,
artist_id: Id,
artist_sort: IntoId,
) -> Result<(), Error> {
self.update_artist_and(
artist_id.as_ref(),
|artist| artist.set_sort_key(artist_sort),
|collection| Self::sort_artists(collection),
)
}
pub fn clear_artist_sort<Id: AsRef<ArtistId>>(&mut self, artist_id: Id) -> Result<(), Error> {
self.update_artist_and(
artist_id.as_ref(),
|artist| artist.clear_sort_key(),
|collection| Self::sort_artists(collection),
)
}
pub fn set_artist_musicbrainz<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
url: S,
) -> Result<(), Error> {
let mb = MusicBrainzUrl::artist_from_str(url)?;
self.update_artist(artist_id.as_ref(), |artist| artist.set_musicbrainz_url(mb))
}
pub fn clear_artist_musicbrainz<Id: AsRef<ArtistId>>(
&mut self,
artist_id: Id,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| artist.clear_musicbrainz_url())
}
pub fn add_to_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.add_to_property(property, values)
})
}
pub fn remove_from_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.remove_from_property(property, values)
})
}
pub fn set_artist_property<Id: AsRef<ArtistId>, S: AsRef<str> + Into<String>>(
&mut self,
artist_id: Id,
property: S,
values: Vec<S>,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| {
artist.set_property(property, values)
})
}
pub fn clear_artist_property<Id: AsRef<ArtistId>, S: AsRef<str>>(
&mut self,
artist_id: Id,
property: S,
) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| artist.clear_property(property))
}
pub fn set_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
seq: u8,
) -> Result<(), Error> {
self.update_album_and(
artist_id.as_ref(),
album_id.as_ref(),
|album| album.set_seq(AlbumSeq(seq)),
|artist| artist.albums.sort_unstable(),
|_| {},
)
}
pub fn clear_album_seq<ArtistIdRef: AsRef<ArtistId>, AlbumIdRef: AsRef<AlbumId>>(
&mut self,
artist_id: ArtistIdRef,
album_id: AlbumIdRef,
) -> Result<(), Error> {
self.update_album_and(
artist_id.as_ref(),
album_id.as_ref(),
|album| album.clear_seq(),
|artist| artist.albums.sort_unstable(),
|_| {},
)
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -11,7 +11,10 @@ use crate::core::{
database::IDatabase, database::IDatabase,
library::{ILibrary, Item, Query}, library::{ILibrary, Item, Query},
}, },
musichoard::{base::IMusicHoardBasePrivate, Error, MusicHoard, NoDatabase}, musichoard::{
base::IMusicHoardBasePrivate, database::IMusicHoardDatabasePrivate, Error, MusicHoard,
NoDatabase,
},
}; };
impl<Library: ILibrary> MusicHoard<NoDatabase, Library> { impl<Library: ILibrary> MusicHoard<NoDatabase, Library> {

View File

@ -7,6 +7,7 @@ mod library;
pub mod builder; pub mod builder;
pub use base::IMusicHoardBase; pub use base::IMusicHoardBase;
pub use database::IMusicHoardDatabase;
use std::{ use std::{
collections::HashMap, collections::HashMap,

View File

@ -8,7 +8,8 @@ pub use core::collection;
pub use core::interface; pub use core::interface;
pub use core::musichoard::{ pub use core::musichoard::{
builder::MusicHoardBuilder, Error, IMusicHoardBase, MusicHoard, NoDatabase, NoLibrary, builder::MusicHoardBuilder, Error, IMusicHoardBase, IMusicHoardDatabase, MusicHoard,
NoDatabase, NoLibrary,
}; };
#[cfg(test)] #[cfg(test)]

View File

@ -1,6 +1,6 @@
use musichoard::{ use musichoard::{
collection::Collection, interface::database::IDatabase, interface::library::ILibrary, collection::Collection, interface::database::IDatabase, interface::library::ILibrary,
IMusicHoardBase, MusicHoard, IMusicHoardBase, IMusicHoardDatabase, MusicHoard,
}; };
#[cfg(test)] #[cfg(test)]
@ -20,7 +20,7 @@ impl<Database: IDatabase, Library: ILibrary> IMusicHoard for MusicHoard<Database
} }
fn reload_database(&mut self) -> Result<(), musichoard::Error> { fn reload_database(&mut self) -> Result<(), musichoard::Error> {
Self::reload_database(self) <Self as IMusicHoardDatabase>::reload_database(self)
} }
fn get_collection(&self) -> &Collection { fn get_collection(&self) -> &Collection {

View File

@ -9,7 +9,7 @@ mod testlib;
use musichoard::{ use musichoard::{
database::json::{backend::JsonDatabaseFileBackend, JsonDatabase}, database::json::{backend::JsonDatabaseFileBackend, JsonDatabase},
library::beets::{executor::BeetsLibraryProcessExecutor, BeetsLibrary}, library::beets::{executor::BeetsLibraryProcessExecutor, BeetsLibrary},
IMusicHoardBase, MusicHoard, IMusicHoardBase, IMusicHoardDatabase, MusicHoard,
}; };
use crate::testlib::COLLECTION; use crate::testlib::COLLECTION;