diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a05b287 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# IDE0011: Add braces +csharp_prefer_braces = when_multiline diff --git a/Paginator.sln b/Paginator.sln index 5c9b300..c051370 100644 --- a/Paginator.sln +++ b/Paginator.sln @@ -5,10 +5,11 @@ VisualStudioVersion = 16.0.29006.145 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Paginator", "src\Paginator.csproj", "{372B4525-5399-4792-BBC7-33BB8897F191}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnitTests", "tests\TestCases.csproj", "{48A1CCEB-85F0-4091-8B9F-154D61AF1D5A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestCases", "tests\TestCases.csproj", "{48A1CCEB-85F0-4091-8B9F-154D61AF1D5A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5A9AA53E-5B35-419C-BBCA-C42DD98FBE71}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore _config.yml = _config.yml diff --git a/Tests/IEnumerableTests.cs b/Tests/IEnumerableTests.cs index 30a0763..cc7b288 100644 --- a/Tests/IEnumerableTests.cs +++ b/Tests/IEnumerableTests.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using Paginator; using System.Linq; -using System; -using Common; namespace Tests { @@ -41,8 +39,8 @@ public void Empty(ICollection Rates) public void FuncTest(ICollection nums) { int perpage = 5; - - var result = nums.Paged(x => x.Matches("0"), 2, perpage); + + var result = nums.Paged(x => x.Equals("0"), 2, perpage, x => x); int pages = GetPages(result.TotalItems, perpage); Assert.AreEqual(2, result.Page); @@ -53,24 +51,12 @@ public void FuncTest(ICollection nums) [Test, TestCaseSource(typeof(Seed), "Pages")] public void OrderByProperty(ICollection Rates) { - var result = Rates.ToPaginate(null, 1, 10, "Value", "desc"); + var result = Rates.ToPaginate(null, 1, 10, x=>x.Value, "desc"); Assert.IsNotNull(result); Assert.AreEqual(1, result.Page); Assert.AreEqual(Rates.Count, result.TotalItems); Assert.Greater(result.Items.First().Value, result.Items.Last().Value); - result.Items.ForEach(x => - { - Console.WriteLine(x.Value); - }); - } - - [Test, TestCaseSource(typeof(Seed), "Pages")] - public void NullRequestTest(ICollection list) - { - var result = list.ToPages(null); - - Assert.AreEqual(1, result.Page); } } } \ No newline at end of file diff --git a/Tests/IQueryableTests.cs b/Tests/IQueryableTests.cs index 5107e7f..3a29793 100644 --- a/Tests/IQueryableTests.cs +++ b/Tests/IQueryableTests.cs @@ -38,21 +38,12 @@ public void Empty(ICollection Rates) public void FuncTest(ICollection Rates) { var result = Rates.AsQueryable() - .Paged(x => x.Value > 9, 2, 2); + .Paged(x => x.Value > 9, 2, 2, x => x.Value); Assert.NotNull(result); Assert.AreEqual(2, result.Page); Assert.AreEqual(2, result.ItemsPerPage); Assert.AreEqual(Rates.Count(x => x.Value > 9), result.TotalItems); } - - [Test, TestCaseSource(typeof(Seed), "Pages")] - public void NullRequestTest(ICollection list) - { - var result = list.AsQueryable() - .ToPages(null); - - Assert.AreEqual(1, result.Page); - } } } \ No newline at end of file diff --git a/src/PagedResult.cs b/src/PagedResult.cs index 644000d..9199284 100644 --- a/src/PagedResult.cs +++ b/src/PagedResult.cs @@ -22,7 +22,7 @@ public class PagedResult /// public PagedResult() { - Items = new HashSet(); + Items = new List(); } /// /// Current page in pagination @@ -45,7 +45,7 @@ public PagedResult() /// /// Collection containing items in the current page. /// - public ICollection Items { get; set; } + public IList Items { get; set; } /// /// Calculates & returns the hashcode of the current object. diff --git a/src/Paginator.cs b/src/Paginator.cs index 5c3a690..9a4cf24 100644 --- a/src/Paginator.cs +++ b/src/Paginator.cs @@ -1,5 +1,4 @@ -using Common; -using System; +using System; using System.Collections.Generic; using System.Linq; @@ -18,6 +17,7 @@ public static class Paginator /// Number of items to return per page. /// private const int _perpage = 10; + private const bool _skipCount = false; #region .Paginate Methods /// @@ -35,39 +35,43 @@ public static PagedResult Paginate(this IEnumerable enumerable) /// Type of entity in collection. /// The page to retrive /// Number of items per page. + /// Whether to avoid running count query & only get required items. /// The current collection. /// . - public static PagedResult Paginate(this IEnumerable enumerable, - int page=_page, int perpage=_perpage) - where T : class - => enumerable.ProcessPagination(page, perpage); + public static PagedResult Paginate(this IEnumerable enumerable, + int page = _page, int perpage = _perpage, bool skipCount = _skipCount) + where T : class + => enumerable.ProcessPagination(page, perpage, skipCount); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// A filter to apply to the collection before pagination. /// The current collection. /// . - public static PagedResult Paginate(this IEnumerable enumerable, Func predicate) + public static PagedResult Paginate(this IEnumerable enumerable, Func predicate) where T : class - => enumerable.ProcessPagination(predicate); + => enumerable.ProcessPagination2(predicate); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. /// Number of items per page. /// . - public static PagedResult Paginate(this IEnumerable enumerable, Func predicate, + public static PagedResult Paginate(this IEnumerable enumerable, Func predicate, int page = _page, int perpage = _perpage) where T : class - => enumerable.ProcessPagination(predicate, page, perpage); + => enumerable.ProcessPagination2(predicate, page, perpage); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. @@ -75,10 +79,10 @@ public static PagedResult Paginate(this IEnumerable enumerable, FuncProperty to order by /// Ordering type e.g asc or desc /// . - public static PagedResult Paginate(this IEnumerable enumerable, Func predicate, - int page = _page, int perpage = _perpage, string orderBy = null, string order = "asc") + public static PagedResult Paginate(this IEnumerable enumerable, Func predicate, + int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class - => enumerable.ProcessPagination(predicate, page, perpage, orderBy, order); + => enumerable.ProcessPagination2(predicate, page, perpage, orderBy, order); #endregion #region .Page Methods @@ -107,29 +111,32 @@ public static PagedResult Page(this IEnumerable enumerable) /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// . - public static PagedResult Page(this IEnumerable enumerable, Func predicate) + public static PagedResult Page(this IEnumerable enumerable, Func predicate) where T : class - => enumerable.ProcessPagination(predicate); + => enumerable.ProcessPagination2(predicate); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. /// Number of items per page. /// . - public static PagedResult Page(this IEnumerable enumerable, Func predicate, + public static PagedResult Page(this IEnumerable enumerable, Func predicate, int page = _page, int perpage = _perpage) where T : class - => enumerable.ProcessPagination(predicate, page, perpage); + => enumerable.ProcessPagination2(predicate, page, perpage); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. @@ -137,10 +144,10 @@ public static PagedResult Page(this IEnumerable enumerable, FuncProperty to order by /// Ordering type e.g asc or desc /// . - public static PagedResult Page(this IEnumerable enumerable, Func predicate, - int page = _page, int perpage = _perpage, string orderBy = null, string order = "asc") + public static PagedResult Page(this IEnumerable enumerable, Func predicate, + int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class - => enumerable.ProcessPagination(predicate, page, perpage, orderBy, order); + => enumerable.ProcessPagination2(predicate, page, perpage, orderBy, order); #endregion #region .Paged Methods @@ -150,6 +157,7 @@ public static PagedResult Page(this IEnumerable enumerable, FuncType of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Paged(this IEnumerable enumerable) where T : class => enumerable.ProcessPagination(_page, _perpage); @@ -161,6 +169,7 @@ public static PagedResult Paged(this IEnumerable enumerable) /// The page to retrieve. /// Number of items per page. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Paged(this IEnumerable enumerable, int page = _page, int perpage = _perpage) where T : class @@ -169,29 +178,34 @@ public static PagedResult Paged(this IEnumerable enumerable) /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// . - public static PagedResult Paged(this IEnumerable enumerable, Func predicate) + [Obsolete("Use .Paginate instead")] + public static PagedResult Paged(this IEnumerable enumerable, Func predicate) where T : class - => enumerable.ProcessPagination(predicate); + => enumerable.ProcessPagination2(predicate); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. /// Number of items per page. /// . - public static PagedResult Paged(this IEnumerable enumerable, Func predicate, + [Obsolete("Use .Paginate instead")] + public static PagedResult Paged(this IEnumerable enumerable, Func predicate, int page = _page, int perpage = _perpage) where T : class - => enumerable.ProcessPagination(predicate, page, perpage); + => enumerable.ProcessPagination2(predicate, page, perpage); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. @@ -199,10 +213,11 @@ public static PagedResult Paged(this IEnumerable enumerable, FuncProperty to order by /// Ordering type e.g asc or desc /// . - public static PagedResult Paged(this IEnumerable enumerable, Func predicate, - int page = _page, int perpage = _perpage, string orderBy = null, string order = "asc") + [Obsolete("Use .Paginate instead")] + public static PagedResult Paged(this IEnumerable enumerable, Func predicate, + int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class - => enumerable.ProcessPagination(predicate, page, perpage, orderBy, order); + => enumerable.ProcessPagination2(predicate, page, perpage, orderBy, order); #endregion #region .ToPages Methods @@ -212,6 +227,7 @@ public static PagedResult Paged(this IEnumerable enumerable, FuncType of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPages(this IEnumerable enumerable) where T : class => enumerable.ProcessPagination(_page, _perpage); @@ -223,6 +239,7 @@ public static PagedResult ToPages(this IEnumerable enumerable) /// The page to retrieve. /// Number of items per page. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPages(this IEnumerable enumerable, int page = _page, int perpage = _perpage) where T : class @@ -231,29 +248,34 @@ public static PagedResult ToPages(this IEnumerable enumerable) /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// . - public static PagedResult ToPages(this IEnumerable enumerable, Func predicate) + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPages(this IEnumerable enumerable, Func predicate) where T : class - => enumerable.ProcessPagination(predicate); + => enumerable.ProcessPagination2(predicate); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. /// Number of items per page. /// . - public static PagedResult ToPages(this IEnumerable enumerable, Func predicate, + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPages(this IEnumerable enumerable, Func predicate, int page = _page, int perpage = _perpage) where T : class - => enumerable.ProcessPagination(predicate, page, perpage); + => enumerable.ProcessPagination2(predicate, page, perpage); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. @@ -261,10 +283,11 @@ public static PagedResult ToPages(this IEnumerable enumerable, FuncProperty to order by /// Ordering type e.g asc or desc /// . - public static PagedResult ToPages(this IEnumerable enumerable, Func predicate, - int page = _page, int perpage = _perpage, string orderBy = null, string order = "asc") + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPages(this IEnumerable enumerable, Func predicate, + int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class - => enumerable.ProcessPagination(predicate, page, perpage, orderBy, order); + => enumerable.ProcessPagination2(predicate, page, perpage, orderBy, order); #endregion #region .ToPaginate Methods @@ -274,6 +297,7 @@ public static PagedResult ToPages(this IEnumerable enumerable, FuncType of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPaginate(this IEnumerable enumerable) where T : class => enumerable.ProcessPagination(_page, _perpage); @@ -285,6 +309,7 @@ public static PagedResult ToPaginate(this IEnumerable enumerable) /// The page to retrieve. /// Number of items per page. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPaginate(this IEnumerable enumerable, int page = _page, int perpage = _perpage) where T : class @@ -293,29 +318,34 @@ public static PagedResult ToPaginate(this IEnumerable enumerable) /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// . - public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate) + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate) where T : class - => enumerable.ProcessPagination(predicate); + => enumerable.ProcessPagination2(predicate); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. /// Number of items per page. /// . - public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate, + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate, int page = _page, int perpage = _perpage) where T : class - => enumerable.ProcessPagination(predicate, page, perpage); + => enumerable.ProcessPagination2(predicate, page, perpage); /// /// Paginate this collection into pages of (x) items each and returns only the first subset. /// /// Type of entity in collection. + /// Type of the property to order by. /// The current collection. /// A filter to apply to the collection before pagination. /// The page to retrieve. @@ -323,10 +353,11 @@ public static PagedResult ToPaginate(this IEnumerable enumerable, Func< /// Property to order by /// Ordering type e.g asc or desc /// . - public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate, - int page = _page, int perpage = _perpage, string orderBy = null, string order = "asc") + [Obsolete("Use .Paginate instead")] + public static PagedResult ToPaginate(this IEnumerable enumerable, Func predicate, + int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class - => enumerable.ProcessPagination(predicate, page, perpage, orderBy, order); + => enumerable.ProcessPagination2(predicate, page, perpage, orderBy, order); #endregion #region IQueryable Methods @@ -336,6 +367,7 @@ public static PagedResult ToPaginate(this IEnumerable enumerable, Func< /// Type of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Page(this IQueryable entities) where TEntity : class => entities.ProcessPagination(_page, _perpage); @@ -347,6 +379,7 @@ public static PagedResult Page(this IQueryable entiti /// Number of items per page. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Page(this IQueryable entities, int page = _page, int perpage = _perpage) where TEntity : class @@ -357,6 +390,7 @@ public static PagedResult Page(this IQueryable entiti /// Type of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Paged(this IQueryable entities) where TEntity : class => entities.ProcessPagination(_page, _perpage); @@ -368,6 +402,7 @@ public static PagedResult Paged(this IQueryable entit /// Number of items per page. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult Paged(this IQueryable entities, int page = _page, int perpage = _perpage) where TEntity : class @@ -378,6 +413,7 @@ public static PagedResult Paged(this IQueryable entit /// Type of entity in collection. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPages(this IQueryable entities) where TEntity : class => entities.ProcessPagination(_page, _perpage); @@ -389,6 +425,7 @@ public static PagedResult ToPages(this IQueryable ent /// Number of items per page. /// The current collection. /// . + [Obsolete("Use .Paginate instead")] public static PagedResult ToPages(this IQueryable entities, int page = _page, int perpage = _perpage) where TEntity : class @@ -408,18 +445,29 @@ public static PagedResult Paginate(this IQueryable en /// Type of entity in collection. /// The page to retrive /// Number of items per page. + /// Whether to avoid running count query & only get required items. /// The current collection. /// . public static PagedResult Paginate(this IQueryable entities, - int page = _page, int perpage = _perpage) + int page = _page, int perpage = _perpage, bool skipCount = _skipCount) where TEntity : class - => entities.ProcessPagination(page, perpage); + => entities.ProcessPagination(page, perpage, skipCount); #endregion - internal static PagedResult ProcessPagination(this IQueryable entities, - int page = _page, int perpage = _perpage) + internal static PagedResult ProcessPagination(this IQueryable query, + int page = _page, int perpage = _perpage, bool skipCount = _skipCount) { - int total = entities.CountEntities(); + int total = 0; + var list = new List(); + + if (!skipCount) + total = query.CountEntities(); + + if (skipCount || (!skipCount && total > 0)) + list = query.Skip((page - 1) * perpage).Take(perpage).ToList(); + + if (skipCount) + total = list.Count; return new PagedResult() { @@ -427,13 +475,23 @@ public static PagedResult Paginate(this IQueryable en ItemsPerPage = perpage, TotalItems = total, TotalPages = CalculateTotalPages(total, perpage), - Items = entities.Skip((page - 1) * perpage).Take(perpage).ToList() + Items = list }; } internal static PagedResult ProcessPagination(this IEnumerable enumerable, - int page = _page, int perpage = _perpage) + int page = _page, int perpage = _perpage, bool skipCount = _skipCount) { - int total = enumerable.CountItems(); + int total = 0; + var list = new List(); + + if (!skipCount) + total = enumerable.CountItems(); + + if (skipCount || (!skipCount && total > 0)) + list = enumerable.Skip((page - 1) * perpage).Take(perpage).ToList(); + + if (skipCount) + total = list.Count; return new PagedResult() { @@ -441,25 +499,24 @@ public static PagedResult Paginate(this IQueryable en ItemsPerPage = perpage, TotalItems = total, TotalPages = CalculateTotalPages(total, perpage), - Items = enumerable.Skip((page - 1) * perpage).Take(perpage).ToList() + Items = list }; } - internal static PagedResult ProcessPagination(this IEnumerable enumerable, - Func predicate=null, int page = _page, int perpage = _perpage, string orderBy = null, + internal static PagedResult ProcessPagination2(this IEnumerable enumerable, + Func predicate=null, int page = _page, int perpage = _perpage, Func orderBy = null, string order = "asc") where T : class { int total = 0; IEnumerable query; query = predicate != null ? enumerable.Where(predicate) : enumerable; - if (orderBy.IsValid()) - { - query = order == "asc" ? query.OrderBy(x => x.GetPropertyValue(orderBy)) : - order == "desc" ? query.OrderByDescending(x => x.GetPropertyValue(orderBy)) : query; - } - total = query.CountItems(); + if (orderBy != null) + { + query = order.Equals("asc", StringComparison.OrdinalIgnoreCase) ? query.OrderBy(orderBy) : + order.Equals("desc", StringComparison.OrdinalIgnoreCase) ? query.OrderByDescending(orderBy) : query; + } PagedResult result = new PagedResult() { diff --git a/src/Paginator.csproj b/src/Paginator.csproj index 1769dce..35ab676 100644 --- a/src/Paginator.csproj +++ b/src/Paginator.csproj @@ -5,7 +5,8 @@ netstandard2.0; netcoreapp3.0;netcoreapp2.0;netcoreapp2.1; - net47 + + net48 false true @@ -18,19 +19,18 @@ https://github.com/tmacharia/linq-paginator linq, pagination, list paginator, paging, list, array, collection For queries that return a lot of data, a need emerges to consume the results in chunks rather than the entire set. Consuming all results at once can be costly in terms of network traffic thus slowing down your application. - Linq Paginator allows you to run your queries and return your data in form of pages. A page contains a set number of items to return per page e.g 20. If for example you have 100 records, it will return the following object: + Linq Paginator allows you to run your queries and return your data in form of pages. A page contains a set number of items to return per page e.g 20. If for example you have 100 records, it will return the following object: - Page: 1, - TotalPages: 5, - ItemsPerPage: 20, - TotalItems: 100, - - List (collection of the first 20 records) + - Items (collection of the first 20 records) LinqPaginator - 1.2.6 + 1.2.7 en - Fixes bug/issue with pagination result: - -> TotalPages is always zero + Fixes bug/issue casting. git @@ -42,12 +42,9 @@ --> - - - - + True diff --git a/tests/TestCases.csproj b/tests/TestCases.csproj index bf4d635..1ffc63f 100644 --- a/tests/TestCases.csproj +++ b/tests/TestCases.csproj @@ -5,10 +5,10 @@ - - - - + + + +