Add info as substruct of meta

This commit is contained in:
Wojciech Kozlowski 2024-09-28 10:46:29 +02:00
parent 50779e2a32
commit 32b09b2f52
17 changed files with 247 additions and 233 deletions

View File

@ -171,10 +171,7 @@ impl SortCommand {
fn handle(self, music_hoard: &mut MH, artist_name: &str) { fn handle(self, music_hoard: &mut MH, artist_name: &str) {
match self { match self {
SortCommand::Set(artist_sort_value) => music_hoard SortCommand::Set(artist_sort_value) => music_hoard
.set_artist_sort( .set_artist_sort(ArtistId::new(artist_name), artist_sort_value.sort)
ArtistId::new(artist_name),
String::from(artist_sort_value.sort),
)
.expect("faild to set artist sort name"), .expect("faild to set artist sort name"),
SortCommand::Clear => music_hoard SortCommand::Clear => music_hoard
.clear_artist_sort(ArtistId::new(artist_name)) .clear_artist_sort(ArtistId::new(artist_name))

View File

@ -22,6 +22,12 @@ pub struct Artist {
pub struct ArtistMeta { pub struct ArtistMeta {
pub id: ArtistId, pub id: ArtistId,
pub sort: Option<String>, pub sort: Option<String>,
pub info: ArtistInfo,
}
/// Artist non-identifier metadata.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ArtistInfo {
pub musicbrainz: MbRefOption<MbArtistRef>, pub musicbrainz: MbRefOption<MbArtistRef>,
pub properties: HashMap<String, Vec<String>>, pub properties: HashMap<String, Vec<String>>,
} }
@ -75,8 +81,10 @@ impl ArtistMeta {
ArtistMeta { ArtistMeta {
id: id.into(), id: id.into(),
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
},
} }
} }
@ -91,7 +99,9 @@ impl ArtistMeta {
pub fn clear_sort_key(&mut self) { pub fn clear_sort_key(&mut self) {
self.sort.take(); self.sort.take();
} }
}
impl ArtistInfo {
pub fn set_musicbrainz_ref(&mut self, mbref: MbRefOption<MbArtistRef>) { pub fn set_musicbrainz_ref(&mut self, mbref: MbRefOption<MbArtistRef>) {
self.musicbrainz = mbref self.musicbrainz = mbref
} }
@ -162,6 +172,12 @@ impl Merge for ArtistMeta {
assert_eq!(self.id, other.id); assert_eq!(self.id, other.id);
self.sort = self.sort.take().or(other.sort); self.sort = self.sort.take().or(other.sort);
self.info.merge_in_place(other.info);
}
}
impl Merge for ArtistInfo {
fn merge_in_place(&mut self, other: Self) {
self.musicbrainz = self.musicbrainz.take().or(other.musicbrainz); self.musicbrainz = self.musicbrainz.take().or(other.musicbrainz);
self.properties.merge_in_place(other.properties); self.properties.merge_in_place(other.properties);
} }
@ -256,160 +272,132 @@ mod tests {
let mut artist = Artist::new(ArtistId::new("an artist")); let mut artist = Artist::new(ArtistId::new("an artist"));
let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None; let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None;
assert_eq!(artist.meta.musicbrainz, expected); assert_eq!(artist.meta.info.musicbrainz, expected);
// Setting a URL on an artist. // Setting a URL on an artist.
artist.meta.set_musicbrainz_ref(MbRefOption::Some( artist.meta.info.set_musicbrainz_ref(MbRefOption::Some(
MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(), MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(),
)); ));
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap()); expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ).unwrap());
assert_eq!(artist.meta.musicbrainz, expected); assert_eq!(artist.meta.info.musicbrainz, expected);
artist.meta.set_musicbrainz_ref(MbRefOption::Some( artist.meta.info.set_musicbrainz_ref(MbRefOption::Some(
MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(), MbArtistRef::from_url_str(MUSICBRAINZ).unwrap(),
)); ));
assert_eq!(artist.meta.musicbrainz, expected); assert_eq!(artist.meta.info.musicbrainz, expected);
artist.meta.set_musicbrainz_ref(MbRefOption::Some( artist.meta.info.set_musicbrainz_ref(MbRefOption::Some(
MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap(), MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap(),
)); ));
expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap()); expected.replace(MbArtistRef::from_url_str(MUSICBRAINZ_2).unwrap());
assert_eq!(artist.meta.musicbrainz, expected); assert_eq!(artist.meta.info.musicbrainz, expected);
// Clearing URLs. // Clearing URLs.
artist.meta.clear_musicbrainz_ref(); artist.meta.info.clear_musicbrainz_ref();
expected.take(); expected.take();
assert_eq!(artist.meta.musicbrainz, expected); assert_eq!(artist.meta.info.musicbrainz, expected);
} }
#[test] #[test]
fn add_to_remove_from_property() { fn add_to_remove_from_property() {
let mut artist = Artist::new(ArtistId::new("an artist")); let mut artist = Artist::new(ArtistId::new("an artist"));
let info = &mut artist.meta.info;
let mut expected: Vec<String> = vec![]; let mut expected: Vec<String> = vec![];
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
// Adding a single URL. // Adding a single URL.
artist info.add_to_property("MusicButler", vec![MUSICBUTLER]);
.meta
.add_to_property("MusicButler", vec![MUSICBUTLER]);
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
// Adding a URL that already exists is ok, but does not do anything. // Adding a URL that already exists is ok, but does not do anything.
artist info.add_to_property("MusicButler", vec![MUSICBUTLER]);
.meta assert_eq!(info.properties.get("MusicButler"), Some(&expected));
.add_to_property("MusicButler", vec![MUSICBUTLER]);
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected));
// Adding another single URL. // Adding another single URL.
artist info.add_to_property("MusicButler", vec![MUSICBUTLER_2]);
.meta
.add_to_property("MusicButler", vec![MUSICBUTLER_2]);
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
artist info.add_to_property("MusicButler", vec![MUSICBUTLER_2]);
.meta assert_eq!(info.properties.get("MusicButler"), Some(&expected));
.add_to_property("MusicButler", vec![MUSICBUTLER_2]);
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected));
// Removing a URL. // Removing a URL.
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER]);
.meta
.remove_from_property("MusicButler", vec![MUSICBUTLER]);
expected.retain(|url| url != MUSICBUTLER); expected.retain(|url| url != MUSICBUTLER);
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
// Removing URls that do not exist is okay, they will be ignored. // Removing URls that do not exist is okay, they will be ignored.
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER]);
.meta assert_eq!(info.properties.get("MusicButler"), Some(&expected));
.remove_from_property("MusicButler", vec![MUSICBUTLER]);
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected));
// Removing a URL. // Removing a URL.
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER_2]);
.meta
.remove_from_property("MusicButler", vec![MUSICBUTLER_2]);
expected.retain(|url| url.as_str() != MUSICBUTLER_2); expected.retain(|url| url.as_str() != MUSICBUTLER_2);
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER_2]);
.meta assert!(info.properties.is_empty());
.remove_from_property("MusicButler", vec![MUSICBUTLER_2]);
assert!(artist.meta.properties.is_empty());
// Adding URLs if some exist is okay, they will be ignored. // Adding URLs if some exist is okay, they will be ignored.
artist info.add_to_property("MusicButler", vec![MUSICBUTLER]);
.meta
.add_to_property("MusicButler", vec![MUSICBUTLER]);
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
artist info.add_to_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
.meta
.add_to_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
// Removing URLs if some do not exist is okay, they will be ignored. // Removing URLs if some do not exist is okay, they will be ignored.
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER]);
.meta
.remove_from_property("MusicButler", vec![MUSICBUTLER]);
expected.retain(|url| url.as_str() != MUSICBUTLER); expected.retain(|url| url.as_str() != MUSICBUTLER);
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
.meta
.remove_from_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
expected.retain(|url| url.as_str() != MUSICBUTLER_2); expected.retain(|url| url.as_str() != MUSICBUTLER_2);
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
// Adding mutliple URLs without clashes. // Adding mutliple URLs without clashes.
artist info.add_to_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
.meta
.add_to_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
// Removing multiple URLs without clashes. // Removing multiple URLs without clashes.
artist info.remove_from_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
.meta
.remove_from_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
expected.clear(); expected.clear();
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
} }
#[test] #[test]
fn set_clear_musicbutler_urls() { fn set_clear_musicbutler_urls() {
let mut artist = Artist::new(ArtistId::new("an artist")); let mut artist = Artist::new(ArtistId::new("an artist"));
let info = &mut artist.meta.info;
let mut expected: Vec<String> = vec![]; let mut expected: Vec<String> = vec![];
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
// Set URLs. // Set URLs.
artist.meta.set_property("MusicButler", vec![MUSICBUTLER]); info.set_property("MusicButler", vec![MUSICBUTLER]);
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
artist.meta.set_property("MusicButler", vec![MUSICBUTLER_2]); info.set_property("MusicButler", vec![MUSICBUTLER_2]);
expected.clear(); expected.clear();
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
artist info.set_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
.meta
.set_property("MusicButler", vec![MUSICBUTLER, MUSICBUTLER_2]);
expected.clear(); expected.clear();
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!(artist.meta.properties.get("MusicButler"), Some(&expected)); assert_eq!(info.properties.get("MusicButler"), Some(&expected));
// Clear URLs. // Clear URLs.
artist.meta.clear_property("MusicButler"); info.clear_property("MusicButler");
expected.clear(); expected.clear();
assert!(artist.meta.properties.is_empty()); assert!(info.properties.is_empty());
} }
#[test] #[test]
@ -417,14 +405,15 @@ mod tests {
let left = FULL_COLLECTION[0].to_owned(); let left = FULL_COLLECTION[0].to_owned();
let mut right = FULL_COLLECTION[1].to_owned(); let mut right = FULL_COLLECTION[1].to_owned();
right.meta.id = left.meta.id.clone(); right.meta.id = left.meta.id.clone();
right.meta.musicbrainz = MbRefOption::None; right.meta.info.musicbrainz = MbRefOption::None;
right.meta.properties = HashMap::new(); right.meta.info.properties = HashMap::new();
let mut expected = left.clone(); let mut expected = left.clone();
expected.meta.properties = expected expected.meta.info.properties = expected
.meta .meta
.info
.properties .properties
.merge(right.clone().meta.properties); .merge(right.clone().meta.info.properties);
expected.albums.append(&mut right.albums.clone()); expected.albums.append(&mut right.albums.clone());
expected.albums.sort_unstable(); expected.albums.sort_unstable();
@ -445,10 +434,11 @@ mod tests {
left.albums.sort_unstable(); left.albums.sort_unstable();
let mut expected = left.clone(); let mut expected = left.clone();
expected.meta.properties = expected expected.meta.info.properties = expected
.meta .meta
.info
.properties .properties
.merge(right.clone().meta.properties); .merge(right.clone().meta.info.properties);
expected.albums.append(&mut right.albums.clone()); expected.albums.append(&mut right.albums.clone());
expected.albums.sort_unstable(); expected.albums.sort_unstable();
expected.albums.dedup(); expected.albums.dedup();

View File

@ -165,7 +165,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
mbid: MbRefOption<MbArtistRef>, mbid: MbRefOption<MbArtistRef>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.set_musicbrainz_ref(mbid) artist.meta.info.set_musicbrainz_ref(mbid)
}) })
} }
@ -174,7 +174,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
artist_id: Id, artist_id: Id,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.clear_musicbrainz_ref() artist.meta.info.clear_musicbrainz_ref()
}) })
} }
@ -185,7 +185,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
values: Vec<S>, values: Vec<S>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.add_to_property(property, values) artist.meta.info.add_to_property(property, values)
}) })
} }
@ -196,7 +196,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
values: Vec<S>, values: Vec<S>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.remove_from_property(property, values) artist.meta.info.remove_from_property(property, values)
}) })
} }
@ -207,7 +207,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
values: Vec<S>, values: Vec<S>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.set_property(property, values) artist.meta.info.set_property(property, values)
}) })
} }
@ -217,7 +217,7 @@ impl<Database: IDatabase, Library> IMusicHoardDatabase for MusicHoard<Database,
property: S, property: S,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.update_artist(artist_id.as_ref(), |artist| { self.update_artist(artist_id.as_ref(), |artist| {
artist.meta.clear_property(property) artist.meta.info.clear_property(property)
}) })
} }
@ -533,7 +533,7 @@ mod tests {
assert!(music_hoard.add_artist(artist_id.clone()).is_ok()); assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None; let mut expected: MbRefOption<MbArtistRef> = MbRefOption::None;
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected); assert_eq!(music_hoard.collection[0].meta.info.musicbrainz, expected);
let mbref = MbRefOption::Some(MbArtistRef::from_uuid_str(MBID).unwrap()); let mbref = MbRefOption::Some(MbArtistRef::from_uuid_str(MBID).unwrap());
@ -541,23 +541,23 @@ mod tests {
assert!(music_hoard assert!(music_hoard
.set_artist_musicbrainz(&artist_id_2, mbref.clone()) .set_artist_musicbrainz(&artist_id_2, mbref.clone())
.is_err()); .is_err());
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected); assert_eq!(music_hoard.collection[0].meta.info.musicbrainz, expected);
// Setting a URL on an artist. // Setting a URL on an artist.
assert!(music_hoard assert!(music_hoard
.set_artist_musicbrainz(&artist_id, mbref.clone()) .set_artist_musicbrainz(&artist_id, mbref.clone())
.is_ok()); .is_ok());
expected.replace(MbArtistRef::from_uuid_str(MBID).unwrap()); expected.replace(MbArtistRef::from_uuid_str(MBID).unwrap());
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected); assert_eq!(music_hoard.collection[0].meta.info.musicbrainz, expected);
// Clearing URLs on an artist that does not exist is an error. // Clearing URLs on an artist that does not exist is an error.
assert!(music_hoard.clear_artist_musicbrainz(&artist_id_2).is_err()); assert!(music_hoard.clear_artist_musicbrainz(&artist_id_2).is_err());
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected); assert_eq!(music_hoard.collection[0].meta.info.musicbrainz, expected);
// Clearing URLs. // Clearing URLs.
assert!(music_hoard.clear_artist_musicbrainz(&artist_id).is_ok()); assert!(music_hoard.clear_artist_musicbrainz(&artist_id).is_ok());
expected.take(); expected.take();
assert_eq!(music_hoard.collection[0].meta.musicbrainz, expected); assert_eq!(music_hoard.collection[0].meta.info.musicbrainz, expected);
} }
#[test] #[test]
@ -573,13 +573,13 @@ mod tests {
assert!(music_hoard.add_artist(artist_id.clone()).is_ok()); assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
let mut expected: Vec<String> = vec![]; let mut expected: Vec<String> = vec![];
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
// Adding URLs to an artist not in the collection is an error. // Adding URLs to an artist not in the collection is an error.
assert!(music_hoard assert!(music_hoard
.add_to_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER]) .add_to_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER])
.is_err()); .is_err());
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
// Adding mutliple URLs without clashes. // Adding mutliple URLs without clashes.
assert!(music_hoard assert!(music_hoard
@ -587,19 +587,15 @@ mod tests {
.is_ok()); .is_ok());
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!( let info = &music_hoard.collection[0].meta.info;
music_hoard.collection[0].meta.properties.get("MusicButler"), assert_eq!(info.properties.get("MusicButler"), Some(&expected));
Some(&expected)
);
// Removing URLs from an artist not in the collection is an error. // Removing URLs from an artist not in the collection is an error.
assert!(music_hoard assert!(music_hoard
.remove_from_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER]) .remove_from_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER])
.is_err()); .is_err());
assert_eq!( let info = &music_hoard.collection[0].meta.info;
music_hoard.collection[0].meta.properties.get("MusicButler"), assert_eq!(info.properties.get("MusicButler"), Some(&expected));
Some(&expected)
);
// Removing multiple URLs without clashes. // Removing multiple URLs without clashes.
assert!(music_hoard assert!(music_hoard
@ -610,7 +606,7 @@ mod tests {
) )
.is_ok()); .is_ok());
expected.clear(); expected.clear();
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
} }
#[test] #[test]
@ -626,13 +622,13 @@ mod tests {
assert!(music_hoard.add_artist(artist_id.clone()).is_ok()); assert!(music_hoard.add_artist(artist_id.clone()).is_ok());
let mut expected: Vec<String> = vec![]; let mut expected: Vec<String> = vec![];
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
// Seting URL on an artist not in the collection is an error. // Seting URL on an artist not in the collection is an error.
assert!(music_hoard assert!(music_hoard
.set_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER]) .set_artist_property(&artist_id_2, "MusicButler", vec![MUSICBUTLER])
.is_err()); .is_err());
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
// Set URLs. // Set URLs.
assert!(music_hoard assert!(music_hoard
@ -641,10 +637,8 @@ mod tests {
expected.clear(); expected.clear();
expected.push(MUSICBUTLER.to_owned()); expected.push(MUSICBUTLER.to_owned());
expected.push(MUSICBUTLER_2.to_owned()); expected.push(MUSICBUTLER_2.to_owned());
assert_eq!( let info = &music_hoard.collection[0].meta.info;
music_hoard.collection[0].meta.properties.get("MusicButler"), assert_eq!(info.properties.get("MusicButler"), Some(&expected));
Some(&expected)
);
// Clearing URLs on an artist that does not exist is an error. // Clearing URLs on an artist that does not exist is an error.
assert!(music_hoard assert!(music_hoard
@ -656,7 +650,7 @@ mod tests {
.clear_artist_property(&artist_id, "MusicButler") .clear_artist_property(&artist_id, "MusicButler")
.is_ok()); .is_ok());
expected.clear(); expected.clear();
assert!(music_hoard.collection[0].meta.properties.is_empty()); assert!(music_hoard.collection[0].meta.info.properties.is_empty());
} }
#[test] #[test]

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::core::collection::{ use crate::core::collection::{
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq}, album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
artist::{Artist, ArtistId, ArtistMeta}, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
}; };

View File

@ -5,7 +5,7 @@ use serde::{de::Visitor, Deserialize, Deserializer};
use crate::{ use crate::{
collection::{ collection::{
album::AlbumMeta, album::AlbumMeta,
artist::ArtistMeta, artist::{ArtistInfo, ArtistMeta},
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption, Mbid},
}, },
core::collection::{ core::collection::{
@ -115,9 +115,11 @@ impl From<DeserializeArtist> for Artist {
meta: ArtistMeta { meta: ArtistMeta {
id: ArtistId::new(artist.name), id: ArtistId::new(artist.name),
sort: artist.sort, sort: artist.sort,
info: ArtistInfo {
musicbrainz: artist.musicbrainz.into(), musicbrainz: artist.musicbrainz.into(),
properties: artist.properties, properties: artist.properties,
}, },
},
albums: artist.albums.into_iter().map(Into::into).collect(), albums: artist.albums.into_iter().map(Into::into).collect(),
} }
} }

View File

@ -73,9 +73,10 @@ impl<'a> From<&'a Artist> for SerializeArtist<'a> {
SerializeArtist { SerializeArtist {
name: &artist.meta.id.name, name: &artist.meta.id.name,
sort: artist.meta.sort.as_deref(), sort: artist.meta.sort.as_deref(),
musicbrainz: (&artist.meta.musicbrainz).into(), musicbrainz: (&artist.meta.info.musicbrainz).into(),
properties: artist properties: artist
.meta .meta
.info
.properties .properties
.iter() .iter()
.map(|(k, v)| (k.as_ref(), v)) .map(|(k, v)| (k.as_ref(), v))

View File

@ -79,8 +79,8 @@ impl From<SerdeMbArtistMeta> for MbArtistMeta {
fn from(value: SerdeMbArtistMeta) -> Self { fn from(value: SerdeMbArtistMeta) -> Self {
MbArtistMeta { MbArtistMeta {
id: value.id.into(), id: value.id.into(),
name: value.name.into(), name: value.name,
sort_name: value.sort_name.into(), sort_name: value.sort_name,
disambiguation: value.disambiguation, disambiguation: value.disambiguation,
} }
} }
@ -109,7 +109,7 @@ impl From<SerdeMbReleaseGroupMeta> for MbReleaseGroupMeta {
fn from(value: SerdeMbReleaseGroupMeta) -> Self { fn from(value: SerdeMbReleaseGroupMeta) -> Self {
MbReleaseGroupMeta { MbReleaseGroupMeta {
id: value.id.into(), id: value.id.into(),
title: value.title.into(), title: value.title,
first_release_date: value.first_release_date.into(), first_release_date: value.first_release_date.into(),
primary_type: value.primary_type.into(), primary_type: value.primary_type.into(),
secondary_types: value secondary_types: value

View File

@ -7,6 +7,7 @@ macro_rules! full_collection {
name: "Album_Artist A".to_string(), name: "Album_Artist A".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/00000000-0000-0000-0000-000000000000" "https://musicbrainz.org/artist/00000000-0000-0000-0000-000000000000"
).unwrap()), ).unwrap()),
@ -21,6 +22,7 @@ macro_rules! full_collection {
]), ]),
]), ]),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -129,6 +131,7 @@ macro_rules! full_collection {
name: "Album_Artist B".to_string(), name: "Album_Artist B".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111" "https://musicbrainz.org/artist/11111111-1111-1111-1111-111111111111"
).unwrap()), ).unwrap()),
@ -147,6 +150,7 @@ macro_rules! full_collection {
]), ]),
]), ]),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -316,9 +320,11 @@ macro_rules! full_collection {
name: "The Album_Artist C".to_string(), name: "The Album_Artist C".to_string(),
}, },
sort: Some("Album_Artist C, The".to_string()), sort: Some("Album_Artist C, The".to_string()),
info: ArtistInfo {
musicbrainz: MbRefOption::CannotHaveMbid, musicbrainz: MbRefOption::CannotHaveMbid,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -406,9 +412,11 @@ macro_rules! full_collection {
name: "Album_Artist D".to_string(), name: "Album_Artist D".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {

View File

@ -8,9 +8,11 @@ macro_rules! library_collection {
name: "Album_Artist A".to_string(), name: "Album_Artist A".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -117,9 +119,11 @@ macro_rules! library_collection {
name: "Album_Artist B".to_string(), name: "Album_Artist B".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -285,9 +289,11 @@ macro_rules! library_collection {
name: "The Album_Artist C".to_string(), name: "The Album_Artist C".to_string(),
}, },
sort: Some("Album_Artist C, The".to_string()), sort: Some("Album_Artist C, The".to_string()),
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -375,9 +381,11 @@ macro_rules! library_collection {
name: "Album_Artist D".to_string(), name: "Album_Artist D".to_string(),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::None, musicbrainz: MbRefOption::None,
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {

View File

@ -156,7 +156,7 @@ impl AppMachine<FetchState> {
result_sender: ResultSender, result_sender: ResultSender,
artist: &Artist, artist: &Artist,
) -> Result<(), FetchError> { ) -> Result<(), FetchError> {
let requests = match artist.meta.musicbrainz { let requests = match artist.meta.info.musicbrainz {
MbRefOption::Some(ref arid) => { MbRefOption::Some(ref arid) => {
let arid = arid.mbid(); let arid = arid.mbid();
let albums = artist.albums.iter(); let albums = artist.albums.iter();

View File

@ -27,7 +27,7 @@ macro_rules! item_option_artist_set {
meta: &ArtistMeta, meta: &ArtistMeta,
) -> Result<(), musichoard::Error> { ) -> Result<(), musichoard::Error> {
let mbref = match self { let mbref = match self {
MatchOption::Some(m) => m.item.musicbrainz, MatchOption::Some(m) => m.item.info.musicbrainz,
MatchOption::CannotHaveMbid => MbRefOption::CannotHaveMbid, MatchOption::CannotHaveMbid => MbRefOption::CannotHaveMbid,
MatchOption::ManualInputMbid => panic!(), MatchOption::ManualInputMbid => panic!(),
}; };

View File

@ -182,7 +182,7 @@ impl IAppInteractSearchPrivate for AppMachine<SearchState> {
if let Some(ref probe_sort) = probe.meta.sort { if let Some(ref probe_sort) = probe.meta.sort {
if !result { if !result {
let name = Self::normalize_search(&probe_sort, !case_sens, !char_sens); let name = Self::normalize_search(probe_sort, !case_sens, !char_sens);
result = name.starts_with(search); result = name.starts_with(search);
} }
} }

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
use musichoard::{ use musichoard::{
collection::{ collection::{
album::{AlbumDate, AlbumMeta, AlbumSeq}, album::{AlbumDate, AlbumMeta, AlbumSeq},
artist::ArtistMeta, artist::{ArtistInfo, ArtistMeta},
musicbrainz::{MbRefOption, Mbid}, musicbrainz::{MbRefOption, Mbid},
}, },
external::musicbrainz::{ external::musicbrainz::{
@ -98,9 +98,11 @@ fn from_lookup_artist_response(entity: LookupArtistResponse) -> Lookup<ArtistMet
item: ArtistMeta { item: ArtistMeta {
id: entity.meta.name.into(), id: entity.meta.name.into(),
sort, sort,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(entity.meta.id.into()), musicbrainz: MbRefOption::Some(entity.meta.id.into()),
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
disambiguation: entity.meta.disambiguation, disambiguation: entity.meta.disambiguation,
} }
} }
@ -126,9 +128,11 @@ fn from_search_artist_response_artist(entity: SearchArtistResponseArtist) -> Mat
item: ArtistMeta { item: ArtistMeta {
id: entity.meta.name.into(), id: entity.meta.name.into(),
sort, sort,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(entity.meta.id.into()), musicbrainz: MbRefOption::Some(entity.meta.id.into()),
properties: HashMap::new(), properties: HashMap::new(),
}, },
},
disambiguation: entity.meta.disambiguation, disambiguation: entity.meta.disambiguation,
} }
} }

View File

@ -419,7 +419,7 @@ mod tests {
} }
fn search_albums_requests() -> VecDeque<MbParams> { fn search_albums_requests() -> VecDeque<MbParams> {
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz); let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.info.musicbrainz);
let arid = mb_ref_opt_unwrap(mbref).mbid().clone(); let arid = mb_ref_opt_unwrap(mbref).mbid().clone();
let artist_id = COLLECTION[1].meta.id.clone(); let artist_id = COLLECTION[1].meta.id.clone();
@ -437,7 +437,7 @@ mod tests {
} }
fn album_arid_expectation() -> Mbid { fn album_arid_expectation() -> Mbid {
let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.musicbrainz); let mbref = mb_ref_opt_as_ref(&COLLECTION[1].meta.info.musicbrainz);
mb_ref_opt_unwrap(mbref).mbid().clone() mb_ref_opt_unwrap(mbref).mbid().clone()
} }

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
use musichoard::collection::{ use musichoard::collection::{
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq}, album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSeq},
artist::{Artist, ArtistId, ArtistMeta}, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption}, musicbrainz::{MbAlbumRef, MbArtistRef, MbRefOption},
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
}; };

View File

@ -76,10 +76,10 @@ impl<'a> ArtistOverlay<'a> {
Properties: {}", Properties: {}",
artist.map(|a| a.meta.id.name.as_str()).unwrap_or(""), artist.map(|a| a.meta.id.name.as_str()).unwrap_or(""),
artist artist
.map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.musicbrainz)) .map(|a| UiDisplay::display_mb_ref_option_as_url(&a.meta.info.musicbrainz))
.unwrap_or_default(), .unwrap_or_default(),
Self::opt_hashmap_to_string( Self::opt_hashmap_to_string(
artist.map(|a| &a.meta.properties), artist.map(|a| &a.meta.info.properties),
&double_item_indent, &double_item_indent,
&double_list_indent &double_list_indent
), ),

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use musichoard::collection::{ use musichoard::collection::{
album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq}, album::{Album, AlbumId, AlbumMeta, AlbumPrimaryType, AlbumSecondaryType, AlbumSeq},
artist::{Artist, ArtistId, ArtistMeta}, artist::{Artist, ArtistId, ArtistInfo, ArtistMeta},
musicbrainz::{MbArtistRef, MbRefOption}, musicbrainz::{MbArtistRef, MbRefOption},
track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality}, track::{Track, TrackFormat, TrackId, TrackNum, TrackQuality},
Collection, Collection,
@ -17,6 +17,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
name: String::from("Аркона"), name: String::from("Аркона"),
}, },
sort: Some(String::from("Arkona")), sort: Some(String::from("Arkona")),
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/baad262d-55ef-427a-83c7-f7530964f212" "https://musicbrainz.org/artist/baad262d-55ef-427a-83c7-f7530964f212"
).unwrap()), ).unwrap()),
@ -32,6 +33,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
)]), )]),
]), ]),
}, },
},
albums: vec![Album { albums: vec![Album {
meta: AlbumMeta { meta: AlbumMeta {
id: AlbumId { id: AlbumId {
@ -207,6 +209,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
name: String::from("Eluveitie"), name: String::from("Eluveitie"),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/8000598a-5edb-401c-8e6d-36b167feaf38" "https://musicbrainz.org/artist/8000598a-5edb-401c-8e6d-36b167feaf38"
).unwrap()), ).unwrap()),
@ -219,6 +222,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
)]), )]),
]), ]),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {
@ -454,6 +458,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
name: String::from("Frontside"), name: String::from("Frontside"),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/3a901353-fccd-4afd-ad01-9c03f451b490" "https://musicbrainz.org/artist/3a901353-fccd-4afd-ad01-9c03f451b490"
).unwrap()), ).unwrap()),
@ -466,6 +471,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
)]), )]),
]), ]),
}, },
},
albums: vec![Album { albums: vec![Album {
meta: AlbumMeta { meta: AlbumMeta {
id: AlbumId { id: AlbumId {
@ -608,6 +614,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
name: String::from("Heavens Basement"), name: String::from("Heavens Basement"),
}, },
sort: Some(String::from("Heavens Basement")), sort: Some(String::from("Heavens Basement")),
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/c2c4d56a-d599-4a18-bd2f-ae644e2198cc" "https://musicbrainz.org/artist/c2c4d56a-d599-4a18-bd2f-ae644e2198cc"
).unwrap()), ).unwrap()),
@ -620,6 +627,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
)]), )]),
]), ]),
}, },
},
albums: vec![Album { albums: vec![Album {
meta: AlbumMeta { meta: AlbumMeta {
id: AlbumId { id: AlbumId {
@ -742,6 +750,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
name: String::from("Metallica"), name: String::from("Metallica"),
}, },
sort: None, sort: None,
info: ArtistInfo {
musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str( musicbrainz: MbRefOption::Some(MbArtistRef::from_url_str(
"https://musicbrainz.org/artist/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab" "https://musicbrainz.org/artist/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"
).unwrap()), ).unwrap()),
@ -754,6 +763,7 @@ pub static COLLECTION: Lazy<Vec<Artist>> = Lazy::new(|| -> Collection {
)]), )]),
]), ]),
}, },
},
albums: vec![ albums: vec![
Album { Album {
meta: AlbumMeta { meta: AlbumMeta {