tgstation-server 6.12.3
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:17