forked from xiongyuxing/tiku-backend.net
48 lines
1.8 KiB
C#
48 lines
1.8 KiB
C#
using System.Linq.Expressions;
|
|
using Tiku.Application.Security;
|
|
|
|
namespace Tiku.Infrastructure.Security;
|
|
|
|
internal static class DataScopeQueryableExtensions
|
|
{
|
|
public static IQueryable<TEntity> ApplyDataScope<TEntity>(
|
|
this IQueryable<TEntity> query,
|
|
CurrentDataScope scope,
|
|
Expression<Func<TEntity, bool>>? selfPredicate,
|
|
Expression<Func<TEntity, bool>>? restrictedPredicate)
|
|
{
|
|
if (scope.Mode == DataScopeMode.All)
|
|
{
|
|
return query;
|
|
}
|
|
|
|
Expression<Func<TEntity, bool>>? 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<Func<TEntity, bool>> OrElse<TEntity>(
|
|
Expression<Func<TEntity, bool>> left,
|
|
Expression<Func<TEntity, bool>> 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<Func<TEntity, bool>>(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);
|
|
}
|
|
}
|