Skip to content

Instantly share code, notes, and snippets.

@ShawnShiSS
Created November 21, 2020 03:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ShawnShiSS/19e3ef0d9a9cfd1dad4dc0723aeb13ec to your computer and use it in GitHub Desktop.
Save ShawnShiSS/19e3ef0d9a9cfd1dad4dc0723aeb13ec to your computer and use it in GitHub Desktop.
Example search functionality to support pagination and searching and datatables.
namespace CleanArchitectureCosmosDB.WebAPI.Models.ToDoItem
{
/// <summary>
/// Search related commands, validators, and handlers
/// </summary>
public class Search
{
/// <summary>
/// Model to Search
/// </summary>
public class SearchToDoItemQuery : IRequest<QueryResponse>, ISearchQuery
{
// Pagination and Sort
/// <summary>
/// Starting point (translates to OFFSET)
/// </summary>
public int Start { get; set; }
/// <summary>
/// Page Size (translates to LIMIT)
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// Sort by Column
/// </summary>
public string SortColumn { get; set; }
/// <summary>
/// Sort direction
/// </summary>
public SortDirection? SortDirection { get; set; }
// Search
/// <summary>
/// Title
/// </summary>
public string TitleFilter { get; set; }
}
/// <summary>
/// Query Response
/// </summary>
public class QueryResponse
{
/// <summary>
/// Current Page, 0-indexed
/// </summary>
public int CurrentPage { get; set; }
/// <summary>
/// Total Records Matched. For Pagination purpose.
/// </summary>
public int TotalRecordsMatched { get; set; }
/// <summary>
/// Resource
/// </summary>
public IEnumerable<ToDoItemModel> Resource { get; set; }
}
/// <summary>
/// Register Validation
/// </summary>
public class SearchToDoItemQueryValidator : AbstractValidator<SearchToDoItemQuery>
{
/// <summary>
/// Validator ctor
/// </summary>
public SearchToDoItemQueryValidator()
{
RuleFor(x => x.PageSize)
.GreaterThan(0);
}
}
/// <summary>
/// Handler
/// </summary>
public class QueryHandler : IRequestHandler<SearchToDoItemQuery, QueryResponse>
{
private readonly IToDoItemRepository _repo;
private readonly IMapper _mapper;
/// <summary>
/// Ctor
/// </summary>
/// <param name="repo"></param>
/// <param name="mapper"></param>
public QueryHandler(IToDoItemRepository repo,
IMapper mapper)
{
this._repo = repo ?? throw new ArgumentNullException(nameof(repo));
this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
/// <summary>
/// Handle
/// </summary>
/// <param name="query"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<QueryResponse> Handle(SearchToDoItemQuery query, CancellationToken cancellationToken)
{
QueryResponse response = new QueryResponse();
// records
var specification = new ToDoItemSearchSpecification(query.TitleFilter,
query.Start,
query.PageSize,
query.SortColumn,
query.SortDirection ?? query.SortDirection.Value);
var entities = await _repo.GetItemsAsync(specification);
response.Resource = entities.Select(x => _mapper.Map<ToDoItemModel>(x));
// count
var countSpecification = new ToDoItemSearchAggregationSpecification(query.TitleFilter);
response.TotalRecordsMatched = await _repo.GetItemsCountAsync(countSpecification);
response.CurrentPage = (query.PageSize != 0) ? query.Start / query.PageSize : 0;
return response;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment