Skip to content

Commit

Permalink
Merge pull request #81 from amantinband/add-then-that-invokes-an-action
Browse files Browse the repository at this point in the history
Add Then/ThenAsync that invokes an action
  • Loading branch information
amantinband authored Jan 5, 2024
2 parents dae4251 + bcfe8c4 commit a3fadca
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 15 deletions.
34 changes: 34 additions & 0 deletions src/ErrorOr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,23 @@ public ErrorOr<TResult> Then<TResult>(Func<TValue, ErrorOr<TResult>> onValue)
return onValue(Value);
}

/// <summary>
/// If the state is a value, the provided <paramref name="action"/> is invoked.
/// </summary>
/// <param name="action">The action to execute if the state is a value.</param>
/// <returns>The original <see cref="ErrorOr"/> instance.</returns>
public ErrorOr<TValue> Then(Action<TValue> action)
{
if (IsError)
{
return Errors;
}

action(Value);

return this;
}

/// <summary>
/// If the state is a value, the provided function <paramref name="onValue"/> is executed and its result is returned.
/// </summary>
Expand Down Expand Up @@ -308,6 +325,23 @@ public async Task<ErrorOr<TResult>> ThenAsync<TResult>(Func<TValue, Task<ErrorOr
return await onValue(Value).ConfigureAwait(false);
}

/// <summary>
/// If the state is a value, the provided <paramref name="action"/> is invoked asynchronously.
/// </summary>
/// <param name="action">The action to execute if the state is a value.</param>
/// <returns>The original <see cref="ErrorOr"/> instance.</returns>
public async Task<ErrorOr<TValue>> ThenAsync(Func<TValue, Task> action)
{
if (IsError)
{
return Errors;
}

await action(Value).ConfigureAwait(false);

return this;
}

