Anapher/Strive

View on GitHub
src/Services/ConferenceManagement/Strive.Core/Interfaces/SuccessOrError{T}.cs

Summary

Maintainability
A
0 mins
Test Coverage
using System;
using System.Diagnostics.CodeAnalysis;
using MediatR;
using Strive.Core.Dto;

namespace Strive.Core.Interfaces
{
    /// <summary>
    ///     Indicate the result of an action that may have failed or returns a value
    /// </summary>
    /// <typeparam name="T">The type of the return value if the action did not fail</typeparam>
    public class SuccessOrError<T> : ISuccessOrError
    {
        /// <summary>
        ///     Initialize a new instance of <see cref="SuccessOrError{T}" /> as succeeded with a return value
        /// </summary>
        /// <param name="response">The return value</param>
        public SuccessOrError(T response)
        {
            Response = response;
        }

        /// <summary>
        ///     Initialize a new instance of <see cref="SuccessOrError{T}" /> as failed
        /// </summary>
        /// <param name="error">The error that is responsible for the failure</param>
        public SuccessOrError(Error error)
        {
            Error = error;
        }

        /// <summary>
        ///     Initialize a new instance of <see cref="SuccessOrError{T}" />. Please not that either <see cref="Error" /> or
        ///     <see cref="Response" /> must be set
        /// </summary>
        public SuccessOrError()
        {
        }

#pragma warning disable CS8775 // Member must have a non-null value when exiting in some condition.
        [MemberNotNullWhen(false, nameof(Error))]
        [MemberNotNullWhen(true, nameof(Response))]
        public bool Success => Error == null;
#pragma warning restore CS8775 // Member must have a non-null value when exiting in some condition.

        public Error? Error { get; init; }

        /// <summary>
        ///     The return value of the action if succeeded
        /// </summary>
        public T? Response { get; init; }

        /// <summary>
        ///     Determine whether <see cref="Response" /> should be serialized
        /// </summary>
        /// <returns>Return true it should be serialized</returns>
        public bool ShouldSerializeResponse()
        {
            return Response != null && Response.GetType() != typeof(Unit);
        }

        /// <summary>
        ///     Create a new instance of <see cref="SuccessOrError{T}" /> as succeeded with a return value
        /// </summary>
        /// <param name="response">The return value</param>
        public static SuccessOrError<T> Succeeded(T response)
        {
            return new() {Response = response};
        }

        /// <summary>
        ///     Initialize a new instance of <see cref="SuccessOrError{T}" /> as failed
        /// </summary>
        /// <param name="error">The error that is responsible for the failure</param>
        public static SuccessOrError<T> Failed(Error error)
        {
            return new() {Error = error};
        }

        /// <summary>
        ///     Implicitly create a new <see cref="SuccessOrError{T}" /> that failed from an error
        /// </summary>
        /// <param name="error">The error that is responsible for the failure</param>
        public static implicit operator SuccessOrError<T>(Error error)
        {
            return Failed(error);
        }

        /// <summary>
        ///     Implicitly create a new instance of <see cref="SuccessOrError{T}" /> if the action did not fail with a return value
        /// </summary>
        /// <param name="response">The return value</param>
        public static implicit operator SuccessOrError<T>(T response)
        {
            if (response is Error)
                throw new InvalidOperationException("Cannot implicitly convert an error to a success result");

            return Succeeded(response);
        }
    }
}