private static bool ShouldCreateSpecializedDocumentQueryExecutionContext(
     ResourceType resourceTypeEnum,
     FeedOptions feedOptions,
     PartitionedQueryExecutionInfo partitionedQueryExecutionInfo,
     PartitionKeyDefinition partitionKeyDefinition,
     bool isContinuationExpected)
 {
     // We need to aggregate the total results with Pipelined~Context if isContinuationExpected is false.
     return
         ((DocumentQueryExecutionContextFactory.IsCrossPartitionQuery(
               resourceTypeEnum,
               feedOptions,
               partitionKeyDefinition,
               partitionedQueryExecutionInfo) &&
           (DocumentQueryExecutionContextFactory.IsTopOrderByQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsAggregateQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsOffsetLimitQuery(partitionedQueryExecutionInfo) ||
            DocumentQueryExecutionContextFactory.IsParallelQuery(feedOptions)) ||
           !string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId)) ||
          // Even if it's single partition query we create a specialized context to aggregate the aggregates and distinct of distinct.
          DocumentQueryExecutionContextFactory.IsAggregateQueryWithoutContinuation(
              partitionedQueryExecutionInfo,
              isContinuationExpected) ||
          DocumentQueryExecutionContextFactory.IsDistinctQuery(partitionedQueryExecutionInfo) ||
          DocumentQueryExecutionContextFactory.IsGroupByQuery(partitionedQueryExecutionInfo));
 }
        public async Task <FeedResponse <dynamic> > ExecuteNextAsync(CancellationToken token)
        {
            if (this.IsDone)
            {
                throw new InvalidOperationException(RMResources.DocumentQueryExecutionContextIsDone);
            }

            Error error = null;

            try
            {
                return(await this.innerExecutionContext.ExecuteNextAsync(token));
            }
            catch (DocumentClientException ex)
            {
                if (ex.StatusCode != HttpStatusCode.BadRequest || ex.GetSubStatus() != SubStatusCodes.CrossPartitionQueryNotServable)
                {
                    throw;
                }

                error = ex.Error;
            }

            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo =
                JsonConvert.DeserializeObject <PartitionedQueryExecutionInfo>(error.AdditionalErrorInfo);

            DefaultDocumentQueryExecutionContext queryExecutionContext =
                (DefaultDocumentQueryExecutionContext)this.innerExecutionContext;

            List <PartitionKeyRange> partitionKeyRanges =
                await
                queryExecutionContext.GetTargetPartitionKeyRanges(collection.ResourceId,
                                                                  partitionedQueryExecutionInfo.QueryRanges);

            this.innerExecutionContext = await DocumentQueryExecutionContextFactory.CreateSpecializedDocumentQueryExecutionContext(
                this.client,
                this.resourceTypeEnum,
                this.resourceType,
                this.expression,
                this.feedOptions,
                this.resourceLink,
                isContinuationExpected,
                partitionedQueryExecutionInfo,
                partitionKeyRanges,
                this.collection.ResourceId,
                token,
                this.correlatedActivityId);

            return(await this.innerExecutionContext.ExecuteNextAsync(token));
        }
        public static async Task <MultiCollectionDocumentQueryExecutionContext> CreateAsync(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            IEnumerable <string> documentFeedLinks,
            bool isContinuationExpected,
            CancellationToken token,
            Guid correlatedActivityId)
        {
            if (client == null)
            {
                throw new ArgumentNullException("client");
            }

            if (feedOptions == null)
            {
                throw new ArgumentNullException("feedOptions");
            }

            if (documentFeedLinks == null)
            {
                throw new ArgumentNullException("documentFeedLinks");
            }

            List <IDocumentQueryExecutionContext> childQueryExecutionContexts = new List <IDocumentQueryExecutionContext>();

            foreach (string link in documentFeedLinks)
            {
                childQueryExecutionContexts.Add(await DocumentQueryExecutionContextFactory.CreateDocumentQueryExecutionContextAsync(
                                                    client,
                                                    resourceTypeEnum,
                                                    resourceType,
                                                    expression,
                                                    feedOptions,
                                                    link,
                                                    isContinuationExpected,
                                                    token,
                                                    correlatedActivityId));
            }

            return(new MultiCollectionDocumentQueryExecutionContext(childQueryExecutionContexts));
        }
        public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            string resourceLink,
            bool isContinuationExpected,
            CancellationToken token,
            Guid correlatedActivityId)
        {
            ContainerProperties collection = null;

            if (resourceTypeEnum.IsCollectionChild())
            {
                CollectionCache collectionCache = await client.GetCollectionCacheAsync();

                using (
                    DocumentServiceRequest request = DocumentServiceRequest.Create(
                        OperationType.Query,
                        resourceTypeEnum,
                        resourceLink,
                        AuthorizationTokenType.Invalid)) //this request doesnt actually go to server
                {
                    collection = await collectionCache.ResolveCollectionAsync(request, token);
                }

                if (feedOptions != null && feedOptions.PartitionKey != null && feedOptions.PartitionKey.Equals(Documents.PartitionKey.None))
                {
                    feedOptions.PartitionKey = Documents.PartitionKey.FromInternalKey(collection.GetNoneValue());
                }
            }

            DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams(
                client,
                resourceTypeEnum,
                resourceType,
                expression,
                feedOptions,
                resourceLink,
                false,
                correlatedActivityId);

            // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop, so need to bypass in that case.
            // We are also now bypassing this for 32 bit host process running even on Windows as there are many 32 bit apps that will not work without this
            if (CustomTypeExtensions.ByPassQueryParsing())
            {
                // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext
                // which will be used to send the query to Gateway and on getting 400(bad request) with 1004(cross partition query not servable), we initialize it with
                // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from Gateway).
                ProxyDocumentQueryExecutionContext proxyQueryExecutionContext =
                    ProxyDocumentQueryExecutionContext.Create(
                        client,
                        resourceTypeEnum,
                        resourceType,
                        expression,
                        feedOptions,
                        resourceLink,
                        token,
                        collection,
                        isContinuationExpected,
                        correlatedActivityId);

                return(proxyQueryExecutionContext);
            }

            DefaultDocumentQueryExecutionContext queryExecutionContext = await DefaultDocumentQueryExecutionContext.CreateAsync(
                constructorParams, isContinuationExpected, token);

            // If isContinuationExpected is false, we want to check if there are aggregates.
            if (
                resourceTypeEnum.IsCollectionChild() &&
                resourceTypeEnum.IsPartitioned() &&
                (feedOptions.EnableCrossPartitionQuery || !isContinuationExpected))
            {
                //todo:elasticcollections this may rely on information from collection cache which is outdated
                //if collection is deleted/created with same name.
                //need to make it not rely on information from collection cache.
                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = await queryExecutionContext.GetPartitionedQueryExecutionInfoAsync(
                    partitionKeyDefinition : collection.PartitionKey,
                    requireFormattableOrderByQuery : true,
                    isContinuationExpected : isContinuationExpected,
                    allowNonValueAggregateQuery : true,
                    hasLogicalPartitionKey : feedOptions.PartitionKey != null,
                    cancellationToken : token);

                if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext(
                        resourceTypeEnum,
                        feedOptions,
                        partitionedQueryExecutionInfo,
                        collection.PartitionKey,
                        isContinuationExpected))
                {
                    List <PartitionKeyRange> targetRanges = await GetTargetPartitionKeyRangesAsync(
                        queryExecutionContext,
                        partitionedQueryExecutionInfo,
                        collection,
                        feedOptions);

                    // Devnote this will get replace by the new v3 to v2 logic
                    throw new NotSupportedException("v2 query excution context is currently not supported.");
                }
            }

            return(queryExecutionContext);
        }
