Skip to content

Commit

Permalink
CommandResult refactoring
Browse files Browse the repository at this point in the history
Add CommandResultBase.cs
Add unit test for CommandResult and CreationResult
  • Loading branch information
Brice Chapellier committed Aug 8, 2023
1 parent 724dd8c commit a7e7071
Show file tree
Hide file tree
Showing 6 changed files with 359 additions and 93 deletions.
64 changes: 21 additions & 43 deletions src/HerrGeneral.WriteSide/CommandResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@
/// <summary>
/// Result of an handled command.
/// </summary>
public sealed record CommandResult : IWithSuccess
public sealed record CommandResult : CommandResultBase
{
private readonly Exception? _panicException;
private readonly DomainError? _domainError;
private bool IsDomainError => _domainError != null;
private bool IsPanicError => _panicException != null;

/// <summary>
/// Operation succeeded.
/// </summary>
public bool IsSuccess => !IsDomainError && !IsPanicError;

private CommandResult() { }
private CommandResult()
{
}

private CommandResult(DomainError error) : base(error)
{
}

private CommandResult(DomainError error) => _domainError = error;
private CommandResult(Exception panicException) : base(panicException)
{
}

private CommandResult(Exception panicException) => _panicException = panicException;

/// <summary>
/// Factory for success.
Expand Down Expand Up @@ -52,12 +49,14 @@ public TResult Match<TResult>(Func<TResult> onSuccess, Func<DomainError, TResult
if (onSuccess == null) throw new ArgumentNullException(nameof(onSuccess));
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));
if (onPanicError == null) throw new ArgumentNullException(nameof(onPanicError));

return IsSuccess
? onSuccess()
: IsDomainError
? onDomainError(_domainError ?? throw new InvalidOperationException($"{nameof(_domainError)} is null"))
: onPanicError(_panicException ?? throw new InvalidOperationException($"{nameof(_panicException)} is null"));
? onDomainError(DomainError ?? throw new InvalidOperationException($"{nameof(DomainError)} is null"))
: IsPanicError
? onPanicError(PanicException ?? throw new InvalidOperationException($"{nameof(PanicException)} is null"))
: throw new InvalidOperationException("Invalid state");
}

/// <summary>
Expand All @@ -70,13 +69,16 @@ public void Match(Action onSuccess, Action<DomainError> onDomainError, Action<Ex
{
if (onSuccess == null) throw new ArgumentNullException(nameof(onSuccess));
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));
if (onPanicError == null) throw new ArgumentNullException(nameof(onPanicError));

if (IsSuccess)
onSuccess();
else if (IsDomainError)
onDomainError(_domainError ?? throw new InvalidOperationException($"{nameof(_domainError)} is null"));
onDomainError(DomainError ?? throw new InvalidOperationException($"{nameof(DomainError)} is null"));
else if (IsPanicError)
onPanicError(PanicException ?? throw new InvalidOperationException($"{nameof(PanicException)} is null"));
else
onPanicError(_panicException ?? throw new InvalidOperationException($"{nameof(_panicException)} is null"));
throw new InvalidOperationException("Invalid state");
}

/// <summary>
Expand All @@ -90,30 +92,6 @@ public void MatchSuccess(Action success)
if (IsSuccess) success();
}

/// <summary>
/// Evaluates a specified action on domain error.
/// </summary>
/// <param name="onDomainError">The action to evaluate if the value is missing.</param>
public void MatchDomainError(Action<DomainError> onDomainError)
{
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));

if (IsDomainError) onDomainError(_domainError ?? throw new InvalidOperationException($"{nameof(_domainError)} is null"));
}

/// <summary>
/// Evaluates a specified action on panic exception.
/// </summary>
/// <param name="onPanicException"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException"></exception>
public void MatchPanicException(Action<Exception> onPanicException)
{
if (onPanicException == null) throw new ArgumentNullException(nameof(onPanicException));

if (IsPanicError) onPanicException(_panicException ?? throw new InvalidOperationException($"{nameof(_panicException)} is null"));
}

/// <summary>
/// True if success, else false.
/// </summary>
Expand Down
72 changes: 72 additions & 0 deletions src/HerrGeneral.WriteSide/CommandResultBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
namespace HerrGeneral.WriteSide;

/// <summary>
/// Base class for command result implementation
/// </summary>
public abstract record CommandResultBase : IWithSuccess
{
/// <summary>
/// A panic exception
/// </summary>
internal Exception? PanicException;

/// <summary>
/// A domain exception
/// </summary>
internal DomainError? DomainError;

/// <summary>
///
/// </summary>
internal bool IsDomainError => DomainError != null;

internal bool IsPanicError => PanicException != null;

/// <summary>
/// Operation succeeded.
/// </summary>
public bool IsSuccess => !IsDomainError && !IsPanicError;

/// <summary>
/// Ctor
/// </summary>
internal CommandResultBase()
{
}

/// <summary>
/// Ctor
/// </summary>
/// <param name="error"></param>
internal CommandResultBase(DomainError error) => DomainError = error;

/// <summary>
/// Ctor
/// </summary>
/// <param name="panicException"></param>
internal CommandResultBase(Exception panicException) => PanicException = panicException;

/// <summary>
/// Evaluates a specified action on domain error.
/// </summary>
/// <param name="onDomainError">The action to evaluate if the value is missing.</param>
public void MatchDomainError(Action<DomainError> onDomainError)
{
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));

if (IsDomainError) onDomainError(DomainError ?? throw new InvalidOperationException($"{nameof(DomainError)} is null"));
}

/// <summary>
/// Evaluates a specified action on panic exception.
/// </summary>
/// <param name="onPanicException"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException"></exception>
public void MatchPanicException(Action<Exception> onPanicException)
{
if (onPanicException == null) throw new ArgumentNullException(nameof(onPanicException));

if (IsPanicError) onPanicException(PanicException ?? throw new InvalidOperationException($"{nameof(PanicException)} is null"));
}
}
74 changes: 25 additions & 49 deletions src/HerrGeneral.WriteSide/CreationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,40 @@
/// Result of an handled creation command
/// Contain the aggregate id
/// </summary>
public sealed record CreationResult : IWithSuccess
public sealed record CreationResult : CommandResultBase
{
private readonly Guid _aggregateId;
private readonly Exception? _panicException;
private readonly DomainError? _domainError;
private readonly Guid? _aggregateId;

/// <summary>
/// The operation was successful.
/// </summary>
public bool IsSuccess => !IsDomainError && !IsPanicError;
private bool IsDomainError => _domainError != null;
private bool IsPanicError => _panicException != null;

private CreationResult(Guid aggregateId) =>
private CreationResult(Guid aggregateId) =>
_aggregateId = aggregateId;

private CreationResult(DomainError error) =>
_domainError = error;
private CreationResult(DomainError error) : base(error)
{
}

private CreationResult(Exception panicException) =>
_panicException = panicException;
private CreationResult(Exception panicException) : base(panicException)
{
}

/// <summary>
/// Factory for success
/// </summary>
public static CreationResult Success(Guid aggregateId) => new CreationResult(aggregateId);
public static CreationResult Success(Guid aggregateId) => new(aggregateId);

/// <summary>
/// Factory for domain error
/// </summary>
/// <param name="error"></param>
/// <returns></returns>
public static CreationResult DomainFail(DomainError error) => new CreationResult(error);
public static CreationResult DomainFail(DomainError error) => new(error);

/// <summary>
/// Factory for panic exception
/// </summary>
/// <param name="panicException"></param>
/// <returns></returns>
public static CreationResult PanicFail(Exception panicException) => new CreationResult(panicException);
public static CreationResult PanicFail(Exception panicException) => new(panicException);

/// <summary>
/// Evaluates a specified function, based on the .current state
Expand All @@ -57,12 +51,14 @@ public TResult Match<TResult>(Func<Guid, TResult> onSuccess, Func<DomainError, T
if (onSuccess == null) throw new ArgumentNullException(nameof(onSuccess));
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));
if (onPanicError == null) throw new ArgumentNullException(nameof(onPanicError));

return IsSuccess
? onSuccess(_aggregateId)
? onSuccess(_aggregateId ?? throw new InvalidOperationException($"{nameof(_aggregateId)} is null"))
: IsDomainError
? onDomainError(_domainError ?? throw new InvalidOperationException())
: onPanicError(_panicException ?? throw new InvalidOperationException());
? onDomainError(DomainError ?? throw new InvalidOperationException($"{nameof(DomainError)} is null"))
: IsPanicError
? onPanicError(PanicException ?? throw new InvalidOperationException($"{nameof(PanicException)} is null"))
: throw new InvalidOperationException("Invalid state");
}

/// <summary>
Expand All @@ -75,13 +71,16 @@ public void Match(Action<Guid> onSuccess, Action<DomainError> onDomainError, Act
{
if (onSuccess == null) throw new ArgumentNullException(nameof(onSuccess));
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));
if (onPanicError == null) throw new ArgumentNullException(nameof(onPanicError));

if (IsSuccess)
onSuccess(_aggregateId);
onSuccess(_aggregateId ?? throw new InvalidOperationException($"{nameof(_aggregateId)} is null"));
else if (IsDomainError)
onDomainError(_domainError ?? throw new InvalidOperationException());
onDomainError(DomainError ?? throw new InvalidOperationException($"{nameof(DomainError)} is null"));
else if (IsPanicError)
onPanicError(PanicException ?? throw new InvalidOperationException($"{nameof(PanicException)} is null"));
else
onPanicError(_panicException ?? throw new InvalidOperationException());
throw new InvalidOperationException("Invalid state");
}

/// <summary>
Expand All @@ -92,32 +91,9 @@ public void MatchSuccess(Action<Guid> success)
{
if (success == null) throw new ArgumentNullException(nameof(success));

if (IsSuccess) success(_aggregateId);
}

/// <summary>
/// Evaluates a specified action based on the .current state.
/// </summary>
/// <param name="onDomainError">The action to evaluate if the value is missing.</param>
public void MatchDomainError(Action<DomainError> onDomainError)
{
if (onDomainError == null) throw new ArgumentNullException(nameof(onDomainError));

if (IsDomainError) onDomainError(_domainError ?? throw new InvalidOperationException());
if (IsSuccess) success(_aggregateId ?? throw new InvalidOperationException($"{nameof(_aggregateId)} is null"));
}

/// <summary>
/// Evaluates a specified action on panic exception.
/// </summary>
/// <param name="onPanicException"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="InvalidOperationException"></exception>
public void MatchPanicException(Action<Exception> onPanicException)
{
if (onPanicException == null) throw new ArgumentNullException(nameof(onPanicException));

if (IsPanicError) onPanicException(_panicException ?? throw new InvalidOperationException());
}

/// <summary>
/// True if success, else false.
Expand Down
Loading

0 comments on commit a7e7071

Please sign in to comment.