public void SingleLevelExpandTermTokenWorks()
 {
     ExpandTermToken expandTermToken = new ExpandTermToken(new NonSystemToken("MyDog", null, null));
     ExpandToken expandToken = new ExpandToken(new ExpandTermToken[] {expandTermToken});
     var item = this.binderForPerson.Bind(BuildUnifiedSelectExpandToken(expandToken));
     item.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetPersonMyDogNavProp()).And.SelectAndExpand.AllSelected.Should().BeTrue();
 }
        /// <summary>
        /// Invert the all of the paths in an expandToken, such that they are now in the same order as they are present in the 
        /// base url
        /// </summary>
        /// <param name="treeToInvert">the tree to invert paths on</param>
        /// <returns>a new tree with all of its paths inverted</returns>
        public ExpandToken NormalizePaths(ExpandToken treeToInvert)
        {
            // iterate through each expand term token, and reverse the tree in its path property
            List<ExpandTermToken> updatedTerms = new List<ExpandTermToken>();
            foreach (ExpandTermToken term in treeToInvert.ExpandTerms)
            {
                PathReverser pathReverser = new PathReverser();
                PathSegmentToken reversedPath = term.PathToNavProp.Accept(pathReverser);

                // we also need to call the select token normalizer for this level to reverse the select paths
                SelectToken newSelectToken = term.SelectOption;
                if (term.SelectOption != null)
                {
                    SelectTreeNormalizer selectTreeNormalizer = new SelectTreeNormalizer();
                    newSelectToken = selectTreeNormalizer.NormalizeSelectTree(term.SelectOption);
                }

                ExpandToken subExpandTree;
                if (term.ExpandOption != null)
                {
                    subExpandTree = this.NormalizePaths(term.ExpandOption);
                }
                else
                {
                    subExpandTree = null;
                }

                ExpandTermToken newTerm = new ExpandTermToken(reversedPath, term.FilterOption, term.OrderByOptions, term.TopOption, term.SkipOption, term.CountQueryOption, term.LevelsOption, term.SearchOption, newSelectToken, subExpandTree);
                updatedTerms.Add(newTerm);
            }

            return new ExpandToken(updatedTerms);
        }
        /// <summary>
        /// Collapse all redundant terms in an expand tree
        /// </summary>
        /// <param name="treeToCollapse">the tree to collapse</param>
        /// <returns>A new tree with all redundant terms collapsed.</returns>
        public ExpandToken CombineTerms(ExpandToken treeToCollapse)
        {
            var combinedTerms = new Dictionary<PathSegmentToken, ExpandTermToken>(new PathSegmentTokenEqualityComparer());
            foreach (ExpandTermToken termToken in treeToCollapse.ExpandTerms)
            {
                ExpandTermToken finalTermToken = termToken;
                if (termToken.ExpandOption != null)
                {
                    ExpandToken newSubExpand = CombineTerms(termToken.ExpandOption);
                    finalTermToken = new ExpandTermToken(
                                                              termToken.PathToNavProp,
                                                              termToken.FilterOption,
                                                              termToken.OrderByOptions,
                                                              termToken.TopOption,
                                                              termToken.SkipOption,
                                                              termToken.CountQueryOption,
                                                              termToken.LevelsOption,
                                                              termToken.SearchOption,
                                                              RemoveDuplicateSelect(termToken.SelectOption),
                                                              newSubExpand);
                }

                AddOrCombine(combinedTerms, finalTermToken);
            }

            return new ExpandToken(combinedTerms.Values);
        }
 public void CombineTermsWorksOnASingleTerm()
 {
     // $expand=stuff
     ExpandToken expand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("stuff", null, null)) });
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken combinedExpand = expandTreeNormalizer.CombineTerms(expand);
     combinedExpand.ExpandTerms.Single().ShouldBeExpandTermToken("stuff", false);
 }
        /// <summary>
        /// Normalize an expand syntax tree into the new ExpandOption syntax.
        /// </summary>
        /// <param name="treeToNormalize">the tree to normalize</param>
        /// <returns>a new tree, in the new ExpandOption syntax</returns>
        public ExpandToken NormalizeExpandTree(ExpandToken treeToNormalize)
        {
            // To normalize the expand tree we need to
            // 1) invert the path tree on each of its expand term tokens
            // 2) combine terms that start with the path tree
            ExpandToken invertedPathTree = this.NormalizePaths(treeToNormalize);

            return CombineTerms(invertedPathTree);
        }
 public void InvertPathsActuallyInvertsPaths()
 {
     // $expand=1/2
     ExpandToken expand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("2", null, new NonSystemToken("1", null, null))) });
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken invertedPaths = expandTreeNormalizer.NormalizePaths(expand);
     invertedPaths.ExpandTerms.Single().ShouldBeExpandTermToken("1", false)
         .And.PathToNavProp.NextToken.ShouldBeNonSystemToken("2");
 }
 public void BindingOnTreeWithWithMultipleNavPropPathsThrows()
 {
     NonSystemToken topLevelSegment = new NonSystemToken("MyDog", null, null);
     NonSystemToken navProp = new NonSystemToken("MyPeople", null, topLevelSegment);
     ExpandTermToken expandTerm = new ExpandTermToken(navProp);
     ExpandToken expandToken = new ExpandToken(new ExpandTermToken[] {expandTerm});
     Action bindTreeWithMultipleNavPropPaths = () => this.binderForPerson.Bind(BuildUnifiedSelectExpandToken(expandToken));
     bindTreeWithMultipleNavPropPaths.ShouldThrow<ODataException>()
                         .WithMessage(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath);
 }
 public void NormalizeTreeWorksWhenPathsHaveArguments()
 {
     // $expand=1(name=value)/2
     ExpandToken expand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("1", new NamedValue[] { new NamedValue("name", new LiteralToken("value")) }, null)) });
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken normalizedExpand = expandTreeNormalizer.NormalizeExpandTree(expand);
     normalizedExpand.ExpandTerms.Single().ShouldBeExpandTermToken("1", true)
         .And.PathToNavProp.As<NonSystemToken>().NamedValues.Single().ShouldBeNamedValue("name", "value");
     normalizedExpand.ExpandTerms.Single().ExpandOption.Should().BeNull();
 }
 public void NullOriginalSelectTokenIsReflectedInNewTopLevelExpandToken()
 {
     ExpandToken originalExpand = new ExpandToken(
         new List<ExpandTermToken>()
         {
             new ExpandTermToken(new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null), /*SelectOption*/null, /*ExpandOption*/null)
         });
     SelectToken originalSelect = null;
     ExpandToken unifiedExpand = SelectExpandSyntacticUnifier.Combine(originalExpand, originalSelect);
     unifiedExpand.ExpandTerms.Single().SelectOption.Should().BeNull();
 }
 public void NormalizeAnExpandOptionSyntaxTreeResultsInUnchangedOutput()
 {
     // $expand=1($expand=2;)
     ExpandToken innerExpand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("2", null, null)) });
     ExpandToken expand = new ExpandToken(new ExpandTermToken[]{new ExpandTermToken(new NonSystemToken("1", null, null),
                                                                null /*selectOption*/,
                                                                innerExpand)});
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken normalizedExpand = expandTreeNormalizer.NormalizeExpandTree(expand);
     normalizedExpand.ExpandTerms.Single().ShouldBeExpandTermToken("1", true)
         .And.ExpandOption.ExpandTerms.Single().ShouldBeExpandTermToken("2", true)
         .And.ExpandOption.Should().BeNull();
 }
 public void CombineTermsWorksForMultipleTerms()
 {
     // $expand=1($expand=2), 1($expand=3)
     List<ExpandTermToken> expandTerms = new List<ExpandTermToken>();
     var token2 = new NonSystemToken("2", null, null);
     var token3 = new NonSystemToken("3", null, null);
     expandTerms.Add(new ExpandTermToken(new NonSystemToken("1", /*namedValues*/null, /*nextToken*/null), /*SelectToken*/null, new ExpandToken(new List<ExpandTermToken>() { new ExpandTermToken(token2) })));
     expandTerms.Add(new ExpandTermToken(new NonSystemToken("1", /*namedValues*/null, /*nextToken*/null), /*SelectToken*/null, new ExpandToken(new List<ExpandTermToken>() { new ExpandTermToken(token3) })));
     ExpandToken expand = new ExpandToken(expandTerms);
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken combinedExpand = expandTreeNormalizer.CombineTerms(expand);
     combinedExpand.ExpandTerms.Single().ShouldBeExpandTermToken("1", true);
     combinedExpand.ExpandTerms.ElementAt(0).ExpandOption.ExpandTerms.Should().Contain(t => t.PathToNavProp == token2);
     combinedExpand.ExpandTerms.ElementAt(0).ExpandOption.ExpandTerms.Should().Contain(t => t.PathToNavProp == token3);
 }
 public void NewTopLevelExpandTokenReferencesDollarIt()
 {
     ExpandToken originalExpand = new ExpandToken(
         new List<ExpandTermToken>()
         {
             new ExpandTermToken(new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null), /*SelectOption*/null, /*ExpandOption*/null)
         });
     SelectToken originalSelect = new SelectToken(
         new List<PathSegmentToken>()
         {
             new NonSystemToken("Name", /*namedValues*/null, /*nextToken*/null)
         });
     ExpandToken unifiedExpand = SelectExpandSyntacticUnifier.Combine(originalExpand, originalSelect);
     unifiedExpand.ExpandTerms.Single().ShouldBeExpandTermToken(ExpressionConstants.It, true);
 }
        public void SelectClauseIsAddedAsNewTopLevelExpandToken()
        {
            ExpandToken originalExpand = new ExpandToken(
                new List<ExpandTermToken>()
                {
                    new ExpandTermToken(new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null), /*SelectOption*/null, /*ExpandOption*/null)
                });
            SelectToken originalSelect = new SelectToken(
                new List<PathSegmentToken>()
                {
                    new NonSystemToken("Name", /*namedValues*/null, /*nextToken*/null)
                });

            ExpandToken unifiedExpand = SelectExpandSyntacticUnifier.Combine(originalExpand, originalSelect);
            unifiedExpand.ExpandTerms.Single().As<ExpandTermToken>().SelectOption.ShouldBeSelectToken(new string[] {"Name"});
        }
 public void OriginalExpandTokenIsUnChanged()
 {
     ExpandToken originalExpand = new ExpandToken(
         new List<ExpandTermToken>()
         {
             new ExpandTermToken(new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null), /*SelectOption*/null, /*ExpandOption*/null)
         });
     SelectToken originalSelect = new SelectToken(
         new List<PathSegmentToken>()
         {
             new NonSystemToken("Name", /*namedValues*/null, /*nextToken*/null)
         });
     ExpandToken unifiedExpand = SelectExpandSyntacticUnifier.Combine(originalExpand, originalSelect);
     var subExpand = unifiedExpand.ExpandTerms.Single().As<ExpandTermToken>().ExpandOption;
     subExpand.ExpandTerms.Single().ShouldBeExpandTermToken("MyDog", false);
 }
        /// <summary>
        /// Add semantic meaning to a Select or Expand Token
        /// </summary>
        /// <param name="elementType">the top level entity type.</param>
        /// <param name="navigationSource">the top level navigation source</param>
        /// <param name="expandToken">the syntactically parsed expand token</param>
        /// <param name="selectToken">the syntactically parsed select token</param>
        /// <param name="configuration">The configuration to use for parsing.</param>
        /// <returns>A select expand clause bound to metadata.</returns>
        public SelectExpandClause Bind(
            IEdmStructuredType elementType, 
            IEdmNavigationSource navigationSource,
            ExpandToken expandToken, 
            SelectToken selectToken, 
            ODataUriParserConfiguration configuration)
        {
            ExpandToken unifiedSelectExpandToken = SelectExpandSyntacticUnifier.Combine(expandToken, selectToken);

            ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
            ExpandToken normalizedSelectExpandToken = expandTreeNormalizer.NormalizeExpandTree(unifiedSelectExpandToken);

            SelectExpandBinder selectExpandBinder = new SelectExpandBinder(configuration, elementType, navigationSource);
            SelectExpandClause clause = selectExpandBinder.Bind(normalizedSelectExpandToken);

            SelectExpandClauseFinisher.AddExplicitNavPropLinksWhereNecessary(clause);

            new ExpandDepthAndCountValidator(configuration.Settings.MaximumExpansionDepth, configuration.Settings.MaximumExpansionCount).Validate(clause);

            return clause;
        }
        /// <summary>
        /// Parse the raw select and expand strings into Abstract Syntax Trees
        /// </summary>
        /// <param name="selectClause">The raw select string</param>
        /// <param name="expandClause">the raw expand string</param>
        /// <param name="configuration">Configuration parameters</param>
        /// <param name="expandTree">the resulting expand AST</param>
        /// <param name="selectTree">the resulting select AST</param>
        public static void Parse(
            string selectClause, 
            string expandClause, 
            ODataUriParserConfiguration configuration, 
            out ExpandToken expandTree, 
            out SelectToken selectTree)
        {
            SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit
            };
            selectTree = selectParser.ParseSelect();

            SelectExpandParser expandParser = new SelectExpandParser(expandClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveBuiltinIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit,
                MaxFilterDepth = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth = configuration.Settings.SearchLimit
            };
            expandTree = expandParser.ParseExpand();
        }
        /// <summary>
        /// Parse the raw select and expand strings into Abstract Syntax Trees
        /// </summary>
        /// <param name="selectClause">the raw select string</param>
        /// <param name="expandClause">the raw expand string</param>
        /// <param name="parentEntityType">the parent entity type for expand option</param>
        /// <param name="configuration">the OData URI parser configuration</param>
        /// <param name="expandTree">the resulting expand AST</param>
        /// <param name="selectTree">the resulting select AST</param>
        public static void Parse(
            string selectClause, 
            string expandClause,
            IEdmStructuredType parentEntityType,
            ODataUriParserConfiguration configuration, 
            out ExpandToken expandTree, 
            out SelectToken selectTree)
        {
            SelectExpandParser selectParser = new SelectExpandParser(selectClause, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit
            };
            selectTree = selectParser.ParseSelect();

            SelectExpandParser expandParser = new SelectExpandParser(configuration.Resolver, expandClause, parentEntityType, configuration.Settings.SelectExpandLimit, configuration.EnableCaseInsensitiveUriFunctionIdentifier)
            {
                MaxPathDepth = configuration.Settings.PathLimit,
                MaxFilterDepth = configuration.Settings.FilterLimit,
                MaxOrderByDepth = configuration.Settings.OrderByLimit,
                MaxSearchDepth = configuration.Settings.SearchLimit
            };
            expandTree = expandParser.ParseExpand();
        }
