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); }
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"); } }
private void VisitBinaryExpression(BinaryExpression binaryExpression, ExplainOrExpression rootExpression) { // manage AND expressions if (binaryExpression.NodeType == ExpressionType.AndAlso) { var andExpression = new ExplainAndExpression(); rootExpression.Elements.Add(andExpression); VisitAndExpression(binaryExpression, andExpression); } // manage OR expressions else if (binaryExpression.NodeType == ExpressionType.OrElse) { VisitOrExpression(binaryExpression, rootExpression); } // manage simple expressions like a > 10 else if (IsLeafExpression(binaryExpression)) { ExplainAndExpression andExpression; if (!rootExpression.MultipleWhereClauses) { andExpression = new ExplainAndExpression(); rootExpression.Elements.Add(andExpression); } else // if multiple where clauses consider them as expressions linked by AND { andExpression = rootExpression.Elements[0]; } andExpression.Elements.Add(VisitLeafExpression(binaryExpression)); } else { throw new NotSupportedException("ExplainExpression too complex"); } }
//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"); } }