public override Expression LinqExpression(Dictionary<string, Expression> bindings, LinqDialect dialect) { switch (CompoundPredicateType) { case CompoundPredicateType.And: return GenerateAnd(bindings, Subpredicates, dialect); case CompoundPredicateType.Or: return GenerateOr(bindings, Subpredicates, dialect); case CompoundPredicateType.Not: return Expression.Not(Subpredicates.First().LinqExpression(bindings, dialect)); } return null; }
private Expression _LinqExpression(Expression left, Expression right, LinqDialect dialect) { if (0 != (Options & ComparisonPredicateOptions.CaseInsensitive) && 0 == (dialect & LinqDialect.CaseInsensitiveCollation)) { left = Utils.CallSafe(dialect, left, "ToLower"); if (PredicateOperatorType != PredicateOperatorType.Matches) { right = Utils.CallSafe(dialect, right, "ToLower"); } } var tuple = MakeComparable(left, right, dialect); left = tuple.Item1; right = tuple.Item2; switch (PredicateOperatorType) { case PredicateOperatorType.LessThan: return Expression.LessThan(left, right); case PredicateOperatorType.LessThanOrEqualTo: return Expression.LessThanOrEqual(left, right); case PredicateOperatorType.GreaterThan: return Expression.GreaterThan(left, right); case PredicateOperatorType.GreaterThanOrEqualTo: return Expression.GreaterThanOrEqual(left, right); case PredicateOperatorType.EqualTo: return Expression.Equal(left, right); case PredicateOperatorType.NotEqualTo: return Expression.NotEqual(left, right); case PredicateOperatorType.Matches: var method = typeof(Utils).GetMethod("_Predicate_MatchesRegex", BindingFlags.Public | BindingFlags.Static); return Expression.Call(method, left, right); case PredicateOperatorType.Like: throw new NotImplementedException(); case PredicateOperatorType.BeginsWith: return Utils.CallSafe(dialect, left, "StartsWith", right); case PredicateOperatorType.EndsWith: return Utils.CallSafe(dialect, left, "EndsWith", right); case PredicateOperatorType.In: return Utils.CallSafe(dialect, right, "Contains", left); case PredicateOperatorType.Contains: return Utils.CallSafe(dialect, left, "Contains", right); case PredicateOperatorType.Between: Expression lower, upper; if (right.Type.IsSubclassOf(typeof(Array))) { lower = Expression.ArrayIndex(right, Expression.Constant(0)); upper = Expression.ArrayIndex(right, Expression.Constant(1)); } else { lower = Expression.Property(right, "Item", Expression.Constant(0)); upper = Expression.Property(right, "Item", Expression.Constant(1)); } return Expression.AndAlso(Expression.GreaterThanOrEqual(left, lower), Expression.LessThanOrEqual(left, upper)); } return null; }
private Expression MakeComparableVector(Expression needle, Expression haystack, LinqDialect dialect) { var haystackElementType = Utils.ElementType(haystack.Type); int order = CompareTypePrecision(haystackElementType, needle.Type); if (order != 0) { return Cast(needle, haystackElementType); } else { return needle; } }
private Tuple<Expression, Expression> MakeComparableScalar(Expression left, Expression right, LinqDialect dialect) { var lr = PromoteNullableValueTypes(left, right); var exprs = new Expression[] { lr.Item1, lr.Item2 }; Array.Sort(exprs, CompareExpressionTypePrecision); bool needsFlip = exprs[0] == right; if (exprs[0].Type != exprs[1].Type) { exprs[0] = Cast(exprs[0], exprs[1].Type); } if (needsFlip) { Array.Reverse(exprs); } return new Tuple<Expression, Expression>(exprs[0], exprs[1]); }
private Tuple<Expression, Expression> MakeComparable(Expression left, Expression right, LinqDialect dialect) { if (left.Type == right.Type) { return new Tuple<Expression, Expression>(left, right); } else if (Utils.TypeIsEnumerable(left.Type) && !Utils.TypeIsEnumerable(right.Type)) { return new Tuple<Expression, Expression>(left, MakeComparableVector(right, left, dialect)); } else if (Utils.TypeIsEnumerable(right.Type) && !Utils.TypeIsEnumerable(left.Type)) { return new Tuple<Expression, Expression>(MakeComparableVector(left, right, dialect), right); } else if (IsCastableType(left.Type) && IsCastableType(right.Type)) { return MakeComparableScalar(left, right, dialect); } else { // Hope there is some comparison overload already defined for us return new Tuple<Expression, Expression>(left, right); } }
public override Expression LinqExpression(Dictionary<string, Expression> bindings, LinqDialect dialect) { Expression left = LeftExpression.LinqExpression(bindings, dialect); Expression right = RightExpression.LinqExpression(bindings, dialect); if (ComparisonPredicateModifier != ComparisonPredicateModifier.Direct) { ParameterExpression t = Expression.Parameter(Utils.ElementType(left.Type)); Expression filter = Expression.Lambda(_LinqExpression(t, right, dialect), new ParameterExpression[] { t }); if (ComparisonPredicateModifier == ComparisonPredicateModifier.All) { Expression all = Utils.CallAggregate("All", left, filter); return all; } else if (ComparisonPredicateModifier == ComparisonPredicateModifier.Any) { Expression any = Utils.CallAggregate("Any", left, filter); return any; } else { throw new NotImplementedException($"Unhandled ComparisonPredicateModifier {ComparisonPredicateModifier}"); } } else { return _LinqExpression(left, right, dialect); } }
private Expression GenerateOr(Dictionary<string, Expression> bindings, IEnumerable<Predicate> predicates, LinqDialect dialect) { if (predicates.Count() > 2) { Expression a = predicates.First().LinqExpression(bindings, dialect); Expression b = GenerateOr(bindings, predicates.Skip(1), dialect); return Expression.OrElse(a, b); } else if (predicates.Count() == 2) { Expression a = predicates.First().LinqExpression(bindings, dialect); Expression b = predicates.Last().LinqExpression(bindings, dialect); return Expression.OrElse(a, b); } else if (predicates.Count() == 1) { return predicates.First().LinqExpression(bindings, dialect); } else { return new ConstantPredicate(false).LinqExpression(bindings, dialect); } }
public override Expression LinqExpression(Dictionary<string, Expression> bindings, LinqDialect dialect) { return Expression.Constant(Value); }
public static Expression CallSafe(LinqDialect dialect, Expression target, string methodName, params Expression[] arguments) { if ((dialect & LinqDialect.EntityFramework) == 0) { var defaultTarget = Expression.Default(target.Type); var isNull = Expression.ReferenceEqual(target, defaultTarget); var argTypes = arguments.Select(a => a.Type).ToArray(); var called = Expression.Call(target, target.Type.GetMethod(methodName, argTypes), arguments); var defaultCalled = Expression.Default(called.Type); return Expression.Condition(isNull, defaultCalled, called); } else { var argTypes = arguments.Select(a => a.Type).ToArray(); return Expression.Call(target, target.Type.GetMethod(methodName, argTypes), arguments); } }