예제 #1
0
        /// <summary>
        /// Bind a parameter alias which is inside another alias value.
        /// </summary>
        /// <param name="bindingState">The alias name which is inside another alias value.</param>
        /// <param name="aliasToken">The cache of alias value nodes</param>
        /// <returns>The semantics node tree for alias (the @p1 in "@p1=...", not alias value expression)</returns>
        internal ParameterAliasNode BindParameterAlias(BindingState bindingState, FunctionParameterAliasToken aliasToken)
        {
            ExceptionUtils.CheckArgumentNotNull(bindingState, "bindingState");
            ExceptionUtils.CheckArgumentNotNull(aliasToken, "aliasToken");

            string alias = aliasToken.Alias;
            ParameterAliasValueAccessor aliasValueAccessor = bindingState.Configuration.ParameterAliasValueAccessor;
            if (aliasValueAccessor == null)
            {
                return new ParameterAliasNode(alias, null);
            }

            // in cache?
            SingleValueNode aliasValueNode = null;
            if (!aliasValueAccessor.ParameterAliasValueNodesCached.TryGetValue(alias, out aliasValueNode))
            {
                // has value expression?
                string aliasValueExpression = aliasValueAccessor.GetAliasValueExpression(alias);
                if (aliasValueExpression == null)
                {
                    aliasValueAccessor.ParameterAliasValueNodesCached[alias] = null;
                }
                else
                {
                    aliasValueNode = this.ParseAndBindParameterAliasValueExpression(bindingState, aliasValueExpression, aliasToken.ExpectedParameterType);
                    aliasValueAccessor.ParameterAliasValueNodesCached[alias] = aliasValueNode;
                }
            }

            return new ParameterAliasNode(alias, aliasValueNode.GetEdmTypeReference());
        }
예제 #2
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);
        }
예제 #3
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;
        }
예제 #4
0
        /// <summary>
        /// Constructs a MetadataBinder with the given <paramref name="initialState"/>.
        /// This constructor gets used if you are not calling the top level entry point ParseQuery.
        /// This is an at-your-own-risk constructor, since you must provide valid initial state.
        /// </summary>
        /// <param name="initialState">The initialState to use for binding.</param>
        internal MetadataBinder(BindingState initialState)
        {
            ExceptionUtils.CheckArgumentNotNull(initialState, "initialState");
            ExceptionUtils.CheckArgumentNotNull(initialState.Model, "initialState.Model");

            this.BindingState = initialState;
        }
예제 #5
0
 /// <summary>
 /// Constructor for binderbase.
 /// </summary>
 /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param>
 /// <param name="state">State of the metadata binding.</param>
 protected BinderBase(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
 {
     ExceptionUtils.CheckArgumentNotNull(bindMethod, "bindMethod");
     ExceptionUtils.CheckArgumentNotNull(state, "state");
     this.bindMethod = bindMethod;
     this.state = state;
 }
예제 #6
0
        /// <summary>
        /// Constructs a MetadataBinder with the given <paramref name="initialState"/>.
        /// This constructor gets used if you are not calling the top level entry point ParseQuery.
        /// This is an at-your-own-risk constructor, since you must provide valid initial state.
        /// </summary>
        /// <param name="initialState">The initialState to use for binding.</param>
        internal MetadataBinder(BindingState initialState)
        {
            ExceptionUtils.CheckArgumentNotNull(initialState, "initialState");
            ExceptionUtils.CheckArgumentNotNull(initialState.Model, "initialState.Model");

            this.BindingState = initialState;
        }
예제 #7
0
        /// <summary>
        /// Bind a parameter alias which is inside another alias value.
        /// </summary>
        /// <param name="bindingState">The alias name which is inside another alias value.</param>
        /// <param name="aliasToken">The cache of alias value nodes</param>
        /// <returns>The semantics node tree for alias (the @p1 in "@p1=...", not alias value expression)</returns>
        internal ParameterAliasNode BindParameterAlias(BindingState bindingState, FunctionParameterAliasToken aliasToken)
        {
            ExceptionUtils.CheckArgumentNotNull(bindingState, "bindingState");
            ExceptionUtils.CheckArgumentNotNull(aliasToken, "aliasToken");

            string alias = aliasToken.Alias;
            ParameterAliasValueAccessor aliasValueAccessor = bindingState.Configuration.ParameterAliasValueAccessor;

            if (aliasValueAccessor == null)
            {
                return(new ParameterAliasNode(alias, null));
            }

            // in cache?
            SingleValueNode aliasValueNode = null;

            if (!aliasValueAccessor.ParameterAliasValueNodesCached.TryGetValue(alias, out aliasValueNode))
            {
                // has value expression?
                string aliasValueExpression = aliasValueAccessor.GetAliasValueExpression(alias);
                if (aliasValueExpression == null)
                {
                    aliasValueAccessor.ParameterAliasValueNodesCached[alias] = null;
                }
                else
                {
                    aliasValueNode = this.ParseAndBindParameterAliasValueExpression(bindingState, aliasValueExpression);
                    aliasValueAccessor.ParameterAliasValueNodesCached[alias] = aliasValueNode;
                }
            }

            return(new ParameterAliasNode(alias, aliasValueNode.GetEdmTypeReference()));
        }
예제 #8
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);
        }
