Ejemplo n.º 1
0
 internal static (object?value, string?error) TryEvaluateExpression(this IQueryElement expr, EvaluationContext context)
 {
     if (!context.TryGetValue(expr, out var info))
     {
         if (TryEvaluateExpressionInternal(expr, context, out var result, out var errorMessage))
         {
             context.Register(expr, result);
         }
         else
         {
             context.RegisterError(expr, errorMessage);
         }
         return(result, errorMessage);
     }
Ejemplo n.º 2
0
 public static bool CanBeEvaluated(this IQueryElement expr, EvaluationContext context)
 {
     return(expr.TryEvaluateExpression(context, out _, out _));
 }
Ejemplo n.º 3
0
 public static bool TryEvaluateExpression(this IQueryElement expr, EvaluationContext context, out object?result)
 {
     (result, var error) = expr.TryEvaluateExpression(context);
     return(error == null);
 }
Ejemplo n.º 4
0
        static bool TryEvaluateExpressionInternal(this IQueryElement expr, EvaluationContext context, out object?result, out string?errorMessage)
        {
            result       = null;
            errorMessage = null;
            switch (expr.ElementType)
            {
            case QueryElementType.SqlValue: result = ((SqlValue)expr).Value; return(true);

            case QueryElementType.SqlParameter:
            {
                var sqlParameter = (SqlParameter)expr;

                if (context.ParameterValues == null)
                {
                    return(false);
                }

                result = sqlParameter.GetParameterValue(context.ParameterValues).Value;
                return(true);
            }

            case QueryElementType.IsNullPredicate:
            {
                var isNullPredicate = (SqlPredicate.IsNull)expr;
                if (!isNullPredicate.Expr1.TryEvaluateExpression(context, out var value))
                {
                    return(false);
                }
                result = isNullPredicate.IsNot == (value != null);
                return(true);
            }

            case QueryElementType.ExprExprPredicate:
            {
                var exprExpr = (SqlPredicate.ExprExpr)expr;
                var reduced  = exprExpr.Reduce(context);
                if (!ReferenceEquals(reduced, expr))
                {
                    return(TryEvaluateExpression(reduced, context, out result, out errorMessage));
                }

                if (!exprExpr.Expr1.TryEvaluateExpression(context, out var value1) ||
                    !exprExpr.Expr2.TryEvaluateExpression(context, out var value2))
                {
                    return(false);
                }

                switch (exprExpr.Operator)
                {
                case SqlPredicate.Operator.Equal:
                {
                    if (value1 == null)
                    {
                        result = value2 == null;
                    }
                    else
                    {
                        result = (value2 != null) && value1.Equals(value2);
                    }
                    break;
                }

                case SqlPredicate.Operator.NotEqual:
                {
                    if (value1 == null)
                    {
                        result = value2 != null;
                    }
                    else
                    {
                        result = value2 == null || !value1.Equals(value2);
                    }
                    break;
                }

                default:
                {
                    if (!(value1 is IComparable comp1) || !(value2 is IComparable comp2))
                    {
                        result = false;
                        return(true);
                    }

                    switch (exprExpr.Operator)
                    {
                    case SqlPredicate.Operator.Greater:
                        result = comp1.CompareTo(comp2) > 0;
                        break;

                    case SqlPredicate.Operator.GreaterOrEqual:
                        result = comp1.CompareTo(comp2) >= 0;
                        break;

                    case SqlPredicate.Operator.NotGreater:
                        result = !(comp1.CompareTo(comp2) > 0);
                        break;

                    case SqlPredicate.Operator.Less:
                        result = comp1.CompareTo(comp2) < 0;
                        break;

                    case SqlPredicate.Operator.LessOrEqual:
                        result = comp1.CompareTo(comp2) <= 0;
                        break;

                    case SqlPredicate.Operator.NotLess:
                        result = !(comp1.CompareTo(comp2) < 0);
                        break;

                    default:
                        return(false);
                    }
                    break;
                }
                }

                return(true);
            }

            case QueryElementType.IsTruePredicate:
            {
                var isTruePredicate = (SqlPredicate.IsTrue)expr;
                if (!isTruePredicate.Expr1.TryEvaluateExpression(context, out var value))
                {
                    return(false);
                }

                if (value == null)
                {
                    result = false;
                    return(true);
                }

                if (value is bool boolValue)
                {
                    result = boolValue != isTruePredicate.IsNot;
                    return(true);
                }
                return(false);
            }

            case QueryElementType.SqlBinaryExpression:
            {
                var binary = (SqlBinaryExpression)expr;
                if (!binary.Expr1.TryEvaluateExpression(context, out var leftEvaluated, out errorMessage))
                {
                    return(false);
                }
                if (!binary.Expr2.TryEvaluateExpression(context, out var rightEvaluated, out errorMessage))
                {
                    return(false);
                }
                dynamic?left  = leftEvaluated;
                dynamic?right = rightEvaluated;
                if (left == null || right == null)
                {
                    return(true);
                }
                switch (binary.Operation)
                {
                case "+": result = left + right; break;

                case "-": result = left - right; break;

                case "*": result = left * right; break;

                case "/": result = left / right; break;

                case "%": result = left % right; break;

                case "^": result = left ^ right; break;

                case "&": result = left & right; break;

                case "<": result = left < right; break;

                case ">": result = left > right; break;

                case "<=": result = left <= right; break;

                case ">=": result = left >= right; break;

                default:
                    errorMessage = $"Unknown binary operation '{binary.Operation}'.";
                    return(false);
                }

                return(true);
            }

            case QueryElementType.SqlFunction:
            {
                var function = (SqlFunction)expr;

                switch (function.Name)
                {
                case "CASE":
                {
                    if (function.Parameters.Length != 3)
                    {
                        errorMessage = "CASE function expected to have 3 parameters.";
                        return(false);
                    }

                    if (!function.Parameters[0]
                        .TryEvaluateExpression(context, out var cond, out errorMessage))
                    {
                        return(false);
                    }

                    if (!(cond is bool))
                    {
                        errorMessage =
                            $"CASE function expected to have boolean condition (was: {cond?.GetType()}).";
                        return(false);
                    }

                    if ((bool)cond !)
                    {
                        return(function.Parameters[1]
                               .TryEvaluateExpression(context, out result, out errorMessage));
                    }
                    else
                    {
                        return(function.Parameters[2]
                               .TryEvaluateExpression(context, out result, out errorMessage));
                    }
                }

                case "Length":
                {
                    if (function.Parameters[0]
                        .TryEvaluateExpression(context, out var strValue, out errorMessage))
                    {
                        if (strValue == null)
                        {
                            return(true);
                        }
                        if (strValue is string str)
                        {
                            result = str.Length;
                            return(true);
                        }
                    }

                    return(false);
                }

                case "$ToLower$":
                {
                    if (function.Parameters[0]
                        .TryEvaluateExpression(context, out var strValue, out errorMessage))
                    {
                        if (strValue == null)
                        {
                            return(true);
                        }
                        if (strValue is string str)
                        {
                            result = str.ToLower(CultureInfo.InvariantCulture);
                            return(true);
                        }
                    }

                    return(false);
                }

                case "$ToUpper$":
                {
                    if (function.Parameters[0]
                        .TryEvaluateExpression(context, out var strValue, out errorMessage))
                    {
                        if (strValue == null)
                        {
                            return(true);
                        }
                        if (strValue is string str)
                        {
                            result = str.ToUpper(CultureInfo.InvariantCulture);
                            return(true);
                        }
                    }

                    return(false);
                }

                default:
                    errorMessage = $"Unknown function '{function.Name}'.";
                    return(false);
                }
            }

            default:
            {
                return(false);
            }
            }
        }
Ejemplo n.º 5
0
        public static EvaluationContext.EvaluationInfo TryEvaluateExpression(this IQueryElement expr, EvaluationContext context)
        {
            if (!context.TryGetValue(expr, out var info))
            {
                var canBeEvaluated =
                    TryEvaluateExpressionInternal(expr, context, out var result, out var errorMessage);
                info = new EvaluationContext.EvaluationInfo(canBeEvaluated, result, errorMessage);
                context.Register(expr, info);
                return(info);
            }

            return(info !);
        }
Ejemplo n.º 6
0
            public ISqlPredicate Reduce(EvaluationContext context)
            {
                if (Operator == Operator.Equal || Operator == Operator.NotEqual)
                {
                    if (Expr1.TryEvaluateExpression(context, out var value1))
                    {
                        if (value1 == null)
                        {
                            return(new IsNull(Expr2, Operator != Operator.Equal));
                        }
                    }
                    else if (Expr2.TryEvaluateExpression(context, out var value2))
                    {
                        if (value2 == null)
                        {
                            return(new IsNull(Expr1, Operator != Operator.Equal));
                        }
                    }
                }

                if (WithNull == null)
                {
                    return(this);
                }

                var canBeNull_1 = Expr1.ShouldCheckForNull();
                var canBeNull_2 = Expr2.ShouldCheckForNull();

                var isInverted = !WithNull.Value;

                var predicate = new ExprExpr(Expr1, Operator, Expr2, null);

                if (!canBeNull_1 && !canBeNull_2)
                {
                    return(predicate);
                }

                var search = new SqlSearchCondition();

                if (Expr1.CanBeEvaluated(context))
                {
                    if (!Expr2.CanBeEvaluated(context))
                    {
                        if (canBeNull_2)
                        {
                            if (isInverted)
                            {
                                if (Operator != Operator.Equal)
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                            }
                            else if (Operator == Operator.NotEqual)
                            {
                                search.Conditions.Add(new SqlCondition(false, predicate, true));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                            }
                        }
                    }
                }
                else if (Expr2.CanBeEvaluated(context))
                {
                    if (canBeNull_1)
                    {
                        if (isInverted)
                        {
                            if (Operator != Operator.Equal)
                            {
                                search.Conditions.Add(new SqlCondition(false, predicate, true));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                            }
                        }
                        else if (Operator == Operator.NotEqual)
                        {
                            search.Conditions.Add(new SqlCondition(false, predicate, true));
                            search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                        }
                    }
                }
                else
                {
                    if (canBeNull_2)
                    {
                        if (canBeNull_1)
                        {
                            if (isInverted)
                            {
                                if (Operator == Operator.Equal)
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));

                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, true), true));

                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, true), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                                else
                                if (Operator == Operator.NotEqual)
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));

                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, true), true));

                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, true), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                                else
                                if (Operator == Operator.LessOrEqual || Operator == Operator.GreaterOrEqual)
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), true));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                                else if (Operator == Operator.NotEqual)
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                                else
                                {
                                    search.Conditions.Add(new SqlCondition(false, predicate, true));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                    search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                                }
                            }
                            else if (Operator == Operator.Equal)
                            {
                                search.Conditions.Add(new SqlCondition(false, predicate, true));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                            }
                            else if (Operator == Operator.NotEqual)
                            {
                                search.Conditions.Add(new SqlCondition(false, predicate, true));

                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, true), true));

                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, true), false));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                            }
                        }
                        else
                        if (isInverted)
                        {
                            search.Conditions.Add(new SqlCondition(false, predicate, true));
                            search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                        }
                    }
                    else
                    {
                        if (canBeNull_1)
                        {
                            if (isInverted)
                            {
                                search.Conditions.Add(new SqlCondition(false, predicate, true));
                                search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                            }
                        }
                        else
                        {
                            search.Conditions.Add(new SqlCondition(false, predicate, true));
                            search.Conditions.Add(new SqlCondition(false, new IsNull(Expr1, false), false));
                            search.Conditions.Add(new SqlCondition(false, new IsNull(Expr2, false), false));
                        }
                    }
                }


                if (search.Conditions.Count == 0)
                {
                    return(predicate);
                }

                return(search);
            }