public static TryCatch <CompositeContinuationToken> TryCreateFromCosmosElement(CosmosElement cosmosElement)
        {
            if (!(cosmosElement is CosmosObject cosmosObject))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is not an object: {cosmosElement}")));
            }

            if (!cosmosObject.TryGetValue(TokenName, out CosmosElement rawToken))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{TokenName}': {cosmosElement}")));
            }

            string token;

            if (rawToken is CosmosString rawTokenString)
            {
                token = rawTokenString.Value;
            }
            else
            {
                token = null;
            }

            if (!cosmosObject.TryGetValue(RangeName, out CosmosObject rawRange))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{RangeName}': {cosmosElement}")));
            }

            if (!rawRange.TryGetValue(MinName, out CosmosString rawMin))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{MinName}': {cosmosElement}")));
            }

            string min = rawMin.Value;

            if (!rawRange.TryGetValue(MaxName, out CosmosString rawMax))
            {
                return(TryCatch <CompositeContinuationToken> .FromException(
                           new MalformedContinuationTokenException($"{nameof(CompositeContinuationToken)} is missing field: '{MaxName}': {cosmosElement}")));
            }

            string max = rawMax.Value;

            Documents.Routing.Range <string> range = new Documents.Routing.Range <string>(min, max, true, false);

            CompositeContinuationToken compositeContinuationToken = new CompositeContinuationToken()
            {
                Token = token,
                Range = range,
            };

            return(TryCatch <CompositeContinuationToken> .FromResult(compositeContinuationToken));
        }
            public override async ValueTask <bool> MoveNextAsync(ITrace trace)
            {
                this.cancellationToken.ThrowIfCancellationRequested();

                if (trace == null)
                {
                    throw new ArgumentNullException(nameof(trace));
                }

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

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

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

                QueryPage sourcePage = tryGetSourcePage.Result;

                List <CosmosElement> takedDocuments = sourcePage.Documents.Take(this.takeCount).ToList();

                this.takeCount -= takedDocuments.Count;

                QueryState state;

                if ((sourcePage.State != null) && (sourcePage.DisallowContinuationTokenMessage == null))
                {
                    string updatedContinuationToken = this.takeEnum switch
                    {
                        TakeEnum.Limit => new LimitContinuationToken(
                            limit: this.takeCount,
                            sourceToken: sourcePage.State?.Value.ToString()).ToString(),
                        TakeEnum.Top => new TopContinuationToken(
                            top: this.takeCount,
                            sourceToken: sourcePage.State?.Value.ToString()).ToString(),
                        _ => throw new ArgumentOutOfRangeException($"Unknown {nameof(TakeEnum)}: {this.takeEnum}."),
                    };

                    state = new QueryState(CosmosElement.Parse(updatedContinuationToken));
                }
                else
                {
                    state = null;
                }

                QueryPage queryPage = new QueryPage(
                    documents: takedDocuments,
                    requestCharge: sourcePage.RequestCharge,
                    activityId: sourcePage.ActivityId,
                    responseLengthInBytes: sourcePage.ResponseLengthInBytes,
                    cosmosQueryExecutionInfo: sourcePage.CosmosQueryExecutionInfo,
                    disallowContinuationTokenMessage: sourcePage.DisallowContinuationTokenMessage,
                    additionalHeaders: sourcePage.AdditionalHeaders,
                    state: state);

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

                return(true);
            }
