Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
mattiasnordqvist committed Feb 23, 2024
2 parents fec64c2 + 19c4f1b commit 1e9a5de
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 133 deletions.
8 changes: 4 additions & 4 deletions Results.Tests/DotNetThoughts.Results.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1" />
<PackageReference Include="xunit.core" Version="2.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0">
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit.core" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
224 changes: 207 additions & 17 deletions Results/BindAll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,27 @@ public static Result<Unit> BindAll<T>(this Result<IEnumerable<T>> source, Func<T
}
}

public static Result<Unit> BindAll<T>(this Result<IEnumerable<T>> source, Func<T, int, Result<Unit>> next)
{
if (source.Success)
{
var results = new List<Result<Unit>>();
var index = 0;
foreach (var s in source.Value)
{
results.Add(next(s, index));
index++;
}
return results.Any(x => !x.Success)
? UnitResult.Error(results.SelectMany(x => x.Errors))
: UnitResult.Ok;
}
else
{
return Result<Unit>.Error(source.Errors);
}
}

public static async Task<Result<Unit>> BindAll<T>(this Result<IEnumerable<T>> source, Func<T, Task<Result<Unit>>> next)
{
if (source.Success)
Expand All @@ -42,6 +63,27 @@ public static async Task<Result<Unit>> BindAll<T>(this Result<IEnumerable<T>> so
}
}

public static async Task<Result<Unit>> BindAll<T>(this Result<IEnumerable<T>> source, Func<T, int, Task<Result<Unit>>> next)
{
if (source.Success)
{
var results = new List<Result<Unit>>();
var index = 0;
foreach (var s in source.Value)
{
results.Add(await next(s, index));
index++;
}
return results.Any(x => !x.Success)
? UnitResult.Error(results.SelectMany(x => x.Errors))
: UnitResult.Ok;
}
else
{
return Result<Unit>.Error(source.Errors);
}
}

/// <summary>
/// Does not short circuit. Returns all errors or all results
/// </summary>
Expand All @@ -65,35 +107,117 @@ public static Result<List<TResult>> BindAll<T, TResult>(this Result<IEnumerable<
}
}

[Obsolete("Does not take a Result as input. Use one of the regular extensions that takes a result as input. (Do a .Return() on your non-result object first)")]
public static Result<List<TResult>> BindAll<T, TResult>(this IEnumerable<T> source, Func<T, Result<TResult>> next)
public static Result<List<TResult>> BindAll<T, TResult>(this Result<IEnumerable<T>> source, Func<T, int, Result<TResult>> next)
{
if (source.Success)
{
var results = new List<Result<TResult>>();
var index = 0;
foreach (var s in source.Value)
{
results.Add(next(s, index));
index++;
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}
else
{
return Result<List<TResult>>.Error(source.Errors);
}
}

/// <summary>
/// Does not short circuit. Returns all errors or all results
/// </summary>
public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Result<IEnumerable<T>> source, Func<T, Task<Result<TResult>>> next)
{
var results = new List<Result<TResult>>();
if (source.Success)
{
var results = new List<Result<TResult>>();

foreach (var s in source)
foreach (var s in source.Value)
{
results.Add(await next(s));
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}
else
{
results.Add(next(s));
return Result<List<TResult>>.Error(source.Errors);
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}

[Obsolete("Does not take a Result as input. Use one of the regular extensions that takes a result as input. (Do a .Return() on your non-result object first)")]
public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this IEnumerable<T> source, Func<T, Task<Result<TResult>>> next)
public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Result<IEnumerable<T>> source, Func<T, int, Task<Result<TResult>>> next)
{
if (source.Success)
{
var results = new List<Result<TResult>>();
var index = 0;
foreach (var s in source.Value)
{
results.Add(await next(s, index));
index++;
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}
else
{
return Result<List<TResult>>.Error(source.Errors);
}
}

////// Same as above, but from tasks


/// <summary>
/// Does not short circuit. Returns all errors or one unit
/// </summary>
public static async Task<Result<Unit>> BindAll<T>(this Task<Result<IEnumerable<T>>> source, Func<T, Result<Unit>> next)
{
var results = new List<Result<TResult>>();
if ((await source).Success)
{
var results = new List<Result<Unit>>();
foreach (var s in (await source).Value)
{
results.Add(next(s));
}
return results.Any(x => !x.Success)
? UnitResult.Error(results.SelectMany(x => x.Errors))
: UnitResult.Ok;
}
else
{
return Result<Unit>.Error((await source).Errors);
}
}

foreach (var s in source)
public static async Task<Result<Unit>> BindAll<T>(this Task<Result<IEnumerable<T>>> source, Func<T, int, Result<Unit>> next)
{
if ((await source).Success)
{
results.Add(await next(s));
var results = new List<Result<Unit>>();
var index = 0;
foreach (var s in (await source).Value)
{
results.Add(next(s, index));
index++;
}
return results.Any(x => !x.Success)
? UnitResult.Error(results.SelectMany(x => x.Errors))
: UnitResult.Ok;
}
else
{
return Result<Unit>.Error((await source).Errors);
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}

// with tasks
public static async Task<Result<Unit>> BindAll<T>(this Task<Result<IEnumerable<T>>> source, Func<T, Task<Result<Unit>>> next)
{
if ((await source).Success)
Expand All @@ -113,6 +237,27 @@ public static async Task<Result<Unit>> BindAll<T>(this Task<Result<IEnumerable<T
}
}

public static async Task<Result<Unit>> BindAll<T>(this Task<Result<IEnumerable<T>>> source, Func<T, int, Task<Result<Unit>>> next)
{
if ((await source).Success)
{
var results = new List<Result<Unit>>();
var index = 0;
foreach (var s in (await source).Value)
{
results.Add(await next(s, index));
index++;
}
return results.Any(x => !x.Success)
? UnitResult.Error(results.SelectMany(x => x.Errors))
: UnitResult.Ok;
}
else
{
return Result<Unit>.Error((await source).Errors);
}
}

/// <summary>
/// Does not short circuit. Returns all errors or all results
/// </summary>
Expand All @@ -136,6 +281,30 @@ public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Task<Re
}
}

