Complete support for paging

This commit is contained in:
Wojciech Kozlowski 2024-09-29 21:06:29 +02:00
parent e2c103b4d7
commit 77a97659d1
7 changed files with 101 additions and 24 deletions

View File

@ -3,7 +3,7 @@ use std::{thread, time};
use musichoard::{
collection::musicbrainz::Mbid,
external::musicbrainz::{
api::{browse::BrowseReleaseGroupRequest, MusicBrainzClient, PageSettings},
api::{browse::BrowseReleaseGroupRequest, MusicBrainzClient, NextPage, PageSettings},
http::MusicBrainzHttp,
},
};
@ -66,20 +66,19 @@ fn main() {
println!("{rg:?}\n");
}
let offset = response.release_group_offset;
let offset = response.page.release_group_offset;
let count = response.release_groups.len();
response_counts.push(count);
let total = response.release_group_count;
let total = response.page.release_group_count;
println!("Release group offset : {offset}");
println!("Release groups in this response: {count}");
println!("Release groups in total : {total}");
let next_offset = offset + count;
if next_offset == total {
break;
match response.page.next_page_offset(count) {
NextPage::Offset(next_offset) => paging.with_offset(next_offset),
NextPage::Complete => break,
}
paging.with_offset(next_offset);
thread::sleep(time::Duration::from_secs(1));
}

View File

