/// <summary> /// Gets all of the entitySets that are involved for the given uri which includes expands /// </summary> /// <param name="uri">The uri to get the set for</param> /// <returns>The expected entity sets for the given uri</returns> internal static IEnumerable <EntitySet> GetIncludingExpandsSets(this ODataUri uri) { List <EntitySet> entitySets = new List <EntitySet>(); EntitySet startingEntitySet = null; if (uri.TryGetExpectedEntitySet(out startingEntitySet)) { // Review all expanded entity sets, get its version, if higher substitute its version foreach (IEnumerable <ODataUriSegment> segmentList in uri.ExpandSegments) { EntitySet currentEntitySet = startingEntitySet; foreach (ODataUriSegment segment in segmentList) { var navigationSegment = segment as NavigationSegment; if (navigationSegment != null) { EntitySet relatedEntitySet = currentEntitySet.GetRelatedEntitySet(navigationSegment.NavigationProperty); entitySets.Add(relatedEntitySet); currentEntitySet = relatedEntitySet; } } } } return(entitySets); }
/// <summary> /// Gets all of the entitySets that are involved for the given uri which includes expands /// </summary> /// <param name="uri">The uri to get the set for</param> /// <returns>The expected entity sets for the given uri</returns> internal static IEnumerable <EntitySet> GetAllEntitySetsIncludingExpands(this ODataUri uri) { List <EntitySet> entitySets = new List <EntitySet>(); EntitySet startingEntitySet = null; if (uri.TryGetExpectedEntitySet(out startingEntitySet)) { entitySets.Add(startingEntitySet); entitySets.AddRange(GetIncludingExpandsSets(uri)); } return(entitySets); }
internal static ODataUri ConstructODataUriWithoutActionInformation(IEnumerable<EntitySet> entitySets, ODataUri uri) { var segmentsToInclude = new List<ODataUriSegment>(); ServiceOperationAnnotation serviceOperationAnnotation = null; string setName = null; foreach (var segment in uri.Segments) { var functionSegment = segment as FunctionSegment; if (functionSegment != null && functionSegment.Function.IsAction()) { serviceOperationAnnotation = functionSegment.Function.Annotations.OfType<ServiceOperationAnnotation>().Single(); var toggleBooleanAnnotation = functionSegment.Function.Annotations.OfType<ToggleBoolPropertyValueActionAnnotation>().SingleOrDefault(); if (toggleBooleanAnnotation != null) { setName = toggleBooleanAnnotation.SourceEntitySet; } break; } segmentsToInclude.Add(segment); } if (!serviceOperationAnnotation.BindingKind.IsBound()) { ExceptionUtilities.CheckObjectNotNull(setName, "Cannot find the set name that the action starts from"); var sourceEntitySet = entitySets.Single(es => es.Name == setName); segmentsToInclude.Add(new EntitySetSegment(sourceEntitySet)); } var actionlessODataUri = new ODataUri(segmentsToInclude); actionlessODataUri.CustomQueryOptions = uri.CustomQueryOptions; actionlessODataUri.Filter = uri.Filter; actionlessODataUri.InlineCount = uri.InlineCount; actionlessODataUri.OrderBy = uri.OrderBy; actionlessODataUri.Skip = uri.Skip; actionlessODataUri.SkipToken = uri.SkipToken; actionlessODataUri.Top = uri.Top; EntitySet expectedEntitySet = null; ExceptionUtilities.Assert(actionlessODataUri.TryGetExpectedEntitySet(out expectedEntitySet), "Expected entity set not found"); // expand all navigations for actionlessODataUri so that we do not need to send additional request when calculating expected action result foreach (NavigationProperty navigation in expectedEntitySet.EntityType.NavigationProperties) { actionlessODataUri.ExpandSegments.Add(new List<ODataUriSegment>() { new NavigationSegment(navigation) }); } return actionlessODataUri; }
internal static bool ResponseMightIncludeNextLink(ODataUri uri) { var payloadsWithNextLinks = new[] { ODataPayloadElementType.EntitySetInstance, ODataPayloadElementType.LinkCollection }; var expectedPayloadType = uri.GetExpectedPayloadType(); if (!payloadsWithNextLinks.Contains(expectedPayloadType)) { return false; } EntitySet expectedSet; ExceptionUtilities.Assert(uri.TryGetExpectedEntitySet(out expectedSet), "Could not get expected entity set"); var pageSize = expectedSet.GetEffectivePageSize(); if (!pageSize.HasValue) { return false; } // if the value of $top is less than 1 page size, no next link will be included return !uri.Top.HasValue || uri.Top.Value > pageSize.Value; }
/// <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; }