Exemple #1
0
        /// <summary>
        /// Binds an Count segment token.
        /// </summary>
        /// <param name="countSegmentToken">The Count segment token to bind.</param>
        /// <param name="state">State of the metadata binding.</param>
        /// <returns>The bound Count segment token.</returns>
        internal QueryNode BindCountSegment(CountSegmentToken countSegmentToken)
        {
            ExceptionUtils.CheckArgumentNotNull(countSegmentToken, "countSegmentToken");

            QueryNode      source = this.bindMethod(countSegmentToken.NextToken);
            CollectionNode node   = source as CollectionNode;

            if (node == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_CountSegmentNextTokenNotCollectionValue());
            }

            FilterClause filterClause = null;
            SearchClause searchClause = null;

            BindingState innerBindingState = new BindingState(state.Configuration);

            innerBindingState.ImplicitRangeVariable = NodeFactory.CreateParameterNode(ExpressionConstants.It, node);
            MetadataBinder binder = new MetadataBinder(innerBindingState);

            if (countSegmentToken.FilterOption != null)
            {
                FilterBinder filterBinder = new FilterBinder(binder.Bind, innerBindingState);
                filterClause = filterBinder.BindFilter(countSegmentToken.FilterOption);
            }

            if (countSegmentToken.SearchOption != null)
            {
                SearchBinder searchBinder = new SearchBinder(binder.Bind);
                searchClause = searchBinder.BindSearch(countSegmentToken.SearchOption);
            }

            return(new CountNode(node, filterClause, searchClause));
        }
        /// <summary>
        /// Constructs a MetadataBinder with the given <paramref name="initialState"/>.
        /// This constructor gets used if you are not calling the top level resource 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>
        /// <exception cref="System.ArgumentNullException">Throws if initial state is null.</exception>
        /// <exception cref="System.ArgumentNullException">Throws if initialState.Model is null.</exception>
        internal MetadataBinder(BindingState initialState)
        {
            ExceptionUtils.CheckArgumentNotNull(initialState, "initialState");
            ExceptionUtils.CheckArgumentNotNull(initialState.Model, "initialState.Model");

            this.BindingState = initialState;
        }
Exemple #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);
        }
        /// <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);
        }
        private BindingState CreateBindingState(ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            BindingState state = new BindingState(configuration, odataPathInfo.Segments.ToList());

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            if (applyClause != null)
            {
                state.AggregatedPropertyNames = applyClause.GetLastAggregatedPropertyNames();
                if (applyClause.Transformations.Any(x => x.Kind == TransformationNodeKind.GroupBy || x.Kind == TransformationNodeKind.Aggregate))
                {
                    state.IsCollapsed = true;
                }
            }

            if (computeClause != null)
            {
                var computedProperties = new HashSet <EndPathToken>(computeClause.ComputedItems.Select(i => new EndPathToken(i.Alias, null)));
                if (state.AggregatedPropertyNames == null)
                {
                    state.AggregatedPropertyNames = computedProperties;
                }
                else
                {
                    state.AggregatedPropertyNames.UnionWith(computedProperties);
                }
            }

            return(state);
        }
        /// <summary>
        /// Parses a <paramref name="filter"/> clause, 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="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns>
        private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(odataPathInfo, "odataPathInfo");
            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, odataPathInfo.Segments.ToList());

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            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);
        }
        /// <summary>
        /// Parses an <paramref name="orderBy "/> clause, 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="odataPathInfo">The path info from Uri path.</param>
        /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns>
        private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");
            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, odataPathInfo.Segments.ToList());

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            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);
        }
Exemple #8
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);
        }
        /// <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()));
        }
        /// <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>
        /// <exception cref="ODataException">Throws if bindingState is null.</exception>
        /// <exception cref="ODataException">Throws if bindMethod is null.</exception>
        public static List <QueryNode> ProcessQueryOptions(BindingState bindingState, MetadataBinder.QueryTokenVisitor bindMethod)
        {
            if (bindingState == null || bindingState.QueryOptions == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionsBindStateCannotBeNull);
            }

            if (bindMethod == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionsBindMethodCannotBeNull);
            }

            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);
        }