예제 #9
0
 public ApplyBinderTests()
 {
     var implicitRangeVariable = new EntityRangeVariable(ExpressionConstants.It,
         HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
     this._bindingState = new BindingState(_configuration) { ImplicitRangeVariable = implicitRangeVariable };
     this._bindingState.RangeVariables.Push(
         new BindingState(_configuration) { ImplicitRangeVariable = implicitRangeVariable }.ImplicitRangeVariable);
 }
        /// <summary>
        /// Create a new ODataUriSemanticBinder to bind an entire uri to Metadata.
        /// </summary>
        /// <param name="bindingState">the current state of the binding algorithm</param>
        /// <param name="bindMethod">pointer to the metadata bind method.</param>
        public ODataUriSemanticBinder(BindingState bindingState, MetadataBinder.QueryTokenVisitor bindMethod)
        {
            ExceptionUtils.CheckArgumentNotNull(bindingState, "bindingState");
            ExceptionUtils.CheckArgumentNotNull(bindMethod, "bindMethod");

            this.bindingState = bindingState;
            this.bindMethod   = bindMethod;
        }
예제 #11
0
        public void Init()
        {
            this.orderbyBinder = new OrderByBinder(FakeBindMethods.BindMethodReturningASinglePrimitive);

            var implicitRangeVariable = new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
            this.bindingState = new BindingState(configuration) { ImplicitRangeVariable = implicitRangeVariable };
            this.bindingState.RangeVariables.Push(new BindingState(configuration) { ImplicitRangeVariable = implicitRangeVariable }.ImplicitRangeVariable);
        }
        public void PrimitiveCollectionPropertyShouldCreateMatchingNode()
        {
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASingleDog, state);
            var token = new InnerPathToken("Nicknames", new DummyToken(), null /*namedValues*/);

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetDogNicknamesProperty());
        }
        public void DeclaredPropertyOnOpenTypeShouldCreateMatchingNode()
        {
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASinglePainting, state);
            var token = new InnerPathToken("Colors", new DummyToken(), null /*namedValues*/);

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetPaintingColorsProperty());
        }
예제 #14
0
        internal static List <OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection <FunctionParameterToken> segmentParameterTokens)
        {
            // TODO: HandleComplexOrCollectionParameterValueIfExists is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value.
            ICollection <FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.Resolver.EnableCaseInsensitive, configuration.EnableUriTemplateParsing);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);

            state.ImplicitRangeVariable = null;
            state.RangeVariables.Clear();
            MetadataBinder binder = new MetadataBinder(state);
            List <OperationSegmentParameter> boundParameters = new List <OperationSegmentParameter>();

            IDictionary <string, SingleValueNode> input = new Dictionary <string, SingleValueNode>(StringComparer.Ordinal);

            foreach (var paraToken in parametersParsed)
            {
                // TODO: considering another better exception
                if (paraToken.ValueToken is EndPathToken)
                {
                    throw new ODataException(Strings.MetadataBinder_ParameterNotInScope(
                                                 string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier)));
                }

                SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken);

                if (!input.ContainsKey(paraToken.ParameterName))
                {
                    input.Add(paraToken.ParameterName, boundNode);
                }
            }

            IDictionary <IEdmOperationParameter, SingleValueNode> result = configuration.Resolver.ResolveOperationParameters(functionOrOpertion, input);

            foreach (var item in result)
            {
                SingleValueNode boundNode = item.Value;

                // ensure node type is compatible with parameter type.
                var  sourceTypeReference    = boundNode.GetEdmTypeReference();
                bool sourceIsNullOrOpenType = (sourceTypeReference == null);
                if (!sourceIsNullOrOpenType)
                {
                    // if the node has been rewritten, no further conversion is needed.
                    if (!TryRewriteIntegralConstantNode(ref boundNode, item.Key.Type))
                    {
                        boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, item.Key.Type);
                    }
                }

                OperationSegmentParameter boundParamer = new OperationSegmentParameter(item.Key.Name, boundNode);
                boundParameters.Add(boundParamer);
            }

            return(boundParameters);
        }
        public void OpenPropertyShouldCreateMatchingNode()
        {
            const string OpenPropertyName = "Emotions";
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASinglePainting, state);
            var token = new InnerPathToken(OpenPropertyName, new DummyToken(), null /*namedValues*/);

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeSingleValueOpenPropertyAccessQueryNode(OpenPropertyName);
        }
        public void CollectionNavigationPropertyShouldCreateMatchingNode()
        {
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASingleDog, state);
            var token = new InnerPathToken("MyPeople", new DummyToken(), null /*namedValues*/);

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeCollectionNavigationNode(HardCodedTestModel.GetDogMyPeopleNavProp()).
                And.NavigationSource.Should().BeSameAs(HardCodedTestModel.GetDogsSet().FindNavigationTarget(HardCodedTestModel.GetDogMyPeopleNavProp()));
        }
예제 #17
0
 public void CreateLambdaNodeForAnyTokenShouldCreateAnyNode()
 {
     BindingState bindingState = new BindingState(configuration);
     EntityCollectionNode parent = new EntitySetNode(HardCodedTestModel.GetPeopleSet());
     SingleValueNode expression = new ConstantNode(true);
     RangeVariable rangeVariable = new EntityRangeVariable("bob", HardCodedTestModel.GetPersonTypeReference(), parent);
     var resultNode = NodeFactory.CreateLambdaNode(bindingState, parent, expression, rangeVariable, QueryTokenKind.Any);
     var node = resultNode.ShouldBeAnyQueryNode().And;
     node.Body.Should().BeSameAs(expression);
     node.Source.Should().BeSameAs(parent);
 }
예제 #18
0
        private MetadataBinder BuildNewMetadataBinder(IEdmNavigationSource targetNavigationSource)
        {
            BindingState state = new BindingState(this.configuration)
            {
                ImplicitRangeVariable =
                    NodeFactory.CreateImplicitRangeVariable(targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
            };

            state.RangeVariables.Push(state.ImplicitRangeVariable);
            return(new MetadataBinder(state));
        }
예제 #19
0
        /// <summary>
        /// Constructs parent node from binding state
        /// </summary>
        /// <param name="state">Current binding state</param>
        /// <returns>The parent node.</returns>
        internal static SingleValueNode CreateParentFromImplicitRangeVariable(BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            // If the Parent is null, then it must be referring to the implicit $it parameter
            if (state.ImplicitRangeVariable == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessWithoutParentParameter);
            }

            return(NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable));
        }
예제 #20
0
        /// <summary>
        /// Constructs parent node from binding state
        /// </summary>
        /// <param name="state">Current binding state</param>
        /// <returns>The parent node.</returns>
        internal static SingleValueNode CreateParentFromImplicitRangeVariable(BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            // If the Parent is null, then it must be referring to the implicit $it parameter
            if (state.ImplicitRangeVariable == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyAccessWithoutParentParameter);
            }

            return NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable);
        }
        public void MissingPropertyShouldThrow()
        {
            const string MissingPropertyName = "ThisPropertyDoesNotExist";
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASingleDog, state);
            var token = new InnerPathToken(MissingPropertyName, new DummyToken(), null /*namedValues*/);

            Action bind = () => binder.BindInnerPathSegment(token);

            string expectedMessage =
                ODataErrorStrings.MetadataBinder_PropertyNotDeclared(HardCodedTestModel.GetDogType().FullTypeName(), MissingPropertyName);
            bind.ShouldThrow<ODataException>(expectedMessage);
        }
예제 #22
0
        /// <summary>
        /// Binds a parameter token.
        /// </summary>
        /// <param name="rangeVariableToken">The parameter token to bind.</param>
        /// <param name="state">The state of metadata binding.</param>
        /// <returns>The bound query node.</returns>
        internal static SingleValueNode BindRangeVariableToken(RangeVariableToken rangeVariableToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(rangeVariableToken, "rangeVariableToken");
            
            RangeVariable rangeVariable = state.RangeVariables.SingleOrDefault(p => p.Name == rangeVariableToken.Name);

            if (rangeVariable == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_ParameterNotInScope(rangeVariableToken.Name));
            }

            return NodeFactory.CreateRangeVariableReferenceNode(rangeVariable);
        }
예제 #23
0
        /// <summary>
        /// Processes the order-by tokens of a entityCollection (if any).
        /// </summary>
        /// <param name="state">State to use for binding.</param>
        /// <param name="orderByTokens">The order-by tokens to bind.</param>
        /// <returns>An OrderByClause representing the orderby statements expressed in the tokens.</returns>
        internal OrderByClause BindOrderBy(BindingState state, IEnumerable<OrderByToken> orderByTokens)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");
            ExceptionUtils.CheckArgumentNotNull(orderByTokens, "orderByTokens");

            OrderByClause orderByClause = null;

            // Go through the orderby tokens starting from the last one
            foreach (OrderByToken orderByToken in orderByTokens.Reverse())
            {
                orderByClause = this.ProcessSingleOrderBy(state, orderByClause, orderByToken);
            }

            return orderByClause;
        }
예제 #24
0
        /// <summary>
        /// Processes the order-by tokens of a entityCollection (if any).
        /// </summary>
        /// <param name="state">State to use for binding.</param>
        /// <param name="orderByTokens">The order-by tokens to bind.</param>
        /// <returns>An OrderByClause representing the orderby statements expressed in the tokens.</returns>
        internal OrderByClause BindOrderBy(BindingState state, IEnumerable <OrderByToken> orderByTokens)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");
            ExceptionUtils.CheckArgumentNotNull(orderByTokens, "orderByTokens");

            OrderByClause orderByClause = null;

            // Go through the orderby tokens starting from the last one
            foreach (OrderByToken orderByToken in orderByTokens.Reverse())
            {
                orderByClause = this.ProcessSingleOrderBy(state, orderByClause, orderByToken);
            }

            return(orderByClause);
        }
예제 #25
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>
        /// <param name="state">Current state of binding.</param>
        /// <returns>A SingleValueQueryNode that is the parent node of the <paramref name="segmentToken"/>.</returns>
        private QueryNode DetermineParentNode(InnerPathToken segmentToken, BindingState state)
        {
            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));
            }
        }
예제 #26
0
        /// <summary>
        /// Process the remaining query options (represent the set of custom query options after
        /// service operation parameters and system query options have been removed).
        /// </summary>
        /// <param name="bindingState">the current state of the binding algorithm.</param>
        /// <param name="bindMethod">pointer to a binder method.</param>
        /// <returns>The list of <see cref="QueryNode"/> instances after binding.</returns>
        public static List <QueryNode> ProcessQueryOptions(BindingState bindingState, MetadataBinder.QueryTokenVisitor bindMethod)
        {
            List <QueryNode> customQueryOptionNodes = new List <QueryNode>();

            foreach (CustomQueryOptionToken queryToken in bindingState.QueryOptions)
            {
                QueryNode customQueryOptionNode = bindMethod(queryToken);
                if (customQueryOptionNode != null)
                {
                    customQueryOptionNodes.Add(customQueryOptionNode);
                }
            }

            bindingState.QueryOptions = null;
            return(customQueryOptionNodes);
        }
예제 #27
0
        internal static List <OperationSegmentParameter> BindSegmentParameters(ODataUriParserConfiguration configuration, IEdmOperation functionOrOpertion, ICollection <FunctionParameterToken> segmentParameterTokens)
        {
            // TODO: HandleComplexOrCollectionParameterValueIfExists  is temp work around for single copmlex or colleciton type, it can't handle nested complex or collection value.
            ICollection <FunctionParameterToken> parametersParsed = FunctionCallBinder.HandleComplexOrCollectionParameterValueIfExists(configuration.Model, functionOrOpertion, segmentParameterTokens, configuration.EnableUriTemplateParsing);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);

            state.ImplicitRangeVariable = null;
            state.RangeVariables.Clear();
            MetadataBinder binder = new MetadataBinder(state);
            List <OperationSegmentParameter> boundParameters = new List <OperationSegmentParameter>();

            foreach (var paraToken in parametersParsed)
            {
                // TODO: considering another better exception
                if (paraToken.ValueToken is EndPathToken)
                {
                    throw new ODataException(Strings.MetadataBinder_ParameterNotInScope(
                                                 string.Format(CultureInfo.InvariantCulture, "{0}={1}", paraToken.ParameterName, (paraToken.ValueToken as EndPathToken).Identifier)));
                }

                SingleValueNode boundNode = (SingleValueNode)binder.Bind(paraToken.ValueToken);

                // ensure parameter name existis
                var functionParameter = functionOrOpertion.FindParameter(paraToken.ParameterName);
                if (functionParameter == null)
                {
                    throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(paraToken.ParameterName, functionOrOpertion.Name));
                }

                // ensure node type is compatible with parameter type.
                var  sourceTypeReference    = boundNode.GetEdmTypeReference();
                bool sourceIsNullOrOpenType = (sourceTypeReference == null);
                if (!sourceIsNullOrOpenType)
                {
                    boundNode = MetadataBindingUtils.ConvertToTypeIfNeeded(boundNode, functionParameter.Type);
                }

                OperationSegmentParameter boundParamer = new OperationSegmentParameter(paraToken.ParameterName, boundNode);
                boundParameters.Add(boundParamer);
            }

            return(boundParameters);
        }
