示例#1
0
        internal static string ToDebugString(this SyntacticTree queryDescriptor)
        {
            if (queryDescriptor == null)
            {
                return("(null)");
            }
            string result       = queryDescriptor.Path.ToDebugString();
            var    queryOptions = new List <KeyValuePair <string, string> >();

            if (queryDescriptor.Filter != null)
            {
                queryOptions.Add(new KeyValuePair <string, string>("$filter", queryDescriptor.Filter.ToDebugString()));
            }
            if (queryDescriptor.OrderByTokens != null)
            {
                queryOptions.Add(new KeyValuePair <string, string>("$orderby", string.Join(",", queryDescriptor.OrderByTokens.Select(ob => ob.ToDebugString()).ToArray())));
            }
            if (queryDescriptor.Select != null)
            {
                queryOptions.Add(new KeyValuePair <string, string>("$select", queryDescriptor.Select.ToDebugString()));
            }
            if (queryOptions.Count > 0)
            {
                result += "?" + string.Join("&", queryOptions.Select(qo => qo.Key + "=" + qo.Value).ToArray());
            }

            return(result);
        }
示例#2
0
        public void FormatExpressionTest()
        {
            string[] values = new string[] { "json", "xml", "foo", "bar" };

            var testCases = values.Select(value =>
                                          new
            {
                Value = value,
            });

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                SyntacticTree actual =
                    QueryTokenUtils.ParseQuery("Root", format: testCase.Value);

                SyntacticTree expected = new SyntacticTree(
                    null,
                    new[] { "Root" },
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    testCase.Value,
                    null);

                QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert);
            });
        }
        /// <summary>
        /// Binds a <see cref="SyntacticTree"/>.
        /// </summary>
        /// <param name="syntax">The query descriptor token to bind.</param>
        /// <returns>The bound query descriptor.</returns>
        public ODataUri BindTree(SyntacticTree syntax)
        {
            ExceptionUtils.CheckArgumentNotNull(syntax, "syntax");
            ExceptionUtils.CheckArgumentNotNull(syntax.Path, "syntax.Path");

            // Make a copy of query options since we may consume some of them as we bind the query
            bindingState.QueryOptions = new List <CustomQueryOptionToken>(syntax.QueryOptions);

            ParameterAliasValueAccessor parameterAliasValueAccessor = new ParameterAliasValueAccessor(syntax.ParameterAliases);
            ODataPath          path         = null;
            FilterClause       filter       = null;
            OrderByClause      orderBy      = null;
            long?              skip         = null;
            long?              top          = null;
            SelectExpandClause selectExpand = null;
            bool?              count        = null;

            // set parameterAliasValueAccessor for uri path, $filter, $orderby
            this.bindingState.Configuration.ParameterAliasValueAccessor = parameterAliasValueAccessor;

            // First bind the path
            path = ODataPathFactory.BindPath(syntax.Path, this.bindingState.Configuration);

            // If the path leads to a collection, then create a range variable that represents iterating over the collection
            var rangeVariable = NodeFactory.CreateImplicitRangeVariable(path);

            if (rangeVariable != null)
            {
                this.bindingState.RangeVariables.Push(rangeVariable);
            }

            if (syntax.Filter != null || syntax.OrderByTokens.Any())
            {
                this.bindingState.ImplicitRangeVariable = this.bindingState.RangeVariables.Peek();
            }

            // Apply filter first, then order-by, skip, top, select and expand
            filter = BindFilter(syntax, rangeVariable);

            orderBy = BindOrderBy(syntax, rangeVariable, path);

            skip = BindSkip(syntax, rangeVariable, path);

            top = BindTop(syntax, rangeVariable, path);

            selectExpand = BindSelectExpand(syntax, path, this.bindingState.Configuration);

            count = BindQueryCount(syntax, path);

            // Add the remaining query options to the query descriptor.
            List <QueryNode> boundQueryOptions = MetadataBinder.ProcessQueryOptions(this.bindingState, this.bindMethod);

            Debug.Assert(bindingState.QueryOptions == null, "this.queryOptions == null");
            bindingState.RangeVariables.Pop();
            bindingState.ImplicitRangeVariable = null;

            return(new ODataUri(parameterAliasValueAccessor, path, boundQueryOptions, selectExpand, filter, orderBy, skip, top, count));
        }
