/// <summary> /// Determines the parent node. If the token has a parent, that token is bound. If not, then we /// use the implicit parameter from the BindingState as the parent node. /// </summary> /// <param name="segmentToken">Token to determine the parent node for.</param> /// <param name="state">Current state of binding.</param> /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns> private QueryNode DetermineParentNode(InnerPathToken segmentToken, BindingState state) { ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); if (segmentToken.NextToken != null) { return(this.bindMethod(segmentToken.NextToken)); } else { RangeVariable implicitRangeVariable = state.ImplicitRangeVariable; return(NodeFactory.CreateRangeVariableReferenceNode(implicitRangeVariable)); } }
/// <summary> /// Try to bind an inner path token as a function call. Used for bound functions without parameters /// that parse as inner path tokens syntactically /// </summary> /// <param name="innerPathToken">the end path token to bind</param> /// <param name="parent">the parent node to this end path token.</param> /// <param name="boundFunction">a single value function call node representing the function call, if it exists</param> /// <returns>true if we found a function for this token, false otherwise.</returns> internal bool TryBindInnerPathAsFunctionCall(InnerPathToken innerPathToken, QueryNode parent, out QueryNode boundFunction) { return(this.TryBindIdentifier(innerPathToken.Identifier, null, parent, state, out boundFunction)); }
/// <summary> /// Binds an InnerPathToken. /// </summary> /// <param name="token">Token to bind.</param> /// <returns>Either a SingleNavigationNode, CollectionNavigationNode, SinglePropertyAccessNode (complex), /// or CollectionPropertyAccessNode (primitive or complex) that is the metadata-bound version of the given token.</returns> protected virtual QueryNode BindInnerPathSegment(InnerPathToken token) { InnerPathTokenBinder innerPathTokenBinder = new InnerPathTokenBinder(this.Bind, this.BindingState); return(innerPathTokenBinder.BindInnerPathSegment(token)); }
/// <summary> /// Binds a <see cref="InnerPathToken"/>. /// This includes more than just navigations - it includes complex property access and primitive collections. /// </summary> /// <param name="segmentToken">The segment token to bind.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod, state); // First we get the parent node QueryNode parent = this.DetermineParentNode(segmentToken, state); Debug.Assert(parent != null, "parent should never be null"); SingleValueNode singleValueParent = parent as SingleValueNode; if (singleValueParent == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Identifier)); } // Using the parent and name of this token, we try to get the IEdmProperty it represents IEdmProperty property = BindProperty(singleValueParent.TypeReference, segmentToken.Identifier, this.Resolver); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, out boundFunction)) { return(boundFunction); } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpen()) { throw ExceptionUtil.CreatePropertyNotFoundException(segmentToken.Identifier, parent.GetEdmTypeReference().FullName()); } return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier)); } IEdmStructuralProperty structuralProperty = property as IEdmStructuralProperty; if (property.Type.IsComplex()) { // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new PropertySegment(structuralProperty)); return(new SingleComplexNode(singleValueParent as SingleResourceNode, property)); } else if (property.Type.IsPrimitive()) { return(new SingleValuePropertyAccessNode(singleValueParent, property)); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { if (property.Type.IsStructuredCollectionType()) { // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new PropertySegment(structuralProperty)); return(new CollectionComplexNode(singleValueParent as SingleResourceNode, property)); } return(new CollectionPropertyAccessNode(singleValueParent, property)); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleResourceNode parentResource = EnsureParentIsResourceForNavProp(singleValueParent); IEdmNavigationSource navigationSource; QueryNode node = GetNavigationNode(navigationProperty, parentResource, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod), out navigationSource); // Generate a segment to parsed segments for the parsed token state.ParsedSegments.Add(new NavigationPropertySegment(navigationProperty, navigationSource)); return(node); }
/// <summary> /// Visits a InnerPathToken /// </summary> /// <param name="tokenIn">The InnerPathToken to bind</param> /// <returns>A SingleValueNode or SingleEntityNode bound to this InnerPathToken</returns> public virtual T Visit(InnerPathToken tokenIn) { throw new NotImplementedException(); }