fix: use AsRef generics for pagination

This commit is contained in:
ThetaDev 2022-11-30 12:42:06 +01:00
parent 85cac83070
commit 94b55711cb
4 changed files with 68 additions and 60 deletions

View file

@ -208,7 +208,7 @@ async fn playlist_cont(testfiles: &Path) {
.unwrap();
let rp = rp_testfile(&json_path);
playlist.videos.next(&rp.query()).await.unwrap().unwrap();
playlist.videos.next(rp.query()).await.unwrap().unwrap();
}
async fn video_details(testfiles: &Path) {
@ -246,7 +246,7 @@ async fn comments_top(testfiles: &Path) {
let rp = rp_testfile(&json_path);
details
.top_comments
.next(&rp.query())
.next(rp.query())
.await
.unwrap()
.unwrap();
@ -266,7 +266,7 @@ async fn comments_latest(testfiles: &Path) {
let rp = rp_testfile(&json_path);
details
.latest_comments
.next(&rp.query())
.next(rp.query())
.await
.unwrap()
.unwrap();
@ -284,7 +284,7 @@ async fn recommendations(testfiles: &Path) {
let details = rp.query().video_details("ZeerrnuLi5E").await.unwrap();
let rp = rp_testfile(&json_path);
details.recommended.next(&rp.query()).await.unwrap();
details.recommended.next(rp.query()).await.unwrap();
}
async fn channel_videos(testfiles: &Path) {
@ -384,7 +384,7 @@ async fn channel_videos_cont(testfiles: &Path) {
.unwrap();
let rp = rp_testfile(&json_path);
videos.content.next(&rp.query()).await.unwrap().unwrap();
videos.content.next(rp.query()).await.unwrap().unwrap();
}
async fn channel_playlists_cont(testfiles: &Path) {
@ -403,7 +403,7 @@ async fn channel_playlists_cont(testfiles: &Path) {
.unwrap();
let rp = rp_testfile(&json_path);
playlists.content.next(&rp.query()).await.unwrap().unwrap();
playlists.content.next(rp.query()).await.unwrap().unwrap();
}
async fn search(testfiles: &Path) {
@ -430,7 +430,7 @@ async fn search_cont(testfiles: &Path) {
let search = rp.query().search("doobydoobap").await.unwrap();
let rp = rp_testfile(&json_path);
search.items.next(&rp.query()).await.unwrap().unwrap();
search.items.next(rp.query()).await.unwrap().unwrap();
}
async fn search_playlists(testfiles: &Path) {
@ -492,7 +492,7 @@ async fn startpage_cont(testfiles: &Path) {
let startpage = rp.query().startpage().await.unwrap();
let rp = rp_testfile(&json_path);
startpage.next(&rp.query()).await.unwrap();
startpage.next(rp.query()).await.unwrap();
}
async fn trending(testfiles: &Path) {
@ -541,7 +541,7 @@ async fn music_playlist_cont(testfiles: &Path) {
.unwrap();
let rp = rp_testfile(&json_path);
playlist.tracks.next(&rp.query()).await.unwrap().unwrap();
playlist.tracks.next(rp.query()).await.unwrap().unwrap();
}
async fn music_playlist_related(testfiles: &Path) {
@ -562,7 +562,7 @@ async fn music_playlist_related(testfiles: &Path) {
let rp = rp_testfile(&json_path);
playlist
.related_playlists
.next(&rp.query())
.next(rp.query())
.await
.unwrap()
.unwrap();
@ -688,7 +688,7 @@ async fn music_search_cont(testfiles: &Path) {
let res = rp.query().music_search_tracks("black mamba").await.unwrap();
let rp = rp_testfile(&json_path);
res.items.next(&rp.query()).await.unwrap().unwrap();
res.items.next(rp.query()).await.unwrap().unwrap();
}
async fn music_search_suggestion(testfiles: &Path) {
@ -801,7 +801,7 @@ async fn music_radio_cont(testfiles: &Path) {
let res = rp.query().music_radio("RDAMVM7nigXQS1Xb0").await.unwrap();
let rp = rp_testfile(&json_path);
res.next(&rp.query()).await.unwrap().unwrap();
res.next(rp.query()).await.unwrap().unwrap();
}
async fn music_new_albums(testfiles: &Path) {

View file

@ -1164,6 +1164,12 @@ impl RustyPipeQuery {
}
}
impl AsRef<RustyPipeQuery> for RustyPipeQuery {
fn as_ref(&self) -> &RustyPipeQuery {
self
}
}
/// Implement this for YouTube API response structs that need to be mapped to
/// RustyPipe models.
trait MapResponse<T> {

View file

@ -176,10 +176,11 @@ impl MapResponse<Paginator<MusicItem>> for response::MusicContinuation {
}
impl<T: FromYtItem> Paginator<T> {
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
Ok(match &self.ctoken {
Some(ctoken) => Some(
query
.as_ref()
.continuation(ctoken, self.endpoint, self.visitor_data.as_deref())
.await?,
),
@ -187,7 +188,7 @@ impl<T: FromYtItem> Paginator<T> {
})
}
pub async fn extend(&mut self, query: &RustyPipeQuery) -> Result<bool, Error> {
pub async fn extend<Q: AsRef<RustyPipeQuery>>(&mut self, query: Q) -> Result<bool, Error> {
match self.next(query).await {
Ok(Some(paginator)) => {
let mut items = paginator.items;
@ -200,11 +201,12 @@ impl<T: FromYtItem> Paginator<T> {
}
}
pub async fn extend_pages(
pub async fn extend_pages<Q: AsRef<RustyPipeQuery>>(
&mut self,
query: &RustyPipeQuery,
query: Q,
n_pages: usize,
) -> Result<(), Error> {
let query = query.as_ref();
for _ in 0..n_pages {
match self.extend(query).await {
Ok(false) => break,
@ -215,11 +217,12 @@ impl<T: FromYtItem> Paginator<T> {
Ok(())
}
pub async fn extend_limit(
pub async fn extend_limit<Q: AsRef<RustyPipeQuery>>(
&mut self,
query: &RustyPipeQuery,
query: Q,
n_items: usize,
) -> Result<(), Error> {
let query = query.as_ref();
while self.items.len() < n_items {
match self.extend(query).await {
Ok(false) => break,
@ -232,10 +235,11 @@ impl<T: FromYtItem> Paginator<T> {
}
impl Paginator<Comment> {
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
Ok(match &self.ctoken {
Some(ctoken) => Some(
query
.as_ref()
.video_comments(ctoken, self.visitor_data.as_deref())
.await?,
),
@ -245,9 +249,9 @@ impl Paginator<Comment> {
}
impl Paginator<PlaylistVideo> {
pub async fn next(&self, query: &RustyPipeQuery) -> Result<Option<Self>, Error> {
pub async fn next<Q: AsRef<RustyPipeQuery>>(&self, query: Q) -> Result<Option<Self>, Error> {
Ok(match &self.ctoken {
Some(ctoken) => Some(query.playlist_continuation(ctoken).await?),
Some(ctoken) => Some(query.as_ref().playlist_continuation(ctoken).await?),
None => None,
})
}
@ -256,7 +260,10 @@ impl Paginator<PlaylistVideo> {
macro_rules! paginator {
($entity_type:ty) => {
impl Paginator<$entity_type> {
pub async fn extend(&mut self, query: &RustyPipeQuery) -> Result<bool, Error> {
pub async fn extend<Q: AsRef<RustyPipeQuery>>(
&mut self,
query: Q,
) -> Result<bool, Error> {
match self.next(query).await {
Ok(Some(paginator)) => {
let mut items = paginator.items;
@ -269,11 +276,12 @@ macro_rules! paginator {
}
}
pub async fn extend_pages(
pub async fn extend_pages<Q: AsRef<RustyPipeQuery>>(
&mut self,
query: &RustyPipeQuery,
query: Q,
n_pages: usize,
) -> Result<(), Error> {
let query = query.as_ref();
for _ in 0..n_pages {
match self.extend(query).await {
Ok(false) => break,
@ -284,11 +292,12 @@ macro_rules! paginator {
Ok(())
}
pub async fn extend_limit(
pub async fn extend_limit<Q: AsRef<RustyPipeQuery>>(
&mut self,
query: &RustyPipeQuery,
query: Q,
n_items: usize,
) -> Result<(), Error> {
let query = query.as_ref();
while self.items.len() < n_items {
match self.extend(query).await {
Ok(false) => break,

View file

@ -380,7 +380,7 @@ async fn playlist_cont() {
playlist
.videos
.extend_pages(&rp.query(), usize::MAX)
.extend_pages(rp.query(), usize::MAX)
.await
.unwrap();
assert!(playlist.videos.items.len() > 100);
@ -396,11 +396,7 @@ async fn playlist_cont2() {
.await
.unwrap();
playlist
.videos
.extend_limit(&rp.query(), 101)
.await
.unwrap();
playlist.videos.extend_limit(rp.query(), 101).await.unwrap();
assert!(playlist.videos.items.len() > 100);
assert!(playlist.videos.count.unwrap() > 100);
}
@ -461,7 +457,7 @@ async fn get_video_details() {
assert!(!details.is_ccommons);
assert!(details.recommended.visitor_data.is_some());
assert_next(details.recommended, &rp.query(), 10, 2).await;
assert_next(details.recommended, rp.query(), 10, 2).await;
assert_gte(details.top_comments.count.unwrap(), 700_000, "comments");
assert!(!details.top_comments.is_exhausted());
@ -499,7 +495,7 @@ async fn get_video_details_music() {
assert!(!details.is_ccommons);
assert!(details.recommended.visitor_data.is_some());
assert_next(details.recommended, &rp.query(), 10, 2).await;
assert_next(details.recommended, rp.query(), 10, 2).await;
// Update(01.11.2022): comments are sometimes enabled
/*
@ -548,7 +544,7 @@ async fn get_video_details_ccommons() {
assert!(details.is_ccommons);
assert!(details.recommended.visitor_data.is_some());
assert_next(details.recommended, &rp.query(), 10, 2).await;
assert_next(details.recommended, rp.query(), 10, 2).await;
assert_gte(details.top_comments.count.unwrap(), 2199, "comments");
assert!(!details.top_comments.is_exhausted());
@ -673,7 +669,7 @@ async fn get_video_details_chapters() {
}
assert!(details.recommended.visitor_data.is_some());
assert_next(details.recommended, &rp.query(), 10, 2).await;
assert_next(details.recommended, rp.query(), 10, 2).await;
assert_gte(details.top_comments.count.unwrap(), 3200, "comments");
assert!(!details.top_comments.is_exhausted());
@ -718,7 +714,7 @@ async fn get_video_details_live() {
assert!(!details.is_ccommons);
assert!(details.recommended.visitor_data.is_some());
assert_next(details.recommended, &rp.query(), 10, 2).await;
assert_next(details.recommended, rp.query(), 10, 2).await;
// No comments because livestream
assert_eq!(details.top_comments.count, Some(0));
@ -786,7 +782,7 @@ async fn get_video_comments() {
let top_comments = details
.top_comments
.next(&rp.query())
.next(rp.query())
.await
.unwrap()
.unwrap();
@ -805,7 +801,7 @@ async fn get_video_comments() {
let latest_comments = details
.latest_comments
.next(&rp.query())
.next(rp.query())
.await
.unwrap()
.unwrap();
@ -839,7 +835,7 @@ async fn channel_videos() {
assert!(age_days < 60, "latest video older than 60 days");
assert_next(channel.content, &rp.query(), 15, 2).await;
assert_next(channel.content, rp.query(), 15, 2).await;
}
#[tokio::test]
@ -873,7 +869,7 @@ async fn channel_shorts() {
"got no shorts"
);
assert_next(channel.content, &rp.query(), 15, 1).await;
assert_next(channel.content, rp.query(), 15, 1).await;
}
#[tokio::test]
@ -893,7 +889,7 @@ async fn channel_livestreams() {
"got no streams"
);
assert_next(channel.content, &rp.query(), 5, 1).await;
assert_next(channel.content, rp.query(), 5, 1).await;
}
#[tokio::test]
@ -912,7 +908,7 @@ async fn channel_playlists() {
"got no playlists"
);
assert_next(channel.content, &rp.query(), 15, 1).await;
assert_next(channel.content, rp.query(), 15, 1).await;
}
#[tokio::test]
@ -1099,7 +1095,7 @@ async fn search() {
);
assert_eq!(result.corrected_query.unwrap(), "doobydobap");
assert_next(result.items, &rp.query(), 10, 2).await;
assert_next(result.items, rp.query(), 10, 2).await;
}
#[rstest]
@ -1115,7 +1111,7 @@ async fn search_filter_entity(#[case] entity: search_filter::Entity) {
.await
.unwrap();
result.items.extend(&rp.query()).await.unwrap();
result.items.extend(rp.query()).await.unwrap();
assert_gte(result.items.items.len(), 20, "items");
result.items.items.iter().for_each(|item| match item {
@ -1243,7 +1239,7 @@ async fn startpage() {
// The startpage requires visitor data to fetch continuations
assert!(startpage.visitor_data.is_some());
assert_next(startpage, &rp.query(), 20, 2).await;
assert_next(startpage, rp.query(), 20, 2).await;
}
#[tokio::test]
@ -1321,7 +1317,7 @@ async fn music_playlist_cont() {
playlist
.tracks
.extend_pages(&rp.query(), usize::MAX)
.extend_pages(rp.query(), usize::MAX)
.await
.unwrap();
@ -1338,11 +1334,7 @@ async fn music_playlist_related() {
.await
.unwrap();
playlist
.related_playlists
.extend(&rp.query())
.await
.unwrap();
playlist.related_playlists.extend(rp.query()).await.unwrap();
assert_gte(
playlist.related_playlists.items.len(),
@ -1571,7 +1563,7 @@ async fn music_search_tracks() {
assert_eq!(album.id, "MPREb_OpHWHwyNOuY");
assert_eq!(album.name, "Black Mamba");
assert_next(res.items, &rp.query(), 15, 2).await;
assert_next(res.items, rp.query(), 15, 2).await;
}
#[tokio::test]
@ -1605,7 +1597,7 @@ async fn music_search_videos() {
assert_eq!(track.album, None);
assert_gte(track.view_count.unwrap(), 230_000_000, "views");
assert_next(res.items, &rp.query(), 15, 2).await;
assert_next(res.items, rp.query(), 15, 2).await;
}
#[tokio::test]
@ -1692,7 +1684,7 @@ async fn music_search_albums(
assert_eq!(res.corrected_query, None);
assert_next(res.items, &rp.query(), 15, n_pages).await;
assert_next(res.items, rp.query(), 15, n_pages).await;
}
#[tokio::test]
@ -1724,7 +1716,7 @@ async fn music_search_artists_cont() {
let res = rp.query().music_search_artists("band").await.unwrap();
assert_eq!(res.corrected_query, None);
assert_next(res.items, &rp.query(), 15, 2).await;
assert_next(res.items, rp.query(), 15, 2).await;
}
#[rstest]
@ -2000,7 +1992,7 @@ async fn music_details_not_found() {
async fn music_radio_track() {
let rp = RustyPipe::builder().strict().build();
let tracks = rp.query().music_radio_track("ZeerrnuLi5E").await.unwrap();
assert_next(tracks, &rp.query(), 20, 3).await;
assert_next(tracks, rp.query(), 20, 3).await;
}
#[tokio::test]
@ -2030,7 +2022,7 @@ async fn music_radio_playlist() {
.music_radio_playlist("PL5dDx681T4bR7ZF1IuWzOv1omlRbE7PiJ")
.await
.unwrap();
assert_next(tracks, &rp.query(), 10, 1).await;
assert_next(tracks, rp.query(), 10, 1).await;
}
#[tokio::test]
@ -2121,13 +2113,14 @@ fn assert_gte<T: PartialOrd + Display>(a: T, b: T, msg: &str) {
assert!(a >= b, "expected {} {}, got {}", b, msg, a);
}
async fn assert_next<T: FromYtItem>(
async fn assert_next<T: FromYtItem, Q: AsRef<RustyPipeQuery>>(
paginator: Paginator<T>,
query: &RustyPipeQuery,
query: Q,
min_items: usize,
n_pages: usize,
) {
let mut p = paginator;
let query = query.as_ref();
assert_gte(p.items.len(), min_items, "items on page 0");
for i in 0..n_pages {