예제 #28
0
        /// <summary>
        /// Parse expression into syntaxs token tree, and bind it into semantics node tree.
        /// </summary>
        /// <param name="bindingState">The BindingState.</param>
        /// <param name="aliasValueExpression">The alias value's expression text.</param>
        /// <returns>The semantcs node of the expression text.</returns>
        private SingleValueNode ParseAndBindParameterAliasValueExpression(BindingState bindingState, string aliasValueExpression)
        {
            // Get the syntactic representation of the filter expression
            // TODO: change Settings.FilterLimit to ParameterAliasValueLimit
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(bindingState.Configuration.Settings.FilterLimit);
            QueryToken aliasValueToken = expressionParser.ParseExpressionText(aliasValueExpression);

            // Get the semantic node, and check for SingleValueNode
            QueryNode       aliasValueNode = this.bindMethod(aliasValueToken);
            SingleValueNode result         = aliasValueNode as SingleValueNode;

            if (result == null)
            {
                // TODO: add string resource
                throw new ODataException("ODataErrorStrings.MetadataBinder_ParameterAliasValueExpressionNotSingleValue");
            }

            return(result);
        }
예제 #29
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>
        /// <param name="state">State of the binding algorithm.</param>
        /// <returns>A Query node representing this endpath token, bound to metadata.</returns>
        internal QueryNode BindEndPath(EndPathToken endPathToken, BindingState state)
        {
            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, state);

            QueryNode boundFunction;

            SingleValueNode singleValueParent = parent as SingleValueNode;

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

                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 : structuredParentType.FindProperty(endPathToken.Identifier);

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

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

            return(GeneratePropertyAccessQueryForOpenType(endPathToken, singleValueParent));
        }
예제 #30
0
        /// <summary>
        /// Binds the token to a SingleValueFunctionCallNode
        /// </summary>
        /// <param name="functionCallToken">Token to bind</param>
        /// <param name="state">The current state of the binding algorithm</param>
        /// <returns>The resulting SingleValueFunctionCallNode</returns>
        internal QueryNode BindFunctionCall(FunctionCallToken functionCallToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(functionCallToken, "functionCallToken");
            ExceptionUtils.CheckArgumentNotNull(functionCallToken.Name, "functionCallToken.Name");

            // Bind the parent, if present.
            // TODO: parent can be a collection as well, so we need to loosen this to QueryNode.
            QueryNode parent = null;

            if (state.ImplicitRangeVariable != null)
            {
                if (functionCallToken.Source != null)
                {
                    parent = this.bindMethod(functionCallToken.Source);
                }
                else
                {
                    parent = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable);
                }
            }

            // First see if there is a custom function for this
            QueryNode boundFunction;

            if (this.TryBindIdentifier(functionCallToken.Name, functionCallToken.Arguments, parent, state, out boundFunction))
            {
                return(boundFunction);
            }

            // then check if there is a global custom function(i.e with out a parent node)
            if (this.TryBindIdentifier(functionCallToken.Name, functionCallToken.Arguments, null, state, out boundFunction))
            {
                return(boundFunction);
            }

            // If there isn't, bind as built-in function
            // Bind all arguments
            List <QueryNode> argumentNodes = new List <QueryNode>(functionCallToken.Arguments.Select(ar => this.bindMethod(ar)));

            return(BindAsBuiltInFunction(functionCallToken, state, argumentNodes));
        }
예제 #31
0
        /// <summary>
        /// Parse expression into syntaxs token tree, and bind it into semantics node tree.
        /// </summary>
        /// <param name="bindingState">The BindingState.</param>
        /// <param name="aliasValueExpression">The alias value's expression text.</param>
        /// <param name="parameterType">The edm type of the parameter.</param>
        /// <returns>The semantcs node of the expression text.</returns>
        private SingleValueNode ParseAndBindParameterAliasValueExpression(BindingState bindingState, string aliasValueExpression, IEdmTypeReference parameterType)
        {
            // Get the syntactic representation of the filter expression
            // TODO: change Settings.FilterLimit to ParameterAliasValueLimit
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(bindingState.Configuration.Settings.FilterLimit);
            QueryToken aliasValueToken = expressionParser.ParseExpressionText(aliasValueExpression);
            
            // Special logic to handle parameter alias token.
            aliasValueToken = ParseComplexOrCollectionAlias(aliasValueToken, parameterType, bindingState.Model);
            
            // Get the semantic node, and check for SingleValueNode
            QueryNode aliasValueNode = this.bindMethod(aliasValueToken);
            SingleValueNode result = aliasValueNode as SingleValueNode;
            if (result == null)
            {
                // TODO: add string resource
                throw new ODataException("ODataErrorStrings.MetadataBinder_ParameterAliasValueExpressionNotSingleValue");
            }

            return result;
        }
