(feature): expression extensions
This commit is contained in:
parent
6da856e2ad
commit
d8eacdd32a
@ -0,0 +1,59 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using MaksIT.Core.Extensions;
|
||||
|
||||
|
||||
namespace MaksIT.Core.Tests.Extensions;
|
||||
|
||||
public class ExpressionExtensionsTests {
|
||||
[Fact]
|
||||
public void CreateContainsPredicate_ShouldReturnTrue_WhenIdIsInList() {
|
||||
// Arrange
|
||||
var ids = new List<Guid> { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var targetId = ids[1];
|
||||
var predicate = ExpressionExtensions.CreateContainsPredicate<TestEntity>(ids, nameof(TestEntity.Id));
|
||||
|
||||
// Act
|
||||
var result = predicate.Compile()(new TestEntity { Id = targetId });
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateContainsPredicate_ShouldReturnFalse_WhenIdIsNotInList() {
|
||||
// Arrange
|
||||
var ids = new List<Guid> { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var targetId = Guid.NewGuid();
|
||||
var predicate = ExpressionExtensions.CreateContainsPredicate<TestEntity>(ids, nameof(TestEntity.Id));
|
||||
|
||||
// Act
|
||||
var result = predicate.Compile()(new TestEntity { Id = targetId });
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CombineWith_ShouldCombineTwoPredicates() {
|
||||
// Arrange
|
||||
Expression<Func<TestEntity, bool>> firstPredicate = x => x.Age > 18;
|
||||
Expression<Func<TestEntity, bool>> secondPredicate = x => x.Name.StartsWith("A");
|
||||
|
||||
// Act
|
||||
var combinedPredicate = firstPredicate.CombineWith(secondPredicate);
|
||||
var compiledPredicate = combinedPredicate.Compile();
|
||||
|
||||
// Assert
|
||||
Assert.True(compiledPredicate(new TestEntity { Age = 20, Name = "Alice" }));
|
||||
Assert.False(compiledPredicate(new TestEntity { Age = 17, Name = "Alice" }));
|
||||
Assert.False(compiledPredicate(new TestEntity { Age = 20, Name = "Bob" }));
|
||||
}
|
||||
|
||||
private class TestEntity {
|
||||
public Guid Id { get; set; }
|
||||
public int Age { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
44
src/MaksIT.Core/Extensions/ExpressionExtensions.cs
Normal file
44
src/MaksIT.Core/Extensions/ExpressionExtensions.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
|
||||
namespace MaksIT.Core.Extensions;
|
||||
|
||||
public static class ExpressionExtensions {
|
||||
|
||||
public static Expression<Func<T, bool>> CreateContainsPredicate<T>(IEnumerable<Guid> ids, string propertyName) {
|
||||
var parameter = Expression.Parameter(typeof(T), "x");
|
||||
var property = Expression.Property(parameter, propertyName);
|
||||
var containsMethod = typeof(List<Guid>).GetMethod("Contains", new[] { typeof(Guid) });
|
||||
var containsCall = Expression.Call(Expression.Constant(ids), containsMethod!, property);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(containsCall, parameter);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> CombineWith<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second) {
|
||||
var parameter = first.Parameters[0];
|
||||
var visitor = new SubstituteParameterVisitor(second.Parameters[0], parameter);
|
||||
var secondBody = visitor.Visit(second.Body);
|
||||
var combinedBody = Expression.AndAlso(first.Body, secondBody);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(combinedBody, parameter);
|
||||
}
|
||||
|
||||
private class SubstituteParameterVisitor : ExpressionVisitor {
|
||||
private readonly ParameterExpression _oldParameter;
|
||||
private readonly ParameterExpression _newParameter;
|
||||
|
||||
public SubstituteParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter) {
|
||||
_oldParameter = oldParameter;
|
||||
_newParameter = newParameter;
|
||||
}
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression node) {
|
||||
// Replace old parameter with the new one
|
||||
return node == _oldParameter ? _newParameter : base.VisitParameter(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
<!-- NuGet package metadata -->
|
||||
<PackageId>MaksIT.Core</PackageId>
|
||||
<Version>1.1.0</Version>
|
||||
<Version>1.1.1</Version>
|
||||
<Authors>Maksym Sadovnychyy</Authors>
|
||||
<Company>MAKS-IT</Company>
|
||||
<Product>MaksIT.Core</Product>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user