Skip to content

Commit d9dd760

Browse files
maureiwisepotato
authored andcommitted
fix: #641 (#642)
On IPageService, exposes DefaultPageSize next to the RequestedPageSize to give the user more control over pagination.
1 parent e52615d commit d9dd760

File tree

6 files changed

+45
-22
lines changed

6 files changed

+45
-22
lines changed

src/JsonApiDotNetCore/QueryParameterServices/Contracts/IPageService.cs

+12-4
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ namespace JsonApiDotNetCore.Query
66
public interface IPageService : IQueryParameterService
77
{
88
/// <summary>
9-
/// What the total records are for this output
9+
/// Gets the requested or default page size
1010
/// </summary>
11-
int? TotalRecords { get; set; }
11+
int CurrentPageSize { get; }
12+
/// <summary>
13+
/// Default size to be used in pagination
14+
/// </summary>
15+
int DefaultPageSize { get; set; }
1216
/// <summary>
13-
/// How many records per page should be shown
17+
/// Currently requested page size to be used in pagination
1418
/// </summary>
15-
int PageSize { get; set; }
19+
int? RequestedPageSize { get; set; }
1620
/// <summary>
1721
/// The page requested. Note that the page number is one-based.
1822
/// </summary>
@@ -29,5 +33,9 @@ public interface IPageService : IQueryParameterService
2933
/// Denotes if pagination is backwards
3034
/// </summary>
3135
bool Backwards { get; }
36+
/// <summary>
37+
/// What the total records are for this output
38+
/// </summary>
39+
int? TotalRecords { get; set; }
3240
}
3341
}

src/JsonApiDotNetCore/QueryParameterServices/PageService.cs