예제 #3
0
 private MinMaxAggregator(bool isMinAggregation, CosmosElement globalMinMax)
 {
     this.isMinAggregation = isMinAggregation;
     this.globalMinMax     = globalMinMax;
 }
            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);
                }

                CosmosElement distinctMapToken;

                if (distinctContinuationToken.DistinctMapToken != null)
                {
                    distinctMapToken = CosmosString.Create(distinctContinuationToken.DistinctMapToken);
                }
                else
                {
                    distinctMapToken = null;
                }

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

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

                CosmosElement sourceToken;

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

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

                TryCatch <IDocumentQueryExecutionComponent> tryCreateSource = await tryCreateSourceAsync(sourceToken);

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

                return(TryCatch <IDocumentQueryExecutionComponent> .FromResult(
                           new ClientDistinctDocumentQueryExecutionComponent(
                               distinctQueryType,
                               tryCreateDistinctMap.Result,
                               tryCreateSource.Result)));
            }
 public static (bool parsed, OffsetContinuationToken offsetContinuationToken) TryParse(CosmosElement value)
 {
     if (value == null)
     {
         return(false, default);
예제 #6
0
        internal void GetDeserializedObjectsFromQueryResponseTest(JsonSerializationFormat jsonSerializationFormat)
        {
            // Constants to use for vertex document property key/values
            const string vertex1Id             = "v_0";
            const string vertex2Id             = "v_1";
            const string vertex1Label          = "l_0";
            const string vertex2Label          = "l_1";
            const string vertex1PkValue        = "pk_0";
            const string vertex2PkValue        = "pk_1";
            const string property1Name         = "p_0";
            const string vertex1Property1Value = "v_0_p_0_v_0";
            const string vertex2Property1Value = "v_1_p_0_v_0";
            const string property2Name         = "p_1";
            const double vertex1Property2Value = 12.34;
            const long   vertex2Property2Value = 5678;

            // Compose two initial vertex documents using eager CosmosElements
            CosmosObject initialVertex1EagerObject = this.CreateVertexDocument(
                vertex1Id,
                vertex1Label,
                GremlinScenarioTests.PartitionKeyPropertyName,
                vertex1PkValue,
                new Tuple <string, IEnumerable <object> >[]
            {
                Tuple.Create <string, IEnumerable <object> >(property1Name, new object[] { vertex1Property1Value }),
                Tuple.Create <string, IEnumerable <object> >(property2Name, new object[] { vertex1Property2Value }),
            });
            CosmosObject initialVertex2EagerObject = this.CreateVertexDocument(
                vertex2Id,
                vertex2Label,
                GremlinScenarioTests.PartitionKeyPropertyName,
                vertex2PkValue,
                new Tuple <string, IEnumerable <object> >[]
            {
                Tuple.Create <string, IEnumerable <object> >(property1Name, new object[] { vertex2Property1Value }),
                Tuple.Create <string, IEnumerable <object> >(property2Name, new object[] { vertex2Property2Value }),
            });

            // Serialize the initial vertex object into a document using the specified serialization format
            IJsonWriter jsonWriter = JsonWriter.Create(jsonSerializationFormat);

            initialVertex1EagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> vertex1JsonWriterResult = jsonWriter.GetResult();

            Assert.IsTrue(vertex1JsonWriterResult.Length > 0, "IJsonWriter result data is empty.");

            jsonWriter = JsonWriter.Create(jsonSerializationFormat);
            initialVertex2EagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> vertex2JsonWriterResult = jsonWriter.GetResult();

            Assert.IsTrue(vertex2JsonWriterResult.Length > 0, "IJsonWriter result data is empty.");

            // Navigate into the serialized vertex documents using lazy CosmosElements
            CosmosElement vertex1LazyObject = CosmosElement.CreateFromBuffer(vertex1JsonWriterResult);
            CosmosElement vertex2LazyObject = CosmosElement.CreateFromBuffer(vertex2JsonWriterResult);

            // Create a dynamically-typed QueryResponse backed by the vertex document CosmosElements
            CosmosArray vertexArray = CosmosArray.Create(
                new CosmosElement[]
            {
                vertex1LazyObject,
                vertex2LazyObject,
            });
            QueryResponse queryResponse = QueryResponse.CreateSuccess(
                vertexArray,
                count: 2,
                responseLengthBytes: vertex1JsonWriterResult.Length + vertex2JsonWriterResult.Length,
                serializationOptions: null,
                responseHeaders: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders(
                    sourceHeaders: null,
                    resourceType: ResourceType.Document,
                    containerRid: GremlinScenarioTests.CreateRandomString(10)),
                diagnostics: new CosmosDiagnosticsContextCore());
            QueryResponse <dynamic> cosmosElementQueryResponse =
                QueryResponse <dynamic> .CreateResponse <dynamic>(
                    queryResponse,
                    MockCosmosUtil.Serializer);

            // Assert that other objects (anything besides the lazy CosmosElements that we created earlier) are deserialized
            // from the backing CosmosElement contents rather than being directly returned as CosmosElements
            List <dynamic> responseCosmosElements = new List <dynamic>(cosmosElementQueryResponse.Resource);

            Assert.AreEqual(vertexArray.Count, responseCosmosElements.Count);
            Assert.AreNotSame(vertex1LazyObject, responseCosmosElements[0]);
            Assert.AreNotSame(vertex2LazyObject, responseCosmosElements[1]);
        }
 public static UInt128 GetHash(CosmosElement cosmosElement)
 {
     return(GetHash(cosmosElement, RootHashSeed));
 }
 /// <summary>
 /// Gets the hash of a JToken value.
 /// </summary>
 /// <param name="cosmosElement">The element to load.</param>
 /// <returns>The hash of the JToken.</returns>
 public UInt192 GetHashToken(CosmosElement cosmosElement)
 {
     return(this.GetHashToken(cosmosElement, this.HashSeedValues.Root));
 }
 /// <summary>
 /// Gets the hash of a JToken.
 /// </summary>
 /// <param name="cosmosElement">The token to hash.</param>
 /// <returns>The hash of the JToken.</returns>
 protected static UInt192 GetHash(CosmosElement cosmosElement)
 {
     return(DistinctHash.Value.GetHashToken(cosmosElement));
 }
        private static TryCatch <CrossPartitionState <QueryState> > MonadicExtractState(
            CosmosElement continuationToken,
            IReadOnlyList <FeedRangeEpk> ranges)
        {
            if (continuationToken == null)
            {
                // Full fan out to the ranges with null continuations
                CrossPartitionState <QueryState> fullFanOutState = new CrossPartitionState <QueryState>(ranges.Select(range => ((FeedRangeInternal)range, (QueryState)null)).ToArray());
                return(TryCatch <CrossPartitionState <QueryState> > .FromResult(fullFanOutState));
            }

            if (!(continuationToken is CosmosArray parallelContinuationTokenListRaw))
            {
                return(TryCatch <CrossPartitionState <QueryState> > .FromException(
                           new MalformedContinuationTokenException(
                               $"Invalid format for continuation token {continuationToken} for {nameof(ParallelCrossPartitionQueryPipelineStage)}")));
            }

            if (parallelContinuationTokenListRaw.Count == 0)
            {
                return(TryCatch <CrossPartitionState <QueryState> > .FromException(
                           new MalformedContinuationTokenException(
                               $"Invalid format for continuation token {continuationToken} for {nameof(ParallelCrossPartitionQueryPipelineStage)}")));
            }

            List <ParallelContinuationToken> parallelContinuationTokens = new List <ParallelContinuationToken>();

            foreach (CosmosElement parallelContinuationTokenRaw in parallelContinuationTokenListRaw)
            {
                TryCatch <ParallelContinuationToken> tryCreateParallelContinuationToken = ParallelContinuationToken.TryCreateFromCosmosElement(parallelContinuationTokenRaw);
                if (tryCreateParallelContinuationToken.Failed)
                {
                    return(TryCatch <CrossPartitionState <QueryState> > .FromException(
                               tryCreateParallelContinuationToken.Exception));
                }

                parallelContinuationTokens.Add(tryCreateParallelContinuationToken.Result);
            }

            TryCatch <PartitionMapping <ParallelContinuationToken> > partitionMappingMonad = PartitionMapper.MonadicGetPartitionMapping(
                ranges,
                parallelContinuationTokens);

            if (partitionMappingMonad.Failed)
            {
                return(TryCatch <CrossPartitionState <QueryState> > .FromException(
                           partitionMappingMonad.Exception));
            }

            PartitionMapping <ParallelContinuationToken> partitionMapping = partitionMappingMonad.Result;
            List <(FeedRangeInternal, QueryState)>       rangesAndStates  = new List <(FeedRangeInternal, QueryState)>();

            List <IReadOnlyDictionary <FeedRangeEpk, ParallelContinuationToken> > rangesToInitialize = new List <IReadOnlyDictionary <FeedRangeEpk, ParallelContinuationToken> >()
            {
                // Skip all the partitions left of the target range, since they have already been drained fully.
                partitionMapping.TargetPartition,
                partitionMapping.PartitionsRightOfTarget,
            };

            foreach (IReadOnlyDictionary <FeedRangeEpk, ParallelContinuationToken> rangeToInitalize in rangesToInitialize)
            {
                foreach (KeyValuePair <FeedRangeEpk, ParallelContinuationToken> kvp in rangeToInitalize)
                {
                    (FeedRangeInternal, QueryState)rangeAndState = (kvp.Key, kvp.Value?.Token != null ? new QueryState(CosmosString.Create(kvp.Value.Token)) : null);
                    rangesAndStates.Add(rangeAndState);
                }
            }

            CrossPartitionState <QueryState> crossPartitionState = new CrossPartitionState <QueryState>(rangesAndStates);

            return(TryCatch <CrossPartitionState <QueryState> > .FromResult(crossPartitionState));
        }
 public static ReadFeedState Continuation(CosmosElement cosmosElement) => new ReadFeedContinuationState(cosmosElement);
예제 #12
0
        private static async Task <TryCatch <CosmosQueryExecutionContext> > TryCreateCoreContextAsync(
            CosmosQueryContext cosmosQueryContext,
            InputParameters inputParameters,
            CancellationToken cancellationToken)
        {
            // The default
            using (cosmosQueryContext.CreateDiagnosticScope("CreateQueryPipeline"))
            {
                // Try to parse the continuation token.
                CosmosElement continuationToken = inputParameters.InitialUserContinuationToken;
                PartitionedQueryExecutionInfo queryPlanFromContinuationToken = inputParameters.PartitionedQueryExecutionInfo;
                if (continuationToken != null)
                {
                    if (!PipelineContinuationToken.TryCreateFromCosmosElement(
                            continuationToken,
                            out PipelineContinuationToken pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Malformed {nameof(PipelineContinuationToken)}: {continuationToken}.")));
                    }

                    if (PipelineContinuationToken.IsTokenFromTheFuture(pipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)} Continuation token is from a newer version of the SDK. " +
                                       $"Upgrade the SDK to avoid this issue." +
                                       $"{continuationToken}.")));
                    }

                    if (!PipelineContinuationToken.TryConvertToLatest(
                            pipelineContinuationToken,
                            out PipelineContinuationTokenV1_1 latestVersionPipelineContinuationToken))
                    {
                        return(TryCatch <CosmosQueryExecutionContext> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(PipelineContinuationToken)}: '{continuationToken}' is no longer supported.")));
                    }

                    continuationToken = latestVersionPipelineContinuationToken.SourceContinuationToken;
                    if (latestVersionPipelineContinuationToken.QueryPlan != null)
                    {
                        queryPlanFromContinuationToken = latestVersionPipelineContinuationToken.QueryPlan;
                    }
                }

                CosmosQueryClient        cosmosQueryClient        = cosmosQueryContext.QueryClient;
                ContainerQueryProperties containerQueryProperties = await cosmosQueryClient.GetCachedContainerQueryPropertiesAsync(
                    cosmosQueryContext.ResourceLink,
                    inputParameters.PartitionKey,
                    cancellationToken);

                cosmosQueryContext.ContainerResourceId = containerQueryProperties.ResourceId;

                PartitionedQueryExecutionInfo partitionedQueryExecutionInfo;
                if (inputParameters.ForcePassthrough)
                {
                    partitionedQueryExecutionInfo = new PartitionedQueryExecutionInfo()
                    {
                        QueryInfo = new QueryInfo()
                        {
                            Aggregates     = null,
                            DistinctType   = DistinctQueryType.None,
                            GroupByAliases = null,
                            GroupByAliasToAggregateType = null,
                            GroupByExpressions          = null,
                            HasSelectValue     = false,
                            Limit              = null,
                            Offset             = null,
                            OrderBy            = null,
                            OrderByExpressions = null,
                            RewrittenQuery     = null,
                            Top = null,
                        },
                        QueryRanges = new List <Documents.Routing.Range <string> >(),
                    };
                }
                else if (queryPlanFromContinuationToken != null)
                {
                    partitionedQueryExecutionInfo = queryPlanFromContinuationToken;
                }
                else
                {
                    // If the query would go to gateway, but we have a partition key,
                    // then try seeing if we can execute as a passthrough using client side only logic.
                    // This is to short circuit the need to go to the gateway to get the query plan.
                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing() &&
                        inputParameters.PartitionKey.HasValue)
                    {
                        bool     parsed;
                        SqlQuery sqlQuery;
                        using (cosmosQueryContext.CreateDiagnosticScope("QueryParsing"))
                        {
                            parsed = SqlQueryParser.TryParse(inputParameters.SqlQuerySpec.QueryText, out sqlQuery);
                        }

                        if (parsed)
                        {
                            bool hasDistinct            = sqlQuery.SelectClause.HasDistinct;
                            bool hasGroupBy             = sqlQuery.GroupByClause != default;
                            bool hasAggregates          = AggregateProjectionDetector.HasAggregate(sqlQuery.SelectClause.SelectSpec);
                            bool createPassthroughQuery = !hasAggregates && !hasDistinct && !hasGroupBy;

                            if (createPassthroughQuery)
                            {
                                TestInjections.ResponseStats responseStats = inputParameters?.TestInjections?.Stats;
                                if (responseStats != null)
                                {
                                    responseStats.PipelineType = TestInjections.PipelineType.Passthrough;
                                }

                                // Only thing that matters is that we target the correct range.
                                Documents.PartitionKeyDefinition   partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);
                                List <Documents.PartitionKeyRange> targetRanges           = await cosmosQueryContext.QueryClient.GetTargetPartitionKeyRangesByEpkStringAsync(
                                    cosmosQueryContext.ResourceLink,
                                    containerQueryProperties.ResourceId,
                                    inputParameters.PartitionKey.Value.InternalKey.GetEffectivePartitionKeyString(partitionKeyDefinition));

                                return(await CosmosQueryExecutionContextFactory.TryCreatePassthroughQueryExecutionContextAsync(
                                           cosmosQueryContext,
                                           inputParameters,
                                           partitionedQueryExecutionInfo : new PartitionedQueryExecutionInfo(),
                                           targetRanges,
                                           containerQueryProperties.ResourceId,
                                           cancellationToken));
                            }
                        }
                    }

                    if (cosmosQueryContext.QueryClient.ByPassQueryParsing())
                    {
                        // 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
                        partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanThroughGatewayAsync(
                            cosmosQueryContext,
                            inputParameters.SqlQuerySpec,
                            cosmosQueryContext.ResourceLink,
                            inputParameters.PartitionKey,
                            cancellationToken);
                    }
                    else
                    {
                        using (cosmosQueryContext.CreateDiagnosticScope("ServiceInterop"))
                        {
                            Documents.PartitionKeyDefinition partitionKeyDefinition = GetPartitionKeyDefinition(inputParameters, containerQueryProperties);

                            partitionedQueryExecutionInfo = await QueryPlanRetriever.GetQueryPlanWithServiceInteropAsync(
                                cosmosQueryContext.QueryClient,
                                inputParameters.SqlQuerySpec,
                                partitionKeyDefinition,
                                inputParameters.PartitionKey != null,
                                cancellationToken);
                        }
                    }
                }

                return(await TryCreateFromPartitionedQuerExecutionInfoAsync(
                           partitionedQueryExecutionInfo,
                           containerQueryProperties,
                           cosmosQueryContext,
                           inputParameters,
                           cancellationToken));
            }
        }
            public static TryCatch <DistinctMap> TryCreate(string continuationToken)
            {
                HashSet <Number64> numbers             = new HashSet <Number64>();
                HashSet <uint>     stringsLength4      = new HashSet <uint>();
                HashSet <ulong>    stringsLength8      = new HashSet <ulong>();
                HashSet <UInt128>  stringsLength16     = new HashSet <UInt128>();
                HashSet <UInt128>  stringsLength16Plus = new HashSet <UInt128>();
                HashSet <UInt128>  arrays       = new HashSet <UInt128>();
                HashSet <UInt128>  objects      = new HashSet <UInt128>();
                SimpleValues       simpleValues = SimpleValues.None;

                if (continuationToken != null)
                {
                    byte[]        binaryBuffer  = Convert.FromBase64String(continuationToken);
                    CosmosElement cosmosElement = CosmosElement.CreateFromBuffer(binaryBuffer);
                    if (!(cosmosElement is CosmosObject hashDictionary))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }

                    // Numbers
                    if (!hashDictionary.TryGetValue(UnorderdDistinctMap.NumbersName, out CosmosArray numbersArray))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }

                    foreach (CosmosElement rawNumber in numbersArray)
                    {
                        if (!(rawNumber is CosmosNumber64 number))
                        {
                            return(TryCatch <DistinctMap> .FromException(
                                       new MalformedContinuationTokenException(
                                           $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                        }

                        numbers.Add(number.GetValue());
                    }

                    // Strings Length 4
                    if (!hashDictionary.TryGetValue(UnorderdDistinctMap.StringsLength4Name, out CosmosArray stringsLength4Array))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }

                    foreach (CosmosElement rawStringLength4 in stringsLength4Array)
                    {
                        if (!(rawStringLength4 is CosmosUInt32 stringlength4))
                        {
                            return(TryCatch <DistinctMap> .FromException(
                                       new MalformedContinuationTokenException(
                                           $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                        }

                        stringsLength4.Add(stringlength4.GetValue());
                    }

                    // Strings Length 8
                    if (!hashDictionary.TryGetValue(UnorderdDistinctMap.StringsLength8Name, out CosmosArray stringsLength8Array))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }

                    foreach (CosmosElement rawStringLength8 in stringsLength8Array)
                    {
                        if (!(rawStringLength8 is CosmosInt64 stringlength8))
                        {
                            return(TryCatch <DistinctMap> .FromException(
                                       new MalformedContinuationTokenException(
                                           $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                        }

                        stringsLength8.Add((ulong)stringlength8.GetValue());
                    }

                    // Strings Length 16
                    stringsLength16 = Parse128BitHashes(hashDictionary, UnorderdDistinctMap.StringsLength16Name);

                    // Strings Length 24
                    stringsLength16Plus = Parse128BitHashes(hashDictionary, UnorderdDistinctMap.StringsLength16PlusName);

                    // Array
                    arrays = Parse128BitHashes(hashDictionary, UnorderdDistinctMap.ArraysName);

                    // Object
                    objects = Parse128BitHashes(hashDictionary, UnorderdDistinctMap.ObjectName);

                    // Simple Values
                    CosmosElement rawSimpleValues = hashDictionary[UnorderdDistinctMap.SimpleValuesName];
                    if (!(rawSimpleValues is CosmosString simpleValuesString))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }

                    if (!Enum.TryParse <SimpleValues>(simpleValuesString.Value, out simpleValues))
                    {
                        return(TryCatch <DistinctMap> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"{nameof(UnorderdDistinctMap)} continuation token was malformed.")));
                    }
                }

                return(TryCatch <DistinctMap> .FromResult(new UnorderdDistinctMap(
                                                              numbers,
                                                              stringsLength4,
                                                              stringsLength8,
                                                              stringsLength16,
                                                              stringsLength16Plus,
                                                              arrays,
                                                              objects,
                                                              simpleValues)));
            }
예제 #14
0
        /// <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
            }));
        }
