├── docs ├── help.md └── _config.yml ├── global.json ├── images ├── data.png ├── data-paginable.png ├── paginable-alpha.png └── paginable-table.png ├── src └── PaginableCollections │ ├── Properties │ └── AssemblyInfo.cs │ ├── IPaginableRequest.cs │ ├── IPager.cs │ ├── IPaginableItem.cs │ ├── IPagerItem.cs │ ├── PaginableRequest.cs │ ├── EmptyPaginable.cs │ ├── PagerItem.cs │ ├── PaginableItem.cs │ ├── EnumerableExtensions.cs │ ├── PaginableCollections.csproj │ ├── StaticPaginable.cs │ ├── StaticPager.cs │ ├── QueryableBasedPaginable.cs │ ├── IPaginable.cs │ ├── PaginableExtensions.cs │ └── Paginable.cs ├── tools └── packages.config ├── samples ├── ConsoleAppDotNet45 │ ├── App.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ConsoleAppDotNet45.csproj ├── ConsoleAppDotNetCore11 │ ├── ConsoleAppDotNetCore11.csproj │ └── Program.cs └── ConsoleAppDotNetCore20 │ ├── ConsoleAppDotNetCore20.csproj │ └── Program.cs ├── tests └── PaginableCollections.Tests │ ├── StaticPagerTests.cs │ ├── PaginableRequestTests.cs │ ├── EmptyPaginableTests.cs │ ├── PaginableCollections.Tests.csproj │ ├── EnumerableStaticPaginableRequestTests.cs │ ├── QueryablePaginableRequestTests.cs │ ├── EnumerableQueryablePaginableTests.cs │ ├── EnumerableStaticPaginableTests.cs │ ├── StaticPaginableTests.cs │ ├── QueryablePaginableTests.cs │ └── PagerItemTests.cs ├── .gitattributes ├── appveyor.yml ├── LICENSE ├── README.md ├── CODE_OF_CONDUCT.md ├── PaginableCollections.sln └── .gitignore /docs/help.md: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.1.400" 4 | } 5 | } -------------------------------------------------------------------------------- /images/data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dataneek/paginable-collections/HEAD/images/data.png -------------------------------------------------------------------------------- /src/PaginableCollections/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | [assembly: CLSCompliant(true)] -------------------------------------------------------------------------------- /images/data-paginable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dataneek/paginable-collections/HEAD/images/data-paginable.png -------------------------------------------------------------------------------- /images/paginable-alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dataneek/paginable-collections/HEAD/images/paginable-alpha.png -------------------------------------------------------------------------------- /images/paginable-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dataneek/paginable-collections/HEAD/images/paginable-table.png -------------------------------------------------------------------------------- /tools/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/PaginableCollections/IPaginableRequest.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public interface IPaginableRequest 4 | { 5 | int PageNumber { get; } 6 | int ItemCountPerPage { get; } 7 | } 8 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNet45/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/PaginableCollections/IPager.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Collections.Generic; 4 | 5 | public interface IPager 6 | { 7 | IEnumerable GetPages(); 8 | 9 | int TotalPageCount { get; } 10 | int MaximumPageNumberCount { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/PaginableCollections/IPaginableItem.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public interface IPaginableItem 4 | { 5 | int ItemNumber { get; } 6 | int PageNumber { get; } 7 | int ItemCountPerPage { get; } 8 | } 9 | 10 | public interface IPaginableItem : IPaginableItem 11 | { 12 | T Item { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/PaginableCollections/IPagerItem.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public interface IPagerItem 4 | { 5 | int PageNumber { get; } 6 | int TotalPageCount { get; } 7 | 8 | bool IsFirstPage { get; } 9 | bool IsLastPage { get; } 10 | 11 | bool HasPreviousPage { get; } 12 | bool HasNextPage { get; } 13 | } 14 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/StaticPagerTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using System.Linq; 4 | using Xunit; 5 | 6 | public class StaticPagerTest 7 | { 8 | [Fact] 9 | public void ShouldNotBeNull() 10 | { 11 | var sut = Enumerable.Range(1, 10).ToPaginable(1, 5).ToPager(2); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNetCore11/ConsoleAppDotNetCore11.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp1.1 6 | ConsoleAppDotNetCore 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/ConsoleAppDotNetCore20/ConsoleAppDotNetCore20.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | ConsoleAppDotNetCore 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /src/PaginableCollections/PaginableRequest.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public class PaginableRequest : IPaginableRequest 4 | { 5 | public PaginableRequest(int pageNumber, int itemCountPerPage) 6 | { 7 | PageNumber = pageNumber; 8 | ItemCountPerPage = itemCountPerPage; 9 | } 10 | 11 | public int PageNumber { get; private set; } 12 | public int ItemCountPerPage { get; private set; } 13 | } 14 | } -------------------------------------------------------------------------------- /src/PaginableCollections/EmptyPaginable.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Linq; 4 | 5 | /// 6 | /// Represents an empty paginable collection. 7 | /// 8 | /// 9 | public class EmptyPaginable : StaticPaginable 10 | { 11 | public const int DefaultItemCountPerPage = 10; 12 | 13 | /// 14 | /// Create new empty paginable collection. 15 | /// 16 | public EmptyPaginable() 17 | : base(Enumerable.Empty(), 1, DefaultItemCountPerPage, 0) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/PaginableCollections/PagerItem.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public class PagerItem: IPagerItem 4 | { 5 | public PagerItem(int pageNumber, int totalPageCount) 6 | { 7 | PageNumber = pageNumber; 8 | TotalPageCount = totalPageCount; 9 | } 10 | 11 | public int PageNumber { get; private set; } 12 | public int TotalPageCount { get; private set; } 13 | 14 | public bool IsFirstPage => PageNumber == 1; 15 | public bool IsLastPage => PageNumber >= TotalPageCount; 16 | 17 | public bool HasPreviousPage => PageNumber > 1; 18 | public bool HasNextPage => PageNumber < TotalPageCount; 19 | } 20 | } -------------------------------------------------------------------------------- /src/PaginableCollections/PaginableItem.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | public class PaginableItem : IPaginableItem 4 | { 5 | private PaginableItem() { } 6 | 7 | public PaginableItem(T item, int itemNumber, int pageNumber, int itemCountPerPage) 8 | { 9 | Item = item; 10 | ItemNumber = itemNumber; 11 | PageNumber = pageNumber; 12 | ItemCountPerPage = itemCountPerPage; 13 | } 14 | 15 | public T Item { get; private set; } 16 | public int ItemNumber { get; private set; } 17 | public int PageNumber { get; private set; } 18 | public int ItemCountPerPage { get; private set; } 19 | } 20 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | version: '{build}' 3 | pull_requests: 4 | do_not_increment_build_number: true 5 | branches: 6 | only: 7 | - master 8 | nuget: 9 | disable_publish_on_pr: true 10 | build_script: 11 | - ps: .\build.ps1 12 | test: off 13 | artifacts: 14 | - path: .\artifacts\**\*.nupkg 15 | name: NuGet 16 | deploy: 17 | - provider: NuGet 18 | server: https://www.myget.org/F/neekgreen/api/v2 19 | api_key: 20 | secure: F+HOhtceWDrA8csKd3erzdsHZQDTiZyuZu1GxUF9cn6lQCi57c1A1Spz61jY6jMb 21 | skip_symbols: true 22 | on: 23 | branch: master 24 | - provider: NuGet 25 | name: production 26 | api_key: 27 | secure: LETsd+PTuBvLDx2FdbTtP/gbsYonG2uh/gT7BVG2ZNU1RZBZ7UNJ/uXlpB5/ztKv 28 | on: 29 | branch: master 30 | appveyor_repo_tag: true -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/PaginableRequestTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using FluentAssertions; 4 | using Xunit; 5 | 6 | public class PaginableRequestTests 7 | { 8 | [Fact] 9 | public void ShouldEqualPageNumber() 10 | { 11 | var expectedPageNumber = 2; 12 | var sut = new PaginableRequest(expectedPageNumber, 10); 13 | 14 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 15 | } 16 | 17 | [Fact] 18 | public void ShouldEqualItemCountPerPage() 19 | { 20 | var expectedItemCountPerPage = 12; 21 | var sut = new PaginableRequest(2, expectedItemCountPerPage); 22 | 23 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNet45/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ConsoleAppDotNet45 2 | { 3 | using System; 4 | using System.Linq; 5 | using PaginableCollections; 6 | 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | var itemCountPerPage = 25; 12 | var pageNumber = 4; 13 | 14 | var paginable = 15 | Enumerable.Range(1, 200) 16 | .ToPaginable(pageNumber, itemCountPerPage); 17 | 18 | Console.WriteLine(string.Format("page number {0}", pageNumber)); 19 | Console.WriteLine(string.Format("item count per page {0}", itemCountPerPage)); 20 | Console.WriteLine(string.Join(",", paginable.Select(t => t.Item))); 21 | Console.WriteLine(string.Format("showing items {0} to {1} of {2}", paginable.FirstItemNumber, paginable.LastItemNumber, paginable.TotalItemCount)); 22 | Console.ReadLine(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNetCore11/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ConsoleAppDotNetCore 2 | { 3 | using System; 4 | using System.Linq; 5 | using PaginableCollections; 6 | 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | var itemCountPerPage = 25; 12 | var pageNumber = 4; 13 | 14 | var paginable = 15 | Enumerable.Range(1, 200) 16 | .ToPaginable(pageNumber, itemCountPerPage); 17 | 18 | Console.WriteLine(string.Format("page number {0}", pageNumber)); 19 | Console.WriteLine(string.Format("item count per page {0}", itemCountPerPage)); 20 | Console.WriteLine(string.Join(",", paginable.Select(t => t.Item))); 21 | Console.WriteLine(string.Format("showing items {0} to {1} of {2}", paginable.FirstItemNumber, paginable.LastItemNumber, paginable.TotalItemCount)); 22 | Console.ReadLine(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNetCore20/Program.cs: -------------------------------------------------------------------------------- 1 | namespace ConsoleAppDotNetCore 2 | { 3 | using System; 4 | using System.Linq; 5 | using PaginableCollections; 6 | 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | var itemCountPerPage = 25; 12 | var pageNumber = 4; 13 | 14 | var paginable = 15 | Enumerable.Range(1, 200) 16 | .ToPaginable(pageNumber, itemCountPerPage); 17 | 18 | Console.WriteLine(string.Format("page number {0}", pageNumber)); 19 | Console.WriteLine(string.Format("item count per page {0}", itemCountPerPage)); 20 | Console.WriteLine(string.Join(",", paginable.Select(t => t.Item))); 21 | Console.WriteLine(string.Format("showing items {0} to {1} of {2}", paginable.FirstItemNumber, paginable.LastItemNumber, paginable.TotalItemCount)); 22 | Console.ReadLine(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/EmptyPaginableTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using FluentAssertions; 4 | using Xunit; 5 | 6 | public class EmptyPaginableTests 7 | { 8 | [Fact] 9 | public void ShouldEqualPageNumber() 10 | { 11 | var expectedPageNumber = 1; 12 | var sut = Paginable.Empty(); 13 | 14 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 15 | } 16 | 17 | [Fact] 18 | public void ShouldEqualItemCountPerPage() 19 | { 20 | var expectedItemCountPerPage = EmptyPaginable.DefaultItemCountPerPage; 21 | var sut = Paginable.Empty(); 22 | 23 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 24 | } 25 | 26 | [Fact] 27 | public void ShouldEqualTotalItemCount() 28 | { 29 | var expectedTotalItemCount = 0; 30 | var sut = Paginable.Empty(); 31 | 32 | sut.TotalItemCount.ShouldBeEquivalentTo(expectedTotalItemCount); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/PaginableCollections.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.0 5 | PaginableCollections.Tests 6 | PaginableCollections.Tests 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/PaginableCollections/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | public static class EnumerableExtensions 7 | { 8 | public static IPaginable ToPaginable(this IEnumerable enumerable, int pageNumber, int itemCountPerPage) 9 | { 10 | return 11 | enumerable 12 | .AsQueryable() 13 | .ToPaginable(pageNumber, itemCountPerPage); 14 | } 15 | 16 | public static IPaginable ToPaginable(this IEnumerable enumerable, IPaginableRequest paginableRequest) 17 | { 18 | return 19 | enumerable 20 | .ToPaginable(paginableRequest.PageNumber, paginableRequest.ItemCountPerPage); 21 | } 22 | 23 | public static IPaginable ToPaginable(this IEnumerable enumerable, int pageNumber, int itemCountPerPage, int totalItemCount) 24 | { 25 | return new StaticPaginable(enumerable, pageNumber, itemCountPerPage, totalItemCount); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nicholas Myers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/EnumerableStaticPaginableRequestTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class EnumerableStaticPaginableRequestTests 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(10, 50); 13 | var expectedPageNumber = 2; 14 | var paginableInfo = new PaginableRequest(expectedPageNumber, 10); 15 | 16 | var sut = source.ToPaginable(paginableInfo); 17 | 18 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 19 | } 20 | 21 | [Fact] 22 | public void ShouldEqualItemCountPerPage() 23 | { 24 | var source = Enumerable.Range(11, 100); 25 | var expectedItemCountPerPage = 12; 26 | var paginableInfo = new PaginableRequest(2, expectedItemCountPerPage); 27 | 28 | var sut = source.ToPaginable(paginableInfo); 29 | 30 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/QueryablePaginableRequestTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class QueryablePaginableRequestTests 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(10, 50).AsQueryable(); 13 | var expectedPageNumber = 2; 14 | var paginableInfo = new PaginableRequest(expectedPageNumber, 10); 15 | 16 | var sut = source.ToPaginable(paginableInfo); 17 | 18 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 19 | } 20 | 21 | [Fact] 22 | public void ShouldEqualItemCountPerPage() 23 | { 24 | var source = Enumerable.Range(11, 100).AsQueryable(); 25 | var expectedItemCountPerPage = 12; 26 | var paginableInfo = new PaginableRequest(2, expectedItemCountPerPage); 27 | 28 | var sut = source.ToPaginable(paginableInfo); 29 | 30 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/EnumerableQueryablePaginableTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class EnumerableQueryablePaginableTests 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(10, 50); 13 | var expectedPageNumber = 2; 14 | 15 | var sut = source.ToPaginable(expectedPageNumber, itemCountPerPage: 10); 16 | 17 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 18 | } 19 | 20 | [Fact] 21 | public void ShouldEqualItemCountPerPage() 22 | { 23 | var source = Enumerable.Range(11, 100); 24 | var expectedItemCountPerPage = 12; 25 | 26 | var sut = source.ToPaginable(2, expectedItemCountPerPage); 27 | 28 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 29 | } 30 | 31 | [Fact] 32 | public void ShouldEqualTotalItemCount() 33 | { 34 | var expectedTotalItemCount = 25; 35 | var source = Enumerable.Range(11, expectedTotalItemCount); 36 | 37 | var sut = source.ToPaginable(2, 10); 38 | 39 | sut.TotalItemCount.ShouldBeEquivalentTo(expectedTotalItemCount); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/EnumerableStaticPaginableTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Tests 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class EnumerableStaticPaginableTests 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(11, 20); 13 | var expectedPageNumber = 2; 14 | 15 | var sut = source.ToPaginable(expectedPageNumber, 10, 100); 16 | 17 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 18 | } 19 | 20 | [Fact] 21 | public void ShouldEqualItemCountPerPage() 22 | { 23 | var source = Enumerable.Range(11, 20); 24 | var expectedItemCountPerPage = 12; 25 | 26 | var sut = source.ToPaginable(2, expectedItemCountPerPage, 100); 27 | 28 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 29 | } 30 | 31 | [Fact] 32 | public void ShouldEqualTotalItemCount() 33 | { 34 | var expectedTotalItemCount = 25; 35 | var source = Enumerable.Range(11, expectedTotalItemCount); 36 | 37 | var sut = source.ToPaginable(2, 10, expectedTotalItemCount); 38 | 39 | sut.TotalItemCount.ShouldBeEquivalentTo(expectedTotalItemCount); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNet45/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ConsoleAppDotNet45")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ConsoleAppDotNet45")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0a23a5a4-8f3f-4d07-a9eb-31aadb95c2e5")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /src/PaginableCollections/PaginableCollections.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A light weight pagination framework 5 | Copyright Nicholas Myers 6 | 3.3.0 7 | Nicholas Myers 8 | net45;netstandard1.3;netstandard2.0 9 | PaginableCollections 10 | PaginableCollections 11 | paginable;page;paging;queryable;collections;paginablecollections 12 | https://github.com/neekgreen/PaginableCollections 13 | git 14 | git://github.com/neekgreen/paginable-collections 15 | 3.3.0 16 | 17 | 18 | 19 | bin\ 20 | TRACE;DEBUG 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | all 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/PaginableCollections/StaticPaginable.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Encapsulates a collection of data. 9 | /// 10 | /// 11 | public class StaticPaginable : Paginable 12 | { 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | public StaticPaginable(IEnumerable subset, int pageNumber, int itemCountPerPage, int totalItemCount) 21 | { 22 | if (pageNumber < 1) 23 | throw new ArgumentOutOfRangeException(nameof(pageNumber)); 24 | 25 | if (itemCountPerPage < 1) 26 | throw new ArgumentOutOfRangeException(nameof(itemCountPerPage)); 27 | 28 | var list = subset as IList ?? subset.ToList(); 29 | if (list.Count > totalItemCount) 30 | throw new ArgumentOutOfRangeException(nameof(totalItemCount)); 31 | 32 | TotalItemCount = totalItemCount; 33 | PageNumber = pageNumber; 34 | ItemCountPerPage = itemCountPerPage; 35 | 36 | innerList.AddRange(list.ToPaginableItemList(pageNumber, itemCountPerPage)); 37 | 38 | if (innerList.Any()) 39 | { 40 | FirstItemNumber = innerList.First().ItemNumber; 41 | LastItemNumber = innerList.Last().ItemNumber; 42 | } 43 | else 44 | { 45 | FirstItemNumber = 0; 46 | LastItemNumber = 0; 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PaginableCollections 2 | ==================== 3 | 4 | [![Build status](https://ci.appveyor.com/api/projects/status/8hedo7ja62gaq022?svg=true)](https://ci.appveyor.com/project/neekgreen/paginablecollections) 5 | [![NuGet](https://img.shields.io/nuget/v/paginablecollections.svg)](https://www.nuget.org/packages/paginablecollections) 6 | [![NuGet](https://img.shields.io/nuget/dt/paginablecollections.svg)](https://www.nuget.org/packages/paginablecollections) 7 | [![CodeFactor](https://www.codefactor.io/repository/github/neekgreen/paginable-collections/badge)](https://www.codefactor.io/repository/github/neekgreen/paginablecollections) 8 | 9 | A light weight pagination framework for .NET and .NET Core. 10 | 11 | [![something](https://img.shields.io/badge/.NET-4.5-blue.svg)](https://img.shields.io/badge/.NET-4.5-blue.svg) 12 | [![something](https://img.shields.io/badge/.netstandard-1.3-blue.svg)](https://img.shields.io/badge/.netstandard-1.3-blue.svg) 13 | [![something](https://img.shields.io/badge/.netstandard-2.0-blue.svg)](https://img.shields.io/badge/.netstandard-1.3-blue.svg) 14 | 15 | ### Installing PaginableCollections 16 | 17 | You should install [PaginableCollections with NuGet](https://www.nuget.org/packages/paginablecollections): 18 | 19 | Install-Package PaginableCollections 20 | 21 | This command will download and install PaginableCollections. Let me know if you have questions! 22 | 23 | 24 | ## TD;DR 25 | 26 | ```csharp 27 | 28 | var numbers = new int[] { 2, 4, 5, 1, 6, 8, 2, 0, 4, 3, 4, 1, 5, 9, 7, 0, 2, 4, 8, 9 }; 29 | 30 | var pageNumber = 2; 31 | var itemCountPerPage = 6; 32 | 33 | var paginable = numbers.ToPaginable(pageNumber, itemCountPerPage); 34 | 35 | foreach(var t in paginable) 36 | { 37 | Console.WriteLine($"{t.ItemNumber}, {t.Item}"); 38 | } 39 | 40 | //output 41 | 1, 2 42 | 2, 0 43 | 3, 4 44 | 4, 3 45 | 5, 4 46 | 6, 1 47 | -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/StaticPaginableTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Facts 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class StaticPaginableFacts 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(11, 20); 13 | var expectedPageNumber = 2; 14 | 15 | IPaginable sut = new StaticPaginable(source, expectedPageNumber, 10, 100); 16 | 17 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 18 | } 19 | 20 | [Fact] 21 | public void ShouldEqualItemCountPerPage() 22 | { 23 | var source = Enumerable.Range(11, 20); 24 | var expectedItemCountPerPage = 12; 25 | 26 | var sut = new StaticPaginable(source, 2, expectedItemCountPerPage, 100); 27 | 28 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 29 | } 30 | 31 | [Fact] 32 | public void ShouldEqualTotalItemCount() 33 | { 34 | var expectedTotalItemCount = 25; 35 | var source = Enumerable.Range(11, expectedTotalItemCount); 36 | 37 | var sut = new StaticPaginable(source, 2, 10, expectedTotalItemCount); 38 | 39 | sut.TotalItemCount.ShouldBeEquivalentTo(expectedTotalItemCount); 40 | } 41 | 42 | [Fact] 43 | public void ShouldEqualFirstElementNextPage() 44 | { 45 | var source = Enumerable.Range(1, 100); 46 | var paginable = new StaticPaginable(source, 3, 10, 100); 47 | 48 | var sut = paginable.ElementAt(0); 49 | 50 | sut.ItemNumber.ShouldBeEquivalentTo(21); 51 | sut.Item.ShouldBeEquivalentTo(1); 52 | sut.PageNumber.ShouldBeEquivalentTo(3); 53 | sut.ItemCountPerPage.ShouldBeEquivalentTo(10); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/QueryablePaginableTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Facts 2 | { 3 | using System.Linq; 4 | using FluentAssertions; 5 | using Xunit; 6 | 7 | public class QueryablePaginableFacts 8 | { 9 | [Fact] 10 | public void ShouldEqualPageNumber() 11 | { 12 | var source = Enumerable.Range(10, 50).AsQueryable(); 13 | var expectedPageNumber = 2; 14 | 15 | var sut = new QueryableBasedPaginable(source, expectedPageNumber, 10); 16 | 17 | sut.PageNumber.ShouldBeEquivalentTo(expectedPageNumber); 18 | } 19 | 20 | [Fact] 21 | public void ShouldEqualItemCountPerPage() 22 | { 23 | var source = Enumerable.Range(11, 100).AsQueryable(); 24 | var expectedItemCountPerPage = 12; 25 | 26 | var sut = new QueryableBasedPaginable(source, 2, expectedItemCountPerPage); 27 | 28 | sut.ItemCountPerPage.ShouldBeEquivalentTo(expectedItemCountPerPage); 29 | } 30 | 31 | [Fact] 32 | public void ShouldEqualTotalItemCount() 33 | { 34 | var expectedTotalItemCount = 25; 35 | var source = Enumerable.Range(11, expectedTotalItemCount).AsQueryable(); 36 | 37 | var sut = new QueryableBasedPaginable(source, 2, 10); 38 | 39 | sut.TotalItemCount.ShouldBeEquivalentTo(expectedTotalItemCount); 40 | } 41 | 42 | [Fact] 43 | public void ShouldEqualFirstElementNextPage() 44 | { 45 | var source = Enumerable.Range(1, 100).AsQueryable(); 46 | var paginable = new QueryableBasedPaginable(source, 3, 10); 47 | 48 | var sut = paginable.ElementAt(0); 49 | 50 | sut.ItemNumber.ShouldBeEquivalentTo(21); 51 | sut.Item.ShouldBeEquivalentTo(21); 52 | sut.PageNumber.ShouldBeEquivalentTo(3); 53 | sut.ItemCountPerPage.ShouldBeEquivalentTo(10); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /tests/PaginableCollections.Tests/PagerItemTests.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections.Facts 2 | { 3 | using FluentAssertions; 4 | using Xunit; 5 | 6 | public class StaticPagerPageFacts 7 | { 8 | [Fact] 9 | public void ShouldSetPageNumber() 10 | { 11 | var pageNumber = 1; 12 | var sut = new PagerItem(pageNumber, 10); 13 | 14 | sut.PageNumber.ShouldBeEquivalentTo(pageNumber); 15 | } 16 | 17 | [Fact] 18 | public void ShouldSetIsFirstPage() 19 | { 20 | var pageNumber = 1; 21 | var sut = new PagerItem(pageNumber, 10); 22 | 23 | sut.IsFirstPage.ShouldBeEquivalentTo(true); 24 | } 25 | 26 | [Fact] 27 | public void ShouldSetIsPreviousPage() 28 | { 29 | var pageNumber = 1; 30 | var sut = new PagerItem(pageNumber, 10); 31 | 32 | sut.HasPreviousPage.ShouldBeEquivalentTo(false); 33 | } 34 | 35 | [Fact] 36 | public void ShouldSetHasNextPage() 37 | { 38 | var pageNumber = 1; 39 | var sut = new PagerItem(pageNumber, 10); 40 | 41 | sut.HasNextPage.ShouldBeEquivalentTo(true); 42 | } 43 | 44 | [Fact] 45 | public void ShouldSetTotalPageCount() 46 | { 47 | var totalPageCount = 1; 48 | var sut = new PagerItem(1, totalPageCount); 49 | 50 | sut.TotalPageCount.ShouldBeEquivalentTo(totalPageCount); 51 | } 52 | 53 | [Fact] 54 | public void ShouldBeLastPage() 55 | { 56 | var totalPageCount = 10; 57 | var sut = new PagerItem(totalPageCount, totalPageCount); 58 | 59 | sut.IsLastPage.ShouldBeEquivalentTo(true); 60 | } 61 | 62 | [Fact] 63 | public void ShouldBeHasNextPage() 64 | { 65 | var totalPageCount = 10; 66 | var sut = new PagerItem(totalPageCount, totalPageCount); 67 | 68 | sut.HasNextPage.ShouldBeEquivalentTo(false); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/PaginableCollections/StaticPager.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class StaticPager : IPager 6 | { 7 | private readonly IList pages; 8 | 9 | public StaticPager(IPaginable paginable, int maximumPageNumberCount) 10 | { 11 | MaximumPageNumberCount = maximumPageNumberCount; 12 | TotalPageCount = paginable.TotalPageCount; 13 | 14 | var firstPageToDisplay = 1; 15 | var lastPageToDisplay = paginable.TotalPageCount; 16 | var pageNumbersToDisplay = lastPageToDisplay; 17 | 18 | if (paginable.TotalPageCount > maximumPageNumberCount) 19 | { 20 | var maxPageNumbersToDisplay = maximumPageNumberCount; 21 | firstPageToDisplay = paginable.PageNumber - (maxPageNumbersToDisplay / 2); 22 | if (firstPageToDisplay < 1) 23 | { 24 | firstPageToDisplay = 1; 25 | } 26 | pageNumbersToDisplay = maxPageNumbersToDisplay; 27 | lastPageToDisplay = firstPageToDisplay + pageNumbersToDisplay - 1; 28 | if (lastPageToDisplay > paginable.TotalPageCount) 29 | { 30 | firstPageToDisplay = paginable.TotalPageCount - maxPageNumbersToDisplay + 1; 31 | } 32 | } 33 | 34 | var totalPageNumber = paginable.TotalPageCount; 35 | if (totalPageNumber == 0) 36 | { 37 | totalPageNumber = 1; 38 | } 39 | 40 | pages = new List(); 41 | 42 | for (int i = firstPageToDisplay; i <= firstPageToDisplay + pageNumbersToDisplay - 1; i++) 43 | { 44 | pages.Add(new PagerItem(i, totalPageNumber)); 45 | } 46 | } 47 | 48 | IEnumerable IPager.GetPages() 49 | { 50 | return pages; 51 | } 52 | 53 | public int TotalPageCount { get; private set; } 54 | public int MaximumPageNumberCount { get; private set; } 55 | } 56 | } -------------------------------------------------------------------------------- /src/PaginableCollections/QueryableBasedPaginable.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// This paginable that uses the underlying data source to calculate pagination statistics. 9 | /// 10 | /// 11 | public class QueryableBasedPaginable : Paginable 12 | { 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | public QueryableBasedPaginable(IQueryable queryable, int pageNumber, int itemCountPerPage) 20 | { 21 | if (pageNumber < 1) 22 | throw new ArgumentOutOfRangeException(nameof(pageNumber)); 23 | 24 | if (itemCountPerPage < 1) 25 | throw new ArgumentOutOfRangeException(nameof(itemCountPerPage)); 26 | 27 | TotalItemCount = queryable?.Count() ?? 0; 28 | PageNumber = pageNumber; 29 | ItemCountPerPage = itemCountPerPage; 30 | 31 | if (TotalItemCount > 0) 32 | { 33 | innerList.AddRange(queryable 34 | .Skip((pageNumber - 1) * ItemCountPerPage) 35 | .Take(ItemCountPerPage) 36 | .ToPaginableItemList(pageNumber, itemCountPerPage)); 37 | } 38 | 39 | if (innerList.Any()) 40 | { 41 | FirstItemNumber = innerList.First().ItemNumber; 42 | LastItemNumber = innerList.Last().ItemNumber; 43 | } 44 | else 45 | { 46 | FirstItemNumber = 0; 47 | LastItemNumber = 0; 48 | } 49 | } 50 | 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | public QueryableBasedPaginable(IEnumerable superset, int pageNumber, int itemCountPerPage) 58 | : this(superset.AsQueryable(), pageNumber, itemCountPerPage) { } 59 | } 60 | } -------------------------------------------------------------------------------- /src/PaginableCollections/IPaginable.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Non-generic contract representing a page of data. 8 | /// 9 | public interface IPaginable : IEnumerable 10 | { 11 | /// 12 | /// Total number of pages. 13 | /// 14 | int TotalPageCount { get; } 15 | 16 | /// 17 | /// Total item count. 18 | /// 19 | int TotalItemCount { get; } 20 | 21 | /// 22 | /// Current page number. 23 | /// 24 | int PageNumber { get; } 25 | 26 | /// 27 | /// Requested item count per page. 28 | /// 29 | int ItemCountPerPage { get; } 30 | 31 | /// 32 | /// Identifies the first page. 33 | /// 34 | bool IsFirstPage { get; } 35 | 36 | /// 37 | /// Identifies the last page. 38 | /// 39 | bool IsLastPage { get; } 40 | 41 | /// 42 | /// Identifies if there is a previous page. 43 | /// 44 | bool HasPreviousPage { get; } 45 | 46 | /// 47 | /// Identifies if there is a next page. 48 | /// 49 | bool HasNextPage { get; } 50 | 51 | /// 52 | /// The first item number of the page. 53 | /// 54 | int FirstItemNumber { get; } 55 | 56 | /// 57 | /// The last item number of this page. 58 | /// 59 | int LastItemNumber { get; } 60 | } 61 | 62 | /// 63 | /// Generic contract representing a page of data. 64 | /// 65 | /// 66 | public interface IPaginable : IEnumerable>, IPaginable 67 | { 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | IPaginableItem this[int index] { get; } 74 | 75 | /// 76 | /// Number of items in this paginable. 77 | /// 78 | int Count { get; } 79 | } 80 | } -------------------------------------------------------------------------------- /src/PaginableCollections/PaginableExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | public static class PaginableExtensions 7 | { 8 | /// 9 | /// Convert queryable to paginable. 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | public static IPaginable ToPaginable(this IQueryable queryable, int pageNumber, int itemCountPerPage) 17 | { 18 | return new QueryableBasedPaginable(queryable, pageNumber, itemCountPerPage); 19 | } 20 | 21 | /// 22 | /// Convert queryable to paginable. 23 | /// 24 | /// 25 | /// 26 | /// 27 | /// 28 | public static IPaginable ToPaginable(this IQueryable queryable, IPaginableRequest paginableRequest) 29 | { 30 | return queryable.ToPaginable(paginableRequest.PageNumber, paginableRequest.ItemCountPerPage); 31 | } 32 | 33 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public static IPager ToPager(this IPaginable paginable, int maximumPageNumberCount) 40 | { 41 | return new StaticPager(paginable, maximumPageNumberCount); 42 | } 43 | 44 | /// 45 | /// 46 | /// 47 | /// 48 | /// 49 | /// 50 | /// 51 | /// 52 | internal static IEnumerable> ToPaginableItemList(this IEnumerable t, int pageNumber, int itemCountPerPage) 53 | { 54 | var offset = (pageNumber - 1) * itemCountPerPage; 55 | var list = t as IList ?? t.ToList(); 56 | for (var i = 0; i < list.Count; i++) 57 | { 58 | yield return new PaginableItem(list[i], offset + 1, pageNumber, itemCountPerPage); 59 | offset++; 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /samples/ConsoleAppDotNet45/ConsoleAppDotNet45.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5} 8 | Exe 9 | ConsoleAppDotNet45 10 | ConsoleAppDotNet45 11 | v4.5 12 | 512 13 | 14 | 15 | AnyCPU 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | AnyCPU 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {8f6c7555-710f-443f-a5ca-bf50fc37484d} 53 | PaginableCollections 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at neekgreen@users.noreply.github.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/PaginableCollections/Paginable.cs: -------------------------------------------------------------------------------- 1 | namespace PaginableCollections 2 | { 3 | using System; 4 | using System.Collections; 5 | using System.Collections.Generic; 6 | 7 | /// 8 | /// Base class represents page of items. 9 | /// 10 | /// The type of items in this paginable. 11 | public abstract class Paginable : IPaginable 12 | { 13 | protected readonly List> innerList = new List>(); 14 | 15 | /// 16 | /// 17 | /// 18 | /// 19 | IEnumerator IEnumerable.GetEnumerator() 20 | { 21 | return innerList.GetEnumerator(); 22 | } 23 | 24 | IEnumerator> IEnumerable>.GetEnumerator() 25 | { 26 | return innerList.GetEnumerator(); 27 | } 28 | 29 | /// 30 | /// Total number of items. 31 | /// 32 | public int TotalItemCount { get; protected set; } 33 | 34 | /// 35 | /// Requested page number. 36 | /// 37 | public int PageNumber { get; protected set; } 38 | 39 | /// 40 | /// Requested number of items per page. 41 | /// 42 | public int ItemCountPerPage { get; protected set; } 43 | 44 | /// 45 | /// 46 | /// 47 | /// 48 | /// 49 | IPaginableItem IPaginable.this[int index] => innerList[index]; 50 | 51 | /// 52 | /// Number of items in this result set. 53 | /// 54 | public int Count => innerList.Count; 55 | 56 | /// 57 | /// Total number of pages. 58 | /// 59 | public int TotalPageCount => 60 | TotalItemCount > 0 ? (int)Math.Ceiling(TotalItemCount / (double)ItemCountPerPage) : 0; 61 | 62 | /// 63 | /// Identifies the first page. 64 | /// 65 | public bool IsFirstPage => PageNumber == 1; 66 | 67 | /// 68 | /// Identifies the last page. 69 | /// 70 | public bool IsLastPage => PageNumber >= TotalPageCount; 71 | 72 | /// 73 | /// Identifies if a previous page is available. 74 | /// 75 | public bool HasPreviousPage => PageNumber > 1; 76 | 77 | /// 78 | /// Identifies if a next page is available. 79 | /// 80 | public bool HasNextPage => PageNumber < TotalPageCount; 81 | 82 | /// 83 | /// Identifies the first item number of the page. 84 | /// 85 | public int FirstItemNumber { get; protected set; } 86 | 87 | /// 88 | /// Identifies the last item number of the page. 89 | /// 90 | public int LastItemNumber { get; protected set; } 91 | } 92 | 93 | 94 | /// 95 | /// 96 | /// 97 | public static class Paginable 98 | { 99 | /// 100 | /// Returns new empty paginable collection. 101 | /// 102 | /// 103 | public static IPaginable Empty() 104 | { 105 | return new EmptyPaginable(); 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /PaginableCollections.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26730.3 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{B15992BA-EB0A-4096-BA64-A7E1B7F6FA32}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{50BAA0E6-841D-4678-9679-38A2A3456F60}" 9 | ProjectSection(SolutionItems) = preProject 10 | appveyor.yml = appveyor.yml 11 | build.cake = build.cake 12 | EndProjectSection 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaginableCollections", "src\PaginableCollections\PaginableCollections.csproj", "{8F6C7555-710F-443F-A5CA-BF50FC37484D}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PaginableCollections.Tests", "tests\PaginableCollections.Tests\PaginableCollections.Tests.csproj", "{1834508B-44C8-44AD-83F2-19ACEE028AAF}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleAppDotNet45", "samples\ConsoleAppDotNet45\ConsoleAppDotNet45.csproj", "{0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5}" 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{FC4DDD23-0F50-4F65-AA6D-DB5D2657C4D3}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppDotNetCore20", "samples\ConsoleAppDotNetCore20\ConsoleAppDotNetCore20.csproj", "{AF24831C-3E29-4CA4-A209-DD97C5203E5F}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleAppDotNetCore11", "samples\ConsoleAppDotNetCore11\ConsoleAppDotNetCore11.csproj", "{48954628-76B2-4736-95F3-D2F508330893}" 25 | EndProject 26 | Global 27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 28 | Debug|Any CPU = Debug|Any CPU 29 | Release|Any CPU = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {8F6C7555-710F-443F-A5CA-BF50FC37484D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {8F6C7555-710F-443F-A5CA-BF50FC37484D}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {8F6C7555-710F-443F-A5CA-BF50FC37484D}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {8F6C7555-710F-443F-A5CA-BF50FC37484D}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {1834508B-44C8-44AD-83F2-19ACEE028AAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {1834508B-44C8-44AD-83F2-19ACEE028AAF}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {1834508B-44C8-44AD-83F2-19ACEE028AAF}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {1834508B-44C8-44AD-83F2-19ACEE028AAF}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {AF24831C-3E29-4CA4-A209-DD97C5203E5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {AF24831C-3E29-4CA4-A209-DD97C5203E5F}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {AF24831C-3E29-4CA4-A209-DD97C5203E5F}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {AF24831C-3E29-4CA4-A209-DD97C5203E5F}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {48954628-76B2-4736-95F3-D2F508330893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {48954628-76B2-4736-95F3-D2F508330893}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {48954628-76B2-4736-95F3-D2F508330893}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {48954628-76B2-4736-95F3-D2F508330893}.Release|Any CPU.Build.0 = Release|Any CPU 52 | EndGlobalSection 53 | GlobalSection(SolutionProperties) = preSolution 54 | HideSolutionNode = FALSE 55 | EndGlobalSection 56 | GlobalSection(NestedProjects) = preSolution 57 | {1834508B-44C8-44AD-83F2-19ACEE028AAF} = {B15992BA-EB0A-4096-BA64-A7E1B7F6FA32} 58 | {0A23A5A4-8F3F-4D07-A9EB-31AADB95C2E5} = {FC4DDD23-0F50-4F65-AA6D-DB5D2657C4D3} 59 | {AF24831C-3E29-4CA4-A209-DD97C5203E5F} = {FC4DDD23-0F50-4F65-AA6D-DB5D2657C4D3} 60 | {48954628-76B2-4736-95F3-D2F508330893} = {FC4DDD23-0F50-4F65-AA6D-DB5D2657C4D3} 61 | EndGlobalSection 62 | GlobalSection(ExtensibilityGlobals) = postSolution 63 | SolutionGuid = {BF46CCCA-4A7A-42C2-BB58-2A5A43DBFC87} 64 | EndGlobalSection 65 | EndGlobal 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | 83 | # Visual Studio profiler 84 | *.psess 85 | *.vsp 86 | *.vspx 87 | *.sap 88 | 89 | # TFS 2012 Local Workspace 90 | $tf/ 91 | 92 | # Guidance Automation Toolkit 93 | *.gpState 94 | 95 | # ReSharper is a .NET coding add-in 96 | _ReSharper*/ 97 | *.[Rr]e[Ss]harper 98 | *.DotSettings.user 99 | 100 | # JustCode is a .NET coding add-in 101 | .JustCode 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | _NCrunch_* 111 | .*crunch*.local.xml 112 | nCrunchTemp_* 113 | 114 | # MightyMoose 115 | *.mm.* 116 | AutoTest.Net/ 117 | 118 | # Web workbench (sass) 119 | .sass-cache/ 120 | 121 | # Installshield output folder 122 | [Ee]xpress/ 123 | 124 | # DocProject is a documentation generator add-in 125 | DocProject/buildhelp/ 126 | DocProject/Help/*.HxT 127 | DocProject/Help/*.HxC 128 | DocProject/Help/*.hhc 129 | DocProject/Help/*.hhk 130 | DocProject/Help/*.hhp 131 | DocProject/Help/Html2 132 | DocProject/Help/html 133 | 134 | # Click-Once directory 135 | publish/ 136 | 137 | # Publish Web Output 138 | *.[Pp]ublish.xml 139 | *.azurePubxml 140 | # TODO: Comment the next line if you want to checkin your web deploy settings 141 | # but database connection strings (with potential passwords) will be unencrypted 142 | *.pubxml 143 | *.publishproj 144 | 145 | # NuGet Packages 146 | *.nupkg 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Azure Emulator 159 | ecf/ 160 | rcf/ 161 | 162 | # Windows Store app package directory 163 | AppPackages/ 164 | 165 | # Visual Studio cache files 166 | # files ending in .cache can be ignored 167 | *.[Cc]ache 168 | # but keep track of directories ending in .cache 169 | !*.[Cc]ache/ 170 | 171 | # Others 172 | ClientBin/ 173 | [Ss]tyle[Cc]op.* 174 | ~$* 175 | *~ 176 | *.dbmdl 177 | *.dbproj.schemaview 178 | *.pfx 179 | *.publishsettings 180 | node_modules/ 181 | orleans.codegen.cs 182 | 183 | # RIA/Silverlight projects 184 | Generated_Code/ 185 | 186 | # Backup & report files from converting an old project file 187 | # to a newer Visual Studio version. Backup files are not needed, 188 | # because we have git ;-) 189 | _UpgradeReport_Files/ 190 | Backup*/ 191 | UpgradeLog*.XML 192 | UpgradeLog*.htm 193 | 194 | # SQL Server files 195 | *.mdf 196 | *.ldf 197 | 198 | # Business Intelligence projects 199 | *.rdl.data 200 | *.bim.layout 201 | *.bim_*.settings 202 | 203 | # Microsoft Fakes 204 | FakesAssemblies/ 205 | 206 | # GhostDoc plugin setting file 207 | *.GhostDoc.xml 208 | 209 | # Node.js Tools for Visual Studio 210 | .ntvs_analysis.dat 211 | 212 | # Visual Studio 6 build log 213 | *.plg 214 | 215 | # Visual Studio 6 workspace options file 216 | *.opt 217 | 218 | # Visual Studio LightSwitch build output 219 | **/*.HTMLClient/GeneratedArtifacts 220 | **/*.DesktopClient/GeneratedArtifacts 221 | **/*.DesktopClient/ModelManifest.xml 222 | **/*.Server/GeneratedArtifacts 223 | **/*.Server/ModelManifest.xml 224 | _Pvt_Extensions 225 | 226 | # Paket dependency manager 227 | .paket/paket.exe 228 | 229 | # FAKE - F# Make 230 | .fake/ 231 | 232 | # VSCode 233 | .dotnet/ 234 | 235 | tools/* 236 | !tools/packages.config --------------------------------------------------------------------------------