Пример #1
0
        /// <summary>
        /// Binds a LambdaToken to metadata.
        /// </summary>
        /// <param name="lambdaToken">Token to bind.</param>
        /// <param name="state">Object to hold the state of binding.</param>
        /// <returns>A metadata bound any or all node.</returns>
        internal LambdaNode BindLambdaToken(LambdaToken lambdaToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(lambdaToken, "LambdaToken");
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            // Start by binding the parent token
            CollectionNode parent        = this.BindParentToken(lambdaToken.Parent);
            RangeVariable  rangeVariable = null;

            // Add the lambda variable to the stack
            if (lambdaToken.Parameter != null)
            {
                rangeVariable = NodeFactory.CreateParameterNode(lambdaToken.Parameter, parent);
                state.RangeVariables.Push(rangeVariable);
            }

            // Bind the expression
            SingleValueNode expression = this.BindExpressionToken(lambdaToken.Expression);

            // Create the node
            LambdaNode lambdaNode = NodeFactory.CreateLambdaNode(state, parent, expression, rangeVariable, lambdaToken.Kind);

            // Remove the lambda variable as it is now out of scope
            if (rangeVariable != null)
            {
                state.RangeVariables.Pop();
            }

            return(lambdaNode);
        }
Пример #2
0
        /// <summary>
        /// Constructs a new <see cref="CountNode"/>.
        /// </summary>
        /// <param name="source">The value containing the property.</param>
        /// <exception cref="System.ArgumentNullException">Throws if the input source is null.</exception>
        public CountNode(CollectionNode source)
            : this(source, null, null)
        {
            ExceptionUtils.CheckArgumentNotNull(source, "source");

            this.source = source;
        }
Пример #3
0
        /// <summary>
        /// Creates an AnyNode or an AllNode from the given
        /// </summary>
        /// <param name="state">State of binding.</param>
        /// <param name="parent">Parent node to the lambda.</param>
        /// <param name="lambdaExpression">Bound Lambda expression.</param>
        /// <param name="newRangeVariable">The new range variable being added by this lambda node.</param>
        /// <param name="queryTokenKind">Token kind.</param>
        /// <returns>A new LambdaNode bound to metadata.</returns>
        internal static LambdaNode CreateLambdaNode(
            BindingState state,
            CollectionNode parent,
            SingleValueNode lambdaExpression,
            RangeVariable newRangeVariable,
            QueryTokenKind queryTokenKind)
        {
            LambdaNode lambdaNode;

            if (queryTokenKind == QueryTokenKind.Any)
            {
                lambdaNode = new AnyNode(new Collection <RangeVariable>(state.RangeVariables.ToList()), newRangeVariable)
                {
                    Body   = lambdaExpression,
                    Source = parent,
                };
            }
            else
            {
                Debug.Assert(queryTokenKind == QueryTokenKind.All, "LambdaQueryNodes must be Any or All only.");
                lambdaNode = new AllNode(new Collection <RangeVariable>(state.RangeVariables.ToList()), newRangeVariable)
                {
                    Body   = lambdaExpression,
                    Source = parent,
                };
            }

            return(lambdaNode);
        }
Пример #4
0
        /// <summary>
        /// Binds an Count segment token.
        /// </summary>
        /// <param name="countSegmentToken">The Count segment token to bind.</param>
        /// <param name="state">State of the metadata binding.</param>
        /// <returns>The bound Count segment token.</returns>
        internal QueryNode BindCountSegment(CountSegmentToken countSegmentToken)
        {
            ExceptionUtils.CheckArgumentNotNull(countSegmentToken, "countSegmentToken");

            QueryNode      source = this.bindMethod(countSegmentToken.NextToken);
            CollectionNode node   = source as CollectionNode;

            if (node == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_CountSegmentNextTokenNotCollectionValue());
            }

            FilterClause filterClause = null;
            SearchClause searchClause = null;

            BindingState innerBindingState = new BindingState(state.Configuration);

            innerBindingState.ImplicitRangeVariable = NodeFactory.CreateParameterNode(ExpressionConstants.It, node);
            MetadataBinder binder = new MetadataBinder(innerBindingState);

            if (countSegmentToken.FilterOption != null)
            {
                FilterBinder filterBinder = new FilterBinder(binder.Bind, innerBindingState);
                filterClause = filterBinder.BindFilter(countSegmentToken.FilterOption);
            }

            if (countSegmentToken.SearchOption != null)
            {
                SearchBinder searchBinder = new SearchBinder(binder.Bind);
                searchClause = searchBinder.BindSearch(countSegmentToken.SearchOption);
            }

            return(new CountNode(node, filterClause, searchClause));
        }