/// <summary>
/// If the state is a value, the provided function <paramref name="onValue"/> is executed asynchronously and its result is returned.
/// </summary>
Expand Down
52 changes: 40 additions & 12 deletions src/ErrorOrExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ public static class ErrorOrExtensions
/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided function <paramref name="onValue"/> is executed and its result is returned.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <typeparam name="TNextResult">The type of the next result.</typeparam>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <typeparam name="TNextValue">The type of the next result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="onValue">The function to execute if the state is a value.</param>
/// <returns>The result from calling <paramref name="onValue"/> if state is value; otherwise the original errors.</returns>
public static async Task<ErrorOr<TNextResult>> Then<TResult, TNextResult>(this Task<ErrorOr<TResult>> errorOr, Func<TResult, ErrorOr<TNextResult>> onValue)
public static async Task<ErrorOr<TNextValue>> Then<TValue, TNextValue>(this Task<ErrorOr<TValue>> errorOr, Func<TValue, ErrorOr<TNextValue>> onValue)
{
var result = await errorOr.ConfigureAwait(false);

Expand All @@ -20,27 +20,41 @@ public static async Task<ErrorOr<TNextResult>> Then<TResult, TNextResult>(this T
/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided function <paramref name="onValue"/> is executed and its result is returned.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <typeparam name="TNextResult">The type of the next result.</typeparam>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <typeparam name="TNextValue">The type of the next result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="onValue">The function to execute if the state is a value.</param>
/// <returns>The result from calling <paramref name="onValue"/> if state is value; otherwise the original errors.</returns>
public static async Task<ErrorOr<TNextResult>> Then<TResult, TNextResult>(this Task<ErrorOr<TResult>> errorOr, Func<TResult, TNextResult> onValue)
public static async Task<ErrorOr<TNextValue>> Then<TValue, TNextValue>(this Task<ErrorOr<TValue>> errorOr, Func<TValue, TNextValue> onValue)
{
var result = await errorOr.ConfigureAwait(false);

return result.Then(onValue);
}

/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided <paramref name="action"/> is invoked.
/// </summary>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="action">The action to execute if the state is a value.</param>
/// <returns>The original <paramref name="errorOr"/>.</returns>
public static async Task<ErrorOr<TValue>> Then<TValue>(this Task<ErrorOr<TValue>> errorOr, Action<TValue> action)
{
var result = await errorOr.ConfigureAwait(false);

return result.Then(action);
}

/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided function <paramref name="onValue"/> is executed asynchronously and its result is returned.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <typeparam name="TNextResult">The type of the next result.</typeparam>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <typeparam name="TNextValue">The type of the next result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="onValue">The function to execute if the state is a value.</param>
/// <returns>The result from calling <paramref name="onValue"/> if state is value; otherwise the original errors.</returns>
public static async Task<ErrorOr<TNextResult>> ThenAsync<TResult, TNextResult>(this Task<ErrorOr<TResult>> errorOr, Func<TResult, Task<ErrorOr<TNextResult>>> onValue)
public static async Task<ErrorOr<TNextValue>> ThenAsync<TValue, TNextValue>(this Task<ErrorOr<TValue>> errorOr, Func<TValue, Task<ErrorOr<TNextValue>>> onValue)
{
var result = await errorOr.ConfigureAwait(false);

Expand All @@ -50,18 +64,32 @@ public static async Task<ErrorOr<TNextResult>> ThenAsync<TResult, TNextResult>(t
/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided function <paramref name="onValue"/> is executed asynchronously and its result is returned.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
/// <typeparam name="TNextResult">The type of the next result.</typeparam>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <typeparam name="TNextValue">The type of the next result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="onValue">The function to execute if the state is a value.</param>
/// <returns>The result from calling <paramref name="onValue"/> if state is value; otherwise the original errors.</returns>
public static async Task<ErrorOr<TNextResult>> ThenAsync<TResult, TNextResult>(this Task<ErrorOr<TResult>> errorOr, Func<TResult, Task<TNextResult>> onValue)
public static async Task<ErrorOr<TNextValue>> ThenAsync<TValue, TNextValue>(this Task<ErrorOr<TValue>> errorOr, Func<TValue, Task<TNextValue>> onValue)
{
var result = await errorOr.ConfigureAwait(false);

return await result.ThenAsync(onValue).ConfigureAwait(false);
}

/// <summary>
/// If the state of <paramref name="errorOr"/> is a value, the provided <paramref name="action"/> is executed asynchronously.
/// </summary>
/// <typeparam name="TValue">The type of the result.</typeparam>
/// <param name="errorOr">The error.</param>
/// <param name="action">The action to execute if the state is a value.</param>
/// <returns>The original <paramref name="errorOr"/>.</returns>
public static async Task<ErrorOr<TValue>> ThenAsync<TValue>(this Task<ErrorOr<TValue>> errorOr, Func<TValue, Task> action)
{
var result = await errorOr.ConfigureAwait(false);

return await result.ThenAsync(action).ConfigureAwait(false);
}

/// <summary>
/// If the state is error, the provided function <paramref name="onError"/> is executed asynchronously and its result is returned.
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions tests/ErrorOr.ThenAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public async Task CallingThenAsync_WhenIsError_ShouldReturnErrors()
ErrorOr<string> result = await errorOrString
.ThenAsync(str => ConvertToIntAsync(str))
.ThenAsync(num => Task.FromResult(num * 2))
.ThenAsync(num => Task.Run(() => { _ = 5; }))
.ThenAsync(num => ConvertToStringAsync(num));

// Assert
Expand Down
26 changes: 23 additions & 3 deletions tests/ErrorOr.ThenTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,23 @@ public void CallingThen_WhenIsSuccess_ShouldInvokeGivenFunc()
result.Value.Should().BeEquivalentTo("10");
}

[Fact]
public void CallingThen_WhenIsSuccess_ShouldInvokeGivenAction()
{
// Arrange
ErrorOr<string> errorOrString = "5";

// Act
ErrorOr<int> result = errorOrString
.Then(str => { _ = 5; })
.Then(str => ConvertToInt(str))
.Then(str => { _ = 5; });

// Assert
result.IsError.Should().BeFalse();
result.Value.Should().Be(5);
}

[Fact]
public void CallingThen_WhenIsError_ShouldReturnErrors()
{
Expand All @@ -32,6 +49,7 @@ public void CallingThen_WhenIsError_ShouldReturnErrors()
ErrorOr<string> result = errorOrString
.Then(str => ConvertToInt(str))
.Then(num => num * 2)
.Then(str => { _ = 5; })
.Then(num => ConvertToString(num));

// Assert
Expand All @@ -46,15 +64,17 @@ public async Task CallingThenAfterThenAsync_WhenIsSuccess_ShouldInvokeGivenFunc(
ErrorOr<string> errorOrString = "5";

// Act
ErrorOr<int> result = await errorOrString
ErrorOr<string> result = await errorOrString
.ThenAsync(str => ConvertToIntAsync(str))
.Then(num => num * 2)
.ThenAsync(num => ConvertToStringAsync(num))
.Then(str => ConvertToInt(str));
.Then(str => ConvertToInt(str))
.ThenAsync(num => ConvertToStringAsync(num))
.Then(num => { _ = 5; });

// Assert
result.IsError.Should().BeFalse();
result.Value.Should().Be(10);
result.Value.Should().Be("10");
}

[Fact]
Expand Down

0 comments on commit a3fadca

Please sign in to comment.