Ensure consistency between in-memory and database state #146

Merged
wojtek merged 8 commits from 120---ensure-consistency-between-in-memory-and-database-state into main 2024-03-01 09:00:53 +01:00
12 changed files with 35 additions and 88 deletions
Showing only changes of commit 05cdd71c2b - Show all commits

View File

@ -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");
}

View File

@ -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)
}
}

View File

@ -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());
}
}

View File

@ -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());

View File

@ -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())));

View File

@ -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);

View File

@ -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"))));

View File

@ -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;

View File

@ -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(),

View File

@ -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 {

View File

@ -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);

View File

@ -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);