示例#4
0
        public void CountExpressionTest()
        {
            object[] values = new object[] { null, 0, 1, 2, 5, 11111, -2, 12.3, "Foo", -12.4m, 'c', (long)int.MaxValue + 1, (long)int.MinValue - 1, 2.3f, "(1)", "2 + 3", "int.MaxValue", "false", "true", "False", "True", "FaLSE", "trUE" };

            string           errorMessageTemplate = "Invalid value '{0}' for $count query option found. Valid values are '{1}'.";
            HashSet <string> correctValues        = new HashSet <string>(StringComparer.OrdinalIgnoreCase)
            {
                "true", "false"
            };
            string correctValuesStr = string.Join(", ", correctValues.ToArray());
            var    testCases        = values.Select(value =>
                                                    new
            {
                Value = value == null ? null : value.ToString(),
                ExpectedErrorMessage = value == null || correctValues.Contains(value.ToString())
                        ? null
                        : string.Format(CultureInfo.InvariantCulture, errorMessageTemplate, value, correctValuesStr).Replace('+', ' ')    // URI all + will be replace by space
            });

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                this.Assert.ExpectedException <ODataException>(
                    () =>
                {
                    SyntacticTree actual =
                        QueryTokenUtils.ParseQuery("Root", count: testCase.Value);

                    bool?countQuery = null;

                    if (testCase.Value != null)
                    {
                        bool countValue;
                        bool.TryParse(testCase.Value, out countValue);

                        countQuery = countValue;
                    }

                    SyntacticTree expected = new SyntacticTree(
                        null,
                        new[] { "Root" },
                        null,
                        null,
                        null,
                        null,
                        null,
                        null,
                        countQuery,
                        null,
                        null);

                    QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert);
                },
                    testCase.ExpectedErrorMessage,
                    null);
            });
        }
示例#5
0
 public void ParseThenBind()
 {
     var            serviceBaseUri = new Uri("http://server/service/");
     var            queryUri       = new Uri(serviceBaseUri, "Customers(1)");
     var            syntacticTree  = SyntacticTree.ParseUri(queryUri, serviceBaseUri);
     var            model          = new ODataModelBuilder().Add_Customer_EntityType().Add_Customers_EntitySet().GetServiceModel();
     MetadataBinder binder         = new MetadataBinder(model);
     var            semanticTree   = binder.BindQuery(syntacticTree);
 }
示例#6
0
        /// <summary>
        /// Parses the specified query into a query descriptor.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <returns>The parsed query.</returns>
        internal static SyntacticTree ParseQuery(string query)
        {
            Uri baseUri = new Uri("http://odata.org/test/");

            if (query.StartsWith("/"))
            {
                query = query.Substring(1);
            }

            return(SyntacticTree.ParseUri(new Uri(baseUri, query), baseUri));
        }
        public void BindExtensionTest()
        {
            var metadata = QueryTestMetadata.BuildTestMetadata(this.PrimitiveTypeResolver, this.UntypedDataServiceProviderFactory);

            MetadataBinder binder = new MetadataBinder(metadata);
            SyntacticTree  syntax = new SyntacticTree(new TestExtensionQueryToken(), null, null, null, null, null, null, null, null, null);

            this.Assert.ExpectedException <ODataException>(
                () => binder.BindQuery(syntax),
                "An unsupported extension query token was found.",
                "BindExtensionTest");
        }
        /// <summary>
        /// Bind a skip option
        /// </summary>
        /// <param name="syntax">a syntax tree containing the skip option</param>
        /// <param name="rangeVariable">the range variable that iterates over the top level collection</param>
        /// <param name="path">the top level path.</param>
        /// <returns>a nullable long representing this skip option</returns>
        public static long?BindSkip(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path)
        {
            if (syntax.Skip != null)
            {
                if (rangeVariable == null || !path.EdmType().IsEntityCollection())
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$skip"));
                }

                return(MetadataBinder.ProcessSkip(syntax.Skip));
            }

            return(null);
        }
        /// <summary>
        /// Bind a count option
        /// </summary>
        /// <param name="syntax">The count option to bind.</param>
        /// <param name="path">the top level path</param>
        /// <returns>a count representing this count option</returns>
        public static bool?BindQueryCount(SyntacticTree syntax, ODataPath path)
        {
            if (syntax.QueryCount != null)
            {
                if (!path.EdmType().IsEntityCollection())
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$count"));
                }

                return(syntax.QueryCount);
            }

            return(null);
        }
        /// <summary>
        /// Bind an orderby option
        /// </summary>
        /// <param name="syntax">a syntac tree containing the orderby option</param>
        /// <param name="rangeVariable">the range variable that iterates over the top level collection</param>
        /// <param name="path">the top level path</param>
        /// <returns>an OrderByClause representing this orderby option</returns>
        public OrderByClause BindOrderBy(SyntacticTree syntax, RangeVariable rangeVariable, ODataPath path)
        {
            if (syntax.OrderByTokens != null && syntax.OrderByTokens.Any())
            {
                if (rangeVariable == null || !path.EdmType().IsEntityCollection())
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$orderby"));
                }

                OrderByBinder orderByBinder = new OrderByBinder(this.bindMethod);
                return(orderByBinder.BindOrderBy(this.bindingState, syntax.OrderByTokens));
            }

            return(null);
        }
        /// <summary>
        /// Bind a filter option
        /// </summary>
        /// <param name="syntax">a syntactic tree containing the filter option</param>
        /// <param name="rangeVariable">the range variable that iterates over the top level collection.</param>
        /// <returns>A filter clause representing this filter option</returns>
        public FilterClause BindFilter(SyntacticTree syntax, RangeVariable rangeVariable)
        {
            if (syntax.Filter != null)
            {
                if (rangeVariable == null)
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$filter"));
                }

                FilterBinder filterBinder = new FilterBinder(this.bindMethod, this.bindingState);
                return(filterBinder.BindFilter(syntax.Filter));
            }

            return(null);
        }
        /// <summary>
        /// Bind a select and expand option.
        /// </summary>
        /// <param name="syntax">A syntax tree containing the select and expand options to bind</param>
        /// <param name="path">the top level path</param>
        /// <param name="configuration">The configuration to use for binding.</param>
        /// <returns>a select expand clause bound to metadata</returns>
        public static SelectExpandClause BindSelectExpand(SyntacticTree syntax, ODataPath path, ODataUriParserConfiguration configuration)
        {
            if (syntax.Select != null || syntax.Expand != null)
            {
                if (!path.EdmType().IsEntityCollection() && !path.EdmType().IsEntity())
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_QueryOptionNotApplicable("$select or $expand"));
                }

                SelectExpandSemanticBinder semanticBinder = new SelectExpandSemanticBinder();

                return(semanticBinder.Bind((IEdmEntityType)((IEdmCollectionTypeReference)path.EdmType()).ElementType().Definition, path.NavigationSource(), syntax.Expand, syntax.Select, configuration));
            }

            return(null);
        }
示例#13
0
 /// <summary>
 /// Verifies that two queries are equal.
 /// </summary>
 /// <param name="expected">The expected query.</param>
 /// <param name="actual">The actual query.</param>
 /// <param name="assert">Assertion handler to use.</param>
 internal static void VerifySyntaxTreesAreEqual(SyntacticTree expected, SyntacticTree actual, AssertionHandler assert)
 {
     try
     {
         if (!VerifyNullnessMatches(expected, actual, assert, "query"))
         {
             return;
         }
         VerifySyntaxTreesAreEqualImpl(expected, actual, assert);
     }
     catch (Exception)
     {
         assert.Warn("Expected query: " + expected.ToDebugString());
         assert.Warn("Actual query: " + actual.ToDebugString());
         throw;
     }
 }
