Ejemplo n.º 1
0
        private GroupByTransformationNode BindGroupByToken(GroupByToken token)
        {
            List <GroupByPropertyNode> properties = new List <GroupByPropertyNode>();

            foreach (EndPathToken propertyToken in token.Properties)
            {
                QueryNode bindResult = this.bindMethod(propertyToken);
                SingleValuePropertyAccessNode property        = bindResult as SingleValuePropertyAccessNode;
                SingleComplexNode             complexProperty = bindResult as SingleComplexNode;

                if (property != null)
                {
                    RegisterProperty(properties, ReversePropertyPath(property));
                }
                else if (complexProperty != null)
                {
                    RegisterProperty(properties, ReversePropertyPath(complexProperty));
                }
                else
                {
                    SingleValueOpenPropertyAccessNode openProperty = bindResult as SingleValueOpenPropertyAccessNode;
                    if (openProperty != null)
                    {
                        IEdmTypeReference type = GetTypeReferenceByPropertyName(openProperty.Name);
                        properties.Add(new GroupByPropertyNode(openProperty.Name, openProperty, type));
                    }
                    else
                    {
                        throw new ODataException(
                                  ODataErrorStrings.ApplyBinder_GroupByPropertyNotPropertyAccessValue(propertyToken.Identifier));
                    }
                }
            }

            var newProperties = new HashSet <EndPathToken>(((GroupByToken)token).Properties);

            TransformationNode aggregate = null;

            if (token.Child != null)
            {
                if (token.Child.Kind == QueryTokenKind.Aggregate)
                {
                    aggregate = BindAggregateToken((AggregateToken)token.Child);
                    aggregateExpressionsCache = ((AggregateTransformationNode)aggregate).AggregateExpressions;
                    newProperties.UnionWith(aggregateExpressionsCache.Select(statement => new EndPathToken(statement.Alias, null)));
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.ApplyBinder_UnsupportedGroupByChild(token.Child.Kind));
                }
            }

            state.AggregatedPropertyNames = newProperties;

            // TODO: Determine source
            return(new GroupByTransformationNode(properties, aggregate, null));
        }
Ejemplo n.º 2
0
        private GroupByTransformationNode BindGroupByToken(GroupByToken token)
        {
            var properties = new List <GroupByPropertyNode>();

            foreach (var propertyToken in token.Properties)
            {
                var bindResult      = this.bindMethod(propertyToken);
                var property        = bindResult as SingleValuePropertyAccessNode;
                var complexProperty = bindResult as SingleComplexNode;

                if (property != null)
                {
                    RegisterProperty(properties, ReversePropertyPath(property));
                }
                else if (complexProperty != null)
                {
                    RegisterProperty(properties, ReversePropertyPath(complexProperty));
                }
                else
                {
                    var openProperty = bindResult as SingleValueOpenPropertyAccessNode;
                    if (openProperty != null)
                    {
                        var type = GetTypeReferenceByPropertyName(openProperty.Name);
                        properties.Add(new GroupByPropertyNode(openProperty.Name, openProperty, type));
                    }
                    else
                    {
                        throw new ODataException(
                                  ODataErrorStrings.ApplyBinder_GroupByPropertyNotPropertyAccessValue(propertyToken.Identifier));
                    }
                }
            }

            TransformationNode aggregate = null;

            if (token.Child != null)
            {
                if (token.Child.Kind == QueryTokenKind.Aggregate)
                {
                    aggregate = BindAggregateToken((AggregateToken)token.Child);
                    aggregateExpressionsCache     = ((AggregateTransformationNode)aggregate).Expressions;
                    state.AggregatedPropertyNames =
                        aggregateExpressionsCache.Select(statement => statement.Alias).ToList();
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.ApplyBinder_UnsupportedGroupByChild(token.Child.Kind));
                }
            }

            // TODO: Determine source
            return(new GroupByTransformationNode(properties, aggregate, null));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Build a segment from a token.
        /// </summary>
        /// <param name="tokenIn">the token to bind</param>
        /// <param name="model">The model.</param>
        /// <param name="edmType">the type of the current scope based on type segments.</param>
        /// <param name="resolver">Resolver for uri parser.</param>
        /// <param name="state">The binding state.</param>
        /// <returns>The segment created from the token.</returns>
        public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver, BindingState state = null)
        {
            ExceptionUtils.CheckArgumentNotNull(resolver, "resolver");

            ODataPathSegment nextSegment;

            if (UriParserHelper.IsAnnotation(tokenIn.Identifier))
            {
                if (TryBindAsDeclaredTerm(tokenIn, model, resolver, out nextSegment))
                {
                    return(nextSegment);
                }

                string qualifiedTermName = tokenIn.Identifier.Remove(0, 1);
                int    separator         = qualifiedTermName.LastIndexOf(".", StringComparison.Ordinal);
                string namespaceName     = qualifiedTermName.Substring(0, separator);
                string termName          = qualifiedTermName.Substring(separator == 0 ? 0 : separator + 1);

                // Don't allow selecting odata control information
                if (String.Compare(namespaceName, ODataConstants.ODataPrefix, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(tokenIn.Identifier));
                }

                return(new AnnotationSegment(new EdmTerm(namespaceName, termName, EdmCoreModel.Instance.GetUntyped())));
            }

            EndPathToken endPathToken = new EndPathToken(tokenIn.Identifier, null);

            if ((state?.IsCollapsed ?? false) && !(state?.AggregatedPropertyNames?.Contains(endPathToken) ?? false))
            {
                throw new ODataException(ODataErrorStrings.ApplyBinder_GroupByPropertyNotPropertyAccessValue(tokenIn.Identifier));
            }

            if (TryBindAsDeclaredProperty(tokenIn, edmType, resolver, out nextSegment))
            {
                return(nextSegment);
            }

            // Operations must be container-qualified, and because the token type indicates it was not a .-separated identifier, we should not try to look up operations.
            if (tokenIn.IsNamespaceOrContainerQualified())
            {
                if (TryBindAsOperation(tokenIn, model, edmType, out nextSegment))
                {
                    return(nextSegment);
                }

                // If an action or function is requested in a selectItem using a qualifiedActionName or a qualifiedFunctionName
                // and that operation cannot be bound to the entities requested, the service MUST ignore the selectItem.
                if (!edmType.IsOpen)
                {
                    return(null);
                }
            }

            if (edmType.IsOpen || (state?.AggregatedPropertyNames?.Contains(endPathToken) ?? false))
            {
                return(new DynamicPathSegment(tokenIn.Identifier));
            }

            throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(edmType.FullTypeName(), tokenIn.Identifier));
        }
Ejemplo n.º 4
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)
            {
                if (endPathToken.Identifier == ExpressionConstants.QueryOptionCount)
                {
                    return(new CountVirtualPropertyNode());
                }

                if (state.IsCollapsed && !IsAggregatedProperty(endPathToken))
                {
                    throw new ODataException(ODataErrorStrings.ApplyBinder_GroupByPropertyNotPropertyAccessValue(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 (functionCallBinder.TryBindEndPathAsFunctionCall(endPathToken, singleValueParent, state, out boundFunction))
                {
                    return(boundFunction);
                }

                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.InEntitySetAggregation)
                {
                    return(new AggregatedCollectionPropertyNode(collectionParent, property));
                }
            }

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

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