Пример #5
0
        /// <summary>
        /// Retrieve CollectionNode bound with given query token.
        /// </summary>
        /// <param name="queryToken">The query token</param>
        /// <param name="expectedType">The expected type that this collection holds</param>
        /// <param name="model">The Edm model</param>
        /// <returns>The corresponding CollectionNode</returns>
        private CollectionNode GetCollectionOperandFromToken(QueryToken queryToken, IEdmTypeReference expectedType, IEdmModel model)
        {
            CollectionNode operand      = null;
            LiteralToken   literalToken = queryToken as LiteralToken;

            if (literalToken != null)
            {
                string originalLiteralText = literalToken.OriginalText;

                // Parentheses-based collections are not standard JSON but bracket-based ones are.
                // Temporarily switch our collection to bracket-based so that the JSON reader will
                // correctly parse the collection. Then pass the original literal text to the token.
                string bracketLiteralText = originalLiteralText;
                if (bracketLiteralText[0] == '(')
                {
                    Debug.Assert(bracketLiteralText[bracketLiteralText.Length - 1] == ')',
                                 "Collection with opening '(' should have corresponding ')'");

                    StringBuilder replacedText = new StringBuilder(bracketLiteralText);
                    replacedText[0] = '[';
                    replacedText[replacedText.Length - 1] = ']';
                    bracketLiteralText = replacedText.ToString();

                    Debug.Assert(expectedType.IsCollection());
                    string expectedTypeFullName = expectedType.Definition.AsElementType().FullTypeName();
                    if (expectedTypeFullName.Equals("Edm.String"))
                    {
                        // For collection of strings, need to convert single-quoted string to double-quoted string,
                        // and also, per ABNF, a single quote within a string literal is "encoded" as two consecutive single quotes in either
                        // literal or percent - encoded representation.
                        // Sample: ['a''bc','''def','xyz'''] ==> ["a'bc","'def","xyz'"], which is legitimate Json format.
                        bracketLiteralText = NormalizeStringCollectionItems(bracketLiteralText);
                    }
                    else if (expectedTypeFullName.Equals("Edm.Guid"))
                    {
                        // For collection of Guids, need to convert the Guid literals to single-quoted form, so that it is compatible
                        // with the Json reader used for deserialization.
                        // Sample: [D01663CF-EB21-4A0E-88E0-361C10ACE7FD, 492CF54A-84C9-490C-A7A4-B5010FAD8104]
                        //    ==>  ['D01663CF-EB21-4A0E-88E0-361C10ACE7FD', '492CF54A-84C9-490C-A7A4-B5010FAD8104']
                        bracketLiteralText = NormalizeGuidCollectionItems(bracketLiteralText);
                    }
                }

                object       collection             = ODataUriConversionUtils.ConvertFromCollectionValue(bracketLiteralText, model, expectedType);
                LiteralToken collectionLiteralToken = new LiteralToken(collection, originalLiteralText, expectedType);
                operand = this.bindMethod(collectionLiteralToken) as CollectionConstantNode;
            }
            else
            {
                operand = this.bindMethod(queryToken) as CollectionNode;
            }

            if (operand == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_RightOperandNotCollectionValue);
            }

            return(operand);
        }
