Exemplo n.º 1
0
        public async Task UndefinedSinglePageAsync()
        {
            IReadOnlyList <IReadOnlyList <CosmosElement> > pages = new List <List <CosmosElement> >()
            {
                new List <CosmosElement>()
                {
                    CosmosElement.Parse("{\"payload\": {\"$1\": {}}}")
                }
            };

            List <CosmosElement> elements = await AggregateQueryPipelineStageTests.CreateAndDrain(
                pages : pages,
                executionEnvironment : ExecutionEnvironment.Compute,
                aggregates : new List <AggregateOperator>()
            {
                AggregateOperator.Sum
            },
                aliasToAggregateType : new Dictionary <string, AggregateOperator?>()
            {
                { "$1", AggregateOperator.Sum }
            },
                orderedAliases : new List <string>()
            {
                "$1"
            },
                hasSelectValue : false,
                continuationToken : null);

            Assert.AreEqual(1, elements.Count);
            Assert.AreEqual(0, (elements[0] as CosmosObject).Keys.Count());
        }
            public override async ValueTask <bool> MoveNextAsync(ITrace trace)
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                if (trace == null)
                {
                    throw new ArgumentNullException(nameof(trace));
                }

                if (!await this.inputStage.MoveNextAsync(trace))
                {
                    this.Current = default;
                    return(false);
                }

                TryCatch <QueryPage> tryGetSourcePage = this.inputStage.Current;

                if (tryGetSourcePage.Failed)
                {
                    this.Current = tryGetSourcePage;
                    return(true);
                }

                QueryPage sourcePage = tryGetSourcePage.Result;

                // Skip the documents but keep all the other headers
                IReadOnlyList <CosmosElement> documentsAfterSkip = sourcePage.Documents.Skip(this.skipCount).ToList();

                int numberOfDocumentsSkipped = sourcePage.Documents.Count - documentsAfterSkip.Count;

                this.skipCount -= numberOfDocumentsSkipped;

                QueryState state;

                if ((sourcePage.State != null) && (sourcePage.DisallowContinuationTokenMessage == null))
                {
                    string token = new OffsetContinuationToken(
                        offset: this.skipCount,
                        sourceToken: sourcePage.State?.Value.ToString()).ToString();
                    state = new QueryState(CosmosElement.Parse(token));
                }
                else
                {
                    state = null;
                }

                QueryPage queryPage = new QueryPage(
                    documents: documentsAfterSkip,
                    requestCharge: sourcePage.RequestCharge,
                    activityId: sourcePage.ActivityId,
                    responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                    cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                    disallowContinuationTokenMessage: sourcePage.DisallowContinuationTokenMessage,
                    additionalHeaders: sourcePage.AdditionalHeaders,
                    state: state);

                this.Current = TryCatch <QueryPage> .FromResult(queryPage);

                return(true);
            }
        public async Task SinglePageAsync()
        {
            IReadOnlyList <IReadOnlyList <CosmosElement> > pages = new List <List <CosmosElement> >()
            {
                new List <CosmosElement>()
                {
                    CosmosElement.Parse("{\"groupByItems\": [{\"item\" : \"John\"}], \"payload\" : {\"name\": \"John\", \"count\": {\"item\": 42}}}")
                }
            };

            List <CosmosElement> elements = await GroupByQueryPipelineStageTests.CreateAndDrainAsync(
                pages : pages,
                executionEnvironment : ExecutionEnvironment.Compute,
                continuationToken : null,
                groupByAliasToAggregateType : new Dictionary <string, AggregateOperator?>()
            {
                { "name", null }, { "count", AggregateOperator.Sum }
            },
                orderedAliases : new List <string>()
            {
                "name", "count"
            },
                hasSelectValue : false);

            Assert.AreEqual(1, elements.Count);
            Assert.AreEqual(42, Number64.ToLong(((elements[0] as CosmosObject)["count"] as CosmosNumber).Value));
            Assert.AreEqual("John", ((elements[0] as CosmosObject)["name"] as CosmosString).Value.ToString());
        }
Exemplo n.º 4
0
        public void SanityTest()
        {
            List <CosmosElement> allElements = GenerateInputsFromClass(typeof(Elements))
                                               .Concat(GenerateInputsFromClass(typeof(ExtendedTypes)))
                                               .Concat(GenerateInputsFromClass(typeof(Numbers)))
                                               .ToList();

            foreach (CosmosElement first in allElements)
            {
                foreach (CosmosElement second in allElements)
                {
                    if (object.ReferenceEquals(first, second))
                    {
                        // They should be equals semantically too
                        Assert.AreEqual(first, second);

                        // Try with a deep copy to make sure it's not just asserting reference eqaulity.
                        Assert.AreEqual(first, CosmosElement.Parse(second.ToString()));

                        // If two objects are equal, then so are their hashes (consistent hashing).
                        Assert.AreEqual(first.GetHashCode(), second.GetHashCode());
                    }
                    else
                    {
                        Assert.AreNotEqual(first, second);
                    }
                }
            }
        }
Exemplo n.º 5
0
        public async Task MultiplePagesAsync()
        {
            long[] values = new long[] { 42, 1337 };
            IReadOnlyList <IReadOnlyList <CosmosElement> > pages = values
                                                                   .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"payload\": {{\"$1\": {{\"item\": {value}}}}}}}")
            })
                                                                   .ToList();

            List <CosmosElement> elements = await AggregateQueryPipelineStageTests.CreateAndDrain(
                pages : pages,
                executionEnvironment : ExecutionEnvironment.Compute,
                aggregates : new List <AggregateOperator>()
            {
                AggregateOperator.Sum
            },
                aliasToAggregateType : new Dictionary <string, AggregateOperator?>()
            {
                { "$1", AggregateOperator.Sum }
            },
                orderedAliases : new List <string>()
            {
                "$1"
            },
                hasSelectValue : false,
                continuationToken : null);

            Assert.AreEqual(1, elements.Count);
            Assert.AreEqual(values.Sum(), Number64.ToLong(((elements[0] as CosmosObject)["$1"] as CosmosNumber).Value));
        }