示例#14
0
        public void ExpandExpressionTest()
        {
            IEnumerable <ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases()
                                                                   .Concat(ExpressionTestCase.BinaryOperatorTestCases())
                                                                   .Concat(ExpressionTestCase.UnaryOperatorTestCases())
                                                                   .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames))
                                                                   .Concat(ExpressionTestCase.ParenthesisTestCases())
                                                                   .Concat(ExpressionTestCase.FunctionCallTestCases());

            var testCases = expressionTestCases.Select(tc => new ExpandTestCase()
            {
                Expand = tc.Expression,
                ExpectedExpandToken = new ExpandToken(new QueryToken[] { tc.ExpectedToken })
            });

            // All expressions
            testCases.Concat(new ExpandTestCase[] { new ExpandTestCase()
                                                    {
                                                        Expand = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()),
                                                        ExpectedExpandToken = new ExpandToken(expressionTestCases.Select(tc => tc.ExpectedToken))
                                                    } });

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                SyntacticTree actual   = QueryTokenUtils.ParseQuery("Root", expand: testCase.Expand);
                SyntacticTree expected = new SyntacticTree(
                    new SegmentToken("Root", null, null),
                    null,
                    null,
                    null,
                    testCase.ExpectedExpandToken,
                    null,
                    null,
                    null,
                    null,
                    null);

                QueryTokenUtils.VerifySyntaxTreesAreEqual(
                    expected,
                    actual,
                    this.Assert);
            });
        }
        public static string GetOperationName(Uri requestUri, Uri baseAddress)
        {
            try
            {
                // remove the query part as they are irrelevant here and we dont want to fail parsing them.
                Uri               requestUriWithoutQuerypart = new Uri(requestUri.GetLeftPart(UriPartial.Path));
                SyntacticTree     syntacticTree = SyntacticTree.ParseUri(requestUriWithoutQuerypart, baseAddress);
                SegmentQueryToken lastSegment   = syntacticTree.Path as SegmentQueryToken;
                if (lastSegment != null && !String.IsNullOrEmpty(lastSegment.Name))
                {
                    return(lastSegment.Name);
                }
            }
            catch (Exception)
            {
            }

            return(null);
        }
示例#16
0
 private static void VerifySyntaxTreesAreEqualImpl(SyntacticTree expected, SyntacticTree actual, AssertionHandler assert)
 {
     VerifyStringsAreEqual(expected.Path, actual.Path, assert);
     VerifyQueryTokensAreEqual(expected.Filter, actual.Filter, assert);
     if (expected.OrderByTokens != null && actual.OrderByTokens != null)
     {
         VerifyQueryTokensAreEqual(expected.OrderByTokens.Cast <QueryToken>(), actual.OrderByTokens.Cast <QueryToken>(), assert);
     }
     else if ((expected.OrderByTokens != null && actual.OrderByTokens == null) || (expected.OrderByTokens == null && actual.OrderByTokens != null))
     {
         assert.Fail("Query tokens are different");
     }
     assert.AreEqual(expected.Skip, actual.Skip, "Skip values are different.");
     VerificationUtils.VerifyEnumerationsAreEqual(
         expected.QueryOptions,
         actual.QueryOptions,
         VerifyCustomQueryOptionQueryTokensAreEqual,
         (item) => item.ToDebugString(),
         assert);
 }
示例#17
0
        public void UriCheckTests()
        {
            this.Assert.ExpectedException <ODataException>(
                () => SyntacticTree.ParseUri(new Uri("http://www.odata.org/base1/foo"), new Uri("http://www.odata.org/base2/")),
                "The URI 'http://www.odata.org/base1/foo' is not valid because it is not based on 'http://www.odata.org/base2/'.",
                "The operation should fail if the request URI is not relative to the specified base.");

            // Starting with .Net 4.5, Uri.UnescapeDataString does not throw an exception on invalid sequence. It just does not unescape something
            // that it does not understand. Hence disabling these tests.
            //this.Assert.ExpectedException<ODataException>(
            //    () => SyntacticTree.ParseUri(new Uri("http://www.odata.org/base1/foo%ZZ%%/", true), new Uri("http://www.odata.org/base1/")),
            //    "Bad Request: there was an error in the query syntax.",
            //    "Wrong escape sequence should cause ODataException.");

            // Test the what will be a default max depth which should be 800
            string longUri = "http://www.odata.org/";

            for (int i = 0; i < 801; i++)
            {
                longUri += "seg/";
            }

            this.Assert.ExpectedException <ODataException>(
                () => SyntacticTree.ParseUri(new Uri(longUri), new Uri("http://www.odata.org/")),
                "Too many segments in URI.",
                "Recursion limit should reject long URI.");

            // Test the explicit max depth
            // Test short max depth
            longUri = "http://www.odata.org/";
            for (int i = 0; i < 11; i++)
            {
                longUri += "seg/";
            }

            this.Assert.ExpectedException <ODataException>(
                () => SyntacticTree.ParseUri(new Uri(longUri), new Uri("http://www.odata.org/"), 10),
                "Too many segments in URI.",
                "Recursion limit should reject long URI.");
        }
