예제 #1
0
        public void LogicalPartitionKey()
        {
            Cosmos.PartitionKey somePartitionKey = new Cosmos.PartitionKey(42);
            FeedRangeInternal   feedRange        = new FeedRangePartitionKey(somePartitionKey);

            AssertRoundTrip(feedRange);
        }
예제 #2
0
        public void FeedRangePK_PK()
        {
            PartitionKey          partitionKey          = new PartitionKey("test");
            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);

            Assert.AreEqual(partitionKey, feedRangePartitionKey.PartitionKey);
        }
예제 #3
0
        public async Task FeedRangePK_GetPartitionKeyRangesAsync()
        {
            Documents.Routing.Range <string> range             = new Documents.Routing.Range <string>("AA", "BB", true, false);
            Documents.PartitionKeyRange      partitionKeyRange = new Documents.PartitionKeyRange()
            {
                Id = Guid.NewGuid().ToString(), MinInclusive = range.Min, MaxExclusive = range.Max
            };
            Documents.PartitionKeyDefinition partitionKeyDefinition = new Documents.PartitionKeyDefinition();
            partitionKeyDefinition.Paths.Add("/id");
            PartitionKey        partitionKey    = new PartitionKey("test");
            IRoutingMapProvider routingProvider = Mock.Of <IRoutingMapProvider>();

            Mock.Get(routingProvider)
            .Setup(f => f.TryGetOverlappingRangesAsync(It.IsAny <string>(), It.IsAny <Documents.Routing.Range <string> >(), It.IsAny <bool>()))
            .ReturnsAsync(new List <Documents.PartitionKeyRange>()
            {
                partitionKeyRange
            });

            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);
            IEnumerable <string>  pkRanges = await feedRangePartitionKey.GetPartitionKeyRangesAsync(routingProvider, null, partitionKeyDefinition, default(CancellationToken));

            Assert.AreEqual(1, pkRanges.Count());
            Assert.AreEqual(partitionKeyRange.Id, pkRanges.First());
        }
예제 #4
0
 public Task <TryCatch <QueryPage> > VisitAsync(
     FeedRangePartitionKey feedRange,
     Arguments argument,
     CancellationToken cancellationToken) => this.documentContainer.MonadicQueryAsync(
     argument.SqlQuerySpec,
     argument.ContinuationToken,
     feedRange.PartitionKey,
     argument.PageSize,
     cancellationToken);
예제 #5
0
        public void FeedRangePK_ToJsonFromJson()
        {
            PartitionKey          partitionKey          = new PartitionKey("test");
            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);
            string representation = feedRangePartitionKey.ToJsonString();
            FeedRangePartitionKey feedRangePartitionKeyDeserialized = Cosmos.FeedRange.FromJsonString(representation) as FeedRangePartitionKey;

            Assert.IsNotNull(feedRangePartitionKeyDeserialized);
            Assert.AreEqual(feedRangePartitionKey.PartitionKey.ToJsonString(), feedRangePartitionKeyDeserialized.PartitionKey.ToJsonString());
        }
예제 #6
0
        public void FeedRangePK_RequestVisitor()
        {
            PartitionKey          partitionKey          = new PartitionKey("test");
            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);
            RequestMessage        requestMessage        = new RequestMessage();

            feedRangePartitionKey.Accept(FeedRangeRequestMessagePopulatorVisitor.Singleton, requestMessage);
            Assert.AreEqual(partitionKey.InternalKey.ToJsonString(), requestMessage.Headers.PartitionKey);
            Assert.IsFalse(requestMessage.IsPartitionKeyRangeHandlerRequired);
        }
예제 #7
0
        public async Task FeedRangePK_GetEffectiveRangesAsync()
        {
            Documents.PartitionKeyDefinition partitionKeyDefinition = new Documents.PartitionKeyDefinition();
            partitionKeyDefinition.Paths.Add("/id");
            PartitionKey          partitionKey          = new PartitionKey("test");
            FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey);

            Documents.Routing.Range <string> range = Documents.Routing.Range <string> .GetPointRange(partitionKey.InternalKey.GetEffectivePartitionKeyString(partitionKeyDefinition));

            List <Documents.Routing.Range <string> > ranges = await feedRangePartitionKey.GetEffectiveRangesAsync(Mock.Of <IRoutingMapProvider>(), null, partitionKeyDefinition);

            Assert.AreEqual(1, ranges.Count);
            Assert.AreEqual(range, ranges[0]);
        }
예제 #8
0
        public async Task GetPartitionKeyRangesAsync_WithPKToken()
        {
            DocumentFeedResponse <Documents.PartitionKeyRange> ranges = await this.Container.ClientContext.DocumentClient.ReadPartitionKeyRangeFeedAsync(this.Container.LinkUri);

            FeedRange     feedToken      = new FeedRangePartitionKey(new PartitionKey("TBD"));
            List <string> resolvedRanges = (await this.Container.GetPartitionKeyRangesAsync(feedToken)).ToList();

            Assert.AreEqual(1, resolvedRanges.Count, "PK value should resolve to a single range");

            foreach (string id in resolvedRanges)
            {
                Assert.IsTrue(ranges.Any(range => range.Id == id));
            }
        }
