Make fetch also fetch artist MBID if it is missing #201
2
src/external/musicbrainz/api/mod.rs
vendored
2
src/external/musicbrainz/api/mod.rs
vendored
@ -70,7 +70,7 @@ impl ApiDisplay {
|
||||
},
|
||||
None => format!("{year}"),
|
||||
},
|
||||
None => format!("*"),
|
||||
None => String::from("*"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
71
src/external/musicbrainz/api/search/artist.rs
vendored
71
src/external/musicbrainz/api/search/artist.rs
vendored
@ -2,7 +2,10 @@ use std::fmt;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{collection::{artist::ArtistId, musicbrainz::Mbid}, external::musicbrainz::api::SerdeMbid};
|
||||
use crate::{
|
||||
collection::{artist::ArtistId, musicbrainz::Mbid},
|
||||
external::musicbrainz::api::SerdeMbid,
|
||||
};
|
||||
|
||||
use super::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin};
|
||||
|
||||
@ -74,3 +77,69 @@ impl From<DeserializeSearchArtistResponseArtist> for SearchArtistResponseArtist
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mockall::predicate;
|
||||
|
||||
use crate::external::musicbrainz::{api::MusicBrainzClient, MockIMusicBrainzHttp};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn de_response() -> DeserializeSearchArtistResponse {
|
||||
let de_artist = DeserializeSearchArtistResponseArtist {
|
||||
score: 67,
|
||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||
name: String::from("an artist"),
|
||||
sort_name: String::from("artist, an"),
|
||||
disambiguation: None,
|
||||
};
|
||||
DeserializeSearchArtistResponse {
|
||||
artists: vec![de_artist.clone()],
|
||||
}
|
||||
}
|
||||
|
||||
fn response(de_response: DeserializeSearchArtistResponse) -> SearchArtistResponse {
|
||||
SearchArtistResponse {
|
||||
artists: de_response
|
||||
.artists
|
||||
.into_iter()
|
||||
.map(|a| SearchArtistResponseArtist {
|
||||
score: 67,
|
||||
id: a.id.0,
|
||||
name: a.name.clone().into(),
|
||||
sort: Some(a.sort_name).filter(|sn| sn != &a.name).map(Into::into),
|
||||
disambiguation: a.disambiguation,
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_no_field() {
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/artist\
|
||||
?query=%22{no_field}%22",
|
||||
no_field = "an+artist",
|
||||
);
|
||||
|
||||
let de_response = de_response();
|
||||
let response = response(de_response.clone());
|
||||
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
.with(predicate::eq(url))
|
||||
.return_once(|_| Ok(de_response));
|
||||
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let name = "an artist";
|
||||
|
||||
let query = SearchArtistRequest::new().no_field(name);
|
||||
|
||||
let matches = client.search_artist(query).unwrap();
|
||||
assert_eq!(matches, response);
|
||||
}
|
||||
}
|
||||
|
51
src/external/musicbrainz/api/search/query.rs
vendored
51
src/external/musicbrainz/api/search/query.rs
vendored
@ -141,6 +141,7 @@ impl<Entity: fmt::Display> fmt::Display for Query<Entity> {
|
||||
}
|
||||
|
||||
impl<Entity> Query<Entity> {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new() -> EmptyQuery<Entity> {
|
||||
EmptyQuery::default()
|
||||
}
|
||||
@ -219,30 +220,54 @@ pub(crate) use impl_term;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::external::musicbrainz::api::search::SearchReleaseGroupRequest;
|
||||
use std::fmt;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub enum TestEntity<'a> {
|
||||
NoField(&'a str),
|
||||
}
|
||||
|
||||
impl<'a> fmt::Display for TestEntity<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::NoField(s) => write!(f, "\"{s}\""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TestEntityRequest<'a> = Query<TestEntity<'a>>;
|
||||
|
||||
impl_term!(no_field, TestEntity<'a>, NoField, &'a str);
|
||||
|
||||
#[test]
|
||||
fn lucene_logical() {
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.no_field("jakarta apache")
|
||||
.or()
|
||||
.no_field("jakarta");
|
||||
assert_eq!(format!("{query}"), "\"jakarta apache\" OR \"jakarta\"");
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.no_field("jakarta apache")
|
||||
.and()
|
||||
.no_field("jakarta");
|
||||
assert_eq!(format!("{query}"), "\"jakarta apache\" AND \"jakarta\"");
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.require()
|
||||
.no_field("jakarta")
|
||||
.or()
|
||||
.no_field("lucene");
|
||||
assert_eq!(format!("{query}"), "+\"jakarta\" OR \"lucene\"");
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.no_field("lucene")
|
||||
.require()
|
||||
.no_field("jakarta");
|
||||
assert_eq!(format!("{query}"), "\"lucene\" +\"jakarta\"");
|
||||
|
||||
let query = TestEntityRequest::new()
|
||||
.no_field("jakarta apache")
|
||||
.not()
|
||||
.no_field("Apache Lucene");
|
||||
@ -251,7 +276,17 @@ mod tests {
|
||||
"\"jakarta apache\" NOT \"Apache Lucene\""
|
||||
);
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.prohibit()
|
||||
.no_field("Apache Lucene")
|
||||
.or()
|
||||
.no_field("jakarta apache");
|
||||
assert_eq!(
|
||||
format!("{query}"),
|
||||
"-\"Apache Lucene\" OR \"jakarta apache\""
|
||||
);
|
||||
|
||||
let query = TestEntityRequest::new()
|
||||
.no_field("jakarta apache")
|
||||
.prohibit()
|
||||
.no_field("Apache Lucene");
|
||||
@ -260,9 +295,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn lucene_grouping() {
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
let query = TestEntityRequest::new()
|
||||
.expression(
|
||||
SearchReleaseGroupRequest::new()
|
||||
TestEntityRequest::new()
|
||||
.no_field("jakarta")
|
||||
.or()
|
||||
.no_field("apache"),
|
||||
|
161
src/external/musicbrainz/api/search/release_group.rs
vendored
161
src/external/musicbrainz/api/search/release_group.rs
vendored
@ -4,7 +4,7 @@ use serde::Deserialize;
|
||||
|
||||
use crate::{
|
||||
collection::{
|
||||
album::{AlbumDate, AlbumPrimaryType, AlbumSecondaryType},
|
||||
album::{AlbumDate, AlbumId, AlbumPrimaryType, AlbumSecondaryType},
|
||||
musicbrainz::Mbid,
|
||||
},
|
||||
external::musicbrainz::api::{
|
||||
@ -74,7 +74,7 @@ impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse
|
||||
pub struct SearchReleaseGroupResponseReleaseGroup {
|
||||
pub score: u8,
|
||||
pub id: Mbid,
|
||||
pub title: String,
|
||||
pub title: AlbumId,
|
||||
pub first_release_date: AlbumDate,
|
||||
pub primary_type: AlbumPrimaryType,
|
||||
pub secondary_types: Option<Vec<AlbumSecondaryType>>,
|
||||
@ -82,7 +82,7 @@ pub struct SearchReleaseGroupResponseReleaseGroup {
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
#[serde(rename_all(deserialize = "kebab-case"))]
|
||||
struct DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||
pub struct DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||
score: u8,
|
||||
id: SerdeMbid,
|
||||
title: String,
|
||||
@ -98,7 +98,7 @@ impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
||||
SearchReleaseGroupResponseReleaseGroup {
|
||||
score: value.score,
|
||||
id: value.id.into(),
|
||||
title: value.title,
|
||||
title: value.title.into(),
|
||||
first_release_date: value.first_release_date.into(),
|
||||
primary_type: value.primary_type.into(),
|
||||
secondary_types: value
|
||||
@ -110,33 +110,13 @@ impl From<DeserializeSearchReleaseGroupResponseReleaseGroup>
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mockall::{predicate, Sequence};
|
||||
use mockall::predicate;
|
||||
|
||||
use crate::{
|
||||
collection::album::AlbumId,
|
||||
external::musicbrainz::{api::MusicBrainzClient, MockIMusicBrainzHttp},
|
||||
};
|
||||
use crate::external::musicbrainz::{api::MusicBrainzClient, MockIMusicBrainzHttp};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn search_release_group() {
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url_title = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/release-group\
|
||||
?query=arid%3A{arid}+AND+firstreleasedate%3A{date}+AND+releasegroup%3A%22{title}%22",
|
||||
arid = "00000000-0000-0000-0000-000000000000",
|
||||
date = "1986-04",
|
||||
title = "an+album",
|
||||
);
|
||||
let url_rgid = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/release-group\
|
||||
?query=rgid%3A{rgid}",
|
||||
rgid = "11111111-1111-1111-1111-111111111111",
|
||||
);
|
||||
|
||||
fn de_response() -> DeserializeSearchReleaseGroupResponse {
|
||||
let de_release_group = DeserializeSearchReleaseGroupResponseReleaseGroup {
|
||||
score: 67,
|
||||
id: SerdeMbid("11111111-1111-1111-1111-111111111111".try_into().unwrap()),
|
||||
@ -145,78 +125,72 @@ mod tests {
|
||||
primary_type: SerdeAlbumPrimaryType(AlbumPrimaryType::Album),
|
||||
secondary_types: Some(vec![SerdeAlbumSecondaryType(AlbumSecondaryType::Live)]),
|
||||
};
|
||||
let de_response = DeserializeSearchReleaseGroupResponse {
|
||||
DeserializeSearchReleaseGroupResponse {
|
||||
release_groups: vec![de_release_group.clone()],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let release_group = SearchReleaseGroupResponseReleaseGroup {
|
||||
score: 67,
|
||||
id: de_release_group.id.0,
|
||||
title: de_release_group.title,
|
||||
first_release_date: de_release_group.first_release_date.0,
|
||||
primary_type: de_release_group.primary_type.0,
|
||||
secondary_types: de_release_group
|
||||
.secondary_types
|
||||
.map(|v| v.into_iter().map(|st| st.0).collect()),
|
||||
};
|
||||
let response = SearchReleaseGroupResponse {
|
||||
release_groups: vec![release_group.clone()],
|
||||
};
|
||||
fn response(de_response: DeserializeSearchReleaseGroupResponse) -> SearchReleaseGroupResponse {
|
||||
SearchReleaseGroupResponse {
|
||||
release_groups: de_response
|
||||
.release_groups
|
||||
.into_iter()
|
||||
.map(|rg| SearchReleaseGroupResponseReleaseGroup {
|
||||
score: 67,
|
||||
id: rg.id.0,
|
||||
title: rg.title.into(),
|
||||
first_release_date: rg.first_release_date.0,
|
||||
primary_type: rg.primary_type.0,
|
||||
secondary_types: rg
|
||||
.secondary_types
|
||||
.map(|v| v.into_iter().map(|st| st.0).collect()),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
let mut seq = Sequence::new();
|
||||
#[test]
|
||||
fn search_no_field() {
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/release-group\
|
||||
?query=%22{title}%22",
|
||||
title = "an+album",
|
||||
);
|
||||
|
||||
let de_response = de_response();
|
||||
let response = response(de_response.clone());
|
||||
|
||||
let title_response = de_response.clone();
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
.with(predicate::eq(url_title))
|
||||
.return_once(|_| Ok(title_response))
|
||||
.in_sequence(&mut seq);
|
||||
|
||||
let rgid_response = de_response;
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
.with(predicate::eq(url_rgid))
|
||||
.return_once(|_| Ok(rgid_response))
|
||||
.in_sequence(&mut seq);
|
||||
.with(predicate::eq(url))
|
||||
.return_once(|_| Ok(de_response));
|
||||
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let arid: Mbid = "00000000-0000-0000-0000-000000000000".try_into().unwrap();
|
||||
let title: AlbumId = AlbumId::new("an album");
|
||||
let date = (1986, 4).into();
|
||||
let title = "an album";
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
.arid(&arid)
|
||||
.and()
|
||||
.release_group(&title.title)
|
||||
.and()
|
||||
.first_release_date(&date);
|
||||
|
||||
let matches = client.search_release_group(query).unwrap();
|
||||
assert_eq!(matches, response);
|
||||
|
||||
let rgid: Mbid = "11111111-1111-1111-1111-111111111111".try_into().unwrap();
|
||||
|
||||
let query = SearchReleaseGroupRequest::new().rgid(&rgid);
|
||||
let query = SearchReleaseGroupRequest::new().no_field(title);
|
||||
|
||||
let matches = client.search_release_group(query).unwrap();
|
||||
assert_eq!(matches, response);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_release_group_empty_date() {
|
||||
fn search_arid_album_date_release_group() {
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/release-group\
|
||||
?query=arid%3A{arid}+AND+releasegroup%3A%22{title}%22",
|
||||
?query=arid%3A{arid}+AND+releasegroup%3A%22{title}%22+AND+firstreleasedate%3A{date}",
|
||||
arid = "00000000-0000-0000-0000-000000000000",
|
||||
date = "1986-04",
|
||||
title = "an+album",
|
||||
);
|
||||
|
||||
let de_response = DeserializeSearchReleaseGroupResponse {
|
||||
release_groups: vec![],
|
||||
};
|
||||
let de_response = de_response();
|
||||
let response = response(de_response.clone());
|
||||
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
@ -226,16 +200,45 @@ mod tests {
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let arid: Mbid = "00000000-0000-0000-0000-000000000000".try_into().unwrap();
|
||||
let title: AlbumId = AlbumId::new("an album");
|
||||
let date = AlbumDate::default();
|
||||
let title = "an album";
|
||||
let date = (1986, 4).into();
|
||||
|
||||
let query = SearchReleaseGroupRequest::new()
|
||||
.arid(&arid)
|
||||
.and()
|
||||
.release_group(&title.title)
|
||||
.release_group(title)
|
||||
.and()
|
||||
.first_release_date(&date);
|
||||
|
||||
let _ = client.search_release_group(query).unwrap();
|
||||
let matches = client.search_release_group(query).unwrap();
|
||||
assert_eq!(matches, response);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_rgid() {
|
||||
let mut http = MockIMusicBrainzHttp::new();
|
||||
let url = format!(
|
||||
"https://musicbrainz.org/ws/2\
|
||||
/release-group\
|
||||
?query=rgid%3A{rgid}",
|
||||
rgid = "11111111-1111-1111-1111-111111111111",
|
||||
);
|
||||
|
||||
let de_response = de_response();
|
||||
let response = response(de_response.clone());
|
||||
|
||||
http.expect_get()
|
||||
.times(1)
|
||||
.with(predicate::eq(url))
|
||||
.return_once(|_| Ok(de_response));
|
||||
|
||||
let mut client = MusicBrainzClient::new(http);
|
||||
|
||||
let rgid: Mbid = "11111111-1111-1111-1111-111111111111".try_into().unwrap();
|
||||
|
||||
let query = SearchReleaseGroupRequest::new().rgid(&rgid);
|
||||
|
||||
let matches = client.search_release_group(query).unwrap();
|
||||
assert_eq!(matches, response);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user