Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pagination for repository and response message #32

Merged
merged 6 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

<ItemGroup>
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace BSN.Commons.Converters
{
/// <summary>
/// Force to keep numeral object or value, while convert an object or value to or from JSON.
/// for example 'StatusCode' in Response that should stay numeral.
/// </summary>
/// <typeparam name="T"> The type of object or value handled by the converter. </typeparam>
public class JsonForceDefaultConverter<T> : JsonConverter<T>
soroshsabz marked this conversation as resolved.
Show resolved Hide resolved
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<T>(ref reader);
}

public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace BSN.Commons.Responses
{
/// <summary>
/// Add data as given type to response class.
/// </summary>
/// <typeparam name="T"> The type of object or value handled by the class. </typeparam>
public class GenericResponseBase<T> : Response where T : class
soroshsabz marked this conversation as resolved.
Show resolved Hide resolved
{
public GenericResponseBase() { }

public T Data { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace BSN.Commons.Responses
{
/// <summary>
/// Generic response base for paginated data.
/// </summary>
/// <remarks>
/// Paginated response provides metadata for navigation purpose.
/// </remarks>
/// <typeparam name="T">Data type.</typeparam>
public class GenericResponseBaseWithPagination<T> : GenericResponseBase<T> where T : class
soroshsabz marked this conversation as resolved.
Show resolved Hide resolved
{
/// <summary>
/// Pagination metada used by the client as the parameters for navigation through whole records.
/// </summary>
public PaginationMetadata Meta { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace BSN.Commons.Responses
{
/// <summary>
/// Stores the paginated meta data.
/// </summary>
public class PaginationMetadata
{
/// <summary>
/// Current page number
/// </summary>
public uint Page { get; set; }

/// <summary>
/// Total number of pages
/// </summary>
public uint PageCount { get; set; }

/// <summary>
/// Number of records per page
/// </summary>
public uint PageSize { get; set; }

/// <summary>
/// Total number of records that exist
/// </summary>
public uint RecordCount { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using BSN.Commons.Converters;
using BSN.Commons.PresentationInfrastructure;
using System.Text.Json.Serialization;

namespace BSN.Commons.Responses
{
/// <summary>
/// During serialization and deserialization operations, enumeration values are always converted to and from strings.
/// This is possible through registering the 'JsonStringEnumConverter' in our DI infrastructure. There is once exception,
/// namely the 'StatusCode' property of the 'ResponseBase' class which should keep it's default numeral value when being converted.
/// </summary>
public class Response : ResponseBase
{
public new bool IsSuccess => (int)StatusCode >= 200 && (int)StatusCode <= 299;

[JsonConverter(typeof(JsonForceDefaultConverter<ResponseStatusCode>))]
public new ResponseStatusCode StatusCode { get; set; }
}
}
36 changes: 36 additions & 0 deletions Source/BSN.Commons/Dto/PagedEntityCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;

namespace BSN.Commons.Dto
{
/// <summary>
/// Stores the paginated data for the given entity type.
/// </summary>
/// <typeparam name="T">Type of Entity for which pagination is being implemented.</typeparam>
public class PagedEntityCollection<T>
{
/// <summary>
/// Current page number
/// </summary>
public uint CurrentPage { get; set; }

/// <summary>
/// Total number of pages
/// </summary>
public uint PageCount { get; set; }

/// <summary>
/// Number of records per page
/// </summary>
public uint PageSize { get; set; }

/// <summary>
/// Total number of records that exist for the query
/// </summary>
public uint RecordCount { get; set; }

/// <summary>
/// IEnumerable of the paginated data
/// </summary>
public IEnumerable<T> Results { get; set; }
}
}
34 changes: 34 additions & 0 deletions Source/BSN.Commons/Extensions/IQueryableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using BSN.Commons.Dto;
using System;
using System.Linq;

namespace BSN.Commons.Extensions
{
public static partial class IQueryableExtensions
{
/// <summary>
/// Paginate IQueryable of <T>
/// with given pageNumber and pageSize
/// </summary>
public static PagedEntityCollection<T> Paginate<T>(this IQueryable<T> query, uint pageNumber, uint pageSize)
{
if (pageNumber == 0)
throw new ArgumentException("Must be greater than zero.", nameof(pageNumber));

if (pageSize == 0)
throw new ArgumentException("Must be greater than zero.", nameof(pageSize));

var result = new PagedEntityCollection<T>
{
CurrentPage = pageNumber,
PageSize = pageSize,
RecordCount = (uint)query.Count(),
Results = query.Skip((int)((pageNumber - 1) * pageSize)).Take((int)pageSize).ToList()
};

result.PageCount = (uint)Math.Ceiling((double)result.RecordCount / pageSize);

return result;
}
}
}
Loading