@ -6,14 +6,31 @@ use crate::{
collection::musicbrainz::Mbid,
external::musicbrainz::{
api::{
Error, MbReleaseGroupMeta, MusicBrainzClient, PageSettings, SerdeMbReleaseGroupMeta,
MB_BASE_URL,
ApiDisplay, Error, MbReleaseGroupMeta, MusicBrainzClient, NextPage, PageSettings,
SerdeMbReleaseGroupMeta, MB_BASE_URL,
},
IMusicBrainzHttp,
},
};
use super::ApiDisplay;
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all(deserialize = "kebab-case"))]
pub struct BrowseReleaseGroupPage {
pub release_group_offset: usize,
pub release_group_count: usize,
}
impl BrowseReleaseGroupPage {
pub fn next_page_offset(&self, page_count: usize) -> NextPage {
NextPage::next_page_offset(
self.release_group_offset,
self.release_group_count,
page_count,
)
}
}
pub type SerdeBrowseReleaseGroupPage = BrowseReleaseGroupPage;
impl<Http: IMusicBrainzHttp> MusicBrainzClient<Http> {
pub fn browse_release_group(
@ -60,24 +77,22 @@ impl<'a> BrowseReleaseGroupRequest<'a> {
#[derive(Debug, PartialEq, Eq)]
pub struct BrowseReleaseGroupResponse {
pub release_group_offset: usize,
pub release_group_count: usize,
pub release_groups: Vec<MbReleaseGroupMeta>,
pub page: BrowseReleaseGroupPage,
}
#[derive(Clone, Deserialize)]
#[serde(rename_all(deserialize = "kebab-case"))]
struct DeserializeBrowseReleaseGroupResponse {
release_group_offset: usize,
release_group_count: usize,
release_groups: Option<Vec<SerdeMbReleaseGroupMeta>>,
#[serde(flatten)]
page: SerdeBrowseReleaseGroupPage,
}
impl From<DeserializeBrowseReleaseGroupResponse> for BrowseReleaseGroupResponse {
fn from(value: DeserializeBrowseReleaseGroupResponse) -> Self {
BrowseReleaseGroupResponse {
release_group_offset: value.release_group_offset,
release_group_count: value.release_group_count,
page: value.page,
release_groups: value
.release_groups
.map(|rgs| rgs.into_iter().map(Into::into).collect())
@ -120,14 +135,15 @@ mod tests {
)]),
};
let de_response = DeserializeBrowseReleaseGroupResponse {
page: SerdeBrowseReleaseGroupPage {
release_group_offset: de_release_group_offset,
release_group_count: de_release_group_count,
},
release_groups: Some(vec![de_meta.clone()]),
};
let response = BrowseReleaseGroupResponse {
release_group_offset: de_release_group_offset,
release_group_count: de_release_group_count,
page: de_response.page,
release_groups: vec![de_meta.clone().into()],
};

View File

@ -84,6 +84,22 @@ impl PageSettings {
}
}
pub enum NextPage {
Offset(usize),
Complete,
}
impl NextPage {
pub fn next_page_offset(offset: usize, total_count: usize, page_count: usize) -> NextPage {
let next_offset = offset + page_count;
if next_offset < total_count {
NextPage::Offset(next_offset)
} else {
NextPage::Complete
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MbArtistMeta {
pub id: Mbid,

View File

@ -3,7 +3,10 @@ use std::fmt;
use serde::Deserialize;
use crate::external::musicbrainz::api::{
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
search::{
query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
SearchPage, SerdeSearchPage,
},
MbArtistMeta, SerdeMbArtistMeta,
};
@ -26,18 +29,22 @@ impl_term!(string, SearchArtist<'a>, String, &'a str);
#[derive(Debug, PartialEq, Eq)]
pub struct SearchArtistResponse {
pub artists: Vec<SearchArtistResponseArtist>,
pub page: SearchPage,
}
#[derive(Clone, Deserialize)]
#[serde(rename_all(deserialize = "kebab-case"))]
pub struct DeserializeSearchArtistResponse {
artists: Vec<DeserializeSearchArtistResponseArtist>,
#[serde(flatten)]
page: SerdeSearchPage,
}
impl From<DeserializeSearchArtistResponse> for SearchArtistResponse {
fn from(value: DeserializeSearchArtistResponse) -> Self {
SearchArtistResponse {
artists: value.artists.into_iter().map(Into::into).collect(),
page: value.page,
}
}
}
@ -77,6 +84,8 @@ mod tests {
use super::*;
fn de_response() -> DeserializeSearchArtistResponse {
let de_offset = 24;
let de_count = 124;
let de_artist = DeserializeSearchArtistResponseArtist {
score: 67,
meta: SerdeMbArtistMeta {
@ -88,6 +97,10 @@ mod tests {
};
DeserializeSearchArtistResponse {
artists: vec![de_artist.clone()],
page: SerdeSearchPage {
offset: de_offset,
count: de_count,
},
}
}
@ -101,6 +114,7 @@ mod tests {
meta: a.meta.into(),
})
.collect(),
page: de_response.page,
}
}

View File

@ -9,6 +9,7 @@ pub use release_group::{
};
use paste::paste;
use serde::Deserialize;
use url::form_urlencoded;
use crate::external::musicbrainz::{
@ -22,6 +23,23 @@ use crate::external::musicbrainz::{
IMusicBrainzHttp,
};
use super::NextPage;
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq)]
#[serde(rename_all(deserialize = "kebab-case"))]
pub struct SearchPage {
pub offset: usize,
pub count: usize,
}
impl SearchPage {
pub fn next_page_offset(&self, page_count: usize) -> NextPage {
NextPage::next_page_offset(self.offset, self.count, page_count)
}
}
pub type SerdeSearchPage = SearchPage;
macro_rules! impl_search_entity {
($name:ident, $entity:literal) => {
paste! {

View File

@ -5,7 +5,10 @@ use serde::Deserialize;
use crate::{
collection::{album::AlbumDate, musicbrainz::Mbid},
external::musicbrainz::api::{
search::query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
search::{
query::{impl_term, EmptyQuery, EmptyQueryJoin, Query, QueryJoin},
SearchPage, SerdeSearchPage,
},
ApiDisplay, MbReleaseGroupMeta, SerdeMbReleaseGroupMeta,
},
};
@ -50,18 +53,22 @@ impl_term!(rgid, SearchReleaseGroup<'a>, Rgid, &'a Mbid);
#[derive(Debug, PartialEq, Eq)]
pub struct SearchReleaseGroupResponse {
pub release_groups: Vec<SearchReleaseGroupResponseReleaseGroup>,
pub page: SearchPage,
}
#[derive(Clone, Deserialize)]
#[serde(rename_all(deserialize = "kebab-case"))]
pub struct DeserializeSearchReleaseGroupResponse {
release_groups: Vec<DeserializeSearchReleaseGroupResponseReleaseGroup>,
#[serde(flatten)]
page: SerdeSearchPage,
}
impl From<DeserializeSearchReleaseGroupResponse> for SearchReleaseGroupResponse {
fn from(value: DeserializeSearchReleaseGroupResponse) -> Self {
SearchReleaseGroupResponse {
release_groups: value.release_groups.into_iter().map(Into::into).collect(),
page: value.page,
}
}
}
@ -109,6 +116,8 @@ mod tests {
use super::*;
fn de_response() -> DeserializeSearchReleaseGroupResponse {
let de_offset = 26;
let de_count = 126;
let de_release_group = DeserializeSearchReleaseGroupResponseReleaseGroup {
score: 67,
meta: SerdeMbReleaseGroupMeta {
@ -121,6 +130,10 @@ mod tests {
};
DeserializeSearchReleaseGroupResponse {
release_groups: vec![de_release_group.clone()],
page: SerdeSearchPage {
offset: de_offset,
count: de_count,
},
}
}
@ -134,6 +147,7 @@ mod tests {
meta: rg.meta.into(),
})
.collect(),
page: de_response.page,
}
}

View File

@ -57,7 +57,7 @@ impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
fn search_artist(&mut self, artist: &ArtistMeta) -> Result<Vec<Match<ArtistMeta>>, Error> {
let query = SearchArtistRequest::new().string(&artist.id.name);
let paging = PageSettings::with_max_limit();
let paging = PageSettings::default();
let mb_response = self.client.search_artist(&query, &paging)?;
Ok(mb_response
@ -83,7 +83,7 @@ impl<Http: IMusicBrainzHttp> IMusicBrainz for MusicBrainz<Http> {
.and()
.release_group(&album.id.title);
let paging = PageSettings::with_max_limit();
let paging = PageSettings::default();
let mb_response = self.client.search_release_group(&query, &paging)?;
Ok(mb_response