Exemplo n.º 1
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));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Determines the parent node. If the token has a parent, that token is bound. If not, then we
        /// use the implicit parameter from the BindingState as the parent node.
        /// </summary>
        /// <param name="segmentToken">Token to determine the parent node for.</param>
        /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns>
        private QueryNode DetermineParentNode(EndPathToken segmentToken)
        {
            ExceptionUtils.CheckArgumentNotNull(segmentToken, "segmentToken");
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            if (segmentToken.NextToken != null)
            {
                return(this.bindMethod(segmentToken.NextToken));
            }
            else
            {
                RangeVariable implicitRangeVariable = state.ImplicitRangeVariable;
                return(NodeFactory.CreateRangeVariableReferenceNode(implicitRangeVariable));
            }
        }
Exemplo n.º 3
0
        internal AggregateTokenBase ParseAggregateExpression()
        {
            try
            {
                this.parseAggregateExpresionDepth++;

                // expression
                QueryToken expression = ParseLogicalOr();

                if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.OpenParen)
                {
                    // When there's a parenthesis after the expression we have a entity set aggregation.
                    // The syntax is the same as the aggregate expression itself, so we recurse on ParseAggregateExpressions.
                    this.aggregateExpressionParents.Push(expression);
                    List <AggregateTokenBase> statements = ParseAggregateExpressions();
                    this.aggregateExpressionParents.Pop();

                    return(new EntitySetAggregateToken(expression, statements));
                }

                AggregationMethodDefinition verb;

                // "with" verb
                EndPathToken endPathExpression = expression as EndPathToken;
                if (endPathExpression != null && endPathExpression.Identifier == ExpressionConstants.QueryOptionCount)
                {
                    // e.g. aggregate($count as Count)
                    verb = AggregationMethodDefinition.VirtualPropertyCount;
                }
                else
                {
                    // e.g. aggregate(UnitPrice with sum as Total)
                    verb = this.ParseAggregateWith();
                }

                // "as" alias
                StringLiteralToken alias = this.ParseAggregateAs();

                return(new AggregateExpressionToken(expression, verb, alias.Text));
            }
            finally
            {
                this.parseAggregateExpresionDepth--;
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Try to bind an end path token as a function call. Used for bound functions without parameters
 /// that parse as end path tokens syntactically
 /// </summary>
 /// <param name="endPathToken">the end path token to bind</param>
 /// <param name="parent">the parent node to this end path token.</param>
 /// <param name="state">the current state of the binding algorithm</param>
 /// <param name="boundFunction">a single value function call node representing the function call, if it exists</param>
 /// <returns>true if we found a function for this token, false otherwise.</returns>
 internal bool TryBindEndPathAsFunctionCall(EndPathToken endPathToken, QueryNode parent, BindingState state, out QueryNode boundFunction)
 {
     return(this.TryBindIdentifier(endPathToken.Identifier, null, parent, state, out boundFunction));
 }
Exemplo n.º 5
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));
        }
Exemplo n.º 6
0
 /// <summary>
 /// This method generates a <see cref="SingleValueOpenPropertyAccessNode"/> for properties of open type
 /// </summary>
 /// <param name="endPathToken">EndPathToken to bind into an open property node.</param>
 /// <param name="parentNode">Parent node of this open property</param>
 /// <returns>Will return a <see cref="SingleValueOpenPropertyAccessNode"/> when open types are supported</returns>
 internal SingleValueOpenPropertyAccessNode GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode)
 {
     if (parentNode.TypeReference == null ||
         parentNode.TypeReference.Definition.IsOpen() ||
         IsAggregatedProperty(endPathToken.Identifier))
     {
         return(new SingleValueOpenPropertyAccessNode(parentNode, endPathToken.Identifier));
     }
     else
     {
         throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(
                                      parentNode.TypeReference.FullName(),
                                      endPathToken.Identifier));
     }
 }
Exemplo n.º 7
0
        /// <summary>
        /// Binds a property access token.
        /// </summary>
        /// <param name="endPathToken">The property access token to bind.</param>
        /// <returns>The bound property access token.</returns>
        protected virtual QueryNode BindEndPath(EndPathToken endPathToken)
        {
            EndPathBinder endPathBinder = new EndPathBinder(this.Bind, this.BindingState);

            return(endPathBinder.BindEndPath(endPathToken));
        }
Exemplo n.º 8
0
 /// <summary>
 /// Determines the token if represents an aggregated property or not.
 /// </summary>
 /// <param name="endPath">EndPathToken to check in the list of aggregated properties.</param>
 /// <returns>Whether the token represents an aggregated property.</returns>
 private bool IsAggregatedProperty(EndPathToken endPath) => state?.AggregatedPropertyNames?.Contains(endPath) ?? false;
Exemplo n.º 9
0
 /// <summary>
 /// Visits an EndPathToken
 /// </summary>
 /// <param name="tokenIn">The EndPathToken to bind</param>
 /// <returns>A PropertyAccessClause bound to this EndPathToken</returns>
 public virtual T Visit(EndPathToken tokenIn)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 10
0
 /// <summary>
 /// This method generates a <see cref="SingleValueOpenPropertyAccessNode"/> for properties of open type
 /// </summary>
 /// <param name="endPathToken">EndPathToken to bind into an open property node.</param>
 /// <param name="parentNode">Parent node of this open property</param>
 /// <returns>Will return a <see cref="SingleValueOpenPropertyAccessNode"/> when open types are supported</returns>
 internal SingleValueOpenPropertyAccessNode GeneratePropertyAccessQueryForOpenType(EndPathToken endPathToken, SingleValueNode parentNode)
 {
     if (parentNode.TypeReference == null ||
         parentNode.TypeReference.Definition.IsOpen() ||
         IsAggregatedProperty(endPathToken.Identifier))
     {
         return(new SingleValueOpenPropertyAccessNode(parentNode, endPathToken.Identifier));
     }
     else
     {
         throw ExceptionUtil.CreatePropertyNotFoundException(endPathToken.Identifier, parentNode.TypeReference.FullName());
     }
 }