+23-8
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ namespace JsonApiDotNetCore.Query
1313
public class PageService : QueryParameterService, IPageService
1414
{
1515
private readonly IJsonApiOptions _options;
16-
1716
public PageService(IJsonApiOptions options, IResourceGraph resourceGraph, ICurrentRequest currentRequest) : base(resourceGraph, currentRequest)
1817
{
1918
_options = options;
20-
PageSize = _options.DefaultPageSize;
19+
DefaultPageSize = _options.DefaultPageSize;
2120
}
2221

2322
/// <summary>
@@ -26,14 +25,27 @@ public PageService(IJsonApiOptions options, IResourceGraph resourceGraph, ICurre
2625
internal PageService(IJsonApiOptions options)
2726
{
2827
_options = options;
29-
PageSize = _options.DefaultPageSize;
28+
DefaultPageSize = _options.DefaultPageSize;
3029
}
3130

3231
/// <inheritdoc/>
33-
public int? TotalRecords { get; set; }
32+
public int CurrentPageSize
33+
{
34+
get
35+
{
36+
if (RequestedPageSize.HasValue)
37+
{
38+
return RequestedPageSize.Value;
39+
}
40+
return DefaultPageSize;
41+
}
42+
}
43+
44+
/// <inheritdoc/>
45+
public int DefaultPageSize { get; set; }
3446

3547
/// <inheritdoc/>
36-
public int PageSize { get; set; }
48+
public int? RequestedPageSize { get; set; }
3749

3850
/// <inheritdoc/>
3951
public int CurrentPage { get; set; } = 1;
@@ -42,17 +54,20 @@ internal PageService(IJsonApiOptions options)
4254
public bool Backwards { get; set; }
4355

4456
/// <inheritdoc/>
45-
public int TotalPages => (TotalRecords == null || PageSize == 0) ? -1 : (int)Math.Ceiling(decimal.Divide(TotalRecords.Value, PageSize));
57+
public int TotalPages => (TotalRecords == null || CurrentPageSize == 0) ? -1 : (int)Math.Ceiling(decimal.Divide(TotalRecords.Value, CurrentPageSize));
4658

4759
/// <inheritdoc/>
4860
public bool CanPaginate { get { return TotalPages > 1; } }
4961

62+
/// <inheritdoc/>
63+
public int? TotalRecords { get; set; }
64+
5065
/// <inheritdoc/>
5166
public virtual void Parse(KeyValuePair<string, StringValues> queryParameter)
5267
{
5368
EnsureNoNestedResourceRoute();
5469
// expected input = page[size]=<integer>
55-
// page[number]=<integer > 0>
70+
// page[number]=<integer greater than zero>
5671
var propertyName = queryParameter.Key.Split(QueryConstants.OPEN_BRACKET, QueryConstants.CLOSE_BRACKET)[1];
5772

5873
const string SIZE = "size";
@@ -70,7 +85,7 @@ public virtual void Parse(KeyValuePair<string, StringValues> queryParameter)
7085
}
7186
else
7287
{
73-
PageSize = size;
88+
RequestedPageSize = size;
7489
}
7590
}
7691
else if (propertyName == NUMBER)

src/JsonApiDotNetCore/Serialization/Server/Builders/LinkBuilder.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,19 @@ private void SetPageLinks(ResourceContext primaryResource, TopLevelLinks links)
6363
{
6464
if (_pageService.CurrentPage > 1)
6565
{
66-
links.Prev = GetPageLink(primaryResource, _pageService.CurrentPage - 1, _pageService.PageSize);
66+
links.Prev = GetPageLink(primaryResource, _pageService.CurrentPage - 1, _pageService.CurrentPageSize);
6767
}
6868

6969
if (_pageService.CurrentPage < _pageService.TotalPages)
7070
{
71-
links.Next = GetPageLink(primaryResource, _pageService.CurrentPage + 1, _pageService.PageSize);
71+
links.Next = GetPageLink(primaryResource, _pageService.CurrentPage + 1, _pageService.CurrentPageSize);
7272
}
7373

7474
if (_pageService.TotalPages > 0)
7575
{
76-
links.Self = GetPageLink(primaryResource, _pageService.CurrentPage, _pageService.PageSize);
77-
links.First = GetPageLink(primaryResource, 1, _pageService.PageSize);
78-
links.Last = GetPageLink(primaryResource, _pageService.TotalPages, _pageService.PageSize);
76+
links.Self = GetPageLink(primaryResource, _pageService.CurrentPage, _pageService.CurrentPageSize);
77+
links.First = GetPageLink(primaryResource, 1, _pageService.CurrentPageSize);
78+
links.Last = GetPageLink(primaryResource, _pageService.TotalPages, _pageService.CurrentPageSize);
7979
}
8080
}
8181

src/JsonApiDotNetCore/Services/DefaultResourceService.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public virtual async Task UpdateRelationshipsAsync(TId id, string relationshipNa
200200

201201
protected virtual async Task<IEnumerable<TResource>> ApplyPageQueryAsync(IQueryable<TResource> entities)
202202
{
203-
if (!(_pageService.PageSize > 0))
203+
if (!(_pageService.CurrentPageSize > 0))
204204
{
205205
var allEntities = await _repository.ToListAsync(entities);
206206
return allEntities as IEnumerable<TResource>;
@@ -214,10 +214,10 @@ protected virtual async Task<IEnumerable<TResource>> ApplyPageQueryAsync(IQuerya
214214
if (_logger?.IsEnabled(LogLevel.Information) == true)
215215
{
216216
_logger?.LogInformation($"Applying paging query. Fetching page {pageOffset} " +
217-
$"with {_pageService.PageSize} entities");
217+
$"with {_pageService.CurrentPageSize} entities");
218218
}
219219

220-
return await _repository.PageAsync(entities, _pageService.PageSize, pageOffset);
220+
return await _repository.PageAsync(entities, _pageService.CurrentPageSize, pageOffset);
221221
}
222222

223223
/// <summary>

test/UnitTests/Builders/LinkBuilderTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ private IPageService GetPageManager()
195195
mock.Setup(m => m.CanPaginate).Returns(true);
196196
mock.Setup(m => m.CurrentPage).Returns(2);
197197
mock.Setup(m => m.TotalPages).Returns(3);
198-
mock.Setup(m => m.PageSize).Returns(10);
198+
mock.Setup(m => m.CurrentPageSize).Returns(10);
199199
return mock.Object;
200200

201201
}

test/UnitTests/QueryParameters/PageServiceTests.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void Parse_PageSize_CanParse(string value, int expectedValue, bool should
4646
else
4747
{
4848
service.Parse(query);
49-
Assert.Equal(expectedValue, service.PageSize);
49+
Assert.Equal(expectedValue, service.CurrentPageSize);
5050
}
5151
}
5252

0 commit comments

Comments
 (0)