Exemple #11
0
 /// <summary>
 /// Build a property visitor to visit the select tree and decorate a SelectExpandClause
 /// </summary>
 /// <param name="model">The model used for binding.</param>
 /// <param name="edmType">The entity type that the $select is being applied to.</param>
 /// <param name="maxDepth">the maximum recursive depth.</param>
 /// <param name="expandClauseToDecorate">The already built expand clause to decorate</param>
 /// <param name="resolver">Resolver for uri parser.</param>
 /// <param name="state">The binding state of the visitor.</param>
 public SelectPropertyVisitor(IEdmModel model, IEdmStructuredType edmType, int maxDepth, SelectExpandClause expandClauseToDecorate, ODataUriResolver resolver, BindingState state)
 {
     this.model    = model;
     this.edmType  = edmType;
     this.maxDepth = maxDepth;
     this.expandClauseToDecorate = expandClauseToDecorate;
     this.resolver = resolver;
     this.state    = state;
 }
Exemple #12
0
        /// <summary>
        /// Bind path segment's operation or operationImport's parameters.
        /// </summary>
        /// <param name="configuration">The ODataUriParserConfiguration.</param>
        /// <param name="functionOrOpertion">The function or operation.</param>
        /// <param name="segmentParameterTokens">The parameter tokens to be binded.</param>
        /// <returns>The binded semantic nodes.</returns>
        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 (FunctionParameterToken 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 (KeyValuePair <IEdmOperationParameter, SingleValueNode> item in result)
            {
                SingleValueNode boundNode = item.Value;

                // ensure node type is compatible with parameter type.
                IEdmTypeReference 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);
        }
Exemple #13
0
        /// <summary>
        /// Binds an In operator token.
        /// </summary>
        /// <param name="inToken">The In operator token to bind.</param>
        /// <param name="state">State of the metadata binding.</param>
        /// <returns>The bound In operator token.</returns>
        internal QueryNode BindInOperator(InToken inToken, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(inToken, "inToken");

            SingleValueNode left  = this.GetSingleValueOperandFromToken(inToken.Left);
            CollectionNode  right = this.GetCollectionOperandFromToken(
                inToken.Right, new EdmCollectionTypeReference(new EdmCollectionType(left.TypeReference)), state.Model);

            return(new InNode(left, right));
        }
Exemple #14
0
        /// <summary>
        /// Build a new MetadataBinder to use for expand options.
        /// </summary>
        private static MetadataBinder BuildNewMetadataBinder(ODataUriParserConfiguration config,
                                                             IEdmNavigationSource targetNavigationSource,
                                                             IEdmTypeReference elementType,
                                                             HashSet <EndPathToken> generatedProperties = null,
                                                             bool collapsed = false)
        {
            BindingState state = CreateBindingState(config, targetNavigationSource, elementType, generatedProperties, collapsed);

            return(new MetadataBinder(state));
        }
Exemple #15
0
        public SelectExpandBinder(ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo, BindingState state)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(odataPathInfo.TargetStructuredType, "edmType");

            this.configuration    = configuration;
            this.edmType          = odataPathInfo.TargetStructuredType;
            this.navigationSource = odataPathInfo.TargetNavigationSource;
            this.parsedSegments   = odataPathInfo.Segments.ToList();
            this.state            = state;
        }
Exemple #16
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));
        }
Exemple #17
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));
        }
        /// <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));
        }
Exemple #19
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);
        }
Exemple #20
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));
            }
        }