示例#18
0
 public void ExpandSetCorrectly()
 {
     ExpandToken expand = new ExpandToken(new ExpandTermToken[]{new ExpandTermToken(new NonSystemToken("stuff", null, null),
                                                                                    null /*selectOption*/,
                                                                                    null /*expandOption*/ )});
     ExpandTermToken expandTerm = new ExpandTermToken(new NonSystemToken("stuff", null, null),
                                                      null /*selectOption*/,
                                                      expand);
     expandTerm.ExpandOption.Should().NotBeNull();
 }
 public void MultiLevelExpandTermTokenWorks()
 {
     ExpandTermToken innerExpandTerm = new ExpandTermToken(new NonSystemToken("MyPeople", null, null));
     ExpandTermToken outerExpandTerm = new ExpandTermToken(new NonSystemToken("MyDog", null, null), null,
                                                           new ExpandToken(new ExpandTermToken[]
                                                               {innerExpandTerm}));
     ExpandToken expandToken = new ExpandToken(new ExpandTermToken[] {outerExpandTerm});
     var item = this.binderForPerson.Bind(BuildUnifiedSelectExpandToken(expandToken));
     var subSelectExpand = item.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetPersonMyDogNavProp()).And.SelectAndExpand;
     subSelectExpand.AllSelected.Should().BeTrue();
     subSelectExpand.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetDogMyPeopleNavProp())
         .And.SelectAndExpand.AllSelected.Should().BeTrue();
 }
