/// <summary> /// Processes the given uri and produces an expected value according to the conventions of an OData server implementation /// </summary> /// <param name="uri">The uri to process</param> /// <param name="applySelectAndExpand">A value indicating whether or not $select and $expand should be applied to the query values</param> /// <param name="applyPaging">A value indicating whether server-driven paging should be applied to the query values</param> /// <returns>The value resulting from processing the uri</returns> public QueryValue Evaluate(ODataUri uri, bool applySelectAndExpand, bool applyPaging) { this.applyPagingInExpands = applyPaging; ExceptionUtilities.CheckArgumentNotNull(uri, "uri"); ExceptionUtilities.CheckCollectionNotEmpty(uri.Segments, "uri.Segments"); ExceptionUtilities.CheckAllRequiredDependencies(this); this.currentUri = uri; this.shouldLastSegmentBeSingleton = false; applyPaging &= uri.TryGetExpectedEntitySet(out this.expectedEntitySet); if (applyPaging) { // compute the expected page size for this request based on the existence of a universal page size or set-specific page size this.expectedPageSize = this.expectedEntitySet.GetEffectivePageSize(); } else { this.expectedPageSize = null; } var query = this.BuildQueryFromSegments(); ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri); // we explicitly do not process expand or select here because they do not affect the number of rows returned or their ordering query = this.ProcessFilter(query); ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri); if (uri.IsEntitySet()) { // TODO: skip-token processing should happen before ordering query = this.ProcessOrderBy(query); ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri); query = this.ProcessSkipAndTop(query); ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri); } // handle $count requests if (uri.IsCount()) { query = query.LongCount(); } // need to resolve types since we constructed new QueryExpression tree var resolvedQuery = this.QueryResolver.Resolve(query); var value = this.Evaluator.Evaluate(resolvedQuery); ExceptionUtilities.CheckObjectNotNull(value, "Could not evaluate query '{0}'", query); ExceptionUtilities.Assert(value.EvaluationError == null, "Query evaluation produced an error: {0}", value.EvaluationError); // post-process the result to defer properties that were not expanded if (applySelectAndExpand) { value = this.ApplySelectAndExpand(uri, value); } // fixup for key expressions that should return singletons if (this.shouldLastSegmentBeSingleton) { value = EnsureLastSegmentIsSingletonOrNull(value); } this.currentUri = null; this.expectedEntitySet = null; this.expectedPageSize = null; return(value); }