예제 #15
0
        internal void SerializeAndDeserializeVertexDocumentTest(JsonSerializationFormat jsonSerializationFormat)
        {
            // Constants to use for vertex document property key/values
            const string idName             = "id";
            const string idValue            = "v_0";
            const string pkValue            = "pk_0";
            const string labelName          = "label";
            const string labelValue         = "l_0";
            const string boolName           = "myBool";
            const string boolId             = "3648bdcc-5113-43f8-86dd-c19fe793a2f8";
            const bool   boolValue          = true;
            const string intName            = "myInteger";
            const string intId              = "7546f541-a003-4e69-a25c-608372ed1321";
            const int    intValue           = 12345;
            const string longId             = "b119c62a-82a2-48b2-b293-9963fa99fbe2";
            const long   longValue          = 67890L;
            const string floatName          = "myFloatingPoint";
            const string floatId            = "98d27280-70ee-4edd-8461-7633a328539a";
            const float  floatValue         = 123.4f;
            const string doubleId           = "f9bfcc22-221a-4c92-b5b9-be53cdedb092";
            const double doubleValue        = 56.78;
            const string stringName         = "myString";
            const string stringId           = "6bb8ae5b-19ca-450e-b369-922a34c02729";
            const string stringValue        = "str_0";
            const string metaProperty0Name  = "myMetaProperty0";
            const string metaProperty0Value = "m_0";
            const string metaProperty1Name  = "myMetaProperty1";
            const int    metaProperty1Value = 123;

            // Compose the vertex document using eager CosmosElements
            Dictionary <string, CosmosElement> vertexDocumentProperties = new Dictionary <string, CosmosElement>()
            {
                { idName, CosmosString.Create(idValue) },
                { GremlinScenarioTests.PartitionKeyPropertyName, CosmosString.Create(pkValue) },
                { labelName, CosmosString.Create(labelValue) },
                {
                    boolName,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(boolId), CosmosBoolean.Create(boolValue)),
                    }
                        )
                },
                {
                    intName,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(intId), CosmosNumber64.Create(intValue)),
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(longId), CosmosNumber64.Create(longValue)),
                    }
                        )
                },
                {
                    floatName,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(floatId), CosmosNumber64.Create(floatValue)),
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(doubleId), CosmosNumber64.Create(doubleValue)),
                    }
                        )
                },
                {
                    stringName,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(
                            CosmosString.Create(stringId),
                            CosmosString.Create(stringValue),
                            Tuple.Create <string, CosmosElement>(metaProperty0Name, CosmosString.Create(metaProperty0Value)),
                            Tuple.Create <string, CosmosElement>(metaProperty1Name, CosmosNumber64.Create(metaProperty1Value))),
                    }
                        )
                },
            };

            CosmosObject vertexEagerObject = CosmosObject.Create(vertexDocumentProperties);

            // Serialize the vertex object into a document using the specified serialization format
            IJsonWriter jsonWriter = JsonWriter.Create(jsonSerializationFormat);

            vertexEagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> jsonResult = jsonWriter.GetResult();

            Assert.IsTrue(jsonResult.Length > 0, "IJsonWriter result data is empty.");

            // Navigate into the serialized vertex document using lazy CosmosElements
            CosmosElement rootLazyElement = CosmosElement.CreateFromBuffer(jsonResult);

            // Validate the expected vertex document structure/values

            // Root vertex document object
            CosmosObject vertexLazyObject = rootLazyElement as CosmosObject;

            Assert.IsNotNull(vertexLazyObject, $"Vertex document root is not {nameof(CosmosObject)}.");
            Assert.AreEqual(vertexDocumentProperties.Count, vertexLazyObject.Count);

            // Vertex system document properties
            CosmosString idLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, idName);

            Assert.AreEqual(idValue, idLazyString.Value);

            CosmosString pkLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, GremlinScenarioTests.PartitionKeyPropertyName);

            Assert.AreEqual(pkValue, pkLazyString.Value);

            CosmosString labelLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, labelName);

            Assert.AreEqual(labelValue, labelLazyString.Value);

            // Vertex user properties
            CosmosArray boolLazyArray = this.GetAndAssertObjectProperty <CosmosArray>(vertexLazyObject, boolName);

            Assert.AreEqual(1, boolLazyArray.Count);

            // Bool value(s)
            CosmosObject boolValue0LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(boolLazyArray, 0);
            CosmosString boolValue0IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(boolValue0LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(boolId, boolValue0IdLazyString.Value);
            CosmosBoolean boolValue0ValueLazyBool = this.GetAndAssertObjectProperty <CosmosBoolean>(boolValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(boolValue, boolValue0ValueLazyBool.Value);

            CosmosArray intLazyArray = this.GetAndAssertObjectProperty <CosmosArray>(vertexLazyObject, intName);

            Assert.AreEqual(2, intLazyArray.Count);

            // Integer value(s)
            CosmosObject intValue0LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(intLazyArray, 0);
            CosmosString intValue0IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(intValue0LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(intId, intValue0IdLazyString.Value);
            CosmosNumber intValue0ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(intValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(CosmosNumberType.Number64, intValue0ValueLazyNumber.NumberType);
            Assert.IsTrue(intValue0ValueLazyNumber.Value.IsInteger);
            Assert.AreEqual((long)intValue, intValue0ValueLazyNumber.Value);

            CosmosObject intValue1LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(intLazyArray, 1);
            CosmosString intValue1IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(intValue1LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(longId, intValue1IdLazyString.Value);
            CosmosNumber intValue1ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(intValue1LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(CosmosNumberType.Number64, intValue1ValueLazyNumber.NumberType);
            Assert.IsTrue(intValue1ValueLazyNumber.Value.IsInteger);
            Assert.AreEqual(longValue, intValue1ValueLazyNumber.Value);

            // Floating point value(s)
            CosmosArray floatLazyArray = this.GetAndAssertObjectProperty <CosmosArray>(vertexLazyObject, floatName);

            Assert.AreEqual(2, floatLazyArray.Count);

            CosmosObject floatValue0LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(floatLazyArray, 0);
            CosmosString floatValue0IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(floatValue0LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(floatId, floatValue0IdLazyString.Value);
            CosmosNumber floatValue0ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(floatValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(CosmosNumberType.Number64, floatValue0ValueLazyNumber.NumberType);
            Assert.IsTrue(floatValue0ValueLazyNumber.Value.IsDouble);
            Assert.AreEqual((double)floatValue, floatValue0ValueLazyNumber.Value);

            CosmosObject floatValue1LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(floatLazyArray, 1);
            CosmosString floatValue1IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(floatValue1LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(doubleId, floatValue1IdLazyString.Value);
            CosmosNumber floatValue1ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(floatValue1LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(CosmosNumberType.Number64, floatValue1ValueLazyNumber.NumberType);
            Assert.IsTrue(floatValue1ValueLazyNumber.Value.IsDouble);
            Assert.AreEqual(doubleValue, floatValue1ValueLazyNumber.Value);

            // String value(s)
            CosmosArray stringLazyArray = this.GetAndAssertObjectProperty <CosmosArray>(vertexLazyObject, stringName);

            Assert.AreEqual(1, stringLazyArray.Count);

            CosmosObject stringValue0LazyObject   = this.GetAndAssertArrayValue <CosmosObject>(stringLazyArray, 0);
            CosmosString stringValue0IdLazyString = this.GetAndAssertObjectProperty <CosmosString>(stringValue0LazyObject, GremlinKeywords.KW_PROPERTY_ID);

            Assert.AreEqual(stringId, stringValue0IdLazyString.Value);
            CosmosString stringValue0ValueLazyString = this.GetAndAssertObjectProperty <CosmosString>(stringValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE);

            Assert.AreEqual(stringValue, stringValue0ValueLazyString.Value);

            // String value meta-properties
            CosmosObject stringValue0MetaLazyObject = this.GetAndAssertObjectProperty <CosmosObject>(stringValue0LazyObject, GremlinKeywords.KW_PROPERTY_META);

            Assert.AreEqual(2, stringValue0MetaLazyObject.Count);

            CosmosString stringValue0MetaValue0LazyString = this.GetAndAssertObjectProperty <CosmosString>(stringValue0MetaLazyObject, metaProperty0Name);

            Assert.AreEqual(metaProperty0Value, stringValue0MetaValue0LazyString.Value);

            CosmosNumber stringValue0MetaValue1LazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(stringValue0MetaLazyObject, metaProperty1Name);

            Assert.AreEqual(CosmosNumberType.Number64, stringValue0MetaValue1LazyNumber.NumberType);
            Assert.IsTrue(stringValue0MetaValue1LazyNumber.Value.IsInteger);
            Assert.AreEqual((long)metaProperty1Value, stringValue0MetaValue1LazyNumber.Value);
        }
예제 #16
0
        public void Aggregate(CosmosElement localMinMax)
        {
            // If the value became undefinded at some point then it should stay that way.
            if (this.globalMinMax == Undefined)
            {
                return;
            }

            if (localMinMax == Undefined)
            {
                // If we got an undefined in the pipeline then the whole thing becomes undefined.
                this.globalMinMax = Undefined;
                return;
            }

            // Check to see if we got the higher precision result
            // and unwrap the object to get the actual item of interest
            if (localMinMax is CosmosObject cosmosObject)
            {
                if (cosmosObject["count"] is CosmosNumber countToken)
                {
                    // We know the object looks like: {"min": MIN(c.blah), "count": COUNT(c.blah)}
                    long count;
                    if (countToken.IsFloatingPoint)
                    {
                        count = (long)countToken.AsFloatingPoint().Value;
                    }
                    else
                    {
                        count = countToken.AsInteger().Value;
                    }

                    if (count == 0)
                    {
                        // Ignore the value since the continuation / partition had no results that matched the filter so min is undefined.
                        return;
                    }

                    CosmosElement min = cosmosObject["min"];
                    CosmosElement max = cosmosObject["max"];

                    // Note that JToken won't equal null as long as a value is there
                    // even if that value is a JSON null.
                    if (min != null)
                    {
                        localMinMax = min;
                    }
                    else if (max != null)
                    {
                        localMinMax = max;
                    }
                    else
                    {
                        localMinMax = Undefined;
                    }
                }
            }

            if (!ItemComparer.IsMinOrMax(this.globalMinMax) &&
                (!CosmosElementIsPrimitive(localMinMax) || !CosmosElementIsPrimitive(this.globalMinMax)))
            {
                // This means we are comparing non primitives with is undefined
                this.globalMinMax = Undefined;
                return;
            }

            // Finally do the comparision
            if (this.isMinAggregation)
            {
                if (ItemComparer.Instance.Compare(localMinMax, this.globalMinMax) < 0)
                {
                    this.globalMinMax = localMinMax;
                }
            }
            else
            {
                if (ItemComparer.Instance.Compare(localMinMax, this.globalMinMax) > 0)
                {
                    this.globalMinMax = localMinMax;
                }
            }
        }
예제 #17
0
        internal void DeserializeModifyAndSerializeVertexDocumentTest(JsonSerializationFormat jsonSerializationFormat)
        {
            // Constants to use for vertex document property key/values
            const string idName            = "id";
            const string idValue           = "v_0";
            const string pkValue           = "pk_0";
            const string labelName         = "label";
            const string labelValue        = "l_0";
            const string property1Name     = "p_0";
            const string property1Value1Id = "3648bdcc-5113-43f8-86dd-c19fe793a2f8";
            const string property1Value1   = "p_0_v_0";
            const string property1Value2Id = "7546f541-a003-4e69-a25c-608372ed1321";
            const long   property1Value2   = 1234;
            const string property2Name     = "p_1";
            const string property2Value1Id = "b119c62a-82a2-48b2-b293-9963fa99fbe2";
            const double property2Value1   = 34.56;
            const string property3Name     = "p_2";
            const string property3Value1Id = "98d27280-70ee-4edd-8461-7633a328539a";
            const bool   property3Value1   = true;
            const string property4Name     = "p_3";
            const string property4Value1Id = "f9bfcc22-221a-4c92-b5b9-be53cdedb092";
            const string property4Value1   = "p_3_v_0";

            // Compose the initial vertex document using eager CosmosElements
            Dictionary <string, CosmosElement> initialVertexDocumentProperties = new Dictionary <string, CosmosElement>()
            {
                { idName, CosmosString.Create(idValue) },
                { GremlinScenarioTests.PartitionKeyPropertyName, CosmosString.Create(pkValue) },
                { labelName, CosmosString.Create(labelValue) },
                {
                    property1Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property1Value1Id), CosmosString.Create(property1Value1)),
                    }
                        )
                },
                {
                    property2Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property2Value1Id), CosmosNumber64.Create(property2Value1)),
                    }
                        )
                },
                {
                    property3Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property3Value1Id), CosmosBoolean.Create(property3Value1)),
                    }
                        )
                },
            };

            CosmosObject initialVertexEagerObject = CosmosObject.Create(initialVertexDocumentProperties);

            // Serialize the initial vertex object into a document using the specified serialization format
            IJsonWriter jsonWriter = JsonWriter.Create(jsonSerializationFormat);

            initialVertexEagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> initialJsonWriterResult = jsonWriter.GetResult();

            Assert.IsTrue(initialJsonWriterResult.Length > 0, "IJsonWriter result data is empty.");

            // Navigate into the serialized vertex document using lazy CosmosElements
            CosmosElement rootLazyElement = CosmosElement.CreateFromBuffer(initialJsonWriterResult);

            // Root vertex document object
            CosmosObject vertexLazyObject = rootLazyElement as CosmosObject;

            Assert.IsNotNull(vertexLazyObject, $"Vertex document root is not {nameof(CosmosObject)}.");
            Assert.AreEqual(initialVertexDocumentProperties.Count, vertexLazyObject.Count);

            CosmosString idLazyString    = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, idName);
            CosmosString pkLazyString    = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, GremlinScenarioTests.PartitionKeyPropertyName);
            CosmosString labelLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, labelName);
            CosmosArray  property2Array  = this.GetAndAssertObjectProperty <CosmosArray>(vertexLazyObject, property2Name);

            // Compose a new vertex document using a combination of lazy and eager CosmosElements
            Dictionary <string, CosmosElement> modifiedVertexDocumentProperties = new Dictionary <string, CosmosElement>()
            {
                { idName, idLazyString },
                { GremlinScenarioTests.PartitionKeyPropertyName, pkLazyString },
                { labelName, labelLazyString },

                // Property 1 is modified with a new value
                {
                    property1Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property1Value2Id), CosmosNumber64.Create(property1Value2)),
                    }
                        )
                },

                // Property 2 is unmodified
                { property2Name, property2Array },

                // Property 3 is deleted

                // Property 4 is newly added
                {
                    property4Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property4Value1Id), CosmosString.Create(property4Value1)),
                    }
                        )
                },
            };

            CosmosObject modifiedVertexEagerObject = CosmosObject.Create(modifiedVertexDocumentProperties);

            // Serialize the modified vertex object into a document using the specified serialization format
            jsonWriter = JsonWriter.Create(jsonSerializationFormat);
            modifiedVertexEagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> modifiedJsonWriterResult = jsonWriter.GetResult();

            Assert.IsTrue(modifiedJsonWriterResult.Length > 0, "IJsonWriter result data is empty.");

            // Compose an expected vertex document using eager CosmosElements
            Dictionary <string, CosmosElement> expectedVertexDocumentProperties = new Dictionary <string, CosmosElement>()
            {
                { idName, CosmosString.Create(idValue) },
                { GremlinScenarioTests.PartitionKeyPropertyName, CosmosString.Create(pkValue) },
                { labelName, CosmosString.Create(labelValue) },
                {
                    property1Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property1Value2Id), CosmosNumber64.Create(property1Value2)),
                    }
                        )
                },
                {
                    property2Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property2Value1Id), CosmosNumber64.Create(property2Value1)),
                    }
                        )
                },
                {
                    property4Name,
                    CosmosArray.Create(
                        new CosmosElement[]
                    {
                        this.CreateVertexPropertySingleComplexValue(CosmosString.Create(property4Value1Id), CosmosString.Create(property4Value1)),
                    }
                        )
                },
            };

            CosmosObject expectedVertexEagerObject = CosmosObject.Create(expectedVertexDocumentProperties);

            // Serialize the initial vertex object into a document using the specified serialization format
            jsonWriter = JsonWriter.Create(jsonSerializationFormat);
            expectedVertexEagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> expectedJsonWriterResult = jsonWriter.GetResult();

            Assert.IsTrue(expectedJsonWriterResult.Length > 0, "IJsonWriter result data is empty.");

            // Verify that the modified serialized document matches the expected serialized document
            Assert.IsTrue(modifiedJsonWriterResult.Span.SequenceEqual(expectedJsonWriterResult.Span));
        }
