/// <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="parsedQuery">The parsed query.</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, out string parsedQuery) { var expression = BuildExpressionLambda <T>(filterRule, options, out parsedQuery); if (expression == null) { return(_ => true); } return(expression.Compile()); }
/// <summary> /// Builds an expression lambda for 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="parsedQuery">The parsed query.</param> /// <param name="options">The options to use when building the expression</param> /// <returns>An expression lambda that implements the filter rule</returns> public static Expression <Func <T, bool> > BuildExpressionLambda <T>(this IFilterRule filterRule, BuildExpressionOptions options, out string parsedQuery) { if (filterRule == null) { parsedQuery = ""; return(null); } var pe = Expression.Parameter(typeof(T), "item"); var expressionTree = BuildExpressionTree(pe, filterRule, options); if (expressionTree == null) { parsedQuery = ""; return(null); } parsedQuery = expressionTree.ToString(); return(Expression.Lambda <Func <T, bool> >(expressionTree, pe)); }
/* * private static Expression Between(Type type, object value, Expression propertyExp, BuildExpressionOptions options, string customizedType = null) * { * var someValue = GetConstants(type, value, true, options); * var nullCheck = GetNullCheckExpression(propertyExp); * Expression exBelow; * Expression exAbove; * * // Handling customized type "anniversarydate" in order to filter on dd/MM formatted dates * if ((propertyExp.Type.Equals(typeof(DateTime)) || propertyExp.Type.Equals(typeof(DateTime?))) && !String.IsNullOrEmpty(customizedType) && customizedType.Equals("anniversarydate")) * { * int startPeriodDay, startPeriodMonth, endPeriodDay, endPeriodMonth; * MethodCallExpression propertyExpToStringMmDd, startPeriodDayToStringMmDd, endPeriodDayToStringMmDd; * * if (propertyExp.Type.Equals(typeof(DateTime?))) * { * startPeriodDay = (int)Expression.Lambda(Expression.Property(Expression.Property(Expression.Convert(someValue[0], propertyExp.Type), "Value"), "Day")).Compile().DynamicInvoke(); * startPeriodMonth = (int)Expression.Lambda(Expression.Property(Expression.Property(Expression.Convert(someValue[0], propertyExp.Type), "Value"), "Month")).Compile().DynamicInvoke(); * * endPeriodDay = (int)Expression.Lambda(Expression.Property(Expression.Property(Expression.Convert(someValue[1], propertyExp.Type), "Value"), "Day")).Compile().DynamicInvoke(); * endPeriodMonth = (int)Expression.Lambda(Expression.Property(Expression.Property(Expression.Convert(someValue[1], propertyExp.Type), "Value"), "Month")).Compile().DynamicInvoke(); * * propertyExpToStringMmDd = Expression.Call(Expression.Property(propertyExp, "Value"), typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * startPeriodDayToStringMmDd = Expression.Call(someValue[0], typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * endPeriodDayToStringMmDd = Expression.Call(someValue[1], typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * } * else * { * startPeriodDay = (int)Expression.Lambda(Expression.Property(Expression.Convert(someValue[0], propertyExp.Type), "Day")).Compile().DynamicInvoke(); * startPeriodMonth = (int)Expression.Lambda(Expression.Property(Expression.Convert(someValue[0], propertyExp.Type), "Month")).Compile().DynamicInvoke(); * * endPeriodDay = (int)Expression.Lambda(Expression.Property(Expression.Convert(someValue[1], propertyExp.Type), "Day")).Compile().DynamicInvoke(); * endPeriodMonth = (int)Expression.Lambda(Expression.Property(Expression.Convert(someValue[1], propertyExp.Type), "Month")).Compile().DynamicInvoke(); * * propertyExpToStringMmDd = Expression.Call(propertyExp, typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * startPeriodDayToStringMmDd = Expression.Call(Expression.Convert(someValue[0], propertyExp.Type), typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * endPeriodDayToStringMmDd = Expression.Call(Expression.Convert(someValue[1], propertyExp.Type), typeof(DateTime).GetMethod("ToString", new[] { typeof(string) }), Expression.Constant("MMdd")); * } * * var propertyExpMmDd = Expression.Call(typeof(int).GetMethod("Parse", new[] { typeof(string) }), propertyExpToStringMmDd); * var startPeriodDayMmDd = Expression.Call(typeof(int).GetMethod("Parse", new[] { typeof(string) }), startPeriodDayToStringMmDd); * var endPeriodDayMmDd = Expression.Call(typeof(int).GetMethod("Parse", new[] { typeof(string) }), endPeriodDayToStringMmDd); * * // Case 1 : end period is on the same year as the start period * if ((endPeriodMonth > startPeriodMonth) || ((endPeriodMonth == startPeriodMonth) && (endPeriodDay >= startPeriodDay))) * { * exBelow = Expression.GreaterThanOrEqual(propertyExpMmDd, startPeriodDayMmDd); * exAbove = Expression.LessThanOrEqual(propertyExpMmDd, endPeriodDayMmDd); * } * // Case 2 : start period and end period are not on the same year * else * { * int startNextYearMmDd = int.Parse(new DateTime(1, 1, 1).ToString("MMdd")); * int endCurrentYearMmDd = int.Parse(new DateTime(1, 12, 31).ToString("MMdd")); * * Expression exGreaterThanStartPeriod = Expression.GreaterThanOrEqual(propertyExpMmDd, startPeriodDayMmDd); * Expression exLessThanEndCurrentYear = Expression.LessThanOrEqual(propertyExpMmDd, Expression.Constant(endCurrentYearMmDd)); * exBelow = Expression.And(exGreaterThanStartPeriod, exLessThanEndCurrentYear); * * Expression exGreaterThanStartNextYear = Expression.GreaterThanOrEqual(propertyExpMmDd, Expression.Constant(startNextYearMmDd)); * Expression exLessThanEndPeriod = Expression.LessThanOrEqual(propertyExpMmDd, endPeriodDayMmDd); * exAbove = Expression.And(exGreaterThanStartNextYear, exLessThanEndPeriod); * * * return Expression.AndAlso(nullCheck, Expression.Or(exBelow, exAbove)); * } * } * else * { * exBelow = Expression.GreaterThanOrEqual(propertyExp, Expression.Convert(someValue[0], propertyExp.Type)); * exAbove = Expression.LessThanOrEqual(propertyExp, Expression.Convert(someValue[1], propertyExp.Type)); * } * * return Expression.AndAlso(nullCheck, Expression.And(exBelow, exAbove)); * } */ #endregion private static Expression NotBetween(Type type, object value, Expression propertyExp, BuildExpressionOptions options) { return(Expression.Not(Between(type, value, propertyExp, options))); }
private static Expression GreaterThan(Type type, object value, Expression propertyExp, BuildExpressionOptions options, Expression rightPropertyExp = null) { if (rightPropertyExp != null) { return(Expression.GreaterThan(propertyExp, rightPropertyExp)); } var someValue = GetConstants(type, value, false, options).First(); Expression exOut = Expression.GreaterThan(propertyExp, Expression.Convert(someValue, propertyExp.Type)); return(exOut); }
private static Expression NotEquals(Type type, object value, Expression propertyExp, BuildExpressionOptions options, string customizedType = null) { return(Expression.Not(Equals(type, value, propertyExp, options, customizedType))); }
private static Expression GreaterThanOrEqual(Type type, object value, Expression propertyExp, BuildExpressionOptions options) { var someValue = GetConstants(type, value, false, options).First(); Expression exOut = Expression.GreaterThanOrEqual(propertyExp, Expression.Convert(someValue, propertyExp.Type)); return(exOut); }
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); }
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, rule.Type); break; case "not_in": expression = NotIn(type, rule.Value, propertyExp, options, rule.Type); break; case "equal": expression = Equals(type, rule.Value, propertyExp, options, rule.Type); break; case "not_equal": expression = NotEquals(type, rule.Value, propertyExp, options, rule.Type); 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; case "is_null_or_empty": expression = IsNullOrEmpty(propertyExp); break; case "is_not_null_and_not_empty": expression = IsNotNullAndNotEmpty(propertyExp); break; default: throw new Exception($"Unknown expression operator: {rule.Operator}"); } return(expression); }
private static Expression NotIn(Type type, string value, Expression propertyExp, BuildExpressionOptions options) { return(Expression.Not(In(type, value, propertyExp, options))); }
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); }
private static Expression LessThan(Type type, string value, Expression propertyExp, BuildExpressionOptions options) { var someValue = GetConstants(type, value, false, options).First(); Expression exOut = Expression.LessThan(propertyExp, Expression.Convert(someValue, propertyExp.Type)); return(exOut); }
private static List <ConstantExpression> GetConstants(Type type, string value, bool isCollection, BuildExpressionOptions options) { if (type == typeof(DateTime) && (options.ParseDatesAsUtc || ParseDatesAsUtc)) { DateTime tDate; if (isCollection) { var vals = value.Split(new[] { ",", "[", "]", "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Where(p => !string.IsNullOrWhiteSpace(p)) .Select( p => DateTime.TryParse(p.Trim(), options.CultureInfo, DateTimeStyles.AdjustToUniversal, out tDate) ? (DateTime?) tDate : null).Select(p => Expression.Constant(p, type)); return(vals.ToList()); } else { return(new List <ConstantExpression>() { Expression.Constant(DateTime.TryParse(value.Trim(), options.CultureInfo, DateTimeStyles.AdjustToUniversal, out tDate) ? (DateTime?) tDate : null) }); } } else { if (isCollection) { var tc = TypeDescriptor.GetConverter(type); if (type == typeof(string)) { var bracketSplit = value.Split(new[] { "[", "]" }, StringSplitOptions.RemoveEmptyEntries); var vals = bracketSplit.SelectMany(v => v.Split(new[] { ",", "\r\n" }, StringSplitOptions.None)) .Select(p => tc.ConvertFromString(null, options.CultureInfo, p.Trim())).Select(p => Expression.Constant(p, type)); return(vals.Distinct().ToList()); } else { var vals = value.Split(new[] { ",", "[", "]", "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Where(p => !string.IsNullOrWhiteSpace(p)) .Select(p => tc.ConvertFromString(null, options.CultureInfo, p.Trim())).Select(p => Expression.Constant(p, type)); return(vals.ToList()); } } else { var tc = TypeDescriptor.GetConverter(type); return(new List <ConstantExpression>() { Expression.Constant(tc.ConvertFromString(null, options.CultureInfo, value.Trim())) }); } } }
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); }
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": case "anniversarydate": 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 Equals(Type type, object value, Expression propertyExp, BuildExpressionOptions options) { Expression someValue = GetConstants(type, value, false, options).First(); Expression exOut; if (type == typeof(string)) { var nullCheck = GetNullCheckExpression(propertyExp); exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); someValue = Expression.Call(someValue, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.AndAlso(nullCheck, Expression.Equal(exOut, someValue)); } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValue, propertyExp.Type)); } return(exOut); }
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)); }
private static Expression In(Type type, object value, Expression propertyExp, BuildExpressionOptions options) { var someValues = GetConstants(type, value, true, options); var nullCheck = GetNullCheckExpression(propertyExp); if (IsGenericList(propertyExp.Type)) { var genericType = propertyExp.Type.GetGenericArguments().First(); var method = propertyExp.Type.GetMethod("Contains", new[] { genericType }); Expression exOut; if (someValues.Count > 1) { exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues[0], genericType)); var counter = 1; while (counter < someValues.Count) { exOut = Expression.Or(exOut, Expression.Call(propertyExp, method, Expression.Convert(someValues[counter], genericType))); counter++; } } else { exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues.First(), genericType)); } return(Expression.AndAlso(nullCheck, exOut)); } else { Expression exOut; if (someValues.Count > 1) { if (type == typeof(string)) { exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); var somevalue = Expression.Call(someValues[0], typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Equal(exOut, somevalue); var counter = 1; while (counter < someValues.Count) { var nextvalue = Expression.Call(someValues[counter], typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Or(exOut, Expression.Equal( Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)), nextvalue)); counter++; } } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValues[0], propertyExp.Type)); var counter = 1; while (counter < someValues.Count) { exOut = Expression.Or(exOut, Expression.Equal(propertyExp, Expression.Convert(someValues[counter], propertyExp.Type))); counter++; } } } else { if (type == typeof(string)) { exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); var somevalue = Expression.Call(someValues.First(), typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Equal(exOut, somevalue); } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValues.First(), propertyExp.Type)); } } return(Expression.AndAlso(nullCheck, exOut)); } }
private static List <ConstantExpression> GetConstants(Type type, object value, bool isCollection, BuildExpressionOptions options) { if (type == typeof(DateTime) && (options.ParseDatesAsUtc || ParseDatesAsUtc)) { DateTime tDate; if (isCollection) { if (!(value is string) && value is IEnumerable list) { var constants = new List <ConstantExpression>(); foreach (object item in list) { var date = DateTime.TryParse(item.ToString().Trim(), options.CultureInfo, DateTimeStyles.AdjustToUniversal, out tDate) ? (DateTime?) tDate : null; constants.Add(Expression.Constant(date, type)); } return(constants); } else { var vals = value.ToString().Split(new[] { ",", "[", "]", "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Where(p => !string.IsNullOrWhiteSpace(p)) .Select( p => DateTime.TryParse(p.Trim(), options.CultureInfo, DateTimeStyles.AdjustToUniversal, out tDate) ? (DateTime?) tDate : null).Select(p => Expression.Constant(p, type)); return(vals.ToList()); } } else { if (value is Array items) { value = items.GetValue(0); } return(new List <ConstantExpression>() { Expression.Constant(DateTime.TryParse(value.ToString().Trim(), options.CultureInfo, DateTimeStyles.AdjustToUniversal, out tDate) ? (DateTime?) tDate : null) }); } } else { if (isCollection) { var tc = TypeDescriptor.GetConverter(type); if (type == typeof(string)) { if (!(value is string) && value is IEnumerable list) { var expressions = new List <ConstantExpression>(); foreach (object item in list) { expressions.Add(Expression.Constant(tc.ConvertFromString(item.ToString()), type)); } return(expressions); } else { var bracketSplit = value.ToString().Split(new[] { "[", "]" }, StringSplitOptions.RemoveEmptyEntries); var vals = bracketSplit.SelectMany(v => v.Split(new[] { ",", "\r\n" }, StringSplitOptions.None)) .Select(p => tc.ConvertFromString(null, options.CultureInfo, p.Trim())).Select(p => Expression.Constant(p, type)); return(vals.Distinct().ToList()); } } else { if (!(value is string) && value is IEnumerable list) { var expressions = new List <ConstantExpression>(); foreach (object item in list) { expressions.Add(Expression.Constant(tc.ConvertFromString(item.ToString()), type)); } return(expressions); } else { var vals = value.ToString().Split(new[] { ",", "[", "]", "\r\n" }, StringSplitOptions.RemoveEmptyEntries) .Where(p => !string.IsNullOrWhiteSpace(p)) .Select(p => tc.ConvertFromString(null, options.CultureInfo, p.Trim())).Select(p => Expression.Constant(p, type)); return(vals.ToList()); } } } else { var tc = TypeDescriptor.GetConverter(type); if (value is Array items) { value = items.GetValue(0); } return(new List <ConstantExpression> { Expression.Constant(tc.ConvertFromString(null, options.CultureInfo, value.ToString().Trim())) }); } } }
/// <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)); }
private static Expression Equals(Type type, object value, Expression propertyExp, BuildExpressionOptions options, string customizedType = null) { Expression someValue = GetConstants(type, value, false, options).First(); Expression exOut; if (type == typeof(string)) { var nullCheck = GetNullCheckExpression(propertyExp); exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); someValue = Expression.Call(someValue, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.AndAlso(nullCheck, Expression.Equal(exOut, someValue)); } // Handling customized type "anniversarydate" in order to filter on dd/MM formatted dates else if ((propertyExp.Type.Equals(typeof(DateTime)) || propertyExp.Type.Equals(typeof(DateTime?))) && !String.IsNullOrEmpty(customizedType) && customizedType.Equals("anniversarydate")) { Expression exDayEqual; Expression exMonthEqual; if (propertyExp.Type.Equals(typeof(DateTime?))) { exDayEqual = Expression.Equal(Expression.Property(Expression.Property(propertyExp, "Value"), "Day"), Expression.Property(Expression.Property(Expression.Convert(someValue, propertyExp.Type), "Value"), "Day")); exMonthEqual = Expression.Equal(Expression.Property(Expression.Property(propertyExp, "Value"), "Month"), Expression.Property(Expression.Property(Expression.Convert(someValue, propertyExp.Type), "Value"), "Month")); } else { exDayEqual = Expression.Equal(Expression.Property(propertyExp, "Day"), Expression.Property(Expression.Convert(someValue, propertyExp.Type), "Day")); exMonthEqual = Expression.Equal(Expression.Property(propertyExp, "Month"), Expression.Property(Expression.Convert(someValue, propertyExp.Type), "Month")); } exOut = Expression.And(exDayEqual, exMonthEqual); } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValue, propertyExp.Type)); } return(exOut); }
/// <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> /// <param name="parsedQuery">The parsed query.</param> /// <returns>Filtered IQueryable.</returns> public static IQueryable <T> BuildQuery <T>(this IQueryable <T> queryable, IFilterRule filterRule, BuildExpressionOptions options, out string parsedQuery) { var expression = BuildExpressionLambda <T>(filterRule, options, out parsedQuery); if (expression == null) { return(queryable); } var whereCallExpression = Expression.Call( typeof(Queryable), "Where", new[] { queryable.ElementType }, queryable.Expression, expression); var filteredResults = queryable.Provider.CreateQuery <T>(whereCallExpression); return(filteredResults); }
private static Expression Between(Type type, object value, Expression propertyExp, BuildExpressionOptions options) { var someValue = GetConstants(type, value, true, options); Expression exBelow = Expression.GreaterThanOrEqual(propertyExp, Expression.Convert(someValue[0], propertyExp.Type)); Expression exAbove = Expression.LessThanOrEqual(propertyExp, Expression.Convert(someValue[1], propertyExp.Type)); return(Expression.And(exBelow, exAbove)); }
/// <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 In(Type type, object value, Expression propertyExp, BuildExpressionOptions options, string customizedType = null) { var someValues = GetConstants(type, value, true, options); var nullCheck = GetNullCheckExpression(propertyExp); if (IsGenericList(propertyExp.Type)) { var genericType = propertyExp.Type.GetGenericArguments().First(); var method = propertyExp.Type.GetMethod("Contains", new[] { genericType }); Expression exOut; if (someValues.Count > 1) { exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues[0], genericType)); var counter = 1; while (counter < someValues.Count) { exOut = Expression.Or(exOut, Expression.Call(propertyExp, method, Expression.Convert(someValues[counter], genericType))); counter++; } } else { exOut = Expression.Call(propertyExp, method, Expression.Convert(someValues.First(), genericType)); } return(Expression.AndAlso(nullCheck, exOut)); } else { Expression exOut; if (someValues.Count > 1) { if (type == typeof(string)) { exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); var somevalue = Expression.Call(someValues[0], typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Equal(exOut, somevalue); var counter = 1; while (counter < someValues.Count) { var nextvalue = Expression.Call(someValues[counter], typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Or(exOut, Expression.Equal( Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)), nextvalue)); counter++; } } // Handling customized type "anniversarydate" in order to filter on dd/MM formatted dates else if ((propertyExp.Type.Equals(typeof(DateTime)) || propertyExp.Type.Equals(typeof(DateTime?))) && !String.IsNullOrEmpty(customizedType) && customizedType.Equals("anniversarydate")) { Expression exDayEqual; Expression exMonthEqual; if (propertyExp.Type.Equals(typeof(DateTime?))) { exDayEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Day"), Expression.Property(Expression.Property(Expression.Convert(someValues[0], propertyExp.Type), "Value"), "Day")); exMonthEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Month"), Expression.Property(Expression.Property(Expression.Convert(someValues[0], propertyExp.Type), "Value"), "Month")); } else { exDayEqual = Expression.Equal(Expression.Property(propertyExp, "Day"), Expression.Property(Expression.Convert(someValues[0], propertyExp.Type), "Day")); exMonthEqual = Expression.Equal(Expression.Property(propertyExp, "Month"), Expression.Property(Expression.Convert(someValues[0], propertyExp.Type), "Month")); } exOut = Expression.And(exDayEqual, exMonthEqual); var counter = 1; while (counter < someValues.Count) { if (propertyExp.Type.Equals(typeof(DateTime?))) { exDayEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Day"), Expression.Property(Expression.Property(Expression.Convert(someValues[counter], propertyExp.Type), "Value"), "Day")); exMonthEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Month"), Expression.Property(Expression.Property(Expression.Convert(someValues[counter], propertyExp.Type), "Value"), "Month")); } else { exDayEqual = Expression.Equal(Expression.Property(propertyExp, "Day"), Expression.Property(Expression.Convert(someValues[counter], propertyExp.Type), "Day")); exMonthEqual = Expression.Equal(Expression.Property(propertyExp, "Month"), Expression.Property(Expression.Convert(someValues[counter], propertyExp.Type), "Month")); } exOut = Expression.Or(exOut, Expression.And(exDayEqual, exMonthEqual)); counter++; } } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValues[0], propertyExp.Type)); var counter = 1; while (counter < someValues.Count) { exOut = Expression.Or(exOut, Expression.Equal(propertyExp, Expression.Convert(someValues[counter], propertyExp.Type))); counter++; } } } else { if (type == typeof(string)) { exOut = Expression.Call(propertyExp, typeof(string).GetMethod("ToLower", Type.EmptyTypes)); var somevalue = Expression.Call(someValues.First(), typeof(string).GetMethod("ToLower", Type.EmptyTypes)); exOut = Expression.Equal(exOut, somevalue); } // Handling customized type "anniversarydate" in order to filter on dd/MM formatted dates else if ((propertyExp.Type.Equals(typeof(DateTime)) || propertyExp.Type.Equals(typeof(DateTime?))) && !String.IsNullOrEmpty(customizedType) && customizedType.Equals("anniversarydate")) { Expression exDayEqual; Expression exMonthEqual; if (propertyExp.Type.Equals(typeof(DateTime?))) { exDayEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Day"), Expression.Property(Expression.Property(Expression.Convert(someValues.First(), propertyExp.Type), "Value"), "Day")); exMonthEqual = Expression.Equal( Expression.Property(Expression.Property(propertyExp, "Value"), "Month"), Expression.Property(Expression.Property(Expression.Convert(someValues.First(), propertyExp.Type), "Value"), "Month")); } else { exDayEqual = Expression.Equal(Expression.Property(propertyExp, "Day"), Expression.Property(Expression.Convert(someValues.First(), propertyExp.Type), "Day")); exMonthEqual = Expression.Equal(Expression.Property(propertyExp, "Month"), Expression.Property(Expression.Convert(someValues.First(), propertyExp.Type), "Month")); } exOut = Expression.And(exDayEqual, exMonthEqual); } else { exOut = Expression.Equal(propertyExp, Expression.Convert(someValues.First(), propertyExp.Type)); } } return(Expression.AndAlso(nullCheck, exOut)); } }
private static Expression NotEquals(Type type, object value, Expression propertyExp, BuildExpressionOptions options, Expression rightPropertyExp = null) { return(Expression.Not(Equals(type, value, propertyExp, options, rightPropertyExp))); }