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); }
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); }
public static void ClassSetup(TestContext testContext = null) { CosmosClient client = TestCommon.CreateCosmosClient(false); QueryTestsBase.CleanUp(client).Wait(); }
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)}"); } } } } }
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) { } } }
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}"); } } } } }
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); } } } }