예제 #32
0
        /// <summary>
        /// Processes the specified order-by token.
        /// </summary>
        /// <param name="state">State to use for binding.</param>
        /// <param name="thenBy"> The next OrderBy node, or null if there is no orderby after this.</param>
        /// <param name="orderByToken">The order-by token to bind.</param>
        /// <returns>Returns the combined entityCollection including the ordering.</returns>
        private OrderByClause ProcessSingleOrderBy(BindingState state, OrderByClause thenBy, OrderByToken orderByToken)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");
            ExceptionUtils.CheckArgumentNotNull(orderByToken, "orderByToken");

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

            // The order-by expressions need to be primitive / enumeration types
            SingleValueNode expressionResultNode = expressionNode as SingleValueNode;
            if (expressionResultNode == null ||
                (expressionResultNode.TypeReference != null && !expressionResultNode.TypeReference.IsODataPrimitiveTypeKind() && !expressionResultNode.TypeReference.IsODataEnumTypeKind() && !expressionResultNode.TypeReference.IsODataTypeDefinitionTypeKind()))
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_OrderByExpressionNotSingleValue);
            }

            OrderByClause orderByNode = new OrderByClause(
                thenBy,
                expressionResultNode,
                orderByToken.Direction,
                state.ImplicitRangeVariable);

            return orderByNode;
        }
예제 #33
0
        /// <summary>
        /// Processes the specified order-by token.
        /// </summary>
        /// <param name="state">State to use for binding.</param>
        /// <param name="thenBy"> The next OrderBy node, or null if there is no orderby after this.</param>
        /// <param name="orderByToken">The order-by token to bind.</param>
        /// <returns>Returns the combined entityCollection including the ordering.</returns>
        private OrderByClause ProcessSingleOrderBy(BindingState state, OrderByClause thenBy, OrderByToken orderByToken)
        {
            ExceptionUtils.CheckArgumentNotNull(state, "state");
            ExceptionUtils.CheckArgumentNotNull(orderByToken, "orderByToken");

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

            // The order-by expressions need to be primitive / enumeration types
            SingleValueNode expressionResultNode = expressionNode as SingleValueNode;

            if (expressionResultNode == null ||
                (expressionResultNode.TypeReference != null && !expressionResultNode.TypeReference.IsODataPrimitiveTypeKind() && !expressionResultNode.TypeReference.IsODataEnumTypeKind()))
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_OrderByExpressionNotSingleValue);
            }

            OrderByClause orderByNode = new OrderByClause(
                thenBy,
                expressionResultNode,
                orderByToken.Direction,
                state.ImplicitRangeVariable);

            return(orderByNode);
        }
예제 #34
0
 /// <summary>
 /// Validate the arguments (adding the implicit range variable if necessary), and determine the correct return type
 /// for an IsOf function
 /// </summary>
 /// <param name="state">the current state of the binding algorithm, used to get the implicit range variable if necessary</param>
 /// <param name="args">current list of args, can be changed</param>
 /// <returns>the correct return type for this function.</returns>
 private static IEdmTypeReference ValidateAndBuildIsOfArgs(BindingState state, ref List <QueryNode> args)
 {
     return(ValidateIsOfOrCast(state, false, ref args));
 }
예제 #35
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>
        /// <returns>A new CollectionNavigationNode or SingleNavigationNode to capture the navigation propety access.</returns>
        internal static QueryNode GetNavigationNode(IEdmNavigationProperty property, SingleEntityNode parent, IEnumerable <NamedValue> namedValues, BindingState state, KeyBinder keyBinder)
        {
            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(property, parent);

                // 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 colleciton");

            // Otherwise it's a single navigation property
            return(new SingleNavigationNode(property, parent));
        }
예제 #36
0
        /// <summary>
        /// Parses an <paramref name="orderBy "/> clause on the given <paramref name="elementType"/>, binding
        /// the text into semantic nodes using the provided model.
        /// </summary>
        /// <param name="orderBy">String representation of the orderby expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="elementType">Type that the orderby clause refers to.</param>
        /// <param name="navigationSource">NavigationSource that the elements are from.</param>
        /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns>
        private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");
            ExceptionUtils.CheckArgumentNotNull(elementType, "elementType");
            ExceptionUtils.CheckArgumentNotNull(orderBy, "orderBy");

            // Get the syntactic representation of the orderby expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.OrderByLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            var orderByQueryTokens = expressionParser.ParseOrderBy(orderBy);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);
            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            if (applyClause != null)
            {
                state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames();
            }

            MetadataBinder binder = new MetadataBinder(state);
            OrderByBinder orderByBinder = new OrderByBinder(binder.Bind);
            OrderByClause orderByClause = orderByBinder.BindOrderBy(state, orderByQueryTokens);

            return orderByClause;
        }
예제 #37
0
        /// <summary>
        /// Parses a <paramref name="filter"/> clause on the given <paramref name="elementType"/>, binding
        /// the text into semantic nodes using the provided model.
        /// </summary>
        /// <param name="filter">String representation of the filter expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="elementType">Type that the filter clause refers to.</param>
        /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param>
        /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns>
        private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(elementType, "elementType");
            ExceptionUtils.CheckArgumentNotNull(filter, "filter");

            // Get the syntactic representation of the filter expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            QueryToken filterToken = expressionParser.ParseFilter(filter);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);
            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            if (applyClause != null)
            {
                state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames();
            }

            MetadataBinder binder = new MetadataBinder(state);
            FilterBinder filterBinder = new FilterBinder(binder.Bind, state);
            FilterClause boundNode = filterBinder.BindFilter(filterToken);

            return boundNode;
        }
예제 #38
0
 /// <summary>
 /// Constructs a EndPathBinder object using the given function to bind parent token.
 /// </summary>
 /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param>
 /// <param name="state">State of the metadata binding.</param>am>
 /// <remarks>
 /// Make bindMethod of return type SingleValueQueryNode.
 /// </remarks>
 internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
     : base(bindMethod, state)
 {
     this.functionCallBinder = new FunctionCallBinder(bindMethod, state);
 }
