tgstation-server 6.0.1
The /tg/station 13 server suite
Loading...
Searching...
No Matches
PaginatedClient.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Globalization;
4using System.Linq;
5using System.Threading;
6using System.Threading.Tasks;
7
10
12{
16 abstract class PaginatedClient
17 {
21 protected IApiClient ApiClient { get; }
22
27 public PaginatedClient(IApiClient apiClient)
28 {
29 ApiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
30 }
31
41 protected async ValueTask<List<TModel>> ReadPaged<TModel>(
42 PaginationSettings? paginationSettings,
43 string route,
44 long? instanceId,
45 CancellationToken cancellationToken)
46 {
47 if (route == null)
48 throw new ArgumentNullException(nameof(route));
49
50 var routeFormatter = $"{route}?page={{0}}";
51 var currentPage = 1;
52 if (paginationSettings != null)
53 {
54 if (paginationSettings.RetrieveCount == 0)
55 return new List<TModel>(); // that was easy
56 else if (paginationSettings.RetrieveCount < 0)
57 throw new ArgumentOutOfRangeException(nameof(paginationSettings), "RetrieveCount cannot be less than 0!");
58
59 int? pageSize = null;
60 if (paginationSettings.PageSize.HasValue)
61 {
62 // pagesize validates itself on first request
63 pageSize = paginationSettings.PageSize.Value;
64 routeFormatter += $"&pageSize={pageSize}";
65 }
66
67 if (paginationSettings.Offset.HasValue)
68 {
69 if (paginationSettings.Offset.Value < 0)
70 throw new ArgumentOutOfRangeException(nameof(paginationSettings), "Offset cannot be less than 0!");
71
72 pageSize ??= paginationSettings.Offset.Value;
73 currentPage = (paginationSettings.Offset.Value / pageSize.Value) + 1;
74 }
75 }
76
77 ValueTask<PaginatedResponse<TModel>> GetPage() => instanceId.HasValue
79 String.Format(CultureInfo.InvariantCulture, routeFormatter, currentPage),
80 instanceId.Value,
81 cancellationToken)
83 String.Format(CultureInfo.InvariantCulture, routeFormatter, currentPage),
84 cancellationToken);
85
86 var firstPage = await GetPage().ConfigureAwait(false);
87
88 var totalAvailable = firstPage.TotalPages * firstPage.PageSize;
89 var maximumItems = paginationSettings?.RetrieveCount.HasValue == true
90 ? Math.Min(paginationSettings.RetrieveCount!.Value, totalAvailable)
91 : totalAvailable;
92
93 var results = new List<TModel>(maximumItems);
94 var currentResults = firstPage;
95 do
96 {
97 // check if first page
98 if (currentPage > 1)
99 currentResults = await GetPage().ConfigureAwait(false);
100
101 if (currentResults.Content == null)
102 throw new ApiConflictException("Paginated results missing content!");
103
104 IEnumerable<TModel> rangeToAdd = currentResults.Content;
105 if (paginationSettings?.Offset.HasValue == true)
106 {
107 rangeToAdd = rangeToAdd
108 .Skip(paginationSettings.Offset!.Value % currentResults.PageSize);
109 }
110
111 var itemsAvailableInPage = rangeToAdd.Count();
112 var itemsStillRequired = maximumItems - results.Count;
113 if (itemsAvailableInPage > itemsStillRequired)
114 rangeToAdd = rangeToAdd
115 .Take(itemsStillRequired);
116
117 results.AddRange(rangeToAdd);
118 ++currentPage;
119 }
120 while (results.Count < maximumItems && currentPage <= currentResults.TotalPages);
121
122 return results;
123 }
124 }
125}
int PageSize
The current size of pages in the query.
Occurs when the server returns a bad request response if the ApiException.ErrorCode is present....
Client that deals with getting paginated results.
PaginatedClient(IApiClient apiClient)
Initializes a new instance of the PaginatedClient class.
async ValueTask< List< TModel > > ReadPaged< TModel >(PaginationSettings? paginationSettings, string route, long? instanceId, CancellationToken cancellationToken)
Reads a given route with paged results.
Settings for a paginated request.
int? PageSize
The size of a page. Defaults to server settings.
int? RetrieveCount
The maximum amount of items to retrieve. Default everything.
int? Offset
The offset to take from. Default 0.
Web interface for the API.
Definition: IApiClient.cs:19