Пример #1
0
        public async Task Tracing()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(documents);

            IQueryPipelineStage pipelineStage = CreatePipeline(documentContainer, "SELECT * FROM c", pageSize: 10);

            Trace rootTrace;
            int   numTraces = 1;

            using (rootTrace = Trace.GetRootTrace("Cross Partition Query"))
            {
                while (await pipelineStage.MoveNextAsync(rootTrace))
                {
                    TryCatch <QueryPage> tryGetQueryPage = pipelineStage.Current;
                    tryGetQueryPage.ThrowIfFailed();

                    numTraces++;
                }
            }

            string traceString = TraceWriter.TraceToText(rootTrace);

            Console.WriteLine(traceString);

            Assert.AreEqual(numTraces, rootTrace.Children.Count);
        }
        public async Task Tracing()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(documents);

            IQueryPipelineStage pipelineStage = await CreatePipelineAsync(documentContainer, "SELECT * FROM c", pageSize : 10);

            Trace rootTrace;
            int   numTraces = (await documentContainer.GetFeedRangesAsync(NoOpTrace.Singleton, default)).Count;

            using (rootTrace = Trace.GetRootTrace("Cross Partition Query"))
            {
                while (await pipelineStage.MoveNextAsync(rootTrace))
                {
                    TryCatch <QueryPage> tryGetQueryPage = pipelineStage.Current;
                    tryGetQueryPage.ThrowIfFailed();

                    numTraces++;
                }
            }

            Assert.AreEqual(numTraces, rootTrace.Children.Count);
        }
        public async Task StartFromTimeAsync(bool useContinuations)
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems);
            CrossPartitionChangeFeedAsyncEnumerator enumerator = CrossPartitionChangeFeedAsyncEnumerator.Create(
                documentContainer,
                new CrossFeedRangeState<ChangeFeedState>(
                    new FeedRangeState<ChangeFeedState>[]
                    {
                        new FeedRangeState<ChangeFeedState>(FeedRangeEpk.FullRange, ChangeFeedState.Time(DateTime.UtcNow))
                    }),
                ChangeFeedPaginationOptions.Default,
                cancellationToken: default);

            for (int i = 0; i < numItems; i++)
            {
                // Insert an item
                CosmosObject item = CosmosObject.Parse($"{{\"pk\" : {i} }}");
                while (true)
                {
                    TryCatch<Record> monadicCreateRecord = await documentContainer.MonadicCreateItemAsync(item, cancellationToken: default);
                    if (monadicCreateRecord.Succeeded)
                    {
                        break;
                    }
                }
            }

            (int globalCount, double _) = await (useContinuations
                ? DrainWithUntilNotModifiedWithContinuationTokens(documentContainer, enumerator)
                : DrainUntilNotModifedAsync(enumerator));

            Assert.AreEqual(numItems, globalCount);
        }
Пример #4
0
        public async Task StartFromTimeAsync(bool useContinuations)
        {
            int numItems = 100;
            IDocumentContainer documentContainer = await CreateDocumentContainerAsync(numItems);

            TryCatch <CrossPartitionChangeFeedAsyncEnumerator> monadicEnumerator = CrossPartitionChangeFeedAsyncEnumerator.MonadicCreate(
                documentContainer,
                new ChangeFeedRequestOptions(),
                ChangeFeedStartFrom.Time(DateTime.UtcNow),
                cancellationToken: default);

            for (int i = 0; i < numItems; i++)
            {
                // Insert an item
                CosmosObject item = CosmosObject.Parse($"{{\"pk\" : {i} }}");
                while (true)
                {
                    TryCatch <Record> monadicCreateRecord = await documentContainer.MonadicCreateItemAsync(item, cancellationToken : default);

                    if (monadicCreateRecord.Succeeded)
                    {
                        break;
                    }
                }
            }

            Assert.IsTrue(monadicEnumerator.Succeeded);
            CrossPartitionChangeFeedAsyncEnumerator enumerator = monadicEnumerator.Result;

            int globalCount = await(useContinuations
                ? DrainWithUntilNotModifiedWithContinuationTokens(documentContainer, enumerator)
                : DrainUntilNotModifedAsync(enumerator));

            Assert.AreEqual(numItems, globalCount);
        }
            private static int ParseQueryState(QueryState state)
            {
                if (state == default)
                {
                    return(0);
                }

                CosmosObject parsedContinuationToken = CosmosObject.Parse(((CosmosString)state.Value).Value);
                int          continuationCount       = (int)Number64.ToLong(((CosmosNumber64)parsedContinuationToken["continuationCount"]).Value);

                return(continuationCount);
            }
