/// <summary> /// Constructs a new SelectBinder. /// </summary> /// <param name="model">The model used for binding.</param> /// <param name="entityType">The entity type that the $select is being applied to.</param> /// <param name="maxDepth">the maximum recursive depth.</param> /// <param name="expandClauseToDecorate">The already built expand clause to decorate</param> public SelectBinder(IEdmModel model, IEdmEntityType entityType, int maxDepth, SelectExpandClause expandClauseToDecorate) { ExceptionUtils.CheckArgumentNotNull(model, "tokenIn"); ExceptionUtils.CheckArgumentNotNull(entityType, "entityType"); this.visitor = new SelectPropertyVisitor(model, entityType, maxDepth, expandClauseToDecorate); }
private void ProcessTokenAsPath(NonSystemToken tokenIn) { Debug.Assert(tokenIn != null, "tokenIn != null"); List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); IEdmEntityType currentLevelEntityType = this.entityType; // first, walk through all type segments in a row, converting them from tokens into segments. if (tokenIn.IsNamespaceOrContainerQualified()) { PathSegmentToken firstNonTypeToken; pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.model, this.maxDepth, ref currentLevelEntityType, out firstNonTypeToken)); Debug.Assert(firstNonTypeToken != null, "Did not get last token."); tokenIn = firstNonTypeToken as NonSystemToken; if (tokenIn == null) { throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_SystemTokenInSelect(firstNonTypeToken.Identifier)); } } // next, create a segment for the first non-type segment in the path. ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.model, currentLevelEntityType); Debug.Assert(lastSegment != null, "nextSegment != null"); // next, create an ODataPath and add the segments to it. pathSoFar.Add(lastSegment); ODataSelectPath selectedPath = new ODataSelectPath(pathSoFar); var navigationSelection = new PathSelectItem(selectedPath); // next, create a selection item for the path, based on the last segment's type. // TODO: just have PathSelectItem if (lastSegment is NavigationPropertySegment) { bool foundExactExpand = false; bool foundDifferentTypeExpand = false; foreach (var subItem in this.expandClauseToDecorate.Expansion.ExpandItems) { IEdmNavigationProperty subItemNavigationProperty = subItem.PathToNavigationProperty.GetNavigationProperty(); if (subItem.PathToNavigationProperty.Equals(navigationSelection.SelectedPath)) { foundExactExpand = true; if (tokenIn.NextToken == null) { subItem.SelectAndExpand.SetAllSelectionRecursively(); } else { SelectPropertyVisitor nextLevelVisitor = new SelectPropertyVisitor(this.model, subItemNavigationProperty.ToEntityType(), this.maxDepth, subItem.SelectAndExpand); tokenIn.NextToken.Accept(nextLevelVisitor); } } else if (subItem.PathToNavigationProperty.LastSegment.Equals(navigationSelection.SelectedPath.LastSegment)) { foundDifferentTypeExpand = true; } } if (foundDifferentTypeExpand && !foundExactExpand) { throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_DisparateTypeSegmentsInSelectExpand); } if (!foundExactExpand) { // if it has sub-properties selected, then require it to have been expanded. if (tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectionItemBinder_NoExpandForSelectedProperty(tokenIn.Identifier)); } // otherwise just add it to the partial selection. this.expandClauseToDecorate.AddSelectItem(navigationSelection); } else { this.expandClauseToDecorate.InitializeEmptySelection(); } } else { // non-navigation cases do not allow further segments in $select. if (tokenIn.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectionItemBinder_NonNavigationPathToken); } this.expandClauseToDecorate.AddSelectItem(navigationSelection); } }