diff --git a/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTETests.cs b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTETests.cs new file mode 100644 index 00000000..5126f03b --- /dev/null +++ b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTETests.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using FluentAssertions; +using Xunit; + +namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With +{ + public class AsyncResultOfTETests + { + [Fact] + public async Task Combining_successful() + { + var r1 = Result.Success(1); + var r2 = Result.Success(2); + var actual = await r1.WithMap(r2, (a, b) => Task.FromResult(a + b), (e1, e2) => "failure"); + + actual.IsSuccess.Should().BeTrue(); + } + + [Fact] + public async Task Successful_results_are_combined_with_binding() + { + var r1 = Result.Success(1); + var r2 = Result.Success(2); + + var actual = await r1 + .WithBind(r2, (a, b) => Task.FromResult(Result.Success(a + b)), (e1, e2) => "error"); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be(3); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTTests.cs b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTTests.cs new file mode 100644 index 00000000..5c6d1f86 --- /dev/null +++ b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/AsyncResultOfTTests.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using FluentAssertions; +using Xunit; + +namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With +{ + public class AsyncResultOfTTests + { + [Fact] + public async Task Successful_results_are_combined_with_mapping() + { + var r1 = Result.Success(1); + var r2 = Result.Success("hola"); + + var actual = await r1 + .WithMap(r2, (a, b) => Task.FromResult(a + b)); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be("1hola"); + } + + [Fact] + public async Task Successful_results_are_combined_with_binding() + { + var r1 = Result.Success(1); + var r2 = Result.Success("hola"); + + var actual = await r1 + .WithBind(r2, (a, b) => Task.FromResult(Result.Success(a + b))); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be("1hola"); + } + + [Fact] + public async Task Successful_results_are_combined_into_success() + { + var r1 = Result.Success(1); + var r2 = Result.Success("hola"); + + var actual = await r1 + .WithBind(r2, (a, b) => Task.FromResult(Result.Success())); + + actual.IsSuccess.Should().BeTrue(); + } + + [Fact] + public async Task Failures_are_combined_into_failure() + { + var r1 = Result.Failure("Failed"); + var r2 = Result.Success("hola"); + + var actual = await r1 + .WithBind(r2, (a, b) => Task.FromResult(Result.Success())); + + actual.IsSuccess.Should().BeFalse(); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTETests.cs b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTETests.cs new file mode 100644 index 00000000..a3529394 --- /dev/null +++ b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTETests.cs @@ -0,0 +1,44 @@ +using FluentAssertions; +using Xunit; + +namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With +{ + public class ResultOfTETests + { + [Fact] + public async void Successful_results_are_combined_with_map() + { + var r1 = Result.Success(1); + var r2 = Result.Success(2); + + var actual = r1.WithMap(r2, (a, b) => a + b, (e1, e2) => ""); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be(3); + } + + [Fact] + public async void Successful_results_are_combined_with_binding() + { + var r1 = Result.Success(1); + var r2 = Result.Success(2); + + var actual = r1.WithBind(r2, (a, b) => Result.Success(a + b), (e1, e2) => ""); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be(3); + } + + [Fact] + public async void Successful_results_are_combined_with_binding_different_types() + { + var r1 = Result.Success("Hi"); + var r2 = Result.Success(2); + + var actual = r1.WithBind(r2, (a, b) => Result.Success(a + b), (e1, e2) => ""); + + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be("Hi2"); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTTest.cs b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTTest.cs new file mode 100644 index 00000000..d7a42873 --- /dev/null +++ b/CSharpFunctionalExtensions.Tests/ResultTests/Extensions/With/ResultOfTTest.cs @@ -0,0 +1,41 @@ +using FluentAssertions; +using Xunit; + +namespace CSharpFunctionalExtensions.Tests.ResultTests.Extensions.With +{ + public class ResultOfTTest + { + [Fact] + public void Results_of_same_type_are_combined_correctly() + { + var r1 = Result.Success("Hello"); + var r2 = Result.Success("world"); + + var actual = r1.With(r2); + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be(("Hello", "world")); + } + + [Fact] + public void Results_of_different_type_are_mapped_correctly() + { + var r1 = Result.Success("Hello"); + var r2 = Result.Success("world"); + + var actual = r1.WithMap(r2, (a, b) => a + b); + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be("Helloworld"); + } + + [Fact] + public void Results_of_different_type_are_bound_correctly() + { + var r1 = Result.Success("Hello"); + var r2 = Result.Success("world"); + + var actual = r1.WithBind(r2, (a, b) => Result.Success(a + b)); + actual.IsSuccess.Should().BeTrue(); + actual.Value.Should().Be("Helloworld"); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj b/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj index 0693dedc..7e319cb1 100644 --- a/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj +++ b/CSharpFunctionalExtensions/CSharpFunctionalExtensions.csproj @@ -36,6 +36,10 @@ + + + + diff --git a/CSharpFunctionalExtensions/Result/Extensions/BindError.cs b/CSharpFunctionalExtensions/Result/Extensions/BindError.cs new file mode 100644 index 00000000..36c41903 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/BindError.cs @@ -0,0 +1,29 @@ +using System; + +namespace CSharpFunctionalExtensions +{ + public partial class ResultExtensions + { + public static Result BindError(this Result self, + Func> func) + { + if (self.IsSuccess) + { + return Result.Success(self.Value); + } + + return func(self.Error); + } + + public static Result BindError(this Result self, + Func> func) + { + if (self.IsSuccess) + { + return Result.Success(self.Value); + } + + return func(self.Error); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfT.cs b/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfT.cs new file mode 100644 index 00000000..cef6a8c5 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfT.cs @@ -0,0 +1,53 @@ +using System; +using System.Threading.Tasks; + +namespace CSharpFunctionalExtensions +{ + public static partial class ResultExtensions + { + public static Task> WithMap(this Result a, + Result b, + Func> func) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => Errors.Join(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Map(y => func(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + + public static Task> WithBind(this Result a, + Result b, + Func>> func) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => Errors.Join(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Bind(y => func(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + + public static Task WithBind(this Result a, + Result b, + Func> map) + { + var mapSuccess = + a.BindError(el1 => b + .MapError(el2 => string.Join(Result.ErrorMessagesSeparator, el1, el2)) + .Bind(_ => Result.Failure(el1))) + .Bind(x => b + .Bind(y => map(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfTE.cs b/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfTE.cs new file mode 100644 index 00000000..cf7f16bf --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/With/AsyncResultOfTE.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; + +namespace CSharpFunctionalExtensions +{ + public static partial class ResultExtensions + { + public static Task> WithMap(this Result a, + Result b, + Func> map, Func combineError) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => combineError(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Map(y => map(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + + public static Task> WithBind(this Result a, + Result b, + Func>> map, Func combineError) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => combineError(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Bind(y => map(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/Result/Extensions/With/Errors.cs b/CSharpFunctionalExtensions/Result/Extensions/With/Errors.cs new file mode 100644 index 00000000..7c5c0059 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/With/Errors.cs @@ -0,0 +1,10 @@ +namespace CSharpFunctionalExtensions +{ + public static class Errors + { + public static string Join(string e1, string e2) + { + return string.Join(Result.ErrorMessagesSeparator, e1, e2); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfT.cs b/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfT.cs new file mode 100644 index 00000000..fa7decd5 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfT.cs @@ -0,0 +1,40 @@ +using System; + +namespace CSharpFunctionalExtensions +{ + public static partial class ResultExtensions + { + public static Result<(T1, T2)> With(this Result a, Result b) + { + return a.WithMap(b, (x, y) => (x, y)); + } + + public static Result WithMap( + this Result a, + Result b, + Func func) + { + return a + .BindError(e1 => b + .MapError(e2 => Errors.Join(e1, e2)) + .Bind(_ => Result.Failure(e1)) + ).Bind(x => b + .Map(y => func(x, y)) + .MapError(e => e)); + } + + public static Result WithBind( + this Result a, + Result b, + Func> func) + { + return a + .BindError(e1 => b + .MapError(e2 => Errors.Join(e1, e2)) + .Bind(_ => Result.Failure(e1)) + ).Bind(x => b + .Bind(y => func(x, y)) + .MapError(e => e)); + } + } +} \ No newline at end of file diff --git a/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfTE.cs b/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfTE.cs new file mode 100644 index 00000000..39321ed3 --- /dev/null +++ b/CSharpFunctionalExtensions/Result/Extensions/With/ResultOfTE.cs @@ -0,0 +1,52 @@ +using System; + +namespace CSharpFunctionalExtensions +{ + public static partial class ResultExtensions + { + public static Result WithMap(this Result a, + Result b, + Func func, Func combineError) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => combineError(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Map(y => func(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + + public static Result WithBind( + this Result a, + Result b, + Func> func, Func combineError) + { + return a + .BindError(e1 => b + .MapError(e2 => combineError(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Bind(y => func(x, y)) + .MapError(el => el)); + } + + + public static Result WithBind(this Result a, + Result b, + Func> func, Func combineError) + { + var mapSuccess = + a.BindError(e1 => b + .MapError(e2 => combineError(e1, e2)) + .Bind(_ => Result.Failure(e1))) + .Bind(x => b + .Bind(y => func(x, y)) + .MapError(el => el)); + + return mapSuccess; + } + } +} \ No newline at end of file