示例#20
0
        /// <summary>
        /// Create an expand term token
        /// </summary>
        /// <param name="pathToNavProp">the nav prop for this expand term</param>
        /// <param name="filterOption">the filter option for this expand term</param>
        /// <param name="orderByOptions">the orderby options for this expand term</param>
        /// <param name="topOption">the top option for this expand term</param>
        /// <param name="skipOption">the skip option for this expand term</param>
        /// <param name="countQueryOption">the query count option for this expand term</param>
        /// <param name="levelsOption">the levels option for this expand term</param>
        /// <param name="searchOption">the search option for this expand term</param>
        /// <param name="selectOption">the select option for this expand term</param>
        /// <param name="expandOption">the expand option for this expand term</param>
        public ExpandTermToken(PathSegmentToken pathToNavProp, QueryToken filterOption, IEnumerable <OrderByToken> orderByOptions, long?topOption, long?skipOption, bool?countQueryOption, long?levelsOption, QueryToken searchOption, SelectToken selectOption, ExpandToken expandOption)
        {
            ExceptionUtils.CheckArgumentNotNull(pathToNavProp, "property");

            this.pathToNavProp    = pathToNavProp;
            this.filterOption     = filterOption;
            this.orderByOptions   = orderByOptions;
            this.topOption        = topOption;
            this.skipOption       = skipOption;
            this.countQueryOption = countQueryOption;
            this.levelsOption     = levelsOption;
            this.searchOption     = searchOption;
            this.selectOption     = selectOption;
            this.expandOption     = expandOption;
        }
示例#21
0
 /// <summary>
 /// Visits an ExpandToken
 /// </summary>
 /// <param name="tokenIn">The ExpandToken to visit</param>
 /// <returns>A QueryNode bound to this ExpandToken</returns>
 public virtual T Visit(ExpandToken tokenIn)
 {
     throw new NotImplementedException();
 }
 public bool Visit(ExpandToken tokenIn)
 {
     throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "QueryToken of type '{0}' is not supported.", tokenIn.Kind));
 }
 public void CombineChildNodesWorksForTwoPopulatedNodes()
 {
     // $expand=1($expand=2), 1($expand=3)
     ExpandTermToken innerExpandTerm1 = new ExpandTermToken(new NonSystemToken("2", null, null));
     ExpandToken innerExpand1 = new ExpandToken(new ExpandTermToken[] { innerExpandTerm1 });
     ExpandTermToken outerExpandTerm1 = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                            null /*selectOption*/,
                                                            innerExpand1);
     ExpandTermToken innerExpandTerm2 = new ExpandTermToken(new NonSystemToken("3", null, null));
     ExpandToken innerExpand2 = new ExpandToken(new ExpandTermToken[] { innerExpandTerm2 });
     ExpandTermToken outerExpandTerm2 = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                            null /*selectOption*/,
                                                            innerExpand2);
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     IEnumerable<ExpandTermToken> combinedChildren = expandTreeNormalizer.CombineChildNodes(outerExpandTerm1, outerExpandTerm2);
     combinedChildren.Should().Contain(innerExpandTerm1).And.Contain(innerExpandTerm2);
 }
