/// <summary> /// Apply the individual query to the given IQueryable in the right order. /// </summary> /// <param name="query">The original <see cref="IQueryable"/>.</param> /// <param name="querySettings">The settings to use in query composition.</param> /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns> public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull(nameof(query)); } if (querySettings == null) { throw Error.ArgumentNull(nameof(querySettings)); } IQueryable result = query; IODataFeature odataFeature = Request.ODataFeature(); // Update the query setting querySettings = Context.UpdateQuerySettings(querySettings, query); // First apply $apply // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311 if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply)) { result = Apply.ApplyTo(result, querySettings); odataFeature.ApplyClause = Apply.ApplyClause; this.Context.ElementClrType = Apply.ResultClrType; } // TODO: need pass the result from $compute to the remaining query options // Construct the actual query and apply them in the following order: filter, orderby, skip, top if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter)) { if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute)) { Filter.Compute = Compute; } result = Filter.ApplyTo(result, querySettings); } // If both $search and $filter are specified in the same request, only those items satisfying both criteria are returned // apply $search if (IsAvailableODataQueryOption(Search, AllowedQueryOptions.Search)) { result = Search.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count)) { if (odataFeature.TotalCountFunc == null) { Func <long> countFunc = Count.GetEntityCountFunc(result); if (countFunc != null) { odataFeature.TotalCountFunc = countFunc; } } if (Request.IsCountRequest()) { return(result); } } OrderByQueryOption orderBy = OrderBy; // $skip or $top require a stable sort for predictable results. // Result limits require a stable sort to be able to generate a next page link. // If either is present in the query and we have permission, // generate an $orderby that will produce a stable sort. if (querySettings.EnsureStableOrdering && (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) || IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) || querySettings.PageSize.HasValue)) { // If there is no OrderBy present, we manufacture a default. // If an OrderBy is already present, we add any missing // properties necessary to make a stable sort. // Instead of failing early here if we cannot generate the OrderBy, // let the IQueryable backend fail (if it has to). orderBy = GenerateStableOrder(); } if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy)) { if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute)) { orderBy.Compute = Compute; } result = orderBy.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(SkipToken, AllowedQueryOptions.SkipToken)) { result = SkipToken.ApplyTo(result, querySettings, this); } AddAutoSelectExpandProperties(); if (SelectExpand != null) { var tempResult = ApplySelectExpand(result, querySettings); if (tempResult != default(IQueryable)) { result = tempResult; } } if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip)) { result = Skip.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top)) { result = Top.ApplyTo(result, querySettings); } result = ApplyPaging(result, querySettings); return(result); }
public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull("query"); } if (querySettings == null) { throw Error.ArgumentNull("querySettings"); } IQueryable result = query; // First apply $apply // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311 if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply)) { result = Apply.ApplyTo(result, querySettings, _assembliesResolver); Request.ODataProperties().ApplyClause = Apply.ApplyClause; this.Context.ElementClrType = Apply.ResultClrType; } // Construct the actual query and apply them in the following order: filter, orderby, skip, top if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter)) { result = Filter.ApplyTo(result, querySettings, _assembliesResolver); } if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count)) { if (Request.ODataProperties().TotalCountFunc == null) { Func <long> countFunc = Count.GetEntityCountFunc(result); if (countFunc != null) { Request.ODataProperties().TotalCountFunc = countFunc; } } if (ODataCountMediaTypeMapping.IsCountRequest(Request)) { return(result); } } OrderByQueryOption orderBy = OrderBy; // $skip or $top require a stable sort for predictable results. // Result limits require a stable sort to be able to generate a next page link. // If either is present in the query and we have permission, // generate an $orderby that will produce a stable sort. if (querySettings.EnsureStableOrdering && (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) || IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) || querySettings.PageSize.HasValue)) { // If there is no OrderBy present, we manufacture a default. // If an OrderBy is already present, we add any missing // properties necessary to make a stable sort. // Instead of failing early here if we cannot generate the OrderBy, // let the IQueryable backend fail (if it has to). orderBy = orderBy == null ? GenerateDefaultOrderBy(Context) : EnsureStableSortOrderBy(orderBy, Context); } if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy)) { result = orderBy.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip)) { result = Skip.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top)) { result = Top.ApplyTo(result, querySettings); } AddAutoExpandProperties(querySettings); if (SelectExpand != null) { var tempResult = ApplySelectExpand(result, querySettings); if (tempResult != default(IQueryable)) { result = tempResult; } } if (querySettings.PageSize.HasValue) { bool resultsLimited; result = LimitResults(result, querySettings.PageSize.Value, out resultsLimited); if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri && Request.ODataProperties().NextLink == null) { Uri nextPageLink = Request.GetNextPageLink(querySettings.PageSize.Value); Request.ODataProperties().NextLink = nextPageLink; } } return(result); }
/// <summary> /// Apply the individual query to the given IQueryable in the right order. /// </summary> /// <param name="query">The original <see cref="IQueryable"/>.</param> /// <param name="querySettings">The settings to use in query composition.</param> /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns> public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull("query"); } if (querySettings == null) { throw Error.ArgumentNull("querySettings"); } IQueryable result = query; // Construct the actual query and apply them in the following order: filter, orderby, skip, top if (Filter != null) { result = Filter.ApplyTo(result, querySettings, _assembliesResolver); } if (Apply != null) { result = Apply.ApplyTo(result, querySettings, _assembliesResolver, _aggregationWindowSize); UpdateOtherQueryOptions(result); } if (Count != null && Request.ODataProperties().TotalCount == null) { long?count = Count.GetEntityCount(result); if (count.HasValue) { Request.ODataProperties().TotalCount = count.Value; } } OrderByQueryOption orderBy = OrderBy; // $skip or $top require a stable sort for predictable results. // Result limits require a stable sort to be able to generate a next page link. // If either is present in the query and we have permission, // generate an $orderby that will produce a stable sort. if ((Apply == null) && querySettings.EnsureStableOrdering && (Skip != null || Top != null || querySettings.PageSize.HasValue)) { // If there is no OrderBy present, we manufacture a default. // If an OrderBy is already present, we add any missing // properties necessary to make a stable sort. // Instead of failing early here if we cannot generate the OrderBy, // let the IQueryable backend fail (if it has to). orderBy = orderBy == null ? GenerateDefaultOrderBy(Context) : EnsureStableSortOrderBy(orderBy, Context); } if (orderBy != null) { result = orderBy.ApplyTo(result, querySettings); } if (Skip != null) { result = Skip.ApplyTo(result, querySettings); } if (Top != null) { result = Top.ApplyTo(result, querySettings); } if (SelectExpand != null) { Request.ODataProperties().SelectExpandClause = SelectExpand.SelectExpandClause; result = SelectExpand.ApplyTo(result, querySettings); } if (querySettings.PageSize.HasValue) { bool resultsLimited; result = LimitResults(result, querySettings.PageSize.Value, out resultsLimited); if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri && Request.ODataProperties().NextLink == null) { Uri nextPageLink = GetNextPageLink(Request, querySettings.PageSize.Value); Request.ODataProperties().NextLink = nextPageLink; } } return(result); }
/// <summary> /// Apply the individual query to the given IQueryable in the right order. /// </summary> /// <param name="query">The original <see cref="IQueryable"/>.</param> /// <param name="querySettings">The settings to use in query composition.</param> /// <param name="pageSize">The page size for this query</param> /// <param name="queryOptions"></param> /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns> public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, int?pageSize, ODataQueryOptions queryOptions) { if (query == null) { throw Error.ArgumentNull("query"); } // Construct the actual query and apply them in the following order: filter if (Filter != null) { query = Filter.ApplyTo(query, querySettings, _assemblyProvider); } var orderBy = OrderBy; // $skip or $top require a stable sort for predictable results. // Result limits require a stable sort to be able to generate a next page link. // If either is present in the query and we have permission, // generate an $orderby that will produce a stable sort. if (querySettings.EnsureStableOrdering && ((Skip != null && queryOptions.IgnoreSkip == false) || (Top != null && queryOptions.IgnoreTop == false) || pageSize.HasValue)) { // If there is no OrderBy present, we manufacture a default. // If an OrderBy is already present, we add any missing // properties necessary to make a stable sort. // Instead of failing early here if we cannot generate the OrderBy, // let the IQueryable backend fail (if it has to). orderBy = orderBy == null ? OrderByHelper.GenerateDefaultOrderBy(Context, _serviceProvider) : OrderByHelper.EnsureStableSortOrderBy(orderBy, Context, _serviceProvider); } // First apply $apply // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311 if (Apply != null) { query = Apply.ApplyTo(query, querySettings, _assemblyProvider); Request.ODataFeature().ApplyClause = Apply.ApplyClause; Context.ElementClrType = Apply.ResultClrType; } if (orderBy != null && Apply == null) { query = orderBy.ApplyTo(query, querySettings); } if (Skip.HasValue && queryOptions.IgnoreSkip == false) { query = ExpressionHelpers.Skip(query, Skip.Value, Context.ElementClrType, false); } int?take = null; if (querySettings.PageSize.HasValue) { take = Math.Min(querySettings.PageSize.Value, int.MaxValue); } if (Top.HasValue && queryOptions.IgnoreTop == false) { take = Math.Min(Top.Value, take ?? int.MaxValue); } if (take.HasValue) { query = ExpressionHelpers.Take(query, take.Value, Context.ElementClrType, false); } if (SelectExpand != null) { query = SelectExpand.ApplyTo(query, querySettings, _assemblyProvider); } if (CountQueryOption != null) { if (Request.ODataFeature().TotalCountFunc == null) { Func <long> countFunc = CountQueryOption.GetEntityCountFunc(query); if (countFunc != null) { Request.ODataFeature().TotalCountFunc = countFunc; } } if (ODataCountMediaTypeMapping.IsCountRequest(Request.HttpContext)) { return(query); } } if (pageSize.HasValue && Apply == null) { bool resultsLimited; query = LimitResults(query, pageSize.Value, out resultsLimited); if (resultsLimited && Request.GetDisplayUrl() != null && new Uri(Request.GetDisplayUrl()).IsAbsoluteUri&& Request.ODataFeature().NextLink == null) { Uri nextPageLink = Request.GetNextPageLink(pageSize.Value); Request.ODataFeature().NextLink = nextPageLink; } } return(query); }
public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull("query"); } if (querySettings == null) { throw Error.ArgumentNull("querySettings"); } IQueryable result = query; // First apply $apply // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311 if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply)) { result = Apply.ApplyTo(result, querySettings); InternalRequest.Context.ApplyClause = Apply.ApplyClause; if (Apply.SelectExpandClause != null) { // In case of just expand in $apply falling back to $expand serialization InternalRequest.Context.ProcessedSelectExpandClause = Apply.SelectExpandClause; } this.Context.ElementClrType = Apply.ResultClrType; } // Apply compute // It should be executed before $filter, because it defines computed properties that can be used in a $select or within a $filter or $orderby expression. if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute)) { result = Compute.ApplyTo(result, querySettings); } // Construct the actual query and apply them in the following order: filter, orderby, skip, top if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter)) { result = Filter.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count)) { if (InternalRequest.Context.TotalCountFunc == null) { Func <long> countFunc = Count.GetEntityCountFunc(result); if (countFunc != null) { InternalRequest.Context.TotalCountFunc = countFunc; } } if (InternalRequest.IsCountRequest()) { return(result); } } OrderByQueryOption orderBy = OrderBy; // $skip or $top require a stable sort for predictable results. // Result limits require a stable sort to be able to generate a next page link. // If either is present in the query and we have permission, // generate an $orderby that will produce a stable sort. if (querySettings.EnsureStableOrdering && (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) || IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) || querySettings.PageSize.HasValue)) { // If there is no OrderBy present, we manufacture a default. // If an OrderBy is already present, we add any missing // properties necessary to make a stable sort. // Instead of failing early here if we cannot generate the OrderBy, // let the IQueryable backend fail (if it has to). orderBy = GenerateStableOrder(); } if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy)) { result = orderBy.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(SkipToken, AllowedQueryOptions.SkipToken)) { result = SkipToken.ApplyTo(result, querySettings, this); } if (!IsAggregated(Apply?.ApplyClause)) { AddAutoSelectExpandProperties(); } if (SelectExpand != null) { var tempResult = ApplySelectExpand(result, querySettings); if (tempResult != default(IQueryable)) { result = tempResult; } } if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip)) { result = Skip.ApplyTo(result, querySettings); } if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top)) { result = Top.ApplyTo(result, querySettings); } result = ApplyPaging(result, querySettings); return(result); }