Exemplo n.º 6
0
            public override async ValueTask <bool> MoveNextAsync()
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                if (!await this.inputStage.MoveNextAsync())
                {
                    this.Current = default;
                    return(false);
                }

                TryCatch <QueryPage> tryGetSourcePage = this.inputStage.Current;

                if (tryGetSourcePage.Failed)
                {
                    this.Current = tryGetSourcePage;
                    return(true);
                }

                QueryPage sourcePage = tryGetSourcePage.Result;

                List <CosmosElement> takedDocuments = sourcePage.Documents.Take(this.takeCount).ToList();

                this.takeCount -= takedDocuments.Count;

                QueryState state;

                if ((sourcePage.State != null) && (sourcePage.DisallowContinuationTokenMessage == null))
                {
                    string updatedContinuationToken = this.takeEnum switch
                    {
                        TakeEnum.Limit => new LimitContinuationToken(
                            limit: this.takeCount,
                            sourceToken: sourcePage.State?.Value.ToString()).ToString(),
                        TakeEnum.Top => new TopContinuationToken(
                            top: this.takeCount,
                            sourceToken: sourcePage.State?.Value.ToString()).ToString(),
                        _ => throw new ArgumentOutOfRangeException($"Unknown {nameof(TakeEnum)}: {this.takeEnum}."),
                    };

                    state = new QueryState(CosmosElement.Parse(updatedContinuationToken));
                }
                else
                {
                    state = null;
                }

                QueryPage queryPage = new QueryPage(
                    documents: takedDocuments,
                    requestCharge: sourcePage.RequestCharge,
                    activityId: sourcePage.ActivityId,
                    responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                    cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                    disallowContinuationTokenMessage: sourcePage.DisallowContinuationTokenMessage,
                    state: state);

                this.Current = TryCatch <QueryPage> .FromResult(queryPage);

                return(true);
            }
        internal static async Task <List <T> > QueryWithCosmosElementContinuationTokenAsync <T>(
            Container container,
            string query,
            QueryRequestOptions queryRequestOptions = null)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            List <T>      resultsFromCosmosElementContinuationToken = new List <T>();
            CosmosElement continuationToken = null;

            do
            {
                QueryRequestOptions computeRequestOptions = queryRequestOptions.Clone();
                computeRequestOptions.ExecutionEnvironment           = Cosmos.Query.Core.ExecutionContext.ExecutionEnvironment.Compute;
                computeRequestOptions.CosmosElementContinuationToken = continuationToken;

                FeedIteratorInternal <T> itemQuery = (FeedIteratorInternal <T>)container.GetItemQueryIterator <T>(
                    queryText: query,
                    requestOptions: computeRequestOptions);
                try
                {
                    FeedResponse <T> cosmosQueryResponse = await itemQuery.ReadNextAsync();

                    if (queryRequestOptions.MaxItemCount.HasValue)
                    {
                        Assert.IsTrue(
                            cosmosQueryResponse.Count <= queryRequestOptions.MaxItemCount.Value,
                            "Max Item Count is not being honored");
                    }

                    resultsFromCosmosElementContinuationToken.AddRange(cosmosQueryResponse);

                    // Force a rewrite of the continuation token, so that we test the case where we roundtrip it over the wire.
                    // There was a bug where resuming from double.NaN lead to an exception,
                    // since we parsed the type assuming it was always a double and not a string.
                    CosmosElement originalContinuationToken = itemQuery.GetCosmosElementContinuationToken();
                    if (originalContinuationToken != null)
                    {
                        continuationToken = CosmosElement.Parse(originalContinuationToken.ToString());
                    }
                    else
                    {
                        continuationToken = null;
                    }
                }
                catch (CosmosException cosmosException) when(cosmosException.StatusCode == (HttpStatusCode)429)
                {
                    itemQuery = (FeedIteratorInternal <T>)container.GetItemQueryIterator <T>(
                        queryText: query,
                        requestOptions: queryRequestOptions);
                }
            } while (continuationToken != null);

            return(resultsFromCosmosElementContinuationToken);
        }
Exemplo n.º 8
0
        static IReadOnlyList <(PageList, int, DistinctQueryType[])> TestCases()
        {
            List <(PageList, int, DistinctQueryType[])> result = new List <(PageList, int, DistinctQueryType[])>();

            long[]   values = new long[] { 42, 1337, 1337, 42 };
            PageList pages  = values
                              .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"item\": {value}}}")
            })
                              .ToList();

            result.Add((pages, values.Distinct().Count(), new[] { DistinctQueryType.Unordered }));

            values = new long[] { 0, 1, 1, 2, 3, 5, 8, 13 };
            pages  = values
                     .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"item\": {value}}}")
            })
                     .ToList();
            result.Add((pages, values.Distinct().Count(), new[] { DistinctQueryType.Unordered, DistinctQueryType.Ordered }));

            int expectedCount = 50;

            pages = Enumerable
                    .Range(0, 10)
                    .Select(_ => Enumerable
                            .Range(0, expectedCount)
                            .Select(j => CosmosElement.Parse($"{{ \"val\": {j} }}"))
                            .ToList())
                    .ToList();
            result.Add((pages, expectedCount, new[] { DistinctQueryType.Unordered }));

            pages = Enumerable
                    .Range(0, expectedCount)
                    .Select(i => Enumerable
                            .Repeat(i, 50)
                            .Select(j => CosmosElement.Parse($"{{ \"val\": {j} }}"))
                            .ToList())
                    .ToList();
            result.Add((pages, expectedCount, new[] { DistinctQueryType.Unordered, DistinctQueryType.Ordered }));

            return(result);
        }
Exemplo n.º 9
0
        public async Task SanityTests()
        {
            long[] values = new long[] { 42, 1337, 1337, 42 };
            IReadOnlyList <IReadOnlyList <CosmosElement> > pages = values
                                                                   .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"item\": {value}}}")
            })
                                                                   .ToList();

            List <CosmosElement> elements = await DistinctQueryPipelineStageTests.CreateAndDrainAsync(
                pages : pages,
                executionEnvironment : ExecutionEnvironment.Compute,
                continuationToken : null,
                distinctQueryType : DistinctQueryType.Unordered);

            Assert.AreEqual(values.Distinct().Count(), elements.Count);
        }