示例#24
0
        /// <summary>
        /// Building off of a PathSegmentToken, continue parsing any expand options (nested $filter, $expand, etc)
        /// to build up an ExpandTermToken which fully represents the tree that makes up this expand term.
        /// </summary>
        /// <param name="pathToken">The PathSegmentToken representing the parsed expand path whose options we are now parsing.</param>
        /// <param name="optionsText">A string of the text between the parenthesis after an expand option.</param>
        /// <returns>An expand term token based on the path token, and all available expand options.</returns>
        internal ExpandTermToken BuildExpandTermToken(PathSegmentToken pathToken, string optionsText)
        {
            // Setup a new lexer for parsing the optionsText
            this.lexer = new ExpressionLexer(optionsText ?? "", true /*moveToFirstToken*/, true /*useSemicolonDelimiter*/);

            QueryToken filterOption = null;
            IEnumerable <OrderByToken> orderByOptions = null;
            long?       topOption    = null;
            long?       skipOption   = null;
            bool?       countOption  = null;
            long?       levelsOption = null;
            QueryToken  searchOption = null;
            SelectToken selectOption = null;
            ExpandToken expandOption = null;

            if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.OpenParen)
            {
                // advance past the '('
                this.lexer.NextToken();

                // Check for (), which is not allowed.
                if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.CloseParen)
                {
                    throw new ODataException(ODataErrorStrings.UriParser_MissingExpandOption(pathToken.Identifier));
                }

                // Look for all the supported query options
                while (this.lexer.CurrentToken.Kind != ExpressionTokenKind.CloseParen)
                {
                    string text = this.enableCaseInsensitiveBuiltinIdentifier
                        ? this.lexer.CurrentToken.Text.ToLowerInvariant()
                        : this.lexer.CurrentToken.Text;
                    switch (text)
                    {
                    case ExpressionConstants.QueryOptionFilter:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string filterText = this.ReadQueryOption();

                        UriQueryExpressionParser filterParser = new UriQueryExpressionParser(this.MaxFilterDepth, enableCaseInsensitiveBuiltinIdentifier);
                        filterOption = filterParser.ParseFilter(filterText);
                        break;
                    }

                    case ExpressionConstants.QueryOptionOrderby:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string orderByText = this.ReadQueryOption();

                        UriQueryExpressionParser orderbyParser = new UriQueryExpressionParser(this.MaxOrderByDepth, enableCaseInsensitiveBuiltinIdentifier);
                        orderByOptions = orderbyParser.ParseOrderBy(orderByText);
                        break;
                    }

                    case ExpressionConstants.QueryOptionTop:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string topText = this.ReadQueryOption();

                        // TryParse requires a non-nullable non-negative long.
                        long top;
                        if (!long.TryParse(topText, out top) || top < 0)
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidTopOption(topText));
                        }

                        topOption = top;
                        break;
                    }

                    case ExpressionConstants.QueryOptionSkip:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string skipText = this.ReadQueryOption();

                        // TryParse requires a non-nullable non-negative long.
                        long skip;
                        if (!long.TryParse(skipText, out skip) || skip < 0)
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidSkipOption(skipText));
                        }

                        skipOption = skip;
                        break;
                    }

                    case ExpressionConstants.QueryOptionCount:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string countText = this.ReadQueryOption();
                        switch (countText)
                        {
                        case ExpressionConstants.KeywordTrue:
                        {
                            countOption = true;
                            break;
                        }

                        case ExpressionConstants.KeywordFalse:
                        {
                            countOption = false;
                            break;
                        }

                        default:
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidCountOption(countText));
                        }
                        }

                        break;
                    }

                    case ExpressionConstants.QueryOptionLevels:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string levelsText = this.ReadQueryOption();
                        long   level;

                        if (string.Equals(
                                ExpressionConstants.KeywordMax,
                                levelsText,
                                this.enableCaseInsensitiveBuiltinIdentifier ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
                        {
                            levelsOption = long.MinValue;
                        }
                        else if (!long.TryParse(levelsText, out level) || level < 0)
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidLevelsOption(levelsText));
                        }
                        else
                        {
                            levelsOption = level;
                        }

                        break;
                    }

                    case ExpressionConstants.QueryOptionSearch:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string searchText = this.ReadQueryOption();

                        SearchParser searchParser = new SearchParser(this.MaxSearchDepth);
                        searchOption = searchParser.ParseSearch(searchText);

                        break;
                    }

                    case ExpressionConstants.QueryOptionSelect:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string selectText = this.ReadQueryOption();

                        SelectExpandParser innerSelectParser = new SelectExpandParser(selectText, this.maxRecursionDepth, enableCaseInsensitiveBuiltinIdentifier);
                        selectOption = innerSelectParser.ParseSelect();
                        break;
                    }

                    case ExpressionConstants.QueryOptionExpand:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string expandText = this.ReadQueryOption();

                        SelectExpandParser innerExpandParser = new SelectExpandParser(expandText, this.maxRecursionDepth - 1, enableCaseInsensitiveBuiltinIdentifier);
                        expandOption = innerExpandParser.ParseExpand();
                        break;
                    }

                    default:
                    {
                        throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.lexer.ExpressionText));
                    }
                    }
                }

                // Move past the ')'
                this.lexer.NextToken();
            }

            // Either there was no '(' at all or we just read past the ')' so we should be at the end
            if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.End)
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.lexer.ExpressionText));
            }

            return(new ExpandTermToken(pathToken, filterOption, orderByOptions, topOption, skipOption, countOption, levelsOption, searchOption, selectOption, expandOption));
        }
 public void CanSelectPropertyOnNonEntityType()
 {
     ExpandTermToken expandTermToken = new ExpandTermToken(new SystemToken(ExpressionConstants.It, null), new SelectToken(new List<PathSegmentToken>(){new NonSystemToken("City", null, null)}), null );
     ExpandToken expandToken = new ExpandToken(new ExpandTermToken[] { expandTermToken });
     var item = this.binderForAddress.Bind(expandToken);
     item.SelectedItems.Single().ShouldBePathSelectionItem(new ODataPath(new PropertySegment(HardCodedTestModel.GetAddressCityProperty())));
 }
 public void SelectedAndExpandedNavPropProduceExpandedNavPropSelectionItemAndPathSelectionItem()
 {
     ExpandTermToken innerExpandTermToken = new ExpandTermToken(new NonSystemToken("MyDog", null, null));
     ExpandToken innerExpandToken = new ExpandToken(new ExpandTermToken[] { innerExpandTermToken });
     ExpandTermToken topLevelExpandTermToken = new ExpandTermToken(new SystemToken(ExpressionConstants.It, /*nextToken*/null), new SelectToken(new List<PathSegmentToken>(){new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null)}), innerExpandToken);
     ExpandToken topLevelExpandToken = new ExpandToken(new ExpandTermToken[]{topLevelExpandTermToken});
     var item = this.binderForPerson.Bind(topLevelExpandToken);
     item.SelectedItems.Should().HaveCount(2);
     item.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetPersonMyDogNavProp());
     item.SelectedItems.Last().ShouldBePathSelectionItem(new ODataPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), HardCodedTestModel.GetPeopleSet())));
 }
 public void EntitySetCorrectlyPopulatedAtEachLevel()
 {
     ExpandTermToken innerExpandTerm = new ExpandTermToken(new NonSystemToken("MyPeople", null, null));
     ExpandTermToken outerExpandTerm = new ExpandTermToken(new NonSystemToken("MyDog", null, null),
                                                           null,
                                                           new ExpandToken(new ExpandTermToken[] { innerExpandTerm }));
     ExpandToken expandToken = new ExpandToken(new ExpandTermToken[] { outerExpandTerm });
     var item = this.binderForPerson.Bind(BuildUnifiedSelectExpandToken(expandToken));
     var myDogExpandItem = item.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetPersonMyDogNavProp()).And;
     myDogExpandItem.NavigationSource.Should().Be(HardCodedTestModel.GetDogsSet());
     var myPeopleExpandItem = myDogExpandItem.SelectAndExpand.SelectedItems.First().ShouldBeExpansionFor(HardCodedTestModel.GetDogMyPeopleNavProp()).And;
     myPeopleExpandItem.NavigationSource.Should().Be(HardCodedTestModel.GetPeopleSet());
     myPeopleExpandItem.SelectAndExpand.SelectedItems.Should().BeEmpty();
 }