예제 #18
0
        public ReadFeedIteratorCore(
            IDocumentContainer documentContainer,
            QueryRequestOptions queryRequestOptions,
            string continuationToken,
            int pageSize,
            CancellationToken cancellationToken)
        {
            this.queryRequestOptions = queryRequestOptions;

            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(queryRequestOptions.PartitionKey.Value);
                }
                else if ((this.queryRequestOptions != null) && (queryRequestOptions.FeedRange != null))
                {
                    feedRange = 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,
                        queryRequestOptions,
                        new CrossFeedRangeState <ReadFeedState>(monadicReadFeedState.Result.FeedRangeStates),
                        pageSize,
                        cancellationToken));
            }

            this.hasMoreResults = true;
        }
 /// <summary>
 /// Adds a JToken to this DistinctMap.
 /// </summary>
 /// <param name="cosmosElement">The element to add.</param>
 /// <param name="hash">The hash of the cosmos element</param>
 /// <returns>Whether or not the token was successfully added.</returns>
 public abstract bool Add(CosmosElement cosmosElement, out UInt128 hash);
        public static QueryIterator Create(
            CosmosQueryClient client,
            CosmosClientContext clientContext,
            SqlQuerySpec sqlQuerySpec,
            string continuationToken,
            QueryRequestOptions queryRequestOptions,
            Uri resourceLink,
            bool isContinuationExpected,
            bool allowNonValueAggregateQuery,
            PartitionedQueryExecutionInfo partitionedQueryExecutionInfo)
        {
            if (queryRequestOptions == null)
            {
                queryRequestOptions = new QueryRequestOptions();
            }

            CosmosDiagnosticsContext queryPipelineCreationDiagnostics = CosmosDiagnosticsContext.Create(queryRequestOptions);

            CosmosQueryContextCore cosmosQueryContext = new CosmosQueryContextCore(
                client: client,
                queryRequestOptions: queryRequestOptions,
                resourceTypeEnum: Documents.ResourceType.Document,
                operationType: Documents.OperationType.Query,
                resourceType: typeof(QueryResponseCore),
                resourceLink: resourceLink,
                isContinuationExpected: isContinuationExpected,
                allowNonValueAggregateQuery: allowNonValueAggregateQuery,
                diagnosticsContext: queryPipelineCreationDiagnostics,
                correlatedActivityId: Guid.NewGuid());

            CosmosElement requestContinuationToken;

            switch (queryRequestOptions.ExecutionEnvironment.GetValueOrDefault(ExecutionEnvironment.Client))
            {
            case ExecutionEnvironment.Client:
                if (continuationToken != null)
                {
                    if (!CosmosElement.TryParse(continuationToken, out requestContinuationToken))
                    {
                        return(new QueryIterator(
                                   cosmosQueryContext,
                                   new QueryExecutionContextWithException(
                                       new MalformedContinuationTokenException(
                                           $"Malformed Continuation Token: {continuationToken}")),
                                   queryRequestOptions.CosmosSerializationFormatOptions,
                                   queryRequestOptions,
                                   clientContext));
                    }
                }
                else
                {
                    requestContinuationToken = null;
                }
                break;

            case ExecutionEnvironment.Compute:
                requestContinuationToken = queryRequestOptions.CosmosElementContinuationToken;
                break;

            default:
                throw new ArgumentOutOfRangeException($"Unknown {nameof(ExecutionEnvironment)}: {queryRequestOptions.ExecutionEnvironment.Value}.");
            }

            CosmosQueryExecutionContextFactory.InputParameters inputParameters = new CosmosQueryExecutionContextFactory.InputParameters(
                sqlQuerySpec: sqlQuerySpec,
                initialUserContinuationToken: requestContinuationToken,
                maxConcurrency: queryRequestOptions.MaxConcurrency,
                maxItemCount: queryRequestOptions.MaxItemCount,
                maxBufferedItemCount: queryRequestOptions.MaxBufferedItemCount,
                partitionKey: queryRequestOptions.PartitionKey,
                properties: queryRequestOptions.Properties,
                partitionedQueryExecutionInfo: partitionedQueryExecutionInfo,
                executionEnvironment: queryRequestOptions.ExecutionEnvironment,
                returnResultsInDeterministicOrder: queryRequestOptions.ReturnResultsInDeterministicOrder,
                testInjections: queryRequestOptions.TestSettings);

            return(new QueryIterator(
                       cosmosQueryContext,
                       CosmosQueryExecutionContextFactory.Create(cosmosQueryContext, inputParameters),
                       queryRequestOptions.CosmosSerializationFormatOptions,
                       queryRequestOptions,
                       clientContext));
        }
