feat: add FirstOrEmptyAsync
This commit is contained in:
parent
e8e0ea8f60
commit
4dbba5c2f3
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using FruityFoundation.Base.Structures;
|
using FruityFoundation.Base.Structures;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
@ -51,6 +52,86 @@ public class MaybeExtensionTests
|
||||||
Assert.That(result.HasValue, Is.False);
|
Assert.That(result.HasValue, Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Enumerable_FirstOrEmptyAsync_WithEmptyEnumerable_ReturnsEmptyMaybe()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = ToAsyncEnumerable(Array.Empty<int>());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await data.FirstOrEmptyAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
|
Assert.That(result.HasValue, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Enumerable_FirstOrEmptyAsync_WithMatchingPredicate_ReturnsMaybeWithValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = ToAsyncEnumerable([1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await data.FirstOrEmptyAsync(x => x > 1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
|
Assert.That(result.HasValue, Is.True);
|
||||||
|
Assert.That(result.Value, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Enumerable_FirstOrEmptyAsync_WithMatchingAsyncPredicate_ReturnsMaybeWithValue()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = ToAsyncEnumerable([1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await data.FirstOrEmptyAsync(async x =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
return x > 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
|
Assert.That(result.HasValue, Is.True);
|
||||||
|
Assert.That(result.Value, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Enumerable_FirstOrEmptyAsync_WithNonMatchingPredicate_ReturnsEmptyMaybe()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = ToAsyncEnumerable([1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await data.FirstOrEmptyAsync(x => x > 100);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
|
Assert.That(result.HasValue, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Enumerable_FirstOrEmptyAsync_WithNonMatchingAsyncPredicate_ReturnsEmptyMaybe()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var data = ToAsyncEnumerable([1, 2, 3, 4]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = await data.FirstOrEmptyAsync(async x =>
|
||||||
|
{
|
||||||
|
await Task.Yield();
|
||||||
|
return x > 100;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
|
Assert.That(result.HasValue, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void MaybeNullableTests()
|
public void MaybeNullableTests()
|
||||||
{
|
{
|
||||||
|
@ -125,4 +206,12 @@ public class MaybeExtensionTests
|
||||||
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
Assert.That(result, Is.InstanceOf<Maybe<int>>());
|
||||||
Assert.That(result.HasValue, Is.False);
|
Assert.That(result.HasValue, Is.False);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(IEnumerable<T> enumerable)
|
||||||
|
{
|
||||||
|
foreach (var item in enumerable)
|
||||||
|
yield return item;
|
||||||
|
|
||||||
|
await Task.Yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace FruityFoundation.Base.Structures;
|
namespace FruityFoundation.Base.Structures;
|
||||||
|
|
||||||
|
@ -22,6 +23,64 @@ public static class MaybeExtensions
|
||||||
return Maybe.Empty<T>();
|
return Maybe.Empty<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async ValueTask<Maybe<T>> FirstOrEmptyAsync<T>(this IAsyncEnumerable<T> source, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (source is IList<T> { Count: > 0 } list)
|
||||||
|
return Maybe.Create(list[0]);
|
||||||
|
|
||||||
|
await using var e = source
|
||||||
|
.ConfigureAwait(false)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
.GetAsyncEnumerator();
|
||||||
|
|
||||||
|
if (await e.MoveNextAsync())
|
||||||
|
return e.Current;
|
||||||
|
|
||||||
|
return Maybe.Empty<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async ValueTask<Maybe<T>> FirstOrEmptyAsync<T>(this IAsyncEnumerable<T> source, Func<T, bool> predicate, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (source is IList<T> { Count: > 0 } list)
|
||||||
|
return list[0];
|
||||||
|
|
||||||
|
await using var e = source
|
||||||
|
.ConfigureAwait(false)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
.GetAsyncEnumerator();
|
||||||
|
|
||||||
|
while (await e.MoveNextAsync())
|
||||||
|
{
|
||||||
|
var value = e.Current;
|
||||||
|
|
||||||
|
if (predicate(value))
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Maybe.Empty<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async ValueTask<Maybe<T>> FirstOrEmptyAsync<T>(this IAsyncEnumerable<T> source, Func<T, ValueTask<bool>> asyncPredicate, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (source is IList<T> { Count: > 0 } list)
|
||||||
|
return list[0];
|
||||||
|
|
||||||
|
await using var e = source
|
||||||
|
.ConfigureAwait(false)
|
||||||
|
.WithCancellation(cancellationToken)
|
||||||
|
.GetAsyncEnumerator();
|
||||||
|
|
||||||
|
while (await e.MoveNextAsync())
|
||||||
|
{
|
||||||
|
var value = e.Current;
|
||||||
|
|
||||||
|
if (await asyncPredicate(value).ConfigureAwait(false))
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Maybe.Empty<T>();
|
||||||
|
}
|
||||||
|
|
||||||
public static Maybe<TValue> TryGetValue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) =>
|
public static Maybe<TValue> TryGetValue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) =>
|
||||||
dict.TryGetValue(key, out var value) ? Maybe.Create(value) : Maybe.Empty<TValue>();
|
dict.TryGetValue(key, out var value) ? Maybe.Create(value) : Maybe.Empty<TValue>();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user