예제 #39
0
        private bool TryBindIdentifier(string identifier, IEnumerable <FunctionParameterToken> arguments, QueryNode parent, BindingState state, out QueryNode boundFunction)
        {
            boundFunction = null;

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

            if (singleValueParent != null)
            {
                if (singleValueParent.TypeReference != null)
                {
                    bindingType = singleValueParent.TypeReference.Definition;
                }
            }
            else
            {
                var 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;
            var singleEntityNode         = parent as SingleEntityNode;

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

            string functionName = function.FullName();

            if (returnType.IsEntity())
            {
                boundFunction = new SingleEntityFunctionCallNode(functionName, new[] { function }, boundArguments, (IEdmEntityTypeReference)returnType.Definition.ToTypeReference(), returnSet, parent);
            }
            else if (returnType.IsEntityCollection())
            {
                IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)returnType;
                boundFunction = new EntityCollectionFunctionCallNode(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);
        }
예제 #40
0
 /// <summary>
 /// Constructs a FunctionCallBinder with the given method to be used binding the parent token if needed.
 /// </summary>
 /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param>
 /// <param name="state">State of the metadata binding.</param>
 internal FunctionCallBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
     : base(bindMethod, state)
 {
 }
        public void GetNavigationNodeCreatesCollectionNavigationNodeForManyMultiplicityProperty()
        {
            IEdmNavigationProperty property = HardCodedTestModel.GetDogMyPeopleNavProp();
            SingleEntityNode parent = new SingleEntityCastNode(null, HardCodedTestModel.GetDogType());
            BindingState state = new BindingState(configuration);
            KeyBinder keyBinder = new KeyBinder(FakeBindMethods.BindMethodReturningASingleDog);

            var result = InnerPathTokenBinder.GetNavigationNode(property, parent, null, state, keyBinder);
            result.ShouldBeCollectionNavigationNode(property);
        }
        public void InnerPathTokenBinderShouldFailIfPropertySourceIsNotASingleValue()
        {
            var state = new BindingState(configuration);
            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet());
            var metadataBinder = new MetadataBinder(state);
            var binder = new InnerPathTokenBinder(metadataBinder.Bind, state);
            var token = new InnerPathToken("MyDog", new InnerPathToken("MyPeople", null, null), null);

            Action bind = () => binder.BindInnerPathSegment(token);
            bind.ShouldThrow<ODataException>().WithMessage(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue("MyDog"));
        }
        public void KeyLookupOnNavPropIntegrationTest()
        {
            var state = new BindingState(configuration);
            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet());
            var metadataBinder = new MetadataBinder(state);
            var binder = new InnerPathTokenBinder(metadataBinder.Bind, state);
            var token = new InnerPathToken("MyPeople", null, new[] { new NamedValue(null, new LiteralToken(123)) });

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeKeyLookupQueryNode();
        }
        public void CollectionOfTimeOfDayShouldCreateMatchingNode()
        {
            var state = new BindingState(configuration);
            var binder = new InnerPathTokenBinder(FakeBindMethods.BindMethodReturningASinglePerson, state);
            var token = new InnerPathToken("MyTimeOfDays", new DummyToken(), null /*namedValues*/);

            var result = binder.BindInnerPathSegment(token);
            result.ShouldBeCollectionPropertyAccessQueryNode(HardCodedTestModel.GetPersonMyTimeOfDaysProp());
        }
 private void ResetState()
 {
     BindingState state = new BindingState(this.configuration);
     state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
     state.RangeVariables.Push(state.ImplicitRangeVariable);
     binder = new MetadataBinder(state);
     this.functionCallBinder = new FunctionCallBinder(binder.Bind, state);
 }
예제 #46
0
 /// <summary>
 /// Constructs a DottedIdentifierBinder with the given method to be used binding the parent token if needed.
 /// </summary>
 /// <param name="bindMethod">Method to use for binding the parent token, if needed.</param>
 /// <param name="state">State of the metadata binding.</param>
 internal DottedIdentifierBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
     : base(bindMethod, state)
 {
 }
예제 #47
0
 /// <summary>
 /// Constructs a EndPathBinder object using the given function to bind parent token.
 /// </summary>
 /// <param name="bindMethod">Method to bind the EndPathToken's parent, if there is one.</param>
 /// <param name="state">State of the metadata binding.</param>am>
 /// <remarks>
 /// Make bindMethod of return type SingleValueQueryNode.
 /// </remarks>
 internal EndPathBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
     : base(bindMethod, state)
 {
     this.functionCallBinder = new FunctionCallBinder(bindMethod, state);
 }
예제 #48
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));
 }
예제 #49
0
 /// <summary>
 /// Try to bind a dotted identifier as enum node
 /// </summary>
 /// <param name="dottedIdentifierToken">a dotted identifier token</param>
 /// <param name="parent">the parent node</param>
 /// <param name="state">the current state of the binding algorithm</param>
 /// <param name="boundEnum">the output bound enum node</param>
 /// <returns>true if we bound an enum node, false otherwise.</returns>
 internal static bool TryBindDottedIdentifierAsEnum(DottedIdentifierToken dottedIdentifierToken, SingleValueNode parent, BindingState state, out QueryNode boundEnum)
 {
     return(TryBindIdentifier(dottedIdentifierToken.Identifier, null, state.Model, out boundEnum));
 }
