private static Expression BuildExpressionTree(ParameterExpression pe, FilterRule rule, bool useIndexedProperty = false, string indexedPropertyName = null) { if (rule.Rules != null && rule.Rules.Any()) { var expressions = rule.Rules.Select(childRule => BuildExpressionTree(pe, childRule, useIndexedProperty, indexedPropertyName)) .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 (useIndexedProperty) { propertyExp = Expression.Property(pe, indexedPropertyName, Expression.Constant(rule.Field)); } else { propertyExp = Expression.Property(pe, rule.Field); } Expression expression; switch (rule.Operator.ToLower()) { case "in": expression = In(type, rule.Value, propertyExp); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp); break; case "equal": expression = Equals(type, rule.Value, propertyExp); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp); break; case "between": expression = Between(type, rule.Value, propertyExp); break; case "not_between": expression = NotBetween(type, rule.Value, propertyExp); break; case "less": expression = LessThan(type, rule.Value, propertyExp); break; case "less_or_equal": expression = LessThanOrEqual(type, rule.Value, propertyExp); break; case "greater": expression = GreaterThan(type, rule.Value, propertyExp); break; case "greater_or_equal": expression = GreaterThanOrEqual(type, rule.Value, propertyExp); 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. /// </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 IQueryable <T> queryable, FilterRule filterRule, bool useIndexedProperty = false, string indexedPropertyName = null) { string parsedQuery; return(BuildQuery(queryable, filterRule, out parsedQuery, useIndexedProperty, indexedPropertyName)); }
/// <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> /// <returns>Filtered IQueryable</returns> public static IQueryable <T> BuildQuery <T>(this IQueryable <T> queryable, FilterRule filterRule) { string parsedQuery; return(BuildQuery(queryable, filterRule, out parsedQuery)); }
/// <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, FilterRule filterRule, out string parsedQuery, bool useIndexedProperty = false, string indexedPropertyName = null) { return(BuildQuery(queryable, filterRule, new BuildExpressionOptions { UseIndexedProperty = useIndexedProperty, IndexedPropertyName = indexedPropertyName }, 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 FilterRule filterRule, BuildExpressionOptions options) { string parsedQuery; return(BuildPredicate <T>(filterRule, options, out parsedQuery)); }
/// <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, FilterRule filterRule, BuildExpressionOptions options) { string parsedQuery; return(BuildQuery(queryable, filterRule, options, out parsedQuery)); }
/// <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 Expression <Func <T, bool> > BuildQueryExpression <T>(FilterRule filterRule, bool useIndexedProperty = false, string indexedPropertyName = null) { return(BuildExpression <T>(filterRule, useIndexedProperty, indexedPropertyName)); }