/// <summary>
                /// Tries to parse a DistinctContinuationToken from a string.
                /// </summary>
                /// <param name="cosmosElement">The value to parse.</param>
                /// <param name="distinctContinuationToken">The output DistinctContinuationToken.</param>
                /// <returns>True if we successfully parsed the DistinctContinuationToken, else false.</returns>
                public static bool TryParse(
                    CosmosElement cosmosElement,
                    out DistinctContinuationToken distinctContinuationToken)
                {
                    if (!(cosmosElement is CosmosObject cosmosObject))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    if (!cosmosObject.TryGetValue(
                            DistinctContinuationToken.PropertyNames.SourceToken,
                            out CosmosString sourceToken))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    if (!cosmosObject.TryGetValue(
                            DistinctContinuationToken.PropertyNames.DistinctMapToken,
                            out CosmosString distinctMapToken))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    distinctContinuationToken = new DistinctContinuationToken(sourceToken.Value, distinctMapToken.Value);
                    return(true);
                }
                public static bool TryParse(
                    CosmosElement requestContinuationToken,
                    out DistinctContinuationToken distinctContinuationToken)
                {
                    if (requestContinuationToken == null)
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    if (!(requestContinuationToken is CosmosObject rawObject))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    if (!rawObject.TryGetValue(SourceTokenName, out CosmosElement sourceToken))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    if (!rawObject.TryGetValue(DistinctMapTokenName, out CosmosElement distinctMapToken))
                    {
                        distinctContinuationToken = default;
                        return(false);
                    }

                    distinctContinuationToken = new DistinctContinuationToken(sourceToken: sourceToken, distinctMapToken: distinctMapToken);
                    return(true);
                }
            /// <summary>
            /// Creates an DistinctDocumentQueryExecutionComponent
            /// </summary>
            /// <param name="queryClient">The query client</param>
            /// <param name="requestContinuation">The continuation token.</param>
            /// <param name="createSourceCallback">The callback to create the source to drain from.</param>
            /// <param name="distinctQueryType">The type of distinct query.</param>
            /// <returns>A task to await on and in return </returns>
            public static async Task <DistinctDocumentQueryExecutionComponent> CreateAsync(
                CosmosQueryClient queryClient,
                string requestContinuation,
                Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
                DistinctQueryType distinctQueryType)
            {
                DistinctContinuationToken distinctContinuationToken;

                if (requestContinuation != null)
                {
                    if (!DistinctContinuationToken.TryParse(requestContinuation, out distinctContinuationToken))
                    {
                        throw queryClient.CreateBadRequestException($"Invalid {nameof(DistinctContinuationToken)}: {requestContinuation}");
                    }
                }
                else
                {
                    distinctContinuationToken = new DistinctContinuationToken(sourceToken: null, distinctMapToken: null);
                }

                DistinctMap distinctMap = DistinctMap.Create(distinctQueryType, distinctContinuationToken.DistinctMapToken);
                IDocumentQueryExecutionComponent source = await createSourceCallback(distinctContinuationToken.SourceToken);

                return(new ComputeDistinctDocumentQueryExecutionComponent(
                           distinctQueryType,
                           distinctMap,
                           source));
            }
            /// <summary>
            /// Drains a page of results returning only distinct elements.
            /// </summary>
            /// <param name="maxElements">The maximum number of items to drain.</param>
            /// <param name="cancellationToken">The cancellation token.</param>
            /// <returns>A page of distinct results.</returns>
            public override async Task <QueryResponseCore> DrainAsync(int maxElements, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                List <CosmosElement> distinctResults = new List <CosmosElement>();
                QueryResponseCore    sourceResponse  = await base.DrainAsync(maxElements, cancellationToken);

                if (!sourceResponse.IsSuccess)
                {
                    return(sourceResponse);
                }

                foreach (CosmosElement document in sourceResponse.CosmosElements)
                {
                    if (this.distinctMap.Add(document, out UInt128 hash))
                    {
                        distinctResults.Add(document);
                    }
                }

                // For clients we write out the continuation token if it's a streaming query.
                QueryResponseCore queryResponseCore;

                if (this.distinctQueryType == DistinctQueryType.Ordered)
                {
                    string updatedContinuationToken;
                    if (this.IsDone)
                    {
                        updatedContinuationToken = null;
                    }
                    else
                    {
                        updatedContinuationToken = new DistinctContinuationToken(
                            sourceToken: sourceResponse.ContinuationToken,
                            distinctMapToken: this.distinctMap.GetContinuationToken()).ToString();
                    }

                    queryResponseCore = QueryResponseCore.CreateSuccess(
                        result: distinctResults,
                        continuationToken: updatedContinuationToken,
                        disallowContinuationTokenMessage: null,
                        activityId: sourceResponse.ActivityId,
                        requestCharge: sourceResponse.RequestCharge,
                        diagnostics: sourceResponse.Diagnostics,
                        responseLengthBytes: sourceResponse.ResponseLengthBytes);
                }
                else
                {
                    queryResponseCore = QueryResponseCore.CreateSuccess(
                        result: distinctResults,
                        continuationToken: null,
                        disallowContinuationTokenMessage: ClientDistinctDocumentQueryExecutionComponent.DisallowContinuationTokenMessage,
                        activityId: sourceResponse.ActivityId,
                        requestCharge: sourceResponse.RequestCharge,
                        diagnostics: sourceResponse.Diagnostics,
                        responseLengthBytes: sourceResponse.ResponseLengthBytes);
                }

                return(queryResponseCore);
            }
            public override bool TryGetContinuationToken(out string continuationToken)
            {
                if (this.distinctQueryType != DistinctQueryType.Ordered)
                {
                    continuationToken = null;
                    return(false);
                }

                if (this.IsDone)
                {
                    continuationToken = null;
                    return(true);
                }

                if (!this.Source.TryGetContinuationToken(out string sourceContinuationToken))
                {
                    continuationToken = default;
                    return(false);
                }

                continuationToken = new DistinctContinuationToken(
                    sourceContinuationToken,
                    this.distinctMap.GetContinuationToken()).ToString();
                return(true);
            }
