Skip to content

Commit fb3e16f

Browse files
docs: document pagination result APIs
1 parent 5122d43 commit fb3e16f

3 files changed

Lines changed: 168 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using System.Linq;
2+
using SqlKata.Execution;
3+
using Xunit;
4+
5+
namespace SqlKata.Tests
6+
{
7+
public class PaginationResultTests
8+
{
9+
[Fact]
10+
public void ReportsPageStateFromCountAndPageSize()
11+
{
12+
var result = new PaginationResult<int>
13+
{
14+
Count = 25,
15+
Page = 2,
16+
PerPage = 10,
17+
};
18+
19+
Assert.Equal(3, result.TotalPages);
20+
Assert.False(result.IsFirst);
21+
Assert.False(result.IsLast);
22+
Assert.True(result.HasNext);
23+
Assert.True(result.HasPrevious);
24+
}
25+
26+
[Fact]
27+
public void BuildsQueriesForAdjacentPages()
28+
{
29+
var nextResult = new PaginationResult<int>
30+
{
31+
Query = new Query("Posts"),
32+
Page = 2,
33+
PerPage = 10,
34+
};
35+
36+
var nextQuery = nextResult.NextQuery();
37+
38+
Assert.Same(nextResult.Query, nextQuery);
39+
Assert.Equal(20, nextQuery.GetOffset());
40+
Assert.Equal(10, nextQuery.GetLimit());
41+
42+
var previousResult = new PaginationResult<int>
43+
{
44+
Query = new Query("Posts"),
45+
Page = 2,
46+
PerPage = 10,
47+
};
48+
49+
var previousQuery = previousResult.PreviousQuery();
50+
51+
Assert.Same(previousResult.Query, previousQuery);
52+
Assert.Equal(0, previousQuery.GetOffset());
53+
Assert.Equal(10, previousQuery.GetLimit());
54+
}
55+
56+
[Fact]
57+
public void EachYieldsTheCurrentPageWhenThereIsNoNextPage()
58+
{
59+
var result = new PaginationResult<int>
60+
{
61+
Count = 2,
62+
List = new[] { 1, 2 },
63+
Page = 1,
64+
PerPage = 10,
65+
};
66+
67+
var iterator = result.Each;
68+
var pages = iterator.ToList();
69+
70+
Assert.Single(pages);
71+
Assert.Same(result, pages[0]);
72+
Assert.Same(result, iterator.CurrentPage);
73+
}
74+
}
75+
}

SqlKata.Execution/PaginationIterator.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,27 @@
33

