/// <summary>
        /// Processes the filter of the query (if any).
        /// </summary>
        /// <param name="query">The query tree constructed so far.</param>
        /// <param name="filter">The filter to bind.</param>
        /// <returns>If no filter is specified, returns the <paramref name="query"/> unchanged. If a filter is specified it returns the combined query including the filter.</returns>
        private QueryNode ProcessFilter(QueryNode query, QueryToken filter)
        {
            ExceptionUtils.CheckArgumentNotNull(query, "query");

            if (filter != null)
            {
                CollectionQueryNode entityCollection = query.AsEntityCollectionNode();
                if (entityCollection == null)
                {
                    throw new ODataException(Strings.MetadataBinder_FilterNotApplicable);
                }

                this.parameter = new ParameterQueryNode() { ParameterType = entityCollection.ItemType };

                QueryNode expressionNode = this.Bind(filter);

                SingleValueQueryNode expressionResultNode = expressionNode as SingleValueQueryNode;
                if (expressionResultNode == null ||
                    (expressionResultNode.TypeReference != null && !expressionResultNode.TypeReference.IsODataPrimitiveTypeKind()))
                {
                    throw new ODataException(Strings.MetadataBinder_FilterExpressionNotSingleValue);
                }

                // The type may be null here if the query statically represents the null literal
                // TODO: once we support open types/properties a 'null' type will mean 'we don't know the type'. Review.
                IEdmTypeReference expressionResultType = expressionResultNode.TypeReference;
                if (expressionResultType != null)
                {
                    IEdmPrimitiveTypeReference primitiveExpressionResultType = expressionResultType.AsPrimitiveOrNull();
                    if (primitiveExpressionResultType == null || primitiveExpressionResultType.PrimitiveKind() != EdmPrimitiveTypeKind.Boolean)
                    {
                        throw new ODataException(Strings.MetadataBinder_FilterExpressionNotSingleValue);
                    }
                }

                query = new FilterQueryNode()
                {
                    Collection = entityCollection,
                    Parameter = this.parameter,
                    Expression = expressionResultNode
                };

                this.parameter = null;
            }

            return query;
        }
        /// <summary>
        /// Processes the specified order-by token.
        /// </summary>
        /// <param name="query">The query tree constructed so far.</param>
        /// <param name="orderByToken">The order-by token to bind.</param>
        /// <returns>Returns the combined query including the ordering.</returns>
        private QueryNode ProcessSingleOrderBy(QueryNode query, OrderByQueryToken orderByToken)
        {
            Debug.Assert(query != null, "query != null");
            ExceptionUtils.CheckArgumentNotNull(orderByToken, "orderByToken");

            CollectionQueryNode entityCollection = query.AsEntityCollectionNode();
            if (entityCollection == null)
            {
                throw new ODataException(Strings.MetadataBinder_OrderByNotApplicable);
            }

            this.parameter = new ParameterQueryNode() { ParameterType = entityCollection.ItemType };

            QueryNode expressionNode = this.Bind(orderByToken.Expression);

            // TODO: shall we really restrict order-by expressions to primitive types?
            SingleValueQueryNode expressionResultNode = expressionNode as SingleValueQueryNode;
            if (expressionResultNode == null ||
                (expressionResultNode.TypeReference != null && !expressionResultNode.TypeReference.IsODataPrimitiveTypeKind()))
            {
                throw new ODataException(Strings.MetadataBinder_OrderByExpressionNotSingleValue);
            }

            query = new OrderByQueryNode()
            {
                Collection = entityCollection,
                Direction = orderByToken.Direction,
                Parameter = this.parameter,
                Expression = expressionResultNode
            };

            this.parameter = null;

            return query;
        }
        /// <summary>
        /// Binds a <see cref="NavigationPropertyToken"/>.
        /// </summary>
        /// <param name="segmentToken">The segment token to bind.</param>
        /// <returns>The bound node.</returns>
        private SingleValueQueryNode BindNavigationProperty(NavigationPropertyToken segmentToken)
        {
            QueryNode source = null;
            IEdmNavigationProperty property;
            if (segmentToken.Parent != null)
            {
                source = this.Bind(segmentToken.Parent);
                IEdmType entityType = null;
                if (IsDerivedComplexType(segmentToken, GetType(source)))
                {
                    IEdmProperty returnProperty = BindProperty(GetType(source).ToTypeReference(), segmentToken.Name);
                    return new PropertyAccessQueryNode()
                    {
                        Source = (SingleValueQueryNode)source,
                        Property = returnProperty
                    };
                }
                else
                {
                    entityType = GetType(source);
                }

                ParameterQueryNode parentNode = new ParameterQueryNode
                                                    { ParameterType = entityType.ToTypeReference() };
                property = (IEdmNavigationProperty)BindProperty(parentNode.TypeReference, segmentToken.Name);
            }
            else
            {
                if (IsDerivedComplexType(segmentToken, this.parameter.TypeReference.Definition))
                {
                    IEdmProperty returnProperty = BindProperty(new EdmEntityTypeReference((IEdmEntityType)this.parameter.TypeReference.Definition, true), segmentToken.Name);
                    return new PropertyAccessQueryNode
                    {
                        Source = this.parameter,
                        Property = returnProperty
                    };
                }

                property = (IEdmNavigationProperty)BindProperty(this.parameter.TypeReference, segmentToken.Name);
            }

                // Ensure that only collections head Any queries and nothing else
                if (property.OwnMultiplicity() == EdmMultiplicity.Many && segmentToken.AnyAllParent == false)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(segmentToken.Name));
                }
                else if (property.OwnMultiplicity() != EdmMultiplicity.Many && segmentToken.AnyAllParent == true)
                {
                    throw new ODataException(Strings.MetadataBinder_InvalidAnyAllHead);
                }

                return new NavigationPropertyNode() { Source = source, NavigationProperty = property };
        }
        /// <summary>
        /// Binds a property access token.
        /// </summary>
        /// <param name="propertyAccessToken">The property access token to bind.</param>
        /// <returns>The bound property access token.</returns>
        protected virtual QueryNode BindPropertyAccess(PropertyAccessQueryToken propertyAccessToken)
        {
            ExceptionUtils.CheckArgumentNotNull(propertyAccessToken, "propertyAccessToken");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(propertyAccessToken.Name, "propertyAccessToken.Name");

            SingleValueQueryNode parentNode;
            SingleValueQueryNode navigationPath = null;

            // Set the parentNode (get the parent type, so you can check whether the Name inside propertyAccessToken really is legit offshoot of the parent type)
            QueryNode parent = null;
            if (propertyAccessToken.Parent == null)
            {
                if (this.parameter == null)
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyAccessWithoutParentParameter);
                }

                parentNode = this.parameter;
                parent = this.parameter;
            }
            else
            {
                    parent = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode;
                    if (parent == null)
                    {
                        throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(propertyAccessToken.Name));
                    }

                    NavigationPropertyNode parentNav = parent as NavigationPropertyNode;
                    CastNode parentCast = parent as CastNode;
                    PropertyAccessQueryNode parentProperty = parent as PropertyAccessQueryNode;

                    if (parentProperty != null)
                    {
                        navigationPath = parentProperty;
                        var propertyPath = (IEdmStructuralProperty)parentProperty.Property;
                        parentNode = new ParameterQueryNode()
                                         {
                                             ParameterType = propertyPath.Type
                                         };
                    }
                    else if (parentCast != null)
                    {
                        IEdmType entityType = parentCast.EdmType;
                        parentNode = new ParameterQueryNode()
                        {
                            ParameterType = entityType.ToTypeReference()
                        };
                    }
                    else if (parentNav != null)
                    {
                        navigationPath = parentNav;
                        IEdmEntityType entityType = parentNav.NavigationProperty.ToEntityType();
                        parentNode = new ParameterQueryNode()
                        {
                            ParameterType = new EdmEntityTypeReference(entityType, true)
                        };
                    }
                    else
                    {
                        parentNode = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode;
                    }
            }

            // Now that we have the parent type, can find its corresponding EDM type
            IEdmStructuredTypeReference structuredParentType =
                parentNode.TypeReference == null ? null : parentNode.TypeReference.AsStructuredOrNull();
            IEdmProperty property =
                structuredParentType == null ? null : structuredParentType.FindProperty(propertyAccessToken.Name);

            if (property != null)
            {
                // TODO: Check that we have entity set once we add the entity set propagation into the bound tree
                // See RequestQueryParser.ExpressionParser.ParseMemberAccess
                if (property.Type.IsNonEntityODataCollectionTypeKind())
                {
                    throw new ODataException(Strings.MetadataBinder_MultiValuePropertyNotSupportedInExpression(property.Name));
                }

                if (property.PropertyKind == EdmPropertyKind.Navigation)
                {
                    // TODO: Implement navigations
                    throw new NotImplementedException();
                }

                if (navigationPath != null)
                {
                    parentNode = navigationPath;
                }

                return new PropertyAccessQueryNode()
                {
                    Source = (SingleValueQueryNode)parent,
                    Property = property
                };
            }
            else
            {
                if (parentNode.TypeReference != null && !parentNode.TypeReference.Definition.IsOpenType())
                {
                    throw new ODataException(Strings.MetadataBinder_PropertyNotDeclared(parentNode.TypeReference.ODataFullName(), propertyAccessToken.Name));
                }

                // TODO: Implement open property support
                throw new NotImplementedException();
            }
        }
 private Expression BindParameterQueryNode(ParameterQueryNode parameterNode)
 {
     return(_lambdaParameters[parameterNode.Name]);
 }
        /// <summary>
        /// Translates a parameter node.
        /// </summary>
        /// <param name="parameterNode">The parameter node to translate.</param>
        /// <returns>Expression which evaluates to the result of the parameter.</returns>
        protected virtual Expression TranslateParameter(ParameterQueryNode parameterNode)
        {
            ExceptionUtils.CheckArgumentNotNull(parameterNode, "parameterNode");

            if (this.parameterNodeDefinitions.Count == 0)
            {
                throw new ODataException(Strings.QueryExpressionTranslator_ParameterNotDefinedInScope);
            }

            KeyValuePair<ParameterQueryNode, Expression> currentParameter = this.parameterNodeDefinitions.Peek();
            if (!object.ReferenceEquals(currentParameter.Key, parameterNode))
            {
                throw new ODataException(Strings.QueryExpressionTranslator_ParameterNotDefinedInScope);
            }

            return currentParameter.Value;
        }
        /// <summary>
        /// Processes the filter of the query (if any).
        /// </summary>
        /// <param name="query">The query tree constructed so far.</param>
        /// <param name="filter">The filter to bind.</param>
        /// <returns>If no filter is specified, returns the <paramref name="query"/> unchanged. If a filter is specified it returns the combined query including the filter.</returns>
        private QueryNode ProcessFilter(QueryNode query, QueryToken filter)
        {
            ExceptionUtils.CheckArgumentNotNull(query, "query");

            if (filter != null)
            {
                CollectionQueryNode entityCollection = query.AsEntityCollectionNode();
                if (entityCollection == null)
                {
                    throw new ODataException(Strings.MetadataBinder_FilterNotApplicable);
                }

                this.parameter = new ParameterQueryNode() { ParameterResourceType = entityCollection.ItemType };

                QueryNode expressionNode = this.Bind(filter);

                SingleValueQueryNode expressionResultNode = expressionNode as SingleValueQueryNode;
                if (expressionResultNode == null ||
                    (expressionResultNode.ResourceType != null && expressionResultNode.ResourceType.ResourceTypeKind != ResourceTypeKind.Primitive))
                {
                    throw new ODataException(Strings.MetadataBinder_FilterExpressionNotSingleValue);
                }

                // The resource type may be null here if the query statically represents the null literal
                // TODO: once we support open types/properties a 'null' resource type will mean 'we don't know the type'. Review.
                if (expressionResultNode.ResourceType != null &&
                    !this.ResourceTypesEqual(expressionResultNode.ResourceType, PrimitiveTypeUtils.BoolResourceType) &&
                    !this.ResourceTypesEqual(expressionResultNode.ResourceType, PrimitiveTypeUtils.NullableBoolResourceType))
                {
                    throw new ODataException(Strings.MetadataBinder_FilterExpressionNotSingleValue);
                }

                query = new FilterQueryNode()
                {
                    Collection = entityCollection,
                    Parameter = this.parameter,
                    Expression = expressionResultNode
                };

                this.parameter = null;
            }

            return query;
        }