private static Expression BuildNavigationExpression(Expression parameter, OperatorComparer comparer, object value, params string[] properties) { Expression resultExpression; Type childType = null; if (properties.Count() > 1) { //build path parameter = Expression.Property(parameter, properties[0]); var isCollection = typeof(IEnumerable).IsAssignableFrom(parameter.Type); //if it´s a collection we later need to use the predicate in the methodexpressioncall Expression childParameter; if (isCollection) { childType = parameter.Type.GetGenericArguments()[0]; childParameter = Expression.Parameter(childType, childType.Name); } else { childParameter = parameter; } //skip current property and get navigation property expression recursivly var innerProperties = properties.Skip(1).ToArray(); var predicate = BuildNavigationExpression(childParameter, comparer, value, innerProperties); resultExpression = isCollection ? BuildSubQuery(parameter, childType, predicate) : predicate; } else { //build final predicate resultExpression = BuildCondition(parameter, properties[0], comparer, value); } return(resultExpression); }
public void TypesWithoutOperators_Throw() { var subject = new OperatorComparer <ComparisonSubject>(); Assert.That(() => subject.Compare(ComparisonSubject.One, ComparisonSubject.Two), Throws.InstanceOf <InvalidOperationException>()); }
private Expression BuildComparsion(Expression left, OperatorComparer comparer, Expression right) { var mask = new List <OperatorComparer> { OperatorComparer.Contains, OperatorComparer.NotContains, OperatorComparer.StartsWith, OperatorComparer.NotStartsWith, OperatorComparer.EndsWith, OperatorComparer.NotEndsWith }; var rangeMask = new List <OperatorComparer> { OperatorComparer.BetweenExclusive, OperatorComparer.BetweenInclusive, OperatorComparer.BetweenHigherInclusive, OperatorComparer.BetweenLowerInclusive }; if (mask.Contains(comparer) && left.Type != typeof(string)) { comparer = OperatorComparer.Equals; } if (rangeMask.Contains(comparer)) { } else if (!mask.Contains(comparer)) { return(Expression.MakeBinary((ExpressionType)comparer, left, Expression.Convert(right, left.Type))); } return(BuildStringCondition(left, comparer, right)); }
private Expression BuildStringCondition(Expression left, OperatorComparer comparer, Expression right) { var isNot = false; var operatorName = Enum.GetName(typeof(OperatorComparer), comparer); if (operatorName.Contains("Not")) { isNot = true; operatorName = operatorName.Replace("Not", ""); } // Single or first, we'll need to debug var compareMethod = typeof(string).GetMethods() .Single(m => m.GetParameters().Any(p => p.ParameterType == typeof(string)) && m.Name.Equals(operatorName) && m.GetParameters().Count() == 1); //we assume ignoreCase, so call ToLower on paramter and memberexpression var toLowerMethod = typeof(string).GetMethods() .Single(m => m.Name.Equals("ToLower") && m.GetParameters().Count() == 0); left = Expression.Call(Expression.Coalesce(left, Expression.Constant(string.Empty)), toLowerMethod); right = Expression.Call(right, toLowerMethod); if (isNot) { return(Expression.Not(Expression.Call(left, compareMethod, right))); } else { return(Expression.Call(left, compareMethod, right)); } }
public static Expression <Func <T, bool> > BuildPredicate <T>(object value, OperatorComparer comparer, params string[] properties) { var parameterExpression = Expression.Parameter(typeof(T), typeof(T).Name); return((Expression <Func <T, bool> >)BuildNavigationExpression(parameterExpression, comparer, value, properties)); }
public void Explore() { IComparer <OperatorsOnly> subject = new OperatorComparer <OperatorsOnly>(Direction.Descending); Assert.That(subject.Compare(new OperatorsOnly(1), new OperatorsOnly(2)), Is.GreaterThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(1)), Is.LessThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(2)), Is.EqualTo(0)); }
private static Expression BuildStringCondition(Expression left, OperatorComparer comparer, Expression right) { var compareMethod = typeof(string).GetMethods().Single(m => m.Name.Equals(Enum.GetName(typeof(OperatorComparer), comparer)) && m.GetParameters().Count() == 1); //we assume ignoreCase, so call ToLower on paramter and memberexpression var toLowerMethod = typeof(string).GetMethods().Single(m => m.Name.Equals("ToLower") && m.GetParameters().Count() == 0); left = Expression.Call(left, toLowerMethod); right = Expression.Call(right, toLowerMethod); return Expression.Call(left, compareMethod, right); }
public void Compare_HonorsDirection() { var subject = new OperatorComparer <OperatorsOnly>(); Assert.That(subject.Compare(new OperatorsOnly(1), new OperatorsOnly(2)), Is.LessThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(1)), Is.GreaterThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(2)), Is.EqualTo(0)); subject = new OperatorComparer <OperatorsOnly>(Direction.Descending); Assert.That(subject.Compare(new OperatorsOnly(1), new OperatorsOnly(2)), Is.GreaterThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(1)), Is.LessThan(0)); Assert.That(subject.Compare(new OperatorsOnly(2), new OperatorsOnly(2)), Is.EqualTo(0)); }
private static Expression BuildComparsion(Expression left, OperatorComparer comparer, Expression right) { var mask = new List<OperatorComparer>{ OperatorComparer.Contains, OperatorComparer.StartsWith, OperatorComparer.EndsWith }; if(mask.Contains(comparer) && left.Type != typeof(string)) { comparer = OperatorComparer.Equals; } if(!mask.Contains(comparer)) { return Expression.MakeBinary((ExpressionType)comparer, left, Expression.Convert(right,left.Type)); } return BuildStringCondition(left, comparer, right); }
/// <summary> /// Used to build Expression for the specifications /// </summary> /// <typeparam name="T"> The Type </typeparam> /// <param name="name"> (the name of the colomn to be filtered)</param> /// <param name="value">(the value to be used for the comparision)</param> /// <param name="comparer">type of comparer (Equal,Contains, NotEqual)</param> /// <returns></returns> public static Expression <Func <T, bool> > BuildPredicate <T>(string name, string value, OperatorComparer comparer) { if (typeof(T).GetProperties().Any(t => t.Name == name)) { Expression <Func <T, bool> > predicateCompiled = ExpressionBuilder.BuildPredicate <T>(value, comparer, name); return(predicateCompiled); } else { throw new Exception("Property Not Found, Please check property name used"); } }
/// <summary> /// Build Search Condition /// </summary> /// <param name="parameter"></param> /// <param name="property"></param> /// <param name="comparer"></param> /// <param name="value"></param> /// <returns></returns> private static Expression BuildCondition(Expression parameter, string property, OperatorComparer comparer, object value) { Expression predicate = null; MemberExpression left = null; var childProperty = parameter.Type.GetProperty(property); if (childProperty == null) { if (property.Split('.').Count() > 1) { var splitPropertyName = property.Split('.'); MemberExpression selector = null; Expression propertyExp = parameter; foreach (var x in splitPropertyName) { selector = Expression.Property(propertyExp, x.Split(' ')[0]); propertyExp = selector; } left = selector; } else { return(null); } } else { left = Expression.Property(parameter, childProperty); } var right = Expression.Constant(value); bool isNumericSearch = long.TryParse(value.ToString(), out long testNumeric); var isNumericField = new string[] { "Int64", "Int32", "Int16", "Byte" }.Contains(left.Type.Name); //if it is numeric, ignore operator, always set to equals, other operator are not performance wise with numeric if (isNumericSearch && isNumericField) { if (left.Type.Name.Equals("Int64")) { right = Expression.Constant(Convert.ToInt64(value)); } else if (left.Type.Name.Equals("Int32")) { right = Expression.Constant(Convert.ToInt32(value)); } else if (left.Type.Name.Equals("Int16") || left.Type.Name.Equals("Byte")) { right = Expression.Constant(Convert.ToInt16(value)); } if (comparer == OperatorComparer.Contains) { predicate = Expression.MakeBinary((ExpressionType)OperatorComparer.Equals, left, right); } else { predicate = Expression.MakeBinary((ExpressionType)comparer, left, right); } } else if (!isNumericSearch && isNumericField) { //Skip building comparison for numeric field when the search string is not numeric return(null); } else if (isNumericSearch && !isNumericField) { // Sometimes the field is not detected as numeric but data is a numeric type right = Expression.Constant(Convert.ToString(value)); predicate = BuildComparsion(left, comparer, right); } else { if (left.Type.Name.Equals("DateTime")) { return(null); } predicate = BuildComparsion(left, comparer, right); } return(MakeLambda(parameter, predicate)); }
/// <summary> /// Build Search Predicate for property /// </summary> /// <typeparam name="T"></typeparam> /// <param name="value">Search Value </param> /// <param name="comparer">Comparision Operator </param> /// <param name="property">Property Name </param> /// <returns></returns> public static Expression <Func <T, bool> > BuildPredicate <T>(object value, OperatorComparer comparer, string property) { var parameterExpression = Expression.Parameter(typeof(T), typeof(T).Name); return((Expression <Func <T, bool> >)BuildCondition(parameterExpression, property, comparer, value)); }
private static Expression BuildCondition(Expression parameter, string property, OperatorComparer comparer, object value) { var childProperty = parameter.Type.GetProperty(property); var left = Expression.Property(parameter, childProperty); var right = Expression.Constant(value); var predicate = BuildComparsion(left, comparer, right); return MakeLambda(parameter, predicate); }
private static Expression <Func <T, bool> > BuildCondition <T>(Expression parameter, string property, OperatorComparer comparer, object value) { var childProperty = parameter.Type.GetProperty(property); var left = Expression.Property(parameter, childProperty); var right = Expression.Constant(value.TryCast(left.Type)); var predicate = BuildComparsion(left, comparer, right); return(MakeLambda <T>(parameter, predicate)); }
public void Ctor_SetsDirection() { var subject = new OperatorComparer <OperatorsOnly>(Direction.Descending); Assert.That(subject.SortDirection, Is.EqualTo(Direction.Descending)); }
public void Ctor_DefaultsToAscending() { var subject = new OperatorComparer <OperatorsOnly>(); Assert.That(subject.SortDirection, Is.EqualTo(Direction.Ascending)); }
public int Compare(string x, string y) { return(OperatorComparer.SCompare(x, y)); }