Ejemplo n.º 1
0
        public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index)
        {
            if (whereClause.Predicate is BinaryExpression expression)
            {
                VisitBinaryExpression(expression, RootExpression);
            }
            else
            {
                if (whereClause.Predicate is SubQueryExpression subQuery)
                {
                    ExplainAndExpression andExpression;

                    if (!RootExpression.MultipleWhereClauses)
                    {
                        andExpression = new ExplainAndExpression();
                        RootExpression.Elements.Add(andExpression);
                    }
                    else // multiple where clauses are joined by AND
                    {
                        andExpression = RootExpression.Elements[0];
                    }

                    var leaf = new LeafExpression();
                    andExpression.Elements.Add(leaf);

                    VisitContainsExpression(subQuery, leaf);
                }
                else if (whereClause.Predicate is MethodCallExpression call)
                {
                    ExplainAndExpression andExpression;

                    if (!RootExpression.MultipleWhereClauses)
                    {
                        andExpression = new ExplainAndExpression();
                        RootExpression.Elements.Add(andExpression);
                    }
                    else // multiple where clauses are joined by AND
                    {
                        andExpression = RootExpression.Elements[0];
                    }

                    var leaf = CallToLeafExpression(call);
                    andExpression.Elements.Add(leaf);
                }
                else if (whereClause.Predicate.NodeType != ExpressionType.Constant)
                {
                    throw new NotSupportedException("query too complex");
                }
            }


            RootExpression.MultipleWhereClauses = true;

            base.VisitWhereClause(whereClause, queryModel, index);
        }
Ejemplo n.º 2
0
        private void VisitAndExpression(BinaryExpression binaryExpression, ExplainAndExpression andExpression)
        {
            if (IsLeafExpression(binaryExpression.Left))
            {
                andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Left));
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso)
            {
                VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression);
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.Extension)
            {
                if (binaryExpression.Left is SubQueryExpression subQuery)
                {
                    var leaf = new LeafExpression();
                    andExpression.Elements.Add(leaf);
                    VisitContainsExpression(subQuery, leaf);
                }
            }
            else if (binaryExpression.Left is MethodCallExpression callExpression)
            {
                andExpression.Elements.Add(CallToLeafExpression(callExpression));
            }
            else
            {
                throw new NotSupportedException("ExplainExpression too complex");
            }

            if (IsLeafExpression(binaryExpression.Right))
            {
                andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Right));
            }
            else if (binaryExpression.Right.NodeType == ExpressionType.Extension)
            {
                if (binaryExpression.Right is SubQueryExpression subQuery)
                {
                    var leaf = new LeafExpression();
                    andExpression.Elements.Add(leaf);
                    VisitContainsExpression(subQuery, leaf);
                }
            }
            else if (binaryExpression.Right is MethodCallExpression callExpression)
            {
                andExpression.Elements.Add(CallToLeafExpression(callExpression));
            }
            else
            {
                throw new NotSupportedException("ExplainExpression too complex");
            }
        }
Ejemplo n.º 3
0
        private static LeafExpression CallToLeafExpression(MethodCallExpression call)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(call.Method.Name);
            sb.Append("(");

            foreach (var argument in call.Arguments)
            {
                if (argument is ConstantExpression constant)
                {
                    sb.Append(constant.Value);
                }
            }

            sb.Append(")");


            var leaf = new LeafExpression {
                MethodCall = sb.ToString()
            };

            return(leaf);
        }
