/// <summary> /// Binds a DottedIdentifierToken and it's parent node (if needed). /// </summary> /// <param name="dottedIdentifierToken">Token to bind to metadata.</param> /// <param name="state">State of the Binding.</param> /// <returns>A bound node representing the cast.</returns> internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken"); ExceptionUtils.CheckArgumentNotNull(state, "state"); QueryNode parent; IEdmType parentType; if (dottedIdentifierToken.NextToken == null) { parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable); parentType = state.ImplicitRangeVariable.TypeReference.Definition; } else { parent = this.bindMethod(dottedIdentifierToken.NextToken); parentType = parent.GetEdmType(); } SingleEntityNode parentAsSingleValue = parent as SingleEntityNode; IEdmSchemaType childType = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier); IEdmEntityType childEntityType = childType as IEdmEntityType; if (childEntityType == null) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod); QueryNode functionCallNode; if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode)) { return(functionCallNode); } else { throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier)); } } // Check whether childType is a derived type of the type of its parent node UriEdmHelpers.CheckRelatedTo(parentType, childType); EntityCollectionNode parentAsCollection = parent as EntityCollectionNode; if (parentAsCollection != null) { return(new EntityCollectionCastNode(parentAsCollection, childEntityType)); } // parent can be null for casts on the implicit parameter; this is OK if (parent == null) { return(new SingleEntityCastNode(null, childEntityType)); } Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value."); return(new SingleEntityCastNode(parentAsSingleValue, childEntityType)); }
/// <summary> /// Constructs a EndPathBinder object using the given function to bind parent token. /// </summary> /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param> internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod) { DebugUtils.CheckNoExternalCallers(); this.bind = bindMethod; this.functionCallBinder = new FunctionCallBinder(bindMethod); }
/// <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> /// <param name="state">The state of binding.</param> /// <returns>The bound node.</returns> internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken, BindingState state) { DebugUtils.CheckNoExternalCallers(); FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod); // 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, state, 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); if (property == null) { QueryNode boundFunction; if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, state, out boundFunction)) { return(boundFunction); } if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpenType()) { throw new ODataException( ODataErrorStrings.MetadataBinder_PropertyNotDeclared( parent.GetEdmTypeReference().ODataFullName(), segmentToken.Identifier)); } return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier)); } if (property.Type.IsODataComplexTypeKind()) { return(new SingleValuePropertyAccessNode(singleValueParent, property)); } // Note - this means nonentity collection (primitive or complex) if (property.Type.IsNonEntityCollectionType()) { return(new CollectionPropertyAccessNode(singleValueParent, property)); } IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty; if (navigationProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name)); } SingleEntityNode parentEntity = EnsureParentIsEntityForNavProp(singleValueParent); return(GetNavigationNode(navigationProperty, parentEntity, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod))); }
/// <summary> /// Binds a function call token. /// </summary> /// <param name="functionCallToken">The function call token to bind.</param> /// <returns>The bound function call token.</returns> protected virtual QueryNode BindFunctionCall(FunctionCallToken functionCallToken) { FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.Bind); return(functionCallBinder.BindFunctionCall(functionCallToken, this.BindingState)); }