namespace Groceries; using Microsoft.EntityFrameworkCore; using System.Collections; public interface IListPageModel { int Offset { get; } int Page { get; } int PageSize { get; } int LastPage { get; } int Total { get; } int Count { get; } } public record ListPageModel : IListPageModel, IReadOnlyCollection { public ListPageModel(IList items) { Items = items; } public int Offset { get; init; } public int Page { get; init; } public int PageSize { get; init; } public int LastPage { get; init; } public int Total { get; init; } public IList Items { get; init; } public int Count => Items.Count; public IEnumerator GetEnumerator() { return Items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Items.GetEnumerator(); } } public static class ListPageModel { public static ListPageModel Empty() { return new ListPageModel(Array.Empty()); } } public static class ListPageModelExtensions { public static async Task> ToListPageModelAsync( this IQueryable query, int page, int pageSize = 10, CancellationToken cancellationToken = default) { if (page < 1) { return new ListPageModel(Array.Empty()) { Page = 1 }; } var total = await query.CountAsync(cancellationToken); var lastPage = Math.Max(1, (int)Math.Ceiling((float)total / pageSize)); if (page > lastPage) { return new ListPageModel(Array.Empty()) { Page = lastPage }; } var offset = (page - 1) * pageSize; var items = await query .Skip(offset) .Take(pageSize) .ToArrayAsync(cancellationToken); return new ListPageModel(items) { Offset = offset, Page = page, PageSize = pageSize, LastPage = lastPage, Total = total, }; } }