Spotify.NET/SpotifyAPI.Web/Clients/SimplePaginator.cs
Sascha Kiefer b8a2190168
feat: allow to pass cancellation token to requests (#813)
* feat: implements markets API

* fix: use correct constructor name

* feat: allow to pass a cancellation token

* pass cancellation token

* pass cancellation token only >NETSTANDARD2_1

Co-authored-by: Jonas Dellinger <jonas@dellinger.dev>
2022-11-18 12:30:09 +01:00

130 lines
3.9 KiB
C#

using System.Threading;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SpotifyAPI.Web.Http;
using System.Runtime.CompilerServices;
namespace SpotifyAPI.Web
{
public class SimplePaginator : IPaginator
{
protected virtual Task<bool> ShouldContinue<T>(List<T> results, IPaginatable<T> page)
{
return Task.FromResult(true);
}
protected virtual Task<bool> ShouldContinue<T, TNext>(List<T> results, IPaginatable<T, TNext> page)
{
return Task.FromResult(true);
}
public async Task<IList<T>> PaginateAll<T>(IPaginatable<T> firstPage, IAPIConnector connector, CancellationToken cancel = default)
{
Ensure.ArgumentNotNull(firstPage, nameof(firstPage));
Ensure.ArgumentNotNull(connector, nameof(connector));
var page = firstPage;
var results = new List<T>();
if (page.Items != null)
{
results.AddRange(page.Items);
}
while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false))
{
page = await connector.Get<Paging<T>>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(false);
if (page.Items != null)
{
results.AddRange(page.Items);
}
}
return results;
}
public async Task<IList<T>> PaginateAll<T, TNext>(
IPaginatable<T, TNext> firstPage, Func<TNext, IPaginatable<T, TNext>> mapper, IAPIConnector connector,
CancellationToken cancel = default
)
{
Ensure.ArgumentNotNull(firstPage, nameof(firstPage));
Ensure.ArgumentNotNull(mapper, nameof(mapper));
Ensure.ArgumentNotNull(connector, nameof(connector));
var page = firstPage;
var results = new List<T>();
if (page.Items != null)
{
results.AddRange(page.Items);
}
while (page.Next != null && await ShouldContinue(results, page).ConfigureAwait(false))
{
var next = await connector.Get<TNext>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(false);
page = mapper(next);
if (page.Items != null)
{
results.AddRange(page.Items);
}
}
return results;
}
public async IAsyncEnumerable<T> Paginate<T>(
IPaginatable<T> firstPage,
IAPIConnector connector,
[EnumeratorCancellation] CancellationToken cancel = default)
{
Ensure.ArgumentNotNull(firstPage, nameof(firstPage));
Ensure.ArgumentNotNull(connector, nameof(connector));
if (firstPage.Items == null)
{
throw new ArgumentException("The first page has to contain an Items list!", nameof(firstPage));
}
var page = firstPage;
foreach (var item in page.Items)
{
yield return item;
}
while (page.Next != null)
{
page = await connector.Get<Paging<T>>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(false);
foreach (var item in page.Items!)
{
yield return item;
}
}
}
public async IAsyncEnumerable<T> Paginate<T, TNext>(
IPaginatable<T, TNext> firstPage,
Func<TNext, IPaginatable<T, TNext>> mapper,
IAPIConnector connector,
[EnumeratorCancellation] CancellationToken cancel = default)
{
Ensure.ArgumentNotNull(firstPage, nameof(firstPage));
Ensure.ArgumentNotNull(mapper, nameof(mapper));
Ensure.ArgumentNotNull(connector, nameof(connector));
if (firstPage.Items == null)
{
throw new ArgumentException("The first page has to contain an Items list!", nameof(firstPage));
}
var page = firstPage;
foreach (var item in page.Items)
{
yield return item;
}
while (page.Next != null)
{
var next = await connector.Get<TNext>(new Uri(page.Next, UriKind.Absolute), cancel).ConfigureAwait(false);
page = mapper(next);
foreach (var item in page.Items!)
{
yield return item;
}
}
}
}
}