示例#6
0
            public override async ValueTask <bool> MoveNextAsync(ITrace trace)
            {
                if (trace == null)
                {
                    throw new ArgumentNullException(nameof(trace));
                }

                if (!await this.inputStage.MoveNextAsync(trace))
                {
                    this.Current = default;
                    return(false);
                }

                TryCatch <QueryPage> tryGetSourcePage = this.inputStage.Current;

                if (tryGetSourcePage.Failed)
                {
                    this.Current = tryGetSourcePage;
                    return(true);
                }

                QueryPage sourcePage = tryGetSourcePage.Result;

                List <CosmosElement> distinctResults = new List <CosmosElement>();

                foreach (CosmosElement document in sourcePage.Documents)
                {
                    if (this.distinctMap.Add(document, out UInt128 _))
                    {
                        distinctResults.Add(document);
                    }
                }

                QueryState queryState;

                if (sourcePage.State != null)
                {
                    DistinctContinuationToken distinctContinuationToken = new DistinctContinuationToken(
                        sourceToken: sourcePage.State.Value,
                        distinctMapToken: this.distinctMap.GetCosmosElementContinuationToken());
                    queryState = new QueryState(DistinctContinuationToken.ToCosmosElement(distinctContinuationToken));
                }
                else
                {
                    queryState = null;
                }

                QueryPage queryPage = new QueryPage(
                    documents: distinctResults,
                    requestCharge: sourcePage.RequestCharge,
                    activityId: sourcePage.ActivityId,
                    responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                    cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                    disallowContinuationTokenMessage: ComputeDistinctQueryPipelineStage.UseTryGetContinuationTokenMessage,
                    state: queryState);

                this.Current = TryCatch <QueryPage> .FromResult(queryPage);

                return(true);
            }
            public static TryCatch <IQueryPipelineStage> MonadicCreate(
                CosmosElement requestContinuation,
                CancellationToken cancellationToken,
                MonadicCreatePipelineStage monadicCreatePipelineStage,
                DistinctQueryType distinctQueryType)
            {
                if (monadicCreatePipelineStage == null)
                {
                    throw new ArgumentNullException(nameof(monadicCreatePipelineStage));
                }

                DistinctContinuationToken distinctContinuationToken;

                if (requestContinuation != null)
                {
                    if (!DistinctContinuationToken.TryParse(requestContinuation, out distinctContinuationToken))
                    {
                        return(TryCatch <IQueryPipelineStage> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Invalid {nameof(DistinctContinuationToken)}: {requestContinuation}")));
                    }
                }
                else
                {
                    distinctContinuationToken = new DistinctContinuationToken(sourceToken: null, distinctMapToken: null);
                }

                TryCatch <DistinctMap> tryCreateDistinctMap = DistinctMap.TryCreate(
                    distinctQueryType,
                    distinctContinuationToken.DistinctMapToken);

                if (!tryCreateDistinctMap.Succeeded)
                {
                    return(TryCatch <IQueryPipelineStage> .FromException(tryCreateDistinctMap.Exception));
                }

                TryCatch <IQueryPipelineStage> tryCreateSource = monadicCreatePipelineStage(distinctContinuationToken.SourceToken, cancellationToken);

                if (!tryCreateSource.Succeeded)
                {
                    return(TryCatch <IQueryPipelineStage> .FromException(tryCreateSource.Exception));
                }

                return(TryCatch <IQueryPipelineStage> .FromResult(
                           new ComputeDistinctQueryPipelineStage(
                               tryCreateDistinctMap.Result,
                               tryCreateSource.Result,
                               cancellationToken)));
            }
            public static async Task <TryCatch <IDocumentQueryExecutionComponent> > TryCreateAsync(
                CosmosElement requestContinuation,
                Func <CosmosElement, Task <TryCatch <IDocumentQueryExecutionComponent> > > tryCreateSourceAsync,
                DistinctQueryType distinctQueryType)
            {
                if (tryCreateSourceAsync == null)
                {
                    throw new ArgumentNullException(nameof(tryCreateSourceAsync));
                }

                DistinctContinuationToken distinctContinuationToken;

                if (requestContinuation != null)
                {
                    if (!DistinctContinuationToken.TryParse(requestContinuation, out distinctContinuationToken))
                    {
                        return(TryCatch <IDocumentQueryExecutionComponent> .FromException(
                                   new MalformedContinuationTokenException($"Invalid {nameof(DistinctContinuationToken)}: {requestContinuation}")));
                    }
                }
                else
                {
                    distinctContinuationToken = new DistinctContinuationToken(sourceToken: null, distinctMapToken: null);
                }

                TryCatch <DistinctMap> tryCreateDistinctMap = DistinctMap.TryCreate(
                    distinctQueryType,
                    distinctContinuationToken.DistinctMapToken);

                if (!tryCreateDistinctMap.Succeeded)
                {
                    return(TryCatch <IDocumentQueryExecutionComponent> .FromException(tryCreateDistinctMap.Exception));
                }

                TryCatch <IDocumentQueryExecutionComponent> tryCreateSource = await tryCreateSourceAsync(
                    distinctContinuationToken.SourceToken);

                if (!tryCreateSource.Succeeded)
                {
                    return(TryCatch <IDocumentQueryExecutionComponent> .FromException(tryCreateSource.Exception));
                }

                return(TryCatch <IDocumentQueryExecutionComponent> .FromResult(
                           new ComputeDistinctDocumentQueryExecutionComponent(
                               distinctQueryType,
                               tryCreateDistinctMap.Result,
                               tryCreateSource.Result)));
            }
                public static CosmosElement ToCosmosElement(DistinctContinuationToken distinctContinuationToken)
                {
                    Dictionary <string, CosmosElement> dictionary = new Dictionary <string, CosmosElement>()
                    {
                        {
                            DistinctContinuationToken.SourceTokenName,
                            distinctContinuationToken.SourceToken
                        },
                        {
                            DistinctContinuationToken.DistinctMapTokenName,
                            distinctContinuationToken.DistinctMapToken
                        }
                    };

                    return(CosmosObject.Create(dictionary));
                }
        /// <summary>
        /// Drains a page of results returning only distinct elements.
        /// </summary>
        /// <param name="maxElements">The maximum number of items to drain.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A page of distinct results.</returns>
        public override async Task <QueryResponseCore> DrainAsync(int maxElements, CancellationToken cancellationToken)
        {
            List <CosmosElement> distinctResults     = new List <CosmosElement>();
            QueryResponseCore    cosmosQueryResponse = await base.DrainAsync(maxElements, cancellationToken);

            if (!cosmosQueryResponse.IsSuccess)
            {
                return(cosmosQueryResponse);
            }

            foreach (CosmosElement document in cosmosQueryResponse.CosmosElements)
            {
                if (this.distinctMap.Add(document, out this.lastHash))
                {
                    distinctResults.Add(document);
                }
            }

            string updatedContinuationToken;

            if (!this.IsDone)
            {
                updatedContinuationToken = new DistinctContinuationToken(
                    this.lastHash,
                    cosmosQueryResponse.ContinuationToken).ToString();
            }
            else
            {
                this.Source.Stop();
                updatedContinuationToken = null;
            }

            string disallowContinuationTokenMessage = this.distinctQueryType == DistinctQueryType.Ordered ? null : RMResources.UnorderedDistinctQueryContinuationToken;

            return(QueryResponseCore.CreateSuccess(
                       result: distinctResults,
                       continuationToken: updatedContinuationToken,
                       disallowContinuationTokenMessage: disallowContinuationTokenMessage,
                       activityId: cosmosQueryResponse.ActivityId,
                       requestCharge: cosmosQueryResponse.RequestCharge,
                       queryMetricsText: cosmosQueryResponse.QueryMetricsText,
                       queryMetrics: cosmosQueryResponse.QueryMetrics,
                       requestStatistics: cosmosQueryResponse.RequestStatistics,
                       responseLengthBytes: cosmosQueryResponse.ResponseLengthBytes));
        }
示例#11
0
            /// <summary>
            /// Tries to parse a DistinctContinuationToken from a string.
            /// </summary>
            /// <param name="value">The value to parse.</param>
            /// <param name="distinctContinuationToken">The output DistinctContinuationToken.</param>
            /// <returns>True if we successfully parsed the DistinctContinuationToken, else false.</returns>
            public static bool TryParse(string value, out DistinctContinuationToken distinctContinuationToken)
            {
                distinctContinuationToken = default(DistinctContinuationToken);
                if (string.IsNullOrWhiteSpace(value))
                {
                    return(false);
                }

                try
                {
                    distinctContinuationToken = JsonConvert.DeserializeObject <DistinctContinuationToken>(value);
                    return(true);
                }
                catch (JsonException ex)
                {
                    DefaultTrace.TraceWarning($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)} Invalid continuation token {value} for Distinct~Component, exception: {ex.Message}");
                    return(false);
                }
            }