Exemplo n.º 10
0
        public async Task TestNegativeDistinctComponentCreation()
        {
            TryCatch <IDocumentQueryExecutionComponent> tryCreateWhenSourceFails = await DistinctDocumentQueryExecutionComponent.TryCreateAsync(
                ExecutionEnvironment.Client,
                null,
                FailToCreateSource,
                DistinctQueryType.Ordered);

            Assert.IsFalse(tryCreateWhenSourceFails.Succeeded);

            TryCatch <IDocumentQueryExecutionComponent> tryCreateWhenInvalidContinuationToken = await DistinctDocumentQueryExecutionComponent.TryCreateAsync(
                ExecutionEnvironment.Client,
                CosmosElement.Parse("\"This is not a valid continuation token\""),
                CreateSource,
                DistinctQueryType.Unordered);

            Assert.IsFalse(tryCreateWhenInvalidContinuationToken.Succeeded);
        }
        /// <summary>
        /// Gets the next page of results from this context.
        /// </summary>
        /// <param name="token">The cancellation token.</param>
        /// <returns>A task to await on that in turn returns a DoucmentFeedResponse of results.</returns>
        public override async Task <QueryResponseCore> ExecuteNextAsync(CancellationToken token)
        {
            try
            {
                QueryResponseCore queryResponse = await this.component.DrainAsync(this.actualPageSize, token);

                if (!queryResponse.IsSuccess)
                {
                    this.component.Stop();
                    return(queryResponse);
                }

                string updatedContinuationToken;
                if (queryResponse.DisallowContinuationTokenMessage == null)
                {
                    if (queryResponse.ContinuationToken != null)
                    {
                        updatedContinuationToken = new PipelineContinuationTokenV0(CosmosElement.Parse(queryResponse.ContinuationToken)).ToString();
                    }
                    else
                    {
                        updatedContinuationToken = null;
                    }
                }
                else
                {
                    updatedContinuationToken = null;
                }

                return(QueryResponseCore.CreateSuccess(
                           result: queryResponse.CosmosElements,
                           continuationToken: updatedContinuationToken,
                           disallowContinuationTokenMessage: queryResponse.DisallowContinuationTokenMessage,
                           activityId: queryResponse.ActivityId,
                           requestCharge: queryResponse.RequestCharge,
                           diagnostics: queryResponse.Diagnostics,
                           responseLengthBytes: queryResponse.ResponseLengthBytes));
            }
            catch (Exception)
            {
                this.component.Stop();
                throw;
            }
        }
Exemplo n.º 12
0
            public static Payload Create(string name, string jsonText)
            {
                if (jsonText == null)
                {
                    throw new ArgumentNullException(nameof(jsonText));
                }

                CosmosElement element          = CosmosElement.Parse(jsonText);
                IJsonWriter   jsonBinaryWriter = JsonWriter.Create(JsonSerializationFormat.Binary);
                IJsonWriter   jsonTextWriter   = JsonWriter.Create(JsonSerializationFormat.Text);

                element.WriteTo(jsonTextWriter);
                element.WriteTo(jsonBinaryWriter);

                ReadOnlyMemory <byte> text   = jsonTextWriter.GetResult();
                ReadOnlyMemory <byte> binary = jsonBinaryWriter.GetResult();

                return(new Payload(name, text, binary));
            }
Exemplo n.º 13
0
        public async Task SanityTests()
        {
            long[]   values = new long[] { 42, 1337 };
            PageList pages  = values
                              .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"item\": {value}}}")
            })
                              .ToList();

            foreach (int takeCount in new int[] { 0, 1, values.Length, 2 * values.Length })
            {
                (List <CosmosElement> elements, _) = await TakeQueryPipelineStageTests.CreateAndDrainAsync(
                    pages : pages,
                    executionEnvironment : ExecutionEnvironment.Compute,
                    takeCount : takeCount,
                    continuationToken : null);

                Assert.AreEqual(Math.Min(takeCount, values.Length), elements.Count);
            }
        }
Exemplo n.º 14
0
        public async Task SanityTests()
        {
            long[] values = new long[] { 42, 1337 };
            IReadOnlyList <IReadOnlyList <CosmosElement> > pages = values
                                                                   .Select(value => new List <CosmosElement>()
            {
                CosmosElement.Parse($"{{\"item\": {value}}}")
            })
                                                                   .ToList();

            foreach (int offsetCount in new int[] { 0, 1, values.Length, 2 * values.Length })
            {
                List <CosmosElement> elements = await SkipQueryPipelineStageTests.CreateAndDrainAsync(
                    pages : pages,
                    executionEnvironment : ExecutionEnvironment.Compute,
                    offsetCount : offsetCount,
                    continuationToken : null);

                Assert.AreEqual(Math.Max(values.Length - offsetCount, 0), elements.Count);
            }
        }
Exemplo n.º 15
0
        public DeserializerBenchmark()
        {
            List <Person> people = new List <Person>();

            for (int i = 0; i < 1000; i++)
            {
                people.Add(Person.GetRandomPerson());
            }

            this.json = JsonConvert.SerializeObject(people);

            IJsonWriter jsonTextWriter = Microsoft.Azure.Cosmos.Json.JsonWriter.Create(JsonSerializationFormat.Text);

            CosmosElement.Parse(this.json).WriteTo(jsonTextWriter);
            this.textBuffer = jsonTextWriter.GetResult();

            IJsonWriter jsonBinaryWriter = Microsoft.Azure.Cosmos.Json.JsonWriter.Create(JsonSerializationFormat.Binary);

            CosmosElement.Parse(this.json).WriteTo(jsonBinaryWriter);
            this.binaryBuffer = jsonBinaryWriter.GetResult();
        }
Exemplo n.º 16
0
        static IReadOnlyList <(PageList, int, long)> TestCases()
        {
            // List<(pages, takeCount, pageIndex)>
            List <(PageList, int, long)> result = new List <(PageList, int, long)>();

            long[]   values = new long[] { 0, 1, 13, 42, 1337, 1337, 42, 1, 2, 3 };
            PageList pages  = Enumerable
                              .Range(0, 10)
                              .Select(_ =>
                                      values
                                      .Select(value => CosmosElement.Parse($"{{\"item\": {value}}}"))
                                      .ToList())
                              .ToList();

            foreach (int takeCount in new[] { 1, 3, 6, 10, 15, 20, 23, 32, 41, 56, 81, 97, 100 })
            {
                long pageIndex = takeCount < values.Length ? 1 : Convert.ToInt64(Math.Ceiling((decimal)takeCount / values.Length));
                result.Add((pages, takeCount, pageIndex));
            }

            return(result);
        }
        public void ArrayIteratorCollectionExpressionTest()
        {
            // FROM p in f.parents
            SqlArrayIteratorCollectionExpression fromPInFDotParents = SqlArrayIteratorCollectionExpression.Create(
                SqlIdentifier.Create("p"),
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("f"),
                    SqlStringPathExpression.Create(
                        null,
                        SqlStringLiteral.Create("parents"))));

            CosmosElement andersenParent1  = CosmosElement.Parse(@"{ ""p"" : { ""firstName"": ""Thomas"" }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAA==""}");
            CosmosElement andersenParent2  = CosmosElement.Parse(@"{ ""p"" : { ""firstName"": ""Mary Kay""}, ""_rid"": ""0fomAIxnukU1AQAAAAAAAA=="" }");
            CosmosElement wakeFieldParent1 = CosmosElement.Parse(@"{ ""p"" : { ""familyName"": ""Wakefield"", ""givenName"": ""Robin"" }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAB=="" }");
            CosmosElement wakeFieldParent2 = CosmosElement.Parse(@"{ ""p"" : { ""familyName"": ""Miller"", ""givenName"": ""Ben"" }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAB=="" }");

            AssertEvaluation(new CosmosElement[]
            {
                andersenParent1,
                andersenParent2,
                wakeFieldParent1,
                wakeFieldParent2,
            }, fromPInFDotParents, DataSource);
        }
Exemplo n.º 18
0
        public async Task TestCosmosCrossPartitionQueryExecutionContextWithEmptyPagesAndSplitAsync(bool createInitialContinuationToken)
        {
            int maxPageSize = 5;

            List <MockPartitionResponse[]> mockResponsesScenario = MockQueryFactory.GetSplitScenarios();

            foreach (MockPartitionResponse[] mockResponse in mockResponsesScenario)
            {
                string initialContinuationToken = null;
                string fullContinuationToken    = null;
                if (createInitialContinuationToken)
                {
                    initialContinuationToken = " - RID:02FYAIvUH1kCAAAAAAAAAA ==#RT:1#TRC:1";
                    CompositeContinuationToken compositeContinuation = new CompositeContinuationToken()
                    {
                        Range = new Documents.Routing.Range <string>(
                            min: MockQueryFactory.DefaultPartitionKeyRange.MinInclusive,
                            max: MockQueryFactory.DefaultPartitionKeyRange.MaxExclusive,
                            isMaxInclusive: false,
                            isMinInclusive: true),
                        Token = initialContinuationToken
                    };

                    fullContinuationToken = CosmosArray.Create(
                        new List <CosmosElement>()
                    {
                        CompositeContinuationToken.ToCosmosElement(compositeContinuation)
                    }).ToString();
                }

                Mock <CosmosQueryClient> mockQueryClient = new Mock <CosmosQueryClient>();
                IList <ToDoItem>         allItems        = MockQueryFactory.GenerateAndMockResponse(
                    mockQueryClient,
                    isOrderByQuery: false,
                    sqlQuerySpec: MockQueryFactory.DefaultQuerySpec,
                    containerRid: MockQueryFactory.DefaultCollectionRid,
                    initContinuationToken: initialContinuationToken,
                    maxPageSize: maxPageSize,
                    mockResponseForSinglePartition: mockResponse,
                    cancellationTokenForMocks: this.cancellationToken);

                CosmosQueryContext context = MockQueryFactory.CreateContext(
                    mockQueryClient.Object);

                CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: MockQueryFactory.DefaultQuerySpec,
                    collectionRid: MockQueryFactory.DefaultCollectionRid,
                    partitionedQueryExecutionInfo: new PartitionedQueryExecutionInfo()
                {
                    QueryInfo = new QueryInfo()
                },
                    partitionKeyRanges: new List <PartitionKeyRange> {
                    MockQueryFactory.DefaultPartitionKeyRange
                },
                    initialPageSize: maxPageSize,
                    maxConcurrency: null,
                    maxItemCount: maxPageSize,
                    maxBufferedItemCount: null,
                    returnResultsInDeterministicOrder: true,
                    testSettings: new TestInjections(simulate429s: false, simulateEmptyPages: false));

                IDocumentQueryExecutionComponent executionContext = (await CosmosParallelItemQueryExecutionContext.TryCreateAsync(
                                                                         context,
                                                                         initParams,
                                                                         fullContinuationToken != null ? CosmosElement.Parse(fullContinuationToken) : null,
                                                                         this.cancellationToken)).Result;

                // Read all the pages from both splits
                List <ToDoItem> itemsRead = new List <ToDoItem>();
                Assert.IsTrue(!executionContext.IsDone);

                while (!executionContext.IsDone)
                {
                    QueryResponseCore queryResponse = await executionContext.DrainAsync(maxPageSize, this.cancellationToken);

                    string responseContinuationToken = queryResponse.ContinuationToken;
                    foreach (CosmosElement element in queryResponse.CosmosElements)
                    {
                        string   jsonValue = element.ToString();
                        ToDoItem item      = JsonConvert.DeserializeObject <ToDoItem>(jsonValue);
                        itemsRead.Add(item);
                    }
                }

                Assert.AreEqual(allItems.Count, itemsRead.Count);
                List <ToDoItem> exepected = allItems.OrderBy(x => x.id).ToList();
                List <ToDoItem> actual    = itemsRead.OrderBy(x => x.id).ToList();

                CollectionAssert.AreEqual(exepected, actual, new ToDoItemComparer());
            }
        }
