private static Expression BuildOperatorExpression(Expression propertyExp, IFilterRule rule, BuildExpressionOptions options, Type type) { Expression expression; string oper = rule.Operator.ToLower(); switch (oper) { case "in": expression = In(type, rule.Value, propertyExp, options); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp, options); break; case "equal": expression = Equals(type, rule.Value, propertyExp, options); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp, options); break; case "between": expression = Between(type, rule.Value, propertyExp, options); break; case "not_between": expression = NotBetween(type, rule.Value, propertyExp, options); break; case "less": expression = LessThan(type, rule.Value, propertyExp, options); break; case "less_or_equal": expression = LessThanOrEqual(type, rule.Value, propertyExp, options); break; case "greater": expression = GreaterThan(type, rule.Value, propertyExp, options); break; case "greater_or_equal": expression = GreaterThanOrEqual(type, rule.Value, propertyExp, options); break; case "begins_with": expression = BeginsWith(type, rule.Value, propertyExp); break; case "not_begins_with": expression = NotBeginsWith(type, rule.Value, propertyExp); break; case "contains": expression = Contains(type, rule.Value, propertyExp); break; case "not_contains": expression = NotContains(type, rule.Value, propertyExp); break; case "ends_with": expression = EndsWith(type, rule.Value, propertyExp); break; case "not_ends_with": expression = NotEndsWith(type, rule.Value, propertyExp); break; case "is_empty": expression = IsEmpty(propertyExp); break; case "is_not_empty": expression = IsNotEmpty(propertyExp); break; case "is_null": expression = IsNull(propertyExp); break; case "is_not_null": expression = IsNotNull(propertyExp); break; default: //custom operators support var operators = options.Operators; if (operators != null && operators.Count() > 0) { var customOperator = (from p in operators where p.Operator.ToLower() == oper select p).FirstOrDefault(); if (customOperator != null) { return(customOperator.GetExpression(type, rule, propertyExp, options)); } } throw new Exception($"Unknown expression operator: {rule.Operator}"); } return(expression); }
/// <summary> /// Gets the filtered collection after applying the provided filter rules. /// </summary> /// <typeparam name="T">The generic type.</typeparam> /// <param name="queryable">The queryable.</param> /// <param name="filterRule">The filter rule.</param> /// <param name="useIndexedProperty">Whether or not to use indexed property</param> /// <param name="indexedPropertyName">The indexable property to use</param> /// <returns>Filtered IQueryable</returns> public static IQueryable <T> BuildQuery <T>(this IEnumerable <T> queryable, IFilterRule filterRule, bool useIndexedProperty = false, string indexedPropertyName = null) { string parsedQuery; return(BuildQuery(queryable.AsQueryable(), filterRule, out parsedQuery, useIndexedProperty, indexedPropertyName)); }
private static Expression BuildExpressionTree(ParameterExpression pe, IFilterRule rule, BuildExpressionOptions options) { if (rule.Rules != null && rule.Rules.Any()) { var expressions = rule.Rules.Select(childRule => BuildExpressionTree(pe, childRule, options)) .Where(expression => expression != null) .ToList(); var expressionTree = expressions.First(); var counter = 1; while (counter < expressions.Count) { expressionTree = rule.Condition.ToLower() == "or" ? Expression.Or(expressionTree, expressions[counter]) : Expression.And(expressionTree, expressions[counter]); counter++; } return(expressionTree); } if (rule.Field != null) { Type type; switch (rule.Type) { case "integer": type = typeof(int); break; case "double": type = typeof(double); break; case "string": type = typeof(string); break; case "date": case "datetime": type = typeof(DateTime); break; case "boolean": type = typeof(bool); break; default: throw new Exception($"Unexpected data type {rule.Type}"); } if (options.UseIndexedProperty) { var propertyExp = Expression.Property(pe, options.IndexedPropertyName, Expression.Constant(rule.Field)); return(BuildOperatorExpression(propertyExp, rule, options, type)); } else { var propertyList = rule.Field.Split('.'); if (propertyList.Length > 1) { var propertyCollectionEnumerator = propertyList.AsEnumerable().GetEnumerator(); return(BuildNestedExpression(pe, propertyCollectionEnumerator, rule, options, type)); } else { var propertyExp = Expression.Property(pe, rule.Field); return(BuildOperatorExpression(propertyExp, rule, options, type)); } } } return(null); }
private static Expression BuildNestedExpression(Expression expression, IEnumerator <string> propertyCollectionEnumerator, IFilterRule rule, BuildExpressionOptions options, Type type) { while (propertyCollectionEnumerator.MoveNext()) { var propertyName = propertyCollectionEnumerator.Current; var property = expression.Type.GetProperty(propertyName); expression = Expression.Property(expression, property); var propertyType = property.PropertyType; var enumerable = propertyType.GetInterface("IEnumerable`1"); if (propertyType != typeof(string) && enumerable != null) { var elementType = enumerable.GetGenericArguments()[0]; var predicateFnType = typeof(Func <,>).MakeGenericType(elementType, typeof(bool)); var parameterExpression = Expression.Parameter(elementType); Expression body = BuildNestedExpression(parameterExpression, propertyCollectionEnumerator, rule, options, type); var predicate = Expression.Lambda(predicateFnType, body, parameterExpression); var queryable = Expression.Call(typeof(Queryable), "AsQueryable", new[] { elementType }, expression); return(Expression.Call( typeof(Queryable), "Any", new[] { elementType }, queryable, predicate )); } } return(BuildOperatorExpression(expression, rule, options, type)); }
/// <summary> /// Gets the filtered collection after applying the provided filter rules. /// Returns the string representation for diagnostic purposes. /// </summary> /// <typeparam name="T">The generic type.</typeparam> /// <param name="queryable">The queryable.</param> /// <param name="filterRule">The filter rule.</param> /// <param name="options">The options to use when building the expression</param> /// <returns>Filtered IQueryable.</returns> public static IQueryable <T> BuildQuery <T>(this IQueryable <T> queryable, IFilterRule filterRule, BuildExpressionOptions options) { string parsedQuery; return(BuildQuery(queryable, filterRule, options, out parsedQuery)); }
/// <summary> /// Builds a predicate that returns whether an input test object passes the filter rule. /// </summary> /// <typeparam name="T">The generic type of the input object to test.</typeparam> /// <param name="filterRule">The filter rule.</param> /// <param name="options">The options to use when building the expression</param> /// <returns>A predicate function implementing the filter rule</returns> public static Func <T, bool> BuildPredicate <T>(this IFilterRule filterRule, BuildExpressionOptions options) { string parsedQuery; return(BuildPredicate <T>(filterRule, options, out parsedQuery)); }
private static Expression BuildExpressionTree(ParameterExpression pe, IFilterRule rule, BuildExpressionOptions options) { if (rule.Rules != null && rule.Rules.Any()) { var expressions = rule.Rules.Select(childRule => BuildExpressionTree(pe, childRule, options)) .Where(expression => expression != null) .ToList(); var expressionTree = expressions.First(); var counter = 1; while (counter < expressions.Count) { expressionTree = rule.Condition.ToLower() == "or" ? Expression.Or(expressionTree, expressions[counter]) : Expression.And(expressionTree, expressions[counter]); counter++; } return(expressionTree); } if (rule.Field != null) { Type type; switch (rule.Type) { case "integer": type = typeof(int); break; case "double": type = typeof(double); break; case "string": type = typeof(string); break; case "date": case "datetime": type = typeof(DateTime); break; case "boolean": type = typeof(bool); break; default: throw new Exception($"Unexpected data type {rule.Type}"); } Expression propertyExp = null; if (options.UseIndexedProperty) { propertyExp = Expression.Property(pe, options.IndexedPropertyName, Expression.Constant(rule.Field)); } else { var propertyList = rule.Field.Split('.').ToList(); if (propertyList.Count() > 1) { propertyExp = Expression.Property(pe, propertyList.First()); foreach (var prop in propertyList.Skip(1)) { propertyExp = Expression.Property(propertyExp, prop); } } else { propertyExp = Expression.Property(pe, rule.Field); } } Expression expression; switch (rule.Operator.ToLower()) { case "in": expression = In(type, rule.Value, propertyExp, options); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp, options); break; case "equal": expression = Equals(type, rule.Value, propertyExp, options); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp, options); break; case "between": expression = Between(type, rule.Value, propertyExp, options); break; case "not_between": expression = NotBetween(type, rule.Value, propertyExp, options); break; case "less": expression = LessThan(type, rule.Value, propertyExp, options); break; case "less_or_equal": expression = LessThanOrEqual(type, rule.Value, propertyExp, options); break; case "greater": expression = GreaterThan(type, rule.Value, propertyExp, options); break; case "greater_or_equal": expression = GreaterThanOrEqual(type, rule.Value, propertyExp, options); break; case "begins_with": expression = BeginsWith(type, rule.Value, propertyExp); break; case "not_begins_with": expression = NotBeginsWith(type, rule.Value, propertyExp); break; case "contains": expression = Contains(type, rule.Value, propertyExp); break; case "not_contains": expression = NotContains(type, rule.Value, propertyExp); break; case "ends_with": expression = EndsWith(type, rule.Value, propertyExp); break; case "not_ends_with": expression = NotEndsWith(type, rule.Value, propertyExp); break; case "is_empty": expression = IsEmpty(propertyExp); break; case "is_not_empty": expression = IsNotEmpty(propertyExp); break; case "is_null": expression = IsNull(propertyExp); break; case "is_not_null": expression = IsNotNull(propertyExp); break; default: throw new Exception($"Unknown expression operator: {rule.Operator}"); } return(expression); } return(null); }
/// <summary> /// Gets the filtered collection after applying the provided filter rules. /// Returns the string representation for diagnostic purposes. /// </summary> /// <typeparam name="T">The generic type.</typeparam> /// <param name="queryable">The queryable.</param> /// <param name="filterRule">The filter rule.</param> /// <param name="parsedQuery">The parsed query.</param> /// <param name="useIndexedProperty">Whether or not to use indexed property</param> /// <param name="indexedPropertyName">The indexable property to use</param> /// <returns>Filtered IQueryable.</returns> public static IQueryable <T> BuildQuery <T>(this IQueryable <T> queryable, IFilterRule filterRule, out string parsedQuery, bool useIndexedProperty = false, string indexedPropertyName = null) { return(BuildQuery(queryable, filterRule, new BuildExpressionOptions { UseIndexedProperty = useIndexedProperty, IndexedPropertyName = indexedPropertyName }, out parsedQuery)); }
private IQueryable <TEntity> ApplyFilterRule <TEntity>(IQueryable <TEntity> queryable, IFilterRule filterRule) { var lambda = filterRule.GetExpression <TEntity>(); MethodCallExpression result = Expression.Call( typeof(Queryable), "Where", new[] { queryable.ElementType }, queryable.Expression, lambda); return(queryable.Provider.CreateQuery <TEntity>(result)); }
private static Expression BuildOperatorExpression(Expression propertyExp, IFilterRule rule, BuildExpressionOptions options, Type type) { Expression expression; switch (rule.Operator.ToLower()) { case "in": expression = In(type, rule.Value, propertyExp, options); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp, options); break; case "equal": expression = Equals(type, rule.Value, propertyExp, options); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp, options); break; case "between": expression = Between(type, rule.Value, propertyExp, options); break; case "not_between": expression = NotBetween(type, rule.Value, propertyExp, options); break; case "less": expression = LessThan(type, rule.Value, propertyExp, options); break; case "less_or_equal": expression = LessThanOrEqual(type, rule.Value, propertyExp, options); break; case "greater": expression = GreaterThan(type, rule.Value, propertyExp, options); break; case "greater_or_equal": expression = GreaterThanOrEqual(type, rule.Value, propertyExp, options); break; case "begins_with": expression = BeginsWith(type, rule.Value, propertyExp); break; case "not_begins_with": expression = NotBeginsWith(type, rule.Value, propertyExp); break; case "contains": expression = Contains(type, rule.Value, propertyExp); break; case "not_contains": expression = NotContains(type, rule.Value, propertyExp); break; case "ends_with": expression = EndsWith(type, rule.Value, propertyExp); break; case "not_ends_with": expression = NotEndsWith(type, rule.Value, propertyExp); break; case "is_empty": expression = IsEmpty(propertyExp); break; case "is_not_empty": expression = IsNotEmpty(propertyExp); break; case "is_null": expression = IsNull(propertyExp); break; case "is_not_null": expression = IsNotNull(propertyExp); break; default: throw new Exception($"Unknown expression operator: {rule.Operator}"); } return(expression); }
public Filter(IFilterRule filterRule) { this.filterRule = filterRule ?? throw new ArgumentNullException(nameof(filterRule)); }
private static Expression BuildElementAccessExpression(Expression expression, IEnumerator <string> propertyCollectionEnumerator, IFilterRule rule, BuildExpressionOptions options, Type type) { var propertyName = propertyCollectionEnumerator.Current; var leftBraceIndex = propertyName.IndexOf("["); var rightBraceIndex = propertyName.IndexOf("]"); if (leftBraceIndex > -1) { propertyName = propertyName.Substring(0, leftBraceIndex); } var propertyInfo = expression.Type.GetProperty(propertyName); var propertyExpression = Expression.Property(expression, propertyInfo); var propertyType = propertyInfo.PropertyType; var dictionary = propertyType.GetInterface("IDictionary`2"); Type[] dictionaryTypes = dictionary.GetGenericArguments(); Type dictionaryKeyType = dictionaryTypes[0]; Type dictionaryValueType = dictionaryTypes[1]; if (dictionaryKeyType != typeof(string)) { throw new NotSupportedException("Only Dictionaries with string keys are supported at present."); } var dictionaryKeyValue = propertyCollectionEnumerator.Current.Substring(leftBraceIndex + 2, propertyCollectionEnumerator.Current.Length - leftBraceIndex - 4); PropertyInfo indexerProperty = dictionary.GetProperty("Item"); var dictionaryKeyConst = Expression.Constant(dictionaryKeyValue); var indexExpression = Expression.MakeIndex(propertyExpression, indexerProperty, new[] { dictionaryKeyConst }); return(indexExpression); }
public FilterRuleViewModel(FilterTypeViewModel type, IFilterRule rule) { Rule = rule; Type = type; Details = FilterFactory.GetRuleDetails(rule); }
public Expression GetExpression(Type type, IFilterRule rule, Expression propertyExp, BuildExpressionOptions options) { return(Expression.Call(this.GetType().GetMethod("ContainsIP"), new[] { propertyExp, Expression.Constant(rule.Value) })); }
/// <summary> /// /// </summary> /// <param name="queryable"></param> /// <param name="filterRule"></param> /// <returns></returns> public static IQueryable BuildDynamicQuery(this IQueryable queryable, IFilterRule filterRule) { var returnValue = new ToStringQueryFiltering().ApplyFiltering(queryable, filterRule); return(returnValue); }