Esempio 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);
        }
            static async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                    container,
                    "SELECT * FROM c");

                Assert.AreEqual(
                    documents.Count(),
                    queryResults.Count);
            }
        public async Task TestUnsupportedQueriesAsync()
        {
            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct | ConnectionModes.Gateway,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                NoDocuments,
                ImplementationAsync);

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                QueryRequestOptions feedOptions = new QueryRequestOptions
                {
                    MaxBufferedItemCount = 7000,
                    MaxConcurrency       = 10,
                    MaxItemCount         = 10,
                };

                string compositeAggregate = "SELECT COUNT(1) + 5 FROM c";

                string[] unsupportedQueries = new string[]
                {
                    compositeAggregate,
                };

                foreach (string unsupportedQuery in unsupportedQueries)
                {
                    try
                    {
                        await QueryTestsBase.RunQueryAsync(
                            container,
                            unsupportedQuery,
                            queryRequestOptions : feedOptions);

                        Assert.Fail("Expected query to fail due it not being supported.");
                    }
                    catch (CosmosException e)
                    {
                        Assert.IsTrue(e.Message.Contains("Compositions of aggregates and other expressions are not allowed."),
                                      e.Message);
                    }
                }
            }
        }
        public async Task TestBasicCrossPartitionQueryAsync()
        {
            int                  seed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            uint                 numberOfDocuments = 100;
            QueryOracleUtil      util           = new QueryOracle2(seed);
            IEnumerable <string> inputDocuments = util.GetDocuments(numberOfDocuments);

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                inputDocuments,
                ImplementationAsync);

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                foreach (int maxDegreeOfParallelism in new int[] { 1, 100 })
                {
                    foreach (int maxItemCount in new int[] { 10, 100 })
                    {
                        foreach (string query in new string[] { "SELECT c.id FROM c", "SELECT c._ts, c.id FROM c ORDER BY c._ts" })
                        {
                            QueryRequestOptions feedOptions = new QueryRequestOptions
                            {
                                MaxBufferedItemCount = 7000,
                                MaxConcurrency       = maxDegreeOfParallelism,
                                MaxItemCount         = maxItemCount,
                                ReturnResultsInDeterministicOrder = true,
                            };

                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                feedOptions);

                            Assert.AreEqual(
                                documents.Count(),
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }
                    }
                }
            }
        }
        public async Task TestExceptionlessFailuresAsync()
        {
            int                  seed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            uint                 numberOfDocuments = 100;
            QueryOracleUtil      util           = new QueryOracle2(seed);
            IEnumerable <string> inputDocuments = util.GetDocuments(numberOfDocuments);

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                inputDocuments,
                ImplementationAsync);

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                foreach (int maxItemCount in new int[] { 10, 100 })
                {
                    foreach (string query in new string[] { "SELECT c.id FROM c", "SELECT c._ts, c.id FROM c ORDER BY c._ts" })
                    {
                        QueryRequestOptions feedOptions = new QueryRequestOptions
                        {
                            MaxBufferedItemCount = 7000,
                            MaxConcurrency       = 2,
                            MaxItemCount         = maxItemCount,
                            TestSettings         = new TestInjections(simulate429s: true, simulateEmptyPages: false)
                        };

                        List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                            container,
                            query,
                            feedOptions);

                        Assert.AreEqual(
                            documents.Count(),
                            queryResults.Count,
                            $"query: {query} failed with {nameof(maxItemCount)}: {maxItemCount}");
                    }
                }
            }
        }
        public async Task TestQueryCrossParitionPartitionProviderInvalidAsync()
        {
            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                await QueryTestsBase.NoOp();

                try
                {
                    /// note that there is no space before the from clause thus this query should fail
                    /// '"code":"SC2001","message":"Identifier 'c' could not be resolved."'
                    string                  query             = "SELECT c._ts, c.id, c.TicketNumber, c.PosCustomerNumber, c.CustomerId, c.CustomerUserId, c.ContactEmail, c.ContactPhone, c.StoreCode, c.StoreUid, c.PoNumber, c.OrderPlacedOn, c.OrderType, c.OrderStatus, c.Customer.UserFirstName, c.Customer.UserLastName, c.Customer.Name, c.UpdatedBy, c.UpdatedOn, c.ExpirationDate, c.TotalAmountFROM c ORDER BY c._ts";
                    List <Document>         expectedValues    = new List <Document>();
                    FeedIterator <Document> resultSetIterator = container.GetItemQueryIterator <Document>(
                        query,
                        requestOptions: new QueryRequestOptions()
                    {
                        MaxConcurrency = 0
                    });

                    while (resultSetIterator.HasMoreResults)
                    {
                        expectedValues.AddRange(await resultSetIterator.ReadNextAsync());
                    }

                    Assert.Fail("Expected to get an exception for this query.");
                }
                catch (CosmosException e) when(e.StatusCode == HttpStatusCode.BadRequest)
                {
                }
            }

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct | ConnectionModes.Gateway,
                CollectionTypes.MultiPartition,
                QueryTestsBase.NoDocuments,
                ImplementationAsync);
        }
