Skip to content

Commit e8e330e

Browse files
authored
Merge pull request #33 from jdmartinez/feature/complete-unit-type
feature/complete-unit-type
2 parents 9460619 + 90731ea commit e8e330e

18 files changed

Lines changed: 345 additions & 20 deletions

src/Functional/Functional.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@
1313
<RepositoryUrl>https://github.com/jdmartinez/Functional</RepositoryUrl>
1414
</PropertyGroup>
1515

16+
<ItemGroup>
17+
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.10" />
18+
</ItemGroup>
19+
1620
</Project>

src/Functional/Option/Extensions/IQueryable/Option.FirstOrNone.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ namespace Functional;
55
public static partial class OptionExtensions
66
{
77
public static Option<T> FirstOrNone<T>(this IQueryable<T> query)
8-
=> query.FirstOrDefault() ?? Option<T>.None;
8+
=> query.FirstOrDefault();
99

1010
public static Option<T> FirstOrNone<T>(this IQueryable<T> query, Expression<Func<T, bool>> predicate)
11-
=> query.FirstOrDefault(predicate) ?? Option<T>.None;
11+
=> query.FirstOrDefault(predicate);
1212
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Linq.Expressions;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace Functional;
5+
6+
public static partial class OptionExtensions
7+
{
8+
public static async Task<Option<T>> FirstOrNoneAsync<T>(this IQueryable<T> source, CancellationToken cancellationToken = default)
9+
=> await source.FirstOrDefaultAsync(cancellationToken);
10+
11+
public static async Task<Option<T>> FirstOrNoneAsync<T>(
12+
this IQueryable<T> source,
13+
Expression<Func<T, bool>> predicate,
14+
CancellationToken cancellationToken = default)
15+
=> await source.FirstOrDefaultAsync(predicate, cancellationToken);
16+
17+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Linq.Expressions;
2+
3+
namespace Functional;
4+
5+
public static partial class OptionExtensions
6+
{
7+
public static Option<T> SingleOrNone<T>(this IQueryable<T> query)
8+
=> query.SingleOrDefault();
9+
10+
public static Option<T> SingleOrNone<T>(this IQueryable<T> query, Expression<Func<T, bool>> predicate)
11+
=> query
12+
.SingleOrDefault(predicate);
13+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Linq.Expressions;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace Functional;
5+
6+
public static partial class OptionExtensions
7+
{
8+
public static async Task<Option<T>> SingleOrNoneAsync<T>(this IQueryable<T> source, CancellationToken cancellationToken = default)
9+
=> await source.SingleOrDefaultAsync(cancellationToken);
10+
11+
public static async Task<Option<T>> SingleOrNoneAsync<T>(
12+
this IQueryable<T> source,
13+
Expression<Func<T, bool>> predicate,
14+
CancellationToken cancellationToken = default)
15+
=> await source.FirstOrDefaultAsync(predicate, cancellationToken);
16+
17+
}

src/Functional/Option/Option.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ private Option(T? value)
3131

3232
public static implicit operator Option<T>(Option _) => None;
3333

34-
public static implicit operator Option<T>(T value)
35-
=> value is Option<T> opt
36-
? opt
37-
: Some(value);
34+
public static implicit operator Option<T>(T? value)
35+
=> value switch
36+
{
37+
Option<T> opt => opt,
38+
not null => Some(value),
39+
_ => None
40+
};
3841
}

src/Functional/Unit/Unit.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
namespace Functional;
22

3-
public readonly record struct Unit
3+
public readonly record struct Unit : IComparable<Unit>
44
{
55
public static readonly Unit Default = new();
66

77
public override int GetHashCode() => 0;
88

99
public override string ToString() => "Unit:()";
10+
11+
public int CompareTo(Unit other) => 0;
1012
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Functional;
2+
3+
public static partial class ValidationResultExtensions
4+
{
5+
public static ReadOnlySpan<Error> AsSpan<T>(this ValidationResult<T> result)
6+
=> result.IsSuccess
7+
? []
8+
: new(result.Errors.ToArray());
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Functional;
2+
3+
public static partial class ValidationResultExtensions
4+
{
5+
public static TReturn Match<T, TReturn>(this ValidationResult<T> result, Func<TReturn> onSuccess, Func<TReturn> onFailure)
6+
=> result.IsSuccess
7+
? onSuccess()
8+
: onFailure();
9+
10+
public static TReturn Match<T, TReturn>(this ValidationResult<T> result, Func<T, TReturn> onSuccess, Func<IEnumerable<Error>, TReturn> onFailure)
11+
=> result.IsSuccess
12+
? onSuccess(result.Value)
13+
: onFailure(result.Errors);
14+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace Functional;
2+
3+
public record ValidationResult<T>
4+
{
5+
private readonly List<Error> _errors = [];
6+
7+
public T Value { get; } = default!;
8+
9+
public IReadOnlyList<Error> Errors => _errors.AsReadOnly();
10+
11+
public bool IsSuccess => _errors.Count == 0;
12+
13+
public bool IsFailure => !IsSuccess;
14+
15+
private ValidationResult(T value, IEnumerable<Error> errors)
16+
{
17+
Value = value;
18+
_errors.AddRange(errors.Where(e => e != Error.None));
19+
}
20+
21+
public static ValidationResult<T> Success(T value) => new(value, []);
22+
23+
public static ValidationResult<T> Failure(T value, IEnumerable<Error> errors)
24+
{
25+
if (errors.Any(e => e == Error.None))
26+
throw new InvalidOperationException(nameof(errors));
27+
28+
return new ValidationResult<T>(value, errors);
29+
}
30+
31+
public static implicit operator ValidationResult<T>(T value) => Success(value);
32+
33+
public override int GetHashCode()
34+
=> IsSuccess
35+
? 0
36+
: HashCode.Combine(_errors);
37+
}

0 commit comments

Comments
 (0)