Пример #6
0
        protected string Bind(QueryNode node)
        {
            CollectionNode  collectionNode  = node as CollectionNode;
            SingleValueNode singleValueNode = node as SingleValueNode;

            if (collectionNode != null)
            {
                switch (node.Kind)
                {
                case QueryNodeKind.CollectionNavigationNode:
                    CollectionNavigationNode navigationNode = node as CollectionNavigationNode;
                    return(BindNavigationPropertyNode(navigationNode.Source, navigationNode.NavigationProperty));

                case QueryNodeKind.CollectionPropertyAccess:
                    return(BindCollectionPropertyAccessNode(node as CollectionPropertyAccessNode));
                }
            }
            else if (singleValueNode != null)
            {
                switch (node.Kind)
                {
                case QueryNodeKind.BinaryOperator:
                    return(BindBinaryOperatorNode(node as BinaryOperatorNode));

                case QueryNodeKind.Constant:
                    return(BindConstantNode(node as ConstantNode));

                case QueryNodeKind.Convert:
                    return(BindConvertNode(node as ConvertNode));

                //case QueryNodeKind.EntityRangeVariableReference:
                //    return BindRangeVariable((node as EntityRangeVariableReferenceNode).RangeVariable);

                //case QueryNodeKind.NonentityRangeVariableReference:
                //    return BindRangeVariable((node as NonentityRangeVariableReferenceNode).RangeVariable);

                case QueryNodeKind.SingleValuePropertyAccess:
                    return(BindPropertyAccessQueryNode(node as SingleValuePropertyAccessNode));

                case QueryNodeKind.UnaryOperator:
                    return(BindUnaryOperatorNode(node as UnaryOperatorNode));

                case QueryNodeKind.SingleValueFunctionCall:
                    return(BindSingleValueFunctionCallNode(node as SingleValueFunctionCallNode));

                case QueryNodeKind.SingleNavigationNode:
                    SingleNavigationNode navigationNode = node as SingleNavigationNode;
                    return(BindNavigationPropertyNode(navigationNode.Source, navigationNode.NavigationProperty));

                case QueryNodeKind.Any:
                    return(BindAnyNode(node as AnyNode));

                case QueryNodeKind.All:
                    return(BindAllNode(node as AllNode));
                }
            }

            throw new NotSupportedException(String.Format("Nodes of type {0} are not supported", node.Kind));
        }
Пример #7
0
        /// <summary>
        /// Constructs a new <see cref="CountNode"/>.
        /// </summary>
        /// <param name="source">The value containing the property.</param>
        /// <param name="filterOption">The filter option.</param>
        /// <exception cref="System.ArgumentNullException">Throws if the input source is null.</exception>
        public CountNode(CollectionNode source, FilterClause filterOption)
        {
            ExceptionUtils.CheckArgumentNotNull(source, "source");

            FilterOption = filterOption;

            this.source = source;
        }
Пример #8
0
        /// <summary>
        /// Constructs a new <see cref="CountNode"/>.
        /// </summary>
        /// <param name="source">The value containing the property.</param>
        /// <param name="filterClause">The <see cref="Microsoft.OData.UriParser.FilterClause"/>in the count node.</param>
        /// <param name="searchClause">The <see cref="Microsoft.OData.UriParser.SearchClause"/>in the count node.</param>
        /// <exception cref="System.ArgumentNullException">Throws if the input source is null.</exception>
        public CountNode(CollectionNode source, FilterClause filterClause, SearchClause searchClause)
        {
            ExceptionUtils.CheckArgumentNotNull(source, "source");

            this.source       = source;
            this.filterClause = filterClause;
            this.searchClause = searchClause;
        }
Пример #9
0
        /// <summary>
        /// Binds a an end path token into a PropertyAccessToken, OpenPropertyToken, or FunctionCallToken.
        /// </summary>
        /// <param name="endPathToken">The property access token to bind.</param>
        /// <returns>A Query node representing this endpath token, bound to metadata.</returns>
        internal QueryNode BindEndPath(EndPathToken endPathToken)
        {
            ExceptionUtils.CheckArgumentNotNull(endPathToken, "EndPathToken");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(endPathToken.Identifier, "EndPathToken.Identifier");

            // Set the parent (get the parent type, so you can check whether the Identifier inside EndPathToken really is legit offshoot of the parent type)
            QueryNode parent = this.DetermineParentNode(endPathToken);

            QueryNode boundFunction;

            SingleValueNode singleValueParent = parent as SingleValueNode;

            if (singleValueParent == null)
            {
                if (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, parent, state, out boundFunction))
                {
                    return(boundFunction);
                }

                // Collection with any or all expression is already supported and handled separately.
                // Add support of collection with $count segment.
                CollectionNode colNode = parent as CollectionNode;
                if (colNode != null && endPathToken.Identifier.Equals(UriQueryConstants.CountSegment))
                {
                    // create a collection count node for collection node property.
                    return(new CountNode(colNode));
                }

                throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(endPathToken.Identifier));
            }


            // Now that we have the parent type, can find its corresponding EDM type
            IEdmStructuredTypeReference structuredParentType =
                singleValueParent.TypeReference == null ? null : singleValueParent.TypeReference.AsStructuredOrNull();

            IEdmProperty property =
                structuredParentType == null ? null : this.Resolver.ResolveProperty(structuredParentType.StructuredDefinition(), endPathToken.Identifier);

            if (property != null)
            {
                return(GeneratePropertyAccessQueryNode(singleValueParent as SingleResourceNode, property, state));
            }

            if (endPathToken.Identifier == ExpressionConstants.QueryOptionCount)
            {
                return(new CountVirtualPropertyNode());
            }

            if (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, singleValueParent, state, out boundFunction))
            {
                return(boundFunction);
            }

            return(GeneratePropertyAccessQueryForOpenType(endPathToken, singleValueParent));
        }