Esempio n. 7
0
        public async Task TestAggregateFunctionsAsync()
        {
            AggregateTestArgs args = new AggregateTestArgs()
            {
                NumberOfDocsWithSamePartitionKey       = 37,
                NumberOfDocumentsDifferentPartitionKey = 43,
                PartitionKey       = "key",
                UniquePartitionKey = "uniquePartitionKey",
                Field  = "field",
                Values = new object[] { false, true, "abc", "cdfg", "opqrs", "ttttttt", "xyz" },
            };

            List <string> documents = new List <string>(args.NumberOfDocumentsDifferentPartitionKey + args.NumberOfDocsWithSamePartitionKey);

            foreach (object val in args.Values)
            {
                Document doc;
                doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, val);
                doc.SetPropertyValue("id", Guid.NewGuid().ToString());

                documents.Add(doc.ToString());
            }

            for (int i = 0; i < args.NumberOfDocsWithSamePartitionKey; ++i)
            {
                Document doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, args.UniquePartitionKey);
                documents.Add(doc.ToString());
            }

            Random random = new Random();

            for (int i = 0; i < args.NumberOfDocumentsDifferentPartitionKey; ++i)
            {
                Document doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, random.NextDouble());
                documents.Add(doc.ToString());
            }

            await this.CreateIngestQueryDeleteAsync <AggregateTestArgs>(
                ConnectionModes.Direct | ConnectionModes.Gateway,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                documents,
                ImplementationAsync,
                args,
                "/" + args.PartitionKey);

            async Task ImplementationAsync(
                Container container,
                IReadOnlyList <CosmosObject> inputDocuments,
                AggregateTestArgs aggregateTestArgs)
            {
                IReadOnlyList <CosmosObject> documentsWherePkIsANumber = inputDocuments
                                                                         .Where(doc =>
                {
                    return(double.TryParse(
                               doc[aggregateTestArgs.PartitionKey].ToString(),
                               out double result));
                })
                                                                         .ToList();
                double numberSum = documentsWherePkIsANumber
                                   .Sum(doc =>
                {
                    if (!doc.TryGetValue(aggregateTestArgs.PartitionKey, out CosmosNumber number))
                    {
                        Assert.Fail("Failed to get partition key from document");
                    }

                    return(Number64.ToDouble(number.Value));
                });
                double count = documentsWherePkIsANumber.Count();

                AggregateQueryArguments[] aggregateQueryArgumentsList = new AggregateQueryArguments[]
                {
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "AVG",
                        ExpectedValue     = CosmosNumber64.Create(numberSum / count),
                        Predicate         = $"IS_NUMBER(r.{aggregateTestArgs.PartitionKey})",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "AVG",
                        ExpectedValue     = null,
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "COUNT",
                        ExpectedValue     = CosmosNumber64.Create(documents.Count()),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "MAX",
                        ExpectedValue     = CosmosString.Create("xyz"),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "MIN",
                        ExpectedValue     = CosmosBoolean.Create(false),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "SUM",
                        ExpectedValue     = CosmosNumber64.Create(numberSum),
                        Predicate         = $"IS_NUMBER(r.{aggregateTestArgs.PartitionKey})",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "SUM",
                        ExpectedValue     = null,
                        Predicate         = $"true",
                    },
                };

                foreach (int maxDoP in new[] { 0, 10 })
                {
                    foreach (AggregateQueryArguments argument in aggregateQueryArgumentsList)
                    {
                        string[] queryFormats = new[]
                        {
                            "SELECT VALUE {0}(r.{1}) FROM r WHERE {2}",
                            "SELECT VALUE {0}(r.{1}) FROM r WHERE {2} ORDER BY r.{1}"
                        };

                        foreach (string queryFormat in queryFormats)
                        {
                            string query = string.Format(
                                CultureInfo.InvariantCulture,
                                queryFormat,
                                argument.AggregateOperator,
                                aggregateTestArgs.PartitionKey,
                                argument.Predicate);
                            string message = string.Format(
                                CultureInfo.InvariantCulture,
                                "query: {0}, data: {1}",
                                query,
                                JsonConvert.SerializeObject(argument));

                            List <CosmosElement> items = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                new QueryRequestOptions()
                            {
                                MaxConcurrency = maxDoP,
                            });

                            if (argument.ExpectedValue == null)
                            {
                                Assert.AreEqual(0, items.Count, message);
                            }
                            else
                            {
                                Assert.AreEqual(1, items.Count, message);
                                CosmosElement expected = argument.ExpectedValue;
                                CosmosElement actual   = items.Single();

                                if ((expected is CosmosNumber expectedNumber) && (actual is CosmosNumber actualNumber))
                                {
                                    Assert.AreEqual(Number64.ToDouble(expectedNumber.Value), Number64.ToDouble(actualNumber.Value), .01);
                                }
Esempio n. 8
0
        public static void ClassSetup(TestContext testContext = null)
        {
            CosmosClient client = TestCommon.CreateCosmosClient(false);

            QueryTestsBase.CleanUp(client).Wait();
        }
Esempio n. 9
0
        public async Task TestQueryCrossPartitionOffsetLimitAsync()
        {
            int  seed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            uint numberOfDocuments = 10;

            Random        rand   = new Random(seed);
            List <Person> people = new List <Person>();

            for (int i = 0; i < numberOfDocuments; i++)
            {
                // Generate random people
                Person person = PersonGenerator.GetRandomPerson(rand);
                for (int j = 0; j < rand.Next(0, 4); j++)
                {
                    // Force an exact duplicate
                    people.Add(person);
                }
            }

            List <string> documentsToInsert = new List <string>();

            // Shuffle them so that they end up in different pages.
            people = people.OrderBy((person) => Guid.NewGuid()).ToList();
            foreach (Person person in people)
            {
                documentsToInsert.Add(JsonConvert.SerializeObject(person));
            }

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                documentsToInsert,
                ImplementationAsync,
                "/id");

            async Task ImplementationAsync(
                Container container,
                IReadOnlyList <CosmosObject> documents)
            {
                foreach (int offsetCount in new int[] { 0, 1, 10, documents.Count })
                {
                    foreach (int limitCount in new int[] { 0, 1, 10, documents.Count })
                    {
                        foreach (int pageSize in new int[] { 1, 10, documents.Count })
                        {
                            string query = $@"
                                SELECT VALUE c.guid
                                FROM c
                                ORDER BY c.guid
                                OFFSET {offsetCount} LIMIT {limitCount}";

                            QueryRequestOptions queryRequestOptions = new QueryRequestOptions()
                            {
                                MaxItemCount         = pageSize,
                                MaxBufferedItemCount = 1000,
                                MaxConcurrency       = 2
                            };

                            IEnumerable <CosmosElement> expectedResults = documents;

                            // ORDER BY
                            expectedResults = expectedResults.OrderBy(x => (x as CosmosObject)["guid"].ToString(), StringComparer.Ordinal);

                            // SELECT VALUE c.name
                            expectedResults = expectedResults.Select(document => (document as CosmosObject)["guid"]);

                            // SKIP TAKE
                            expectedResults = expectedResults.Skip(offsetCount);
                            expectedResults = expectedResults.Take(limitCount);

                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                queryRequestOptions : queryRequestOptions);

                            Assert.IsTrue(
                                expectedResults.SequenceEqual(queryResults),
                                $@"
                                {query} (without continuations) didn't match
                                expected: {JsonConvert.SerializeObject(expectedResults)}
                                actual: {JsonConvert.SerializeObject(queryResults)}");
                        }
                    }
                }
            }
        }
Esempio n. 10
0
            static async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                Assert.AreEqual(0, (await QueryTestsBase.RunQueryAsync(
                                        container,
                                        @"SELECT * FROM Root r WHERE false",
                                        new QueryRequestOptions()
                {
                    MaxConcurrency = 1,
                })).Count);

                object[] keys = new object[] { "A", 5, Undefined.Value };
                for (int i = 0; i < keys.Length; ++i)
                {
                    List <string> expected = documents
                                             .Skip(i * 3)
                                             .Take(3)
                                             .Select(doc => ((CosmosString)doc["id"]).Value.ToString())
                                             .ToList();
                    string expectedResult = string.Join(",", expected);

                    // Order-by
                    List <string> expectedCopy = new List <string>(expected);
                    expectedCopy.Reverse();
                    string expectedOrderByResult = string.Join(",", expectedCopy);

                    List <(string, string)> queries = new List <(string, string)>()
                    {
                        ($@"SELECT * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"")", expectedResult),
                        (@"SELECT * FROM Root r WHERE r.prop BETWEEN 1 AND 3", expectedResult),
                        (@"SELECT VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7", expectedResult),
                        ($@"SELECT TOP 10 * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"")", expectedResult),
                        (@"SELECT TOP 10 * FROM Root r WHERE r.prop BETWEEN 1 AND 3", expectedResult),
                        (@"SELECT TOP 10 VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7", expectedResult),
                        ($@"SELECT * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"") ORDER BY r.prop", expectedOrderByResult),
                        (@"SELECT * FROM Root r WHERE r.prop BETWEEN 1 AND 3 ORDER BY r.prop", expectedOrderByResult),
                        (@"SELECT DISTINCT * FROM Root r WHERE r.prop BETWEEN 1 AND 3 ORDER BY r.prop", expectedOrderByResult),
                        (@"SELECT VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7 ORDER BY r.prop", expectedOrderByResult),
                    };

                    if (i < keys.Length - 1)
                    {
                        string key = keys[i] is string? "'" + keys[i].ToString() + "'" : keys[i].ToString();
                        queries.Add((string.Format(CultureInfo.InvariantCulture, @"SELECT * FROM Root r WHERE r.key = {0} ORDER BY r.prop", key), expectedOrderByResult));
                    }

                    foreach ((string, string)queryAndExpectedResult in queries)
                    {
                        FeedIterator <Document> resultSetIterator = container.GetItemQueryIterator <Document>(
                            queryText: queryAndExpectedResult.Item1,
                            requestOptions: new QueryRequestOptions()
                        {
                            MaxItemCount = 1,
                            PartitionKey = new Cosmos.PartitionKey(keys[i]),
                        });

                        List <Document> result = new List <Document>();
                        while (resultSetIterator.HasMoreResults)
                        {
                            result.AddRange(await resultSetIterator.ReadNextAsync());
                        }

                        string resultDocIds = string.Join(",", result.Select(doc => doc.Id));
                        Assert.AreEqual(
                            queryAndExpectedResult.Item2,
                            resultDocIds,
                            $"Query: {queryAndExpectedResult.Item1} with partition key: {keys[i]} failed.");
                    }
                }
            }
        public async Task TestQueryPlanGatewayAndServiceInteropAsync()
        {
            int                  seed = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
            uint                 numberOfDocuments = 100;
            QueryOracleUtil      util           = new QueryOracle2(seed);
            IEnumerable <string> inputDocuments = util.GetDocuments(numberOfDocuments);

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                inputDocuments,
                ImplementationAsync);

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                ContainerCore containerCore = (ContainerInlineCore)container;

                foreach (bool isGatewayQueryPlan in new bool[] { true, false })
                {
                    MockCosmosQueryClient cosmosQueryClientCore = new MockCosmosQueryClient(
                        containerCore.ClientContext,
                        containerCore,
                        isGatewayQueryPlan);

                    ContainerCore containerWithForcedPlan = new ContainerCore(
                        containerCore.ClientContext,
                        (DatabaseCore)containerCore.Database,
                        containerCore.Id,
                        cosmosQueryClientCore);

                    int numOfQueries = 0;
                    foreach (int maxDegreeOfParallelism in new int[] { 1, 100 })
                    {
                        foreach (int maxItemCount in new int[] { 10, 100 })
                        {
                            numOfQueries++;
                            QueryRequestOptions feedOptions = new QueryRequestOptions
                            {
                                MaxBufferedItemCount = 7000,
                                MaxConcurrency       = maxDegreeOfParallelism,
                                MaxItemCount         = maxItemCount,
                            };

                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                containerWithForcedPlan,
                                "SELECT * FROM c ORDER BY c._ts",
                                feedOptions);

                            Assert.AreEqual(documents.Count(), queryResults.Count);
                        }
                    }

                    if (isGatewayQueryPlan)
                    {
                        Assert.IsTrue(cosmosQueryClientCore.QueryPlanCalls > numOfQueries);
                    }
                    else
                    {
                        Assert.AreEqual(0, cosmosQueryClientCore.QueryPlanCalls, "ServiceInterop mode should not be calling gateway plan retriever");
                    }
                }
            }
        }
        private async Task TestGroupByQueryHelper(
            Container container,
            IReadOnlyList <CosmosObject> documents)
        {
            List <(string, IReadOnlyList <CosmosElement>)> queryAndExpectedResultsList = new List <(string, IReadOnlyList <CosmosElement>)>()
            {
                // ------------------------------------------
                // Simple property reference
                // ------------------------------------------

                (
                    "SELECT c.age FROM c GROUP BY c.age",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "age", grouping.Key }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.team FROM c GROUP BY c.team",
                    documents
                    .GroupBy(document => document["team"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "team", grouping.Key }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.gender FROM c GROUP BY c.gender",
                    documents
                    .GroupBy(document => document["gender"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "gender", grouping.Key }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.id FROM c GROUP BY c.id",
                    documents
                    .GroupBy(document => document["id"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "id", grouping.Key }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.age, c.name FROM c GROUP BY c.age, c.name",
                    documents
                    .GroupBy(document => CosmosObject.Create(
                                 new Dictionary <string, CosmosElement>()
                {
                    { "age", document["age"] },
                    { "name", document["name"] },
                }))
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "age", (grouping.Key as CosmosObject)["age"] },
                    { "name", (grouping.Key as CosmosObject)["name"] }
                }))
                    .ToList()
                ),

                // ------------------------------------------
                // With Aggregates
                // ------------------------------------------

                (
                    "SELECT c.age, COUNT(1) as count FROM c GROUP BY c.age",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "age", grouping.Key },
                    { "count", CosmosNumber64.Create(grouping.Count()) }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name, MIN(c.age) AS min_age FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key },
                    { "min_age", CosmosNumber64.Create(grouping.Min(document => document["age"].ToDouble())) }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name, MAX(c.age) AS max_age FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key },
                    { "max_age", CosmosNumber64.Create(grouping.Max(document => document["age"].ToDouble())) }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name, SUM(c.age) AS sum_age FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key },
                    { "sum_age", CosmosNumber64.Create(grouping.Sum(document => document["age"].ToDouble())) }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name, AVG(c.age) AS avg_age FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key },
                    { "avg_age", CosmosNumber64.Create(grouping.Average(document => document["age"].ToDouble())) }
                }))
                    .ToList()
                ),

                (
                    "SELECT c.name, Count(1) AS count, Min(c.age) AS min_age, Max(c.age) AS max_age FROM c GROUP BY c.name",
                    documents
                    .GroupBy(document => document["name"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "name", grouping.Key },
                    { "count", CosmosNumber64.Create(grouping.Count()) },
                    { "min_age", CosmosNumber64.Create(grouping.Min(document => document["age"].ToDouble())) },
                    { "max_age", CosmosNumber64.Create(grouping.Max(document => document["age"].ToDouble())) },
                }))
                    .ToList()
                ),

                // ------------------------------------------
                // SELECT VALUE
                // ------------------------------------------

                (
                    "SELECT VALUE c.age FROM c GROUP BY c.age",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => grouping.Key)
                    .ToList()
                ),

                // ------------------------------------------
                // Corner Cases
                // ------------------------------------------

                (
                    "SELECT AVG(\"asdf\") as avg_asdf FROM c GROUP BY c.age",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => CosmosObject.Create(new Dictionary <string, CosmosElement>()))
                    .ToList()
                ),

                (
                    @"SELECT 
                        c.age, 
                        AVG(c.doesNotExist) as undefined_avg,
                        MIN(c.doesNotExist) as undefined_min,
                        MAX(c.doesNotExist) as undefined_max,
                        COUNT(c.doesNotExist) as undefined_count,
                        SUM(c.doesNotExist) as undefined_sum
                    FROM c 
                    GROUP BY c.age",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "age", grouping.Key },
                    // sum and count default the counter at 0
                    { "undefined_sum", CosmosNumber64.Create(0) },
                    { "undefined_count", CosmosNumber64.Create(0) },
                }))
                    .ToList()
                ),

                (
                    @"SELECT 
                        c.age, 
                        c.doesNotExist
                    FROM c 
                    GROUP BY c.age, c.doesNotExist",
                    documents
                    .GroupBy(document => document["age"])
                    .Select(grouping => CosmosObject.Create(
                                new Dictionary <string, CosmosElement>()
                {
                    { "age", grouping.Key }
                }))
                    .ToList()
                ),
            };

            // Test query correctness.
            foreach ((string query, IReadOnlyList <CosmosElement> expectedResults) in queryAndExpectedResultsList)
            {
                foreach (int maxItemCount in new int[] { 1, 5, 10 })
                {
                    List <CosmosElement> actualWithoutContinuationTokens = await QueryTestsBase.QueryWithoutContinuationTokensAsync <CosmosElement>(
                        container,
                        query,
                        new QueryRequestOptions()
                    {
                        MaxConcurrency       = 2,
                        MaxItemCount         = maxItemCount,
                        MaxBufferedItemCount = 100,
                    });

                    HashSet <CosmosElement> actualWithoutContinuationTokensSet = new HashSet <CosmosElement>(actualWithoutContinuationTokens);

                    List <CosmosElement> actualWithTryGetContinuationTokens = await QueryTestsBase.QueryWithCosmosElementContinuationTokenAsync <CosmosElement>(
                        container,
                        query,
                        new QueryRequestOptions()
                    {
                        MaxConcurrency       = 2,
                        MaxItemCount         = maxItemCount,
                        MaxBufferedItemCount = 100,
                    });

                    HashSet <CosmosElement> actualWithTryGetContinuationTokensSet = new HashSet <CosmosElement>(actualWithTryGetContinuationTokens);

                    Assert.IsTrue(
                        actualWithoutContinuationTokensSet.SetEquals(actualWithTryGetContinuationTokensSet),
                        $"Results did not match for query: {query} with maxItemCount: {maxItemCount}" +
                        $"ActualWithoutContinuationTokens: {JsonConvert.SerializeObject(actualWithoutContinuationTokensSet)}" +
                        $"ActualWithTryGetContinuationTokens: {JsonConvert.SerializeObject(actualWithTryGetContinuationTokensSet)}");

                    HashSet <CosmosElement> expectedSet = new HashSet <CosmosElement>(expectedResults);

                    Assert.IsTrue(
                        actualWithoutContinuationTokensSet.SetEquals(expectedSet),
                        $"Results did not match for query: {query} with maxItemCount: {maxItemCount}" +
                        $"Actual {JsonConvert.SerializeObject(actualWithoutContinuationTokensSet)}" +
                        $"Expected: {JsonConvert.SerializeObject(expectedSet)}");
                }
            }

            // Test that continuation token is blocked
            {
                try
                {
                    List <JToken> actual = await QueryTestsBase.QueryWithContinuationTokensAsync <JToken>(
                        container,
                        "SELECT c.age FROM c GROUP BY c.age",
                        new QueryRequestOptions()
                    {
                        MaxConcurrency = 2,
                        MaxItemCount   = 1
                    });

                    Assert.Fail("Expected an error when trying to drain a GROUP BY query with continuation tokens.");
                }
                catch (Exception)
                {
                }
            }
        }
Esempio n. 13
0
        public async Task TestPassthroughQueryAsync()
        {
            string[] inputDocs = new[]
            {
                @"{""id"":""documentId1"",""key"":""A"",""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId2"",""key"":""A"",""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId3"",""key"":""A"",""prop"":1,""shortArray"":[{""a"":7}]}",
                @"{""id"":""documentId4"",""key"":5,""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId5"",""key"":5,""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId6"",""key"":5,""prop"":1,""shortArray"":[{""a"":7}]}",
                @"{""id"":""documentId10"",""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId11"",""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId12"",""prop"":1,""shortArray"":[{""a"":7}]}",
            };

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                inputDocs,
                ImplementationAsync,
                "/key");

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                foreach (int maxDegreeOfParallelism in new int[] { 1, 100 })
                {
                    foreach (int maxItemCount in new int[] { 10, 100 })
                    {
                        QueryRequestOptions feedOptions = new QueryRequestOptions
                        {
                            MaxBufferedItemCount = 7000,
                            MaxConcurrency       = maxDegreeOfParallelism,
                            MaxItemCount         = maxItemCount,
                        };

                        foreach (string query in new string[]
                        {
                            "SELECT * FROM c WHERE c.key = 5",
                            "SELECT * FROM c WHERE c.key = 5 ORDER BY c._ts",
                        })
                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                feedOptions);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Passthrough, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                3,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }

                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());

                            string query = "SELECT TOP 2 c.id FROM c WHERE c.key = 5";
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                feedOptions);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Passthrough, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                2,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }

                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());

                            string query = "SELECT c.id FROM c WHERE c.key = 5 OFFSET 1 LIMIT 1";
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                feedOptions);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Passthrough, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                1,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }

                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());

                            string query = "SELECT VALUE COUNT(1) FROM c WHERE c.key = 5";
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                feedOptions);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Specialized, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                1,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");

                            Assert.AreEqual(
                                3,
                                Number64.ToLong((queryResults.First() as CosmosNumber64).GetValue()),
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }

                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());

                            string query = "SELECT VALUE c.key FROM c WHERE c.key = 5 GROUP BY c.key";
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryCombinationsAsync(
                                container,
                                query,
                                feedOptions,
                                QueryDrainingMode.HoldState | QueryDrainingMode.CosmosElementContinuationToken);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Specialized, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                1,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }

                        {
                            feedOptions.TestSettings = new TestInjections(simulate429s: false, simulateEmptyPages: false, responseStats: new TestInjections.ResponseStats());

                            string query = "SELECT DISTINCT VALUE c.key FROM c WHERE c.key = 5";
                            List <CosmosElement> queryResults = await QueryTestsBase.RunQueryCombinationsAsync(
                                container,
                                query,
                                feedOptions,
                                QueryDrainingMode.HoldState | QueryDrainingMode.CosmosElementContinuationToken);

                            Assert.IsTrue(feedOptions.TestSettings.Stats.PipelineType.HasValue);
                            Assert.AreEqual(TestInjections.PipelineType.Specialized, feedOptions.TestSettings.Stats.PipelineType.Value);

                            Assert.AreEqual(
                                1,
                                queryResults.Count,
                                $"query: {query} failed with {nameof(maxDegreeOfParallelism)}: {maxDegreeOfParallelism}, {nameof(maxItemCount)}: {maxItemCount}");
                        }
                    }
                }
            }
        }