예제 #21
0
        private DocumentFeedResponse <CosmosElement> GetFeedResponse(
            DocumentServiceRequest documentServiceRequest,
            DocumentServiceResponse documentServiceResponse)
        {
            // Execute the callback an each element of the page
            // For example just could get a response like this
            // {
            //    "_rid": "qHVdAImeKAQ=",
            //    "Documents": [{
            //        "id": "03230",
            //        "_rid": "qHVdAImeKAQBAAAAAAAAAA==",
            //        "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/",
            //        "_etag": "\"410000b0-0000-0000-0000-597916b00000\"",
            //        "_attachments": "attachments\/",
            //        "_ts": 1501107886
            //    }],
            //    "_count": 1
            // }
            // And you should execute the callback on each document in "Documents".
            MemoryStream memoryStream = new MemoryStream();

            documentServiceResponse.ResponseBody.CopyTo(memoryStream);
            long responseLengthBytes = memoryStream.Length;

            ReadOnlyMemory <byte> content;

            if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer))
            {
                content = buffer;
            }
            else
            {
                content = memoryStream.ToArray();
            }

            IJsonNavigator jsonNavigator = null;

            // Use the users custom navigator first. If it returns null back try the
            // internal navigator.
            if (this.feedOptions.CosmosSerializationFormatOptions != null)
            {
                jsonNavigator = this.feedOptions.CosmosSerializationFormatOptions.CreateCustomNavigatorCallback(content);
                if (jsonNavigator == null)
                {
                    throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator.");
                }
            }
            else
            {
                jsonNavigator = JsonNavigator.Create(content);
            }

            string resourceName = this.GetRootNodeName(documentServiceRequest.ResourceType);

            if (!jsonNavigator.TryGetObjectProperty(
                    jsonNavigator.GetRootNode(),
                    resourceName,
                    out ObjectProperty objectProperty))
            {
                throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}");
            }

            IJsonNavigatorNode cosmosElements = objectProperty.ValueNode;

            if (!(CosmosElement.Dispatch(
                      jsonNavigator,
                      cosmosElements) is CosmosArray cosmosArray))
            {
                throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}");
            }

            int itemCount = cosmosArray.Count;

            return(new DocumentFeedResponse <CosmosElement>(
                       cosmosArray,
                       itemCount,
                       documentServiceResponse.Headers,
                       documentServiceResponse.RequestStats,
                       responseLengthBytes));
        }