예제 #50
0
        /// <summary>
        /// Binds a DottedIdentifierToken and it's parent node (if needed).
        /// </summary>
        /// <param name="dottedIdentifierToken">Token to bind to metadata.</param>
        /// <param name="state">State of the Binding.</param>
        /// <returns>A bound node representing the cast.</returns>
        internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken");
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            QueryNode parent     = null;
            IEdmType  parentType = null;

            if (state.ImplicitRangeVariable != null)
            {
                if (dottedIdentifierToken.NextToken == null)
                {
                    parent     = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable);
                    parentType = state.ImplicitRangeVariable.TypeReference.Definition;
                }
                else
                {
                    parent     = this.bindMethod(dottedIdentifierToken.NextToken);
                    parentType = parent.GetEdmType();
                }
            }

            SingleEntityNode   parentAsSingleValue = parent as SingleEntityNode;
            IEdmSchemaType     childType           = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier);
            IEdmStructuredType childStructuredType = childType as IEdmStructuredType;

            if (childStructuredType == null)
            {
                FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod);
                QueryNode          functionCallNode;
                if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode))
                {
                    return(functionCallNode);
                }
                else if ((!string.IsNullOrEmpty(dottedIdentifierToken.Identifier)) &&
                         (dottedIdentifierToken.Identifier[dottedIdentifierToken.Identifier.Length - 1] == '\''))
                {
                    // check if it is enum or not
                    EnumBinder enumBinder = new EnumBinder(this.bindMethod);
                    QueryNode  enumNode;
                    if (enumBinder.TryBindDottedIdentifierAsEnum(dottedIdentifierToken, parentAsSingleValue, state, out enumNode))
                    {
                        return(enumNode);
                    }
                    else
                    {
                        throw new ODataException(ODataErrorStrings.Binder_IsNotValidEnumConstant(dottedIdentifierToken.Identifier));
                    }
                }
                else
                {
                    IEdmTypeReference edmTypeReference = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier).ToTypeReference();
                    if (edmTypeReference is IEdmPrimitiveTypeReference || edmTypeReference is IEdmEnumTypeReference)
                    {
                        return(new ConstantNode(dottedIdentifierToken.Identifier, dottedIdentifierToken.Identifier));
                    }
                    else
                    {
                        throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier));
                    }
                }
            }

            // Check whether childType is a derived type of the type of its parent node
            UriEdmHelpers.CheckRelatedTo(parentType, childType);

            IEdmEntityType childEntityType = childStructuredType as IEdmEntityType;

            if (childEntityType != null)
            {
                EntityCollectionNode parentAsCollection = parent as EntityCollectionNode;
                if (parentAsCollection != null)
                {
                    return(new EntityCollectionCastNode(parentAsCollection, childEntityType));
                }

                // parent can be null for casts on the implicit parameter; this is OK
                if (parent == null)
                {
                    return(new SingleEntityCastNode(null, childEntityType));
                }

                Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value.");
                return(new SingleEntityCastNode(parentAsSingleValue, childEntityType));
            }
            else
            {
                IEdmComplexType childComplexType = childStructuredType as IEdmComplexType;
                Debug.Assert(childComplexType != null, "If it is not entity type, it should be complex type");

                CollectionPropertyAccessNode parentAsCollectionProperty = parent as CollectionPropertyAccessNode;
                if (parentAsCollectionProperty != null)
                {
                    return(new CollectionPropertyCastNode(parentAsCollectionProperty, childComplexType));
                }

                // parent can be null for casts on the implicit parameter; this is OK
                if (parent == null)
                {
                    return(new SingleValueCastNode(null, childComplexType));
                }

                SingleValueNode parentAsSingleValueNode = parent as SingleValueNode;
                Debug.Assert(parentAsSingleValueNode != null, "If parent of the cast node was not collection, it should be a single value.");
                return(new SingleValueCastNode(parentAsSingleValueNode, childComplexType));
            }
        }
예제 #51
0
        /// <summary>
        /// Parses an <paramref name="apply"/> clause on the given <paramref name="elementType"/>, binding
        /// the text into a metadata-bound or dynamic properties to be applied using the provided model.
        /// </summary>
        /// <param name="apply">String representation of the apply expression.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="elementType">Type that the apply clause refers to.</param>
        /// <param name="navigationSource">Navigation source that the elements being filtered are from.</param>
        /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns>
        private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(elementType, "elementType");
            ExceptionUtils.CheckArgumentNotNull(apply, "apply");

            // Get the syntactic representation of the apply expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            var applyTokens = expressionParser.ParseApply(apply);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);
            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(elementType.ToTypeReference(), navigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            MetadataBinder binder = new MetadataBinder(state);
            ApplyBinder applyBinder = new ApplyBinder(binder.Bind, state);
            ApplyClause boundNode = applyBinder.BindApply(applyTokens);

            return boundNode;
        }
예제 #52
0
 public void CreateParentShouldThrowIfBindingStateWithoutImplicitParameter()
 {
     var state = new BindingState(this.configuration);
     Action createparent = () => EndPathBinder.CreateParentFromImplicitRangeVariable(state);
     createparent.ShouldThrow<ODataException>().WithMessage(Strings.MetadataBinder_PropertyAccessWithoutParentParameter);
 }
예제 #53
0
        /// <summary>
        /// Parses the <paramref name="search"/> clause, binding
        /// the text into a metadata-bound list of properties to be selected using the provided model.
        /// </summary>
        /// <param name="search">String representation of the search expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <returns>A <see cref="SearchClause"/> representing the metadata bound search expression.</returns>
        private static SearchClause ParseSearchImplementation(string search, ODataUriParserConfiguration configuration)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(search, "search");

            SearchParser searchParser = new SearchParser(configuration.Settings.SearchLimit);
            QueryToken queryToken = searchParser.ParseSearch(search);

            // Bind it to metadata
            BindingState state = new BindingState(configuration);
            MetadataBinder binder = new MetadataBinder(state);
            SearchBinder searchBinder = new SearchBinder(binder.Bind);

            return searchBinder.BindSearch(queryToken);
        }
예제 #54
0
 public void Init()
 {
     this.bindingState = GetBindingStateForTest(HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet());
     this.propertyBinder = new EndPathBinder(BindMethod, this.bindingState);
 }
예제 #55
0
 /// <summary>
 /// Constructs a InnerPathTokenBinder.
 /// </summary>
 /// <param name="bindMethod">Bind method to use for binding a parent node, if needed.</param>
 /// <param name="state">State of the metadata binding.</param>
 internal InnerPathTokenBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
     : base(bindMethod, state)
 {
 }
예제 #56
0
 /// <summary>
 /// Gets a BindingState for the test to use.
 /// </summary>
 /// <param name="type">Optional type for the implicit parameter.</param>
 /// <returns></returns>
 private BindingState GetBindingStateForTest(IEdmEntityTypeReference typeReference, IEdmEntitySet type)
 {
     type.Should().NotBeNull();
     EntityCollectionNode entityCollectionNode = new EntitySetNode(type);
     var implicitParameter = new EntityRangeVariable(ExpressionConstants.It, typeReference, entityCollectionNode);
     var state = new BindingState(this.configuration) { ImplicitRangeVariable = implicitParameter };
     state.RangeVariables.Push(state.ImplicitRangeVariable);
     return state;
 }
