diff --git a/CleanArchitecture.sln b/CleanArchitecture.sln
index 05432e5..a3460bd 100644
--- a/CleanArchitecture.sln
+++ b/CleanArchitecture.sln
@@ -27,6 +27,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.Applicati
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.Api.IntegrationTests", "tests\CleanArchitecture.Api.IntegrationTests\CleanArchitecture.Api.IntegrationTests.csproj", "{2A315D67-B631-478A-8F67-9EE9DB03D0C5}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ErrorOr", "ErrorOr", "{C47B3C2F-F488-4960-AAF6-A68BB9CB07E3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErrorOr", "ErrorOr\src\ErrorOr.csproj", "{CBA12FED-3AB0-4276-A930-4AA691D595DE}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -76,6 +80,10 @@ Global
{2A315D67-B631-478A-8F67-9EE9DB03D0C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A315D67-B631-478A-8F67-9EE9DB03D0C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A315D67-B631-478A-8F67-9EE9DB03D0C5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CBA12FED-3AB0-4276-A930-4AA691D595DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CBA12FED-3AB0-4276-A930-4AA691D595DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CBA12FED-3AB0-4276-A930-4AA691D595DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CBA12FED-3AB0-4276-A930-4AA691D595DE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0B9F7D22-2A37-4EB6-A410-32BA01213D2A} = {E6C0A80B-5ADC-4138-A79D-C9C128EA163B}
@@ -88,5 +96,6 @@ Global
{9ED129C8-9C2F-4E19-8CCC-51FBC5CDE0A7} = {1DD25606-DF8E-4B91-9335-F916B14BF596}
{EC6267FA-4762-400A-8D7C-0FC0FB167AE8} = {1DD25606-DF8E-4B91-9335-F916B14BF596}
{2A315D67-B631-478A-8F67-9EE9DB03D0C5} = {1DD25606-DF8E-4B91-9335-F916B14BF596}
+ {CBA12FED-3AB0-4276-A930-4AA691D595DE} = {C47B3C2F-F488-4960-AAF6-A68BB9CB07E3}
EndGlobalSection
EndGlobal
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 2febe1d..f7218bb 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,21 +4,21 @@
-
-
+
+
-
+
-
-
-
+
+
+
-
+
@@ -27,7 +27,7 @@
-
+
@@ -36,9 +36,9 @@
-
-
+
+
-
+
\ No newline at end of file
diff --git a/ErrorOr b/ErrorOr
new file mode 160000
index 0000000..40de55e
--- /dev/null
+++ b/ErrorOr
@@ -0,0 +1 @@
+Subproject commit 40de55eb8738605310d096e3adf252e7b88e4cf9
diff --git a/src/CleanArchitecture.Api/Controllers/RemindersController.cs b/src/CleanArchitecture.Api/Controllers/RemindersController.cs
index 44151d2..79ac103 100644
--- a/src/CleanArchitecture.Api/Controllers/RemindersController.cs
+++ b/src/CleanArchitecture.Api/Controllers/RemindersController.cs
@@ -6,6 +6,8 @@
using CleanArchitecture.Contracts.Reminders;
using CleanArchitecture.Domain.Reminders;
+using ErrorOr;
+
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -16,67 +18,41 @@ namespace CleanArchitecture.Api.Controllers;
public class RemindersController(ISender _mediator) : ApiController
{
[HttpPost]
- public async Task CreateReminder(Guid userId, Guid subscriptionId, CreateReminderRequest request)
- {
- var command = new SetReminderCommand(userId, subscriptionId, request.Text, request.DateTime.UtcDateTime);
-
- var result = await _mediator.Send(command);
-
- return result.Match(
- reminder => CreatedAtAction(
- actionName: nameof(GetReminder),
- routeValues: new { UserId = userId, SubscriptionId = subscriptionId, ReminderId = reminder.Id },
- value: ToDto(reminder)),
- Problem);
- }
+ public async Task CreateReminder(Guid userId, Guid subscriptionId, CreateReminderRequest request) =>
+ await new SetReminderCommand(userId, subscriptionId, request.Text, request.DateTime.UtcDateTime).ToErrorOr()
+ .ThenAsync(command => _mediator.Send(command))
+ .Then(ToDto)
+ .Match(
+ reminderResponse => CreatedAtAction(
+ actionName: nameof(GetReminder),
+ routeValues: new { UserId = userId, SubscriptionId = subscriptionId, ReminderId = reminderResponse.Id },
+ value: reminderResponse),
+ Problem);
[HttpPost("{reminderId:guid}/dismiss")]
- public async Task DismissReminder(Guid userId, Guid subscriptionId, Guid reminderId)
- {
- var command = new DismissReminderCommand(userId, subscriptionId, reminderId);
-
- var result = await _mediator.Send(command);
-
- return result.Match(
- _ => NoContent(),
- Problem);
- }
+ public async Task DismissReminder(Guid userId, Guid subscriptionId, Guid reminderId) =>
+ await new DismissReminderCommand(userId, subscriptionId, reminderId).ToErrorOr()
+ .ThenAsync(command => _mediator.Send(command))
+ .Match(_ => NoContent(), Problem);
[HttpDelete("{reminderId:guid}")]
- public async Task DeleteReminder(Guid userId, Guid subscriptionId, Guid reminderId)
- {
- var command = new DeleteReminderCommand(userId, subscriptionId, reminderId);
-
- var result = await _mediator.Send(command);
-
- return result.Match(
- _ => NoContent(),
- Problem);
- }
+ public async Task DeleteReminder(Guid userId, Guid subscriptionId, Guid reminderId) =>
+ await new DeleteReminderCommand(userId, subscriptionId, reminderId).ToErrorOr()
+ .ThenAsync(command => _mediator.Send(command))
+ .Match(_ => NoContent(), Problem);
[HttpGet("{reminderId:guid}")]
- public async Task GetReminder(Guid userId, Guid subscriptionId, Guid reminderId)
- {
- var query = new GetReminderQuery(userId, subscriptionId, reminderId);
-
- var result = await _mediator.Send(query);
-
- return result.Match(
- reminder => Ok(ToDto(reminder)),
- Problem);
- }
+ public async Task GetReminder(Guid userId, Guid subscriptionId, Guid reminderId) =>
+ await new GetReminderQuery(userId, subscriptionId, reminderId).ToErrorOr()
+ .ThenAsync(query => _mediator.Send(query))
+ .Match(Ok, Problem);
[HttpGet]
- public async Task ListReminders(Guid userId, Guid subscriptionId)
- {
- var query = new ListRemindersQuery(userId, subscriptionId);
-
- var result = await _mediator.Send(query);
-
- return result.Match(
- reminders => Ok(reminders.ConvertAll(ToDto)),
- Problem);
- }
+ public async Task ListReminders(Guid userId, Guid subscriptionId) =>
+ await new ListRemindersQuery(userId, subscriptionId).ToErrorOr()
+ .ThenAsync(query => _mediator.Send(query))
+ .Then(reminders => reminders.ConvertAll(ToDto))
+ .Match(Ok, Problem);
private ReminderResponse ToDto(Reminder reminder) =>
new(reminder.Id, reminder.Text, reminder.DateTime, reminder.IsDismissed);
diff --git a/src/CleanArchitecture.Api/Controllers/SubscriptionsController.cs b/src/CleanArchitecture.Api/Controllers/SubscriptionsController.cs
index a3a2041..8e3de39 100644
--- a/src/CleanArchitecture.Api/Controllers/SubscriptionsController.cs
+++ b/src/CleanArchitecture.Api/Controllers/SubscriptionsController.cs
@@ -4,6 +4,8 @@
using CleanArchitecture.Application.Subscriptions.Queries.GetSubscription;
using CleanArchitecture.Contracts.Subscriptions;
+using ErrorOr;
+
using MediatR;
using Microsoft.AspNetCore.Mvc;
@@ -17,55 +19,35 @@ namespace CleanArchitecture.Api.Controllers;
public class SubscriptionsController(IMediator _mediator) : ApiController
{
[HttpPost]
- public async Task CreateSubscription(Guid userId, CreateSubscriptionRequest request)
- {
- if (!DomainSubscriptionType.TryFromName(request.SubscriptionType.ToString(), out var subscriptionType))
- {
- return Problem(
- statusCode: StatusCodes.Status400BadRequest,
- detail: "Invalid plan type");
- }
-
- var command = new CreateSubscriptionCommand(
- userId,
- request.FirstName,
- request.LastName,
- request.Email,
- subscriptionType);
-
- var result = await _mediator.Send(command);
-
- return result.Match(
- subscription => CreatedAtAction(
- actionName: nameof(GetSubscription),
- routeValues: new { UserId = userId },
- value: ToDto(subscription)),
- Problem);
- }
+ public async Task CreateSubscription(Guid userId, CreateSubscriptionRequest request) =>
+ await DomainSubscriptionType.TryFromName(request.SubscriptionType.ToString(), out var subscriptionType).ToErrorOr()
+ .FailIf(val => val is false, Error.Validation("Invalid plan type"))
+ .Then(_ => new CreateSubscriptionCommand(
+ userId,
+ request.FirstName,
+ request.LastName,
+ request.Email,
+ subscriptionType))
+ .ThenAsync(command => _mediator.Send(command))
+ .Match(
+ subscription => CreatedAtAction(
+ actionName: nameof(GetSubscription),
+ routeValues: new { UserId = userId },
+ value: ToDto(subscription)),
+ Problem);
[HttpDelete("{subscriptionId:guid}")]
- public async Task DeleteSubscription(Guid userId, Guid subscriptionId)
- {
- var command = new CancelSubscriptionCommand(userId, subscriptionId);
-
- var result = await _mediator.Send(command);
-
- return result.Match(
- _ => NoContent(),
- Problem);
- }
+ public async Task DeleteSubscription(Guid userId, Guid subscriptionId) =>
+ await new CancelSubscriptionCommand(userId, subscriptionId).ToErrorOr()
+ .ThenAsync(command => _mediator.Send(command))
+ .Match(_ => NoContent(), Problem);
[HttpGet]
- public async Task GetSubscription(Guid userId)
- {
- var query = new GetSubscriptionQuery(userId);
-
- var result = await _mediator.Send(query);
-
- return result.Match(
- user => Ok(ToDto(user)),
- Problem);
- }
+ public async Task GetSubscription(Guid userId) =>
+ await new GetSubscriptionQuery(userId).ToErrorOr()
+ .ThenAsync(query => _mediator.Send(query))
+ .Then(ToDto)
+ .Match(Ok, Problem);
private static SubscriptionType ToDto(DomainSubscriptionType subscriptionType) =>
subscriptionType.Name switch
diff --git a/src/CleanArchitecture.Api/Controllers/TokensController.cs b/src/CleanArchitecture.Api/Controllers/TokensController.cs
index f172eeb..3fb7b66 100644
--- a/src/CleanArchitecture.Api/Controllers/TokensController.cs
+++ b/src/CleanArchitecture.Api/Controllers/TokensController.cs
@@ -3,6 +3,8 @@
using CleanArchitecture.Contracts.Common;
using CleanArchitecture.Contracts.Tokens;
+using ErrorOr;
+
using MediatR;
using Microsoft.AspNetCore.Authorization;
@@ -17,41 +19,29 @@ namespace CleanArchitecture.Api.Controllers;
public class TokensController(ISender _mediator) : ApiController
{
[HttpPost("generate")]
- public async Task GenerateToken(GenerateTokenRequest request)
- {
- if (!DomainSubscriptionType.TryFromName(request.SubscriptionType.ToString(), out var plan))
- {
- return Problem(
- statusCode: StatusCodes.Status400BadRequest,
- detail: "Invalid subscription type");
- }
-
- var query = new GenerateTokenQuery(
- request.Id,
- request.FirstName,
- request.LastName,
- request.Email,
- plan,
- request.Permissions,
- request.Roles);
-
- var result = await _mediator.Send(query);
-
- return result.Match(
- generateTokenResult => Ok(ToDto(generateTokenResult)),
- Problem);
- }
-
- private static TokenResponse ToDto(GenerateTokenResult authResult)
- {
- return new TokenResponse(
+ public async Task GenerateToken(GenerateTokenRequest request) =>
+ await DomainSubscriptionType.TryFromName(request.SubscriptionType.ToString(), out var plan).ToErrorOr()
+ .FailIf(val => val is false, Error.Validation("Invalid subscription type"))
+ .Then(_ => new GenerateTokenQuery(
+ request.Id,
+ request.FirstName,
+ request.LastName,
+ request.Email,
+ plan,
+ request.Permissions,
+ request.Roles))
+ .ThenAsync(query => _mediator.Send(query))
+ .Then(ToDto)
+ .Match(Ok, Problem);
+
+ private static ErrorOr ToDto(GenerateTokenResult authResult) =>
+ new TokenResponse(
authResult.Id,
authResult.FirstName,
authResult.LastName,
authResult.Email,
ToDto(authResult.SubscriptionType),
authResult.Token);
- }
private static SubscriptionType ToDto(DomainSubscriptionType subscriptionType) =>
subscriptionType.Name switch
diff --git a/src/CleanArchitecture.Application/Reminders/Commands/DeleteReminder/DeleteReminderCommandHandler.cs b/src/CleanArchitecture.Application/Reminders/Commands/DeleteReminder/DeleteReminderCommandHandler.cs
index 72fb4b7..52ce332 100644
--- a/src/CleanArchitecture.Application/Reminders/Commands/DeleteReminder/DeleteReminderCommandHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Commands/DeleteReminder/DeleteReminderCommandHandler.cs
@@ -1,4 +1,6 @@
using CleanArchitecture.Application.Common.Interfaces;
+using CleanArchitecture.Domain.Reminders;
+using CleanArchitecture.Domain.Users;
using ErrorOr;
@@ -12,24 +14,14 @@ public class DeleteReminderCommandHandler(
{
public async Task> Handle(DeleteReminderCommand request, CancellationToken cancellationToken)
{
- var reminder = await _remindersRepository.GetByIdAsync(request.ReminderId, cancellationToken);
-
- var user = await _usersRepository.GetByIdAsync(request.UserId, cancellationToken);
-
- if (reminder is null || user is null)
- {
- return Error.NotFound(description: "Reminder not found");
- }
-
- var deleteReminderResult = user.DeleteReminder(reminder);
-
- if (deleteReminderResult.IsError)
- {
- return deleteReminderResult.Errors;
- }
-
- await _usersRepository.UpdateAsync(user, cancellationToken);
-
- return Result.Success;
+ Reminder? reminder = await _remindersRepository.GetByIdAsync(request.ReminderId, cancellationToken);
+ User? user = await _usersRepository.GetByIdAsync(request.UserId, cancellationToken);
+
+ return await (Reminder: reminder, User: user).ToErrorOr()
+ .FailIf(pair => pair.Reminder is null || pair.User is null, Error.NotFound("Reminder not found"))
+ .Then(pair => (Reminder: pair.Reminder!, User: pair.User!))
+ .Then(pair => pair.User.DeleteReminder(pair.Reminder).Then(success => pair))
+ .ThenDoAsync(pair => _usersRepository.UpdateAsync(pair.User, cancellationToken))
+ .Then(_ => Result.Success);
}
}
\ No newline at end of file
diff --git a/src/CleanArchitecture.Application/Reminders/Commands/DismissReminder/DismissReminderCommandHandler.cs b/src/CleanArchitecture.Application/Reminders/Commands/DismissReminder/DismissReminderCommandHandler.cs
index 908e193..f93c814 100644
--- a/src/CleanArchitecture.Application/Reminders/Commands/DismissReminder/DismissReminderCommandHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Commands/DismissReminder/DismissReminderCommandHandler.cs
@@ -6,28 +6,13 @@
namespace CleanArchitecture.Application.Reminders.Commands.DismissReminder;
-public class DismissReminderCommandHandler(
- IUsersRepository _usersRepository)
- : IRequestHandler>
+public class DismissReminderCommandHandler(IUsersRepository _usersRepository)
+ : IRequestHandler>
{
- public async Task> Handle(DismissReminderCommand request, CancellationToken cancellationToken)
- {
- var user = await _usersRepository.GetByIdAsync(request.UserId, cancellationToken);
-
- if (user is null)
- {
- return Error.NotFound(description: "Reminder not found");
- }
-
- var dismissReminderResult = user.DismissReminder(request.ReminderId);
-
- if (dismissReminderResult.IsError)
- {
- return dismissReminderResult.Errors;
- }
-
- await _usersRepository.UpdateAsync(user, cancellationToken);
-
- return Result.Success;
- }
-}
+ public async Task> Handle(DismissReminderCommand request, CancellationToken cancellationToken) =>
+ await (await _usersRepository.GetByIdAsync(request.UserId, cancellationToken)).ToErrorOr()
+ .FailIf(user => user is null, Error.NotFound("User not found"))
+ .Then(user => user!.DismissReminder(request.ReminderId).Then(success => user!))
+ .ThenDoAsync(user => _usersRepository.UpdateAsync(user, cancellationToken))
+ .Then(_ => Result.Success);
+}
\ No newline at end of file
diff --git a/src/CleanArchitecture.Application/Reminders/Commands/SetReminder/SetReminderCommandHandler.cs b/src/CleanArchitecture.Application/Reminders/Commands/SetReminder/SetReminderCommandHandler.cs
index 0ce7764..4328563 100644
--- a/src/CleanArchitecture.Application/Reminders/Commands/SetReminder/SetReminderCommandHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Commands/SetReminder/SetReminderCommandHandler.cs
@@ -12,28 +12,20 @@ public class SetReminderCommandHandler(IUsersRepository _usersRepository)
{
public async Task> Handle(SetReminderCommand command, CancellationToken cancellationToken)
{
- var reminder = new Reminder(
- command.UserId,
- command.SubscriptionId,
- command.Text,
- command.DateTime);
-
- var user = await _usersRepository.GetBySubscriptionIdAsync(command.SubscriptionId, cancellationToken);
-
- if (user is null)
- {
- return Error.NotFound(description: "Subscription not found");
- }
-
- var setReminderResult = user.SetReminder(reminder);
-
- if (setReminderResult.IsError)
- {
- return setReminderResult.Errors;
- }
-
- await _usersRepository.UpdateAsync(user, cancellationToken);
-
- return reminder;
+ return await (await _usersRepository.GetBySubscriptionIdAsync(command.SubscriptionId, cancellationToken)).ToErrorOr()
+ .FailIf(user => user is null, Error.NotFound(description: "Subscription not found"))
+ .Then(user =>
+ {
+ var reminder = new Reminder(
+ command.UserId,
+ command.SubscriptionId,
+ command.Text,
+ command.DateTime);
+
+ return user!.SetReminder(reminder)
+ .Then(success => (User: user!, Reminder: reminder));
+ })
+ .ThenDoAsync(pair => _usersRepository.UpdateAsync(pair.User, cancellationToken))
+ .Then(pair => pair.Reminder);
}
}
\ No newline at end of file
diff --git a/src/CleanArchitecture.Application/Reminders/Events/ReminderDeletedEventHandler.cs b/src/CleanArchitecture.Application/Reminders/Events/ReminderDeletedEventHandler.cs
index 1725a42..01118cf 100644
--- a/src/CleanArchitecture.Application/Reminders/Events/ReminderDeletedEventHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Events/ReminderDeletedEventHandler.cs
@@ -1,6 +1,8 @@
using CleanArchitecture.Application.Common.Interfaces;
using CleanArchitecture.Domain.Users.Events;
+using ErrorOr;
+
using MediatR;
namespace CleanArchitecture.Application.Reminders.Events;
@@ -9,9 +11,10 @@ public class ReminderDeletedEventHandler(IRemindersRepository _remindersReposito
{
public async Task Handle(ReminderDeletedEvent notification, CancellationToken cancellationToken)
{
- var reminder = await _remindersRepository.GetByIdAsync(notification.ReminderId, cancellationToken)
- ?? throw new InvalidOperationException();
-
- await _remindersRepository.RemoveAsync(reminder, cancellationToken);
+ await (await _remindersRepository.GetByIdAsync(notification.ReminderId, cancellationToken)).ToErrorOr()
+ .FailIf(reminder => reminder is null, Error.Unexpected())
+ .SwitchAsync(
+ reminder => _remindersRepository.RemoveAsync(reminder!, cancellationToken),
+ _ => throw new InvalidOperationException());
}
}
diff --git a/src/CleanArchitecture.Application/Reminders/Events/ReminderDismissedEventHandler.cs b/src/CleanArchitecture.Application/Reminders/Events/ReminderDismissedEventHandler.cs
index 88cc760..ca1835f 100644
--- a/src/CleanArchitecture.Application/Reminders/Events/ReminderDismissedEventHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Events/ReminderDismissedEventHandler.cs
@@ -1,6 +1,8 @@
using CleanArchitecture.Application.Common.Interfaces;
using CleanArchitecture.Domain.Users.Events;
+using ErrorOr;
+
using MediatR;
namespace CleanArchitecture.Application.Reminders.Events;
@@ -9,11 +11,9 @@ public class ReminderDismissedEventHandler(IRemindersRepository _remindersReposi
{
public async Task Handle(ReminderDismissedEvent notification, CancellationToken cancellationToken)
{
- var reminder = await _remindersRepository.GetByIdAsync(notification.ReminderId, cancellationToken)
- ?? throw new InvalidOperationException();
-
- reminder.Dismiss();
-
- await _remindersRepository.UpdateAsync(reminder, cancellationToken);
+ await (await _remindersRepository.GetByIdAsync(notification.ReminderId, cancellationToken)).ToErrorOr()
+ .FailIf(reminder => reminder is null, Error.Unexpected())
+ .Then(reminder => reminder!.Dismiss().Then(success => reminder!))
+ .ThenDoAsync(reminder => _remindersRepository.UpdateAsync(reminder, cancellationToken));
}
}
diff --git a/src/CleanArchitecture.Application/Reminders/Queries/GetReminder/GetReminderQueryHandler.cs b/src/CleanArchitecture.Application/Reminders/Queries/GetReminder/GetReminderQueryHandler.cs
index e14e55b..15ac50d 100644
--- a/src/CleanArchitecture.Application/Reminders/Queries/GetReminder/GetReminderQueryHandler.cs
+++ b/src/CleanArchitecture.Application/Reminders/Queries/GetReminder/GetReminderQueryHandler.cs
@@ -12,13 +12,8 @@ public class GetReminderQueryHandler(IRemindersRepository _remindersRepository)
{
public async Task> Handle(GetReminderQuery query, CancellationToken cancellationToken)
{
- var reminder = await _remindersRepository.GetByIdAsync(query.ReminderId, cancellationToken);
-
- if (reminder?.UserId != query.UserId)
- {
- return Error.NotFound(description: "Reminder not found");
- }
-
- return reminder;
+ return (await _remindersRepository.GetByIdAsync(query.ReminderId, cancellationToken)).ToErrorOr()
+ .FailIf(reminder => reminder?.UserId != query.UserId, Error.NotFound(description: "Reminder not found"))
+ .Then(reminder => reminder!);
}
}
\ No newline at end of file
diff --git a/src/CleanArchitecture.Application/Subscriptions/Commands/CancelSubscription/CancelSubscriptionCommandHandler.cs b/src/CleanArchitecture.Application/Subscriptions/Commands/CancelSubscription/CancelSubscriptionCommandHandler.cs
index 59d2c76..704a0d6 100644
--- a/src/CleanArchitecture.Application/Subscriptions/Commands/CancelSubscription/CancelSubscriptionCommandHandler.cs
+++ b/src/CleanArchitecture.Application/Subscriptions/Commands/CancelSubscription/CancelSubscriptionCommandHandler.cs
@@ -9,24 +9,10 @@ namespace CleanArchitecture.Application.Subscriptions.Commands.CancelSubscriptio
public class CancelSubscriptionCommandHandler(IUsersRepository _usersRepository)
: IRequestHandler>
{
- public async Task> Handle(CancelSubscriptionCommand request, CancellationToken cancellationToken)
- {
- var user = await _usersRepository.GetByIdAsync(request.UserId, cancellationToken);
-
- if (user is null)
- {
- return Error.NotFound(description: "User not found");
- }
-
- var deleteSubscriptionResult = user.CancelSubscription(request.SubscriptionId);
-
- if (deleteSubscriptionResult.IsError)
- {
- return deleteSubscriptionResult.Errors;
- }
-
- await _usersRepository.UpdateAsync(user, cancellationToken);
-
- return Result.Success;
- }
+ public async Task> Handle(CancelSubscriptionCommand request, CancellationToken cancellationToken) =>
+ await (await _usersRepository.GetByIdAsync(request.UserId, cancellationToken)).ToErrorOr()
+ .FailIf(user => user is null, Error.NotFound(description: "User not found"))
+ .Then(user => user!.CancelSubscription(request.SubscriptionId).Then(success => user!))
+ .ThenDoAsync(user => _usersRepository.UpdateAsync(user, cancellationToken))
+ .Then(_ => Result.Success);
}
diff --git a/src/CleanArchitecture.Application/Subscriptions/Commands/CreateSubscription/CreateSubscriptionCommandHandler.cs b/src/CleanArchitecture.Application/Subscriptions/Commands/CreateSubscription/CreateSubscriptionCommandHandler.cs
index cbaa03e..ad3931d 100644
--- a/src/CleanArchitecture.Application/Subscriptions/Commands/CreateSubscription/CreateSubscriptionCommandHandler.cs
+++ b/src/CleanArchitecture.Application/Subscriptions/Commands/CreateSubscription/CreateSubscriptionCommandHandler.cs
@@ -12,24 +12,22 @@ namespace CleanArchitecture.Application.Subscriptions.Commands.CreateSubscriptio
public class CreateSubscriptionCommandHandler(
IUsersRepository _usersRepository) : IRequestHandler>
{
- public async Task> Handle(CreateSubscriptionCommand request, CancellationToken cancellationToken)
- {
- if (await _usersRepository.GetByIdAsync(request.UserId, cancellationToken) is not null)
- {
- return Error.Conflict(description: "User already has an active subscription");
- }
-
- var subscription = new Subscription(request.SubscriptionType);
-
- var user = new User(
- request.UserId,
- request.FirstName,
- request.LastName,
- request.Email,
- subscription);
-
- await _usersRepository.AddAsync(user, cancellationToken);
-
- return SubscriptionResult.FromUser(user);
- }
+ public async Task> Handle(CreateSubscriptionCommand request, CancellationToken cancellationToken) =>
+ await (await _usersRepository.GetByIdAsync(request.UserId, cancellationToken)).ToErrorOr()
+ .FailIf(user => user is not null, Error.Conflict(description: "User already has an active subscription"))
+ .Then(_ =>
+ {
+ var subscription = new Subscription(request.SubscriptionType);
+
+ var user = new User(
+ request.UserId,
+ request.FirstName,
+ request.LastName,
+ request.Email,
+ subscription);
+
+ return (Subscription: subscription, User: user);
+ })
+ .ThenDoAsync(pair => _usersRepository.AddAsync(pair.User, cancellationToken))
+ .Then(pair => SubscriptionResult.FromUser(pair.User));
}
diff --git a/src/CleanArchitecture.Application/Subscriptions/Queries/GetSubscription/GetSubscriptionQueryHandler.cs b/src/CleanArchitecture.Application/Subscriptions/Queries/GetSubscription/GetSubscriptionQueryHandler.cs
index 8b084f1..fed39d2 100644
--- a/src/CleanArchitecture.Application/Subscriptions/Queries/GetSubscription/GetSubscriptionQueryHandler.cs
+++ b/src/CleanArchitecture.Application/Subscriptions/Queries/GetSubscription/GetSubscriptionQueryHandler.cs
@@ -13,8 +13,8 @@ public class GetSubscriptionQueryHandler(IUsersRepository _usersRepository)
{
public async Task> Handle(GetSubscriptionQuery request, CancellationToken cancellationToken)
{
- return await _usersRepository.GetByIdAsync(request.UserId, cancellationToken) is User user
- ? SubscriptionResult.FromUser(user)
- : Error.NotFound(description: "Subscription not found.");
+ return (await _usersRepository.GetByIdAsync(request.UserId, cancellationToken)).ToErrorOr()
+ .FailIf(user => user is null, Error.NotFound(description: "Subscription not found."))
+ .Then(user => SubscriptionResult.FromUser(user!));
}
}
diff --git a/src/CleanArchitecture.Domain/CleanArchitecture.Domain.csproj b/src/CleanArchitecture.Domain/CleanArchitecture.Domain.csproj
index 9813ac5..5205b72 100644
--- a/src/CleanArchitecture.Domain/CleanArchitecture.Domain.csproj
+++ b/src/CleanArchitecture.Domain/CleanArchitecture.Domain.csproj
@@ -8,9 +8,12 @@
-
+
+
+
+