Пример #1
0
        public void ParseParamenters(string methodString)
        {
            string[] res = null;

            "Do parsing".When(() => res = AggregationImplementationBase.GetAggregationParams(methodString));
            "check results".Then(() => res.Count().Should().Be(3));
            "check results".Then(() => res.First().Should().Be("a"));
            "check results".Then(() => res.Last().Should().Be("c"));
        }
Пример #2
0
        /// <summary>
        /// Execute the apply query to the given IQueryable.
        /// </summary>
        /// <remarks>
        /// The <see cref="ODataQuerySettings.HandleNullPropagation"/> property specifies
        /// how this method should handle null propagation.
        /// </remarks>
        /// <param name="query">The original <see cref="IQueryable"/>.</param>
        /// <param name="querySettings">The <see cref="ODataQuerySettings"/> that contains all the query application related settings.</param>
        /// <param name="assembliesResolver">IAssembliesResolver provided by the framework.</param>
        /// <param name="aggregationWindowSize">The max number of results to aggregate in each aggregation batch</param>
        /// <returns>The new <see cref="IQueryable"/> After the apply query has been applied to.</returns>
        public IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, IAssembliesResolver assembliesResolver, int aggregationWindowSize)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }
            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }
            if (Context.ElementClrType == null)
            {
                throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo");
            }

            ApplyClause applyClause = ApplyClause;

            Contract.Assert(applyClause != null);

            // Ensure we have decided how to handle null propagation
            ODataQuerySettings updatedSettings = querySettings;

            if (querySettings.HandleNullPropagation == HandleNullPropagationOption.Default)
            {
                updatedSettings = new ODataQuerySettings(updatedSettings);
                updatedSettings.HandleNullPropagation = HandleNullPropagationOption.False;
            }

            var maxResults = querySettings.PageSize ?? 2000;

            if (aggregationWindowSize != 0)
            {
                maxResults = (aggregationWindowSize < MAX_AGGREGATION_WINDOW_SIZE)
                    ? aggregationWindowSize
                    : MAX_AGGREGATION_WINDOW_SIZE;
            }

            // Call InterceptingProvider.Intercept that will create a new <see cref="InterceptingProvider"/> and set its visitors.
            // InterceptingProvider will wrap the actual IQueryable to implement unsupported operations in memory.
            var        mi      = _intercept_mi.MakeGenericMethod(this.Context.ElementClrType);
            IQueryable results = mi.Invoke(null, new object[] { query, maxResults, null }) as IQueryable;

            // Each transformation is the input for the next transformation in the transformations list
            foreach (var transformation in applyClause.Transformations)
            {
                switch (transformation.Item1)
                {
                case "aggregate":
                    ApplyAggregateClause aggregateClause = transformation.Item2 as ApplyAggregateClause;
                    if (aggregateClause == null)
                    {
                        throw Error.Argument("aggregation transformation type mismatch", transformation.Item2);
                    }

                    LambdaExpression propertyToAggregateExpression = FilterBinder.Bind(aggregateClause.AggregatablePropertyExpression, Context.ElementClrType, Context.Model, assembliesResolver, updatedSettings);

                    var aggregationImplementation = AggregationMethodsImplementations.GetAggregationImplementation(aggregateClause.AggregationMethod);
                    if (results.Provider is InterceptingProvider)
                    {
                        (results.Provider as InterceptingProvider).Combiner =
                            aggregationImplementation.CombineTemporaryResults;
                    }

                    IQueryable queryToUse = results;
                    if (aggregateClause.AggregatableProperty.Contains('/'))
                    {
                        queryToUse = AggregationImplementationBase.FilterNullValues(query, this.Context.ElementClrType, aggregateClause);
                    }

                    var      projectionLambda  = AggregationImplementationBase.GetProjectionLambda(this.Context.ElementClrType, aggregateClause, propertyToAggregateExpression);
                    string[] aggregationParams = AggregationImplementationBase.GetAggregationParams(aggregateClause.AggregationMethod);
                    var      aggragationResult = aggregationImplementation.DoAggregatinon(this.Context.ElementClrType, queryToUse, aggregateClause, projectionLambda, aggregationParams);
                    var      aliasType         = aggregationImplementation.GetResultType(this.Context.ElementClrType, aggregateClause);

                    results = this.ProjectResult(aggragationResult, aggregateClause.Alias, aliasType);
                    Context = new ODataQueryContext(this.Context.Model, results.ElementType);

                    break;

                case "groupby":
                    IEnumerable <LambdaExpression> propertiesToGroupByExpressions = null;
                    var groupByImplementation = new GroupByImplementation()
                    {
                        Context = this.Context
                    };
                    var groupByClause = transformation.Item2 as ApplyGroupbyClause;
                    if (groupByClause == null)
                    {
                        throw Error.Argument("aggregation transformation type mismatch", transformation.Item2);
                    }

                    var entityParam = Expression.Parameter(this.Context.ElementClrType, "$it");
                    if (groupByClause.SelectedPropertiesExpressions != null)
                    {
                        propertiesToGroupByExpressions =
                            groupByClause.SelectedPropertiesExpressions.Select(
                                exp =>
                                FilterBinder.Bind(
                                    exp, this.Context.ElementClrType, this.Context.Model, assembliesResolver, updatedSettings, entityParam));
                    }

                    var keyType = groupByImplementation.GetGroupByKeyType(groupByClause);
                    if (groupByClause.Aggregate == null)
                    {
                        // simple group-by without aggregation method
                        results = groupByImplementation.DoGroupBy(results, maxResults, groupByClause, keyType, propertiesToGroupByExpressions);
                    }
                    else
                    {
                        IQueryable keys = null;
                        propertyToAggregateExpression = FilterBinder.Bind(groupByClause.Aggregate.AggregatablePropertyExpression, Context.ElementClrType, Context.Model, assembliesResolver, updatedSettings);

                        object[] aggragatedValues = null;
                        groupByImplementation.DoAggregatedGroupBy(results, maxResults, groupByClause, keyType, propertiesToGroupByExpressions, propertyToAggregateExpression,
                                                                  out keys, out aggragatedValues);

                        results = ProjectGroupedResult(groupByClause, keys, aggragatedValues, keyType, Context);
                    }

                    Context = new ODataQueryContext(this.Context.Model, results.ElementType);
                    break;

                case "filter":
                    var filterClause = transformation.Item2 as ApplyFilterClause;
                    if (filterClause == null)
                    {
                        throw Error.Argument("aggregation transformation type mismatch", transformation.Item2);
                    }

                    var filterImplementation = new FilterImplementation()
                    {
                        Context = this.Context
                    };
                    results = filterImplementation.DoFilter(results, filterClause, querySettings, this._queryOptionParser);

                    break;

                default:
                    throw Error.NotSupported("aggregation not supported", transformation.Item1);
                }
            }

            object convertedResult = null;

            return(results);
        }