(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 -->
|
<!-- NuGet package metadata -->
|
||||||
<PackageId>MaksIT.Core</PackageId>
|
<PackageId>MaksIT.Core</PackageId>
|
||||||
<Version>1.1.0</Version>
|
<Version>1.1.1</Version>
|
||||||
<Authors>Maksym Sadovnychyy</Authors>
|
<Authors>Maksym Sadovnychyy</Authors>
|
||||||
<Company>MAKS-IT</Company>
|
<Company>MAKS-IT</Company>
|
||||||
<Product>MaksIT.Core</Product>
|
<Product>MaksIT.Core</Product>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user