From 8ea30a6587559cc1e322635046b1009806342a07 Mon Sep 17 00:00:00 2001 From: Mohammad Rahhal Date: Fri, 10 Feb 2023 11:29:52 +0100 Subject: [PATCH 1/5] Enable nullable in some places in samples --- samples/Basic/Pages/Index.cshtml.cs | 1 + samples/Basic/Pages/Keyset2.cshtml.cs | 1 + samples/Basic/Pages/Keyset3.cshtml.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/samples/Basic/Pages/Index.cshtml.cs b/samples/Basic/Pages/Index.cshtml.cs index 361ffe2..6e51237 100644 --- a/samples/Basic/Pages/Index.cshtml.cs +++ b/samples/Basic/Pages/Index.cshtml.cs @@ -21,6 +21,7 @@ public IndexModel( public async Task OnGet() { +#nullable enable var query = _dbContext.Users; Users = await _paginationService.KeysetPaginateAsync( diff --git a/samples/Basic/Pages/Keyset2.cshtml.cs b/samples/Basic/Pages/Keyset2.cshtml.cs index c946927..e84f4d1 100644 --- a/samples/Basic/Pages/Keyset2.cshtml.cs +++ b/samples/Basic/Pages/Keyset2.cshtml.cs @@ -27,6 +27,7 @@ public Keyset2Model( public async Task OnGet() { +#nullable enable var query = _dbContext.Users; Users = await _paginationService.KeysetPaginateAsync( diff --git a/samples/Basic/Pages/Keyset3.cshtml.cs b/samples/Basic/Pages/Keyset3.cshtml.cs index 5b25957..522dd06 100644 --- a/samples/Basic/Pages/Keyset3.cshtml.cs +++ b/samples/Basic/Pages/Keyset3.cshtml.cs @@ -21,6 +21,7 @@ public Keyset3Model( public async Task OnGet() { +#nullable enable var query = _dbContext.Posts; Posts = await _paginationService.KeysetPaginateAsync( From 55f395f106a6cb344bb8afb94187f0f752e37eee Mon Sep 17 00:00:00 2001 From: Mohammad Rahhal Date: Fri, 10 Feb 2023 11:30:34 +0100 Subject: [PATCH 2/5] Allow nulls in getReferenceAsync --- src/MR.AspNetCore.Pagination/PaginationService.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/MR.AspNetCore.Pagination/PaginationService.cs b/src/MR.AspNetCore.Pagination/PaginationService.cs index 606ea9e..c629da4 100644 --- a/src/MR.AspNetCore.Pagination/PaginationService.cs +++ b/src/MR.AspNetCore.Pagination/PaginationService.cs @@ -24,7 +24,7 @@ public interface IPaginationService Task> KeysetPaginateAsync( IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, Func, IQueryable> map, KeysetQueryModel queryModel) where T : class @@ -44,7 +44,7 @@ Task> KeysetPaginateAsync( Task> KeysetPaginateAsync( IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, Func, IQueryable> map, int? pageSize = null) where T : class @@ -134,7 +134,7 @@ public static Task> KeysetPaginateAsync( this IPaginationService @this, IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, KeysetQueryModel queryModel) where T : class => @this.KeysetPaginateAsync(source, builderAction, getReferenceAsync, query => query, queryModel); @@ -153,7 +153,7 @@ public static Task> KeysetPaginateAsync( this IPaginationService @this, IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, int? pageSize = null) where T : class => @this.KeysetPaginateAsync(source, builderAction, getReferenceAsync, query => query, pageSize); @@ -242,7 +242,7 @@ public PaginationService( public async Task> KeysetPaginateAsync( IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, Func, IQueryable> map, KeysetQueryModel queryModel) where T : class @@ -302,7 +302,7 @@ public async Task> KeysetPaginateAsync( public Task> KeysetPaginateAsync( IQueryable source, Action> builderAction, - Func> getReferenceAsync, + Func> getReferenceAsync, Func, IQueryable> map, int? pageSize = null) where T : class From 6e8d8364dfe4f0dc657606d88c6f9023ea547265 Mon Sep 17 00:00:00 2001 From: Mohammad Rahhal Date: Fri, 10 Feb 2023 11:30:59 +0100 Subject: [PATCH 3/5] Update version.props --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 16af6b2..e6b0eee 100644 --- a/version.props +++ b/version.props @@ -1,5 +1,5 @@ - 2.0.0 + 2.0.1 From 8e5bc0fefb196b089599ee64946069ebb3ca5cff Mon Sep 17 00:00:00 2001 From: Mohammad Rahhal Date: Fri, 10 Feb 2023 11:31:36 +0100 Subject: [PATCH 4/5] :book: --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 81ab52c..5d7ab35 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ services.AddPagination(options => Check the [`PaginationOptions`](https://github.com/mrahhal/MR.AspNetCore.Pagination/blob/main/src/MR.AspNetCore.Pagination/PaginationOptions.cs) class to see what you can configure. -And then just inject `IPaginationService` in your controller/page and use it. The [returned result](https://github.com/mrahhal/MR.AspNetCore.Pagination/blob/main/src/MR.AspNetCore.Pagination/PaginationResult.cs) is either a `KeysetPaginationResult<>` or an `OffsetPaginationResult<>`, each containing all the info you need for this pagination result. +And then just inject `IPaginationService` in your controller/page and use it. The [returned result](https://github.com/mrahhal/MR.AspNetCore.Pagination/blob/main/src/MR.AspNetCore.Pagination/PaginationResult.cs) is either a `KeysetPaginationResult<>` or an `OffsetPaginationResult<>`, each containing all the info you need for this pagination result. Do a keyset pagination: @@ -110,6 +110,27 @@ var result = _paginationService.OffsetPaginate(orders); There's a helper `PaginationActionDetector` class that can be used with reflection, for example in ASP.NET Core conventions, which can tell you whether the action method returns a pagination result or not. This is what the MR.AspNetCore.Pagination.Swashbuckle package uses to configure swagger for those apis. +## Handling null references (reference has been deleted from the db) + +The `getReferenceAsync` delegate parameter on `KeysetPaginateAsync` that you'll provide allows returning nulls. The behavior when that happens is to always return the first page (enforcing Forward direction). + +If you want to have a special way to handle this, you'll simply have to do that logic in the `getReferenceAsync` delegate you'll provide. Here's an example: +```cs +var result = await _paginationService.KeysetPaginateAsync( + query, + b => b.Descending(x => x.Created), + async id = + { + var reference = await _dbContext.Users.FindAsync(int.Parse(id)); + if (reference == null) + { + // Throw a custom exception which will be captured by some middleware to process. + throw new MyKeysetPaginationReferenceIsNullException(); + } + return reference; + }; +``` + ## Query model as an argument All methods also have overloads that accept the pagination query model directly as an argument, as opposed to parsing it from the request query. From fc5b1fe14dead2a6857850fc57262009445488b8 Mon Sep 17 00:00:00 2001 From: Mohammad Rahhal Date: Fri, 10 Feb 2023 11:31:43 +0100 Subject: [PATCH 5/5] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9b11b6..8753782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased: 2.0.1 + +### Fixed + +- Properly annotate the `getReferenceAsync` delegate to allow nulls, which fixes the mismatch in analysis. + ## 2.0.0 - 2022-11-05 This version introduces breaking changes. Make sure to read on them in the Changed section below.