Пример #10
0
        /// <summary>
        /// Binds an In operator token.
        /// </summary>
        /// <param name="inToken">The In operator token to bind.</param>
        /// <param name="state">State of the metadata binding.</param>
        /// <returns>The bound In operator token.</returns>
        internal QueryNode BindInOperator(InToken inToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(inToken, "inToken");

            SingleValueNode left  = this.GetSingleValueOperandFromToken(inToken.Left);
            CollectionNode  right = this.GetCollectionOperandFromToken(
                inToken.Right, new EdmCollectionTypeReference(new EdmCollectionType(left.TypeReference)), state.Model);

            return(new InNode(left, right));
        }
Пример #11
0
        /// <summary>
        /// Creates a ParameterQueryNode for an explicit parameter.
        /// </summary>
        /// <param name="parameter">Name of the parameter.</param>
        /// <param name="nodeToIterateOver">CollectionNode that the parameter is iterating over.</param>
        /// <returns>A new RangeVariable.</returns>
        internal static RangeVariable CreateParameterNode(string parameter, CollectionNode nodeToIterateOver)
        {
            IEdmTypeReference elementType = nodeToIterateOver.ItemType;

            if (elementType != null && elementType.IsStructured())
            {
                var collectionResourceNode = nodeToIterateOver as CollectionResourceNode;
                Debug.Assert(collectionResourceNode != null, "IF the element type was structured, the node type should be a resource collection");
                return(new ResourceRangeVariable(parameter, elementType as IEdmStructuredTypeReference, collectionResourceNode));
            }

            return(new NonResourceRangeVariable(parameter, elementType, null));
        }
Пример #12
0
        /// <summary>
        /// Create a InNode
        /// </summary>
        /// <param name="left">The left operand.</param>
        /// <param name="right">The right operand.</param>
        /// <exception cref="System.ArgumentNullException">Throws if the left or right inputs are null.</exception>
        /// <exception cref="ODataException">Throws if the right operand single item type isn't the same type as the left operand.</exception>
        public InNode(SingleValueNode left, CollectionNode right)
        {
            ExceptionUtils.CheckArgumentNotNull(left, "left");
            ExceptionUtils.CheckArgumentNotNull(right, "right");
            this.left  = left;
            this.right = right;

            if (!this.left.GetEdmTypeReference().IsAssignableFrom(this.right.ItemType) &&
                !this.right.ItemType.IsAssignableFrom(this.left.GetEdmTypeReference()))
            {
                throw new ArgumentException(ODataErrorStrings.Nodes_InNode_CollectionItemTypeMustBeSameAsSingleItemType(
                                                this.right.ItemType.FullName(), this.left.GetEdmTypeReference().FullName()));
            }
        }
Пример #13
0
        /// <summary>
        /// Creates a <see cref="NonResourceRangeVariable"/>.
        /// </summary>
        /// <param name="name"> The name of the associated range variable.</param>
        /// <param name="typeReference">The type of the value the range variable represents.</param>
        /// <param name="collectionNode">The collection that this rangeVariable node iterates over, can be null in the case of single value nodes.</param>
        /// <exception cref="System.ArgumentNullException">Throws if the input name is null.</exception>
        /// <exception cref="ArgumentException">Throws if the input type reference is an entity type.</exception>
        public NonResourceRangeVariable(string name, IEdmTypeReference typeReference, CollectionNode collectionNode)
        {
            ExceptionUtils.CheckArgumentNotNull(name, "name");
            this.name = name;
            if (typeReference != null)
            {
                if (typeReference.Definition.TypeKind.IsStructured())
                {
                    // TODO: update message #644
                    throw new ArgumentException(
                              ODataErrorStrings.Nodes_NonentityParameterQueryNodeWithEntityType(typeReference.FullName()));
                }
            }

            this.typeReference  = typeReference;
            this.collectionNode = collectionNode;
        }