예제 #22
0
 private PartitionKey CosmosElementToPartitionKeyObject(CosmosElement cosmosElement) => cosmosElement switch
 {
예제 #23
0
        /// <summary>
        /// Converts a list of CosmosElements into a memory stream.
        /// </summary>
        /// <param name="memoryStream">The memory stream response for the query REST response Azure Cosmos</param>
        /// <param name="resourceType">The resource type</param>
        /// <param name="cosmosSerializationOptions">The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats</param>
        /// <returns>An array of CosmosElements parsed from the response body.</returns>
        private static CosmosArray ParseElementsFromRestStream(
            MemoryStream memoryStream,
            ResourceType resourceType,
            CosmosSerializationFormatOptions cosmosSerializationOptions)
        {
            if (!memoryStream.CanRead)
            {
                throw new InvalidDataException("Stream can not be read");
            }

            // Parse out the document from the REST response this:
            // {
            //    "_rid": "qHVdAImeKAQ=",
            //    "Documents": [{
            //        "id": "03230",
            //        "_rid": "qHVdAImeKAQBAAAAAAAAAA==",
            //        "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/",
            //        "_etag": "\"410000b0-0000-0000-0000-597916b00000\"",
            //        "_attachments": "attachments\/",
            //        "_ts": 1501107886
            //    }],
            //    "_count": 1
            // }
            // You want to create a CosmosElement for each document in "Documents".

            ReadOnlyMemory <byte> content;

            if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer))
            {
                content = buffer;
            }
            else
            {
                content = memoryStream.ToArray();
            }

            IJsonNavigator jsonNavigator;

            if (cosmosSerializationOptions != null)
            {
                // Use the users custom navigator
                jsonNavigator = cosmosSerializationOptions.CreateCustomNavigatorCallback(content);
                if (jsonNavigator == null)
                {
                    throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator.");
                }
            }
            else
            {
                jsonNavigator = JsonNavigator.Create(content);
            }

            string resourceName = resourceType switch
            {
                ResourceType.Collection => "DocumentCollections",
                _ => resourceType.ToResourceTypeString() + "s",
            };

            CosmosArray documents;

            if ((jsonNavigator.SerializationFormat == JsonSerializationFormat.Binary) && jsonNavigator.TryGetObjectProperty(
                    jsonNavigator.GetRootNode(),
                    "stringDictionary",
                    out ObjectProperty stringDictionaryProperty))
            {
                // Payload is string dictionary encode so we have to decode using the string dictionary.
                IJsonNavigatorNode   stringDictionaryNode = stringDictionaryProperty.ValueNode;
                JsonStringDictionary jsonStringDictionary = JsonStringDictionary.CreateFromStringArray(
                    jsonNavigator
                    .GetArrayItems(stringDictionaryNode)
                    .Select(item => jsonNavigator.GetStringValue(item))
                    .ToList());

                if (!jsonNavigator.TryGetObjectProperty(
                        jsonNavigator.GetRootNode(),
                        resourceName,
                        out ObjectProperty resourceProperty))
                {
                    throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}");
                }

                IJsonNavigatorNode resources = resourceProperty.ValueNode;
                if (!jsonNavigator.TryGetBufferedBinaryValue(resources, out ReadOnlyMemory <byte> resourceBinary))
                {
                    resourceBinary = jsonNavigator.GetBinaryValue(resources);
                }

                IJsonNavigator navigatorWithStringDictionary = JsonNavigator.Create(resourceBinary, jsonStringDictionary);

                if (!(CosmosElement.Dispatch(
                          navigatorWithStringDictionary,
                          navigatorWithStringDictionary.GetRootNode()) is CosmosArray cosmosArray))
                {
                    throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}");
                }

                documents = cosmosArray;
            }
            else
            {
                // Payload is not string dictionary encoded so we can just do for the documents as is.
                if (!jsonNavigator.TryGetObjectProperty(
                        jsonNavigator.GetRootNode(),
                        resourceName,
                        out ObjectProperty objectProperty))
                {
                    throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}");
                }

                if (!(CosmosElement.Dispatch(
                          jsonNavigator,
                          objectProperty.ValueNode) is CosmosArray cosmosArray))
                {
                    throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}");
                }

                documents = cosmosArray;
            }

            return(documents);
        }
        /// <summary>
        /// Converts a list of CosmosElements into a memory stream.
        /// </summary>
        /// <param name="stream">The memory stream response for the query REST response Azure Cosmos</param>
        /// <param name="resourceType">The resource type</param>
        /// <param name="cosmosSerializationOptions">The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats</param>
        /// <returns>An array of CosmosElements parsed from the response body.</returns>
        public static CosmosArray ParseElementsFromRestStream(
            Stream stream,
            ResourceType resourceType,
            CosmosSerializationFormatOptions cosmosSerializationOptions)
        {
            if (!(stream is MemoryStream memoryStream))
            {
                memoryStream = new MemoryStream();
                stream.CopyTo(memoryStream);
            }

            if (!memoryStream.CanRead)
            {
                throw new InvalidDataException("Stream can not be read");
            }

            // Parse out the document from the REST response like this:
            // {
            //    "_rid": "qHVdAImeKAQ=",
            //    "Documents": [{
            //        "id": "03230",
            //        "_rid": "qHVdAImeKAQBAAAAAAAAAA==",
            //        "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/",
            //        "_etag": "\"410000b0-0000-0000-0000-597916b00000\"",
            //        "_attachments": "attachments\/",
            //        "_ts": 1501107886
            //    }],
            //    "_count": 1
            // }
            // You want to create a CosmosElement for each document in "Documents".

            ReadOnlyMemory <byte> content = memoryStream.TryGetBuffer(out ArraySegment <byte> buffer) ? buffer : (ReadOnlyMemory <byte>)memoryStream.ToArray();
            IJsonNavigator        jsonNavigator;

            if (cosmosSerializationOptions != null)
            {
                // Use the users custom navigator
                jsonNavigator = cosmosSerializationOptions.CreateCustomNavigatorCallback(content);
                if (jsonNavigator == null)
                {
                    throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator.");
                }
            }
            else
            {
                jsonNavigator = JsonNavigator.Create(content);
            }

            string resourceName = resourceType switch
            {
                ResourceType.Collection => "DocumentCollections",
                _ => resourceType.ToResourceTypeString() + "s",
            };

            if (!jsonNavigator.TryGetObjectProperty(
                    jsonNavigator.GetRootNode(),
                    resourceName,
                    out ObjectProperty objectProperty))
            {
                throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}");
            }

            if (!(CosmosElement.Dispatch(
                      jsonNavigator,
                      objectProperty.ValueNode) is CosmosArray cosmosArray))
            {
                throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}");
            }

            return(cosmosArray);
        }