Ejemplo n.º 4
0
        //TODO add unit test for OR expression with Contains
        /// <summary>
        ///     OR expression can be present only at root level
        /// </summary>
        /// <param name="binaryExpression"></param>
        /// <param name="rootExpression"></param>
        private void VisitOrExpression(BinaryExpression binaryExpression, ExplainOrExpression rootExpression)
        {
            // visit left part
            if (IsLeafExpression(binaryExpression.Left))
            {
                var andExpression = new ExplainAndExpression();
                rootExpression.Elements.Add(andExpression);

                andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Left));
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso)
            {
                var andExpression = new ExplainAndExpression();
                rootExpression.Elements.Add(andExpression);
                VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression);
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.Extension)
            {
                if (binaryExpression.Left is SubQueryExpression subQuery)
                {
                    ExplainAndExpression andExpression;

                    if (!rootExpression.MultipleWhereClauses)
                    {
                        andExpression = new ExplainAndExpression();
                        rootExpression.Elements.Add(andExpression);
                    }
                    else // multiple where clauses are joined by AND
                    {
                        andExpression = rootExpression.Elements[0];
                    }


                    var leaf = new LeafExpression();
                    andExpression.Elements.Add(leaf);

                    VisitContainsExpression(subQuery, leaf);
                }
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.OrElse)
            {
                VisitOrExpression((BinaryExpression)binaryExpression.Left, rootExpression);
            }
            else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso)
            {
                var andExpression = new ExplainAndExpression();
                rootExpression.Elements.Add(andExpression);
                VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression);
            }
            else if (binaryExpression.Left is MethodCallExpression call)
            {
                ExplainAndExpression andExpression;

                if (!RootExpression.MultipleWhereClauses)
                {
                    andExpression = new ExplainAndExpression();
                    RootExpression.Elements.Add(andExpression);
                }
                else // multiple where clauses are joined by AND
                {
                    andExpression = RootExpression.Elements[0];
                }

                var leaf = CallToLeafExpression(call);
                andExpression.Elements.Add(leaf);
            }
            else
            {
                throw new NotSupportedException("ExplainExpression too complex");
            }

            // visit right part
            if (IsLeafExpression(binaryExpression.Right))
            {
                var andExpression = new ExplainAndExpression();
                rootExpression.Elements.Add(andExpression);

                andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Right));
            }
            else if (binaryExpression.Right.NodeType == ExpressionType.Extension)
            {
                if (binaryExpression.Right is SubQueryExpression subQuery)
                {
                    var andExpression = new ExplainAndExpression();
                    rootExpression.Elements.Add(andExpression);

                    if (rootExpression.MultipleWhereClauses)
                    {
                        throw new NotSupportedException(
                                  "Multiple where clauses can be used only with simple expressions");
                    }


                    var leaf = new LeafExpression();
                    andExpression.Elements.Add(leaf);
                    VisitContainsExpression(subQuery, leaf);
                }
            }
            else if (binaryExpression.Right.NodeType == ExpressionType.OrElse)
            {
                VisitOrExpression((BinaryExpression)binaryExpression.Right, rootExpression);
            }
            else if (binaryExpression.Right.NodeType == ExpressionType.AndAlso)
            {
                var andExpression = new ExplainAndExpression();
                rootExpression.Elements.Add(andExpression);
                VisitAndExpression((BinaryExpression)binaryExpression.Right, andExpression);
            }
            else if (binaryExpression.Right is MethodCallExpression call)
            {
                ExplainAndExpression andExpression;

                if (!RootExpression.MultipleWhereClauses)
                {
                    andExpression = new ExplainAndExpression();
                    RootExpression.Elements.Add(andExpression);
                }
                else // multiple where clauses are joined by AND
                {
                    andExpression = RootExpression.Elements[0];
                }

                var leaf = CallToLeafExpression(call);
                andExpression.Elements.Add(leaf);
            }
            else
            {
                throw new NotSupportedException("ExplainExpression too complex");
            }
        }
Ejemplo n.º 5
0
        private void VisitContainsExpression(SubQueryExpression subQuery, LeafExpression leaf)
        {
            if (subQuery.QueryModel.ResultOperators.Count != 1)
            {
                throw new NotSupportedException("Only Contains extension is supported");
            }

            var contains = subQuery.QueryModel.ResultOperators[0] as ContainsResultOperator;

            // process collection.Contains(x=>x.Member)
            if (contains?.Item is MemberExpression item)
            {
                var select = subQuery.QueryModel?.SelectClause.Selector as QuerySourceReferenceExpression;

                leaf.MemberName = item.Member.Name;

                if (select?.ReferencedQuerySource is MainFromClause from)
                {
                    var expression = from.FromExpression as ConstantExpression;

                    if (expression?.Value is IEnumerable values)
                    {
                        leaf.Operator = QueryOperator.In;

                        foreach (var value in values)
                        {
                            leaf.InValues.Add(value);
                        }

                        return;
                    }
                }
            }
            // process x=>x.VectorMember.Contains(value)
            else
            {
                var value = contains?.Item;

                if (value != null)
                {
                    var select = subQuery.QueryModel?.SelectClause.Selector as QuerySourceReferenceExpression;
                    var from   = select?.ReferencedQuerySource as MainFromClause;


                    if (from?.FromExpression is MemberExpression expression)
                    {
                        // the member must not be a scalar type. A string is a vector of chars but still considered a scalar in this context
                        var isVector = typeof(IEnumerable).IsAssignableFrom(expression.Type) &&
                                       !typeof(string).IsAssignableFrom(expression.Type);

                        if (!isVector)
                        {
                            throw new NotSupportedException("Trying to use Contains extension on a scalar member");
                        }


                        if (value is ConstantExpression valueExpession)
                        {
                            leaf.Operator = QueryOperator.In;

                            leaf.InValues.Add(valueExpession.Value);

                            return;
                        }
                    }
                }
            }

            throw new NotSupportedException("Only Contains extension is supported");
        }