mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-07-03 20:12:56 +00:00
Merge pull request #21 from alex289/feature/pagination
feat: Add pagination
This commit is contained in:
commit
f46994c60a
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Api.Models;
|
using CleanArchitecture.Api.Models;
|
||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@ -28,10 +28,14 @@ public sealed class TenantController : ApiController
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[SwaggerOperation("Get a list of all tenants")]
|
[SwaggerOperation("Get a list of all tenants")]
|
||||||
[SwaggerResponse(200, "Request successful", typeof(ResponseMessage<IEnumerable<TenantViewModel>>))]
|
[SwaggerResponse(200, "Request successful", typeof(ResponseMessage<PagedResult<TenantViewModel>>))]
|
||||||
public async Task<IActionResult> GetAllTenantsAsync()
|
public async Task<IActionResult> GetAllTenantsAsync(
|
||||||
|
[FromQuery] PageQuery query,
|
||||||
|
[FromQuery] string searchTerm = "")
|
||||||
{
|
{
|
||||||
var tenants = await _tenantService.GetAllTenantsAsync();
|
var tenants = await _tenantService.GetAllTenantsAsync(
|
||||||
|
query,
|
||||||
|
searchTerm);
|
||||||
return Response(tenants);
|
return Response(tenants);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Api.Models;
|
using CleanArchitecture.Api.Models;
|
||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@ -28,10 +28,14 @@ public sealed class UserController : ApiController
|
|||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[SwaggerOperation("Get a list of all users")]
|
[SwaggerOperation("Get a list of all users")]
|
||||||
[SwaggerResponse(200, "Request successful", typeof(ResponseMessage<IEnumerable<UserViewModel>>))]
|
[SwaggerResponse(200, "Request successful", typeof(ResponseMessage<PagedResult<UserViewModel>>))]
|
||||||
public async Task<IActionResult> GetAllUsersAsync()
|
public async Task<IActionResult> GetAllUsersAsync(
|
||||||
|
[FromQuery] PageQuery query,
|
||||||
|
[FromQuery] string searchTerm = "")
|
||||||
{
|
{
|
||||||
var users = await _userService.GetAllUsersAsync();
|
var users = await _userService.GetAllUsersAsync(
|
||||||
|
query,
|
||||||
|
searchTerm);
|
||||||
return Response(users);
|
return Response(users);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
|
|||||||
Handler = new GetAllUsersQueryHandler(UserRepository);
|
Handler = new GetAllUsersQueryHandler(UserRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupUserAsync()
|
public User SetupUserAsync()
|
||||||
{
|
{
|
||||||
var user = new User(
|
var user = new User(
|
||||||
ExistingUserId,
|
ExistingUserId,
|
||||||
@ -35,6 +35,8 @@ public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
|
|||||||
var query = new[] { user }.BuildMock();
|
var query = new[] { user }.BuildMock();
|
||||||
|
|
||||||
UserRepository.GetAllNoTracking().Returns(query);
|
UserRepository.GetAllNoTracking().Returns(query);
|
||||||
|
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetupDeletedUserAsync()
|
public void SetupDeletedUserAsync()
|
||||||
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
||||||
using CleanArchitecture.Application.Tests.Fixtures.Queries.Tenants;
|
using CleanArchitecture.Application.Tests.Fixtures.Queries.Tenants;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -16,13 +17,23 @@ public sealed class GetAllTenantsQueryHandlerTests
|
|||||||
{
|
{
|
||||||
var tenant = _fixture.SetupTenant();
|
var tenant = _fixture.SetupTenant();
|
||||||
|
|
||||||
|
var query = new PageQuery
|
||||||
|
{
|
||||||
|
PageSize = 10,
|
||||||
|
Page = 1
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _fixture.QueryHandler.Handle(
|
var result = await _fixture.QueryHandler.Handle(
|
||||||
new GetAllTenantsQuery(),
|
new GetAllTenantsQuery(query),
|
||||||
default);
|
default);
|
||||||
|
|
||||||
_fixture.VerifyNoDomainNotification();
|
_fixture.VerifyNoDomainNotification();
|
||||||
|
|
||||||
tenant.Should().BeEquivalentTo(result.First());
|
result.PageSize.Should().Be(query.PageSize);
|
||||||
|
result.Page.Should().Be(query.Page);
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
|
||||||
|
tenant.Should().BeEquivalentTo(result.Items.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -30,10 +41,20 @@ public sealed class GetAllTenantsQueryHandlerTests
|
|||||||
{
|
{
|
||||||
_fixture.SetupTenant(true);
|
_fixture.SetupTenant(true);
|
||||||
|
|
||||||
|
var query = new PageQuery
|
||||||
|
{
|
||||||
|
PageSize = 10,
|
||||||
|
Page = 1
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _fixture.QueryHandler.Handle(
|
var result = await _fixture.QueryHandler.Handle(
|
||||||
new GetAllTenantsQuery(),
|
new GetAllTenantsQuery(query),
|
||||||
default);
|
default);
|
||||||
|
|
||||||
result.Should().HaveCount(0);
|
result.PageSize.Should().Be(query.PageSize);
|
||||||
|
result.Page.Should().Be(query.Page);
|
||||||
|
result.Count.Should().Be(0);
|
||||||
|
|
||||||
|
result.Items.Should().HaveCount(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetAll;
|
using CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@ -14,15 +15,25 @@ public sealed class GetAllUsersQueryHandlerTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Should_Get_All_Users()
|
public async Task Should_Get_All_Users()
|
||||||
{
|
{
|
||||||
_fixture.SetupUserAsync();
|
var user = _fixture.SetupUserAsync();
|
||||||
|
|
||||||
|
var query = new PageQuery
|
||||||
|
{
|
||||||
|
PageSize = 1,
|
||||||
|
Page = 1
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _fixture.Handler.Handle(
|
var result = await _fixture.Handler.Handle(
|
||||||
new GetAllUsersQuery(),
|
new GetAllUsersQuery(query, user.Email),
|
||||||
default);
|
default);
|
||||||
|
|
||||||
_fixture.VerifyNoDomainNotification();
|
_fixture.VerifyNoDomainNotification();
|
||||||
|
|
||||||
var userViewModels = result.ToArray();
|
result.PageSize.Should().Be(query.PageSize);
|
||||||
|
result.Page.Should().Be(query.Page);
|
||||||
|
result.Count.Should().Be(1);
|
||||||
|
|
||||||
|
var userViewModels = result.Items.ToArray();
|
||||||
userViewModels.Should().NotBeNull();
|
userViewModels.Should().NotBeNull();
|
||||||
userViewModels.Should().ContainSingle();
|
userViewModels.Should().ContainSingle();
|
||||||
userViewModels.FirstOrDefault()!.Id.Should().Be(_fixture.ExistingUserId);
|
userViewModels.FirstOrDefault()!.Id.Should().Be(_fixture.ExistingUserId);
|
||||||
@ -33,12 +44,22 @@ public sealed class GetAllUsersQueryHandlerTests
|
|||||||
{
|
{
|
||||||
_fixture.SetupDeletedUserAsync();
|
_fixture.SetupDeletedUserAsync();
|
||||||
|
|
||||||
|
var query = new PageQuery
|
||||||
|
{
|
||||||
|
PageSize = 10,
|
||||||
|
Page = 1
|
||||||
|
};
|
||||||
|
|
||||||
var result = await _fixture.Handler.Handle(
|
var result = await _fixture.Handler.Handle(
|
||||||
new GetAllUsersQuery(),
|
new GetAllUsersQuery(query),
|
||||||
default);
|
default);
|
||||||
|
|
||||||
_fixture.VerifyNoDomainNotification();
|
_fixture.VerifyNoDomainNotification();
|
||||||
|
|
||||||
result.Should().BeEmpty();
|
result.PageSize.Should().Be(query.PageSize);
|
||||||
|
result.Page.Should().Be(query.Page);
|
||||||
|
result.Count.Should().Be(0);
|
||||||
|
|
||||||
|
result.Items.Should().BeEmpty();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
||||||
using CleanArchitecture.Application.Queries.Tenants.GetTenantById;
|
using CleanArchitecture.Application.Queries.Tenants.GetTenantById;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetAll;
|
using CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
using CleanArchitecture.Application.Services;
|
using CleanArchitecture.Application.Services;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@ -26,12 +26,12 @@ public static class ServiceCollectionExtension
|
|||||||
{
|
{
|
||||||
// User
|
// User
|
||||||
services.AddScoped<IRequestHandler<GetUserByIdQuery, UserViewModel?>, GetUserByIdQueryHandler>();
|
services.AddScoped<IRequestHandler<GetUserByIdQuery, UserViewModel?>, GetUserByIdQueryHandler>();
|
||||||
services.AddScoped<IRequestHandler<GetAllUsersQuery, IEnumerable<UserViewModel>>, GetAllUsersQueryHandler>();
|
services.AddScoped<IRequestHandler<GetAllUsersQuery, PagedResult<UserViewModel>>, GetAllUsersQueryHandler>();
|
||||||
|
|
||||||
// Tenant
|
// Tenant
|
||||||
services.AddScoped<IRequestHandler<GetTenantByIdQuery, TenantViewModel?>, GetTenantByIdQueryHandler>();
|
services.AddScoped<IRequestHandler<GetTenantByIdQuery, TenantViewModel?>, GetTenantByIdQueryHandler>();
|
||||||
services
|
services
|
||||||
.AddScoped<IRequestHandler<GetAllTenantsQuery, IEnumerable<TenantViewModel>>, GetAllTenantsQueryHandler>();
|
.AddScoped<IRequestHandler<GetAllTenantsQuery, PagedResult<TenantViewModel>>, GetAllTenantsQueryHandler>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Interfaces;
|
namespace CleanArchitecture.Application.Interfaces;
|
||||||
@ -11,5 +12,5 @@ public interface ITenantService
|
|||||||
public Task UpdateTenantAsync(UpdateTenantViewModel tenant);
|
public Task UpdateTenantAsync(UpdateTenantViewModel tenant);
|
||||||
public Task DeleteTenantAsync(Guid tenantId);
|
public Task DeleteTenantAsync(Guid tenantId);
|
||||||
public Task<TenantViewModel?> GetTenantByIdAsync(Guid tenantId, bool deleted);
|
public Task<TenantViewModel?> GetTenantByIdAsync(Guid tenantId, bool deleted);
|
||||||
public Task<IEnumerable<TenantViewModel>> GetAllTenantsAsync();
|
public Task<PagedResult<TenantViewModel>> GetAllTenantsAsync(PageQuery query, string searchTerm = "");
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Interfaces;
|
namespace CleanArchitecture.Application.Interfaces;
|
||||||
@ -9,7 +10,7 @@ public interface IUserService
|
|||||||
{
|
{
|
||||||
public Task<UserViewModel?> GetUserByUserIdAsync(Guid userId, bool isDeleted);
|
public Task<UserViewModel?> GetUserByUserIdAsync(Guid userId, bool isDeleted);
|
||||||
public Task<UserViewModel?> GetCurrentUserAsync();
|
public Task<UserViewModel?> GetCurrentUserAsync();
|
||||||
public Task<IEnumerable<UserViewModel>> GetAllUsersAsync();
|
public Task<PagedResult<UserViewModel>> GetAllUsersAsync(PageQuery query, string searchTerm = "");
|
||||||
public Task<Guid> CreateUserAsync(CreateUserViewModel user);
|
public Task<Guid> CreateUserAsync(CreateUserViewModel user);
|
||||||
public Task UpdateUserAsync(UpdateUserViewModel user);
|
public Task UpdateUserAsync(UpdateUserViewModel user);
|
||||||
public Task DeleteUserAsync(Guid userId);
|
public Task DeleteUserAsync(Guid userId);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Queries.Tenants.GetAll;
|
namespace CleanArchitecture.Application.Queries.Tenants.GetAll;
|
||||||
|
|
||||||
public sealed record GetAllTenantsQuery : IRequest<IEnumerable<TenantViewModel>>;
|
public sealed record GetAllTenantsQuery(PageQuery Query, string SearchTerm = "") :
|
||||||
|
IRequest<PagedResult<TenantViewModel>>;
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace CleanArchitecture.Application.Queries.Tenants.GetAll;
|
namespace CleanArchitecture.Application.Queries.Tenants.GetAll;
|
||||||
|
|
||||||
public sealed class GetAllTenantsQueryHandler :
|
public sealed class GetAllTenantsQueryHandler :
|
||||||
IRequestHandler<GetAllTenantsQuery, IEnumerable<TenantViewModel>>
|
IRequestHandler<GetAllTenantsQuery, PagedResult<TenantViewModel>>
|
||||||
{
|
{
|
||||||
private readonly ITenantRepository _tenantRepository;
|
private readonly ITenantRepository _tenantRepository;
|
||||||
|
|
||||||
@ -19,15 +19,30 @@ public sealed class GetAllTenantsQueryHandler :
|
|||||||
_tenantRepository = tenantRepository;
|
_tenantRepository = tenantRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TenantViewModel>> Handle(
|
public async Task<PagedResult<TenantViewModel>> Handle(
|
||||||
GetAllTenantsQuery request,
|
GetAllTenantsQuery request,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return await _tenantRepository
|
var tenantsQuery = _tenantRepository
|
||||||
.GetAllNoTracking()
|
.GetAllNoTracking()
|
||||||
.Include(x => x.Users)
|
.Include(x => x.Users)
|
||||||
.Where(x => !x.Deleted)
|
.Where(x => !x.Deleted);
|
||||||
.Select(x => TenantViewModel.FromTenant(x))
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.SearchTerm))
|
||||||
|
{
|
||||||
|
tenantsQuery = tenantsQuery.Where(tenant =>
|
||||||
|
tenant.Name.Contains(request.SearchTerm));
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalCount = await tenantsQuery.CountAsync(cancellationToken);
|
||||||
|
|
||||||
|
var tenants = await tenantsQuery
|
||||||
|
.Skip((request.Query.Page - 1) * request.Query.PageSize)
|
||||||
|
.Take(request.Query.PageSize)
|
||||||
|
.Select(tenant => TenantViewModel.FromTenant(tenant))
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return new PagedResult<TenantViewModel>(
|
||||||
|
totalCount, tenants, request.Query.Page, request.Query.PageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
using System.Collections.Generic;
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
|
|
||||||
public sealed record GetAllUsersQuery : IRequest<IEnumerable<UserViewModel>>;
|
public sealed record GetAllUsersQuery(PageQuery Query, string SearchTerm = "") :
|
||||||
|
IRequest<PagedResult<UserViewModel>>;
|
@ -1,7 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
|
|
||||||
public sealed class GetAllUsersQueryHandler :
|
public sealed class GetAllUsersQueryHandler :
|
||||||
IRequestHandler<GetAllUsersQuery, IEnumerable<UserViewModel>>
|
IRequestHandler<GetAllUsersQuery, PagedResult<UserViewModel>>
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _userRepository;
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
@ -19,12 +19,31 @@ public sealed class GetAllUsersQueryHandler :
|
|||||||
_userRepository = userRepository;
|
_userRepository = userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<UserViewModel>> Handle(GetAllUsersQuery request, CancellationToken cancellationToken)
|
public async Task<PagedResult<UserViewModel>> Handle(
|
||||||
|
GetAllUsersQuery request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return await _userRepository
|
var usersQuery = _userRepository
|
||||||
.GetAllNoTracking()
|
.GetAllNoTracking()
|
||||||
.Where(x => !x.Deleted)
|
.Where(x => !x.Deleted);
|
||||||
.Select(x => UserViewModel.FromUser(x))
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(request.SearchTerm))
|
||||||
|
{
|
||||||
|
usersQuery = usersQuery.Where(user =>
|
||||||
|
user.Email.Contains(request.SearchTerm) ||
|
||||||
|
user.FirstName.Contains(request.SearchTerm) ||
|
||||||
|
user.LastName.Contains(request.SearchTerm));
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalCount = await usersQuery.CountAsync(cancellationToken);
|
||||||
|
|
||||||
|
var users = await usersQuery
|
||||||
|
.Skip((request.Query.Page - 1) * request.Query.PageSize)
|
||||||
|
.Take(request.Query.PageSize)
|
||||||
|
.Select(user => UserViewModel.FromUser(user))
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return new PagedResult<UserViewModel>(
|
||||||
|
totalCount, users, request.Query.Page, request.Query.PageSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
using CleanArchitecture.Application.Queries.Tenants.GetAll;
|
||||||
using CleanArchitecture.Application.Queries.Tenants.GetTenantById;
|
using CleanArchitecture.Application.Queries.Tenants.GetTenantById;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using CleanArchitecture.Domain.Commands.Tenants.CreateTenant;
|
using CleanArchitecture.Domain.Commands.Tenants.CreateTenant;
|
||||||
using CleanArchitecture.Domain.Commands.Tenants.DeleteTenant;
|
using CleanArchitecture.Domain.Commands.Tenants.DeleteTenant;
|
||||||
@ -49,8 +50,8 @@ public sealed class TenantService : ITenantService
|
|||||||
return await _bus.QueryAsync(new GetTenantByIdQuery(tenantId, deleted));
|
return await _bus.QueryAsync(new GetTenantByIdQuery(tenantId, deleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<TenantViewModel>> GetAllTenantsAsync()
|
public async Task<PagedResult<TenantViewModel>> GetAllTenantsAsync(PageQuery query, string searchTerm = "")
|
||||||
{
|
{
|
||||||
return await _bus.QueryAsync(new GetAllTenantsQuery());
|
return await _bus.QueryAsync(new GetAllTenantsQuery(query, searchTerm));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using System.Threading.Tasks;
|
|||||||
using CleanArchitecture.Application.Interfaces;
|
using CleanArchitecture.Application.Interfaces;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetAll;
|
using CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Commands.Users.ChangePassword;
|
using CleanArchitecture.Domain.Commands.Users.ChangePassword;
|
||||||
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
||||||
@ -35,9 +36,9 @@ public sealed class UserService : IUserService
|
|||||||
return await _bus.QueryAsync(new GetUserByIdQuery(_user.GetUserId(), false));
|
return await _bus.QueryAsync(new GetUserByIdQuery(_user.GetUserId(), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<UserViewModel>> GetAllUsersAsync()
|
public async Task<PagedResult<UserViewModel>> GetAllUsersAsync(PageQuery query, string searchTerm = "")
|
||||||
{
|
{
|
||||||
return await _bus.QueryAsync(new GetAllUsersQuery());
|
return await _bus.QueryAsync(new GetAllUsersQuery(query, searchTerm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Guid> CreateUserAsync(CreateUserViewModel user)
|
public async Task<Guid> CreateUserAsync(CreateUserViewModel user)
|
||||||
|
20
CleanArchitecture.Application/ViewModels/PageQuery.cs
Normal file
20
CleanArchitecture.Application/ViewModels/PageQuery.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Application.ViewModels;
|
||||||
|
|
||||||
|
public sealed class PageQuery
|
||||||
|
{
|
||||||
|
private int _pageSize = 10;
|
||||||
|
public int PageSize
|
||||||
|
{
|
||||||
|
get => _pageSize;
|
||||||
|
set => _pageSize = Math.Max(0, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _page = 1;
|
||||||
|
public int Page
|
||||||
|
{
|
||||||
|
get => _page;
|
||||||
|
set => _page = Math.Max(1, value);
|
||||||
|
}
|
||||||
|
}
|
39
CleanArchitecture.Application/ViewModels/PagedResult.cs
Normal file
39
CleanArchitecture.Application/ViewModels/PagedResult.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.Application.ViewModels;
|
||||||
|
|
||||||
|
public sealed class PagedResult<T>
|
||||||
|
{
|
||||||
|
public int Count { get; init; }
|
||||||
|
|
||||||
|
public IList<T> Items { get; init; } = Array.Empty<T>();
|
||||||
|
|
||||||
|
public int Page { get; init; }
|
||||||
|
public int PageSize { get; init; }
|
||||||
|
|
||||||
|
public PagedResult(int count, IList<T> items, int page, int pageSize)
|
||||||
|
{
|
||||||
|
Count = count;
|
||||||
|
Items = items;
|
||||||
|
Page = page;
|
||||||
|
PageSize = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by json deserializer
|
||||||
|
private PagedResult()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PagedResult<T> Empty()
|
||||||
|
{
|
||||||
|
return new PagedResult<T>
|
||||||
|
{
|
||||||
|
Count = 0,
|
||||||
|
Items = Array.Empty<T>(),
|
||||||
|
Page = 1,
|
||||||
|
PageSize = 10
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Tenants;
|
using CleanArchitecture.Application.ViewModels.Tenants;
|
||||||
using CleanArchitecture.IntegrationTests.Extensions;
|
using CleanArchitecture.IntegrationTests.Extensions;
|
||||||
using CleanArchitecture.IntegrationTests.Fixtures;
|
using CleanArchitecture.IntegrationTests.Fixtures;
|
||||||
@ -43,15 +43,16 @@ public sealed class TenantControllerTests : IClassFixture<TenantTestFixture>
|
|||||||
[Priority(5)]
|
[Priority(5)]
|
||||||
public async Task Should_Get_All_Tenants()
|
public async Task Should_Get_All_Tenants()
|
||||||
{
|
{
|
||||||
var response = await _fixture.ServerClient.GetAsync("api/v1/Tenant");
|
var response = await _fixture.ServerClient.GetAsync(
|
||||||
|
"api/v1/Tenant?searchTerm=Test&pageSize=5&page=1");
|
||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
var message = await response.Content.ReadAsJsonAsync<IEnumerable<TenantViewModel>>();
|
var message = await response.Content.ReadAsJsonAsync<PagedResult<TenantViewModel>>();
|
||||||
|
|
||||||
message?.Data.Should().NotBeEmpty();
|
message?.Data!.Items.Should().NotBeEmpty();
|
||||||
message!.Data.Should().HaveCountGreaterOrEqualTo(2);
|
message!.Data!.Items.Should().HaveCount(1);
|
||||||
message.Data!
|
message.Data!.Items
|
||||||
.FirstOrDefault(x => x.Id == _fixture.CreatedTenantId)
|
.FirstOrDefault(x => x.Id == _fixture.CreatedTenantId)
|
||||||
.Should().NotBeNull();
|
.Should().NotBeNull();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Application.ViewModels;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Constants;
|
using CleanArchitecture.Domain.Constants;
|
||||||
using CleanArchitecture.Domain.Enums;
|
using CleanArchitecture.Domain.Enums;
|
||||||
@ -34,11 +34,11 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
|||||||
|
|
||||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
var message = await response.Content.ReadAsJsonAsync<IEnumerable<UserViewModel>>();
|
var message = await response.Content.ReadAsJsonAsync<PagedResult<UserViewModel>>();
|
||||||
|
|
||||||
message?.Data.Should().NotBeNull();
|
message?.Data.Should().NotBeNull();
|
||||||
|
|
||||||
var content = message!.Data!.ToList();
|
var content = message!.Data!.Items.ToList();
|
||||||
|
|
||||||
content.Count.Should().Be(2);
|
content.Count.Should().Be(2);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user