mirror of https://github.com/sean-m/McRule.git
Removed the static GenerateExpressionPolicyForType and fleshed out more interfaces. Need testing with nested policies which rely on a specific expression generator for correctness.
parent
484f517979
commit
aef5190f3e
|
@ -93,7 +93,7 @@ namespace McRule.Tests {
|
|||
("People", "name", "*ean").ToFilterRule(),
|
||||
("People", "name", "~*EAN").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
};
|
||||
|
||||
ExpressionPolicy youngens = new ExpressionPolicy {
|
||||
|
@ -104,7 +104,7 @@ namespace McRule.Tests {
|
|||
("People", "number", ">=17").ToFilterRule(),
|
||||
("People", "number", "<30").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
};
|
||||
|
||||
ExpressionPolicy vikings = new ExpressionPolicy {
|
||||
|
@ -113,7 +113,7 @@ namespace McRule.Tests {
|
|||
{
|
||||
("People", "kind", "~viking").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
};
|
||||
|
||||
ExpressionPolicy muggles = new ExpressionPolicy {
|
||||
|
@ -122,7 +122,7 @@ namespace McRule.Tests {
|
|||
{
|
||||
("People", "tags", "muggle").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
};
|
||||
|
||||
ExpressionPolicy notQuiteDead = new ExpressionPolicy {
|
||||
|
@ -130,7 +130,7 @@ namespace McRule.Tests {
|
|||
{
|
||||
("People", "stillWithUs", "true").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
};
|
||||
|
||||
ExpressionPolicy deadOrViking = new ExpressionPolicy {
|
||||
|
@ -139,7 +139,7 @@ namespace McRule.Tests {
|
|||
("People", "stillWithUs", "false").ToFilterRule(),
|
||||
("People", "kind", "Viking").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.Or
|
||||
RuleOperator = RuleOperator.Or
|
||||
};
|
||||
|
||||
#endregion testPolicies
|
||||
|
@ -156,7 +156,7 @@ namespace McRule.Tests {
|
|||
|
||||
// Test using EF generator
|
||||
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
||||
var efFilter = matchNullLiteral.GetPredicateExpression<People>(efGenerator)?.Compile();
|
||||
var efFilter = matchNullLiteral.GeneratePredicateExpression<People>(efGenerator)?.Compile();
|
||||
|
||||
folks = peoples.Where(efFilter);
|
||||
|
||||
|
@ -173,7 +173,7 @@ namespace McRule.Tests {
|
|||
|
||||
// Test using EF generator
|
||||
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
||||
var efFilter = matchNullByString.GetPredicateExpression<People>(efGenerator)?.Compile();
|
||||
var efFilter = matchNullByString.GeneratePredicateExpression<People>(efGenerator)?.Compile();
|
||||
|
||||
folks = peoples.Where(efFilter);
|
||||
|
||||
|
@ -206,7 +206,7 @@ namespace McRule.Tests {
|
|||
Rules = new[] {
|
||||
youngens, vikings
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.And
|
||||
RuleOperator = RuleOperator.And
|
||||
}?.GetPredicateExpression<People>()?.Compile();
|
||||
|
||||
var folks = peoples.Where(filter);
|
||||
|
@ -231,7 +231,7 @@ namespace McRule.Tests {
|
|||
Rules = new[] {
|
||||
youngens, vikings
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.Or
|
||||
RuleOperator = RuleOperator.Or
|
||||
}?.GetPredicateExpression<People>()?.Compile();
|
||||
|
||||
folks = peoples.Where(filter);
|
||||
|
@ -254,11 +254,11 @@ namespace McRule.Tests {
|
|||
public void FilterListOfObjectsByMemberCollectionContents()
|
||||
{
|
||||
var generator = new PolicyToExpressionGenerator();
|
||||
var generatedFilter = muggles.GetPredicateExpression<People>(generator);
|
||||
var generatedFilter = muggles.GeneratePredicateExpression<People>(generator);
|
||||
var filteredFolks = peoples.Where(generatedFilter.Compile());
|
||||
|
||||
var efGenerator = new PolicyToEFExpressionGenerator();
|
||||
var efGeneratedFilter = muggles.GetPredicateExpression<People>(efGenerator);
|
||||
var efGeneratedFilter = muggles.GeneratePredicateExpression<People>(efGenerator);
|
||||
var efFilteredFolks = peoples.Where(efGeneratedFilter.Compile());
|
||||
|
||||
|
||||
|
@ -281,11 +281,9 @@ namespace McRule.Tests {
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void NullFilterWhenNoMatchingTypes() {
|
||||
public void FilterWhenNoMatchingTypesThrows() {
|
||||
// Shouldn't have any filters in the policy for string objects.
|
||||
var filter = notQuiteDead.GetPredicateExpression<string>()?.Compile();
|
||||
|
||||
Assert.Null(filter);
|
||||
Assert.Throws<ExpressionGeneratorException>(() => { notQuiteDead.GetPredicateExpression<string>(); });
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -314,7 +312,7 @@ namespace McRule.Tests {
|
|||
var filter = eans.GetPredicateExpression<People>();
|
||||
|
||||
var efGenerator = PredicateExpressionPolicyExtensions.GetEfExpressionGenerator();
|
||||
var efFilter = eans.GetPredicateExpression<People>(efGenerator);
|
||||
var efFilter = eans.GeneratePredicateExpression<People>(efGenerator);
|
||||
|
||||
Assert.NotNull(filter);
|
||||
Assert.AreNotEqual(efFilter.ToString(), filter.ToString());
|
||||
|
@ -326,7 +324,7 @@ namespace McRule.Tests {
|
|||
public void BaseThrowsOnPoorlyImplementedGenerator()
|
||||
{
|
||||
var failedGenerator = new FailedExpressionGeneratorBase();
|
||||
Assert.Throws<NotImplementedException>(() => { _ = eans.GetPredicateExpression<People>(failedGenerator); });
|
||||
Assert.Throws<NotImplementedException>(() => { _ = eans.GeneratePredicateExpression<People>(failedGenerator); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace McRule {
|
||||
public class ExpressionGeneratorException : Exception {
|
||||
public ExpressionGeneratorException() { }
|
||||
public ExpressionGeneratorException(string message) : base(message) { }
|
||||
public ExpressionGeneratorException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
}
|
|
@ -4,16 +4,32 @@ using System.Linq.Expressions;
|
|||
using System.Text;
|
||||
|
||||
namespace McRule {
|
||||
|
||||
public interface IExpressionRuleCollection {
|
||||
public Guid Id { get; }
|
||||
public IEnumerable<IExpressionPolicy> Rules { get; }
|
||||
public RuleOperator RuleOperator { get; }
|
||||
}
|
||||
|
||||
public interface IExpressionRule {
|
||||
string TargetType { get; set; }
|
||||
string Property { get; set; }
|
||||
string Value { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public interface IExpressionPolicy {
|
||||
|
||||
Expression<Func<T, bool>>? GetPredicateExpression<T>();
|
||||
Expression<Func<T, bool>>? GetPredicateExpression<T>(ExpressionGenerator generator);
|
||||
Expression<Func<T, bool>>? GeneratePredicateExpression<T>(ExpressionGenerator generator);
|
||||
}
|
||||
|
||||
public interface ExpressionGenerator
|
||||
{
|
||||
Expression<Func<T, bool>>? GetPredicateExpression<T>(ExpressionRuleCollection policy);
|
||||
Expression<Func<T, bool>>? GetPredicateExpressionOrFalse<T>(IExpressionPolicy policy);
|
||||
|
||||
Expression<Func<T, bool>>? GetPredicateExpression<T>(IExpressionRule policy);
|
||||
Expression<Func<T, bool>>? GetPredicateExpression<T>(IExpressionRuleCollection policy);
|
||||
Expression<Func<T, bool>> GetPredicateExpressionForType<T>(string property, string value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,32 +3,33 @@ using System.Collections.Generic;
|
|||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
using static McRule.PredicateExpressionPolicyExtensions;
|
||||
|
||||
namespace McRule {
|
||||
|
||||
public class ExpressionRuleCollection : IExpressionRule {
|
||||
public class ExpressionRuleCollection : IExpressionRuleCollection, IExpressionPolicy {
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
public PredicateExpressionPolicyExtensions.RuleOperator RuleOperator { get; set; } = PredicateExpressionPolicyExtensions.RuleOperator.And;
|
||||
public IEnumerable<IExpressionRule> Rules { get; set; }
|
||||
public string Name { get; set; }
|
||||
public RuleOperator RuleOperator { get; set; } = RuleOperator.And;
|
||||
public IEnumerable<IExpressionPolicy> Rules { get; set; }
|
||||
public string TargetType { get; set; }
|
||||
|
||||
public ExpressionRuleCollection() { }
|
||||
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>() {
|
||||
var expressions = Rules.Select(x => x.GetPredicateExpression<T>()).Where(x => x != null);
|
||||
var gen = PredicateExpressionPolicyExtensions.GetCoreExpressionGenerator();
|
||||
|
||||
return (RuleOperator == PredicateExpressionPolicyExtensions.RuleOperator.Or)
|
||||
? PredicateExpressionPolicyExtensions.CombineOr<T>(expressions)
|
||||
: PredicateExpressionPolicyExtensions.CombineAnd<T>(expressions);
|
||||
return GeneratePredicateExpression<T>(gen);
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(ExpressionGenerator generator)
|
||||
public Expression<Func<T, bool>>? GeneratePredicateExpression<T>(ExpressionGenerator generator)
|
||||
{
|
||||
var expressions = generator.GetPredicateExpression<T>(this);
|
||||
return expressions;
|
||||
}
|
||||
}
|
||||
|
||||
public class ExpressionRule : IExpressionRule {
|
||||
public class ExpressionRule : IExpressionRule, IExpressionPolicy {
|
||||
public string TargetType { get; set; }
|
||||
public string Property { get; set; }
|
||||
public string Value { get; set; }
|
||||
|
@ -56,7 +57,7 @@ namespace McRule {
|
|||
if (!(typeof(T).Name.Equals(this.TargetType, StringComparison.CurrentCultureIgnoreCase))) return null;
|
||||
|
||||
if (cachedExpression == null) {
|
||||
cachedExpression = PredicateExpressionPolicyExtensions.GetPredicateExpressionForType<T>(this.Property, this.Value);
|
||||
cachedExpression = GetCoreExpressionGenerator().GetPredicateExpressionForType<T>(this.Property, this.Value);
|
||||
}
|
||||
|
||||
return (Expression<Func<T, bool>>)cachedExpression;
|
||||
|
@ -65,7 +66,7 @@ namespace McRule {
|
|||
/// <summary>
|
||||
/// Returns an expression tree targeting an object type based on policy parameters.
|
||||
/// </summary>
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(ExpressionGenerator generator) {
|
||||
public Expression<Func<T, bool>>? GeneratePredicateExpression<T>(ExpressionGenerator generator) {
|
||||
if (!(typeof(T).Name.Equals(this.TargetType, StringComparison.CurrentCultureIgnoreCase))) return null;
|
||||
|
||||
return generator.GetPredicateExpressionForType<T>(this.Property, this.Value);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<UserSecretsId>63a98c68-03bd-4069-b6b9-e0978081c430</UserSecretsId>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Title>McRule - Rule based expression generator</Title>
|
||||
<Version>0.2.2</Version>
|
||||
<Version>0.3.0</Version>
|
||||
<Company>Sean McArdle</Company>
|
||||
<Description>Library for generating expression trees from simple policy rules.</Description>
|
||||
<Copyright>2023 Sean McArdle</Copyright>
|
||||
|
|
|
@ -8,14 +8,13 @@ using static McRule.PredicateExpressionPolicyExtensions;
|
|||
|
||||
namespace McRule;
|
||||
|
||||
public enum RuleOperator {
|
||||
And,
|
||||
Or
|
||||
}
|
||||
|
||||
public static partial class PredicateExpressionPolicyExtensions
|
||||
{
|
||||
public enum RuleOperator
|
||||
{
|
||||
And,
|
||||
Or
|
||||
}
|
||||
|
||||
public static ExpressionRule ToFilterRule(this (string, string, string) tuple)
|
||||
{
|
||||
return new ExpressionRule(tuple);
|
||||
|
@ -143,7 +142,7 @@ public static partial class PredicateExpressionPolicyExtensions
|
|||
/// Combine a list of expressions based on the given operator enum.
|
||||
/// </summary>
|
||||
public static Expression<Func<T, bool>>? CombinePredicates<T>(IEnumerable<Expression<Func<T, bool>>> predicates,
|
||||
PredicateExpressionPolicyExtensions.RuleOperator op)
|
||||
RuleOperator op)
|
||||
{
|
||||
if (predicates.Count() == 0) return null;
|
||||
|
||||
|
@ -216,133 +215,6 @@ public static partial class PredicateExpressionPolicyExtensions
|
|||
return (false, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dynamically build an expression suitable for filtering in a Where clause
|
||||
/// </summary>
|
||||
public static Expression<Func<T, bool>> GetPredicateExpressionForType<T>(string property, string value)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(T), "x");
|
||||
var opLeft = Expression.Property(parameter, property);
|
||||
(bool literalFound, LiteralValue? processedValue) = GetStringValueLiteral(value);
|
||||
var opRight = Expression.Constant(value);
|
||||
Expression? comparison = null;
|
||||
|
||||
// For IComparable types on the left hand side, attempt to parse the right hand side
|
||||
// into the same type and use <,>,<=,>=,= prefixes to infer BinaryExpression type.
|
||||
// Should work with numerical or datetime values provided they parse correctly.
|
||||
// Note, a float on the right hand side will not parse into an integer type implicitly
|
||||
// so it is parsed into a decimal value first and then rounded to the nearest integral.
|
||||
var lType = opLeft.Type;
|
||||
var isNullable = false;
|
||||
Type? hasComparable = lType.GetInterface("IComparable");
|
||||
Type? hasCollection = lType.GetInterface("ICollection");
|
||||
if (hasComparable == null && opLeft.Type.IsValueType)
|
||||
{
|
||||
lType = Nullable.GetUnderlyingType(opLeft.Type);
|
||||
// Nullable.GetUnderlyingType only returns a non-null value if the
|
||||
// supplied type was indeed a nullable type.
|
||||
if (lType != null)
|
||||
isNullable = true;
|
||||
hasComparable = lType.GetInterface("IComparable");
|
||||
}
|
||||
|
||||
if (literalFound) {
|
||||
if (processedValue is NullValue) {
|
||||
return Expression.Lambda<Func<T, bool>>(IsNull<T>(opLeft), parameter);
|
||||
}
|
||||
}
|
||||
|
||||
// For string comparisons using wildcards, trim the wildcard characters and pass to the comparison method
|
||||
if (lType == typeof(string))
|
||||
{
|
||||
Expression<Func<T, bool>> result;
|
||||
|
||||
// Grab the object property for use in the inner expression body
|
||||
var strParam = Expression.Lambda<Func<T, string>>(opLeft, parameter);
|
||||
|
||||
// If a string match begins with !, we negate the result.
|
||||
var negateResult = false;
|
||||
if (value.StartsWith("!"))
|
||||
{
|
||||
negateResult = true;
|
||||
value = value.TrimStart('!');
|
||||
}
|
||||
|
||||
// String comparisons which are prefixed with '~' will be evaluated ignoring case.
|
||||
// Note: when expression trees are used outside .net, such as with EF to SQL Server,
|
||||
// default case sensitivity for that environment may apply implicitly and counter to
|
||||
// filter policy intent.
|
||||
bool ignoreCase = false;
|
||||
if (value.StartsWith('~'))
|
||||
{
|
||||
ignoreCase = true;
|
||||
value = value.TrimStart('~');
|
||||
}
|
||||
|
||||
if (value.StartsWith("*") && value.EndsWith("*"))
|
||||
{
|
||||
result = AddStringPropertyExpression<T>(strParam, value.Trim('*'), "Contains", ignoreCase);
|
||||
}
|
||||
else if (value.StartsWith("*"))
|
||||
{
|
||||
result = AddStringPropertyExpression<T>(strParam, value.TrimStart('*'), "EndsWith", ignoreCase);
|
||||
}
|
||||
else if (value.EndsWith("*"))
|
||||
{
|
||||
result = AddStringPropertyExpression<T>(strParam, value.TrimEnd('*'), "StartsWith", ignoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = AddStringPropertyExpression<T>(strParam, value, "Equals", ignoreCase);
|
||||
}
|
||||
|
||||
if (negateResult)
|
||||
{
|
||||
result = Negate<T>(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (hasCollection == typeof(ICollection)) {
|
||||
return GetArrayContainsExpression<T>(property, value);
|
||||
}
|
||||
else if (hasComparable == typeof(IComparable)) {
|
||||
var operatorPrefix = Regex.Match(value.Trim(), @"^[!<>=]+");
|
||||
var operand = (operatorPrefix.Success ? value.Replace(operatorPrefix.Value, "") : value).Trim();
|
||||
|
||||
if (!String.IsNullOrEmpty(operand))
|
||||
{
|
||||
var parseMethod = lType.GetMethods().FirstOrDefault(x => x.Name == "Parse");
|
||||
if (intTypes.Contains(opLeft.Type))
|
||||
{
|
||||
operand = operand.Contains(".") ? Math.Round(decimal.Parse(operand)).ToString() : operand;
|
||||
}
|
||||
|
||||
var opRightNumerical = parseMethod?.Invoke(null, new string[] { operand });
|
||||
|
||||
opRight = Expression.Constant(opRightNumerical);
|
||||
Expression opLeftFinal = isNullable ? Expression.Convert(opLeft, lType) : opLeft;
|
||||
comparison = GetComparer(operatorPrefix.Value.Trim(), opLeftFinal, opRight);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
comparison = Expression.Equal(opLeft, opRight);
|
||||
}
|
||||
|
||||
// If comparison is null that means we haven't been able to infer a good comparison
|
||||
// expression for it so just defer to a false literal.
|
||||
Expression<Func<T, bool>> falsePredicate = x => false;
|
||||
comparison = comparison == null ? falsePredicate : comparison;
|
||||
if (isNullable)
|
||||
{
|
||||
comparison = AddNotNullCheck<T>(opLeft, comparison);
|
||||
}
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(comparison ?? Expression.Equal(opLeft, opRight), parameter);
|
||||
}
|
||||
|
||||
|
||||
public static ExpressionGenerator GetCoreExpressionGenerator() => new PolicyToExpressionGenerator();
|
||||
|
||||
public static ExpressionGenerator GetEfExpressionGenerator() => new PolicyToEFExpressionGenerator();
|
||||
|
@ -534,21 +406,16 @@ public abstract class ExpressionGeneratorBase : ExpressionGenerator
|
|||
/// <summary>
|
||||
/// Generate an expression tree targeting an object type based on a given policy.
|
||||
/// </summary>
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(ExpressionRuleCollection policy)
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(IExpressionRuleCollection policy)
|
||||
{
|
||||
Expression<Func<T, bool>>? expressions = PredicateBuilder.False<T>();
|
||||
|
||||
var predicates = new List<Expression<Func<T, bool>>>();
|
||||
var typeName = typeof(T).Name;
|
||||
foreach (var rule in policy.Rules.Where(x => x.TargetType != null))
|
||||
var selectedType = typeof(T);
|
||||
foreach (var rule in policy.Rules)
|
||||
{
|
||||
if (!(typeof(T).Name.Equals(rule.TargetType, StringComparison.CurrentCultureIgnoreCase)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var expression = rule.GetPredicateExpression<T>(this);
|
||||
if (expression != null) predicates.Add(expression);
|
||||
var expression = GetPredicateExpression<T>(rule);
|
||||
if (expression != null) { predicates.Add(expression); }
|
||||
}
|
||||
|
||||
expressions = CombinePredicates<T>(predicates, policy.RuleOperator);
|
||||
|
@ -556,10 +423,28 @@ public abstract class ExpressionGeneratorBase : ExpressionGenerator
|
|||
if (expressions == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(
|
||||
$"No predicates available for type: <{typeof(T).Name}> in policy: {policy.Id}");
|
||||
return PredicateBuilder.False<T>();
|
||||
$"No predicates available for type: <{selectedType.Name}> in policy: {policy.Id}");
|
||||
throw new ExpressionGeneratorException($"No filter expressions found for type: {selectedType.Name} FullName: {selectedType.FullName}");
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(IExpressionPolicy policy) {
|
||||
|
||||
return policy.GeneratePredicateExpression<T>(this);
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>>? GetPredicateExpression<T>(IExpressionRule rule) {
|
||||
if (!string.Equals(typeof(T).Name, rule.TargetType, StringComparison.CurrentCultureIgnoreCase)) return null;
|
||||
|
||||
return GetPredicateExpressionForType<T>(rule.Property, rule.Value);
|
||||
}
|
||||
|
||||
public Expression<Func<T, bool>>? GetPredicateExpressionOrFalse<T>(IExpressionPolicy policy) {
|
||||
var expression = PredicateBuilder.False<T>();
|
||||
try { expression = GetPredicateExpression<T>(policy); }
|
||||
catch { /* Yeah, that didn't work. */ }
|
||||
return expression;
|
||||
}
|
||||
}
|
|
@ -105,7 +105,7 @@ public static class FilterRuleManager
|
|||
return sequence.Where(x => false);
|
||||
}
|
||||
|
||||
var predicates = PredicateExpressionPolicyExtensions.CombinePredicates(rules, PredicateExpressionPolicyExtensions.RuleOperator.And).Compile();
|
||||
var predicates = PredicateExpressionPolicyExtensions.CombinePredicates(rules, RuleOperator.And).Compile();
|
||||
return sequence.Where(predicates);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ using System;
|
|||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static McRule.PredicateExpressionPolicyExtensions;
|
||||
using static RulerDev.MyExtensions;
|
||||
|
||||
|
||||
var users = new List<User> {
|
||||
new User("Sean","McArdle","971-900-7335","503-555-1245", "SDC", "DAS", new string[] {"IT", "Admin"}),
|
||||
new User("Brian","Chamberland","971-900-7335","503-555-1245", "SDC", "DAS"),
|
||||
|
@ -32,7 +33,7 @@ var filterPolicy = new ExpressionPolicy
|
|||
("User", "agency", "OHA").ToFilterRule(),
|
||||
("Group", "agency", "OHA").ToFilterRule(),
|
||||
},
|
||||
RuleOperator = PredicateExpressionPolicyExtensions.RuleOperator.Or
|
||||
RuleOperator = RuleOperator.Or
|
||||
};
|
||||
Expression<Func<User,bool>>? filterExpression = filterPolicy.GetPredicateExpression<User>();
|
||||
filterPolicy.Dump(filterPolicy.Name);
|
||||
|
@ -68,10 +69,10 @@ filterExpression = filterPolicy.GetPredicateExpression<User>();
|
|||
filterPolicy.Dump(filterPolicy.Name);
|
||||
users.Where(filterExpression).Dump($"operator {filterPolicy.RuleOperator}");
|
||||
|
||||
var dynamicFilterDAS = PredicateExpressionPolicyExtensions.GetPredicateExpressionForType<User>("agency", "DAS");
|
||||
var dynamicFilterDAS = GetCoreExpressionGenerator().GetPredicateExpressionForType<User>("agency", "DAS");
|
||||
users.Where(dynamicFilterDAS).Dump("DAS users");
|
||||
|
||||
var dynamicFilterBrian = PredicateExpressionPolicyExtensions.GetPredicateExpressionForType<User>("first","Brian");
|
||||
var dynamicFilterBrian = GetCoreExpressionGenerator().GetPredicateExpressionForType<User>("first","Brian");
|
||||
|
||||
var policies = new List<Expression<Func<User,bool>>>();
|
||||
policies.Add(dynamicFilterDAS);
|
||||
|
|
Loading…
Reference in New Issue