示例#18
0
        public void SelectExpressionTest()
        {
            IEnumerable<SelectExpressionTestCase> expressionTestCases = SelectExpressionTestCase.SelectPropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames);

            var testCases = expressionTestCases.Select(tc => new SelectTestCase()
            {
                Select = tc.Expression,
                ExpectedSelectToken = new SelectToken(new PathSegmentToken[] { tc.ExpectedToken })
            });

            // All expressions
            testCases.Concat(new SelectTestCase[] { new SelectTestCase()
            {
                Select = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()),
                ExpectedSelectToken = new SelectToken(expressionTestCases.Select(tc => tc.ExpectedToken))
            }});

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
                {
                    SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", select: testCase.Select);
                    SyntacticTree expected = new SyntacticTree(
                        new StartPathToken("Root", null, null),
                        null,
                        null,
                        testCase.ExpectedSelectToken,
                        null,
                        null,
                        null,
                        null,
                        null,
                        null);

                    QueryTokenUtils.VerifySyntaxTreesAreEqual(
                        expected,
                        actual,
                        this.Assert);
                });
        }
示例#19
0
        public void SelectExpressionTest()
        {
            IEnumerable <SelectExpressionTestCase> expressionTestCases = SelectExpressionTestCase.SelectPropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames);

            var testCases = expressionTestCases.Select(tc => new SelectTestCase()
            {
                Select = tc.Expression,
                ExpectedSelectToken = new SelectToken(new PathSegmentToken[] { tc.ExpectedToken })
            });

            // All expressions
            testCases.Concat(new SelectTestCase[] { new SelectTestCase()
                                                    {
                                                        Select = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()),
                                                        ExpectedSelectToken = new SelectToken(expressionTestCases.Select(tc => tc.ExpectedToken))
                                                    } });

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                SyntacticTree actual   = QueryTokenUtils.ParseQuery("Root", select: testCase.Select);
                SyntacticTree expected = new SyntacticTree(
                    new StartPathToken("Root", null, null),
                    null,
                    null,
                    testCase.ExpectedSelectToken,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);

                QueryTokenUtils.VerifySyntaxTreesAreEqual(
                    expected,
                    actual,
                    this.Assert);
            });
        }
示例#20
0
        void RunTest(bool includeSpaceAroundSymbols)
        {
            var testCases = new[]
            {
                new
                {
                    QueryOptions         = (List <KeyValuePair <string, string> >)null,
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$filter", "3 eq 2")
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("CustomValue", "null")
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("null", "CustomValue")
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$custom", "2")
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$a", "1"),
                        new KeyValuePair <string, string>("$b", "2"),
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("a", "1"),
                        new KeyValuePair <string, string>("$filter", "3 eq 2"),
                        new KeyValuePair <string, string>("b", "2"),
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$a", "1"),
                        new KeyValuePair <string, string>("$filter", "3 eq 2"),
                        new KeyValuePair <string, string>("$b", "2"),
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("a", "1"),
                        new KeyValuePair <string, string>("b", "2"),
                        new KeyValuePair <string, string>("a", "2"),
                        new KeyValuePair <string, string>("b", "4"),
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$filter", "3 eq 2"),
                        new KeyValuePair <string, string>("$filter", "2 eq 3"),
                        new KeyValuePair <string, string>("$b", "2"),
                    },
                    ExpectedErrorMessage = "Query option '$filter' was specified more than once, but it must be specified at most once.",
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$select", "Name")
                    },
                    ExpectedErrorMessage = (string)null,
                },
                new
                {
                    QueryOptions = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("$expand", "Products")
                    },
                    ExpectedErrorMessage = (string)null,
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                this.Assert.ExpectedException <ODataException>(
                    () =>
                {
                    SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", testCase.QueryOptions, includeSpaceAroundSymbols);
                    List <CustomQueryOptionToken> options = QueryTokenUtils.NormalizeAndRemoveBuiltInQueryOptions(testCase.QueryOptions);
                    options = options != null && options.Count == 0 ? null : options;

                    SyntacticTree expected = new SyntacticTree(
                        null,
                        new[] { "Feed" },
                        actual.Filter,
                        actual.OrderByTokens,
                        null,
                        null,
                        actual.Skip,
                        null,
                        null,
                        null,
                        options);

                    QueryTokenUtils.VerifySyntaxTreesAreEqual(expected, actual, this.Assert);
                },
                    testCase.ExpectedErrorMessage,
                    null);
            });
        }