示例#28
0
 /// <summary>
 /// Create a select term using only the property and its supporting query options.
 /// </summary>
 /// <param name="pathToProperty">the path to the property for this select term</param>
 /// <param name="filterOption">the filter option for this select term</param>
 /// <param name="orderByOptions">the orderby options for this select term</param>
 /// <param name="topOption">the top option for this select term</param>
 /// <param name="skipOption">the skip option for this select term</param>
 /// <param name="countQueryOption">the query count option for this select term</param>
 /// <param name="searchOption">the search option for this select term</param>
 /// <param name="selectOption">the select option for this select term</param>
 /// <param name="expandOption">the expand option for this select term</param>
 public SelectTermToken(PathSegmentToken pathToProperty,
                        QueryToken filterOption, IEnumerable <OrderByToken> orderByOptions, long?topOption, long?skipOption, bool?countQueryOption, QueryToken searchOption, SelectToken selectOption, ExpandToken expandOption, ComputeToken computeOption)
     : base(pathToProperty, filterOption, orderByOptions, topOption, skipOption, countQueryOption, searchOption, selectOption, expandOption, computeOption)
 {
 }
示例#29
0
        /// <summary>
        /// Bind a sub level expand
        /// </summary>
        /// <param name="tokenIn">the token to visit</param>
        /// <returns>a SelectExpand clause based on this ExpandToken</returns>
        private SelectExpandClause BindSubLevel(ExpandToken tokenIn)
        {
            List <SelectItem> expandTerms = tokenIn.ExpandTerms.Select(this.GenerateExpandItem).Where(expandedNavigationSelectItem => expandedNavigationSelectItem != null).Cast <SelectItem>().ToList();

            return(new SelectExpandClause(expandTerms, true));
        }
