public void LogicalPartitionKey() { Cosmos.PartitionKey somePartitionKey = new Cosmos.PartitionKey(42); FeedRangeInternal feedRange = new FeedRangePartitionKey(somePartitionKey); AssertRoundTrip(feedRange); }
public void FeedRangePK_PK() { PartitionKey partitionKey = new PartitionKey("test"); FeedRangePartitionKey feedRangePartitionKey = new FeedRangePartitionKey(partitionKey); Assert.AreEqual(partitionKey, feedRangePartitionKey.PartitionKey); }
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()); }
public Task <TryCatch <QueryPage> > VisitAsync( FeedRangePartitionKey feedRange, Arguments argument, CancellationToken cancellationToken) => this.documentContainer.MonadicQueryAsync( argument.SqlQuerySpec, argument.ContinuationToken, feedRange.PartitionKey, argument.PageSize, cancellationToken);
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()); }
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); }
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]); }
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)); } }
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,