Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</PropertyGroup>

<PropertyGroup Condition="'$(IsPackable)' != 'false'">
<Version>3.1.0</Version>
<Version>3.2.0</Version>
<Authors>DrSkillIssue</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/DrSkillIssue/EFPagination</PackageProjectUrl>
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(

The `Expression<Func<T, TOut>>` overloads run the projection inside the SQL statement that applies the keyset `ORDER BY`. Subqueries inside the selector stay server-side and the SELECT list materializes only the projected columns plus the keyset key columns. The pagination definition must have 1–8 key columns; outside that range, the overload throws `NotSupportedException`.

Every `PaginateAsync` overload throws `BadHttpRequestException` (status 400) for an invalid or expired cursor and for a `request.PageSize` of zero or less. ASP.NET Core's exception handler middleware maps its status code to the response.
Every `PaginateAsync` overload throws `BadHttpRequestException` (status 400) for an invalid or expired cursor, for a `request.PageSize` of zero or less, and for a `request.PageSize` above `maxPageSize`. ASP.NET Core's exception handler middleware maps its status code to the response.

See [Server-Side Projection](patterns.md#server-side-projection) for end-to-end examples.

Expand Down
12 changes: 9 additions & 3 deletions src/EFPagination.AspNetCore/PaginationEndpointExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static class PaginationEndpointExtensions
/// <param name="includeCount">Whether to compute the total row count.</param>
/// <param name="ct">A cancellation token.</param>
/// <returns>A task that resolves to a <see cref="PaginatedResponse{TOut}"/>.</returns>
/// <exception cref="BadHttpRequestException">The request's cursor is invalid or expired, or its page size is not a positive integer of at most <paramref name="maxPageSize"/>.</exception>
public static async Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(
this IQueryable<T> query,
PaginationQueryDefinition<T> definition,
Expand All @@ -32,6 +33,9 @@ public static async Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(
bool includeCount = false,
CancellationToken ct = default) where T : class
{
if (request.PageSize > maxPageSize)
throw new BadHttpRequestException($"pageSize '{request.PageSize}' exceeds the maximum page size {maxPageSize}.");

var (cursor, direction) = request.Before is not null
? (request.Before, PaginationDirection.Backward)
: (request.After, PaginationDirection.Forward);
Expand Down Expand Up @@ -104,7 +108,7 @@ public static Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(
/// <param name="ct">A cancellation token.</param>
/// <returns>A task that resolves to a <see cref="PaginatedResponse{TOut}"/> with projected items.</returns>
/// <exception cref="ArgumentNullException"><paramref name="query"/>, <paramref name="definition"/>, or <paramref name="selector"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">The cursor in <paramref name="request"/> is invalid or expired.</exception>
/// <exception cref="BadHttpRequestException">The request's cursor is invalid or expired, or its page size is not a positive integer of at most <paramref name="maxPageSize"/>.</exception>
/// <exception cref="NotSupportedException">The pagination definition has fewer than 1 or more than 8 key columns.</exception>
public static async Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(
this IQueryable<T> query,
Expand All @@ -119,14 +123,16 @@ public static async Task<PaginatedResponse<TOut>> PaginateAsync<T, TOut>(
ArgumentNullException.ThrowIfNull(definition);
ArgumentNullException.ThrowIfNull(selector);

var effectivePageSize = request.PageSize > maxPageSize ? maxPageSize : request.PageSize;
if (request.PageSize > maxPageSize)
throw new BadHttpRequestException($"pageSize '{request.PageSize}' exceeds the maximum page size {maxPageSize}.");

var builder = query.Keyset(definition).FromRequest(request).MaxPageSize(maxPageSize);
if (includeCount)
builder = builder.IncludeCount();

try
{
var page = await builder.TakeAsync(effectivePageSize, selector, ct).ConfigureAwait(false);
var page = await builder.TakeAsync(request.PageSize, selector, ct).ConfigureAwait(false);

return page.ToPaginatedResponse();
}
Expand Down