private static Collection VisitMethodCall()

in Microsoft.Azure.Cosmos/src/Linq/ExpressionToSQL.cs [1157:1349]


        private static Collection VisitMethodCall(MethodCallExpression inputExpression, TranslationContext context)
        {
            context.PushMethod(inputExpression);

            Type declaringType = inputExpression.Method.DeclaringType;

            if ((declaringType != typeof(Queryable) 
                && declaringType != typeof(Enumerable) /*LINQ Methods*/
                && declaringType != typeof(CosmosLinqExtensions) /*OrderByRank*/)
                || !inputExpression.Method.IsStatic /*Other extansion method*/)
            {
                throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.OnlyLINQMethodsAreSupported, inputExpression.Method.Name));
            }

            Type returnType = inputExpression.Method.ReturnType;
            Type returnElementType = TypeSystem.GetElementType(returnType);

            if (inputExpression.Object != null)
            {
                throw new DocumentQueryException(ClientResources.ExpectedMethodCallsMethods);
            }

            Expression inputCollection = inputExpression.Arguments[0]; // all these methods are static extension methods, so argument[0] is the collection

            Type inputElementType = TypeSystem.GetElementType(inputCollection.Type);
            Collection collection = ExpressionToSql.Translate(inputCollection, context);

            context.PushCollection(collection);

            Collection result = new Collection(inputExpression.Method.Name);
            bool shouldBeOnNewQuery = context.CurrentQuery.ShouldBeOnNewQuery(inputExpression.Method.Name, inputExpression.Arguments.Count);
            context.PushSubqueryBinding(shouldBeOnNewQuery);

            if (context.LastExpressionIsGroupBy)
            {
                throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, "Group By cannot be followed by other methods"));
            }

            switch (inputExpression.Method.Name)
            {
                case LinqMethods.Any:
                    {
                        result = new Collection(string.Empty);

                        if (inputExpression.Arguments.Count == 2)
                        {
                            // Any is translated to an SELECT VALUE EXISTS() where Any operation itself is treated as a Where.
                            SqlWhereClause where = ExpressionToSql.VisitWhere(inputExpression.Arguments, context);
                            context.CurrentQuery = context.CurrentQuery.AddWhereClause(where, context);
                        }
                        break;
                    }
                case LinqMethods.Average:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Avg);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.Count:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitCount(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.Distinct:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitDistinct(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.FirstOrDefault:
                    {
                        if (inputExpression.Arguments.Count == 1)
                        {
                            // TOP is not allowed when OFFSET ... LIMIT is present.
                            if (!context.CurrentQuery.HasOffsetSpec())
                            {
                                SqlNumberLiteral sqlNumberLiteral = SqlNumberLiteral.Create(1);
                                SqlTopSpec topSpec = SqlTopSpec.Create(sqlNumberLiteral);
                                context.CurrentQuery = context.CurrentQuery.AddTopSpec(topSpec);
                            }

                            context.SetClientOperation(ScalarOperationKind.FirstOrDefault);
                        }
                        else
                        {
                            throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.InvalidArgumentsCount, inputExpression.Method.Name, 0, inputExpression.Arguments.Count - 1));
                        }

                        break;
                    }
                case LinqMethods.Max:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Max);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.Min:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Min);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.GroupBy:
                    {
                        context.CurrentQuery = context.PackageCurrentQueryIfNeccessary();
                        result = ExpressionToSql.VisitGroupBy(returnElementType, inputExpression.Arguments, context);
                        context.LastExpressionIsGroupBy = true;
                        break;
                    }
                case LinqMethods.OrderBy:
                    {
                        SqlOrderByClause orderBy = ExpressionToSql.VisitOrderBy(inputExpression.Arguments, false, context);
                        context.CurrentQuery = context.CurrentQuery.AddOrderByClause(orderBy, context);
                        break;
                    }
                case LinqMethods.OrderByDescending:
                    {
                        SqlOrderByClause orderBy = ExpressionToSql.VisitOrderBy(inputExpression.Arguments, true, context);
                        context.CurrentQuery = context.CurrentQuery.AddOrderByClause(orderBy, context);
                        break;
                    }
                case nameof(CosmosLinqExtensions.OrderByRank):
                    {
                        SqlOrderByClause orderBy = ExpressionToSql.VisitOrderByRank(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddOrderByClause(orderBy, context);
                        break;
                    }
                case LinqMethods.Select:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitSelect(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.SelectMany:
                    {
                        context.CurrentQuery = context.PackageCurrentQueryIfNeccessary();
                        result = ExpressionToSql.VisitSelectMany(inputExpression.Arguments, context);
                        break;
                    }
                case LinqMethods.Skip:
                    {
                        SqlOffsetSpec offsetSpec = ExpressionToSql.VisitSkip(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddOffsetSpec(offsetSpec, context);
                        break;
                    }
                case LinqMethods.Sum:
                    {
                        SqlSelectClause select = ExpressionToSql.VisitAggregateFunction(inputExpression.Arguments, context, SqlFunctionCallScalarExpression.Names.Sum);
                        context.CurrentQuery = context.CurrentQuery.AddSelectClause(select, context);
                        break;
                    }
                case LinqMethods.Take:
                    {
                        if (context.CurrentQuery.HasOffsetSpec())
                        {
                            SqlLimitSpec limitSpec = ExpressionToSql.VisitTakeLimit(inputExpression.Arguments, context);
                            context.CurrentQuery = context.CurrentQuery.AddLimitSpec(limitSpec, context);
                        }
                        else
                        {
                            SqlTopSpec topSpec = ExpressionToSql.VisitTakeTop(inputExpression.Arguments, context);
                            context.CurrentQuery = context.CurrentQuery.AddTopSpec(topSpec);
                        }
                        break;
                    }
                case LinqMethods.ThenBy:
                    {
                        SqlOrderByClause thenBy = ExpressionToSql.VisitOrderBy(inputExpression.Arguments, false, context);
                        context.CurrentQuery = context.CurrentQuery.UpdateOrderByClause(thenBy, context);
                        break;
                    }
                case LinqMethods.ThenByDescending:
                    {
                        SqlOrderByClause thenBy = ExpressionToSql.VisitOrderBy(inputExpression.Arguments, true, context);
                        context.CurrentQuery = context.CurrentQuery.UpdateOrderByClause(thenBy, context);
                        break;
                    }
                case LinqMethods.Where:
                    {
                        SqlWhereClause where = ExpressionToSql.VisitWhere(inputExpression.Arguments, context);
                        context.CurrentQuery = context.CurrentQuery.AddWhereClause(where, context);
                        break;
                    }
                default:
                    throw new DocumentQueryException(string.Format(CultureInfo.CurrentCulture, ClientResources.MethodNotSupported, inputExpression.Method.Name));
            }

            context.PopSubqueryBinding();
            context.PopCollection();
            context.PopMethod();
            return result;
        }