Пример #14
0
        /// <summary>
        /// Retrieves the type reference associated to a segment.
        /// </summary>
        /// <param name="segment">The node to retrive the type reference from.</param>
        /// <returns>The Type reference of the node (item type reference for collections).</returns>
        internal static IEdmTypeReference GetEdmTypeReference(this QueryNode segment)
        {
            SingleValueNode singleNode = segment as SingleValueNode;

            if (singleNode != null)
            {
                return(singleNode.TypeReference);
            }

            CollectionNode collectionNode = segment as CollectionNode;

            if (collectionNode != null)
            {
                return(collectionNode.ItemType);
            }

            return(null);
        }
Пример #15
0
        /// <summary>
        /// Retrieves type associated to a segment.
        /// </summary>
        /// <param name="segment">The node to retrieve the type from.</param>
        /// <returns>The type of the node, or item type for collections.</returns>
        internal static IEdmType GetEdmType(this QueryNode segment)
        {
            SingleValueNode singleNode = segment as SingleValueNode;

            if (singleNode != null)
            {
                IEdmTypeReference typeRef = singleNode.TypeReference;
                return((typeRef != null) ? typeRef.Definition : null);
            }

            CollectionNode collectionNode = segment as CollectionNode;

            if (collectionNode != null)
            {
                IEdmTypeReference typeRef = collectionNode.ItemType;
                return((typeRef != null) ? typeRef.Definition : null);
            }

            return(null);
        }
Пример #16
0
        /// <summary>
        /// Bind the parent of the LambdaToken
        /// </summary>
        /// <param name="queryToken">the parent token</param>
        /// <returns>the bound parent node</returns>
        private CollectionNode BindParentToken(QueryToken queryToken)
        {
            QueryNode      parentNode           = this.bindMethod(queryToken);
            CollectionNode parentCollectionNode = parentNode as CollectionNode;

            if (parentCollectionNode == null)
            {
                SingleValueOpenPropertyAccessNode parentOpenPropertyNode =
                    parentNode as SingleValueOpenPropertyAccessNode;

                if (parentOpenPropertyNode == null)
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_LambdaParentMustBeCollection);
                }

                // support open collection properties
                return(new CollectionOpenPropertyAccessNode(parentOpenPropertyNode.Source, parentOpenPropertyNode.Name));
            }

            return(parentCollectionNode);
        }
Пример #17
0
        /// <summary>
        /// Retrieve CollectionNode bound with given query token.
        /// </summary>
        /// <param name="queryToken">The query token</param>
        /// <param name="expectedType">The expected type that this collection holds</param>
        /// <param name="model">The Edm model</param>
        /// <returns>The corresponding CollectionNode</returns>
        private CollectionNode GetCollectionOperandFromToken(QueryToken queryToken, IEdmTypeReference expectedType, IEdmModel model)
        {
            CollectionNode operand      = null;
            LiteralToken   literalToken = queryToken as LiteralToken;

            if (literalToken != null)
            {
                string originalLiteralText = literalToken.OriginalText;

                // Parentheses-based collections are not standard JSON but bracket-based ones are.
                // Temporarily switch our collection to bracket-based so that the JSON reader will
                // correctly parse the collection. Then pass the original literal text to the token.
                string bracketLiteralText = originalLiteralText;
                if (bracketLiteralText[0] == '(')
                {
                    Debug.Assert(bracketLiteralText[bracketLiteralText.Length - 1] == ')',
                                 "Collection with opening '(' should have corresponding ')'");

                    StringBuilder replacedText = new StringBuilder(bracketLiteralText);
                    replacedText[0] = '[';
                    replacedText[replacedText.Length - 1] = ']';
                    bracketLiteralText = replacedText.ToString();
                }

                object       collection             = ODataUriConversionUtils.ConvertFromCollectionValue(bracketLiteralText, model, expectedType);
                LiteralToken collectionLiteralToken = new LiteralToken(collection, originalLiteralText, expectedType);
                operand = this.bindMethod(collectionLiteralToken) as CollectionConstantNode;
            }
            else
            {
                operand = this.bindMethod(queryToken) as CollectionNode;
            }

            if (operand == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_RightOperandNotCollectionValue);
            }

            return(operand);
        }