示例#30
0
        /// <summary>
        /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="SyntacticTree"/>
        /// describing the query specified by the uri.
        /// </summary>
        /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param>
        /// <param name="serviceBaseUri">The base URI of the service.</param>
        /// <param name="maxDepth">The maximum depth of any single query part. Security setting to guard against DoS attacks causing stack overflows and such.</param>
        /// <returns>A new instance of <see cref="SyntacticTree"/> which represents the query specified in the <paramref name="queryUri"/>.</returns>
        public static SyntacticTree ParseUri(Uri queryUri, Uri serviceBaseUri, int maxDepth)
        {
            ExceptionUtils.CheckArgumentNotNull(queryUri, "queryUri");
            if (!queryUri.IsAbsoluteUri)
            {
                throw new ArgumentException(Strings.SyntacticTree_UriMustBeAbsolute(queryUri), "queryUri");
            }

            ExceptionUtils.CheckArgumentNotNull(serviceBaseUri, "serviceBaseUri");
            if (!serviceBaseUri.IsAbsoluteUri)
            {
                throw new ArgumentException(Strings.SyntacticTree_UriMustBeAbsolute(serviceBaseUri), "serviceBaseUri");
            }

            if (maxDepth <= 0)
            {
                throw new ArgumentException(Strings.SyntacticTree_MaxDepthInvalid, "maxDepth");
            }


            UriPathParser pathParser = new UriPathParser(maxDepth);
            var           path       = pathParser.ParsePathIntoSegments(queryUri, serviceBaseUri);

            List <CustomQueryOptionToken> queryOptions     = UriUtils.ParseQueryOptions(queryUri);
            IDictionary <string, string>  parameterAliases = queryOptions.GetParameterAliases();

            QueryToken filter      = null;
            string     filterQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FilterQueryOption);

            if (filterQuery != null)
            {
                UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth);
                filter = expressionParser.ParseFilter(filterQuery);
            }

            IEnumerable <OrderByToken> orderByTokens = null;
            string orderByQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.OrderByQueryOption);

            if (orderByQuery != null)
            {
                UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth);
                orderByTokens = expressionParser.ParseOrderBy(orderByQuery);
            }

            SelectToken select      = null;
            string      selectQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SelectQueryOption);

            if (selectQuery != null)
            {
                SelectExpandParser selectParser = new SelectExpandParser(selectQuery, ODataUriParserSettings.DefaultSelectExpandLimit);
                select = selectParser.ParseSelect();
            }

            ExpandToken expand      = null;
            string      expandQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.ExpandQueryOption);

            if (expandQuery != null)
            {
                SelectExpandParser expandParser = new SelectExpandParser(expandQuery, ODataUriParserSettings.DefaultSelectExpandLimit);
                expand = expandParser.ParseExpand();
            }

            int?   skip      = null;
            string skipQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SkipQueryOption);

            if (skipQuery != null)
            {
                int skipValue;
                if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(skipQuery, out skipValue))
                {
                    throw new ODataException(Strings.SyntacticTree_InvalidSkipQueryOptionValue(skipQuery));
                }

                skip = skipValue;
            }

            int?   top      = null;
            string topQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.TopQueryOption);

            if (topQuery != null)
            {
                int topValue;
                if (!UriPrimitiveTypeParser.TryUriStringToNonNegativeInteger(topQuery, out topValue))
                {
                    throw new ODataException(Strings.SyntacticTree_InvalidTopQueryOptionValue(topQuery));
                }

                top = topValue;
            }

            string countQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.CountQueryOption);
            bool?  count      = QueryTokenUtils.ParseQueryCount(countQuery);

            string format = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FormatQueryOption);

            return(new SyntacticTree(
                       parameterAliases,
                       path,
                       filter,
                       orderByTokens,
                       select,
                       expand,
                       skip,
                       top,
                       count,
                       format,
                       queryOptions.Count == 0 ? null : new ReadOnlyCollection <CustomQueryOptionToken>(queryOptions)));
        }
 public void AddTermsDoesNothingForIdenticalTrees()
 {
     // $expand=1($expand=2;)
     ExpandToken innerExpand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("2", null, null)) });
     ExpandTermToken outerExpandToken = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                            null /*selectOption*/,
                                                            innerExpand);
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     var addedToken = expandTreeNormalizer.CombineTerms(outerExpandToken, outerExpandToken);
     addedToken.ShouldBeExpandTermToken("1", true).And.ExpandOption.ExpandTerms.Single().ShouldBeExpandTermToken("2", true);
 }
 public void AddTermsWorksForOneLevelBelow()
 {
     // $expand=1($expand=2;), 1($expand=3;)
     ExpandTermToken innerExpandTerm1 = new ExpandTermToken(new NonSystemToken("2", null, null));
     ExpandToken innerExpand1 = new ExpandToken(new ExpandTermToken[] { innerExpandTerm1 });
     ExpandTermToken outerToken1 = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                       null /*selectOption*/,
                                                       innerExpand1);
     ExpandTermToken innerExpandTerm2 = new ExpandTermToken(new NonSystemToken("3", null, null));
     ExpandToken innerExpand2 = new ExpandToken(new ExpandTermToken[] { innerExpandTerm2 });
     ExpandTermToken outerToken2 = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                       null /*selectOption*/,
                                                       innerExpand2);
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     var addedToken = expandTreeNormalizer.CombineTerms(outerToken1, outerToken2);
     addedToken.ShouldBeExpandTermToken("1", true).And.ExpandOption.ExpandTerms.Should().Contain(innerExpandTerm2).And.Contain(innerExpandTerm1);
 }
 public void LowerLevelEmptySelectedItemsListDoesNotThrow()
 {
     ExpandToken lowerLevelExpand = new ExpandToken(new List<ExpandTermToken>());
     ExpandTermToken topLevelExpandTermToken = new ExpandTermToken(new NonSystemToken("MyDog", /*namedValues*/null, /*nextToken*/null), null, lowerLevelExpand);
     ExpandToken topLevelExpand = new ExpandToken(new List<ExpandTermToken>(){topLevelExpandTermToken});
     Action bindWithEmptySelectedItemsList = () => this.binderForPerson.Bind(BuildUnifiedSelectExpandToken(topLevelExpand));
     bindWithEmptySelectedItemsList.ShouldNotThrow();
 }
 public void CombineChildNodesWorksForSingleEmptyNode()
 {
     // $expand=1($expand=2;), 1
     ExpandToken innerExpand = new ExpandToken(new ExpandTermToken[] { new ExpandTermToken(new NonSystemToken("2", null, null)) });
     ExpandTermToken outerExpandTerm1 = new ExpandTermToken(new NonSystemToken("1", null, null),
                                                            null /*selectOption*/,
                                                            innerExpand);
     ExpandTermToken outerExpandTerm2 = new ExpandTermToken(new NonSystemToken("1", null, null));
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     IEnumerable<ExpandTermToken> combinedChildren = expandTreeNormalizer.CombineChildNodes(outerExpandTerm1, outerExpandTerm2);
     combinedChildren.Single().ShouldBeExpandTermToken("2", false);
 }
 private static ExpandToken BuildUnifiedSelectExpandToken(ExpandToken expandToken, SelectToken selectToken)
 {
     return new ExpandToken(
         new ExpandTermToken[]
         {
             new ExpandTermToken(new NonSystemToken(ExpressionConstants.It, /*namedValues*/null, /*nextToken*/null), selectToken, expandToken)
         });
 }