Esempio n. 14
0
        public async Task TestQueryWithPartitionKeyAsync()
        {
            string[] inputDocs = new[]
            {
                @"{""id"":""documentId1"",""key"":""A"",""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId2"",""key"":""A"",""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId3"",""key"":""A"",""prop"":1,""shortArray"":[{""a"":7}]}",
                @"{""id"":""documentId4"",""key"":5,""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId5"",""key"":5,""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId6"",""key"":5,""prop"":1,""shortArray"":[{""a"":7}]}",
                @"{""id"":""documentId10"",""prop"":3,""shortArray"":[{""a"":5}]}",
                @"{""id"":""documentId11"",""prop"":2,""shortArray"":[{""a"":6}]}",
                @"{""id"":""documentId12"",""prop"":1,""shortArray"":[{""a"":7}]}",
            };

            await this.CreateIngestQueryDeleteAsync(
                ConnectionModes.Direct | ConnectionModes.Gateway,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                inputDocs,
                ImplementationAsync,
                "/key");

            async Task ImplementationAsync(Container container, IReadOnlyList <CosmosObject> documents)
            {
                Assert.AreEqual(0, (await QueryTestsBase.RunQueryAsync(
                                        container,
                                        @"SELECT * FROM Root r WHERE false",
                                        new QueryRequestOptions()
                {
                    MaxConcurrency = 1,
                })).Count);

                object[] keys = new object[] { "A", 5, Undefined.Value };
                for (int i = 0; i < keys.Length; ++i)
                {
                    List <string> expected = documents
                                             .Skip(i * 3)
                                             .Take(3)
                                             .Select(doc => ((CosmosString)doc["id"]).Value)
                                             .ToList();
                    string expectedResult = string.Join(",", expected);

                    // Order-by
                    List <string> expectedCopy = new List <string>(expected);
                    expectedCopy.Reverse();
                    string expectedOrderByResult = string.Join(",", expectedCopy);

                    List <(string, string)> queries = new List <(string, string)>()
                    {
                        ($@"SELECT * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"")", expectedResult),
                        (@"SELECT * FROM Root r WHERE r.prop BETWEEN 1 AND 3", expectedResult),
                        (@"SELECT VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7", expectedResult),
                        ($@"SELECT TOP 10 * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"")", expectedResult),
                        (@"SELECT TOP 10 * FROM Root r WHERE r.prop BETWEEN 1 AND 3", expectedResult),
                        (@"SELECT TOP 10 VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7", expectedResult),
                        ($@"SELECT * FROM Root r WHERE r.id IN (""{expected[0]}"", ""{expected[1]}"", ""{expected[2]}"") ORDER BY r.prop", expectedOrderByResult),
                        (@"SELECT * FROM Root r WHERE r.prop BETWEEN 1 AND 3 ORDER BY r.prop", expectedOrderByResult),
                        (@"SELECT VALUE r FROM Root r JOIN c IN r.shortArray WHERE c.a BETWEEN 5 and 7 ORDER BY r.prop", expectedOrderByResult),
                    };

                    if (i < keys.Length - 1)
                    {
                        string key;
                        if (keys[i] is string)
                        {
                            key = "'" + keys[i].ToString() + "'";
                        }
                        else
                        {
                            key = keys[i].ToString();
                        }

                        queries.Add((string.Format(CultureInfo.InvariantCulture, @"SELECT * FROM Root r WHERE r.key = {0} ORDER BY r.prop", key), expectedOrderByResult));
                    }

                    foreach ((string, string)queryAndExpectedResult in queries)
                    {
                        FeedIterator <Document> resultSetIterator = container.GetItemQueryIterator <Document>(
                            queryText: queryAndExpectedResult.Item1,
                            requestOptions: new QueryRequestOptions()
                        {
                            MaxItemCount = 1,
                            PartitionKey = new Cosmos.PartitionKey(keys[i]),
                        });

                        List <Document> result = new List <Document>();
                        while (resultSetIterator.HasMoreResults)
                        {
                            result.AddRange(await resultSetIterator.ReadNextAsync());
                        }

                        string resultDocIds = string.Join(",", result.Select(doc => doc.Id));
                        Assert.AreEqual(queryAndExpectedResult.Item2, resultDocIds);
                    }
                }
            }
        }