Skip to content

Instantly share code, notes, and snippets.

@CliffCrerar
Created March 6, 2021 22:52
Show Gist options
  • Save CliffCrerar/1481df40c5d549651b16bce7abed3ebf to your computer and use it in GitHub Desktop.
Save CliffCrerar/1481df40c5d549651b16bce7abed3ebf to your computer and use it in GitHub Desktop.
C# Databook Paginator Service
using System;
using System.Collections.Generic;
using System.Linq;
using Dapper;
namespace TraqIt.Api.Services
{
/// <summary>
/// Defines the contract of a databook page
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IDataPage<T>
{
public int PageNumber { get; }
public IList<T> Page { get; }
}
/// <summary>
/// Concretion of the databook page contract
/// </summary>
/// <typeparam name="T"></typeparam>
public class DataPage<T> : IDataPage<T>
{
public int PageNumber { get; }
public IList<T> Page { get; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="number">The databook page number</param>
/// <param name="page">The data page</param>
public DataPage(int number, IList<T> page)
{
Page = page;
PageNumber = number;
}
/// <summary>
/// Inverts the new page dependancy
/// </summary>
/// <param name="number">The databook page number</param>
/// <param name="page">The databook page number</param>
/// <typeparam name="U">The Page Data Type</typeparam>
/// <returns></returns>
public static IDataPage<T> CreatePage(int number, List<T> page)
{
return new DataPage<T>(number, page);
}
}
/// <summary>
/// Paging controller data contract
/// </summary>
public interface IPagingController
{
public int RangeStart { get; }
public int PageCount { get; }
public int PageSize { get; }
public int CurrentPage { get; }
public bool IsFinalPage { get; }
public IEnumerable<int> RecordIndexRange { get; }
public void NextPage();
}
/// <summary>
/// Defines the meta for the paging of data in the insert pages method. Defines the data partitioning strategy
/// for paging data
/// </summary>
public class PagingController : IPagingController
{
public int RangeStart { get; private set; }
public int CurrentPage { get; private set; }
public bool IsFinalPage { get; private set; }
public int PageCount { get; }
public int PageSize { get; }
public IEnumerable<int> RecordIndexRange { get; private set; }
public PagingController(int rowCount, int pageSize)
{
PageSize = pageSize;
PageCount = rowCount / PageSize;
CurrentPage = 0;
RangeStart = 0;
RecordIndexRange = Enumerable.Range(RangeStart, PageSize);
IsFinalPage = false;
}
/// <summary>
/// Method increments the paging controllers meta data
/// Like licking your finger to go to the next page of a magazine
/// </summary>
public void NextPage()
{
CurrentPage += 1;
RangeStart += PageSize;
RecordIndexRange = Enumerable.Range(RangeStart, PageSize);
IsFinalPage = CurrentPage >= PageCount;
}
}
/// <summary>
/// Defines the data book contract
/// </summary>
/// <typeparam name="T">The page data type</typeparam>
public interface IDataBook<T>
{
public Guid BookId { get; }
public string BookName { get; }
public IPagingController PagingController { get;}
public IList<IDataPage<T>> Pages { get; }
}
/// <summary>
/// Concretion of the data book contract
/// </summary>
/// <typeparam name="T"></typeparam>
public class DataBook<T> : IDataBook<T>
{
public Guid BookId { get; }
public string BookName { get; }
public IPagingController PagingController { get; private set; }
public IList<IDataPage<T>> Pages { get; }
private DataBook(string bookName)
{
BookId = new Guid();
Pages = new List<IDataPage<T>>();
BookName = bookName;
}
/// <summary>
/// Runs a loop that partitions the data, assigns a page number to them and adds the page
/// to the data book.
/// </summary>
/// <param name="Data">The selected data from the database</param>
/// <param name="PageSize">The page size passed in via the API call</param>
/// <returns>Returns this object following page insertion</returns>
private IDataBook<T> InsertPages(IEnumerable<T> Data, int PageSize)
{
PagingController = new PagingController(Data.Count(), PageSize);
while (!PagingController.IsFinalPage)
{
var pageDataContent = Data.Where((row, idx) => PagingController.RecordIndexRange.Contains(idx));
Pages.Add(DataPage<T>.CreatePage(PagingController.CurrentPage,pageDataContent.AsList()));
PagingController.NextPage();
}
return this;
}
/// <summary>
/// Static method used to self instantiate as inversion of control mechanism
/// </summary>
/// <param name="Data">A set of records / array of objects / collection</param>
/// <param name="PageSize">The size the partition</param>
/// <param name="dataBookName">OPTIONAL: name of the databook</param>
/// <returns></returns>
public static IDataBook<T> CreateDataBook(IEnumerable<T> Data, int PageSize, string dataBookName = "anonymous")
{
return new DataBook<T>(dataBookName).InsertPages(Data, PageSize);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment