Exemplo n.º 1
0
        public async Task TestDistinct_CosmosElementContinuationTokenAsync()
        {
            async Task ImplemenationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                // Run the ordered distinct query through the continuation api, should result in the same set
                // since the previous hash is passed in the continuation token.
                foreach (string query in new string[]
                {
                    "SELECT {0} VALUE c.age FROM c ORDER BY c.age",
                    "SELECT {0} VALUE c.name FROM c ORDER BY c.name",
                    "SELECT {0} VALUE c.name from c",
                    "SELECT {0} VALUE c.age from c",
                    "SELECT {0} VALUE c.mixedTypeField from c",
                    "SELECT {0} TOP 2147483647 VALUE c.city from c",
                    "SELECT {0} VALUE c.age from c ORDER BY c.name",
                })
                {
                    string               queryWithoutDistinct         = string.Format(query, "");
                    MockDistinctMap      documentsSeen                = new MockDistinctMap();
                    List <CosmosElement> documentsFromWithoutDistinct = await QueryTestsBase.RunQueryCombinationsAsync(
                        container,
                        queryWithoutDistinct,
                        new QueryRequestOptions()
                    {
                        MaxConcurrency = 10,
                        MaxItemCount   = 100,
                    },
                        QueryDrainingMode.HoldState | QueryDrainingMode.CosmosElementContinuationToken);

                    documentsFromWithoutDistinct = documentsFromWithoutDistinct
                                                   .Where(document => documentsSeen.Add(document, out UInt128 hash))
                                                   .ToList();

                    foreach (int pageSize in new int[] { 1, 10, 100 })
                    {
                        string queryWithDistinct = string.Format(query, "DISTINCT");
                        List <CosmosElement> documentsFromWithDistinct = await QueryTestsBase.RunQueryCombinationsAsync(
                            container,
                            queryWithDistinct,
                            new QueryRequestOptions()
                        {
                            MaxConcurrency = 10,
                            MaxItemCount   = pageSize
                        },
                            QueryDrainingMode.HoldState | QueryDrainingMode.CosmosElementContinuationToken);

                        Assert.AreEqual(
                            expected: CosmosArray.Create(documentsFromWithDistinct),
                            actual: CosmosArray.Create(documentsFromWithoutDistinct),
                            message: $"Documents didn't match for {queryWithDistinct} on a Partitioned container");
                    }
                }
            }

            await this.TestQueryDistinctBaseAsync(ImplemenationAsync);
        }
        public async Task TestDistinct_ExecuteNextAsync()
        {
            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                #region Queries
                // To verify distint queries you can run it once without the distinct clause and run it through a hash set
                // then compare to the query with the distinct clause.
                List <(string, bool)> queries = new List <(string, bool)>()
                {
                    // basic distinct queries
                    ("SELECT {0} VALUE null", true),

                    // number value distinct queries
                    ("SELECT {0} VALUE c.income from c", true),

                    // string value distinct queries
                    ("SELECT {0} VALUE c.name from c", true),

                    // array value distinct queries
                    ("SELECT {0} VALUE c.children from c", true),

                    // object value distinct queries
                    ("SELECT {0} VALUE c.pet from c", true),

                    // scalar expressions distinct query
                    ("SELECT {0} VALUE c.age % 2 FROM c", true),

                    // distinct queries with order by
                    ("SELECT {0} VALUE c.age FROM c ORDER BY c.age", false),

                    // distinct queries with top and no matching order by
                    ("SELECT {0} TOP 2147483647 VALUE c.age FROM c", false),

                    // distinct queries with top and  matching order by
                    ("SELECT {0} TOP 2147483647 VALUE c.age FROM c ORDER BY c.age", false),

                    // distinct queries with aggregates
                    ("SELECT {0} VALUE MAX(c.age) FROM c", false),

                    // distinct queries with joins
                    ("SELECT {0} VALUE c.age FROM p JOIN c IN p.children", true),

                    // distinct queries in subqueries
                    ("SELECT {0} r.age, s FROM r JOIN (SELECT DISTINCT VALUE c FROM (SELECT 1 a) c) s WHERE r.age > 25", false),

                    // distinct queries in scalar subqeries
                    ("SELECT {0} p.name, (SELECT DISTINCT VALUE p.age) AS Age FROM p", true),

                    // select *
                    ("SELECT {0} * FROM c", true)
                };
                #endregion
                #region ExecuteNextAsync API
                // run the query with distinct and without + MockDistinctMap
                // Should receive same results
                // PageSize = 1 guarantees that the backend will return some duplicates.
                foreach ((string query, bool allowDCount) in queries)
                {
                    string queryWithoutDistinct = string.Format(query, "");

                    QueryRequestOptions requestOptions = new QueryRequestOptions()
                    {
                        MaxItemCount = 100, MaxConcurrency = 100
                    };
                    FeedIterator <CosmosElement> documentQueryWithoutDistinct = container.GetItemQueryIterator <CosmosElement>(
                        queryWithoutDistinct,
                        requestOptions: requestOptions);

                    MockDistinctMap      documentsSeen = new MockDistinctMap();
                    List <CosmosElement> documentsFromWithoutDistinct = new List <CosmosElement>();
                    while (documentQueryWithoutDistinct.HasMoreResults)
                    {
                        FeedResponse <CosmosElement> cosmosQueryResponse = await documentQueryWithoutDistinct.ReadNextAsync();

                        foreach (CosmosElement document in cosmosQueryResponse)
                        {
                            if (documentsSeen.Add(document, out UInt128 hash))
                            {
                                documentsFromWithoutDistinct.Add(document);
                            }
                            else
                            {
                                // No Op for debugging purposes.
                            }
                        }
                    }

                    foreach (int pageSize in new int[] { 1, 10, 100 })
                    {
                        string queryWithDistinct = string.Format(query, "DISTINCT");
                        List <CosmosElement>         documentsFromWithDistinct = new List <CosmosElement>();
                        FeedIterator <CosmosElement> documentQueryWithDistinct = container.GetItemQueryIterator <CosmosElement>(
                            queryWithDistinct,
                            requestOptions: requestOptions);

                        while (documentQueryWithDistinct.HasMoreResults)
                        {
                            FeedResponse <CosmosElement> cosmosQueryResponse = await documentQueryWithDistinct.ReadNextAsync();

                            documentsFromWithDistinct.AddRange(cosmosQueryResponse);
                        }

                        Assert.AreEqual(documentsFromWithDistinct.Count, documentsFromWithoutDistinct.Count);
                        for (int i = 0; i < documentsFromWithDistinct.Count; i++)
                        {
                            CosmosElement documentFromWithDistinct    = documentsFromWithDistinct.ElementAt(i);
                            CosmosElement documentFromWithoutDistinct = documentsFromWithoutDistinct.ElementAt(i);
                            Assert.AreEqual(
                                expected: documentFromWithoutDistinct,
                                actual: documentFromWithDistinct,
                                message: $"{documentFromWithDistinct} did not match {documentFromWithoutDistinct} at index {i} for {queryWithDistinct}, with page size: {pageSize} on a container");
                        }

                        if (allowDCount)
                        {
                            string queryWithDCount = $"SELECT VALUE COUNT(1) FROM({queryWithDistinct})";

                            List <CosmosElement>         documentsWithDCount     = new List <CosmosElement>();
                            FeedIterator <CosmosElement> documentQueryWithDCount = container.GetItemQueryIterator <CosmosElement>(
                                queryWithDCount,
                                requestOptions: requestOptions);

                            while (documentQueryWithDCount.HasMoreResults)
                            {
                                FeedResponse <CosmosElement> cosmosQueryResponse = await documentQueryWithDCount.ReadNextAsync();

                                documentsWithDCount.AddRange(cosmosQueryResponse);
                            }

                            Assert.AreEqual(1, documentsWithDCount.Count);
                            long dcount = Number64.ToLong((documentsWithDCount.First() as CosmosNumber).Value);
                            Assert.AreEqual(documentsFromWithoutDistinct.Count, dcount);
                        }
                    }
                }
                #endregion
            }

            await this.TestQueryDistinctBaseAsync(ImplementationAsync);
        }