예제 #25
0
        private QueryResponse GetCosmosElementResponse(
            QueryRequestOptions requestOptions,
            ResourceType resourceType,
            CosmosResponseMessage cosmosResponseMessage)
        {
            using (cosmosResponseMessage)
            {
                if (!cosmosResponseMessage.IsSuccessStatusCode)
                {
                    return(QueryResponse.CreateFailure(
                               CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders(cosmosResponseMessage.Headers),
                               cosmosResponseMessage.StatusCode,
                               cosmosResponseMessage.RequestMessage,
                               cosmosResponseMessage.ErrorMessage,
                               cosmosResponseMessage.Error));
                }

                // Execute the callback an each element of the page
                // For example just could get a response like this
                // {
                //    "_rid": "qHVdAImeKAQ=",
                //    "Documents": [{
                //        "id": "03230",
                //        "_rid": "qHVdAImeKAQBAAAAAAAAAA==",
                //        "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/",
                //        "_etag": "\"410000b0-0000-0000-0000-597916b00000\"",
                //        "_attachments": "attachments\/",
                //        "_ts": 1501107886
                //    }],
                //    "_count": 1
                // }
                // And you should execute the callback on each document in "Documents".
                MemoryStream memoryStream = new MemoryStream();
                cosmosResponseMessage.Content.CopyTo(memoryStream);
                long           responseLengthBytes = memoryStream.Length;
                byte[]         content             = memoryStream.ToArray();
                IJsonNavigator jsonNavigator       = null;

                // Use the users custom navigator
                if (requestOptions.CosmosSerializationOptions != null)
                {
                    jsonNavigator = requestOptions.CosmosSerializationOptions.CreateCustomNavigatorCallback(content);
                    if (jsonNavigator == null)
                    {
                        throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator.");
                    }
                }
                else
                {
                    jsonNavigator = JsonNavigator.Create(content);
                }

                string resourceName = this.GetRootNodeName(resourceType);

                if (!jsonNavigator.TryGetObjectProperty(
                        jsonNavigator.GetRootNode(),
                        resourceName,
                        out ObjectProperty objectProperty))
                {
                    throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}");
                }

                IJsonNavigatorNode cosmosElements = objectProperty.ValueNode;
                if (!(CosmosElement.Dispatch(
                          jsonNavigator,
                          cosmosElements) is CosmosArray cosmosArray))
                {
                    throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}");
                }

                int itemCount = cosmosArray.Count;
                return(QueryResponse.CreateSuccess(
                           result: cosmosArray,
                           count: itemCount,
                           responseHeaders: CosmosQueryResponseMessageHeaders.ConvertToQueryHeaders(cosmosResponseMessage.Headers),
                           responseLengthBytes: responseLengthBytes));
            }
        }
예제 #26
0
            public static TryCatch <FeedRangeState <ReadFeedState> > CreateFromCosmosElement(CosmosElement cosmosElement)
            {
                if (cosmosElement == null)
                {
                    throw new ArgumentNullException(nameof(cosmosElement));
                }

                if (!(cosmosElement is CosmosObject cosmosObject))
                {
                    return(TryCatch <FeedRangeState <ReadFeedState> > .FromException(
                               new FormatException(
                                   $"Expected object for ChangeFeed Continuation: {cosmosElement}.")));
                }

                if (!cosmosObject.TryGetValue(PropertyNames.FeedRange, out CosmosElement feedRangeCosmosElement))
                {
                    return(TryCatch <FeedRangeState <ReadFeedState> > .FromException(
                               new FormatException(
                                   $"Expected '{PropertyNames.FeedRange}' for '{nameof(FeedRangeState<ReadFeedState>)}': {cosmosElement}.")));
                }

                if (!cosmosObject.TryGetValue(PropertyNames.State, out CosmosElement stateCosmosElement))
                {
                    return(TryCatch <FeedRangeState <ReadFeedState> > .FromException(
                               new FormatException(
                                   $"Expected '{PropertyNames.State}' for '{nameof(FeedRangeState<ReadFeedState>)}': {cosmosElement}.")));
                }

                TryCatch <FeedRangeInternal> monadicFeedRange = FeedRangeCosmosElementSerializer.MonadicCreateFromCosmosElement(feedRangeCosmosElement);

                if (monadicFeedRange.Failed)
                {
                    return(TryCatch <FeedRangeState <ReadFeedState> > .FromException(
                               new FormatException(
                                   $"Failed to parse '{PropertyNames.FeedRange}' for '{nameof(FeedRangeState<ReadFeedState>)}': {cosmosElement}.",
                                   innerException : monadicFeedRange.Exception)));
                }

                ReadFeedState readFeedState;

                if (stateCosmosElement is CosmosNull)
                {
                    readFeedState = ReadFeedState.Beginning();
                }
                else
                {
                    readFeedState = ReadFeedState.Continuation(stateCosmosElement);
                }

                return(TryCatch <FeedRangeState <ReadFeedState> > .FromResult(
                           new FeedRangeState <ReadFeedState>(
                               monadicFeedRange.Result,
                               readFeedState)));
            }
            public static TryCatch <IQueryPipelineStage> MonadicCreateLimitStage(
                int limitCount,
                CosmosElement requestContinuationToken,
                CancellationToken cancellationToken,
                MonadicCreatePipelineStage monadicCreatePipelineStage)
            {
                if (limitCount < 0)
                {
                    throw new ArgumentException($"{nameof(limitCount)}: {limitCount} must be a non negative number.");
                }

                if (monadicCreatePipelineStage == null)
                {
                    throw new ArgumentNullException(nameof(monadicCreatePipelineStage));
                }

                LimitContinuationToken limitContinuationToken;

                if (requestContinuationToken != null)
                {
                    if (!LimitContinuationToken.TryParse(requestContinuationToken.ToString(), out limitContinuationToken))
                    {
                        return(TryCatch <IQueryPipelineStage> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Malformed {nameof(LimitContinuationToken)}: {requestContinuationToken}.")));
                    }
                }
                else
                {
                    limitContinuationToken = new LimitContinuationToken(limitCount, null);
                }

                if (limitContinuationToken.Limit > limitCount)
                {
                    return(TryCatch <IQueryPipelineStage> .FromException(
                               new MalformedContinuationTokenException(
                                   $"{nameof(LimitContinuationToken.Limit)} in {nameof(LimitContinuationToken)}: {requestContinuationToken}: {limitContinuationToken.Limit} can not be greater than the limit count in the query: {limitCount}.")));
                }

                CosmosElement sourceToken;

                if (limitContinuationToken.SourceToken != null)
                {
                    TryCatch <CosmosElement> tryParse = CosmosElement.Monadic.Parse(limitContinuationToken.SourceToken);
                    if (tryParse.Failed)
                    {
                        return(TryCatch <IQueryPipelineStage> .FromException(
                                   new MalformedContinuationTokenException(
                                       message : $"Malformed {nameof(LimitContinuationToken)}: {requestContinuationToken}.",
                                       innerException : tryParse.Exception)));
                    }

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

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

                if (tryCreateSource.Failed)
                {
                    return(tryCreateSource);
                }

                IQueryPipelineStage stage = new ClientTakeQueryPipelineStage(
                    tryCreateSource.Result,
                    cancellationToken,
                    limitContinuationToken.Limit,
                    TakeEnum.Limit);

                return(TryCatch <IQueryPipelineStage> .FromResult(stage));
            }
예제 #28
0
        internal void SerializeAndDeserializeEdgeDocumentTest(JsonSerializationFormat jsonSerializationFormat)
        {
            // Constants to use for vertex document property key/values
            const string idName                = "id";
            const string idValue               = "e_0";
            const string pkValue               = "pk_0";
            const string labelName             = "label";
            const string labelValue            = "l_0";
            const string vertexIdValue         = "v_0";
            const string vertexLabelValue      = "l_1";
            const string sinkIdValue           = "v_1";
            const string sinkLabelValue        = "l_2";
            const string sinkPartitionValue    = "pk_1";
            const bool   isEdgeValue           = true;
            const bool   isPkEdgePropertyValue = true;
            const string boolName              = "myBool";
            const bool   boolValue             = true;
            const string intName               = "myInteger";
            const int    intValue              = 12345;
            const string longName              = "myLong";
            const long   longValue             = 67890L;
            const string floatName             = "myFloatingPoint";
            const float  floatValue            = 123.4f;
            const string doubleName            = "myDouble";
            const double doubleValue           = 56.78;
            const string stringName            = "myString";
            const string stringValue           = "str_0";

            Dictionary <string, CosmosElement> edgeDocumentProperties = new Dictionary <string, CosmosElement>()
            {
                { idName, CosmosString.Create(idValue) },
                { GremlinScenarioTests.PartitionKeyPropertyName, CosmosString.Create(pkValue) },
                { labelName, CosmosString.Create(labelValue) },
                { GremlinKeywords.KW_EDGEDOC_VERTEXID, CosmosString.Create(vertexIdValue) },
                { GremlinKeywords.KW_EDGEDOC_VERTEXLABEL, CosmosString.Create(vertexLabelValue) },
                { GremlinKeywords.KW_EDGE_SINKV, CosmosString.Create(sinkIdValue) },
                { GremlinKeywords.KW_EDGE_SINKV_LABEL, CosmosString.Create(sinkLabelValue) },
                { GremlinKeywords.KW_EDGE_SINKV_PARTITION, CosmosString.Create(sinkPartitionValue) },
                { GremlinKeywords.KW_EDGEDOC_IDENTIFIER, CosmosBoolean.Create(isEdgeValue) },
                { GremlinKeywords.KW_EDGEDOC_ISPKPROPERTY, CosmosBoolean.Create(isPkEdgePropertyValue) },
                { boolName, CosmosBoolean.Create(boolValue) },
                { intName, CosmosNumber64.Create(intValue) },
                { longName, CosmosNumber64.Create(longValue) },
                { floatName, CosmosNumber64.Create(floatValue) },
                { doubleName, CosmosNumber64.Create(doubleValue) },
                { stringName, CosmosString.Create(stringValue) },
            };

            CosmosObject edgeEagerObject = CosmosObject.Create(edgeDocumentProperties);

            // Serialize the edge object into a document using the specified serialization format
            IJsonWriter jsonWriter = JsonWriter.Create(jsonSerializationFormat);

            edgeEagerObject.WriteTo(jsonWriter);
            ReadOnlyMemory <byte> jsonResult = jsonWriter.GetResult();

            Assert.IsTrue(jsonResult.Length > 0, "IJsonWriter result data is empty.");

            // Navigate into the serialized edge document using lazy CosmosElements
            CosmosElement rootLazyElement = CosmosElement.CreateFromBuffer(jsonResult);

            // Validate the expected edge document structure/values

            // Root edge document object
            CosmosObject edgeLazyObject = rootLazyElement as CosmosObject;

            Assert.IsNotNull(edgeLazyObject, $"Edge document root is not {nameof(CosmosObject)}.");
            Assert.AreEqual(edgeDocumentProperties.Count, edgeLazyObject.Count);

            // Edge system document properties
            CosmosString idLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, idName);

            Assert.AreEqual(idValue, idLazyString.Value);

            CosmosString pkLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinScenarioTests.PartitionKeyPropertyName);

            Assert.AreEqual(pkValue, pkLazyString.Value);

            CosmosString labelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, labelName);

            Assert.AreEqual(labelValue, labelLazyString.Value);

            CosmosString vertexIdLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_VERTEXID);

            Assert.AreEqual(vertexIdValue, vertexIdLazyString.Value);

            CosmosString vertexLabelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_VERTEXLABEL);

            Assert.AreEqual(vertexLabelValue, vertexLabelLazyString.Value);

            CosmosString sinkIdLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV);

            Assert.AreEqual(sinkIdValue, sinkIdLazyString.Value);

            CosmosString sinkLabelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV_LABEL);

            Assert.AreEqual(sinkLabelValue, sinkLabelLazyString.Value);

            CosmosString sinkPartitionLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV_PARTITION);

            Assert.AreEqual(sinkPartitionValue, sinkPartitionLazyString.Value);

            CosmosBoolean isEdgeLazyBool = this.GetAndAssertObjectProperty <CosmosBoolean>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_IDENTIFIER);

            Assert.AreEqual(isEdgeValue, isEdgeLazyBool.Value);

            CosmosBoolean isPkEdgePropertyLazyBool = this.GetAndAssertObjectProperty <CosmosBoolean>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_ISPKPROPERTY);

            Assert.AreEqual(isPkEdgePropertyValue, isPkEdgePropertyLazyBool.Value);

            // Edge user properties

            CosmosBoolean boolValueLazyBool = this.GetAndAssertObjectProperty <CosmosBoolean>(edgeLazyObject, boolName);

            Assert.AreEqual(boolValue, boolValueLazyBool.Value);

            CosmosNumber intValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, intName);

            Assert.AreEqual(CosmosNumberType.Number64, intValueLazyNumber.NumberType);
            Assert.IsTrue(intValueLazyNumber.Value.IsInteger);
            Assert.AreEqual((long)intValue, intValueLazyNumber.Value);

            CosmosNumber longValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, longName);

            Assert.AreEqual(CosmosNumberType.Number64, intValueLazyNumber.NumberType);
            Assert.IsTrue(intValueLazyNumber.Value.IsInteger);
            Assert.AreEqual(longValue, longValueLazyNumber.Value);

            CosmosNumber floatValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, floatName);

            Assert.AreEqual(CosmosNumberType.Number64, floatValueLazyNumber.NumberType);
            Assert.IsTrue(floatValueLazyNumber.Value.IsDouble);
            Assert.AreEqual((double)floatValue, floatValueLazyNumber.Value);

            CosmosNumber doubleValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, doubleName);

            Assert.AreEqual(CosmosNumberType.Number64, doubleValueLazyNumber.NumberType);
            Assert.IsTrue(doubleValueLazyNumber.Value.IsDouble);
            Assert.AreEqual((double)doubleValue, doubleValueLazyNumber.Value);

            CosmosString stringValueLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, stringName);

            Assert.AreEqual(stringValue, stringValueLazyString.Value);
        }
예제 #29
0
        public void Aggregate(CosmosElement localMinMax)
        {
            // If the value became undefinded at some point then it should stay that way.
            if (this.globalMinMax == Undefined)
            {
                return;
            }

            if (localMinMax == Undefined)
            {
                // If we got an undefined in the pipeline then the whole thing becomes undefined.
                this.globalMinMax = Undefined;
                return;
            }

            // Check to see if we got the higher precision result
            // and unwrap the object to get the actual item of interest
            if (localMinMax is CosmosObject cosmosObject)
            {
                if (cosmosObject.TryGetValue("count", out CosmosNumber countToken))
                {
                    // We know the object looks like: {"min": MIN(c.blah), "count": COUNT(c.blah)}
                    long count = Number64.ToLong(countToken.Value);
                    if (count == 0)
                    {
                        // Ignore the value since the continuation / partition had no results that matched the filter so min is undefined.
                        return;
                    }

                    if (!cosmosObject.TryGetValue("min", out CosmosElement min))
                    {
                        min = null;
                    }

                    if (!cosmosObject.TryGetValue("max", out CosmosElement max))
                    {
                        max = null;
                    }

                    if (min != null)
                    {
                        localMinMax = min;
                    }
                    else if (max != null)
                    {
                        localMinMax = max;
                    }
                    else
                    {
                        localMinMax = Undefined;
                    }
                }
            }

            if (!ItemComparer.IsMinOrMax(this.globalMinMax) &&
                (!CosmosElementIsPrimitive(localMinMax) || !CosmosElementIsPrimitive(this.globalMinMax)))
            {
                // This means we are comparing non primitives which is undefined
                this.globalMinMax = Undefined;
                return;
            }

            // Finally do the comparision
            if (this.isMinAggregation)
            {
                if (ItemComparer.Instance.Compare(localMinMax, this.globalMinMax) < 0)
                {
                    this.globalMinMax = localMinMax;
                }
            }
            else
            {
                if (ItemComparer.Instance.Compare(localMinMax, this.globalMinMax) > 0)
                {
                    this.globalMinMax = localMinMax;
                }
            }
        }
예제 #30
0
 private static Task <TryCatch <IDocumentQueryExecutionComponent> > CreateSource(CosmosElement continuationToken)
 {
     return(Task.FromResult(TryCatch <IDocumentQueryExecutionComponent> .FromResult(new Mock <IDocumentQueryExecutionComponent>().Object)));
 }