/// <summary> /// Drains at most 'maxElements' documents from the AggregateDocumentQueryExecutionComponent. /// </summary> /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param> /// <param name="token">The cancellation token.</param> /// <returns>The aggregate result after all the continuations have been followed.</returns> /// <remarks> /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained. /// This means that if you have a long running query this function will take a very long time to return. /// </remarks> public override async Task <QueryResponse> DrainAsync(int maxElements, CancellationToken token) { // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document. // Note-2019-07-11-brchon: We can return empty pages until all the documents are drained, // but then we will have to design a continuation token. double requestCharge = 0; long responseLengthBytes = 0; List <Uri> replicaUris = new List <Uri>(); ClientSideRequestStatistics requestStatistics = new ClientSideRequestStatistics(); PartitionedQueryMetrics partitionedQueryMetrics = new PartitionedQueryMetrics(); ResourceType resourceType = ResourceType.Document; string containerRid = null; while (!this.IsDone) { QueryResponse result = await base.DrainAsync(int.MaxValue, token); if (!result.IsSuccessStatusCode) { return(result); } containerRid = result.QueryHeaders.ContainerRid; resourceType = result.QueryHeaders.ResourceType; requestCharge += result.Headers.RequestCharge; responseLengthBytes += result.ResponseLengthBytes; // DEVNOTE: Add when query metrics is supported // partitionedQueryMetrics += new PartitionedQueryMetrics(results.QueryMetrics); if (result.RequestStatistics != null) { replicaUris.AddRange(result.RequestStatistics.ContactedReplicas); } foreach (CosmosElement element in result.CosmosElements) { RewrittenAggregateProjections rewrittenAggregateProjections = new RewrittenAggregateProjections( this.isValueAggregateQuery, element); this.singleGroupAggregator.AddValues(rewrittenAggregateProjections.Payload); } } List <CosmosElement> finalResult = new List <CosmosElement>(); CosmosElement aggregationResult = this.singleGroupAggregator.GetResult(); if (aggregationResult != null) { finalResult.Add(aggregationResult); } // The replicaUris may have duplicates. requestStatistics.ContactedReplicas.AddRange(replicaUris); return(QueryResponse.CreateSuccess( result: finalResult, count: finalResult.Count, responseLengthBytes: responseLengthBytes, responseHeaders: new CosmosQueryResponseMessageHeaders( continauationToken: null, disallowContinuationTokenMessage: null, resourceType: resourceType, containerRid: containerRid) { RequestCharge = requestCharge }, queryMetrics: this.GetQueryMetrics())); }
/// <summary> /// Drains at most 'maxElements' documents from the AggregateDocumentQueryExecutionComponent. /// </summary> /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param> /// <param name="token">The cancellation token.</param> /// <returns>The aggregate result after all the continuations have been followed.</returns> /// <remarks> /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained. /// This means that if you have a long running query this function will take a very long time to return. /// </remarks> public override async Task <FeedResponse <CosmosElement> > DrainAsync(int maxElements, CancellationToken token) { // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document. double requestCharge = 0; long responseLengthBytes = 0; List <Uri> replicaUris = new List <Uri>(); ClientSideRequestStatistics requestStatistics = new ClientSideRequestStatistics(); PartitionedQueryMetrics partitionedQueryMetrics = new PartitionedQueryMetrics(); while (!this.IsDone) { FeedResponse <CosmosElement> result = await base.DrainAsync(int.MaxValue, token); requestCharge += result.RequestCharge; responseLengthBytes += result.ResponseLengthBytes; partitionedQueryMetrics += new PartitionedQueryMetrics(result.QueryMetrics); if (result.RequestStatistics != null) { replicaUris.AddRange(result.RequestStatistics.ContactedReplicas); } foreach (CosmosElement item in result) { if (!(item is CosmosArray comosArray)) { throw new InvalidOperationException("Expected an array of aggregate results from the execution context."); } List <AggregateItem> aggregateItems = new List <AggregateItem>(); foreach (CosmosElement arrayItem in comosArray) { aggregateItems.Add(new AggregateItem(arrayItem)); } Debug.Assert( aggregateItems.Count == this.aggregators.Length, $"Expected {this.aggregators.Length} values, but received {aggregateItems.Count}."); for (int i = 0; i < this.aggregators.Length; ++i) { this.aggregators[i].Aggregate(aggregateItems[i].Item); } } } List <CosmosElement> finalResult = this.BindAggregateResults( this.aggregators.Select(aggregator => aggregator.GetResult())); // The replicaUris may have duplicates. requestStatistics.ContactedReplicas.AddRange(replicaUris); return(new FeedResponse <CosmosElement>( finalResult, finalResult.Count, new StringKeyValueCollection() { { HttpConstants.HttpHeaders.RequestCharge, requestCharge.ToString(CultureInfo.InvariantCulture) } }, useETagAsContinuation: false, queryMetrics: partitionedQueryMetrics, requestStats: requestStatistics, disallowContinuationTokenMessage: null, responseLengthBytes: responseLengthBytes)); }
/// <summary> /// Drains at most 'maxElements' documents from the <see cref="AggregateDocumentQueryExecutionComponent"/> . /// </summary> /// <param name="maxElements">This value is ignored, since the aggregates are aggregated for you.</param> /// <param name="token">The cancellation token.</param> /// <returns>The aggregate result after all the continuations have been followed.</returns> /// <remarks> /// Note that this functions follows all continuations meaning that it won't return until all continuations are drained. /// This means that if you have a long running query this function will take a very long time to return. /// </remarks> public override async Task <QueryResponse> DrainAsync(int maxElements, CancellationToken token) { token.ThrowIfCancellationRequested(); // Note-2016-10-25-felixfan: Given what we support now, we should expect to return only 1 document. double requestCharge = 0; long responseLengthBytes = 0; List <Uri> replicaUris = new List <Uri>(); ClientSideRequestStatistics requestStatistics = new ClientSideRequestStatistics(); PartitionedQueryMetrics partitionedQueryMetrics = new PartitionedQueryMetrics(); while (!this.IsDone) { QueryResponse result = await base.DrainAsync(int.MaxValue, token); if (!result.IsSuccessStatusCode) { return(result); } requestCharge += result.Headers.RequestCharge; responseLengthBytes += result.ResponseLengthBytes; //partitionedQueryMetrics += new PartitionedQueryMetrics(result.QueryMetrics); if (result.RequestStatistics != null) { replicaUris.AddRange(result.RequestStatistics.ContactedReplicas); } foreach (CosmosElement item in result.CosmosElements) { if (!(item is CosmosArray comosArray)) { throw new InvalidOperationException("Expected an array of aggregate results from the execution context."); } List <AggregateItem> aggregateItems = new List <AggregateItem>(); foreach (CosmosElement arrayItem in comosArray) { aggregateItems.Add(new AggregateItem(arrayItem)); } Debug.Assert( aggregateItems.Count == this.aggregators.Length, $"Expected {this.aggregators.Length} values, but received {aggregateItems.Count}."); for (int i = 0; i < this.aggregators.Length; ++i) { this.aggregators[i].Aggregate(aggregateItems[i].Item); } } } List <CosmosElement> finalResult = this.BindAggregateResults( this.aggregators.Select(aggregator => aggregator.GetResult())); // The replicaUris may have duplicates. requestStatistics.ContactedReplicas.AddRange(replicaUris); return(QueryResponse.CreateSuccess( result: finalResult, count: finalResult.Count, responseLengthBytes: responseLengthBytes, responseHeaders: new CosmosQueryResponseMessageHeaders(continauationToken: null, disallowContinuationTokenMessage: null) { RequestCharge = requestCharge })); }