示例#21
0
        private bool TryReadSearchFilter(HttpRequestBase request, out SearchFilter searchFilter)
        {
            var odataQuery = SyntacticTree.ParseUri(new Uri(SiteRoot + request.RawUrl), new Uri(SiteRoot));

            var keywordPath = odataQuery.Path as KeywordSegmentQueryToken;

            searchFilter = new SearchFilter
            {
                // HACK: The way the default paging works is WCF attempts to read up to the MaxPageSize elements. If it finds as many, it'll assume there
                // are more elements to be paged and generate a continuation link. Consequently we'll always ask to pull MaxPageSize elements so WCF generates the
                // link for us and then allow it to do a Take on the results. The alternative to do is roll our IDataServicePagingProvider, but we run into
                // issues since we need to manage state over concurrent requests. This seems like an easier solution.
                Take          = MaxPageSize,
                Skip          = odataQuery.Skip ?? 0,
                CountOnly     = keywordPath != null && keywordPath.Keyword == KeywordKind.Count,
                SortDirection = SortDirection.Ascending
            };

            var filterProperty = odataQuery.Filter as PropertyAccessQueryToken;

            if (filterProperty == null ||
                !(filterProperty.Name.Equals("IsLatestVersion", StringComparison.Ordinal) ||
                  filterProperty.Name.Equals("IsAbsoluteLatestVersion", StringComparison.Ordinal)))
            {
                // We'll only use the index if we the query searches for latest \ latest-stable packages
                return(false);
            }

            var orderBy = odataQuery.OrderByTokens.FirstOrDefault();

            if (orderBy == null || orderBy.Expression == null)
            {
                searchFilter.SortProperty = SortProperty.Relevance;
            }
            else if (orderBy.Expression.Kind == QueryTokenKind.PropertyAccess)
            {
                var propertyAccess = (PropertyAccessQueryToken)orderBy.Expression;
                if (propertyAccess.Name.Equals("DownloadCount", StringComparison.Ordinal))
                {
                    searchFilter.SortProperty = SortProperty.DownloadCount;
                }
                else if (propertyAccess.Name.Equals("Published", StringComparison.Ordinal))
                {
                    searchFilter.SortProperty = SortProperty.Recent;
                }
                else if (propertyAccess.Name.Equals("Id", StringComparison.Ordinal))
                {
                    searchFilter.SortProperty = SortProperty.DisplayName;
                }
                else
                {
                    Debug.WriteLine("Order by clause {0} is unsupported", propertyAccess.Name);
                    return(false);
                }
            }
            else if (orderBy.Expression.Kind == QueryTokenKind.FunctionCall)
            {
                var functionCall = (FunctionCallQueryToken)orderBy.Expression;
                if (functionCall.Name.Equals("concat", StringComparison.OrdinalIgnoreCase))
                {
                    // We'll assume this is concat(Title, Id)
                    searchFilter.SortProperty  = SortProperty.DisplayName;
                    searchFilter.SortDirection = orderBy.Direction == OrderByDirection.Descending ? SortDirection.Descending : SortDirection.Ascending;
                }
                else
                {
                    Debug.WriteLine("Order by clause {0} is unsupported", functionCall.Name);
                    return(false);
                }
            }
            else
            {
                Debug.WriteLine("Order by clause {0} is unsupported", orderBy.Expression.Kind);
                return(false);
            }
            return(true);
        }
