Skip to content

Commit

Permalink
feat(resultpattern): add result pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
MorveN11 committed Sep 8, 2024
1 parent 6669bc6 commit 61ace68
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ dotnet_diagnostic.IDE0055.severity = none
dotnet_diagnostic.CS1591.severity = none
# Remove warning about using a resource table - Multilang
dotnet_diagnostic.CA1303.severity = none
# Remove warning about implicit conversion
dotnet_diagnostic.CA2225.severity = none

[**/GlobalUsings.cs]
# Disable warning about global usings
Expand Down
9 changes: 8 additions & 1 deletion DistributionCenter.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
Expand All @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistributionCenter.Domain.T
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistributionCenter.Infraestructure.Tests", "test\DistributionCenter.Infraestructure.Tests\DistributionCenter.Infraestructure.Tests.csproj", "{C06B0D45-AAF2-45AC-8C09-B407B209F195}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DistributionCenter.Commons", "src\DistributionCenter.Commons\DistributionCenter.Commons.csproj", "{547BB964-028E-4B07-9973-89EAD0C6BCC1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -64,6 +66,10 @@ Global
{C06B0D45-AAF2-45AC-8C09-B407B209F195}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C06B0D45-AAF2-45AC-8C09-B407B209F195}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C06B0D45-AAF2-45AC-8C09-B407B209F195}.Release|Any CPU.Build.0 = Release|Any CPU
{547BB964-028E-4B07-9973-89EAD0C6BCC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{547BB964-028E-4B07-9973-89EAD0C6BCC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{547BB964-028E-4B07-9973-89EAD0C6BCC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{547BB964-028E-4B07-9973-89EAD0C6BCC1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A3640FBB-7830-4B83-A3E3-85A41E7C1A75} = {39F24848-9361-498F-8429-2FF5FD73CB5E}
Expand All @@ -74,5 +80,6 @@ Global
{BEC5A375-2EEE-47C8-A21A-C78B9F103808} = {027AE2DC-44EF-4918-BD62-5DB03BE9AAEA}
{2CCC7992-E5F7-4C74-B0A5-6827940D12E9} = {027AE2DC-44EF-4918-BD62-5DB03BE9AAEA}
{C06B0D45-AAF2-45AC-8C09-B407B209F195} = {027AE2DC-44EF-4918-BD62-5DB03BE9AAEA}
{547BB964-028E-4B07-9973-89EAD0C6BCC1} = {39F24848-9361-498F-8429-2FF5FD73CB5E}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
</PropertyGroup>
</Project>
9 changes: 9 additions & 0 deletions src/DistributionCenter.Commons/Enums/ErrorType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace DistributionCenter.Commons.Enums;

public enum ErrorType
{
Conflict,
Validation,
NotFound,
Unauthorized,
}
53 changes: 53 additions & 0 deletions src/DistributionCenter.Commons/Errors/Error.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace DistributionCenter.Commons.Errors;

using DistributionCenter.Commons.Enums;
using DistributionCenter.Commons.Errors.Interfaces;

#pragma warning disable CA1716
public readonly record struct Error : IError
{
public string Code { get; }

public string Description { get; }

public ErrorType Type { get; }

private Error(string code, string description, ErrorType type)
{
Code = code;
Description = description;
Type = type;
}

public static IError Conflict(
string code = "General.Conflict",
string description = "A 'Conflict' error has occurred"
)
{
return new Error(code, description, ErrorType.Conflict);
}

public static IError Validation(
string code = "General.Validation",
string description = "A 'Validation' error has occurred"
)
{
return new Error(code, description, ErrorType.Validation);
}

public static IError NotFound(
string code = "General.NotFound",
string description = "A 'Not Found' error has occurred"
)
{
return new Error(code, description, ErrorType.NotFound);
}

public static IError Unauthorized(
string code = "General.Unauthorized",
string description = "A 'Unauthorized' error has occurred"
)
{
return new Error(code, description, ErrorType.Unauthorized);
}
}
12 changes: 12 additions & 0 deletions src/DistributionCenter.Commons/Errors/Interfaces/IError.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace DistributionCenter.Commons.Errors.Interfaces;

using DistributionCenter.Commons.Enums;

public interface IError
{
string Code { get; }

string Description { get; }

ErrorType Type { get; }
}
19 changes: 19 additions & 0 deletions src/DistributionCenter.Commons/Results/Interfaces/IResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace DistributionCenter.Commons.Results.Interfaces;

using DistributionCenter.Commons.Errors.Interfaces;

public interface IResult
{
bool IsSuccess { get; }

ICollection<IError> Errors { get; }
}

public interface IResult<T> : IResult
{
T Value { get; }

TNext Match<TNext>(Func<T, TNext> success, Func<ICollection<IError>, TNext> failure);

Task<TNext> MatchAsync<TNext>(Func<T, Task<TNext>> success, Func<ICollection<IError>, Task<TNext>> failure);
}
42 changes: 42 additions & 0 deletions src/DistributionCenter.Commons/Results/Result.Implicit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace DistributionCenter.Commons.Results;

using System.Collections.ObjectModel;
using DistributionCenter.Commons.Errors;
using DistributionCenter.Commons.Errors.Interfaces;
using DistributionCenter.Commons.Results.Interfaces;

public partial class Result : IResult
{
public static Result Ok()
{
return new Result();
}

public static implicit operator Result(Error error)
{
return new Result(error);
}

public static implicit operator Result(Collection<IError> errors)
{
return new Result(errors);
}
}

public partial class Result<T> : Result, IResult<T>
{
public static implicit operator Result<T>(T value)
{
return new Result<T>(value);
}

public static implicit operator Result<T>(Error error)
{
return new Result<T>(error);
}

public static implicit operator Result<T>(Collection<IError> errors)
{
return new Result<T>(errors);
}
}
23 changes: 23 additions & 0 deletions src/DistributionCenter.Commons/Results/Result.Match.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace DistributionCenter.Commons.Results;

using DistributionCenter.Commons.Errors.Interfaces;
using DistributionCenter.Commons.Results.Interfaces;

public partial class Result<T> : Result, IResult<T>
{
public TNext Match<TNext>(Func<T, TNext> success, Func<ICollection<IError>, TNext> failure)
{
ArgumentNullException.ThrowIfNull(success, nameof(success));
ArgumentNullException.ThrowIfNull(failure, nameof(failure));

return IsSuccess ? success(Value) : failure(Errors);
}

public Task<TNext> MatchAsync<TNext>(Func<T, Task<TNext>> success, Func<ICollection<IError>, Task<TNext>> failure)
{
ArgumentNullException.ThrowIfNull(success, nameof(success));
ArgumentNullException.ThrowIfNull(failure, nameof(failure));

return IsSuccess ? success(Value) : failure(Errors);
}
}
65 changes: 65 additions & 0 deletions src/DistributionCenter.Commons/Results/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
namespace DistributionCenter.Commons.Results;

using DistributionCenter.Commons.Errors.Interfaces;
using DistributionCenter.Commons.Results.Interfaces;

public partial class Result : IResult
{
private readonly ICollection<IError>? _errors;

protected Result() { }

protected Result(IError error)
{
_errors = [error];
}

protected Result(ICollection<IError> errors)
{
_errors = errors;
}

public bool IsSuccess => _errors is null || _errors.Count == 0;

public ICollection<IError> Errors
{
get
{
if (IsSuccess)
{
throw new InvalidOperationException("Cannot access errors when there are no errors.");
}

return _errors!;
}
}
}

public partial class Result<T> : Result, IResult<T>
{
private readonly T? _value;

private Result(T value)
{
_value = value;
}

private Result(IError error)
: base(error) { }

private Result(ICollection<IError> errors)
: base(errors) { }

public T Value
{
get
{
if (!IsSuccess || _value is null)
{
throw new InvalidOperationException("Cannot access value when there are errors.");
}

return _value;
}
}
}

0 comments on commit 61ace68

Please sign in to comment.