Exemplo n.º 19
0
        public async Task TestCosmosOrderByQueryExecutionContextWithFailurePageAsync(bool createInitialContinuationToken)
        {
            int maxPageSize = 5;

            List <MockPartitionResponse[]> mockResponsesScenario = MockQueryFactory.GetFailureScenarios();

            Mock <CosmosQueryClient> mockQueryClient = new Mock <CosmosQueryClient>();

            foreach (MockPartitionResponse[] mockResponse in mockResponsesScenario)
            {
                string initialContinuationToken = null;
                string fullContinuationToken    = null;
                if (createInitialContinuationToken)
                {
                    ToDoItem itemToRepresentPreviousQuery = ToDoItem.CreateItems(
                        1,
                        "itemToRepresentPreviousQuery",
                        MockQueryFactory.DefaultCollectionRid).First();

                    initialContinuationToken = $" - RID:{itemToRepresentPreviousQuery._rid} ==#RT:1#TRC:1";
                    CompositeContinuationToken compositeContinuation = new CompositeContinuationToken()
                    {
                        Range = new Documents.Routing.Range <string>(
                            min: MockQueryFactory.DefaultPartitionKeyRange.MinInclusive,
                            max: MockQueryFactory.DefaultPartitionKeyRange.MaxExclusive,
                            isMaxInclusive: false,
                            isMinInclusive: true),
                        Token = initialContinuationToken
                    };

                    List <OrderByItem> orderByItems = new List <OrderByItem>()
                    {
                        new OrderByItem(CosmosObject.CreateFromBuffer(Encoding.UTF8.GetBytes("{\"item\":\"2c4ce711-13c3-4c93-817c-49287b71b6c3\"}")))
                    };

                    OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken(
                        compositeContinuationToken: compositeContinuation,
                        orderByItems: orderByItems,
                        rid: itemToRepresentPreviousQuery._rid,
                        skipCount: 0,
                        filter: null);

                    fullContinuationToken = CosmosArray.Create(
                        new List <CosmosElement>()
                    {
                        OrderByContinuationToken.ToCosmosElement(orderByContinuationToken)
                    }).ToString();
                }

                IList <ToDoItem> allItems = MockQueryFactory.GenerateAndMockResponse(
                    mockQueryClient,
                    isOrderByQuery: true,
                    sqlQuerySpec: MockQueryFactory.DefaultQuerySpec,
                    containerRid: MockQueryFactory.DefaultCollectionRid,
                    initContinuationToken: initialContinuationToken,
                    maxPageSize: maxPageSize,
                    mockResponseForSinglePartition: mockResponse,
                    cancellationTokenForMocks: this.cancellationToken);

                // Order by drains the partitions until it finds an item
                // If there are no items then it's not possible to have a continuation token
                if (allItems.Count == 0 && createInitialContinuationToken)
                {
                    continue;
                }

                CosmosQueryContext context = MockQueryFactory.CreateContext(
                    mockQueryClient.Object);

                QueryInfo queryInfo = new QueryInfo()
                {
                    OrderBy            = new SortOrder[] { SortOrder.Ascending },
                    OrderByExpressions = new string[] { "id" }
                };

                CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams(
                    sqlQuerySpec: MockQueryFactory.DefaultQuerySpec,
                    collectionRid: MockQueryFactory.DefaultCollectionRid,
                    partitionedQueryExecutionInfo: new PartitionedQueryExecutionInfo()
                {
                    QueryInfo = queryInfo
                },
                    partitionKeyRanges: new List <PartitionKeyRange>()
                {
                    MockQueryFactory.DefaultPartitionKeyRange
                },
                    initialPageSize: maxPageSize,
                    maxConcurrency: null,
                    maxItemCount: maxPageSize,
                    maxBufferedItemCount: null,
                    returnResultsInDeterministicOrder: true,
                    testSettings: new TestInjections(simulate429s: false, simulateEmptyPages: false));

                TryCatch <IDocumentQueryExecutionComponent> tryCreate = await CosmosOrderByItemQueryExecutionContext.TryCreateAsync(
                    context,
                    initParams,
                    fullContinuationToken != null?CosmosElement.Parse(fullContinuationToken) : null,
                    this.cancellationToken);

                if (tryCreate.Succeeded)
                {
                    IDocumentQueryExecutionComponent executionContext = tryCreate.Result;

                    Assert.IsTrue(!executionContext.IsDone);

                    // Read all the pages from both splits
                    List <ToDoItem>   itemsRead = new List <ToDoItem>();
                    QueryResponseCore?failure   = null;
                    while (!executionContext.IsDone)
                    {
                        QueryResponseCore queryResponse = await executionContext.DrainAsync(
                            maxPageSize,
                            this.cancellationToken);

                        if (queryResponse.IsSuccess)
                        {
                            string responseContinuationToken = queryResponse.ContinuationToken;
                            foreach (CosmosElement element in queryResponse.CosmosElements)
                            {
                                string   jsonValue = element.ToString();
                                ToDoItem item      = JsonConvert.DeserializeObject <ToDoItem>(jsonValue);
                                itemsRead.Add(item);
                            }
                        }
                        else
                        {
                            Assert.IsNull(failure, "There should only be one error");
                            failure = queryResponse;
                        }
                    }

                    Assert.IsNotNull(failure);
                    Assert.AreEqual((HttpStatusCode)429, failure.Value.StatusCode);
                    Assert.IsNotNull(failure.Value.CosmosException.ToString());

                    Assert.AreEqual(0 /*We don't get any items, since we don't buffer the failure anymore*/, itemsRead.Count);

                    //CollectionAssert.AreEqual(allItems.ToList(), itemsRead, new ToDoItemComparer());
                }
                else
                {
                    QueryResponseCore queryResponseCore = QueryResponseFactory.CreateFromException(tryCreate.Exception);
                    Assert.AreEqual((HttpStatusCode)429, queryResponseCore.StatusCode);
                }
            }
        }