Exemple #21
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);
        }
        /// <summary>
        /// Parses the <paramref name="select"/> and <paramref name="expand"/> clauses, binding
        /// the text into a metadata-bound list of properties to be selected using the provided model.
        /// </summary>
        /// <param name="select">String representation of the select expression from the URI.</param>
        /// <param name="expand">String representation of the expand expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="SelectExpandClause"/> representing the metadata bound select and expand expression.</returns>
        private SelectExpandClause ParseSelectAndExpandImplementation(string select, string expand, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");

            ExpandToken expandTree;
            SelectToken selectTree;

            // syntactic pass , pass in the expand parent entity type name, in case expand option contains star, will get all the parent entity navigation properties (both declared and dynamical).
            SelectExpandSyntacticParser.Parse(select, expand, odataPathInfo.TargetStructuredType, configuration, out expandTree, out selectTree);

            // semantic pass
            BindingState state = CreateBindingState(configuration, odataPathInfo);

            return(SelectExpandSemanticBinder.Bind(odataPathInfo, expandTree, selectTree, configuration, state));
        }
        /// <summary>
        /// Parses the <paramref name="compute"/> clause, binding
        /// the text into a metadata-bound list of compuations using the provided model.
        /// </summary>
        /// <param name="compute">String representation of the compute expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="ComputeClause"/> representing the metadata bound compute expression.</returns>
        private ComputeClause ParseComputeImplementation(string compute, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(compute, "compute");

            // Get the syntactic representation of the apply expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            ComputeToken             computeToken     = expressionParser.ParseCompute(compute);

            // Bind it to metadata
            BindingState   state         = CreateBindingState(configuration, odataPathInfo);
            MetadataBinder binder        = new MetadataBinder(state);
            ComputeBinder  computeBinder = new ComputeBinder(binder.Bind);
            ComputeClause  boundNode     = computeBinder.BindCompute(computeToken);

            return(boundNode);
        }
        private static BindingState CreateBindingState(ODataUriParserConfiguration config,
                                                       IEdmNavigationSource resourcePathNavigationSource, IEdmNavigationSource targetNavigationSource,
                                                       IEdmTypeReference elementType, HashSet <EndPathToken> generatedProperties = null,
                                                       bool collapsed = false)
        {
            if (targetNavigationSource == null && elementType == null)
            {
                return(null);
            }

            // For example if we have https://url/Books?$expand=Authors($filter=Name eq $it/Name)
            // $filter=Name will reference Authors(the expanded entity).
            // $it/Name will reference Books(the resource identified by the path).
            // The BindingState ImplicitRangeVariable property will store the $it that references the expanded/selected item (The Implicit Range Variable).
            // We add to the Stack, the $it that references the resource identified by the path (The Explicit Range Variable).

            BindingState state = new BindingState(config)
            {
                ImplicitRangeVariable =
                    NodeFactory.CreateImplicitRangeVariable(elementType != null ? elementType :
                                                            targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
            };

            state.AggregatedPropertyNames      = generatedProperties;
            state.IsCollapsed                  = collapsed;
            state.ResourcePathNavigationSource = resourcePathNavigationSource;

            if (resourcePathNavigationSource != null)
            {
                // This $it rangeVariable will be added the Stack.
                // We are adding a rangeVariable whose navigationSource is the resource path entity set.
                // ODATA spec: Example 106 http://docs.oasis-open.org/odata/odata/v4.01/csprd05/part2-url-conventions/odata-v4.01-csprd05-part2-url-conventions.html#sec_it
                RangeVariable explicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(
                    resourcePathNavigationSource.EntityType().ToTypeReference(), resourcePathNavigationSource);
                state.RangeVariables.Push(explicitRangeVariable);
            }

            // Create $this rangeVariable and add it to the Stack.
            RangeVariable dollarThisRangeVariable = NodeFactory.CreateDollarThisRangeVariable(
                elementType != null ? elementType : targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource);

            state.RangeVariables.Push(dollarThisRangeVariable);

            return(state);
        }
Exemple #25
0
        private BindingState CreateBindingState(IEdmNavigationSource targetNavigationSource, HashSet <EndPathToken> generatedProperties, bool collapsed)
        {
            if (targetNavigationSource == null)
            {
                return(null);
            }

            BindingState state = new BindingState(this.configuration)
            {
                ImplicitRangeVariable =
                    NodeFactory.CreateImplicitRangeVariable(targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
            };

            state.RangeVariables.Push(state.ImplicitRangeVariable);
            state.AggregatedPropertyNames = generatedProperties;
            state.IsCollapsed             = collapsed;
            return(state);
        }
        /// <summary>
        /// Parses an <paramref name="orderBy "/> clause, 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="odataPathInfo">The path info from Uri path.</param>
        /// <returns>An <see cref="OrderByClause"/> representing the metadata bound orderby expression.</returns>
        private OrderByClause ParseOrderByImplementation(string orderBy, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(configuration.Model, "model");
            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 = CreateBindingState(configuration, odataPathInfo);

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

            return(orderByClause);
        }
        /// <summary>
        /// Parses a <paramref name="filter"/> clause, 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="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="FilterClause"/> representing the metadata bound filter expression.</returns>
        private FilterClause ParseFilterImplementation(string filter, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(odataPathInfo, "odataPathInfo");
            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 = CreateBindingState(configuration, odataPathInfo);

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

            return(boundNode);
        }
Exemple #28
0
        /// <summary>
        /// Bind the select and expand clause <see cref="SelectExpandClause"/> at this level.
        /// </summary>
        /// <param name="expandToken">The expand token to visit.</param>
        /// <param name="selectToken">The select token to visit.</param>
        /// <param name="segments">The parsed segments to visit.</param>
        /// <returns>The null or the built select and expand clause.</returns>
        private SelectExpandClause BindSelectExpand(ExpandToken expandToken, SelectToken selectToken,
                                                    IList <ODataPathSegment> segments, IEdmNavigationSource navigationSource, IEdmTypeReference elementType,
                                                    HashSet <EndPathToken> generatedProperties = null, bool collapsed = false)
        {
            if (expandToken != null || selectToken != null)
            {
                BindingState binding = CreateBindingState(this.Configuration, navigationSource, elementType, generatedProperties, collapsed);

                SelectExpandBinder selectExpandBinder = new SelectExpandBinder(this.Configuration,
                                                                               new ODataPathInfo(new ODataPath(segments)), binding);

                return(selectExpandBinder.Bind(expandToken, selectToken));
            }
            else
            {
                // It's better to return null for both Expand and Select are null.
                // However, in order to be consistent, we returns the empty SelectExpandClause with AllSelected = true.
                return(new SelectExpandClause(new Collection <SelectItem>(), true));
            }
        }
        /// <summary>
        /// Parses an <paramref name="apply"/> clause, 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="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="ApplyClause"/> representing the metadata bound apply expression.</returns>
        private static ApplyClause ParseApplyImplementation(string apply, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            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, odataPathInfo.Segments.ToList());

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            MetadataBinder binder      = new MetadataBinder(state);
            ApplyBinder    applyBinder = new ApplyBinder(binder.Bind, state, configuration, odataPathInfo);
            ApplyClause    boundNode   = applyBinder.BindApply(applyTokens);

            return(boundNode);
        }
        /// <summary>
        /// Parses the <paramref name="compute"/> clause, binding
        /// the text into a metadata-bound list of compuations using the provided model.
        /// </summary>
        /// <param name="compute">String representation of the compute expression from the URI.</param>
        /// <param name="configuration">The configuration used for binding.</param>
        /// <param name="odataPathInfo">The path info from Uri path.</param>
        /// <returns>A <see cref="ComputeClause"/> representing the metadata bound compute expression.</returns>
        private static ComputeClause ParseComputeImplementation(string compute, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)
        {
            ExceptionUtils.CheckArgumentNotNull(configuration, "configuration");
            ExceptionUtils.CheckArgumentNotNull(compute, "compute");

            // Get the syntactic representation of the apply expression
            UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(configuration.Settings.FilterLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier);
            ComputeToken             computeToken     = expressionParser.ParseCompute(compute);

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

            state.ImplicitRangeVariable = NodeFactory.CreateImplicitRangeVariable(odataPathInfo.TargetEdmType.ToTypeReference(), odataPathInfo.TargetNavigationSource);
            state.RangeVariables.Push(state.ImplicitRangeVariable);
            MetadataBinder binder        = new MetadataBinder(state);
            ComputeBinder  computeBinder = new ComputeBinder(binder.Bind);
            ComputeClause  boundNode     = computeBinder.BindCompute(computeToken);

            return(boundNode);
        }