Пример #6
0
        public async Task OrderBy()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT * FROM c ORDER BY c._ts",
                documents : documents);

            Assert.AreEqual(expected: documents.Count, actual: documentsQueried.Count);
        }
Пример #7
0
        // Need to implement group by continuation token on the in memory collection.
        public async Task GroupBy()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT VALUE COUNT(1) FROM c GROUP BY c.pk",
                documents : documents);

            Assert.AreEqual(expected: documents.Count, actual: documentsQueried.Count);
        }
Пример #8
0
        public async Task OffsetLimit()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT * FROM c OFFSET 10 LIMIT 103",
                documents : documents);

            Assert.AreEqual(expected: 103, actual: documentsQueried.Count);
        }
Пример #9
0
        [Ignore] // Continuation token for in memory container needs to be updated to suppport this query
        public async Task OrderByWithJoins()
        {
            List <CosmosObject> documents = new List <CosmosObject>()
            {
                CosmosObject.Parse($"{{\"pk\" : {1}, \"children\" : [\"Alice\", \"Bob\", \"Charlie\"]}}"),
                CosmosObject.Parse($"{{\"pk\" : {2}, \"children\" : [\"Dave\", \"Eve\", \"Fancy\"]}}"),
                CosmosObject.Parse($"{{\"pk\" : {3}, \"children\" : [\"George\", \"Henry\", \"Igor\"]}}"),
                CosmosObject.Parse($"{{\"pk\" : {4}, \"children\" : [\"Jack\", \"Kim\", \"Levin\"]}}"),
            };

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT d FROM c JOIN d in c.children ORDER BY c.pk",
                documents : documents,
                pageSize : 2);

            Assert.AreEqual(expected: documents.Count * 3, actual: documentsQueried.Count);
        }
Пример #10
0
        public async Task ChangeFeedIteratorCore_BreathFirst()
        {
            int               expected      = 500;
            CosmosObject      previousToken = null;
            ContainerInternal itemsCore     = await this.InitializeLargeContainerAsync();

            await this.CreateRandomItems(itemsCore, expected, randomPartitionKey : true);

            ChangeFeedIteratorCore feedIterator = itemsCore.GetChangeFeedStreamIterator(
                ChangeFeedStartFrom.Beginning(),
                ChangeFeedMode.Incremental,
                new ChangeFeedRequestOptions()
            {
                PageSizeHint = 1,
            }) as ChangeFeedIteratorCore;

            while (true)
            {
                using (ResponseMessage responseMessage = await feedIterator.ReadNextAsync(this.cancellationToken))
                {
                    CosmosObject cosmosObject = CosmosObject.Parse(responseMessage.ContinuationToken);
                    if (!cosmosObject.TryGetValue("Continuation", out CosmosArray cosmosArray))
                    {
                        Assert.Fail();
                        throw new Exception();
                    }

                    CosmosObject currentToken = (CosmosObject)cosmosArray[0];

                    if (previousToken != null)
                    {
                        // Verify that the token, even though it yielded results, it moved to a new range
                        Assert.AreNotEqual(previousToken, currentToken);
                        break;
                    }

                    previousToken = currentToken;

                    if (responseMessage.StatusCode == HttpStatusCode.NotModified)
                    {
                        break;
                    }
                }
            }
        }
