public bool ShouldBeOnNewQuery()

in Microsoft.Azure.Cosmos/src/Linq/QueryUnderConstruction.cs [498:595]


        public bool ShouldBeOnNewQuery(string methodName, int argumentCount)
        {
            // In the LINQ provider perspective, a SQL query (without subquery) the order of the execution of the operations is:
            //      Join -> Where -> Order By  -> Aggregates/Distinct/Select -> Top/Offset Limit
            //                    |             |
            //                    |-> Group By->|
            //
            // The order for the corresponding LINQ operations is:
            //      SelectMany -> Where -> OrderBy    -> Aggregates/Distinct/Select -> Skip/Take
            //                          |             |
            //                          |-> Group By->|
            //
            // In general, if an operation Op1 is being visited and the current query already has Op0 which
            // appear not before Op1 in the execution order, then this Op1 needs to be in a new query. This ensures
            // the semantics because if both of them are in the same query then the order would be Op0 -> Op1 
            // which is not true to the order they appear. In this case, Op1 will be consider to be in a parent-query 
            // in the flattening step.
            // 
            // In some cases, two operations has commutativity property, e.g. Select and Skip/Take/OrderBy/Where.
            // So visiting Select after Skip/Take has the same affect as visiting Skip/Take and then Select.
            //
            // Some operations are represented together with another operations in QueryUnderConstruction for simplicity purpose.
            // Therefore, the carrying operation needs to be considered instead. E.g. Aggregation functions are represented as a
            // SELECT VALUE <aggregate method> by themselves, Distinct is represented as SELECT VALUE DISTINCT.
            //
            // The rules in this function are simplified based on the above observations.

            bool shouldPackage = false;

            switch (methodName)
            {
                case LinqMethods.Select:
                    // New query is needed when adding a Select to an existing Select
                    shouldPackage = this.selectClause != null;
                    break;

                case LinqMethods.Min:
                case LinqMethods.Max:
                case LinqMethods.Sum:
                case LinqMethods.Average:
                    shouldPackage = (this.selectClause != null) ||
                        (this.offsetSpec != null) ||
                        (this.topSpec != null);
                    break;

                case LinqMethods.Count:
                    // When Count has 2 arguments, it calls into AddWhereClause so it should be considered as a Where in that case.
                    // Otherwise, treat it as other aggregate functions (using Sum here for simplicity).
                    shouldPackage = (argumentCount == 2 && this.ShouldBeOnNewQuery(LinqMethods.Where, 2)) ||
                        this.ShouldBeOnNewQuery(LinqMethods.Sum, 1);
                    break;

                case LinqMethods.Where:
                // Where expression parameter needs to be substituted if necessary so
                // It is not needed in Select distinct because the Select distinct would have the necessary parameter name adjustment.
                case LinqMethods.Any:
                case nameof(CosmosLinqExtensions.OrderByRank):
                case LinqMethods.OrderBy:
                case LinqMethods.OrderByDescending:
                case LinqMethods.ThenBy:
                case LinqMethods.ThenByDescending:
                case LinqMethods.Distinct:
                    // New query is needed when there is already a Take or a non-distinct Select
                    // Or when an Order By Rank is added to a query with an Order By clause (and vice versa)
                    shouldPackage = (this.topSpec != null) ||
                        (this.offsetSpec != null) ||
                        (this.selectClause != null && !this.selectClause.HasDistinct) || 
                        (this.groupByClause != null) || 
                        (this.orderByClause != null && (methodName == nameof(CosmosLinqExtensions.OrderByRank))) ||
                        (this.orderByClause != null && (this.orderByClause.Rank == true) && (methodName == LinqMethods.OrderBy));
                    break;

                case LinqMethods.GroupBy:
                    // New query is needed when there is already a Take or a Select or a Group by clause or an Order By clause
                    shouldPackage = (this.topSpec != null) ||
                        (this.offsetSpec != null) ||
                        (this.selectClause != null) || 
                        (this.groupByClause != null) || 
                        (this.orderByClause != null);
                    break;

                case LinqMethods.Skip:
                    shouldPackage = (this.topSpec != null) ||
                        (this.limitSpec != null);
                    break;

                case LinqMethods.SelectMany:
                    shouldPackage = (this.topSpec != null) ||
                        (this.offsetSpec != null) ||
                        (this.selectClause != null);
                    break;

                default:
                    break;
            }

            return shouldPackage;
        }