Skip to content

Commit

Permalink
Then +ThenAsync Refactoring (#11)
Browse files Browse the repository at this point in the history
* split `.ThenAsync` extension methods into separate file
* added missing `.Then` and `.ThenAsync` extension methods
* added unit tests for `.Then` and `.ThenAsync` extension methods
* added extension methods for unit testing (`.ToResultTask`)
  • Loading branch information
skrasekmichael authored Mar 20, 2024
1 parent cbbb798 commit fea0d50
Show file tree
Hide file tree
Showing 27 changed files with 1,455 additions and 53 deletions.
52 changes: 19 additions & 33 deletions src/RailwayResult.FunctionalExtensions/ResultExtensions.Then.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,43 +44,43 @@ public static async Task<Result<TOut>> Then<TValue, TOut>(this Task<Result<TValu
return result.Then(mapper);
}

public static Result<TOut> Then<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, TOut> mapper)
public static Result Then<TFirst, TSecond>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Result> mapper)
{
if (result.IsFailure)
return result.Error;

return mapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> Then<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> selfTask, Func<TFirst, TSecond, TOut> mapper)
public static async Task<Result> Then<TFirst, TSecond>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Result> mapper)
{
var self = await selfTask;
return self.Then(mapper);
var result = await resultTask;
return result.Then(mapper);
}

public static Result<TOut> Then<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Result<TOut>> mapper)
public static Result<TOut> Then<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, TOut> mapper)
{
if (result.IsFailure)
return result.Error;

return mapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> Then<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Result<TOut>> mapper)
public static async Task<Result<TOut>> Then<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> selfTask, Func<TFirst, TSecond, TOut> mapper)
{
var result = await resultTask;
return result.Then(mapper);
var self = await selfTask;
return self.Then(mapper);
}

public static Result<TOut> Then<TFirst, TSecond, TThird, TOut>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, TOut> mapper)
public static Result<TOut> Then<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Result<TOut>> mapper)
{
if (result.IsFailure)
return result.Error;

return mapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
return mapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> Then<TFirst, TSecond, TThird, TOut>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, TOut> mapper)
public static async Task<Result<TOut>> Then<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Result<TOut>> mapper)
{
var result = await resultTask;
return result.Then(mapper);
Expand All @@ -100,45 +100,31 @@ public static async Task<Result> Then<TFirst, TSecond, TThird>(this Task<Result<
return result.Then(mapper);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Result<TValue> result, Func<TValue, Task<TOut>> asyncMapper)
public static Result<TOut> Then<TFirst, TSecond, TThird, TOut>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, TOut> mapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value);
return mapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Task<Result<TValue>> resultTask, Func<TValue, Task<TOut>> asyncMapper)
public static async Task<Result<TOut>> Then<TFirst, TSecond, TThird, TOut>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, TOut> mapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
return result.Then(mapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Task<TOut>> asyncMapper)
public static Result<TOut> Then<TFirst, TSecond, TThird, TOut>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, Result<TOut>> mapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2);
return mapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Task<TOut>> asyncMapper)
public static async Task<Result<TOut>> Then<TFirst, TSecond, TThird, TOut>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, Result<TOut>> mapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Task<Result<TOut>>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Task<Result<TOut>>> asyncMapper)
{
var self = await resultTask;
return await self.ThenAsync(asyncMapper);
return result.Then(mapper);
}
}
130 changes: 130 additions & 0 deletions src/RailwayResult.FunctionalExtensions/ResultExtensions.ThenAsync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
namespace RailwayResult;

public static partial class ResultExtensions
{
public static async Task<Result> ThenAsync<TValue>(this Result<TValue> result, Func<TValue, Task<Result>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value);
}

public static async Task<Result> ThenAsync<TValue>(this Task<Result<TValue>> resultTask, Func<TValue, Task<Result>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Result<TValue> result, Func<TValue, Task<TOut>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Task<Result<TValue>> resultTask, Func<TValue, Task<TOut>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Result<TValue> result, Func<TValue, Task<Result<TOut>>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value);
}