示例#12
0
            /// <summary>
            /// Tries to parse a DistinctContinuationToken from a string.
            /// </summary>
            /// <param name="value">The value to parse.</param>
            /// <param name="distinctContinuationToken">The output DistinctContinuationToken.</param>
            /// <returns>True if we successfully parsed the DistinctContinuationToken, else false.</returns>
            public static bool TryParse(
                string value,
                out DistinctContinuationToken distinctContinuationToken)
            {
                distinctContinuationToken = default(DistinctContinuationToken);
                if (string.IsNullOrWhiteSpace(value))
                {
                    return(false);
                }

                try
                {
                    distinctContinuationToken = JsonConvert.DeserializeObject <DistinctContinuationToken>(value);
                    return(true);
                }
                catch (JsonException)
                {
                    return(false);
                }
            }
        /// <summary>
        /// Drains a page of results returning only distinct elements.
        /// </summary>
        /// <param name="maxElements">The maximum number of items to drain.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A page of distinct results.</returns>
        public override async Task <QueryResponse> DrainAsync(int maxElements, CancellationToken cancellationToken)
        {
            List <CosmosElement> distinctResults     = new List <CosmosElement>();
            QueryResponse        cosmosQueryResponse = await base.DrainAsync(maxElements, cancellationToken);

            if (!cosmosQueryResponse.IsSuccessStatusCode)
            {
                return(cosmosQueryResponse);
            }

            foreach (CosmosElement document in cosmosQueryResponse.CosmosElements)
            {
                if (this.distinctMap.Add(document, out this.lastHash))
                {
                    distinctResults.Add(document);
                }
            }

            string updatedContinuationToken;

            if (!this.IsDone)
            {
                updatedContinuationToken = new DistinctContinuationToken(
                    this.lastHash,
                    cosmosQueryResponse.Headers.ContinuationToken).ToString();
            }
            else
            {
                this.Source.Stop();
                updatedContinuationToken = null;
            }

            string disallowContinuationTokenMessage = this.distinctQueryType == DistinctQueryType.Ordered ? null : RMResources.UnorderedDistinctQueryContinuationToken;

            return(QueryResponse.CreateSuccess(
                       distinctResults,
                       distinctResults.Count,
                       cosmosQueryResponse.ResponseLengthBytes,
                       cosmosQueryResponse.QueryHeaders.CloneKnownProperties(updatedContinuationToken, disallowContinuationTokenMessage),
                       cosmosQueryResponse.queryMetrics));
        }
示例#14
0
        /// <summary>
        /// Creates an DistinctDocumentQueryExecutionComponent
        /// </summary>
        /// <param name="requestContinuation">The continuation token.</param>
        /// <param name="createSourceCallback">The callback to create the source to drain from.</param>
        /// <param name="distinctQueryType">The type of distinct query.</param>
        /// <returns>A task to await on and in return </returns>
        public static async Task <IDocumentQueryExecutionComponent> CreateAsync(
            string requestContinuation,
            Func <string, Task <IDocumentQueryExecutionComponent> > createSourceCallback,
            DistinctQueryType distinctQueryType)
        {
            DistinctContinuationToken distinctContinuationToken = new DistinctContinuationToken(null, null);

            if (requestContinuation != null)
            {
                distinctContinuationToken = DistinctContinuationToken.Parse(requestContinuation);
                if (distinctQueryType != DistinctQueryType.Ordered && distinctContinuationToken.LastHash != null)
                {
                    throw new BadRequestException($"DistinctContinuationToken is malformed: {distinctContinuationToken}. DistinctContinuationToken can not have a 'lastHash', when the query type is not ordered (ex SELECT DISTINCT VALUE c.blah FROM c ORDER BY c.blah).");
                }
            }

            return(new DistinctDocumentQueryExecutionComponent(
                       distinctQueryType,
                       distinctContinuationToken.LastHash,
                       await createSourceCallback(distinctContinuationToken.SourceToken)));
        }
            public static TryCatch <IQueryPipelineStage> MonadicCreate(
                CosmosElement requestContinuation,
                CancellationToken cancellationToken,
                MonadicCreatePipelineStage monadicCreatePipelineStage,
                DistinctQueryType distinctQueryType)
            {
                if (monadicCreatePipelineStage == null)
                {
                    throw new ArgumentNullException(nameof(monadicCreatePipelineStage));
                }

                DistinctContinuationToken distinctContinuationToken;

                if (requestContinuation != null)
                {
                    if (!DistinctContinuationToken.TryParse(requestContinuation, out distinctContinuationToken))
                    {
                        return(TryCatch <IQueryPipelineStage> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Invalid {nameof(DistinctContinuationToken)}: {requestContinuation}")));
                    }
                }
                else
                {
                    distinctContinuationToken = new DistinctContinuationToken(
                        sourceToken: null,
                        distinctMapToken: null);
                }

                CosmosElement distinctMapToken = distinctContinuationToken.DistinctMapToken != null
                    ? CosmosString.Create(distinctContinuationToken.DistinctMapToken)
                    : null;

                TryCatch <DistinctMap> tryCreateDistinctMap = DistinctMap.TryCreate(
                    distinctQueryType,
                    distinctMapToken);

                if (!tryCreateDistinctMap.Succeeded)
                {
                    return(TryCatch <IQueryPipelineStage> .FromException(tryCreateDistinctMap.Exception));
                }

                CosmosElement sourceToken;

                if (distinctContinuationToken.SourceToken != null)
                {
                    TryCatch <CosmosElement> tryParse = CosmosElement.Monadic.Parse(distinctContinuationToken.SourceToken);
                    if (tryParse.Failed)
                    {
                        return(TryCatch <IQueryPipelineStage> .FromException(
                                   new MalformedContinuationTokenException(
                                       message : $"Invalid Source Token: {distinctContinuationToken.SourceToken}",
                                       innerException : tryParse.Exception)));
                    }

                    sourceToken = tryParse.Result;
                }
                else
                {
                    sourceToken = null;
                }

                TryCatch <IQueryPipelineStage> tryCreateSource = monadicCreatePipelineStage(sourceToken, cancellationToken);

                if (!tryCreateSource.Succeeded)
                {
                    return(TryCatch <IQueryPipelineStage> .FromException(tryCreateSource.Exception));
                }

                return(TryCatch <IQueryPipelineStage> .FromResult(
                           new ClientDistinctQueryPipelineStage(
                               distinctQueryType,
                               tryCreateDistinctMap.Result,
                               tryCreateSource.Result,
                               cancellationToken)));
            }
            public override async ValueTask <bool> MoveNextAsync()
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                if (!await this.inputStage.MoveNextAsync())
                {
                    this.Current = default;
                    return(false);
                }

                TryCatch <QueryPage> tryGetSourcePage = this.inputStage.Current;

                if (tryGetSourcePage.Failed)
                {
                    this.Current = tryGetSourcePage;
                    return(true);
                }

                QueryPage sourcePage = tryGetSourcePage.Result;

                List <CosmosElement> distinctResults = new List <CosmosElement>();

                foreach (CosmosElement document in sourcePage.Documents)
                {
                    this.cancellationToken.ThrowIfCancellationRequested();

                    if (this.distinctMap.Add(document, out UInt128 _))
                    {
                        distinctResults.Add(document);
                    }
                }

                // For clients we write out the continuation token if it's a streaming query.
                QueryPage queryPage;

                if (this.distinctQueryType == DistinctQueryType.Ordered)
                {
                    QueryState state;
                    if (sourcePage.State != null)
                    {
                        string updatedContinuationToken = new DistinctContinuationToken(
                            sourceToken: sourcePage.State.Value.ToString(),
                            distinctMapToken: this.distinctMap.GetContinuationToken()).ToString();
                        state = new QueryState(CosmosElement.Parse(updatedContinuationToken));
                    }
                    else
                    {
                        state = null;
                    }

                    queryPage = new QueryPage(
                        documents: distinctResults,
                        requestCharge: sourcePage.RequestCharge,
                        activityId: sourcePage.ActivityId,
                        responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                        cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                        disallowContinuationTokenMessage: sourcePage.DisallowContinuationTokenMessage,
                        state: state);
                }
                else
                {
                    queryPage = new QueryPage(
                        documents: distinctResults,
                        requestCharge: sourcePage.RequestCharge,
                        activityId: sourcePage.ActivityId,
                        responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                        cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                        disallowContinuationTokenMessage: ClientDistinctQueryPipelineStage.DisallowContinuationTokenMessage,
                        state: null);
                }

                this.Current = TryCatch <QueryPage> .FromResult(queryPage);

                return(true);
            }