Ejemplo n.º 1
0
        public LoadResult Load()
        {
            if (Options.IsCountQuery)
            {
                return new LoadResult {
                           totalCount = ExecCount()
                }
            }
            ;

            var result = new LoadResult();

            if (CanUseRemoteGrouping && ShouldEmptyGroups)
            {
                var groupingResult = ExecRemoteGrouping();

                EmptyGroups(groupingResult.Groups, Options.Group.Length);

                result.data       = Paginate(groupingResult.Groups, Options.Skip, Options.Take);
                result.summary    = groupingResult.Totals;
                result.totalCount = groupingResult.TotalCount;

                if (Options.RequireGroupCount)
                {
                    result.groupCount = groupingResult.Groups.Count();
                }
            }
            else
            {
                if (!Options.HasPrimaryKey)
                {
                    Options.PrimaryKey = Utils.GetPrimaryKey(typeof(S));
                }

                if (!Options.HasPrimaryKey && !Options.HasDefaultSort && (Options.Skip > 0 || Options.Take > 0))
                {
                    if (QueryProviderInfo.IsEFClassic || QueryProviderInfo.IsEFCore)
                    {
                        Options.DefaultSort = EFSorting.FindSortableMember(typeof(S));
                    }
                    else if (QueryProviderInfo.IsXPO)
                    {
                        Options.DefaultSort = "this";
                    }
                }

                var deferPaging = Options.HasGroups || !CanUseRemoteGrouping && !SummaryIsTotalCountOnly && Options.HasSummary;
                var loadExpr    = Builder.BuildLoadExpr(Source.Expression, !deferPaging);

                if (Options.HasAnySelect)
                {
                    ContinueWithGrouping(
                        ExecWithSelect(loadExpr),
                        result
                        );
                }
                else
                {
                    ContinueWithGrouping(
                        ExecExpr <S>(Source, loadExpr),
                        result
                        );
                }

                if (deferPaging)
                {
                    result.data = Paginate(result.data, Options.Skip, Options.Take);
                }

                if (ShouldEmptyGroups)
                {
                    EmptyGroups(result.data, Options.Group.Length);
                }
            }

            return(result);
        }

        IEnumerable <ExpandoObject> ExecWithSelect(Expression loadExpr)
        {
            var select = Options.GetFullSelect();

            if (Options.UseRemoteSelect)
            {
                return(SelectHelper.ConvertRemoteResult(ExecExpr <AnonType>(Source, loadExpr), select));
            }

            return(SelectHelper.Evaluate(ExecExpr <S>(Source, loadExpr), select));
        }

        void ContinueWithGrouping <R>(IEnumerable <R> loadResult, LoadResult result)
        {
            var accessor = new DefaultAccessor <R>();

            if (Options.HasGroups)
            {
                var groups = new GroupHelper <R>(accessor).Group(loadResult, Options.Group);
                if (Options.RequireGroupCount)
                {
                    result.groupCount = groups.Count;
                }
                ContinueWithAggregation(groups, accessor, result);
            }
            else
            {
                ContinueWithAggregation(loadResult, accessor, result);
            }
        }

        void ContinueWithAggregation <R>(IEnumerable data, IAccessor <R> accessor, LoadResult result)
        {
            if (CanUseRemoteGrouping && !SummaryIsTotalCountOnly && Options.HasSummary && !Options.HasGroups)
            {
                var groupingResult = ExecRemoteGrouping();
                result.totalCount = groupingResult.TotalCount;
                result.summary    = groupingResult.Totals;
            }
            else
            {
                var totalCount = -1;

                if (Options.RequireTotalCount || SummaryIsTotalCountOnly)
                {
                    totalCount = ExecCount();
                }

                if (Options.RequireTotalCount)
                {
                    result.totalCount = totalCount;
                }

                if (SummaryIsTotalCountOnly)
                {
                    result.summary = Enumerable.Repeat((object)totalCount, Options.TotalSummary.Length).ToArray();
                }
                else if (Options.HasSummary)
                {
                    data           = Buffer <R>(data);
                    result.summary = new AggregateCalculator <R>(data, accessor, Options.TotalSummary, Options.GroupSummary).Run();
                }
            }

            result.data = data;
        }

        int ExecCount()
        {
            var expr = Builder.BuildCountExpr(Source.Expression);

#if DEBUG
            Options.ExpressionWatcher?.Invoke(expr);
#endif
            return(Source.Provider.Execute <int>(expr));
        }

        RemoteGroupingResult ExecRemoteGrouping()
        {
            return(RemoteGroupTransformer.Run(
                       typeof(S),
                       ExecExpr <AnonType>(Source, Builder.BuildLoadGroupsExpr(Source.Expression)),
                       Options.HasGroups ? Options.Group.Length : 0,
                       Options.TotalSummary,
                       Options.GroupSummary
                       ));
        }

        IEnumerable <R> ExecExpr <R>(IQueryable <S> source, Expression expr)
        {
            IEnumerable <R> result = source.Provider.CreateQuery <R>(expr);

#if DEBUG
            if (Options.UseEnumerableOnce)
            {
                result = new EnumerableOnce <R>(result);
            }

            Options.ExpressionWatcher?.Invoke(expr);
#endif

            return(result);
        }
        public async Task <LoadResult> LoadAsync()
        {
            if (Context.IsCountQuery)
            {
                return new LoadResult {
                           totalCount = await ExecTotalCountAsync()
                }
            }
            ;

            var result = new LoadResult();

            if (Context.UseRemoteGrouping && Context.ShouldEmptyGroups)
            {
                var remotePaging = Context.HasPaging && Context.Group.Count == 1;

                var groupingResult = await ExecRemoteGroupingAsync(remotePaging, false, remotePaging);

                EmptyGroups(groupingResult.Groups, Context.Group.Count);

                result.data = groupingResult.Groups;
                if (!remotePaging)
                {
                    result.data = Paginate(result.data, Context.Skip, Context.Take);
                }

                if (remotePaging)
                {
                    if (Context.HasTotalSummary)
                    {
                        var totalsResult = await ExecRemoteTotalsAsync();

                        result.summary    = totalsResult.Totals;
                        result.totalCount = totalsResult.TotalCount;
                    }
                    else if (Context.RequireTotalCount)
                    {
                        result.totalCount = await ExecTotalCountAsync();
                    }
                }
                else
                {
                    result.summary    = groupingResult.Totals;
                    result.totalCount = groupingResult.TotalCount;
                }

                if (Context.RequireGroupCount)
                {
                    result.groupCount = remotePaging
                        ? await ExecCountAsync(CreateBuilder().BuildGroupCountExpr())
                        : groupingResult.Groups.Count();
                }
            }
            else
            {
                var deferPaging = Context.HasGroups || !Context.UseRemoteGrouping && !Context.SummaryIsTotalCountOnly && Context.HasSummary;

                Expression loadExpr;

                if (!deferPaging && Context.PaginateViaPrimaryKey && Context.Take > 0)
                {
                    if (!Context.HasPrimaryKey)
                    {
                        throw new InvalidOperationException(nameof(DataSourceLoadOptionsBase.PaginateViaPrimaryKey)
                                                            + " requires a primary key."
                                                            + " Specify it via the " + nameof(DataSourceLoadOptionsBase.PrimaryKey) + " property.");
                    }

                    var loadKeysExpr = CreateBuilder().BuildLoadExpr(true, selectOverride: Context.PrimaryKey);
                    var keyTuples    = await ExecExprAsync <AnonType>(loadKeysExpr);

                    loadExpr = CreateBuilder().BuildLoadExpr(false, filterOverride: FilterFromKeys(keyTuples));
                }
                else
                {
                    loadExpr = CreateBuilder().BuildLoadExpr(!deferPaging);
                }

                if (Context.HasAnySelect)
                {
                    await ContinueWithGroupingAsync(
                        await ExecWithSelectAsync(loadExpr),
                        result
                        );
                }
                else
                {
                    await ContinueWithGroupingAsync(
                        await ExecExprAsync <S>(loadExpr),
                        result
                        );
                }

                if (deferPaging)
                {
                    result.data = Paginate(result.data, Context.Skip, Context.Take);
                }

                if (Context.ShouldEmptyGroups)
                {
                    EmptyGroups(result.data, Context.Group.Count);
                }
            }

            return(result);
        }

        async Task <IEnumerable <ExpandoObject> > ExecWithSelectAsync(Expression loadExpr)
        {
            if (Context.UseRemoteSelect)
            {
                return(SelectHelper.ConvertRemoteResult(await ExecExprAsync <AnonType>(loadExpr), Context.FullSelect));
            }

            return(SelectHelper.Evaluate(await ExecExprAsync <S>(loadExpr), Context.FullSelect));
        }

        async Task ContinueWithGroupingAsync <R>(IEnumerable <R> loadResult, LoadResult result)
        {
            var accessor = new DefaultAccessor <R>();

            if (Context.HasGroups)
            {
                var groups = new GroupHelper <R>(accessor).Group(loadResult, Context.Group);
                if (Context.RequireGroupCount)
                {
                    result.groupCount = groups.Count;
                }
                await ContinueWithAggregationAsync(groups, accessor, result);
            }
            else
            {
                await ContinueWithAggregationAsync(loadResult, accessor, result);
            }
        }

        async Task ContinueWithAggregationAsync <R>(IEnumerable data, IAccessor <R> accessor, LoadResult result)
        {
            if (Context.UseRemoteGrouping && !Context.SummaryIsTotalCountOnly && Context.HasSummary && !Context.HasGroups)
            {
                var totalsResult = await ExecRemoteTotalsAsync();

                result.totalCount = totalsResult.TotalCount;
                result.summary    = totalsResult.Totals;
            }
            else
            {
                var totalCount = -1;

                if (Context.RequireTotalCount || Context.SummaryIsTotalCountOnly)
                {
                    totalCount = await ExecTotalCountAsync();
                }

                if (Context.RequireTotalCount)
                {
                    result.totalCount = totalCount;
                }

                if (Context.SummaryIsTotalCountOnly)
                {
                    result.summary = Enumerable.Repeat((object)totalCount, Context.TotalSummary.Count).ToArray();
                }
                else if (Context.HasSummary)
                {
                    data           = Buffer <R>(data);
                    result.summary = new AggregateCalculator <R>(data, accessor, Context.TotalSummary, Context.GroupSummary).Run();
                }
            }

            result.data = data;
        }

        Task <int> ExecCountAsync(Expression expr)
        {
#if DEBUG
            ExpressionWatcher?.Invoke(expr);
#endif

            var executor = CreateExecutor(expr);

            if (Context.RequireQueryableChainBreak)
            {
                executor.BreakQueryableChain();
            }

            return(executor.CountAsync());
        }

        Task <int> ExecTotalCountAsync() => ExecCountAsync(CreateBuilder().BuildCountExpr());

        Task <RemoteGroupingResult> ExecRemoteTotalsAsync() => ExecRemoteGroupingAsync(false, true, false);

        async Task <RemoteGroupingResult> ExecRemoteGroupingAsync(bool remotePaging, bool suppressGroups, bool suppressTotals)
        {
            return(RemoteGroupTransformer.Run(
                       Source.ElementType,
                       await ExecExprAsync <AnonType>(CreateBuilder().BuildLoadGroupsExpr(remotePaging, suppressGroups, suppressTotals)),
                       !suppressGroups && Context.HasGroups ? Context.Group.Count : 0,
                       !suppressTotals ? Context.TotalSummary : null,
                       !suppressGroups ? Context.GroupSummary : null
                       ));
        }

        async Task <IEnumerable <R> > ExecExprAsync <R>(Expression expr)
        {
#if DEBUG
            ExpressionWatcher?.Invoke(expr);
#endif

            var executor = CreateExecutor(expr);

            if (Context.RequireQueryableChainBreak)
            {
                executor.BreakQueryableChain();
            }

            var result = await executor.ToEnumerableAsync <R>();

#if DEBUG
            if (UseEnumerableOnce)
            {
                result = new EnumerableOnce <R>(result);
            }
#endif

            return(result);
        }

        IList FilterFromKeys(IEnumerable <AnonType> keyTuples)
        {
            var result    = new List <object>();
            var key       = Context.PrimaryKey;
            var keyLength = key.Count;

            foreach (var tuple in keyTuples)
            {
                if (result.Count > 0)
                {
                    result.Add("or");
                }

                void AddCondition(IList container, int index)
                {
                    container.Add(new object[] { key[index], tuple[index] });
                }

                if (keyLength == 1)
                {
                    AddCondition(result, 0);
                }
                else
                {
                    var group = new List <object>();
                    for (var i = 0; i < keyLength; i++)
                    {
                        AddCondition(group, i);
                    }
                    result.Add(group);
                }
            }

            return(result);
        }
        public LoadResult Load()
        {
            if (Context.IsCountQuery)
            {
                return new LoadResult {
                           totalCount = ExecCount()
                }
            }
            ;

            var result = new LoadResult();

            if (Context.UseRemoteGrouping && Context.ShouldEmptyGroups)
            {
                var groupingResult = ExecRemoteGrouping();

                EmptyGroups(groupingResult.Groups, Context.Group.Count);

                result.data       = Paginate(groupingResult.Groups, Context.Skip, Context.Take);
                result.summary    = groupingResult.Totals;
                result.totalCount = groupingResult.TotalCount;

                if (Context.RequireGroupCount)
                {
                    result.groupCount = groupingResult.Groups.Count();
                }
            }
            else
            {
                var deferPaging = Context.HasGroups || !Context.UseRemoteGrouping && !Context.SummaryIsTotalCountOnly && Context.HasSummary;
                var loadExpr    = Builder.BuildLoadExpr(Source.Expression, !deferPaging);

                if (Context.HasAnySelect)
                {
                    ContinueWithGrouping(
                        ExecWithSelect(loadExpr),
                        result
                        );
                }
                else
                {
                    ContinueWithGrouping(
                        ExecExpr <S>(Source, loadExpr),
                        result
                        );
                }

                if (deferPaging)
                {
                    result.data = Paginate(result.data, Context.Skip, Context.Take);
                }

                if (Context.ShouldEmptyGroups)
                {
                    EmptyGroups(result.data, Context.Group.Count);
                }
            }

            return(result);
        }

        IEnumerable <ExpandoObject> ExecWithSelect(Expression loadExpr)
        {
            if (Context.UseRemoteSelect)
            {
                return(SelectHelper.ConvertRemoteResult(ExecExpr <AnonType>(Source, loadExpr), Context.FullSelect));
            }

            return(SelectHelper.Evaluate(ExecExpr <S>(Source, loadExpr), Context.FullSelect));
        }

        void ContinueWithGrouping <R>(IEnumerable <R> loadResult, LoadResult result)
        {
            var accessor = new DefaultAccessor <R>();

            if (Context.HasGroups)
            {
                var groups = new GroupHelper <R>(accessor).Group(loadResult, Context.Group);
                if (Context.RequireGroupCount)
                {
                    result.groupCount = groups.Count;
                }
                ContinueWithAggregation(groups, accessor, result);
            }
            else
            {
                ContinueWithAggregation(loadResult, accessor, result);
            }
        }

        void ContinueWithAggregation <R>(IEnumerable data, IAccessor <R> accessor, LoadResult result)
        {
            if (Context.UseRemoteGrouping && !Context.SummaryIsTotalCountOnly && Context.HasSummary && !Context.HasGroups)
            {
                var groupingResult = ExecRemoteGrouping();
                result.totalCount = groupingResult.TotalCount;
                result.summary    = groupingResult.Totals;
            }
            else
            {
                var totalCount = -1;

                if (Context.RequireTotalCount || Context.SummaryIsTotalCountOnly)
                {
                    totalCount = ExecCount();
                }

                if (Context.RequireTotalCount)
                {
                    result.totalCount = totalCount;
                }

                if (Context.SummaryIsTotalCountOnly)
                {
                    result.summary = Enumerable.Repeat((object)totalCount, Context.TotalSummary.Count).ToArray();
                }
                else if (Context.HasSummary)
                {
                    data           = Buffer <R>(data);
                    result.summary = new AggregateCalculator <R>(data, accessor, Context.TotalSummary, Context.GroupSummary).Run();
                }
            }

            result.data = data;
        }

        int ExecCount()
        {
            var expr = Builder.BuildCountExpr(Source.Expression);

#if DEBUG
            ExpressionWatcher?.Invoke(expr);
#endif
            return(Source.Provider.Execute <int>(expr));
        }

        RemoteGroupingResult ExecRemoteGrouping()
        {
            return(RemoteGroupTransformer.Run(
                       typeof(S),
                       ExecExpr <AnonType>(Source, Builder.BuildLoadGroupsExpr(Source.Expression)),
                       Context.HasGroups ? Context.Group.Count : 0,
                       Context.TotalSummary,
                       Context.GroupSummary
                       ));
        }

        IEnumerable <R> ExecExpr <R>(IQueryable <S> source, Expression expr)
        {
            IEnumerable <R> result = source.Provider.CreateQuery <R>(expr);

#if DEBUG
            if (UseEnumerableOnce)
            {
                result = new EnumerableOnce <R>(result);
            }

            ExpressionWatcher?.Invoke(expr);
#endif

            return(result);
        }