Esempio n. 1
0
        /// <summary>
        /// Builds an appropriate navigation query node (collection or single) for the given property and parent node.
        /// </summary>
        /// <param name="property">Navigation property.</param>
        /// <param name="parent">Parent Node.</param>
        /// <param name="namedValues">Named values (key values) that were included in the node we are binding, if any.</param>
        /// <param name="state">State of binding.</param>
        /// <param name="keyBinder">Object to perform binding on any key values that are present.</param>
        /// <param name="navigationSource">The navigation source of the navigation node.</param>
        /// <returns>A new CollectionNavigationNode or SingleNavigationNode to capture the navigation property access.</returns>
        internal static QueryNode GetNavigationNode(IEdmNavigationProperty property, SingleResourceNode parent, IEnumerable <NamedValue> namedValues, BindingState state, KeyBinder keyBinder, out IEdmNavigationSource navigationSource)
        {
            ExceptionUtils.CheckArgumentNotNull(property, "property");
            ExceptionUtils.CheckArgumentNotNull(parent, "parent");
            ExceptionUtils.CheckArgumentNotNull(state, "state");
            ExceptionUtils.CheckArgumentNotNull(keyBinder, "keyBinder");

            // Handle collection navigation property
            if (property.TargetMultiplicity() == EdmMultiplicity.Many)
            {
                CollectionNavigationNode collectionNavigationNode = new CollectionNavigationNode(parent, property, state.ParsedSegments);
                navigationSource = collectionNavigationNode.NavigationSource;

                // Doing key lookup on the collection navigation property
                if (namedValues != null)
                {
                    return(keyBinder.BindKeyValues(collectionNavigationNode, namedValues, state.Model));
                }

                // Otherwise it's just a normal collection of entities
                return(collectionNavigationNode);
            }

            Debug.Assert(namedValues == null || !namedValues.Any(), "namedValues should not exist if it isn't a collection");

            // Otherwise it's a single navigation property
            SingleNavigationNode singleNavigationNode = new SingleNavigationNode(parent, property, state.ParsedSegments);

            navigationSource = singleNavigationNode.NavigationSource;
            return(singleNavigationNode);
        }
Esempio n. 2
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));
        }
        /// <summary>
        /// Constructs a <see cref="SingleValuePropertyAccessNode"/>.
        /// </summary>
        /// <param name="source">The value containing this property.</param>
        /// <param name="property">The EDM property which is to be accessed.</param>
        /// <exception cref="System.ArgumentNullException">Throws if input source or property is null.</exception>
        /// <exception cref="ArgumentException">Throws if input property is not structural, or is a collection.</exception>
        public AggregatedCollectionPropertyNode(CollectionNavigationNode source, IEdmProperty property)
        {
            ExceptionUtils.CheckArgumentNotNull(source, "source");
            ExceptionUtils.CheckArgumentNotNull(property, "property");

            if (property.PropertyKind != EdmPropertyKind.Structural)
            {
                throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessShouldBeNonEntityProperty(property.Name));
            }

            if (property.Type.IsCollection())
            {
                throw new ArgumentException(ODataErrorStrings.Nodes_PropertyAccessTypeShouldNotBeCollection(property.Name));
            }

            this.source           = source;
            this.property         = property;
            this.typeReference    = property.Type.AsComplex();
            this.navigationSource = source.NavigationSource;
        }
Esempio n. 4
0
 /// <summary>
 /// Visit a CollectionNavigationNode
 /// </summary>
 /// <param name="nodeIn">the node to visit</param>
 /// <returns>Defined by the implementer</returns>
 public virtual T Visit(CollectionNavigationNode nodeIn)
 {
     throw new NotImplementedException();
 }
Esempio n. 5
0
        /// <summary>
        /// Binds 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)
            {
                // 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 (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, singleValueParent, state, out boundFunction))
                {
                    return(boundFunction);
                }

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

                return(GeneratePropertyAccessQueryForOpenType(endPathToken, singleValueParent));
            }

            // 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));
            }

            CollectionNavigationNode collectionParent = parent as CollectionNavigationNode;

            if (collectionParent != null)
            {
                IEdmEntityTypeReference parentType = collectionParent.EntityItemType;
                IEdmProperty            property   = this.Resolver.ResolveProperty(parentType.StructuredDefinition(), endPathToken.Identifier);

                if (property.PropertyKind == EdmPropertyKind.Structural &&
                    !property.Type.IsCollection() &&
                    this.state.AggregatedPropertyNames != null &&
                    this.state.AggregatedPropertyNames.Any(p => p == collectionParent.NavigationProperty.Name))
                {
                    return(new AggregatedCollectionPropertyNode(collectionParent, property));
                }
            }

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

            throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessSourceNotSingleValue(endPathToken.Identifier));
        }
        /// <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);
                }

                CollectionNavigationNode collectionParent = parent as CollectionNavigationNode;

                if (collectionParent != null)
                {
                    IEdmEntityTypeReference parentType         = collectionParent.EntityItemType;
                    IEdmProperty            collectionProperty = this.Resolver.ResolveProperty(parentType.StructuredDefinition(), segmentToken.Identifier);
                    if (collectionProperty != null && collectionProperty.PropertyKind == EdmPropertyKind.Structural)
                    {
                        return(new AggregatedCollectionPropertyNode(collectionParent, collectionProperty));
                    }
                }

                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 new ODataException(
                              ODataErrorStrings.MetadataBinder_PropertyNotDeclared(
                                  parent.GetEdmTypeReference().FullName(), segmentToken.Identifier));
                }

                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);
        }