Skip to content

Commit d443c4d

Browse files
committed
With (Combine)
1 parent 2a015bd commit d443c4d

File tree

11 files changed

+402
-0
lines changed

11 files changed

+402
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System.Threading.Tasks;
2+
using FluentAssertions;
3+
using Xunit;
4+
5+
namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With
6+
{
7+
public class AsyncResultOfTETests
8+
{
9+
[Fact]
10+
public async Task Combining_successful()
11+
{
12+
var r1 = Result.Success<int, string>(1);
13+
var r2 = Result.Success<int, string>(2);
14+
var actual = await r1.WithMap(r2, (a, b) => Task.FromResult(a + b), (e1, e2) => "failure");
15+
16+
actual.IsSuccess.Should().BeTrue();
17+
}
18+
19+
[Fact]
20+
public async Task Successful_results_are_combined_with_binding()
21+
{
22+
var r1 = Result.Success<int, string>(1);
23+
var r2 = Result.Success<int, string>(2);
24+
25+
var actual = await r1
26+
.WithBind(r2, (a, b) => Task.FromResult(Result.Success<int, string>(a + b)), (e1, e2) => "error");
27+
28+
actual.IsSuccess.Should().BeTrue();
29+
actual.Value.Should().Be(3);
30+
}
31+
}
32+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Threading.Tasks;
2+
using FluentAssertions;
3+
using Xunit;
4+
5+
namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With
6+
{
7+
public class AsyncResultOfTTests
8+
{
9+
[Fact]
10+
public async Task Successful_results_are_combined_with_mapping()
11+
{
12+
var r1 = Result.Success(1);
13+
var r2 = Result.Success("hola");
14+
15+
var actual = await r1
16+
.WithMap(r2, (a, b) => Task.FromResult(a + b));
17+
18+
actual.IsSuccess.Should().BeTrue();
19+
actual.Value.Should().Be("1hola");
20+
}
21+
22+
[Fact]
23+
public async Task Successful_results_are_combined_with_binding()
24+
{
25+
var r1 = Result.Success(1);
26+
var r2 = Result.Success("hola");
27+
28+
var actual = await r1
29+
.WithBind(r2, (a, b) => Task.FromResult(Result.Success(a + b)));
30+
31+
actual.IsSuccess.Should().BeTrue();
32+
actual.Value.Should().Be("1hola");
33+
}
34+
35+
[Fact]
36+
public async Task Successful_results_are_combined_into_success()
37+
{
38+
var r1 = Result.Success(1);
39+
var r2 = Result.Success("hola");
40+
41+
var actual = await r1
42+
.WithBind(r2, (a, b) => Task.FromResult(Result.Success()));
43+
44+
actual.IsSuccess.Should().BeTrue();
45+
}
46+
47+
[Fact]
48+
public async Task Failures_are_combined_into_failure()
49+
{
50+
var r1 = Result.Failure<int>("Failed");
51+
var r2 = Result.Success("hola");
52+
53+
var actual = await r1
54+
.WithBind(r2, (a, b) => Task.FromResult(Result.Success()));
55+
56+
actual.IsSuccess.Should().BeFalse();
57+
}
58+
}
59+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using FluentAssertions;
2+
using Xunit;
3+
4+
namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With
5+
{
6+
public class ResultOfTETests
7+
{
8+
[Fact]
9+
public async void Successful_results_are_combined_with_map()
10+
{
11+
var r1 = Result.Success<int, string>(1);
12+
var r2 = Result.Success<int, string>(2);
13+
14+
var actual = r1.WithMap(r2, (a, b) => a + b, (e1, e2) => "");
15+
16+
actual.IsSuccess.Should().BeTrue();
17+
actual.Value.Should().Be(3);
18+
}
19+
20+
[Fact]
21+
public async void Successful_results_are_combined_with_binding()
22+
{
23+
var r1 = Result.Success<int, string>(1);
24+
var r2 = Result.Success<int, string>(2);
25+
26+
var actual = r1.WithBind<int, string>(r2, (a, b) => Result.Success<int, string>(a + b), (e1, e2) => "");
27+
28+
actual.IsSuccess.Should().BeTrue();
29+
actual.Value.Should().Be(3);
30+
}
31+
32+
[Fact]
33+
public async void Successful_results_are_combined_with_binding_different_types()
34+
{
35+
var r1 = Result.Success<string, string>("Hi");
36+
var r2 = Result.Success<int, string>(2);
37+
38+
var actual = r1.WithBind(r2, (a, b) => Result.Success<string, string>(a + b), (e1, e2) => "");
39+
40+
actual.IsSuccess.Should().BeTrue();
41+
actual.Value.Should().Be("Hi2");
42+
}
43+
}
44+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using FluentAssertions;
2+
using Xunit;
3+
4+
namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With
5+
{
6+
public class ResultOfTTest
7+
{
8+
[Fact]
9+
public void Results_of_same_type_are_combined_correctly()
10+
{
11+
var r1 = Result.Success("Hello");
12+
var r2 = Result.Success("world");
13+
14+
var actual = r1.With(r2);
15+
actual.IsSuccess.Should().BeTrue();
16+
actual.Value.Should().Be(("Hello", "world"));
17+
}
18+
19+
[Fact]
20+
public void Results_of_different_type_are_mapped_correctly()
21+
{
22+
var r1 = Result.Success("Hello");
23+
var r2 = Result.Success("world");
24+
25+
var actual = r1.WithMap(r2, (a, b) => a + b);
26+
actual.IsSuccess.Should().BeTrue();
27+
actual.Value.Should().Be("Helloworld");
28+
}
29+
30+
[Fact]
31+
public void Results_of_different_type_are_bound_correctly()
32+
{
33+
var r1 = Result.Success("Hello");
34+
var r2 = Result.Success("world");
35+
36+
var actual = r1.WithBind(r2, (a, b) => Result.Success(a + b));
37+
actual.IsSuccess.Should().BeTrue();
38+
actual.Value.Should().Be("Helloworld");
39+
}
40+
}
41+
}

CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
3737
<PackageReference Include="Microsoft.Bcl.Async" Version="1.0.168" />
3838
</ItemGroup>
39+
40+
<ItemGroup Condition="$(TargetFramework.StartsWith('net4')) OR $(TargetFramework)=='netstandard2.0'">
41+
<PackageReference Include="System.ValueTuple" Version="4.*" />
42+
</ItemGroup>
3943

4044
<ItemGroup>
4145
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
3+
namespace CSharpFunctionalExtensions
4+
{
5+
public partial class ResultExtensions
6+
{
7+
public static Result<T, E2> BindError<T, E, E2>(this Result<T, E> self,
8+
Func<E, Result<T, E2>> func)
9+
{
10+
if (self.IsSuccess)
11+
{
12+
return Result.Success<T, E2>(self.Value);
13+
}
14+
15+
return func(self.Error);
16+
}
17+
18+
public static Result<T> BindError<T>(this Result<T> self,
19+
Func<string, Result<T>> func)
20+
{
21+
if (self.IsSuccess)
22+
{
23+
return Result.Success(self.Value);
24+
}
25+
26+
return func(self.Error);
27+
}
28+
}
29+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace CSharpFunctionalExtensions
5+
{
6+
public static partial class ResultExtensions
7+
{
8+
public static Task<Result<TResult>> WithMap<T1, T2, TResult>(this Result<T1> a,
9+
Result<T2> b,
10+
Func<T1, T2, Task<TResult>> func)
11+
{
12+
var mapSuccess =
13+
a.BindError(e1 => b
14+
.MapError(e2 => Errors.Join(e1, e2))
15+
.Bind(_ => Result.Failure<T1>(e1)))
16+
.Bind(x => b
17+
.Map(y => func(x, y))
18+
.MapError(el => el));
19+
20+
return mapSuccess;
21+
}
22+
23+
public static Task<Result<TResult>> WithBind<T1, T2, TResult>(this Result<T1> a,
24+
Result<T2> b,
25+
Func<T1, T2, Task<Result<TResult>>> func)
26+
{
27+
var mapSuccess =
28+
a.BindError(e1 => b
29+
.MapError(e2 => Errors.Join(e1, e2))
30+
.Bind(_ => Result.Failure<T1>(e1)))
31+
.Bind(x => b
32+
.Bind(y => func(x, y))
33+
.MapError(el => el));
34+
35+
return mapSuccess;
36+
}
37+
38+
public static Task<Result> WithBind<T1, T2>(this Result<T1> a,
39+
Result<T2> b,
40+
Func<T1, T2, Task<Result>> map)
41+
{
42+
var mapSuccess =
43+
a.BindError(el1 => b
44+
.MapError(el2 => string.Join(Result.ErrorMessagesSeparator, el1, el2))
45+
.Bind(_ => Result.Failure<T1>(el1)))
46+
.Bind(x => b
47+
.Bind(y => map(x, y))
48+
.MapError(el => el));
49+
50+
return mapSuccess;
51+
}
52+
}
53+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
4+
namespace CSharpFunctionalExtensions
5+
{
6+
public static partial class ResultExtensions
7+
{
8+
public static Task<Result<TResult, E>> WithMap<T1, T2, E, TResult>(this Result<T1, E> a,
9+
Result<T2, E> b,
10+
Func<T1, T2, Task<TResult>> map, Func<E, E, E> combineError)
11+
{
12+
var mapSuccess =
13+
a.BindError(e1 => b
14+
.MapError(e2 => combineError(e1, e2))
15+
.Bind(_ => Result.Failure<T1, E>(e1)))
16+
.Bind(x => b
17+
.Map(y => map(x, y))
18+
.MapError(el => el));
19+
20+
return mapSuccess;
21+
}
22+
23+
public static Task<Result<TResult, E>> WithBind<T1, T2, E, TResult>(this Result<T1, E> a,
24+
Result<T2, E> b,
25+
Func<T1, T2, Task<Result<TResult, E>>> map, Func<E, E, E> combineError)
26+
{
27+
var mapSuccess =
28+
a.BindError(e1 => b
29+
.MapError(e2 => combineError(e1, e2))
30+
.Bind(_ => Result.Failure<T1, E>(e1)))
31+
.Bind(x => b
32+
.Bind(y => map(x, y))
33+
.MapError(el => el));
34+
35+
return mapSuccess;
36+
}
37+
}
38+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace CSharpFunctionalExtensions
2+
{
3+
public static class Errors
4+
{
5+
public static string Join(string e1, string e2)
6+
{
7+
return string.Join(Result.ErrorMessagesSeparator, e1, e2);
8+
}
9+
}
10+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
3+
namespace CSharpFunctionalExtensions
4+
{
5+
public static partial class ResultExtensions
6+
{
7+
public static Result<(T1, T2)> With<T1, T2>(this Result<T1> a, Result<T2> b)
8+
{
9+
return a.WithMap(b, (x, y) => (x, y));
10+
}
11+
12+
public static Result<TResult> WithMap<T, K, TResult>(
13+
this Result<T> a,
14+
Result<K> b,
15+
Func<T, K, TResult> func)
16+
{
17+
return a
18+
.BindError(e1 => b
19+
.MapError(e2 => Errors.Join(e1, e2))
20+
.Bind(_ => Result.Failure<T>(e1))
21+
).Bind(x => b
22+
.Map(y => func(x, y))
23+
.MapError(e => e));
24+
}
25+
26+
public static Result<TResult> WithBind<T, K, TResult>(
27+
this Result<T> a,
28+
Result<K> b,
29+
Func<T, K, Result<TResult>> func)
30+
{
31+
return a
32+
.BindError(e1 => b
33+
.MapError(e2 => Errors.Join(e1, e2))
34+
.Bind(_ => Result.Failure<T>(e1))
35+
).Bind(x => b
36+
.Bind(y => func(x, y))
37+
.MapError(e => e));
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)