예제 #5
0
        public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync(
            IDocumentQueryClient client,
            ResourceType resourceTypeEnum,
            Type resourceType,
            Expression expression,
            FeedOptions feedOptions,
            string resourceLink,
            bool isContinuationExpected,
            CancellationToken token,
            Guid correlatedActivityId)
        {
            DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams(
                client,
                resourceTypeEnum,
                resourceType,
                expression,
                feedOptions,
                resourceLink,
                false,
                correlatedActivityId);

            CosmosContainerSettings collection = null;

            if (resourceTypeEnum.IsCollectionChild())
            {
                CollectionCache collectionCache = await client.GetCollectionCacheAsync();

                using (
                    DocumentServiceRequest request = DocumentServiceRequest.Create(
                        OperationType.Query,
                        resourceTypeEnum,
                        resourceLink,
                        AuthorizationTokenType.Invalid)) //this request doesnt actually go to server
                {
                    collection = await collectionCache.ResolveCollectionAsync(request, token);
                }
            }

            // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop, so need to bypass in that case.
            // We are also now bypassing this for 32 bit host process running even on Windows as there are many 32 bit apps that will not work without this
            if (CustomTypeExtensions.ByPassQueryParsing())
            {
                // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext
                // which will be used to send the query to Gateway and on getting 400(bad request) with 1004(cross partition query not servable), we initialize it with
                // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from Gateway).
                ProxyDocumentQueryExecutionContext proxyQueryExecutionContext =
                    ProxyDocumentQueryExecutionContext.CreateAsync(
                        client,
                        resourceTypeEnum,
                        resourceType,
                        expression,
                        feedOptions,
                        resourceLink,
                        token,
                        collection,
                        isContinuationExpected,
                        correlatedActivityId);

                return(proxyQueryExecutionContext);
            }

            DefaultDocumentQueryExecutionContext queryExecutionContext = await DefaultDocumentQueryExecutionContext.CreateAsync(
                constructorParams, isContinuationExpected, token);

            // If isContinuationExpected is false, we want to check if there are aggregates.
            if (
                resourceTypeEnum.IsCollectionChild() &&
                resourceTypeEnum.IsPartitioned() &&
                (feedOptions.EnableCrossPartitionQuery || !isContinuationExpected))
            {
                //todo:elasticcollections this may rely on information from collection cache which is outdated
                //if collection is deleted/created with same name.
                //need to make it not rely on information from collection cache.
                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = await queryExecutionContext.GetPartitionedQueryExecutionInfoAsync(
                    collection.PartitionKey,
                    true,
                    isContinuationExpected,
                    token);

                if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext(
                        resourceTypeEnum,
                        feedOptions,
                        partitionedQueryExecutionInfo,
                        collection.PartitionKey,
                        isContinuationExpected))
                {
                    List <PartitionKeyRange> targetRanges;
                    if (!string.IsNullOrEmpty(feedOptions.PartitionKeyRangeId))
                    {
                        targetRanges =
                            new List <PartitionKeyRange>
                        {
                            await queryExecutionContext.GetTargetPartitionKeyRangeById(
                                collection.ResourceId,
                                feedOptions.PartitionKeyRangeId)
                        };
                    }
                    else
                    {
                        List <Range <string> > queryRanges = partitionedQueryExecutionInfo.QueryRanges;
                        if (feedOptions.PartitionKey != null)
                        {
                            queryRanges = new List <Range <string> >
                            {
                                Range <string> .GetPointRange(
                                    feedOptions.PartitionKey.InternalKey.GetEffectivePartitionKeyString(
                                        collection.PartitionKey))
                            };
                        }

                        targetRanges =
                            await queryExecutionContext.GetTargetPartitionKeyRanges(collection.ResourceId, queryRanges);
                    }



                    return(await CreateSpecializedDocumentQueryExecutionContext(
                               constructorParams,
                               partitionedQueryExecutionInfo,
                               targetRanges,
                               collection.ResourceId,
                               isContinuationExpected,
                               token));
                }
            }

            return(queryExecutionContext);
        }