using System.Linq.Expressions; using Tiku.Application.Security; namespace Tiku.Infrastructure.Security; internal static class DataScopeQueryableExtensions { public static IQueryable ApplyDataScope( this IQueryable query, CurrentDataScope scope, Expression>? selfPredicate, Expression>? restrictedPredicate) { if (scope.Mode == DataScopeMode.All) { return query; } Expression>? predicate = null; if (scope.IncludesSelf && selfPredicate is not null) { predicate = selfPredicate; } if (scope.Mode == DataScopeMode.Restricted && restrictedPredicate is not null) { predicate = predicate is null ? restrictedPredicate : OrElse(predicate, restrictedPredicate); } return predicate is null ? query.Where(_ => false) : query.Where(predicate); } private static Expression> OrElse( Expression> left, Expression> right) { var parameter = Expression.Parameter(typeof(TEntity), "entity"); var leftBody = new ReplaceParameterVisitor(left.Parameters[0], parameter).Visit(left.Body)!; var rightBody = new ReplaceParameterVisitor(right.Parameters[0], parameter).Visit(right.Body)!; return Expression.Lambda>(Expression.OrElse(leftBody, rightBody), parameter); } private sealed class ReplaceParameterVisitor(ParameterExpression source, ParameterExpression target) : ExpressionVisitor { protected override Expression VisitParameter(ParameterExpression node) => node == source ? target : base.VisitParameter(node); } }