예제 #9
0
        private void FeedRange_PartitionKey_Validate(PartitionKey partitionKey)
        {
            string continuationToken = "TBD";
            string containerRid      = Guid.NewGuid().ToString();
            FeedRangePartitionKey          feedTokenPartitionKey       = new FeedRangePartitionKey(partitionKey);
            FeedRangeCompositeContinuation feedRangeSimpleContinuation = new FeedRangeCompositeContinuation(containerRid, feedTokenPartitionKey, new List <Documents.Routing.Range <string> >()
            {
                Documents.Routing.Range <string> .GetEmptyRange("AA")
            }, continuationToken);
            string serialized = feedRangeSimpleContinuation.ToString();

            Assert.IsTrue(FeedRangeContinuation.TryParse(serialized, out FeedRangeContinuation deserialized));
            FeedRangeCompositeContinuation deserializedContinuation = deserialized as FeedRangeCompositeContinuation;
            FeedRangePartitionKey          deserializedFeedRange    = deserializedContinuation.FeedRange as FeedRangePartitionKey;

            Assert.AreEqual(feedTokenPartitionKey.PartitionKey.ToJsonString(), deserializedFeedRange.PartitionKey.ToJsonString());
            Assert.AreEqual(continuationToken, deserializedContinuation.GetContinuation());
        }
 public void Visit(FeedRangePartitionKey feedRange, RequestMessage requestMessage)
 {
     requestMessage.Headers.PartitionKey = feedRange.PartitionKey.ToJsonString();
 }
        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;
        }
        public override async Task <ResponseMessage> ReadNextAsync(
            ITrace trace,
            CancellationToken cancellationToken = default)
        {
            if (trace == null)
            {
                throw new ArgumentNullException(nameof(trace));
            }

            cancellationToken.ThrowIfCancellationRequested();

            if (!this.hasMoreResults)
            {
                throw new InvalidOperationException("Should not be calling FeedIterator that does not have any more results");
            }

            if (this.monadicEnumerator.Failed)
            {
                this.hasMoreResults = false;

                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(this.monadicEnumerator.Exception);
                return(new ResponseMessage(
                           statusCode: System.Net.HttpStatusCode.BadRequest,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossPartitionReadFeedAsyncEnumerator enumerator = this.monadicEnumerator.Result;
            TryCatch <CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> > monadicPage;

            try
            {
                if (!await enumerator.MoveNextAsync(trace))
                {
                    throw new InvalidOperationException("Should not be calling enumerator that does not have any more results");
                }

                monadicPage = enumerator.Current;
            }
            catch (Exception ex)
            {
                monadicPage = TryCatch <CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> > .FromException(ex);
            }

            if (monadicPage.Failed)
            {
                CosmosException cosmosException = ExceptionToCosmosException.CreateFromException(monadicPage.Exception);
                if (!IsRetriableException(cosmosException))
                {
                    this.hasMoreResults = false;
                }

                return(new ResponseMessage(
                           statusCode: cosmosException.StatusCode,
                           requestMessage: null,
                           headers: cosmosException.Headers,
                           cosmosException: cosmosException,
                           trace: trace));
            }

            CrossFeedRangePage <Pagination.ReadFeedPage, ReadFeedState> crossFeedRangePage = monadicPage.Result;

            if (crossFeedRangePage.State == default)
            {
                this.hasMoreResults = false;
            }

            // Make the continuation token match the older format:
            string continuationToken;

            if (crossFeedRangePage.State != null)
            {
                List <CompositeContinuationToken>   compositeContinuationTokens = new List <CompositeContinuationToken>();
                CrossFeedRangeState <ReadFeedState> crossFeedRangeState         = crossFeedRangePage.State;
                for (int i = 0; i < crossFeedRangeState.Value.Length; i++)
                {
                    FeedRangeState <ReadFeedState> feedRangeState = crossFeedRangeState.Value.Span[i];
                    FeedRangeEpk feedRange;
                    if (feedRangeState.FeedRange is FeedRangeEpk feedRangeEpk)
                    {
                        feedRange = feedRangeEpk;
                    }
                    else
                    {
                        feedRange = FeedRangeEpk.FullRange;
                    }

                    ReadFeedState readFeedState = feedRangeState.State;
                    CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken()
                    {
                        Range = feedRange.Range,
                        Token = readFeedState is ReadFeedBeginningState ? null : ((ReadFeedContinuationState)readFeedState).ContinuationToken.ToString(),
                    };

                    compositeContinuationTokens.Add(compositeContinuationToken);
                }

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

                FeedRangeCompositeContinuation feedRangeCompositeContinuation = new FeedRangeCompositeContinuation(
                    containerRid: string.Empty,
                    feedRange: outerFeedRange,
                    compositeContinuationTokens);

                continuationToken = feedRangeCompositeContinuation.ToString();
            }
            else
            {
                continuationToken = null;
            }

            Pagination.ReadFeedPage page = crossFeedRangePage.Page;
            Headers headers = new Headers()
            {
                RequestCharge     = page.RequestCharge,
                ActivityId        = page.ActivityId,
                ContinuationToken = continuationToken,
            };

            foreach (KeyValuePair <string, string> kvp in page.AdditionalHeaders)
            {
                headers[kvp.Key] = kvp.Value;
            }

            return(new ResponseMessage(
                       statusCode: System.Net.HttpStatusCode.OK,
                       requestMessage: default,