public static async Task<Result<TOut>> ThenAsync<TValue, TOut>(this Task<Result<TValue>> resultTask, Func<TValue, Task<Result<TOut>>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result> ThenAsync<TFirst, TSecond>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Task<Result>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result> ThenAsync<TFirst, TSecond>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Task<Result>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Task<TOut>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> selfTask, Func<TFirst, TSecond, Task<TOut>> asyncMapper)
{
var self = await selfTask;
return await self.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Result<(TFirst, TSecond)> result, Func<TFirst, TSecond, Task<Result<TOut>>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TOut>(this Task<Result<(TFirst, TSecond)>> resultTask, Func<TFirst, TSecond, Task<Result<TOut>>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result> ThenAsync<TFirst, TSecond, TThird>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, Task<Result>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
}

public static async Task<Result> ThenAsync<TFirst, TSecond, TThird>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, Task<Result>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TThird, TOut>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, Task<TOut>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TThird, TOut>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, Task<TOut>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TThird, TOut>(this Result<(TFirst, TSecond, TThird)> result, Func<TFirst, TSecond, TThird, Task<Result<TOut>>> asyncMapper)
{
if (result.IsFailure)
return result.Error;

return await asyncMapper(result.Value.Item1, result.Value.Item2, result.Value.Item3);
}

public static async Task<Result<TOut>> ThenAsync<TFirst, TSecond, TThird, TOut>(this Task<Result<(TFirst, TSecond, TThird)>> resultTask, Func<TFirst, TSecond, TThird, Task<Result<TOut>>> asyncMapper)
{
var result = await resultTask;
return await result.ThenAsync(asyncMapper);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ public sealed class TheoryData_R1_AndAsync : TheoryData<Func<R1, Task<R2>>, R1,
{
public TheoryData_R1_AndAsync()
{
// --- R1 ---

Add(
result => result.AndAsync(_ => Task.FromResult(O.B)),
O.A,
Expand All @@ -20,14 +22,14 @@ public TheoryData_R1_AndAsync()
// --- TaskOfR1 ---

Add(
result => Task.FromResult(result).AndAsync(_ => Task.FromResult(O.B)),
result => result.ToResultTask().AndAsync(_ => Task.FromResult(O.B)),
O.A,
(O.A, O.B)
);

//and should return input failure result
Add(
result => Task.FromResult(result).AndAsync(_ => Task.FromResult(O.B)),
result => result.ToResultTask().AndAsync(_ => Task.FromResult(O.B)),
Errors.ErrorA,
Errors.ErrorA
);
Expand Down

This file was deleted.

20 changes: 20 additions & 0 deletions tests/RailwayResult.FunctionalExtensions.Tests/ErrorExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace RailwayResult.FunctionalExtensions.Tests;

public static class ErrorExtensions
{
public static Result ToResult<TError>(this TError error) where TError : Error => error;

public static Result<T> ToResult<T, TError>(this TError error) where TError : Error => error;

public static Task<Result> ToResultTask<TError>(this TError error) where TError : Error
{
Result r = error;
return Task.FromResult(r);
}

public static Task<Result<T>> ToResultTask<T, TError>(this TError error) where TError : Error
{
Result<T> r = error;
return Task.FromResult(r);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
global using Xunit;

global using O = RailwayResult.FunctionalExtensions.Tests.Obj;
global using RC = RailwayResult.Result<string?>;
global using R1 = RailwayResult.Result<RailwayResult.FunctionalExtensions.Tests.Obj>;
global using R1N = RailwayResult.Result<RailwayResult.FunctionalExtensions.Tests.Obj?>;
global using R2 = RailwayResult.Result<(RailwayResult.FunctionalExtensions.Tests.Obj, RailwayResult.FunctionalExtensions.Tests.Obj)>;
Expand Down
35 changes: 35 additions & 0 deletions tests/RailwayResult.FunctionalExtensions.Tests/ResultExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace RailwayResult.FunctionalExtensions.Tests;

public static class ResultExtensions
{
public static void ShouldBe(this Result self, Result expected)
{
if (self.IsSuccess)
{
expected.IsSuccess.Should().BeTrue();
}
else
{
expected.IsSuccess.Should().BeFalse();
self.Error.Should().BeEquivalentTo(expected.Error);
}
}

public static void ShouldBe<T>(this Result<T> self, Result<T> expected)
{
if (self.IsSuccess)
{
expected.IsSuccess.Should().BeTrue();
self.Value.Should().BeEquivalentTo(expected.Value);
}
else
{
expected.IsSuccess.Should().BeFalse();
self.Error.Should().BeEquivalentTo(expected.Error);
}
}

public static Task<Result> ToResultTask(this Result result) => Task.FromResult(result);

public static Task<Result<T>> ToResultTask<T>(this Result<T> result) => Task.FromResult(result);
}
Loading

0 comments on commit fea0d50

Please sign in to comment.