예제 #57
0
        /// <summary>
        /// Binds a parameter token.
        /// </summary>
        /// <param name="rangeVariableToken">The parameter token to bind.</param>
        /// <param name="state">The state of metadata binding.</param>
        /// <returns>The bound query node.</returns>
        internal static SingleValueNode BindRangeVariableToken(RangeVariableToken rangeVariableToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(rangeVariableToken, "rangeVariableToken");

            RangeVariable rangeVariable = state.RangeVariables.SingleOrDefault(p => p.Name == rangeVariableToken.Name);

            if (rangeVariable == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_ParameterNotInScope(rangeVariableToken.Name));
            }

            return(NodeFactory.CreateRangeVariableReferenceNode(rangeVariable));
        }
예제 #58
0
 /// <summary>
 /// Creates a FilterBinder.
 /// </summary>
 /// <param name="bindMethod">Method to use to visit the token tree and bind the tokens recursively.</param>
 /// <param name="state">State to use for binding.</param>
 internal FilterBinder(MetadataBinder.QueryTokenVisitor bindMethod, BindingState state)
 {
     this.bindMethod = bindMethod;
     this.state      = state;
 }
        /// <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>
        /// <param name="state">The state of binding.</param>
        /// <returns>The bound node.</returns>
        internal QueryNode BindInnerPathSegment(InnerPathToken segmentToken, BindingState state)
        {
            FunctionCallBinder functionCallBinder = new FunctionCallBinder(this.bindMethod);

            // 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, state, out boundFunction))
                {
                    return(boundFunction);
                }

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

            if (property == null)
            {
                QueryNode boundFunction;
                if (functionCallBinder.TryBindInnerPathAsFunctionCall(segmentToken, parent, state, out boundFunction))
                {
                    return(boundFunction);
                }

                if (singleValueParent.TypeReference != null && !singleValueParent.TypeReference.Definition.IsOpenType())
                {
                    throw new ODataException(
                              ODataErrorStrings.MetadataBinder_PropertyNotDeclared(
                                  parent.GetEdmTypeReference().ODataFullName(), segmentToken.Identifier));
                }

                return(new SingleValueOpenPropertyAccessNode(singleValueParent, segmentToken.Identifier));
            }

            if (property.Type.IsODataComplexTypeKind())
            {
                return(new SingleValuePropertyAccessNode(singleValueParent, property));
            }

            // Note - this means nonentity collection (primitive or complex)
            if (property.Type.IsNonEntityCollectionType())
            {
                return(new CollectionPropertyAccessNode(singleValueParent, property));
            }

            IEdmNavigationProperty navigationProperty = property as IEdmNavigationProperty;

            if (navigationProperty == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_IllegalSegmentType(property.Name));
            }

            SingleEntityNode parentEntity = EnsureParentIsEntityForNavProp(singleValueParent);

            return(GetNavigationNode(navigationProperty, parentEntity, segmentToken.NamedValues, state, new KeyBinder(this.bindMethod)));
        }
예제 #60
0
        /// <summary>
        /// Validate the arguments to either isof or cast
        /// </summary>
        /// <param name="state">the current state of the binding algorithm</param>
        /// <param name="isCast">flag to indicate which function we're validating</param>
        /// <param name="args">the list of arguments, which could be changed</param>
        /// <returns>the return type of the function.</returns>
        private static IEdmTypeReference ValidateIsOfOrCast(BindingState state, bool isCast, ref List <QueryNode> args)
        {
            if (args.Count != 1 && args.Count != 2)
            {
                throw new ODataErrorException(
                          ODataErrorStrings.MetadataBinder_CastOrIsOfExpressionWithWrongNumberOfOperands(args.Count));
            }

            ConstantNode typeArgument = args.Last() as ConstantNode;

            IEdmTypeReference returnType = null;

            if (typeArgument != null)
            {
                returnType = TryGetTypeReference(state.Model, typeArgument.Value as string, state.Configuration.Resolver);
            }

            if (returnType == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfFunctionWithoutATypeArgument);
            }

            if (returnType.IsCollection())
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfCollectionsNotSupported);
            }

            // if we only have one argument, then add the implicit range variable as the first argument.
            if (args.Count == 1)
            {
                args = new List <QueryNode>()
                {
                    new EntityRangeVariableReferenceNode(
                        state.ImplicitRangeVariable.Name,
                        state.ImplicitRangeVariable as EntityRangeVariable),
                    args[0]
                };
            }
            else if (!(args[0] is SingleValueNode))
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_CastOrIsOfCollectionsNotSupported);
            }

            if (isCast && (args.Count == 2))
            {
                // throw if cast enum to not-string :
                if ((args[0].GetEdmTypeReference() is IEdmEnumTypeReference) &&
                    !string.Equals(typeArgument.Value as string, Microsoft.OData.Core.Metadata.EdmConstants.EdmStringTypeName, StringComparison.Ordinal))
                {
                    throw new ODataException(ODataErrorStrings.CastBinder_EnumOnlyCastToOrFromString);
                }

                // throw if cast not-string to enum :
                while (returnType is IEdmEnumTypeReference)
                {
                    IEdmTypeReference edmTypeReference = args[0].GetEdmTypeReference();
                    if (edmTypeReference == null)
                    {
                        // Support cast null to enum
                        break;
                    }

                    IEdmPrimitiveTypeReference referenceTmp = edmTypeReference as IEdmPrimitiveTypeReference;
                    if (referenceTmp != null)
                    {
                        IEdmPrimitiveType typeTmp = referenceTmp.Definition as IEdmPrimitiveType;
                        if ((typeTmp != null) && (typeTmp.PrimitiveKind == EdmPrimitiveTypeKind.String))
                        {
                            break;
                        }
                    }

                    throw new ODataException(ODataErrorStrings.CastBinder_EnumOnlyCastToOrFromString);
                }
            }

            if (isCast)
            {
                return(returnType);
            }
            else
            {
                return(EdmCoreModel.Instance.GetBoolean(true));
            }
        }