From bff68a84ee399767a6d84df1134b3f4d21615aad Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Fri, 1 Mar 2024 08:39:42 +0100 Subject: [PATCH] Ensure consistency on library rescan --- src/core/musichoard/musichoard.rs | 81 +++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/src/core/musichoard/musichoard.rs b/src/core/musichoard/musichoard.rs index 2ce1651..38099ed 100644 --- a/src/core/musichoard/musichoard.rs +++ b/src/core/musichoard/musichoard.rs @@ -17,10 +17,11 @@ use crate::core::{ #[derive(Debug)] pub struct MusicHoard { collection: Collection, + pre_commit: Collection, library: LIB, database: DB, library_cache: HashMap, - pre_commit: Collection, + database_cache: Collection, } /// Phantom type for when a library implementation is not needed. @@ -43,10 +44,11 @@ impl MusicHoard { pub fn empty() -> Self { MusicHoard { collection: vec![], + pre_commit: vec![], library: NoLibrary, database: NoDatabase, library_cache: HashMap::new(), - pre_commit: vec![], + database_cache: vec![], } } } @@ -72,14 +74,14 @@ impl MusicHoard { fn merge_collections(&mut self) { let mut primary = self.library_cache.clone(); - for secondary_artist in self.collection.drain(..) { + for secondary_artist in self.database_cache.iter().cloned() { if let Some(ref mut primary_artist) = primary.get_mut(&secondary_artist.id) { primary_artist.merge_in_place(secondary_artist); } else { primary.insert(secondary_artist.id.clone(), secondary_artist); } } - self.collection.extend(primary.into_values()); + self.collection = primary.into_values().collect(); Self::sort_artists(&mut self.collection); } @@ -178,10 +180,11 @@ impl MusicHoard { pub fn library(library: LIB) -> Self { MusicHoard { collection: vec![], + pre_commit: vec![], library, database: NoDatabase, library_cache: HashMap::new(), - pre_commit: vec![], + database_cache: vec![], } } } @@ -203,10 +206,11 @@ impl MusicHoard { pub fn database(database: DB) -> Result { let mut mh = MusicHoard { collection: vec![], + pre_commit: vec![], library: NoLibrary, database, library_cache: HashMap::new(), - pre_commit: vec![], + database_cache: vec![], }; mh.reload_database()?; Ok(mh) @@ -216,8 +220,8 @@ impl MusicHoard { impl MusicHoard { /// Load the database and merge with the in-memory collection. pub fn reload_database(&mut self) -> Result<(), Error> { - self.collection = self.database.load()?; - Self::sort_albums_and_tracks(self.collection.iter_mut()); + self.database_cache = self.database.load()?; + Self::sort_albums_and_tracks(self.database_cache.iter_mut()); self.merge_collections(); self.pre_commit = self.collection.clone(); @@ -367,10 +371,11 @@ impl MusicHoard { pub fn new(library: LIB, database: DB) -> Result { let mut mh = MusicHoard { collection: vec![], + pre_commit: vec![], library, database, library_cache: HashMap::new(), - pre_commit: vec![], + database_cache: vec![], }; mh.reload_database()?; Ok(mh) @@ -657,12 +662,12 @@ mod tests { expected.sort_unstable(); let mut mh = MusicHoard { - collection: right.clone(), library_cache: left .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: right.clone(), ..Default::default() }; @@ -671,12 +676,12 @@ mod tests { // The merge is completely non-overlapping so it should be commutative. let mut mh = MusicHoard { - collection: left.clone(), library_cache: right .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: left.clone(), ..Default::default() }; @@ -695,12 +700,12 @@ mod tests { expected.sort_unstable(); let mut mh = MusicHoard { - collection: right.clone(), library_cache: left .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: right.clone(), ..Default::default() }; @@ -709,12 +714,12 @@ mod tests { // The merge does not overwrite any data so it should be commutative. let mut mh = MusicHoard { - collection: left.clone(), library_cache: right .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: left.clone(), ..Default::default() }; @@ -746,12 +751,12 @@ mod tests { expected.rotate_right(1); let mut mh = MusicHoard { - collection: right.clone(), library_cache: left .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: right.clone(), ..Default::default() }; @@ -760,12 +765,12 @@ mod tests { // The merge overwrites the sort data, but no data is erased so it should be commutative. let mut mh = MusicHoard { - collection: left.clone(), library_cache: right .clone() .into_iter() .map(|a| (a.id.clone(), a)) .collect(), + database_cache: left.clone(), ..Default::default() }; @@ -792,6 +797,52 @@ mod tests { assert_eq!(music_hoard.get_collection(), &*LIBRARY_COLLECTION); } + #[test] + fn rescan_library_changed() { + let mut library = MockILibrary::new(); + let mut seq = Sequence::new(); + + let library_input = Query::new(); + let library_result = Ok(LIBRARY_ITEMS.to_owned()); + + library + .expect_list() + .with(predicate::eq(library_input)) + .times(1) + .in_sequence(&mut seq) + .return_once(|_| library_result); + + let library_input = Query::new(); + let library_result = Ok(LIBRARY_ITEMS + .iter() + .filter(|item| item.album_title != "album_title a.a") + .cloned() + .collect()); + + library + .expect_list() + .with(predicate::eq(library_input)) + .times(1) + .in_sequence(&mut seq) + .return_once(|_| library_result); + + let mut music_hoard = MusicHoard::library(library); + + music_hoard.rescan_library().unwrap(); + assert!(music_hoard.get_collection()[0] + .albums + .iter() + .find(|album| album.id.title == "album_title a.a") + .is_some()); + + music_hoard.rescan_library().unwrap(); + assert!(music_hoard.get_collection()[0] + .albums + .iter() + .find(|album| album.id.title == "album_title a.a") + .is_none()); + } + #[test] fn rescan_library_unordered() { let mut library = MockILibrary::new();