示例#22
0
        public void OrderByExpressionTest()
        {
            IEnumerable <ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases()
                                                                   .Concat(ExpressionTestCase.BinaryOperatorTestCases())
                                                                   .Concat(ExpressionTestCase.UnaryOperatorTestCases())
                                                                   .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames))
                                                                   .Concat(ExpressionTestCase.ParenthesisTestCases())
                                                                   .Concat(ExpressionTestCase.FunctionCallTestCases());

            // Use filter expressions first without anything
            var filterWithNoDirection = expressionTestCases.Select(tc => new OrderByTestCase()
            {
                OrderBy = tc.Expression,
                ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Ascending) }
            });

            // Use filter expressions with asc
            var filterWithAscending = expressionTestCases.Select(tc => new OrderByTestCase()
            {
                OrderBy = tc.Expression + " asc",
                ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Ascending) }
            });

            // Use filter expressions with desc
            var filterWithDescending = expressionTestCases.Select(tc => new OrderByTestCase()
            {
                OrderBy = tc.Expression + " desc",
                ExpectedOrderByTokens = new OrderByToken[] { new OrderByToken(tc.ExpectedToken, OrderByDirection.Descending) }
            });

            // And now some order by specific cases with multiple orderbys
            var orderByTestCases = ExpressionTestCase.VariousExpressions().ToList().Variations(3).Select(tc =>
                                                                                                         new OrderByTestCase
            {
                OrderBy = string.Join(",", tc.Select((t, index) => t.Expression + ((index % 3 == 0) ? "" : ((index % 3 == 1) ? " asc" : " desc"))).ToArray()),
                ExpectedOrderByTokens = tc.Select((t, index) => new OrderByToken(
                                                      t.ExpectedToken,
                                                      (index % 3 == 2) ? OrderByDirection.Descending : OrderByDirection.Ascending)).ToArray()
            });

            CombinatorialEngineProvider.RunCombinations(
                filterWithNoDirection
                .Concat(filterWithAscending)
                .Concat(filterWithDescending)
                .Concat(orderByTestCases),
                (testCase) =>
            {
                SyntacticTree actual   = QueryTokenUtils.ParseQuery("Root", orderby: testCase.OrderBy);
                SyntacticTree expected = new SyntacticTree(
                    null,
                    new[] { "Root" },
                    null,
                    testCase.ExpectedOrderByTokens,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null,
                    null);

                QueryTokenUtils.VerifySyntaxTreesAreEqual(
                    expected,
                    actual,
                    this.Assert);
            });
        }
示例#23
0
 public void CanBuildSyntacticTree()
 {
     var serviceBaseUri = new Uri("http://server/service/");
     var queryUri       = new Uri(serviceBaseUri, "Customers(1)");
     var syntacticTree  = SyntacticTree.ParseUri(queryUri, serviceBaseUri);
 }
        public void ExpandExpressionTest()
        {
            IEnumerable<ExpressionTestCase> expressionTestCases = ExpressionTestCase.PrimitiveLiteralTestCases()
                .Concat(ExpressionTestCase.BinaryOperatorTestCases())
                .Concat(ExpressionTestCase.UnaryOperatorTestCases())
                .Concat(ExpressionTestCase.PropertyAccessTestCases(ExpressionTestCase.PropertyAccessNames))
                .Concat(ExpressionTestCase.ParenthesisTestCases())
                .Concat(ExpressionTestCase.FunctionCallTestCases());

            var testCases = expressionTestCases.Select(tc => new ExpandTestCase()
            {
                Expand = tc.Expression,
                ExpectedExpandToken = new ExpandToken(new QueryToken[] { tc.ExpectedToken })
            });

            // All expressions
            testCases.Concat(new ExpandTestCase[] { new ExpandTestCase()
            {
                Expand = string.Join(", ", expressionTestCases.Select(tc => tc.Expression).ToArray()),
                ExpectedExpandToken = new ExpandToken(expressionTestCases.Select(tc => tc.ExpectedToken))
            }});

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
                {
                    SyntacticTree actual = QueryTokenUtils.ParseQuery("Root", expand: testCase.Expand);
                    SyntacticTree expected = new SyntacticTree(
                        new SegmentToken("Root", null, null),
                        null,
                        null,
                        null,
                        testCase.ExpectedExpandToken,
                        null,
                        null,
                        null,
                        null,
                        null);

                    QueryTokenUtils.VerifySyntaxTreesAreEqual(
                        expected,
                        actual,
                        this.Assert);
                });
        }