public IQueryable DoQuery(string value) { string queryOption = "$apply"; var data = TestDataSource.CreateData(); ODataQuerySettings settings = new ODataQuerySettings() { PageSize = 2000, HandleNullPropagation = HandleNullPropagationOption.False }; var model = TestModelBuilder.CreateModel(new Type[] { typeof(Category), typeof(Product), typeof(Sales) }); var context = new ODataQueryContext(model, typeof(Sales), new ODataPath(new ODataPathSegment[] { new EntitySetPathSegment("Sales") })); IEdmNavigationSource source = model.FindDeclaredEntitySet("Sales"); var parser = new ODataQueryOptionParser(model, model.FindDeclaredType("System.Web.OData.Aggregation.Tests.Common.Sales"), source, new Dictionary <string, string>() { { queryOption, value } }); var applyClause = parser.ParseApply(); var filterClause = applyClause.Transformations.First().Item2 as ApplyFilterClause; var filter = new FilterImplementation() { Context = context }; return(filter.DoFilter(data, filterClause, settings, parser)); }
/// <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); }