示例#36
0
        /// <summary>
        /// Building off of a PathSegmentToken, continue parsing any expand options (nested $filter, $expand, etc)
        /// to build up an ExpandTermToken which fully represents the tree that makes up this expand term.
        /// </summary>
        /// <param name="pathToken">The PathSegmentToken representing the parsed expand path whose options we are now parsing.</param>
        /// <param name="optionsText">A string of the text between the parenthesis after an expand option.</param>
        /// <returns>The list of expand term tokens based on the path token, and all available expand options.</returns>
        internal List <ExpandTermToken> BuildExpandTermToken(PathSegmentToken pathToken, string optionsText)
        {
            // Setup a new lexer for parsing the optionsText
            this.lexer = new ExpressionLexer(optionsText ?? "", true /*moveToFirstToken*/, true /*useSemicolonDelimiter*/);

            // $expand option with star only support $ref option, $expand option property could be "*" or "*/$ref", special logic will be adopted.
            if (pathToken.Identifier == UriQueryConstants.Star || (pathToken.Identifier == UriQueryConstants.RefSegment && pathToken.NextToken.Identifier == UriQueryConstants.Star))
            {
                return(BuildStarExpandTermToken(pathToken));
            }

            QueryToken filterOption = null;
            IEnumerable <OrderByToken> orderByOptions = null;
            long?       topOption    = null;
            long?       skipOption   = null;
            bool?       countOption  = null;
            long?       levelsOption = null;
            QueryToken  searchOption = null;
            SelectToken selectOption = null;
            ExpandToken expandOption = null;

            if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.OpenParen)
            {
                // advance past the '('
                this.lexer.NextToken();

                // Check for (), which is not allowed.
                if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.CloseParen)
                {
                    throw new ODataException(ODataErrorStrings.UriParser_MissingExpandOption(pathToken.Identifier));
                }

                // Look for all the supported query options
                while (this.lexer.CurrentToken.Kind != ExpressionTokenKind.CloseParen)
                {
                    string text = this.enableCaseInsensitiveBuiltinIdentifier
                        ? this.lexer.CurrentToken.Text.ToLowerInvariant()
                        : this.lexer.CurrentToken.Text;
                    switch (text)
                    {
                    case ExpressionConstants.QueryOptionFilter:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string filterText = this.ReadQueryOption();

                        UriQueryExpressionParser filterParser = new UriQueryExpressionParser(this.MaxFilterDepth, enableCaseInsensitiveBuiltinIdentifier);
                        filterOption = filterParser.ParseFilter(filterText);
                        break;
                    }

                    case ExpressionConstants.QueryOptionOrderby:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string orderByText = this.ReadQueryOption();

                        UriQueryExpressionParser orderbyParser = new UriQueryExpressionParser(this.MaxOrderByDepth, enableCaseInsensitiveBuiltinIdentifier);
                        orderByOptions = orderbyParser.ParseOrderBy(orderByText);
                        break;
                    }

                    case ExpressionConstants.QueryOptionTop:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string topText = this.ReadQueryOption();

                        // TryParse requires a non-nullable non-negative long.
                        long top;
                        if (!long.TryParse(topText, out top) || top < 0)
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidTopOption(topText));
                        }

                        topOption = top;
                        break;
                    }

                    case ExpressionConstants.QueryOptionSkip:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string skipText = this.ReadQueryOption();

                        // TryParse requires a non-nullable non-negative long.
                        long skip;
                        if (!long.TryParse(skipText, out skip) || skip < 0)
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidSkipOption(skipText));
                        }

                        skipOption = skip;
                        break;
                    }

                    case ExpressionConstants.QueryOptionCount:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string countText = this.ReadQueryOption();
                        switch (countText)
                        {
                        case ExpressionConstants.KeywordTrue:
                        {
                            countOption = true;
                            break;
                        }

                        case ExpressionConstants.KeywordFalse:
                        {
                            countOption = false;
                            break;
                        }

                        default:
                        {
                            throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidCountOption(countText));
                        }
                        }

                        break;
                    }

                    case ExpressionConstants.QueryOptionLevels:
                    {
                        levelsOption = ResolveLevelOption();
                        break;
                    }

                    case ExpressionConstants.QueryOptionSearch:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string searchText = this.ReadQueryOption();

                        SearchParser searchParser = new SearchParser(this.MaxSearchDepth);
                        searchOption = searchParser.ParseSearch(searchText);

                        break;
                    }

                    case ExpressionConstants.QueryOptionSelect:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string selectText = this.ReadQueryOption();

                        SelectExpandParser innerSelectParser = new SelectExpandParser(selectText, this.maxRecursionDepth, enableCaseInsensitiveBuiltinIdentifier);
                        selectOption = innerSelectParser.ParseSelect();
                        break;
                    }

                    case ExpressionConstants.QueryOptionExpand:
                    {
                        // advance to the equal sign
                        this.lexer.NextToken();
                        string expandText = this.ReadQueryOption();

                        // As 2016/1/8, the navigation property is only supported in entity type, and will support in ComplexType in future.
                        IEdmStructuredType targetEntityType = null;
                        if (this.resolver != null && this.parentEntityType != null)
                        {
                            var parentProperty = this.resolver.ResolveProperty(parentEntityType, pathToken.Identifier) as IEdmNavigationProperty;

                            // it is a navigation property, need to find the type. Like $expand=Friends($expand=Trips($expand=*)), when expandText becomes "Trips($expand=*)", find navigation property Trips of Friends, then get Entity type of Trips.
                            if (parentProperty != null)
                            {
                                targetEntityType = parentProperty.ToEntityType();
                            }
                        }

                        SelectExpandParser innerExpandParser = new SelectExpandParser(resolver, expandText, targetEntityType, this.maxRecursionDepth - 1, enableCaseInsensitiveBuiltinIdentifier);
                        expandOption = innerExpandParser.ParseExpand();
                        break;
                    }

                    default:
                    {
                        throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.lexer.ExpressionText));
                    }
                    }
                }

                // Move past the ')'
                this.lexer.NextToken();
            }

            // Either there was no '(' at all or we just read past the ')' so we should be at the end
            if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.End)
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.lexer.ExpressionText));
            }

            // TODO, there should be some check here in case pathToken identifier is $ref, select, expand and levels options are not allowed.
            List <ExpandTermToken> expandTermTokenList = new List <ExpandTermToken>();
            ExpandTermToken        currentToken        = new ExpandTermToken(pathToken, filterOption, orderByOptions, topOption,
                                                                             skipOption, countOption, levelsOption, searchOption, selectOption, expandOption);

            expandTermTokenList.Add(currentToken);

            return(expandTermTokenList);
        }
示例#37
0
 /// <summary>
 /// Create an expand term using only the property and its subexpand/select
 /// </summary>
 /// <param name="pathToNavProp">the path to the navigation property for this expand term</param>
 /// <param name="selectOption">the sub select for this token</param>
 /// <param name="expandOption">the sub expand for this token</param>
 public ExpandTermToken(PathSegmentToken pathToNavProp, SelectToken selectOption, ExpandToken expandOption)
     : this(pathToNavProp, null, null, null, null, null, null, null, selectOption, expandOption)
 {
 }
 private static ExpandToken BuildUnifiedSelectExpandToken(ExpandToken expandToken)
 {
     return BuildUnifiedSelectExpandToken(expandToken, null);
 }