44
namespace SqlKata.Execution
55
{
6+
/// <summary>
7+
/// Enumerates paginated results, beginning with a supplied first page and
8+
/// loading each subsequent page as enumeration advances.
9+
/// </summary>
10+
/// <typeparam name="T">The type of each item in the paginated results.</typeparam>
611
public class PaginationIterator<T> : IEnumerable<PaginationResult<T>>
712
{
13+
/// <summary>
14+
/// Gets or sets the page from which enumeration starts.
15+
/// </summary>
816
public PaginationResult<T> FirstPage { get; set; }
17+
18+
/// <summary>
19+
/// Gets or sets the page most recently returned by the iterator.
20+
/// </summary>
921
public PaginationResult<T> CurrentPage { get; set; }
1022

23+
/// <summary>
24+
/// Returns an enumerator that yields the first page and loads later pages on demand.
25+
/// </summary>
26+
/// <returns>An enumerator over the available pages.</returns>
1127
public IEnumerator<Execution.PaginationResult<T>> GetEnumerator()
1228
{
1329
CurrentPage = FirstPage;

SqlKata.Execution/PaginationResult.cs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,41 @@
66

77
namespace SqlKata.Execution
88
{
9+
/// <summary>
10+
/// Represents one page of query results together with pagination metadata
11+
/// and helpers for loading adjacent pages.
12+
/// </summary>
13+
/// <typeparam name="T">The type of each item in the result set.</typeparam>
914
public class PaginationResult<T>
1015
{
16+
/// <summary>
17+
/// Gets or sets the query used to produce the paginated results.
18+
/// </summary>
1119
public Query Query { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the total number of matching records across all pages.
23+
/// </summary>
1224
public long Count { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the records in the current page.
28+
/// </summary>
1329
public IEnumerable<T> List { get; set; }
30+
31+
/// <summary>
32+
/// Gets or sets the one-based current page number.
33+
/// </summary>
1434
public int Page { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets the maximum number of records per page.
38+
/// </summary>
1539
public int PerPage { get; set; }
40+
41+
/// <summary>
42+
/// Gets the total number of pages, rounded up from <see cref="Count"/>.
43+
/// </summary>
1644
public int TotalPages
1745
{
1846
get
@@ -30,6 +58,9 @@ public int TotalPages
3058
}
3159
}
3260

61+
/// <summary>
62+
/// Gets a value indicating whether this is the first page.
63+
/// </summary>
3364
public bool IsFirst
3465
{
3566
get
@@ -38,6 +69,9 @@ public bool IsFirst
3869
}
3970
}
4071

72+
/// <summary>
73+
/// Gets a value indicating whether this is the last page.
74+
/// </summary>
4175
public bool IsLast
4276
{
4377
get
@@ -46,6 +80,9 @@ public bool IsLast
4680
}
4781
}
4882

83+
/// <summary>
84+
/// Gets a value indicating whether a page follows the current page.
85+
/// </summary>
4986
public bool HasNext
5087
{
5188
get
@@ -54,6 +91,9 @@ public bool HasNext
5491
}
5592
}
5693

94+
/// <summary>
95+
/// Gets a value indicating whether a page precedes the current page.
96+
/// </summary>
5797
public bool HasPrevious
5898
{
5999
get
@@ -62,36 +102,73 @@ public bool HasPrevious
62102
}
63103
}
64104

105+
/// <summary>
106+
/// Applies the next page's limit and offset to <see cref="Query"/>.
107+
/// </summary>
108+
/// <returns>The query configured for the next page.</returns>
65109
public Query NextQuery()
66110
{
67111
return this.Query.ForPage(Page + 1, PerPage);
68112
}
69113

114+
/// <summary>
115+
/// Executes the query for the next page.
116+
/// </summary>
117+
/// <param name="transaction">The transaction to use, or <see langword="null"/> for none.</param>
118+
/// <param name="timeout">The command timeout in seconds, or <see langword="null"/> to use the configured default.</param>
119+
/// <returns>The next page of results.</returns>
70120
public PaginationResult<T> Next(IDbTransaction transaction = null, int? timeout = null)
71121
{
72122
return this.Query.Paginate<T>(Page + 1, PerPage, transaction, timeout);
73123
}
74124

125+
/// <summary>
126+
/// Asynchronously executes the query for the next page.
127+
/// </summary>
128+
/// <param name="transaction">The transaction to use, or <see langword="null"/> for none.</param>
129+
/// <param name="timeout">The command timeout in seconds, or <see langword="null"/> to use the configured default.</param>
130+
/// <param name="cancellationToken">The token used to cancel the operation.</param>
131+
/// <returns>A task containing the next page of results.</returns>
75132
public async Task<PaginationResult<T>> NextAsync(IDbTransaction transaction = null, int? timeout = null, CancellationToken cancellationToken = default)
76133
{
77134
return await this.Query.PaginateAsync<T>(Page + 1, PerPage, transaction, timeout, cancellationToken);
78135
}
79136

137+
/// <summary>
138+
/// Applies the previous page's limit and offset to <see cref="Query"/>.
139+
/// </summary>
140+
/// <returns>The query configured for the previous page.</returns>
80141
public Query PreviousQuery()
81142
{
82143
return this.Query.ForPage(Page - 1, PerPage);
83144
}
84145

146+
/// <summary>
147+
/// Executes the query for the previous page.
148+
/// </summary>
149+
/// <param name="transaction">The transaction to use, or <see langword="null"/> for none.</param>
150+
/// <param name="timeout">The command timeout in seconds, or <see langword="null"/> to use the configured default.</param>
151+
/// <returns>The previous page of results.</returns>
85152
public PaginationResult<T> Previous(IDbTransaction transaction = null, int? timeout = null)
86153
{
87154
return this.Query.Paginate<T>(Page - 1, PerPage, transaction, timeout);
88155
}
89156

157+
/// <summary>
158+
/// Asynchronously executes the query for the previous page.
159+
/// </summary>
160+
/// <param name="transaction">The transaction to use, or <see langword="null"/> for none.</param>
161+
/// <param name="timeout">The command timeout in seconds, or <see langword="null"/> to use the configured default.</param>
162+
/// <param name="cancellationToken">The token used to cancel the operation.</param>
163+
/// <returns>A task containing the previous page of results.</returns>
90164
public async Task<PaginationResult<T>> PreviousAsync(IDbTransaction transaction = null, int? timeout = null, CancellationToken cancellationToken = default)
91165
{
92166
return await this.Query.PaginateAsync<T>(Page - 1, PerPage, transaction, timeout, cancellationToken);
93167
}
94168

169+
/// <summary>
170+
/// Gets an iterator that starts with this page and loads each remaining page.
171+
/// </summary>
95172
public PaginationIterator<T> Each
96173
{
97174
get

0 commit comments

Comments
 (0)