Ensure consistency between in-memory and database state #146
@ -77,10 +77,6 @@ struct ArtistSortValue {
|
||||
|
||||
#[derive(StructOpt, Debug)]
|
||||
enum MusicBrainzCommand {
|
||||
#[structopt(about = "Add a MusicBrainz URL without overwriting the existing value")]
|
||||
Add(MusicBrainzValue),
|
||||
#[structopt(about = "Remove the MusicBrainz URL")]
|
||||
Remove(MusicBrainzValue),
|
||||
#[structopt(about = "Set the MusicBrainz URL overwriting any existing value")]
|
||||
Set(MusicBrainzValue),
|
||||
#[structopt(about = "Clear the MusicBrainz URL)")]
|
||||
@ -129,10 +125,14 @@ impl ArtistCommand {
|
||||
fn handle(self, music_hoard: &mut MH) {
|
||||
match self {
|
||||
ArtistCommand::Add(artist_value) => {
|
||||
music_hoard.add_artist(ArtistId::new(artist_value.artist));
|
||||
music_hoard
|
||||
.add_artist(ArtistId::new(artist_value.artist))
|
||||
.expect("failed to add artist");
|
||||
}
|
||||
ArtistCommand::Remove(artist_value) => {
|
||||
music_hoard.remove_artist(ArtistId::new(artist_value.artist));
|
||||
music_hoard
|
||||
.remove_artist(ArtistId::new(artist_value.artist))
|
||||
.expect("failed to remove artist");
|
||||
}
|
||||
ArtistCommand::Sort(sort_command) => {
|
||||
sort_command.handle(music_hoard);
|
||||
@ -166,18 +166,6 @@ impl SortCommand {
|
||||
impl MusicBrainzCommand {
|
||||
fn handle(self, music_hoard: &mut MH) {
|
||||
match self {
|
||||
MusicBrainzCommand::Add(musicbrainz_value) => music_hoard
|
||||
.add_musicbrainz_url(
|
||||
ArtistId::new(musicbrainz_value.artist),
|
||||
musicbrainz_value.url,
|
||||
)
|
||||
.expect("failed to add MusicBrainz URL"),
|
||||
MusicBrainzCommand::Remove(musicbrainz_value) => music_hoard
|
||||
.remove_musicbrainz_url(
|
||||
ArtistId::new(musicbrainz_value.artist),
|
||||
musicbrainz_value.url,
|
||||
)
|
||||
.expect("failed to remove MusicBrainz URL"),
|
||||
MusicBrainzCommand::Set(musicbrainz_value) => music_hoard
|
||||
.set_musicbrainz_url(
|
||||
ArtistId::new(musicbrainz_value.artist),
|
||||
@ -227,14 +215,9 @@ fn main() {
|
||||
|
||||
let db = JsonDatabase::new(JsonDatabaseFileBackend::new(&opt.database_file_path));
|
||||
|
||||
let mut music_hoard = MusicHoardBuilder::default().set_database(db).build();
|
||||
music_hoard
|
||||
.load_from_database()
|
||||
.expect("failed to load database");
|
||||
|
||||
let mut music_hoard = MusicHoardBuilder::default()
|
||||
.set_database(db)
|
||||
.build()
|
||||
.expect("failed to initialise MusicHoard");
|
||||
opt.category.handle(&mut music_hoard);
|
||||
|
||||
music_hoard
|
||||
.save_to_database()
|
||||
.expect("failed to save database");
|
||||
}
|
||||
|
@ -208,14 +208,14 @@ impl<DB: IDatabase> MusicHoard<NoLibrary, DB> {
|
||||
library_cache: HashMap::new(),
|
||||
pre_commit: vec![],
|
||||
};
|
||||
mh.load_from_database()?;
|
||||
mh.reload_database()?;
|
||||
Ok(mh)
|
||||
}
|
||||
}
|
||||
|
||||
impl<LIB, DB: IDatabase> MusicHoard<LIB, DB> {
|
||||
/// Load the database and merge with the in-memory collection.
|
||||
pub fn load_from_database(&mut self) -> Result<(), Error> {
|
||||
pub fn reload_database(&mut self) -> Result<(), Error> {
|
||||
self.collection = self.database.load()?;
|
||||
Self::sort_albums_and_tracks(self.collection.iter_mut());
|
||||
|
||||
@ -370,7 +370,7 @@ impl<LIB: ILibrary, DB: IDatabase> MusicHoard<LIB, DB> {
|
||||
library_cache: HashMap::new(),
|
||||
pre_commit: vec![],
|
||||
};
|
||||
mh.load_from_database()?;
|
||||
mh.reload_database()?;
|
||||
Ok(mh)
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ mod tests {
|
||||
.set_database(NullDatabase)
|
||||
.build()
|
||||
.unwrap();
|
||||
assert!(mh.load_from_database().is_ok());
|
||||
assert!(mh.reload_database().is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -113,6 +113,6 @@ mod tests {
|
||||
.build()
|
||||
.unwrap();
|
||||
assert!(mh.rescan_library().is_ok());
|
||||
assert!(mh.load_from_database().is_ok());
|
||||
assert!(mh.reload_database().is_ok());
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ struct DbOpt {
|
||||
}
|
||||
|
||||
fn with<LIB: ILibrary, DB: IDatabase>(builder: MusicHoardBuilder<LIB, DB>) {
|
||||
let music_hoard = builder.build();
|
||||
let music_hoard = builder.build().expect("failed to initialise MusicHoard");
|
||||
|
||||
// Initialize the terminal user interface.
|
||||
let backend = CrosstermBackend::new(io::stdout());
|
||||
|
@ -36,15 +36,10 @@ impl<'a, MH: IMusicHoard> From<&'a mut AppMachine<MH, AppBrowse>> for AppPublic<
|
||||
impl<MH: IMusicHoard> IAppInteractBrowse for AppMachine<MH, AppBrowse> {
|
||||
type APP = App<MH>;
|
||||
|
||||
fn save_and_quit(mut self) -> Self::APP {
|
||||
match self.inner.music_hoard.save_to_database() {
|
||||
Ok(_) => {
|
||||
fn quit(mut self) -> Self::APP {
|
||||
self.inner.running = false;
|
||||
self.into()
|
||||
}
|
||||
Err(err) => AppMachine::error(self.inner, err.to_string()).into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn increment_category(mut self) -> Self::APP {
|
||||
self.inner.selection.increment_category();
|
||||
@ -104,37 +99,16 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn save_and_quit() {
|
||||
let mut music_hoard = music_hoard(vec![]);
|
||||
|
||||
music_hoard
|
||||
.expect_save_to_database()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
fn quit() {
|
||||
let music_hoard = music_hoard(vec![]);
|
||||
|
||||
let browse = AppMachine::browse(inner(music_hoard));
|
||||
|
||||
let app = browse.save_and_quit();
|
||||
let app = browse.quit();
|
||||
assert!(!app.is_running());
|
||||
app.unwrap_browse();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn save_and_quit_error() {
|
||||
let mut music_hoard = music_hoard(vec![]);
|
||||
|
||||
music_hoard
|
||||
.expect_save_to_database()
|
||||
.times(1)
|
||||
.return_once(|| Err(musichoard::Error::DatabaseError(String::from("get rekt"))));
|
||||
|
||||
let browse = AppMachine::browse(inner(music_hoard));
|
||||
|
||||
let app = browse.save_and_quit();
|
||||
assert!(app.is_running());
|
||||
app.unwrap_error();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn increment_decrement() {
|
||||
let mut browse = AppMachine::browse(inner(music_hoard(COLLECTION.to_owned())));
|
||||
|
@ -48,7 +48,6 @@ impl<MH: IMusicHoard> App<MH> {
|
||||
}
|
||||
|
||||
fn init(music_hoard: &mut MH) -> Result<(), musichoard::Error> {
|
||||
music_hoard.load_from_database()?;
|
||||
music_hoard.rescan_library()?;
|
||||
Ok(())
|
||||
}
|
||||
@ -196,10 +195,6 @@ mod tests {
|
||||
fn music_hoard_init(collection: Collection) -> MockIMusicHoard {
|
||||
let mut music_hoard = music_hoard(collection);
|
||||
|
||||
music_hoard
|
||||
.expect_load_from_database()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
music_hoard
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
@ -323,9 +318,9 @@ mod tests {
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
|
||||
music_hoard
|
||||
.expect_load_from_database()
|
||||
.expect_rescan_library()
|
||||
.times(1)
|
||||
.return_once(|| Err(musichoard::Error::DatabaseError(String::from("get rekt"))));
|
||||
.return_once(|| Err(musichoard::Error::LibraryError(String::from("get rekt"))));
|
||||
music_hoard.expect_get_collection().return_const(vec![]);
|
||||
|
||||
let app = App::new(music_hoard);
|
||||
|
@ -49,7 +49,7 @@ impl<MH: IMusicHoard> IAppInteractReload for AppMachine<MH, AppReload> {
|
||||
self.inner.music_hoard.get_collection(),
|
||||
&self.inner.selection,
|
||||
);
|
||||
let result = self.inner.music_hoard.load_from_database();
|
||||
let result = self.inner.music_hoard.reload_database();
|
||||
self.refresh(previous, result)
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ mod tests {
|
||||
let mut music_hoard = music_hoard(vec![]);
|
||||
|
||||
music_hoard
|
||||
.expect_load_from_database()
|
||||
.expect_reload_database()
|
||||
.times(1)
|
||||
.return_once(|| Ok(()));
|
||||
|
||||
@ -126,7 +126,7 @@ mod tests {
|
||||
let mut music_hoard = music_hoard(vec![]);
|
||||
|
||||
music_hoard
|
||||
.expect_load_from_database()
|
||||
.expect_reload_database()
|
||||
.times(1)
|
||||
.return_once(|| Err(musichoard::Error::DatabaseError(String::from("get rekt"))));
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub trait IAppInteract {
|
||||
pub trait IAppInteractBrowse {
|
||||
type APP: IAppInteract;
|
||||
|
||||
fn save_and_quit(self) -> Self::APP;
|
||||
fn quit(self) -> Self::APP;
|
||||
|
||||
fn increment_category(self) -> Self::APP;
|
||||
fn decrement_category(self) -> Self::APP;
|
||||
|
@ -83,7 +83,7 @@ impl<APP: IAppInteract> IEventHandlerPrivate<APP> for EventHandler {
|
||||
fn handle_browse_key_event(app: <APP as IAppInteract>::BS, key_event: KeyEvent) -> APP {
|
||||
match key_event.code {
|
||||
// Exit application on `ESC` or `q`.
|
||||
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('Q') => app.save_and_quit(),
|
||||
KeyCode::Esc | KeyCode::Char('q') | KeyCode::Char('Q') => app.quit(),
|
||||
// Category change.
|
||||
KeyCode::Left => app.decrement_category(),
|
||||
KeyCode::Right => app.increment_category(),
|
||||
|
@ -6,8 +6,7 @@ use mockall::automock;
|
||||
#[cfg_attr(test, automock)]
|
||||
pub trait IMusicHoard {
|
||||
fn rescan_library(&mut self) -> Result<(), musichoard::Error>;
|
||||
fn load_from_database(&mut self) -> Result<(), musichoard::Error>;
|
||||
fn save_to_database(&mut self) -> Result<(), musichoard::Error>;
|
||||
fn reload_database(&mut self) -> Result<(), musichoard::Error>;
|
||||
fn get_collection(&self) -> &Collection;
|
||||
}
|
||||
|
||||
@ -17,12 +16,8 @@ impl<LIB: ILibrary, DB: IDatabase> IMusicHoard for MusicHoard<LIB, DB> {
|
||||
MusicHoard::rescan_library(self)
|
||||
}
|
||||
|
||||
fn load_from_database(&mut self) -> Result<(), musichoard::Error> {
|
||||
MusicHoard::load_from_database(self)
|
||||
}
|
||||
|
||||
fn save_to_database(&mut self) -> Result<(), musichoard::Error> {
|
||||
MusicHoard::save_to_database(self)
|
||||
fn reload_database(&mut self) -> Result<(), musichoard::Error> {
|
||||
MusicHoard::reload_database(self)
|
||||
}
|
||||
|
||||
fn get_collection(&self) -> &Collection {
|
||||
|
@ -193,7 +193,7 @@ mod tests {
|
||||
fn music_hoard(collection: Collection) -> MockIMusicHoard {
|
||||
let mut music_hoard = MockIMusicHoard::new();
|
||||
|
||||
music_hoard.expect_load_from_database().returning(|| Ok(()));
|
||||
music_hoard.expect_reload_database().returning(|| Ok(()));
|
||||
music_hoard.expect_rescan_library().returning(|| Ok(()));
|
||||
music_hoard.expect_get_collection().return_const(collection);
|
||||
|
||||
|
@ -32,7 +32,7 @@ fn merge_library_then_database() {
|
||||
let mut music_hoard = MusicHoard::new(library, database).unwrap();
|
||||
|
||||
music_hoard.rescan_library().unwrap();
|
||||
music_hoard.load_from_database().unwrap();
|
||||
music_hoard.reload_database().unwrap();
|
||||
|
||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
||||
}
|
||||
@ -54,7 +54,7 @@ fn merge_database_then_library() {
|
||||
|
||||
let mut music_hoard = MusicHoard::new(library, database).unwrap();
|
||||
|
||||
music_hoard.load_from_database().unwrap();
|
||||
music_hoard.reload_database().unwrap();
|
||||
music_hoard.rescan_library().unwrap();
|
||||
|
||||
assert_eq!(music_hoard.get_collection(), &*COLLECTION);
|
||||
|
Loading…
Reference in New Issue
Block a user