Expression MakeAggregatingProjection(Expression target, Type groupingType, AnonTypeFacade groupKeyTypeFacade)
        {
            var param      = Expression.Parameter(groupingType, "g");
            var groupCount = groupKeyTypeFacade.MemberCount;

            var projectionExprList = new List <Expression> {
                Expression.Call(typeof(Enumerable), nameof(Enumerable.Count), new[] { ItemType }, param)
            };

            for (var i = 0; i < groupCount; i++)
            {
                projectionExprList.Add(groupKeyTypeFacade.CreateMemberAccessor(Expression.Property(param, "Key"), i));
            }

            projectionExprList.AddRange(MakeAggregates(param, _totalSummary));

            if (groupCount > 0)
            {
                projectionExprList.AddRange(MakeAggregates(param, _groupSummary));
            }

            var projectionTypeFacade = new AnonTypeFacade(projectionExprList);
            var projectionLambda     = Expression.Lambda(projectionTypeFacade.CreateNewExpression(_anonTypeNewTweaks), param);

            return(Expression.Call(typeof(Queryable), nameof(Queryable.Select), new[] { param.Type, projectionLambda.ReturnType }, target, Expression.Quote(projectionLambda)));
        }
        public Expression Compile(Expression target)
        {
            var groupByParam     = CreateItemParam();
            var groupKeyExprList = new List <Expression>();
            var descendingList   = new List <bool>();

            if (_grouping != null)
            {
                foreach (var i in _grouping)
                {
                    var selectorExpr = String.IsNullOrEmpty(i.GroupInterval)
                        ? CompileAccessorExpression(groupByParam, i.Selector, liftToNullable: true)
                        : CompileGroupInterval(groupByParam, i.Selector, i.GroupInterval);

                    groupKeyExprList.Add(selectorExpr);
                    descendingList.Add(i.Desc);
                }
            }

            var groupKeyTypeFacade = new AnonTypeFacade(groupKeyExprList);
            var groupKeyLambda     = Expression.Lambda(groupKeyTypeFacade.CreateNewExpression(_anonTypeNewTweaks), groupByParam);
            var groupingType       = typeof(IGrouping <,>).MakeGenericType(groupKeyLambda.ReturnType, ItemType);

            target = Expression.Call(typeof(Queryable), nameof(Queryable.GroupBy), new[] { ItemType, groupKeyLambda.ReturnType }, target, Expression.Quote(groupKeyLambda));

            for (var i = 0; i < groupKeyExprList.Count; i++)
            {
                var orderParam    = Expression.Parameter(groupingType, "g");
                var orderAccessor = groupKeyTypeFacade.CreateMemberAccessor(
                    Expression.Property(orderParam, "Key"),
                    i
                    );

                target = Expression.Call(
                    typeof(Queryable),
                    Utils.GetSortMethod(i == 0, descendingList[i]),
                    new[] { groupingType, orderAccessor.Type },
                    target,
                    Expression.Quote(Expression.Lambda(orderAccessor, orderParam))
                    );
            }

            return(MakeAggregatingProjection(target, groupingType, groupKeyTypeFacade));
        }