-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add a simple pagination endpoint for employees
- Loading branch information
Showing
5 changed files
with
167 additions
and
2 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
CleanAspCore.Api.Tests/Features/Employees/GetEmployeesTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using CleanAspCore.Api.Tests.Fakers; | ||
|
||
namespace CleanAspCore.Api.Tests.Features.Employees; | ||
|
||
public class GetEmployees : TestBase | ||
{ | ||
[Test] | ||
public async Task? GetEmployees_NoEmployees_ReturnsEmptyPage() | ||
{ | ||
//Act | ||
var response = await Sut.CreateClientFor<IEmployeeApiClient>(ClaimConstants.ReadEmployeesRole).GetEmployees(1); | ||
|
||
//Assert | ||
await response.AssertStatusCode(HttpStatusCode.OK); | ||
await response.AssertJsonBodyIsEquivalentTo(new | ||
{ | ||
TotalPages = 0, | ||
TotalRecords = 0, | ||
PageNumber = 0, | ||
Data = new List<Guid>() | ||
}); | ||
} | ||
|
||
[Test] | ||
public async Task GetEmployees_FirstPage_ReturnsExpectedEmployees() | ||
{ | ||
//Arrange | ||
var department = new DepartmentFaker().Generate(); | ||
var job = new JobFaker().Generate(); | ||
var employees = new EmployeeFaker() | ||
.RuleFor(x => x.Department, department) | ||
.RuleFor(x => x.Job, job) | ||
.Generate(15); | ||
Sut.SeedData(context => | ||
{ | ||
context.Employees.AddRange(employees); | ||
}); | ||
|
||
//Act | ||
var response = await Sut.CreateClientFor<IEmployeeApiClient>(ClaimConstants.ReadEmployeesRole).GetEmployees(1); | ||
|
||
//Assert | ||
await response.AssertStatusCode(HttpStatusCode.OK); | ||
await response.AssertJsonBodyIsEquivalentTo(new | ||
{ | ||
TotalPages = 2, | ||
TotalRecords = 15, | ||
PageNumber = 1, | ||
Data = employees | ||
.OrderBy(x => x.FirstName) | ||
.Select(x => new { x.Id }) | ||
.Take(10) | ||
.ToList() | ||
}); | ||
} | ||
|
||
[Test] | ||
public async Task GetEmployees_SecondPage_ReturnsExpectedEmployees() | ||
{ | ||
//Arrange | ||
var department = new DepartmentFaker().Generate(); | ||
var job = new JobFaker().Generate(); | ||
var employees = new EmployeeFaker() | ||
.RuleFor(x => x.Department, department) | ||
.RuleFor(x => x.Job, job) | ||
.Generate(15); | ||
Sut.SeedData(context => | ||
{ | ||
context.Employees.AddRange(employees); | ||
}); | ||
|
||
//Act | ||
var response = await Sut.CreateClientFor<IEmployeeApiClient>(ClaimConstants.ReadEmployeesRole).GetEmployees(2); | ||
|
||
//Assert | ||
await response.AssertStatusCode(HttpStatusCode.OK); | ||
await response.AssertJsonBodyIsEquivalentTo(new | ||
{ | ||
TotalPages = 2, | ||
TotalRecords = 15, | ||
PageNumber = 2, | ||
Data = employees | ||
.OrderBy(x => x.FirstName) | ||
.Select(x => new { x.Id }) | ||
.Skip(10) | ||
.Take(10) | ||
.ToList() | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
CleanAspCore/Data/Extensions/PagedListQueryableExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System.Collections; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace CleanAspCore.Data.Extensions; | ||
|
||
public static class PagedListQueryableExtensions | ||
{ | ||
public static async Task<PagedList<T>> ToPagedListAsync<T>( | ||
this IQueryable<T> source, | ||
int page, | ||
int pageSize, | ||
CancellationToken token = default) | ||
{ | ||
var count = await source.CountAsync(token); | ||
if (count > 0) | ||
{ | ||
var items = await source | ||
.Skip((page - 1) * pageSize) | ||
.Take(pageSize) | ||
.ToListAsync(token); | ||
return new PagedList<T>(items, count, page, pageSize); | ||
} | ||
|
||
return new(Enumerable.Empty<T>(), 0, 0, pageSize); | ||
} | ||
} | ||
|
||
public class PagedList<T> | ||
{ | ||
public PagedList(IEnumerable<T> items, int count, int pageNumber, int pageSize) | ||
{ | ||
PageNumber = pageNumber; | ||
TotalRecords = count; | ||
TotalPages = (int)Math.Ceiling(count / (double)pageSize); | ||
Data = items as IList<T> ?? new List<T>(items); | ||
} | ||
|
||
public IList<T> Data { get; init; } | ||
public int PageNumber { get; init; } | ||
public int TotalPages { get; init; } | ||
public int TotalRecords { get; init; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using CleanAspCore.Data; | ||
using CleanAspCore.Data.Extensions; | ||
using CleanAspCore.Data.Models.Employees; | ||
using Microsoft.AspNetCore.Http.HttpResults; | ||
|
||
namespace CleanAspCore.Endpoints.Employees; | ||
|
||
internal static class GetEmployees | ||
{ | ||
internal static async Task<Ok<PagedList<GetEmployeeResponse>>> Handle(HrContext context, [FromQuery] int page, CancellationToken cancellationToken) | ||
{ | ||
var result = await context.Employees | ||
.OrderBy(x => x.FirstName) | ||
.Select(x => x.ToDto()) | ||
.ToPagedListAsync(page, 10, cancellationToken); | ||
return TypedResults.Ok(result); | ||
} | ||
|
||
private static GetEmployeeResponse ToDto(this Employee employee) => new() | ||
{ | ||
Id = employee.Id, | ||
FirstName = employee.FirstName, | ||
LastName = employee.LastName, | ||
Email = employee.Email.ToString(), | ||
Gender = employee.Gender, | ||
DepartmentId = employee.DepartmentId, | ||
JobId = employee.JobId | ||
}; | ||
} |