84 lines
3.0 KiB
C#
84 lines
3.0 KiB
C#
using Ardalis.Specification;
|
|
using DD.Persistence.Database.Specifications;
|
|
using System.Linq.Expressions;
|
|
|
|
namespace DD.Persistence.Database.Postgres.Extensions;
|
|
|
|
// ToDo: рассмотреть возможность вынести логику в спецификации
|
|
public static class SpecificationExtensions
|
|
{
|
|
public static ISpecification<T> Or<T>(this ISpecification<T> spec, ISpecification<T> otherSpec)
|
|
{
|
|
var newSpec = new EmptySpecification<T>();
|
|
|
|
var parameter = Expression.Parameter(typeof(T), "x");
|
|
|
|
var exprSpec1 = CombineWhereExpressions(spec.WhereExpressions, parameter);
|
|
var exprSpec2 = CombineWhereExpressions(otherSpec.WhereExpressions, parameter);
|
|
|
|
Expression? orExpression = exprSpec1 is not null && exprSpec2 is not null
|
|
? Expression.OrElse(exprSpec1, exprSpec2)
|
|
: exprSpec1 ?? exprSpec2;
|
|
|
|
if (orExpression is null) return newSpec;
|
|
|
|
var lambdaExpr = Expression.Lambda<Func<T, bool>>(orExpression, parameter);
|
|
|
|
newSpec.Query.Where(lambdaExpr);
|
|
|
|
return newSpec;
|
|
}
|
|
|
|
// ToDo: Рефакторинг
|
|
public static ISpecification<T> And<T>(this ISpecification<T> spec, ISpecification<T> otherSpec)
|
|
{
|
|
var newSpec = new EmptySpecification<T>();
|
|
|
|
var parameter = Expression.Parameter(typeof(T), "x");
|
|
|
|
var exprSpec1 = CombineWhereExpressions(spec.WhereExpressions, parameter);
|
|
var exprSpec2 = CombineWhereExpressions(otherSpec.WhereExpressions, parameter);
|
|
|
|
Expression? andExpression = exprSpec1 is not null && exprSpec2 is not null
|
|
? Expression.AndAlso(exprSpec1, exprSpec2)
|
|
: exprSpec1 ?? exprSpec2;
|
|
|
|
if (andExpression is null) return newSpec;
|
|
|
|
var lambdaExpr = Expression.Lambda<Func<T, bool>>(andExpression, parameter);
|
|
|
|
newSpec.Query.Where(lambdaExpr);
|
|
|
|
return newSpec;
|
|
}
|
|
|
|
public static Expression? CombineWhereExpressions<T>(IEnumerable<WhereExpressionInfo<T>> whereExpressions, ParameterExpression parameter)
|
|
{
|
|
Expression? newExpr = null;
|
|
foreach (var where in whereExpressions)
|
|
{
|
|
var expr = ParameterReplacerVisitor.Replace(where.Filter.Body, where.Filter.Parameters[0], parameter);
|
|
newExpr = newExpr is null ? expr : Expression.AndAlso(newExpr, expr);
|
|
}
|
|
return newExpr;
|
|
}
|
|
}
|
|
|
|
public class ParameterReplacerVisitor : ExpressionVisitor
|
|
{
|
|
private readonly Expression _newExpression;
|
|
private readonly ParameterExpression _oldParameter;
|
|
|
|
private ParameterReplacerVisitor(ParameterExpression oldParameter, Expression newExpression)
|
|
{
|
|
_oldParameter = oldParameter;
|
|
_newExpression = newExpression;
|
|
}
|
|
|
|
internal static Expression Replace(Expression expression, ParameterExpression oldParameter, Expression newExpression)
|
|
=> new ParameterReplacerVisitor(oldParameter, newExpression).Visit(expression);
|
|
|
|
protected override Expression VisitParameter(ParameterExpression p)
|
|
=> p == _oldParameter ? _newExpression : p;
|
|
}
|