Пример #11
0
        private static IReadOnlyList <(string serializedToken, CosmosElement element)> TokenTestData()
        {
            Guid guid = Guid.Parse("69D5AB17-C94A-4173-A278-B59D0D9C7C37");

            byte[] randomBytes = guid.ToByteArray();
            string hexString   = PartitionKeyInternal.HexConvert.ToHex(randomBytes, 0, randomBytes.Length);

            return(new List <(string, CosmosElement)>
            {
                ("[42, 37]", CosmosArray.Parse("[42, 37]")),
                ($@"{{C_Binary(""0x{hexString}"")}}", CosmosBinary.Create(new ReadOnlyMemory <byte>(randomBytes))),
                ("false", CosmosBoolean.Create(false)),
                ($@"{{C_Guid(""{guid}"")}}", CosmosGuid.Create(guid)),
                ("null", CosmosNull.Create()),
                ("1", CosmosInt64.Create(1)),
                ("{\"foo\": false}", CosmosObject.Parse("{\"foo\": false}")),
                ("asdf", CosmosString.Create("asdf"))
            });
Пример #12
0
        public async Task DCount()
        {
            List <CosmosObject> documents = new List <CosmosObject>();

            for (int i = 0; i < 250; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i}, \"val\": {i % 50} }}"));
            }

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT VALUE COUNT(1) FROM (SELECT DISTINCT VALUE c.val FROM c)",
                documents : documents);

            Assert.AreEqual(expected: 1, actual: documentsQueried.Count);
            Assert.IsTrue(documentsQueried[0] is CosmosNumber);
            CosmosNumber result = documentsQueried[0] as CosmosNumber;

            Assert.AreEqual(expected: 50, actual: result);
        }
Пример #13
0
        public async Task TestMerge()
        {
            List <CosmosObject> documents = Enumerable
                                            .Range(0, 100)
                                            .Select(x => CosmosObject.Parse($"{{\"pk\" : {x} }}"))
                                            .ToList();

            MergeTestUtil mergeTest = new MergeTestUtil();

            mergeTest.DocumentContainer = await CreateDocumentContainerAsync(
                documents : documents,
                numPartitions : 2,
                failureConfigs : new FlakyDocumentContainer.FailureConfigs(
                    inject429s: false,
                    injectEmptyPages: false,
                    shouldReturnFailure: mergeTest.ShouldReturnFailure));

            string query    = "SELECT * FROM c ORDER BY c._ts";
            int    pageSize = 10;
            IQueryPipelineStage pipelineStage = CreatePipeline(mergeTest.DocumentContainer, query, pageSize);

            List <CosmosElement> elements = new List <CosmosElement>();
            int iteration = 0;

            while (await pipelineStage.MoveNextAsync())
            {
                TryCatch <QueryPage> tryGetQueryPage = pipelineStage.Current;
                tryGetQueryPage.ThrowIfFailed();

                elements.AddRange(tryGetQueryPage.Result.Documents);
                ++iteration;

                if (iteration == 1)
                {
                    mergeTest.ShouldMerge = MergeTestUtil.TriState.Ready;
                }
            }

            Assert.AreEqual(expected: documents.Count, actual: elements.Count);
        }
Пример #14
0
        private ResponseMessage CreateQueryResponse()
        {
            List <CosmosElement> cosmosElements = new List <CosmosElement>();
            string       serializedItem         = this.GetSerializedToDoActivity();
            CosmosObject cosmosObject           = CosmosObject.Parse(serializedItem);

            cosmosElements.Add(cosmosObject);

            ResponseMessage cosmosResponse = QueryResponse.CreateSuccess(
                cosmosElements,
                1,
                Encoding.UTF8.GetByteCount(serializedItem),
                new CosmosQueryResponseMessageHeaders(
                    continauationToken: null,
                    disallowContinuationTokenMessage: null,
                    resourceType: Documents.ResourceType.Document,
                    "+o4fAPfXPzw="),
                new CosmosDiagnosticsContextCore(),
                null);

            return(cosmosResponse);
        }
