This repository has been archived by the owner on Jul 12, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(customer): add customer use case
- Loading branch information
1 parent
8954efa
commit f643ede
Showing
22 changed files
with
324 additions
and
2 deletions.
There are no files selected for viewing
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
9 changes: 9 additions & 0 deletions
9
src/RookieShop.Application/Customers/Commands/Create/CreateCustomerCommand.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,9 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Enums; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Create; | ||
|
||
public sealed record CreateCustomerCommand(string Name, string Email, string Phone, Gender Gender, string? AccountId) | ||
: ICommand<Result<CustomerId>>; |
24 changes: 24 additions & 0 deletions
24
src/RookieShop.Application/Customers/Commands/Create/CreateCustomerHandler.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,24 @@ | ||
using System.Text.Json; | ||
using Ardalis.Result; | ||
using Microsoft.Extensions.Logging; | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Create; | ||
|
||
public sealed class CreateCustomerHandler(IRepository<Customer> repository, ILogger<CreateCustomerHandler> logger) | ||
: ICommandHandler<CreateCustomerCommand, Result<CustomerId>> | ||
{ | ||
public async Task<Result<CustomerId>> Handle(CreateCustomerCommand request, CancellationToken cancellationToken) | ||
{ | ||
Customer customer = new(request.Name, request.Email, request.Phone, request.Gender, request.AccountId); | ||
|
||
logger.LogInformation("[{Command}] - Creating customer {@Customer}", nameof(CreateCustomerCommand), | ||
JsonSerializer.Serialize(customer)); | ||
|
||
var result = await repository.AddAsync(customer, cancellationToken); | ||
|
||
return result.Id; | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/RookieShop.Application/Customers/Commands/Create/CreateCustomerValidator.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,29 @@ | ||
using FluentValidation; | ||
using RookieShop.Domain.Constants; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Create; | ||
|
||
public sealed class CreateCustomerValidator : AbstractValidator<CreateCustomerCommand> | ||
{ | ||
public CreateCustomerValidator() | ||
{ | ||
RuleFor(x => x.Name) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Medium); | ||
|
||
RuleFor(x => x.Email) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Medium) | ||
.EmailAddress(); | ||
|
||
RuleFor(x => x.Phone) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Small); | ||
|
||
RuleFor(x => x.Gender) | ||
.IsInEnum(); | ||
|
||
RuleFor(x => x.AccountId) | ||
.MaximumLength(DataLength.Medium); | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
src/RookieShop.Application/Customers/Commands/Delete/DeleteCustomerCommand.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,7 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Delete; | ||
|
||
public sealed record DeleteCustomerCommand(CustomerId Id) : ICommand<Result>; |
21 changes: 21 additions & 0 deletions
21
src/RookieShop.Application/Customers/Commands/Delete/DeleteCustomerHandler.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,21 @@ | ||
using Ardalis.GuardClauses; | ||
using Ardalis.Result; | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Delete; | ||
|
||
public sealed class DeleteCustomerHandler(IRepository<Customer> repository) | ||
: ICommandHandler<DeleteCustomerCommand, Result> | ||
{ | ||
public async Task<Result> Handle(DeleteCustomerCommand request, CancellationToken cancellationToken) | ||
{ | ||
var customer = await repository.GetByIdAsync(request.Id, cancellationToken); | ||
|
||
Guard.Against.NotFound(request.Id, customer); | ||
|
||
await repository.DeleteAsync(customer, cancellationToken); | ||
|
||
return Result.Success(); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/RookieShop.Application/Customers/Commands/Delete/DeleteCustomerValidator.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,8 @@ | ||
using FluentValidation; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Delete; | ||
|
||
public sealed class DeleteCustomerValidator : AbstractValidator<DeleteCustomerCommand> | ||
{ | ||
public DeleteCustomerValidator() => RuleFor(x => x.Id).NotEmpty(); | ||
} |
15 changes: 15 additions & 0 deletions
15
src/RookieShop.Application/Customers/Commands/Update/UpdateCustomerCommand.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,15 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Enums; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Update; | ||
|
||
public sealed record UpdateCustomerCommand( | ||
CustomerId Id, | ||
string Name, | ||
string Email, | ||
string Phone, | ||
Gender Gender, | ||
string? AccountId) : ICommand<Result<CustomerDto>>; |
30 changes: 30 additions & 0 deletions
30
src/RookieShop.Application/Customers/Commands/Update/UpdateCustomerHandler.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,30 @@ | ||
using System.Text.Json; | ||
using Ardalis.GuardClauses; | ||
using Ardalis.Result; | ||
using Microsoft.Extensions.Logging; | ||
using RookieShop.Application.Customers.Commands.Create; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Update; | ||
|
||
public sealed class UpdateCustomerHandler(IRepository<Customer> repository, ILogger<CreateCustomerHandler> logger) | ||
: ICommandHandler<UpdateCustomerCommand, Result<CustomerDto>> | ||
{ | ||
public async Task<Result<CustomerDto>> Handle(UpdateCustomerCommand request, CancellationToken cancellationToken) | ||
{ | ||
var customer = await repository.GetByIdAsync(request.Id, cancellationToken); | ||
|
||
Guard.Against.NotFound(request.Id, customer); | ||
|
||
customer.Update(request.Name, request.Email, request.Phone, request.Gender, request.AccountId); | ||
|
||
logger.LogInformation("[{Command}] - Updating customer {@Customer}", nameof(UpdateCustomerCommand), | ||
JsonSerializer.Serialize(customer)); | ||
|
||
await repository.UpdateAsync(customer, cancellationToken); | ||
|
||
return customer.ToCustomerDto(); | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/RookieShop.Application/Customers/Commands/Update/UpdateCustomerValidator.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,32 @@ | ||
using FluentValidation; | ||
using RookieShop.Domain.Constants; | ||
|
||
namespace RookieShop.Application.Customers.Commands.Update; | ||
|
||
public sealed class UpdateCustomerValidator : AbstractValidator<UpdateCustomerCommand> | ||
{ | ||
public UpdateCustomerValidator() | ||
{ | ||
RuleFor(x => x.Id) | ||
.NotEmpty(); | ||
|
||
RuleFor(x => x.Name) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Medium); | ||
|
||
RuleFor(x => x.Email) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Medium) | ||
.EmailAddress(); | ||
|
||
RuleFor(x => x.Phone) | ||
.NotEmpty() | ||
.MaximumLength(DataLength.Small); | ||
|
||
RuleFor(x => x.Gender) | ||
.IsInEnum(); | ||
|
||
RuleFor(x => x.AccountId) | ||
.MaximumLength(DataLength.Medium); | ||
} | ||
} |
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,12 @@ | ||
using RookieShop.Domain.Entities.CustomerAggregator.Enums; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
|
||
namespace RookieShop.Application.Customers.DTOs; | ||
|
||
public sealed record CustomerDto( | ||
CustomerId Id, | ||
string Name, | ||
string Email, | ||
string Phone, | ||
Gender Gender, | ||
string? AccountId); |
12 changes: 12 additions & 0 deletions
12
src/RookieShop.Application/Customers/DTOs/DomainToDtoMapper.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,12 @@ | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
|
||
namespace RookieShop.Application.Customers.DTOs; | ||
|
||
public static class DomainToDtoMapper | ||
{ | ||
public static CustomerDto ToCustomerDto(this Customer customer) => | ||
new(customer.Id, customer.Name, customer.Email, customer.Phone, customer.Gender, customer.AccountId); | ||
|
||
public static IEnumerable<CustomerDto> ToCustomerDto(this IEnumerable<Customer> customers) => | ||
customers.Select(ToCustomerDto); | ||
} |
23 changes: 23 additions & 0 deletions
23
src/RookieShop.Application/Customers/Queries/Get/GetCustomerHandler.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,23 @@ | ||
using Ardalis.GuardClauses; | ||
using Ardalis.Result; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Specifications; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Queries.Get; | ||
|
||
public sealed class GetCustomerHandler(IReadRepository<Customer> repository) | ||
: IQueryHandler<GetCustomerQuery, Result<CustomerDto>> | ||
{ | ||
public async Task<Result<CustomerDto>> Handle(GetCustomerQuery request, CancellationToken cancellationToken) | ||
{ | ||
CustomerByIdSpec spec = new(request.Id); | ||
|
||
var customer = await repository.FirstOrDefaultAsync(spec, cancellationToken); | ||
|
||
Guard.Against.NotFound(request.Id, customer); | ||
|
||
return customer.ToCustomerDto(); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/RookieShop.Application/Customers/Queries/Get/GetCustomerQuery.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,8 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Queries.Get; | ||
|
||
public sealed record GetCustomerQuery(CustomerId Id) : IQuery<Result<CustomerDto>>; |
8 changes: 8 additions & 0 deletions
8
src/RookieShop.Application/Customers/Queries/Get/GetCustomerValidator.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,8 @@ | ||
using FluentValidation; | ||
|
||
namespace RookieShop.Application.Customers.Queries.Get; | ||
|
||
public sealed class GetCustomerValidator : AbstractValidator<GetCustomerQuery> | ||
{ | ||
public GetCustomerValidator() => RuleFor(x => x.Id).NotEmpty(); | ||
} |
27 changes: 27 additions & 0 deletions
27
src/RookieShop.Application/Customers/Queries/List/ListCustomersHandler.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,27 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.Entities.CustomerAggregator; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Specifications; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Queries.List; | ||
|
||
public sealed class ListCustomersHandler(IReadRepository<Customer> repository) | ||
: IQueryHandler<ListCustomersQuery, PagedResult<IEnumerable<CustomerDto>>> | ||
{ | ||
public async Task<PagedResult<IEnumerable<CustomerDto>>> Handle(ListCustomersQuery request, | ||
CancellationToken cancellationToken) | ||
{ | ||
CustomersFilterSpec spec = new(request.PageIndex, request.PageSize, request.Name); | ||
|
||
var customers = await repository.ListAsync(spec, cancellationToken); | ||
|
||
var totalRecords = await repository.CountAsync(cancellationToken); | ||
|
||
var totalPages = (int)Math.Ceiling(totalRecords / (double)request.PageSize); | ||
|
||
var pagedInfo = new PagedInfo(request.PageIndex, request.PageSize, totalPages, totalRecords); | ||
|
||
return new(pagedInfo, customers.ToCustomerDto()); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/RookieShop.Application/Customers/Queries/List/ListCustomersQuery.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,8 @@ | ||
using Ardalis.Result; | ||
using RookieShop.Application.Customers.DTOs; | ||
using RookieShop.Domain.SharedKernel; | ||
|
||
namespace RookieShop.Application.Customers.Queries.List; | ||
|
||
public sealed record ListCustomersQuery(int PageIndex, int PageSize, string? Name) | ||
: IQuery<PagedResult<IEnumerable<CustomerDto>>>; |
12 changes: 12 additions & 0 deletions
12
src/RookieShop.Application/Customers/Queries/List/ListCustomersValidator.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,12 @@ | ||
using FluentValidation; | ||
|
||
namespace RookieShop.Application.Customers.Queries.List; | ||
|
||
public sealed class ListCustomersValidator : AbstractValidator<ListCustomersQuery> | ||
{ | ||
public ListCustomersValidator() | ||
{ | ||
RuleFor(x => x.PageIndex).GreaterThanOrEqualTo(1); | ||
RuleFor(x => x.PageSize).GreaterThanOrEqualTo(0); | ||
} | ||
} |
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
9 changes: 9 additions & 0 deletions
9
src/RookieShop.Domain/Entities/CustomerAggregator/Specifications/CustomerByIdSpec.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,9 @@ | ||
using Ardalis.Specification; | ||
using RookieShop.Domain.Entities.CustomerAggregator.Primitives; | ||
|
||
namespace RookieShop.Domain.Entities.CustomerAggregator.Specifications; | ||
|
||
public sealed class CustomerByIdSpec : Specification<Customer> | ||
{ | ||
public CustomerByIdSpec(CustomerId customerId) => Query.Where(customer => customer.Id == customerId); | ||
} |
18 changes: 18 additions & 0 deletions
18
src/RookieShop.Domain/Entities/CustomerAggregator/Specifications/CustomersFilterSpec.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,18 @@ | ||
using Ardalis.Specification; | ||
|
||
namespace RookieShop.Domain.Entities.CustomerAggregator.Specifications; | ||
|
||
public sealed class CustomersFilterSpec : Specification<Customer> | ||
{ | ||
public CustomersFilterSpec(int pageIndex, int pageSize, string? name) | ||
{ | ||
if (pageSize == 0) pageSize = int.MaxValue; | ||
|
||
Query | ||
.Skip((pageIndex - 1) * pageSize) | ||
.Take(pageSize) | ||
.OrderBy(customer => customer.Name); | ||
|
||
if (!string.IsNullOrWhiteSpace(name)) Query.Where(customer => customer.Name.Contains(name)); | ||
} | ||
} |