private AqlExpression VisitUnary(UnaryExpression node)
        {
            AqlExpression operand = Visit(node.Operand);

            switch (node.NodeType)
            {
            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
                // ignore the cast, because AQL does not support casts
                return(operand);

            case ExpressionType.UnaryPlus:
                return(new AqlUnaryOperator(
                           operand,
                           AqlExpressionType.UnaryPlus
                           ));

            case ExpressionType.Negate:
            case ExpressionType.NegateChecked:
                return(new AqlUnaryOperator(
                           operand,
                           AqlExpressionType.UnaryMinus
                           ));

            case ExpressionType.Not:
                return(new AqlUnaryOperator(
                           operand,
                           AqlExpressionType.Not
                           ));
            }

            throw new AqlParsingException(
                      $"Cannot parse node {node.NodeType} - not implemented"
                      );
        }
        public AqlBinaryOperator(
            AqlExpression left,
            AqlExpression right,
            AqlExpressionType type
            )
        {
            if (
                type != AqlExpressionType.Add &&
                type != AqlExpressionType.Subtract &&
                type != AqlExpressionType.Multiply &&
                type != AqlExpressionType.Divide &&
                type != AqlExpressionType.Modulo &&
                type != AqlExpressionType.Equal &&
                type != AqlExpressionType.NotEqual &&
                type != AqlExpressionType.GreaterThan &&
                type != AqlExpressionType.GreaterThanOrEqual &&
                type != AqlExpressionType.LessThan &&
                type != AqlExpressionType.LessThanOrEqual &&
                type != AqlExpressionType.And &&
                type != AqlExpressionType.Or
                )
            {
                throw new ArgumentException(
                          $"Provided expression type {type} is not a binary operation"
                          );
            }

            ExpressionType = type;
            Left           = left;
            Right          = right;
            Parameters     = new ReadOnlyCollection <string>(
                left.Parameters.Union(right.Parameters).ToList()
                );
        }
        /// <summary>
        /// Parse an expression tree directly, without the lambda wrapper
        /// </summary>
        public AqlExpression ParseExpression(Expression expression)
        {
            // simplify parts that have no parameters
            Expression demungified = demungifier.Demungify(expression);

            // convert to AQL expression
            AqlExpression converted = converter.Convert(demungified);

            return(converted);
        }
Ejemplo n.º 4
0
        public AqlJsonObjectExpression Add(string key, AqlExpression expression)
        {
            if (expression.Parameters.Count > 0)
            {
                parameters = new ReadOnlyCollection <string>(
                    parameters.Union(expression.Parameters).ToList()
                    );
            }

            Items.Add(key, expression);
            return(this);
        }
        public AqlMemberAccessExpression(
            AqlExpression subject,
            AqlExpression member
            )
        {
            Subject = subject;
            Member  = member;

            Parameters = new ReadOnlyCollection <string>(
                Subject.Parameters.Union(Member.Parameters).ToList()
                );
        }
        public AqlUnaryOperator(AqlExpression operand, AqlExpressionType type)
        {
            if (
                type != AqlExpressionType.UnaryPlus &&
                type != AqlExpressionType.UnaryMinus &&
                type != AqlExpressionType.Not
                )
            {
                throw new ArgumentException(
                          $"Provided expression type {type} is not an unary operation"
                          );
            }

            ExpressionType = type;
            Operand        = operand;
        }
        private AqlExpression VisitCall(MethodCallExpression node)
        {
            AqlExpression        instance = Visit(node.Object);
            List <AqlExpression> args     = node.Arguments
                                            .Select(Visit)
                                            .ToList();

            // === handle arango functions ===

            ArangoFunctionAttribute attribute = node.Method
                                                .GetCustomAttribute <ArangoFunctionAttribute>();

            if (attribute != null)
            {
                return(new AqlFunctionExpression(attribute, args));
            }

            // === intercept indexing on JSON objects and arrays ===

            if (possibleIndexerMethods.Contains(node.Method) &&
                args.Count == 1)
            {
                return(new AqlMemberAccessExpression(
                           instance,
                           args[0]
                           ));
            }

            // === handle JSON object construction ===

            // if we call .Add on a JsonObject instance
            if (node.Object?.Type == typeof(JsonObject) &&
                node.Method.Name == "Add")
            {
                // start construction
                if (instance is AqlConstantExpression constant)
                {
                    instance = new AqlJsonObjectExpression(constant.Value);
                }

                // continue construction
                if (instance is AqlJsonObjectExpression obj)
                {
                    return(obj.CallAddViaArgs(args));
                }
            }

            // === handle JSON array construction ===

            // if we call .Add on a JsonArray instance
            if (node.Object?.Type == typeof(JsonArray) &&
                node.Method.Name == "Add")
            {
                // start construction
                if (instance is AqlConstantExpression constant)
                {
                    instance = new AqlJsonArrayExpression(constant.Value);
                }

                // continue construction
                if (instance is AqlJsonArrayExpression arr)
                {
                    return(arr.CallAddViaArgs(args));
                }
            }

            // === expression is invalid ===

            throw new AqlParsingException(
                      $"Expression uses parameters in method '{node.Method}'" +
                      ", but this method cannot be translated to AQL"
                      );
        }
        private AqlExpression VisitBinary(BinaryExpression node)
        {
            AqlExpression left  = Visit(node.Left);
            AqlExpression right = Visit(node.Right);

            switch (node.NodeType)
            {
            case ExpressionType.Add:
            case ExpressionType.AddChecked:
                if (node.Left.Type == typeof(string) ||
                    node.Right.Type == typeof(string))
                {
                    return(new AqlFunctionExpression(
                               "CONCAT", left, right
                               ));
                }
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Add
                           ));

            case ExpressionType.Subtract:
            case ExpressionType.SubtractChecked:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Subtract
                           ));

            case ExpressionType.Multiply:
            case ExpressionType.MultiplyChecked:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Multiply
                           ));

            case ExpressionType.Divide:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Divide
                           ));

            case ExpressionType.Modulo:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Modulo
                           ));

            case ExpressionType.Equal:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Equal
                           ));

            case ExpressionType.NotEqual:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.NotEqual
                           ));

            case ExpressionType.GreaterThan:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.GreaterThan
                           ));

            case ExpressionType.GreaterThanOrEqual:
                return(new AqlBinaryOperator(
                           left, right,
                           AqlExpressionType.GreaterThanOrEqual
                           ));

            case ExpressionType.LessThan:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.LessThan
                           ));

            case ExpressionType.LessThanOrEqual:
                return(new AqlBinaryOperator(
                           left, right,
                           AqlExpressionType.LessThanOrEqual
                           ));

            case ExpressionType.And:
            case ExpressionType.AndAlso:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.And
                           ));

            case ExpressionType.Or:
            case ExpressionType.OrElse:
                return(new AqlBinaryOperator(
                           left, right, AqlExpressionType.Or
                           ));
            }

            throw new AqlParsingException(
                      $"Cannot convert node {node.NodeType} - not implemented"
                      );
        }