Пример #18
0
        /// <summary>
        /// Try to bind an identifier to a FunctionCallNode
        /// </summary>
        /// <param name="identifier">the identifier to bind</param>
        /// <param name="arguments">the semantically bound list of arguments.</param>
        /// <param name="parent">a semantically bound parent node.</param>
        /// <param name="state">the current state of the binding algorithm</param>
        /// <param name="boundFunction">a single value function call node representing this function call, if we found one.</param>
        /// <returns>true if we found a function for this token.</returns>
        private bool TryBindIdentifier(string identifier, IEnumerable <FunctionParameterToken> arguments, QueryNode parent, BindingState state, out QueryNode boundFunction)
        {
            boundFunction = null;

            IEdmType        bindingType       = null;
            SingleValueNode singleValueParent = parent as SingleValueNode;

            if (singleValueParent != null)
            {
                if (singleValueParent.TypeReference != null)
                {
                    bindingType = singleValueParent.TypeReference.Definition;
                }
            }
            else
            {
                CollectionNode collectionValueParent = parent as CollectionNode;
                if (collectionValueParent != null)
                {
                    bindingType = collectionValueParent.CollectionType.Definition;
                }
            }

            if (!UriEdmHelpers.IsBindingTypeValid(bindingType))
            {
                return(false);
            }

            // All functions should be fully qualified, if they aren't they they aren't functions.
            // When using extension, there may be function call with unqualified name. So loose the restriction here.
            if (identifier.IndexOf(".", StringComparison.Ordinal) == -1 && this.Resolver.GetType() == typeof(ODataUriResolver))
            {
                return(false);
            }

            IEdmOperation operation;
            List <FunctionParameterToken> syntacticArguments = arguments == null ? new List <FunctionParameterToken>() : arguments.ToList();

            if (!FunctionOverloadResolver.ResolveOperationFromList(identifier, syntacticArguments.Select(ar => ar.ParameterName).ToList(), bindingType, state.Model, out operation, this.Resolver))
            {
                // TODO: FunctionOverloadResolver.ResolveOperationFromList() looks up the function by parameter names, but it shouldn't ignore parameter types. (test case ParseFilter_AliasInFunction_PropertyAsValue_TypeMismatch should fail)
                return(false);
            }

            if (singleValueParent != null && singleValueParent.TypeReference == null)
            {
                // if the parent exists, but has no type information, then we're in open type land, and we
                // shouldn't go any farther.
                throw new ODataException(ODataErrorStrings.FunctionCallBinder_CallingFunctionOnOpenProperty(identifier));
            }

            if (operation.IsAction())
            {
                return(false);
            }

            IEdmFunction function = (IEdmFunction)operation;

            // TODO:  $filter $orderby parameter expression which contains complex or collection should NOT be supported in this way
            //     but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p));
            ICollection <FunctionParameterToken> parsedParameters = HandleComplexOrCollectionParameterValueIfExists(state.Configuration.Model, function, syntacticArguments, state.Configuration.Resolver.EnableCaseInsensitive);

            IEnumerable <QueryNode> boundArguments = parsedParameters.Select(p => this.bindMethod(p));

            boundArguments = boundArguments.ToList(); // force enumerable to run : will immediately evaluate all this.bindMethod(p).
            IEdmTypeReference  returnType       = function.ReturnType;
            IEdmEntitySetBase  returnSet        = null;
            SingleResourceNode singleEntityNode = parent as SingleResourceNode;

            if (singleEntityNode != null)
            {
                returnSet = function.GetTargetEntitySet(singleEntityNode.NavigationSource, state.Model);
            }

            string functionName = function.FullName();

            if (returnType.IsEntity())
            {
                boundFunction = new SingleResourceFunctionCallNode(functionName, new[] { function }, boundArguments, (IEdmEntityTypeReference)returnType.Definition.ToTypeReference(), returnSet, parent);
            }
            else if (returnType.IsStructuredCollection())
            {
                IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType;
                boundFunction = new CollectionResourceFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, returnSet, parent);
            }
            else if (returnType.IsCollection())
            {
                IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType;
                boundFunction = new CollectionFunctionCallNode(functionName, new[] { function }, boundArguments, collectionTypeReference, parent);
            }
            else
            {
                boundFunction = new SingleValueFunctionCallNode(functionName, new[] { function }, boundArguments,
                                                                returnType, parent);
            }

            return(true);
        }