Exemplo n.º 20
0
        public ReadFeedIteratorCore(
            IDocumentContainer documentContainer,
            QueryRequestOptions queryRequestOptions,
            string continuationToken,
            int pageSize,
            CancellationToken cancellationToken)
        {
            if (!string.IsNullOrEmpty(continuationToken))
            {
                bool isNewArrayFormat = (continuationToken.Length >= 2) && (continuationToken[0] == '[') && (continuationToken[continuationToken.Length - 1] == ']');
                if (!isNewArrayFormat)
                {
                    // One of the two older formats
                    if (!FeedRangeContinuation.TryParse(continuationToken, out FeedRangeContinuation feedRangeContinuation))
                    {
                        // Backward compatible with old format
                        feedRangeContinuation = new FeedRangeCompositeContinuation(
                            containerRid: string.Empty,
                            FeedRangeEpk.FullRange,
                            new List <Documents.Routing.Range <string> >()
                        {
                            new Documents.Routing.Range <string>(
                                Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey,
                                Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey,
                                isMinInclusive: true,
                                isMaxInclusive: false)
                        },
                            continuationToken);
                    }

                    // need to massage it a little
                    string       oldContinuationFormat = feedRangeContinuation.ToString();
                    CosmosObject cosmosObject          = CosmosObject.Parse(oldContinuationFormat);
                    CosmosArray  continuations         = (CosmosArray)cosmosObject["Continuation"];

                    List <CosmosElement> readFeedContinuationTokens = new List <CosmosElement>();
                    foreach (CosmosElement continuation in continuations)
                    {
                        CosmosObject  continuationObject = (CosmosObject)continuation;
                        CosmosObject  rangeObject        = (CosmosObject)continuationObject["range"];
                        string        min   = ((CosmosString)rangeObject["min"]).Value;
                        string        max   = ((CosmosString)rangeObject["max"]).Value;
                        CosmosElement token = CosmosElement.Parse(((CosmosString)continuationObject["token"]).Value);

                        FeedRangeInternal         feedRange = new FeedRangeEpk(new Documents.Routing.Range <string>(min, max, isMinInclusive: true, isMaxInclusive: false));
                        ReadFeedState             state     = new ReadFeedState(token);
                        ReadFeedContinuationToken readFeedContinuationToken = new ReadFeedContinuationToken(feedRange, state);
                        readFeedContinuationTokens.Add(ReadFeedContinuationToken.ToCosmosElement(readFeedContinuationToken));
                    }

                    CosmosArray cosmosArrayContinuationTokens = CosmosArray.Create(readFeedContinuationTokens);
                    continuationToken = cosmosArrayContinuationTokens.ToString();
                }
            }

            this.monadicEnumerator = CrossPartitionReadFeedAsyncEnumerator.MonadicCreate(
                documentContainer,
                queryRequestOptions,
                continuationToken: continuationToken,
                pageSize,
                cancellationToken);

            this.hasMoreResults = true;
        }
            public override async ValueTask <bool> MoveNextAsync()
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                if (!await this.inputStage.MoveNextAsync())
                {
                    this.Current = default;
                    return(false);
                }

                TryCatch <QueryPage> tryGetSourcePage = this.inputStage.Current;

                if (tryGetSourcePage.Failed)
                {
                    this.Current = tryGetSourcePage;
                    return(true);
                }

                QueryPage sourcePage = tryGetSourcePage.Result;

                List <CosmosElement> distinctResults = new List <CosmosElement>();

                foreach (CosmosElement document in sourcePage.Documents)
                {
                    this.cancellationToken.ThrowIfCancellationRequested();

                    if (this.distinctMap.Add(document, out UInt128 _))
                    {
                        distinctResults.Add(document);
                    }
                }

                // For clients we write out the continuation token if it's a streaming query.
                QueryPage queryPage;

                if (this.distinctQueryType == DistinctQueryType.Ordered)
                {
                    QueryState state;
                    if (sourcePage.State != null)
                    {
                        string updatedContinuationToken = new DistinctContinuationToken(
                            sourceToken: sourcePage.State.Value.ToString(),
                            distinctMapToken: this.distinctMap.GetContinuationToken()).ToString();
                        state = new QueryState(CosmosElement.Parse(updatedContinuationToken));
                    }
                    else
                    {
                        state = null;
                    }

                    queryPage = new QueryPage(
                        documents: distinctResults,
                        requestCharge: sourcePage.RequestCharge,
                        activityId: sourcePage.ActivityId,
                        responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                        cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                        disallowContinuationTokenMessage: sourcePage.DisallowContinuationTokenMessage,
                        state: state);
                }
                else
                {
                    queryPage = new QueryPage(
                        documents: distinctResults,
                        requestCharge: sourcePage.RequestCharge,
                        activityId: sourcePage.ActivityId,
                        responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                        cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                        disallowContinuationTokenMessage: ClientDistinctQueryPipelineStage.DisallowContinuationTokenMessage,
                        state: null);
                }

                this.Current = TryCatch <QueryPage> .FromResult(queryPage);

                return(true);
            }
        public void JoinCollectionExpressionTest()
        {
            // FROM f
            // JOIN c IN f.children
            // JOIN p in c.pets
            SqlAliasedCollectionExpression fromf = SqlAliasedCollectionExpression.Create(
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("f"),
                    relativePath: null),
                alias: null);

            SqlArrayIteratorCollectionExpression cInFDotChildren = SqlArrayIteratorCollectionExpression.Create(
                SqlIdentifier.Create("c"),
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("f"),
                    SqlStringPathExpression.Create(
                        null,
                        SqlStringLiteral.Create("children"))));

            SqlJoinCollectionExpression joinFC = SqlJoinCollectionExpression.Create(
                fromf,
                cInFDotChildren);

            CosmosElement andersenChild1 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""AndersenFamily"",
                  ""lastName"": ""Andersen"",
                  ""parents"": [
                     { ""firstName"": ""Thomas"" },
                     { ""firstName"": ""Mary Kay""}
                  ],
                  ""children"": [
                     {
                         ""firstName"": ""Henriette Thaulow"",
                         ""gender"": ""female"",
                         ""grade"": 5,
                         ""pets"": [{ ""givenName"": ""Fluffy"" }]
                     }
                  ],
                  ""address"": { ""state"": ""WA"", ""county"": ""King"", ""city"": ""seattle"" },
                  ""creationDate"": 1431620472,
                  ""isRegistered"": true, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAA==""
                },
              ""c"": {
                         ""firstName"": ""Henriette Thaulow"",
                         ""gender"": ""female"",
                         ""grade"": 5,
                         ""pets"": [{ ""givenName"": ""Fluffy"" }]
                     }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAA==""
            }");

            CosmosElement wakeFieldChild1 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""WakefieldFamily"",
                  ""parents"": [
                      { ""familyName"": ""Wakefield"", ""givenName"": ""Robin"" },
                      { ""familyName"": ""Miller"", ""givenName"": ""Ben"" }
                  ],
                  ""children"": [
                      {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
                      { 
                        ""familyName"": ""Miller"", 
                         ""givenName"": ""Lisa"", 
                         ""gender"": ""female"", 
                         ""grade"": 8 }
                  ],
                  ""address"": { ""state"": ""NY"", ""county"": ""Manhattan"", ""city"": ""NY"" },
                  ""creationDate"": 1431620462,
                  ""isRegistered"": false, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
                },
              ""c"": {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
            }");

            CosmosElement wakeFieldChild2 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""WakefieldFamily"",
                  ""parents"": [
                      { ""familyName"": ""Wakefield"", ""givenName"": ""Robin"" },
                      { ""familyName"": ""Miller"", ""givenName"": ""Ben"" }
                  ],
                  ""children"": [
                      {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
                      { 
                        ""familyName"": ""Miller"", 
                         ""givenName"": ""Lisa"", 
                         ""gender"": ""female"", 
                         ""grade"": 8 }
                  ],
                  ""address"": { ""state"": ""NY"", ""county"": ""Manhattan"", ""city"": ""NY"" },
                  ""creationDate"": 1431620462,
                  ""isRegistered"": false, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
                },
              ""c"": { 
                        ""familyName"": ""Miller"", 
                         ""givenName"": ""Lisa"", 
                         ""gender"": ""female"", 
                         ""grade"": 8 }, ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
            }");

            AssertEvaluation(new CosmosElement[] { andersenChild1, wakeFieldChild1, wakeFieldChild2 }, joinFC, DataSource);

            SqlArrayIteratorCollectionExpression pInCDotPets = SqlArrayIteratorCollectionExpression.Create(
                SqlIdentifier.Create("p"),
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("c"),
                    SqlStringPathExpression.Create(
                        null,
                        SqlStringLiteral.Create("pets"))));

            SqlJoinCollectionExpression joinFCP = SqlJoinCollectionExpression.Create(
                SqlJoinCollectionExpression.Create(fromf, cInFDotChildren),
                pInCDotPets);

            CosmosElement andersenChild1Pet1 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""AndersenFamily"",
                  ""lastName"": ""Andersen"",
                  ""parents"": [
                     { ""firstName"": ""Thomas"" },
                     { ""firstName"": ""Mary Kay""}
                  ],
                  ""children"": [
                     {
                         ""firstName"": ""Henriette Thaulow"",
                         ""gender"": ""female"",
                         ""grade"": 5,
                         ""pets"": [{ ""givenName"": ""Fluffy"" }]
                     }
                  ],
                  ""address"": { ""state"": ""WA"", ""county"": ""King"", ""city"": ""seattle"" },
                  ""creationDate"": 1431620472,
                  ""isRegistered"": true, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAA==""
                },
              ""c"": {
                         ""firstName"": ""Henriette Thaulow"",
                         ""gender"": ""female"",
                         ""grade"": 5,
                         ""pets"": [{ ""givenName"": ""Fluffy"" }]
                     },
              ""p"": { ""givenName"": ""Fluffy"" }, 
              ""_rid"": ""0fomAIxnukU1AQAAAAAAAA==""
            }");

            CosmosElement wakeFieldChild1Pet1 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""WakefieldFamily"",
                  ""parents"": [
                      { ""familyName"": ""Wakefield"", ""givenName"": ""Robin"" },
                      { ""familyName"": ""Miller"", ""givenName"": ""Ben"" }
                  ],
                  ""children"": [
                      {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
                      { 
                        ""familyName"": ""Miller"", 
                         ""givenName"": ""Lisa"", 
                         ""gender"": ""female"", 
                         ""grade"": 8 }
                  ],
                  ""address"": { ""state"": ""NY"", ""county"": ""Manhattan"", ""city"": ""NY"" },
                  ""creationDate"": 1431620462,
                  ""isRegistered"": false, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
                },
              ""c"": {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
              ""p"": { ""givenName"": ""Goofy"" }, 
              ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
            }");

            CosmosElement wakeFieldChild1Pet2 = CosmosElement.Parse(@"
            {
              ""f"": {
                  ""id"": ""WakefieldFamily"",
                  ""parents"": [
                      { ""familyName"": ""Wakefield"", ""givenName"": ""Robin"" },
                      { ""familyName"": ""Miller"", ""givenName"": ""Ben"" }
                  ],
                  ""children"": [
                      {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
                      { 
                        ""familyName"": ""Miller"", 
                         ""givenName"": ""Lisa"", 
                         ""gender"": ""female"", 
                         ""grade"": 8 }
                  ],
                  ""address"": { ""state"": ""NY"", ""county"": ""Manhattan"", ""city"": ""NY"" },
                  ""creationDate"": 1431620462,
                  ""isRegistered"": false, 
                  ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
                },
              ""c"": {
                        ""familyName"": ""Merriam"",
                        ""givenName"": ""Jesse"",
                        ""gender"": ""female"", ""grade"": 1,
                        ""pets"": [
                            { ""givenName"": ""Goofy"" },
                            { ""givenName"": ""Shadow"" }
                        ]
                      },
              ""p"": { ""givenName"": ""Shadow"" }, 
              ""_rid"": ""0fomAIxnukU1AQAAAAAAAB==""
            }");

            AssertEvaluation(new CosmosElement[] { andersenChild1Pet1, wakeFieldChild1Pet1, wakeFieldChild1Pet2 }, joinFCP, DataSource);

            // SELECT c.id
            // FROM c
            // JOIN c.nonExistent

            SqlAliasedCollectionExpression c = SqlAliasedCollectionExpression.Create(
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("c"),
                    relativePath: null),
                alias: null);

            SqlAliasedCollectionExpression cDotNonExistent = SqlAliasedCollectionExpression.Create(
                SqlInputPathCollection.Create(
                    SqlIdentifier.Create("c"),
                    SqlStringPathExpression.Create(
                        null,
                        SqlStringLiteral.Create("nonExistent"))),
                alias: null);

            SqlJoinCollectionExpression joinCAndCDotNonExistent = SqlJoinCollectionExpression.Create(
                c,
                cDotNonExistent);

            AssertEvaluation(new CosmosElement[] { }, joinCAndCDotNonExistent, DataSource);
        }
 public override CosmosElement GetCosmosElementContinuationToken()
 {
     return(CosmosElement.Parse(this.FeedRangeContinuation.ToString()));
 }
        public ReadFeedIteratorCore(
            IDocumentContainer documentContainer,
            string continuationToken,
            ReadFeedPaginationOptions readFeedPaginationOptions,
            QueryRequestOptions queryRequestOptions,
            CancellationToken cancellationToken)
        {
            this.queryRequestOptions = queryRequestOptions;
            readFeedPaginationOptions ??= ReadFeedPaginationOptions.Default;

            if (!string.IsNullOrEmpty(continuationToken))
            {
                bool isNewArrayFormat = (continuationToken.Length >= 2) && (continuationToken[0] == '[') && (continuationToken[continuationToken.Length - 1] == ']');
                if (!isNewArrayFormat)
                {
                    // One of the two older formats
                    if (!FeedRangeContinuation.TryParse(continuationToken, out FeedRangeContinuation feedRangeContinuation))
                    {
                        // Backward compatible with old format
                        feedRangeContinuation = new FeedRangeCompositeContinuation(
                            containerRid: string.Empty,
                            FeedRangeEpk.FullRange,
                            new List <Documents.Routing.Range <string> >()
                        {
                            new Documents.Routing.Range <string>(
                                Documents.Routing.PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey,
                                Documents.Routing.PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey,
                                isMinInclusive: true,
                                isMaxInclusive: false)
                        },
                            continuationToken);
                    }

                    // need to massage it a little
                    List <CosmosElement> feedRangeStates = new List <CosmosElement>();
                    string oldContinuationFormat         = feedRangeContinuation.ToString();
                    if (feedRangeContinuation.FeedRange is FeedRangePartitionKey feedRangePartitionKey)
                    {
                        CosmosObject cosmosObject  = CosmosObject.Parse(oldContinuationFormat);
                        CosmosArray  continuations = (CosmosArray)cosmosObject["Continuation"];
                        if (continuations.Count != 1)
                        {
                            throw new InvalidOperationException("Expected only one continuation for partition key queries");
                        }

                        CosmosElement continuation       = continuations[0];
                        CosmosObject  continuationObject = (CosmosObject)continuation;
                        CosmosElement token = continuationObject["token"];
                        ReadFeedState state;
                        if (token is CosmosNull)
                        {
                            state = ReadFeedState.Beginning();
                        }
                        else
                        {
                            CosmosString tokenAsString = (CosmosString)token;
                            state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value));
                        }

                        FeedRangeState <ReadFeedState> feedRangeState = new FeedRangeState <ReadFeedState>(feedRangePartitionKey, state);
                        feedRangeStates.Add(ReadFeedFeedRangeStateSerializer.ToCosmosElement(feedRangeState));
                    }
                    else
                    {
                        CosmosObject cosmosObject  = CosmosObject.Parse(oldContinuationFormat);
                        CosmosArray  continuations = (CosmosArray)cosmosObject["Continuation"];

                        foreach (CosmosElement continuation in continuations)
                        {
                            CosmosObject  continuationObject = (CosmosObject)continuation;
                            CosmosObject  rangeObject        = (CosmosObject)continuationObject["range"];
                            string        min   = ((CosmosString)rangeObject["min"]).Value;
                            string        max   = ((CosmosString)rangeObject["max"]).Value;
                            CosmosElement token = continuationObject["token"];

                            FeedRangeInternal feedRange = new FeedRangeEpk(new Documents.Routing.Range <string>(min, max, isMinInclusive: true, isMaxInclusive: false));
                            ReadFeedState     state;
                            if (token is CosmosNull)
                            {
                                state = ReadFeedState.Beginning();
                            }
                            else
                            {
                                CosmosString tokenAsString = (CosmosString)token;
                                state = ReadFeedState.Continuation(CosmosElement.Parse(tokenAsString.Value));
                            }

                            FeedRangeState <ReadFeedState> feedRangeState = new FeedRangeState <ReadFeedState>(feedRange, state);
                            feedRangeStates.Add(ReadFeedFeedRangeStateSerializer.ToCosmosElement(feedRangeState));
                        }
                    }

                    CosmosArray cosmosArrayContinuationTokens = CosmosArray.Create(feedRangeStates);
                    continuationToken = cosmosArrayContinuationTokens.ToString();
                }
            }

            TryCatch <ReadFeedCrossFeedRangeState> monadicReadFeedState;

            if (continuationToken == null)
            {
                FeedRange feedRange;
                if ((this.queryRequestOptions != null) && this.queryRequestOptions.PartitionKey.HasValue)
                {
                    feedRange = new FeedRangePartitionKey(this.queryRequestOptions.PartitionKey.Value);
                }
                else if ((this.queryRequestOptions != null) && (this.queryRequestOptions.FeedRange != null))
                {
                    feedRange = this.queryRequestOptions.FeedRange;
                }
                else
                {
                    feedRange = FeedRangeEpk.FullRange;
                }

                monadicReadFeedState = TryCatch <ReadFeedCrossFeedRangeState> .FromResult(ReadFeedCrossFeedRangeState.CreateFromBeginning(feedRange));
            }
            else
            {
                monadicReadFeedState = ReadFeedCrossFeedRangeState.Monadic.Parse(continuationToken);
            }

            if (monadicReadFeedState.Failed)
            {
                this.monadicEnumerator = TryCatch <CrossPartitionReadFeedAsyncEnumerator> .FromException(monadicReadFeedState.Exception);
            }
            else
            {
                this.monadicEnumerator = TryCatch <CrossPartitionReadFeedAsyncEnumerator> .FromResult(
                    CrossPartitionReadFeedAsyncEnumerator.Create(
                        documentContainer,
                        new CrossFeedRangeState <ReadFeedState>(monadicReadFeedState.Result.FeedRangeStates),
                        readFeedPaginationOptions,
                        cancellationToken));
            }

            this.hasMoreResults = true;
        }