mirror of https://github.com/sean-m/McRule.git
Fixed intent of negative match. The Not expression was a bitwise operation rather than logical operation. Whoops.
parent
8081903698
commit
9478aa9bfc
|
@ -8,7 +8,7 @@
|
|||
<UserSecretsId>63a98c68-03bd-4069-b6b9-e0978081c430</UserSecretsId>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Title>McRule - Rule based expression generator</Title>
|
||||
<Version>0.1.1</Version>
|
||||
<Version>0.1.2</Version>
|
||||
<Company>Sean McArdle</Company>
|
||||
<Description>Library for generating expression trees from simple policy rules.</Description>
|
||||
<Copyright>2023 Sean McArdle</Copyright>
|
||||
|
|
|
@ -19,8 +19,8 @@ public static class PredicateExpressionPolicyExtensions {
|
|||
/// <summary>
|
||||
/// Builds expressions using string member functions StartsWith, EndsWith or Contains as the comparator.
|
||||
/// </summary>
|
||||
public static Expression<Func<T, bool>> AddStringPropertyExpression<T>(
|
||||
Expression<Func<T, string>> expression, string filter, string filterType, bool ignoreCase=false)
|
||||
public static Expression<Func<T, bool>> AddStringPropertyExpression<T>(
|
||||
Expression<Func<T, string>> lambda, string filter, string filterType, bool ignoreCase = false)
|
||||
{
|
||||
|
||||
#if DEBUG
|
||||
|
@ -31,7 +31,7 @@ public static class PredicateExpressionPolicyExtensions {
|
|||
|
||||
#endif
|
||||
// Check that the property isn't null, otherwise we'd hit null object exceptions at runtime
|
||||
var notNull = Expression.NotEqual(expression.Body, Expression.Constant(null));
|
||||
var notNull = Expression.NotEqual(lambda.Body, Expression.Constant(null));
|
||||
|
||||
// Setup calls to: StartsWith, EndsWith, Contains, or Equals,
|
||||
// conditionally using character case neutral comparision.
|
||||
|
@ -42,13 +42,13 @@ public static class PredicateExpressionPolicyExtensions {
|
|||
}
|
||||
|
||||
MethodInfo methodInfo = typeof(string).GetMethod(filterType, new[] { typeof(string), typeof(StringComparison) });
|
||||
var strPredicate = Expression.Call(expression.Body, methodInfo, expressionArgs);
|
||||
var strPredicate = Expression.Call(lambda.Body, methodInfo, expressionArgs);
|
||||
|
||||
var filterExpression = Expression.AndAlso(notNull, strPredicate);
|
||||
Expression filterExpression = Expression.AndAlso(notNull, strPredicate);
|
||||
|
||||
return Expression.Lambda<Func<T, bool>>(
|
||||
filterExpression,
|
||||
expression.Parameters);
|
||||
lambda.Parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -69,8 +69,14 @@ public static class PredicateExpressionPolicyExtensions {
|
|||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="operand"></param>
|
||||
/// <returns></returns>
|
||||
public static Expression<Func<T, bool>> Negate<T>(Expression operand) {
|
||||
return Expression.Lambda<Func<T, bool>>(Expression.Not(operand));
|
||||
public static Expression<Func<T, bool>> Negate<T>(Expression<Func<T, bool>> lambda) {
|
||||
var body = lambda.Body;
|
||||
var parameters = lambda.Parameters;
|
||||
|
||||
var negated = Expression.IsFalse(body);
|
||||
return Expression.Lambda<Func<T, bool>>(
|
||||
negated,
|
||||
parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
19
README.md
19
README.md
|
@ -6,15 +6,16 @@ Predicates are built using simple syntax to select comparison operators and meth
|
|||
That is the policy specifies the type by name, property to match against and the value the property must have.
|
||||
A simple equality comparison is used by default but operators can be prefixed to a policy operand for customized behavior, as shown below.
|
||||
|
||||
| Property Type | Operator | Comparison Description |
|
||||
|---------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| string | * | Astrisk can appear at the beginning, end or both denoting: StartsWith, EndsWith or Contains respectively. |
|
||||
| string | ~ | Denotes case-insensitive comparison when used in .net, things that translate the resulting expression tree may not respect this. EF core for instance won't bind a Contains with case insensitive comparison from the string methods at all, results in a runtime error. Note: when used with wildcard, tilde operator must be first: '~*foo'. |
|
||||
| IComparable | > | Greater-than comparison. |
|
||||
| IComparable | >= | Greater-than or equal to comparison. |
|
||||
| IComparable | < | Less-than comparison. |
|
||||
| IComparable | <= | Less-than or equal to comparison. |
|
||||
| IComparable | <>, !=, ! | Not-equal to comparison |
|
||||
| Property Type | Operator | Comparison Description |
|
||||
|---------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| string | * | Astrisk can appear at the beginning, end or both denoting: StartsWith, EndsWith or Contains respectively. |
|
||||
| string | ~ | Denotes case-insensitive comparison when used in .net, things that translate the resulting expression tree may not respect this. EF core for instance won't bind a Contains with case insensitive comparison from the string methods at all, results in a runtime error. Note: when used with wildcard, tilde operator must be first: '~*foo'. |
|
||||
| string | ! | Negative expression. Must prefix all other operators. |
|
||||
| IComparable | > | Greater-than comparison. |
|
||||
| IComparable | >= | Greater-than or equal to comparison. |
|
||||
| IComparable | < | Less-than comparison. |
|
||||
| IComparable | <= | Less-than or equal to comparison. |
|
||||
| IComparable | <>, !=, ! | Not-equal to comparison. |
|
||||
|
||||
> Note: the IComparable interface is mostly used for numerical types but custom types with comparison providers may work at runtime.
|
||||
|
||||
|
|
|
@ -80,9 +80,24 @@ var combined = PredicateExpressionPolicyExtensions.CombineAnd(policies);
|
|||
|
||||
users.Where(dynamicFilterBrian).Dump("All *ian's");
|
||||
(from u in users.Where(combined)
|
||||
select new { u.first, u.last, u.agency}).Dump("All Brian's from DAS");
|
||||
select new { u.first, u.last, u.agency}).Dump("All ian's from DAS");
|
||||
|
||||
|
||||
var thePolicy = new ExpressionPolicy {
|
||||
Name = "All DAS *ians case insensitive",
|
||||
Properties = new string[] { }, // Can't do anything with this yet
|
||||
Rules = new List<ExpressionRule>
|
||||
{
|
||||
("Thing", "Name", "!Sean").ToFilterRule(),
|
||||
}
|
||||
};
|
||||
|
||||
var filter = thePolicy.GetExpression<Thing>();
|
||||
filter.Dump();
|
||||
|
||||
new[] { new Thing("Sean", "Confused"), new Thing("Tim", "Enchantor") }.Where(filter.Compile()).Dump();
|
||||
|
||||
public record Thing(string Name, string Kind);
|
||||
|
||||
record User(string first, string last, string workPhone, string homePhone, string workAddress, string agency, string[] tags = null);
|
||||
|
||||
|
|
Loading…
Reference in New Issue