public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Task<Result<IEnumerable<T>>> source, Func<T, int, Result<TResult>> next)
{
if ((await source).Success)
{
var results = new List<Result<TResult>>();
var index = 0;
foreach (var s in (await source).Value)
{
results.Add(next(s, index));
index++;
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}
else
{
return Result<List<TResult>>.Error((await source).Errors);
}
}

/// <summary>
/// Does not short circuit. Returns all errors or all results
/// </summary>
public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Task<Result<IEnumerable<T>>> source, Func<T, Task<Result<TResult>>> next)
{
if ((await source).Success)
Expand All @@ -155,4 +324,25 @@ public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Task<Re
return Result<List<TResult>>.Error((await source).Errors);
}
}

public static async Task<Result<List<TResult>>> BindAll<T, TResult>(this Task<Result<IEnumerable<T>>> source, Func<T, int, Task<Result<TResult>>> next)
{
if ((await source).Success)
{
var results = new List<Result<TResult>>();
var index = 0;
foreach (var s in (await source).Value)
{
results.Add(await next(s, index));
index++;
}
return results.Any(x => !x.Success)
? Result<List<TResult>>.Error(results.SelectMany(x => x.Errors))
: Result<List<TResult>>.Ok(results.Select(x => x.Value).ToList());
}
else
{
return Result<List<TResult>>.Error((await source).Errors);
}
}
}
44 changes: 0 additions & 44 deletions Results/BindEach.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,6 @@
namespace DotNetThoughts.Results;
public static partial class Extensions
{
/// <summary>
/// Short circuits on failure
/// </summary>
[Obsolete("Does not take a Result as input. Use one of the regular extensions that takes a result as input. (Do a .Return() on your non-result object first)")]
public static Result<Unit> BindEach<T>(this IEnumerable<T> source, Func<T, Result<Unit>> next)
{
foreach (var s in source)
{
var result = next(s);
if (!result.Success) return result;
}
return UnitResult.Ok;
}

/// <summary>
/// Short circuits on failure
/// </summary>
[Obsolete("Does not take a Result as input. Use one of the regular extensions that takes a result as input. (Do a .Return() on your non-result object first)")]
public static async Task<Result<Unit>> BindEach<T>(this IEnumerable<T> source, Func<T, Task<Result<Unit>>> next)
{
foreach (var s in source)
{
var result = await next(s);
if (!result.Success) return result;
}
return UnitResult.Ok;
}

/// <summary>
/// Short circuits on failure
/// </summary>
[Obsolete("Does not take a Result as input. Use one of the regular extensions that takes a result as input. (Do a .Return() on your non-result object first)")]
public static Result<List<TResult>> BindEach<T, TResult>(this IEnumerable<T> source, Func<T, Result<TResult>> next)
{
var result = new List<TResult>();
foreach (var s in source)
{
var r = next(s);
if (!r.Success) return Result<List<TResult>>.Error(r.Errors);
result.Add(r.Value);
}
return Result<List<TResult>>.Ok(result);
}

/// <summary>
/// Short circuits on failure
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions Results/DotNetThoughts.Results.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.4.3</Version>
<Version>1.5.0</Version>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
Expand Down
17 changes: 15 additions & 2 deletions Results/ErrorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,26 @@ public string Type
/// </summary>
public string Message { get; protected set; }

private Dictionary<string, object?> _data = [];

/// <summary>
/// Scans the inheriting type for all properties and returns them as a dictionary where property name is key, and the property value is the value.
/// In addition to data you add yourself, this also contains all properties on the inheriting type with property name as key and property value as value.
/// If you add a key to this dictionary, where the inheriting type has a property with the same name as your key, the value of that dictionary entry will be overwritten by the value of the property.
/// </summary>
/// <returns></returns>
public Dictionary<string, object?> Data { get => GetData(); }

[Pure]
public Dictionary<string, object?> GetData() => GetType()
public Dictionary<string, object?> GetData()
{
var propValues = GetType()
.GetProperties()
.Where(p => p.DeclaringType != typeof(IError) && p.DeclaringType != typeof(ErrorBase))
.ToDictionary(d => d.Name, d => d.GetValue(this));
foreach (var prop in propValues)
{
_data[prop.Key] = prop.Value;
}
return _data;
}
}
Loading

0 comments on commit 1e9a5de

Please sign in to comment.