示例#39
0
        /// <summary>
        /// Parses the <paramref name="queryUri"/> and returns a new instance of <see cref="SyntacticTree"/>
        /// describing the query specified by the uri.
        /// </summary>
        /// <param name="queryUri">The absolute URI which holds the query to parse. This must be a path relative to the <paramref name="serviceBaseUri"/>.</param>
        /// <param name="serviceBaseUri">The base URI of the service.</param>
        /// <param name="maxDepth">The maximum depth of any single query part. Security setting to guard against DoS attacks causing stack overflows and such.</param>
        /// <returns>A new instance of <see cref="SyntacticTree"/> which represents the query specified in the <paramref name="queryUri"/>.</returns>
        public static SyntacticTree ParseUri(Uri queryUri, Uri serviceBaseUri, int maxDepth)
        {
            ExceptionUtils.CheckArgumentNotNull(queryUri, "queryUri");
            if (!queryUri.IsAbsoluteUri)
            {
                throw new ArgumentException(Strings.SyntacticTree_UriMustBeAbsolute(queryUri), "queryUri");
            }

            ExceptionUtils.CheckArgumentNotNull(serviceBaseUri, "serviceBaseUri");
            if (!serviceBaseUri.IsAbsoluteUri)
            {
                throw new ArgumentException(Strings.SyntacticTree_UriMustBeAbsolute(serviceBaseUri), "serviceBaseUri");
            }

            if (maxDepth <= 0)
            {
                throw new ArgumentException(Strings.SyntacticTree_MaxDepthInvalid, "maxDepth");
            }


            UriPathParser pathParser = new UriPathParser(maxDepth);
            var           path       = pathParser.ParsePathIntoSegments(queryUri, serviceBaseUri);

            // COMPAT 32: Differencies in query options parsing in WCF DS
            //
            // We allow non-system $ query options in the lexical space.
            // We allow multiple instances of a custom or non-system $ query option in the lexical space.
            // TODO: we need to decide whether we want to allow multiple system $ query options with the same name (OIPI suggests that this is valid); we currently don't.
            List <CustomQueryOptionToken> queryOptions     = UriUtils.ParseQueryOptions(queryUri);
            IDictionary <string, string>  parameterAliases = queryOptions.GetParameterAliases();

            QueryToken filter      = null;
            string     filterQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FilterQueryOption);

            if (filterQuery != null)
            {
                UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth);
                filter = expressionParser.ParseFilter(filterQuery);
            }

            IEnumerable <OrderByToken> orderByTokens = null;
            string orderByQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.OrderByQueryOption);

            if (orderByQuery != null)
            {
                UriQueryExpressionParser expressionParser = new UriQueryExpressionParser(maxDepth);
                orderByTokens = expressionParser.ParseOrderBy(orderByQuery);
            }

            SelectToken select      = null;
            string      selectQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SelectQueryOption);

            if (selectQuery != null)
            {
                SelectExpandParser selectParser = new SelectExpandParser(selectQuery, ODataUriParserSettings.DefaultSelectExpandLimit);
                select = selectParser.ParseSelect();
            }

            ExpandToken expand      = null;
            string      expandQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.ExpandQueryOption);

            if (expandQuery != null)
            {
                SelectExpandParser expandParser = new SelectExpandParser(expandQuery, ODataUriParserSettings.DefaultSelectExpandLimit);
                expand = expandParser.ParseExpand();
            }

            int?   skip      = null;
            string skipQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.SkipQueryOption);

            if (skipQuery != null)
            {
                int skipValue;
                if (!TryUriStringToNonNegativeInteger(skipQuery, out skipValue))
                {
                    throw new ODataException(Strings.SyntacticTree_InvalidSkipQueryOptionValue(skipQuery));
                }

                skip = skipValue;
            }

            int?   top      = null;
            string topQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.TopQueryOption);

            if (topQuery != null)
            {
                int topValue;
                if (!TryUriStringToNonNegativeInteger(topQuery, out topValue))
                {
                    throw new ODataException(Strings.SyntacticTree_InvalidTopQueryOptionValue(topQuery));
                }

                top = topValue;
            }

            string countQuery = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.CountQueryOption);
            bool?  count      = ParseQueryCount(countQuery);

            string format = queryOptions.GetQueryOptionValueAndRemove(UriQueryConstants.FormatQueryOption);

            return(new SyntacticTree(
                       parameterAliases,
                       path,
                       filter,
                       orderByTokens,
                       select,
                       expand,
                       skip,
                       top,
                       count,
                       format,
                       queryOptions.Count == 0 ? null : new ReadOnlyCollection <CustomQueryOptionToken>(queryOptions)));
        }
 public void InvertPathsKeepsExpandOptionsInvariant()
 {
     //$expand=1($filter=filter, $orderby=orderby, $top=top, $skip=skip;)
     ExpandToken expand = new ExpandToken(
                             new ExpandTermToken[] { 
                                 new ExpandTermToken(
                                     new NonSystemToken("1", null, null), 
                                     new LiteralToken("filter"), 
                                     new OrderByToken []{ new OrderByToken(new LiteralToken("orderby"), OrderByDirection.Descending)}, 
                                     1, 
                                     2, 
                                     false,
                                     3,
                                     new StringLiteralToken("searchme"), 
                                     new SelectToken(null), 
                                     new ExpandToken(null))
                             }
                         );
     ExpandTreeNormalizer expandTreeNormalizer = new ExpandTreeNormalizer();
     ExpandToken invertedPaths = expandTreeNormalizer.NormalizePaths(expand);
     var invertedToken = invertedPaths.ExpandTerms.Single();
     invertedToken.ShouldBeExpandTermToken("1", true);
     invertedToken.FilterOption.ShouldBeLiteralQueryToken("filter");
     invertedToken.OrderByOptions.Single().Expression.ShouldBeLiteralQueryToken("orderby");
     invertedToken.OrderByOptions.Single().Direction.Should().Be(OrderByDirection.Descending);
     invertedToken.TopOption.Should().Be(1);
     invertedToken.SkipOption.Should().Be(2);
     invertedToken.CountQueryOption.Should().BeFalse();
     invertedToken.LevelsOption.Should().Be(3);
     invertedToken.SearchOption.ShouldBeStringLiteralToken("searchme");
     invertedToken.SelectOption.Properties.Should().BeEmpty();
     invertedToken.ExpandOption.ExpandTerms.Should().BeEmpty();
 }
示例#41
0
 /// <summary>
 /// Create an select term using only the property and its subexpand/select
 /// </summary>
 /// <param name="pathToProperty">the path to the property for this select term</param>
 /// <param name="selectOption">the sub select for this token</param>
 /// <param name="expandOption">the sub expand for this token</param>
 public SelectTermToken(PathSegmentToken pathToProperty, SelectToken selectOption, ExpandToken expandOption)
     : this(pathToProperty, null, null, null, null, null, null, selectOption, expandOption, null)
 {
 }