private static Expression MakeAggreagationCondition(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent, Type elementType, Expression filter) { var expression = parent; if (filter != null) { var whereMethod = typeof(Enumerable).GetMethods().Single(x => x.Name == nameof(Enumerable.Where) && x.GetParameters().Last().ParameterType.GetGenericArguments().Length == 2); whereMethod = whereMethod.MakeGenericMethod(elementType); expression = Expression.Call(null, whereMethod, expression, filter); } if (node.Operator == FilterOperator.Count) { var method = typeof(Enumerable).GetMethods().Single(x => x.Name == nameof(Enumerable.Count) && x.GetParameters().Length == 1); method = method.MakeGenericMethod(elementType); expression = Expression.Call(null, method, expression); } else { var methodName = node.Operator.ToString(); var selection = Visit(node.Children[1], parameters, reflector, parent) as LambdaExpression; var method = typeof(Enumerable).GetMethods().Single(x => x.Name == methodName && x.GetParameters().Length == 2 && x.GetParameters()[1].ParameterType.GetGenericArguments().Last() == selection.ReturnType); method = method.MakeGenericMethod(elementType); expression = Expression.Call(null, method, expression, selection); } return(expression); }
private FilterNodeModel addFilterInfo(ModelDetailDocumentRequestor mdDR, FilterTypes filterType) { FilterNodeParser fnParser = new FilterNodeParser(mdDR, filterType); FilterNodeModel fnModel = fnParser.Parse(); return(fnModel); }
private static Expression VisitProperty(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { var propertyName = node.PropertyName; var property = Expression.Property(parent, propertyName); if (node.Children == null || !node.Children.Any() || node.Children.SingleOrDefault() == null) { return(property); } return(Visit(node.Children.Single(), parameters, reflector, property)); }
public static LambdaExpression ToExpression(this FilterNodeModel node, IBusinessReflector reflector) { if (node.NodeType != FilterNodeType.Lambda) { throw new Exception(); } var parameters = new Dictionary <string, ParameterExpression>(); var expression = Visit(node, parameters, reflector, null); return(expression as LambdaExpression); }
private static Expression VisitConstant(FilterNodeModel node, Type type) { if (node.Values.Length == 1) { return(Constant(node.Values[0], type)); } var list = Activator.CreateInstance(typeof(List <>).MakeGenericType(type)); var add = list.GetType().GetMethod(nameof(IList.Add)); foreach (var val in node.Values) { add.Invoke(list, new object[] { ConvertValue(val, type) }); } return(Constant(list, list.GetType())); }
private static Expression VisitLambda(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { if (!parameters.TryGetValue(node.ParameterName, out var parameter)) { parameter = Expression.Parameter(reflector.GetType(node.DataType), node.ParameterName); parameters.Add(node.ParameterName, parameter); } else { if (parameter.Type != reflector.GetType(node.DataType)) { throw new Exception("Parameter names are re-used with incompatible types"); } } var body = Visit(node.Children[0], parameters, reflector, parameter); return(Expression.Lambda(body, parameter)); }
private void addFilters(ModelPageCollectorSet modelPageSet, RowModel rm) { ModelDetailDocumentRequestor mdDR = (ModelDetailDocumentRequestor)modelPageSet.Data; FilterNodeModel fnModelAir = addFilterInfo(mdDR, FilterTypes.Air); if (!String.IsNullOrEmpty(fnModelAir.Filters)) { rm.AirFilters = fnModelAir.Filters; rm.AirFilterDimensions = addFilterDimensions(fnModelAir.FilterUrls, FilterTypes.Air); } FilterNodeModel fnModelOil = addFilterInfo(mdDR, FilterTypes.Oil); if (!String.IsNullOrEmpty(fnModelOil.Filters)) { rm.OilFilters = fnModelOil.Filters; rm.OilFilterDimensions = addFilterDimensions(fnModelOil.FilterUrls, FilterTypes.Oil); } FilterNodeModel fnModelFuel = addFilterInfo(mdDR, FilterTypes.Fuel); if (!String.IsNullOrEmpty(fnModelFuel.Filters)) { rm.FuelFilters = fnModelFuel.Filters; rm.FuelFilterDimensions = addFilterDimensions(fnModelFuel.FilterUrls, FilterTypes.Fuel); } FilterNodeModel fnModelInterior = addFilterInfo(mdDR, FilterTypes.Interior); if (!String.IsNullOrEmpty(fnModelInterior.Filters)) { rm.InteriorFilters = fnModelInterior.Filters; rm.InteriorFilterDimensions = addFilterDimensions(fnModelInterior.FilterUrls, FilterTypes.Interior); } FilterNodeModel fnModelOther = addFilterInfo(mdDR, FilterTypes.Other); if (!String.IsNullOrEmpty(fnModelOther.Filters)) { rm.OtherFilters = fnModelOther.Filters; rm.OtherFilterDimensions = addFilterDimensions(fnModelOther.FilterUrls, FilterTypes.Other); } }
private static Expression SimplifyEqualToBool(FilterNodeModel node, List <Expression> children) { if (children[0].Type == typeof(bool) || children[0].Type == typeof(bool?)) { if (node.Operator == null) { return(children[0]); } if (children.Count == 2) { if ((node.Operator == FilterOperator.Equal || node.Operator == FilterOperator.NotEqual) && children[1] is ConstantExpression && (children[1] as ConstantExpression).Value is bool) { if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value) { return(Expression.Not(children[0])); } return(children[0]); } } } return(null); }
private static Expression VisitLogical(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { Expression current = null; foreach (var child in node.Children) { var childExpression = Visit(child, parameters, reflector, parent); if (current == null) { current = childExpression; } else { if (current.Type == typeof(bool) && childExpression.Type == typeof(bool?)) { current = ConvertType(current, typeof(bool?)); } if (current.Type == typeof(bool?) && childExpression.Type == typeof(bool)) { childExpression = ConvertType(childExpression, typeof(bool?)); } switch (node.Operator) { case FilterOperator.And: current = Expression.AndAlso(current, childExpression); break; case FilterOperator.Or: current = Expression.OrElse(current, childExpression); break; default: throw new NotImplementedException(); } } } return(current); }
private static Expression VisitNavigationList(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { var elementType = parent.Type.GetGenericArguments().Single(); LambdaExpression filter = null; if (node.Operator != FilterOperator.IsEmpty && node.Operator != FilterOperator.IsNotEmpty && node.Children[0] != null) { filter = (LambdaExpression)Visit(node.Children[0], parameters, reflector, parent); if (filter.ReturnType == typeof(bool?)) { filter = Expression.Lambda(ConvertType(filter.Body, typeof(bool)), filter.Parameters); } } if (node.Operator == FilterOperator.Count || node.Operator == FilterOperator.Sum || node.Operator == FilterOperator.Average) { return(MakeAggreagationCondition(node, parameters, reflector, parent, elementType, filter)); } var methodName = node.Operator == FilterOperator.All ? nameof(Enumerable.All) : nameof(Enumerable.Any); var negate = node.Operator == FilterOperator.None || node.Operator == FilterOperator.IsEmpty; var parameterCount = filter == null ? 1 : 2; var method = typeof(Enumerable).GetMethods() .Single(x => x.Name == methodName && x.GetParameters().Length == parameterCount); method = method.MakeGenericMethod(elementType); var expression = Expression.Call(method, parameterCount == 1 ? new Expression[] { parent } : new Expression[] { parent, filter }); if (negate) { return(Expression.Not(expression)); } return(expression); }
private static Expression Visit(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { switch (node.NodeType) { case FilterNodeType.Logical: return(VisitLogical(node, parameters, reflector, parent)); case FilterNodeType.Comparison: case FilterNodeType.Arithmetic: return(VisitOperator(node, parameters, reflector, parent)); case FilterNodeType.NavigationList: return(VisitNavigationList(node, parameters, reflector, parent)); case FilterNodeType.Lambda: return(VisitLambda(node, parameters, reflector, parent)); case FilterNodeType.Property: return(VisitProperty(node, parameters, reflector, parent)); default: throw new NotImplementedException(); } }
public static Expression <Func <T, bool> > ToExpression <T>(this FilterNodeModel node, IBusinessReflector reflector) { return(ToExpression(node, reflector) as Expression <Func <T, bool> >); }
private static Expression SimplifyEqualToBool(FilterNodeModel node, List <Expression> children) { var first = children[0]; if (first.Type == typeof(bool?)) { if (children.Count == 1) { if (node.Operator == null) { return(Expression.Property(first, nameof(Nullable <bool> .Value))); } else if (node.Operator == FilterOperator.IsNull) { Expression.Not(Expression.Property(first, nameof(Nullable <bool> .Value))); } else if (node.Operator == FilterOperator.IsNotNull) { Expression.Property(first, nameof(Nullable <bool> .Value)); } } else if (children.Count == 2) { var second = children[1]; if (second is ConstantExpression) { var constant = (second as ConstantExpression); if (constant.Value == null) { first = Expression.Property(first, nameof(Nullable <bool> .HasValue)); if (node.Operator == FilterOperator.Equal) { return(Expression.Not(first)); } return(first); } else if (constant.Value is bool) { first = Expression.Property(first, nameof(Nullable <bool> .Value)); if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value) { return(Expression.Not(first)); } return(first); } } } } if (first.Type == typeof(bool)) { if (node.Operator == null) { return(first); } if (children.Count == 2) { if ((node.Operator == FilterOperator.Equal || node.Operator == FilterOperator.NotEqual) && children[1] is ConstantExpression && (children[1] as ConstantExpression).Value is bool) { if (node.Operator == FilterOperator.Equal ^ (bool)(children[1] as ConstantExpression).Value) { return(Expression.Not(first)); } return(first); } } } return(null); }
private static Expression VisitOperator(FilterNodeModel node, Dictionary <string, ParameterExpression> parameters, IBusinessReflector reflector, Expression parent) { var children = new List <Expression>(node.Children.Length); Type type = null; foreach (var child in node.Children) { if (child.NodeType == FilterNodeType.Constant) { children.Add(VisitConstant(child, type)); } else { children.Add(Visit(child, parameters, reflector, parent)); } if (children.Count == 1) { type = children[0].Type; } } children = UnifyDataTypes(children, null).ToList(); var simplified = SimplifyEqualToBool(node, children); if (simplified != null) { return(simplified); } switch (node.Operator) { case FilterOperator.Contains: case FilterOperator.EndsWith: case FilterOperator.StartsWith: return(MakeStringContainment(node.Operator.Value, children)); case FilterOperator.Equal: case FilterOperator.NotEqual: case FilterOperator.IsNull: case FilterOperator.IsNotNull: return(MakeEquality(node.Operator.Value, children)); case FilterOperator.GreaterThan: case FilterOperator.greaterThanOrEqual: case FilterOperator.LessThan: case FilterOperator.LessThanOrEqual: case FilterOperator.Between: if (children[0].Type == typeof(string)) { return(MakeStringComparison(node.Operator.Value, children)); } return(MakeComparison(node.Operator.Value, children)); case FilterOperator.Abs: return(MakeUnaryArithmetic(node.Operator.Value, children.Single())); case FilterOperator.Add: case FilterOperator.Multiply: return(MakeMultyArithmetic(node.Operator.Value, children)); case FilterOperator.Subtract: case FilterOperator.Divide: case FilterOperator.Power: case FilterOperator.Log: return(MakeBinaryArithmetic(node.Operator.Value, children)); default: throw new NotImplementedException(); } }