Пример #15
0
        internal override IDocumentContainer CreateDocumentContainer(
            PartitionKeyDefinition partitionKeyDefinition,
            int numItems = 0,
            FlakyDocumentContainer.FailureConfigs failureConfigs = null)
        {
            IMonadicDocumentContainer monadicDocumentContainer = new InMemoryContainer(partitionKeyDefinition);

            if (failureConfigs != null)
            {
                monadicDocumentContainer = new FlakyDocumentContainer(monadicDocumentContainer, failureConfigs);
            }

            DocumentContainer documentContainer = new DocumentContainer(monadicDocumentContainer);

            for (int i = 0; i < numItems; i++)
            {
                // Insert an item
                CosmosObject item = CosmosObject.Parse($"{{\"pk\" : {i} }}");
                documentContainer.CreateItemAsync(item, cancellationToken: default).Wait();
            }

            return(documentContainer);
        }
        public async Task Aggregates()
        {
            const int           DocumentCount = 250;
            List <CosmosObject> documents     = new List <CosmosObject>();

            for (int i = 0; i < DocumentCount; i++)
            {
                documents.Add(CosmosObject.Parse($"{{\"pk\" : {i} }}"));
            }

            List <CosmosElement> documentsQueried = await ExecuteQueryAsync(
                query : "SELECT VALUE COUNT(1) FROM c",
                documents : documents);

            Assert.AreEqual(expected: 1, actual: documentsQueried.Count);
            if (documentsQueried[0] is CosmosNumber number)
            {
                Assert.AreEqual(expected: DocumentCount, actual: Number64.ToLong(number.Value));
            }
            else
            {
                Assert.Fail();
            }
        }
        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;
        }
Пример #18
0
        private async Task <(Container, IReadOnlyList <CosmosObject>)> CreateContainerAndIngestDocumentsAsync(
            CollectionTypes collectionType,
            IEnumerable <string> documents,
            string partitionKey = "/id",
            Cosmos.IndexingPolicy indexingPolicy = null)
        {
            Container container = collectionType switch
            {
                CollectionTypes.NonPartitioned => await this.CreateNonPartitionedContainerAsync(indexingPolicy),
                CollectionTypes.SinglePartition => await this.CreateSinglePartitionContainer(partitionKey, indexingPolicy),
                CollectionTypes.MultiPartition => await this.CreateMultiPartitionContainer(partitionKey, indexingPolicy),
                _ => throw new ArgumentException($"Unknown {nameof(CollectionTypes)} : {collectionType}"),
            };
            List <CosmosObject> insertedDocuments = new List <CosmosObject>();

            foreach (string document in documents)
            {
                JObject documentObject = JsonConvert.DeserializeObject <JObject>(document);
                // Add an id
                if (documentObject["id"] == null)
                {
                    documentObject["id"] = Guid.NewGuid().ToString();
                }

                // Get partition key value.
                Cosmos.PartitionKey pkValue;
                if (partitionKey != null)
                {
                    string jObjectPartitionKey = partitionKey.Remove(0, 1);
                    JValue pkToken             = (JValue)documentObject[jObjectPartitionKey];
                    if (pkToken == null)
                    {
                        pkValue = Cosmos.PartitionKey.None;
                    }
                    else
                    {
                        switch (pkToken.Type)
                        {
                        case JTokenType.Integer:
                        case JTokenType.Float:
                            pkValue = new Cosmos.PartitionKey(pkToken.Value <double>());
                            break;

                        case JTokenType.String:
                            pkValue = new Cosmos.PartitionKey(pkToken.Value <string>());
                            break;

                        case JTokenType.Boolean:
                            pkValue = new Cosmos.PartitionKey(pkToken.Value <bool>());
                            break;

                        case JTokenType.Null:
                            pkValue = Cosmos.PartitionKey.Null;
                            break;

                        default:
                            throw new ArgumentException("Unknown partition key type");
                        }
                    }
                }
                else
                {
                    pkValue = Cosmos.PartitionKey.None;
                }

                JObject createdDocument = await container.CreateItemAsync(documentObject, pkValue);

                CosmosObject insertedDocument = CosmosObject.Parse <CosmosObject>(createdDocument.ToString());
                insertedDocuments.Add(insertedDocument);
            }

            return(container, insertedDocuments);
        }
Пример #19
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;
        }