/// <summary> /// Process a <see cref="SelectTermToken"/> to identify whether it's a Wildcard path. /// </summary> /// <param name="selectToken">the select token to process.</param> /// <param name="newSelectItem">the built select item to out.</param> private bool ProcessWildcardTokenPath(SelectTermToken selectToken, out SelectItem newSelectItem) { newSelectItem = null; if (selectToken == null || selectToken.PathToProperty == null) { return(false); } PathSegmentToken pathToken = selectToken.PathToProperty; if (SelectPathSegmentTokenBinder.TryBindAsWildcard(pathToken, this.Model, out newSelectItem)) { // * or Namespace.* if (pathToken.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectExpandBinder_InvalidIdentifierAfterWildcard(pathToken.NextToken.Identifier)); } VerifyNoQueryOptionsNested(selectToken, pathToken.Identifier); return(true); } return(false); }
private static void VerifySelectedPath(SelectTermToken selectedToken) { PathSegmentToken current = selectedToken.PathToProperty; while (current != null) { if (current is SystemToken) { // It's not allowed to set a system token in a select clause. throw new ODataException(ODataErrorStrings.SelectExpandBinder_SystemTokenInSelect(current.Identifier)); } current = current.NextToken; } }
private static void VerifyNoQueryOptionsNested(SelectTermToken selectToken, string identifier) { if (selectToken != null) { if (selectToken.ComputeOption != null || selectToken.FilterOption != null || selectToken.OrderByOptions != null || selectToken.SearchOption != null || selectToken.CountQueryOption != null || selectToken.SelectOption != null || selectToken.TopOption != null || selectToken.SkipOption != null) { throw new ODataException(ODataErrorStrings.SelectExpandBinder_InvalidQueryOptionNestedSelection(identifier)); } } }
private static bool VerifySelectedNavigationProperty(IList <ODataPathSegment> selectedPath, SelectTermToken tokenIn) { NavigationPropertySegment navPropSegment = selectedPath.LastOrDefault() as NavigationPropertySegment; if (navPropSegment != null) { // After navigation property, it's not allowed to nest query options VerifyNoQueryOptionsNested(tokenIn, navPropSegment.Identifier); return(true); } return(false); }
/// <summary> /// Generate a select item <see cref="SelectItem"/> based on a <see cref="SelectTermToken"/>. /// for example: abc/efg($count=true;$filter=....;$top=1) /// </summary> /// <param name="tokenIn">the select term token to visit</param> /// <returns>the select item for this select term token.</returns> private SelectItem GenerateSelectItem(SelectTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); ExceptionUtils.CheckArgumentNotNull(tokenIn.PathToProperty, "pathToProperty"); VerifySelectedPath(tokenIn); SelectItem newSelectItem; if (ProcessWildcardTokenPath(tokenIn, out newSelectItem)) { return(newSelectItem); } IList <ODataPathSegment> selectedPath = ProcessSelectTokenPath(tokenIn.PathToProperty); Debug.Assert(selectedPath.Count > 0); // Navigation property should be the last segment in select path. if (VerifySelectedNavigationProperty(selectedPath, tokenIn)) { return(new PathSelectItem(new ODataSelectPath(selectedPath))); } // We should use the "NavigationSource" at this level for the next level binding. IEdmNavigationSource targetNavigationSource = this.NavigationSource; ODataPathSegment lastSegment = selectedPath.Last(); IEdmType targetElementType = lastSegment.TargetEdmType; IEdmCollectionType collection = targetElementType as IEdmCollectionType; if (collection != null) { targetElementType = collection.ElementType.Definition; } IEdmTypeReference elementTypeReference = targetElementType.ToTypeReference(); // $compute ComputeClause compute = BindCompute(tokenIn.ComputeOption, targetNavigationSource, elementTypeReference); HashSet <EndPathToken> generatedProperties = GetGeneratedProperties(compute, null); // $filter FilterClause filter = BindFilter(tokenIn.FilterOption, targetNavigationSource, elementTypeReference, generatedProperties); // $orderby OrderByClause orderBy = BindOrderby(tokenIn.OrderByOptions, targetNavigationSource, elementTypeReference, generatedProperties); // $search SearchClause search = BindSearch(tokenIn.SearchOption, targetNavigationSource, elementTypeReference); // $select List <ODataPathSegment> parsedPath = new List <ODataPathSegment>(this.parsedSegments); parsedPath.AddRange(selectedPath); SelectExpandClause selectExpand = BindSelectExpand(null, tokenIn.SelectOption, parsedPath, targetNavigationSource, elementTypeReference, generatedProperties); return(new PathSelectItem(new ODataSelectPath(selectedPath), targetNavigationSource, selectExpand, filter, orderBy, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, search, compute)); }