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.ToString()); CosmosString pkLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, GremlinScenarioTests.PartitionKeyPropertyName); Assert.AreEqual(pkValue, pkLazyString.Value.ToString()); CosmosString labelLazyString = this.GetAndAssertObjectProperty <CosmosString>(vertexLazyObject, labelName); Assert.AreEqual(labelValue, labelLazyString.Value.ToString()); // 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.ToString()); 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.ToString()); CosmosNumber intValue0ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(intValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE); Assert.IsTrue(intValue0ValueLazyNumber is CosmosNumber64); 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.ToString()); CosmosNumber intValue1ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(intValue1LazyObject, GremlinKeywords.KW_PROPERTY_VALUE); Assert.IsTrue(intValue1ValueLazyNumber is CosmosNumber64); 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.ToString()); CosmosNumber floatValue0ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(floatValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE); Assert.IsTrue(floatValue0ValueLazyNumber is CosmosNumber64); 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.ToString()); CosmosNumber floatValue1ValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(floatValue1LazyObject, GremlinKeywords.KW_PROPERTY_VALUE); Assert.IsTrue(floatValue1ValueLazyNumber is CosmosNumber64); 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.ToString()); CosmosString stringValue0ValueLazyString = this.GetAndAssertObjectProperty <CosmosString>(stringValue0LazyObject, GremlinKeywords.KW_PROPERTY_VALUE); Assert.AreEqual(stringValue, stringValue0ValueLazyString.Value.ToString()); // 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.ToString()); CosmosNumber stringValue0MetaValue1LazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(stringValue0MetaLazyObject, metaProperty1Name); Assert.IsTrue(stringValue0MetaValue1LazyNumber is CosmosNumber64); Assert.IsTrue(stringValue0MetaValue1LazyNumber.Value.IsInteger); Assert.AreEqual((long)metaProperty1Value, stringValue0MetaValue1LazyNumber.Value); }
public Task <TryCatch <Record> > MonadicCreateItemAsync( CosmosObject payload, CancellationToken cancellationToken) => this.monadicDocumentContainer.MonadicCreateItemAsync( payload, cancellationToken);
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.ToString()); CosmosString pkLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinScenarioTests.PartitionKeyPropertyName); Assert.AreEqual(pkValue, pkLazyString.Value.ToString()); CosmosString labelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, labelName); Assert.AreEqual(labelValue, labelLazyString.Value.ToString()); CosmosString vertexIdLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_VERTEXID); Assert.AreEqual(vertexIdValue, vertexIdLazyString.Value.ToString()); CosmosString vertexLabelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGEDOC_VERTEXLABEL); Assert.AreEqual(vertexLabelValue, vertexLabelLazyString.Value.ToString()); CosmosString sinkIdLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV); Assert.AreEqual(sinkIdValue, sinkIdLazyString.Value.ToString()); CosmosString sinkLabelLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV_LABEL); Assert.AreEqual(sinkLabelValue, sinkLabelLazyString.Value.ToString()); CosmosString sinkPartitionLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, GremlinKeywords.KW_EDGE_SINKV_PARTITION); Assert.AreEqual(sinkPartitionValue, sinkPartitionLazyString.Value.ToString()); 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.IsTrue(intValueLazyNumber is CosmosNumber64); Assert.IsTrue(intValueLazyNumber.Value.IsInteger); Assert.AreEqual((long)intValue, intValueLazyNumber.Value); CosmosNumber longValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, longName); Assert.IsTrue(intValueLazyNumber is CosmosNumber64); Assert.IsTrue(intValueLazyNumber.Value.IsInteger); Assert.AreEqual(longValue, longValueLazyNumber.Value); CosmosNumber floatValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, floatName); Assert.IsTrue(intValueLazyNumber is CosmosNumber64); Assert.IsTrue(floatValueLazyNumber.Value.IsDouble); Assert.AreEqual((double)floatValue, floatValueLazyNumber.Value); CosmosNumber doubleValueLazyNumber = this.GetAndAssertObjectProperty <CosmosNumber>(edgeLazyObject, doubleName); Assert.IsTrue(intValueLazyNumber is CosmosNumber64); Assert.IsTrue(doubleValueLazyNumber.Value.IsDouble); Assert.AreEqual((double)doubleValue, doubleValueLazyNumber.Value); CosmosString stringValueLazyString = this.GetAndAssertObjectProperty <CosmosString>(edgeLazyObject, stringName); Assert.AreEqual(stringValue, stringValueLazyString.Value.ToString()); }
public LazilyDeserializedPerson(CosmosObject cosmosObject) { this.cosmosObject = cosmosObject; }
/// <summary> /// Adds an object value to the distinct map. /// </summary> /// <param name="cosmosObject">The object to add.</param> /// <returns>Whether or not the value was successfully added.</returns> private bool AddObjectValue(CosmosObject cosmosObject) { UInt128 hash = DistinctHash.GetHash(cosmosObject); return(this.objects.Add(hash)); }
public ReadFeedIteratorCore( IDocumentContainer documentContainer, QueryRequestOptions queryRequestOptions, string continuationToken, int pageSize, CancellationToken cancellationToken) { 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 string oldContinuationFormat = feedRangeContinuation.ToString(); CosmosObject cosmosObject = CosmosObject.Parse(oldContinuationFormat); CosmosArray continuations = (CosmosArray)cosmosObject["Continuation"]; List <CosmosElement> readFeedContinuationTokens = new List <CosmosElement>(); 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 = CosmosElement.Parse(((CosmosString)continuationObject["token"]).Value); FeedRangeInternal feedRange = new FeedRangeEpk(new Documents.Routing.Range <string>(min, max, isMinInclusive: true, isMaxInclusive: false)); ReadFeedState state = new ReadFeedState(token); ReadFeedContinuationToken readFeedContinuationToken = new ReadFeedContinuationToken(feedRange, state); readFeedContinuationTokens.Add(ReadFeedContinuationToken.ToCosmosElement(readFeedContinuationToken)); } CosmosArray cosmosArrayContinuationTokens = CosmosArray.Create(readFeedContinuationTokens); continuationToken = cosmosArrayContinuationTokens.ToString(); } } this.monadicEnumerator = CrossPartitionReadFeedAsyncEnumerator.MonadicCreate( documentContainer, queryRequestOptions, continuationToken: continuationToken, pageSize, cancellationToken); this.hasMoreResults = true; }
private async Task <(Container, IReadOnlyList <CosmosObject>)> CreateContainerAndIngestDocumentsAsync( CollectionTypes collectionType, IEnumerable <string> documents, string partitionKey = "/id", Cosmos.IndexingPolicy indexingPolicy = null) { Container container; switch (collectionType) { case CollectionTypes.NonPartitioned: container = await this.CreateNonPartitionedContainerAsync(indexingPolicy); break; case CollectionTypes.SinglePartition: container = await this.CreateSinglePartitionContainer(partitionKey, indexingPolicy); break; case CollectionTypes.MultiPartition: container = await this.CreateMultiPartitionContainer(partitionKey, indexingPolicy); break; default: throw new ArgumentException($"Unknown {nameof(CollectionTypes)} : {collectionType}"); } List <CosmosObject> insertedDocuments = new List <CosmosObject>(); foreach (string document in documents) { JObject documentObject = JsonConvert.DeserializeObject <JObject>(document); // Add an id if (documentObject["id"] == null) { documentObject["id"] = Guid.NewGuid().ToString(); } // Get partition key value. Cosmos.PartitionKey pkValue; if (partitionKey != null) { string jObjectPartitionKey = partitionKey.Remove(0, 1); JValue pkToken = (JValue)documentObject[jObjectPartitionKey]; if (pkToken == null) { pkValue = Cosmos.PartitionKey.None; } else { switch (pkToken.Type) { case JTokenType.Integer: case JTokenType.Float: pkValue = new Cosmos.PartitionKey(pkToken.Value <double>()); break; case JTokenType.String: pkValue = new Cosmos.PartitionKey(pkToken.Value <string>()); break; case JTokenType.Boolean: pkValue = new Cosmos.PartitionKey(pkToken.Value <bool>()); break; case JTokenType.Null: pkValue = Cosmos.PartitionKey.Null; break; default: throw new ArgumentException("Unknown partition key type"); } } } else { pkValue = Cosmos.PartitionKey.None; } JObject createdDocument = await container.CreateItemAsync(documentObject, pkValue); CosmosObject insertedDocument = CosmosObject.Parse <CosmosObject>(createdDocument.ToString()); insertedDocuments.Add(insertedDocument); } return(container, insertedDocuments); }
public bool Visit(CosmosObject cosmosObject) { return(false); }
private async Task TestGroupByQueryHelper( Container container, IReadOnlyList <CosmosObject> documents) { List <(string, IReadOnlyList <CosmosElement>)> queryAndExpectedResultsList = new List <(string, IReadOnlyList <CosmosElement>)>() { // ------------------------------------------ // Simple property reference // ------------------------------------------ ( "SELECT c.age FROM c GROUP BY c.age", documents .GroupBy(document => document["age"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", grouping.Key } })) .ToList() ), ( "SELECT c.name FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key } })) .ToList() ), ( "SELECT c.team FROM c GROUP BY c.team", documents .GroupBy(document => document["team"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "team", grouping.Key } })) .ToList() ), ( "SELECT c.gender FROM c GROUP BY c.gender", documents .GroupBy(document => document["gender"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "gender", grouping.Key } })) .ToList() ), ( "SELECT c.id FROM c GROUP BY c.id", documents .GroupBy(document => document["id"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "id", grouping.Key } })) .ToList() ), ( "SELECT c.age, c.name FROM c GROUP BY c.age, c.name", documents .GroupBy(document => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", document["age"] }, { "name", document["name"] }, })) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", (grouping.Key as CosmosObject)["age"] }, { "name", (grouping.Key as CosmosObject)["name"] } })) .ToList() ), // ------------------------------------------ // With Aggregates // ------------------------------------------ ( "SELECT c.age, COUNT(1) as count FROM c GROUP BY c.age", documents .GroupBy(document => document["age"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", grouping.Key }, { "count", CosmosNumber64.Create(grouping.Count()) } })) .ToList() ), ( "SELECT c.name, MIN(c.age) AS min_age FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key }, { "min_age", CosmosNumber64.Create(grouping.Min(document => document["age"].ToDouble())) } })) .ToList() ), ( "SELECT c.name, MAX(c.age) AS max_age FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key }, { "max_age", CosmosNumber64.Create(grouping.Max(document => document["age"].ToDouble())) } })) .ToList() ), ( "SELECT c.name, SUM(c.age) AS sum_age FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key }, { "sum_age", CosmosNumber64.Create(grouping.Sum(document => document["age"].ToDouble())) } })) .ToList() ), ( "SELECT c.name, AVG(c.age) AS avg_age FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key }, { "avg_age", CosmosNumber64.Create(grouping.Average(document => document["age"].ToDouble())) } })) .ToList() ), ( "SELECT c.name, Count(1) AS count, Min(c.age) AS min_age, Max(c.age) AS max_age FROM c GROUP BY c.name", documents .GroupBy(document => document["name"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "name", grouping.Key }, { "count", CosmosNumber64.Create(grouping.Count()) }, { "min_age", CosmosNumber64.Create(grouping.Min(document => document["age"].ToDouble())) }, { "max_age", CosmosNumber64.Create(grouping.Max(document => document["age"].ToDouble())) }, })) .ToList() ), // ------------------------------------------ // SELECT VALUE // ------------------------------------------ ( "SELECT VALUE c.age FROM c GROUP BY c.age", documents .GroupBy(document => document["age"]) .Select(grouping => grouping.Key) .ToList() ), // ------------------------------------------ // Corner Cases // ------------------------------------------ ( "SELECT AVG(\"asdf\") as avg_asdf FROM c GROUP BY c.age", documents .GroupBy(document => document["age"]) .Select(grouping => CosmosObject.Create(new Dictionary <string, CosmosElement>())) .ToList() ), ( @"SELECT c.age, AVG(c.doesNotExist) as undefined_avg, MIN(c.doesNotExist) as undefined_min, MAX(c.doesNotExist) as undefined_max, COUNT(c.doesNotExist) as undefined_count, SUM(c.doesNotExist) as undefined_sum FROM c GROUP BY c.age", documents .GroupBy(document => document["age"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", grouping.Key }, // sum and count default the counter at 0 { "undefined_sum", CosmosNumber64.Create(0) }, { "undefined_count", CosmosNumber64.Create(0) }, })) .ToList() ), ( @"SELECT c.age, c.doesNotExist FROM c GROUP BY c.age, c.doesNotExist", documents .GroupBy(document => document["age"]) .Select(grouping => CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "age", grouping.Key } })) .ToList() ), }; // Test query correctness. foreach ((string query, IReadOnlyList <CosmosElement> expectedResults) in queryAndExpectedResultsList) { foreach (int maxItemCount in new int[] { 1, 5, 10 }) { List <CosmosElement> actualWithoutContinuationTokens = await QueryTestsBase.QueryWithoutContinuationTokensAsync <CosmosElement>( container, query, new QueryRequestOptions() { MaxConcurrency = 2, MaxItemCount = maxItemCount, MaxBufferedItemCount = 100, }); HashSet <CosmosElement> actualWithoutContinuationTokensSet = new HashSet <CosmosElement>(actualWithoutContinuationTokens); List <CosmosElement> actualWithTryGetContinuationTokens = await QueryTestsBase.QueryWithCosmosElementContinuationTokenAsync <CosmosElement>( container, query, new QueryRequestOptions() { MaxConcurrency = 2, MaxItemCount = maxItemCount, MaxBufferedItemCount = 100, }); HashSet <CosmosElement> actualWithTryGetContinuationTokensSet = new HashSet <CosmosElement>(actualWithTryGetContinuationTokens); Assert.IsTrue( actualWithoutContinuationTokensSet.SetEquals(actualWithTryGetContinuationTokensSet), $"Results did not match for query: {query} with maxItemCount: {maxItemCount}" + $"ActualWithoutContinuationTokens: {JsonConvert.SerializeObject(actualWithoutContinuationTokensSet)}" + $"ActualWithTryGetContinuationTokens: {JsonConvert.SerializeObject(actualWithTryGetContinuationTokensSet)}"); HashSet <CosmosElement> expectedSet = new HashSet <CosmosElement>(expectedResults); Assert.IsTrue( actualWithoutContinuationTokensSet.SetEquals(expectedSet), $"Results did not match for query: {query} with maxItemCount: {maxItemCount}" + $"Actual {JsonConvert.SerializeObject(actualWithoutContinuationTokensSet)}" + $"Expected: {JsonConvert.SerializeObject(expectedSet)}"); } } // Test that continuation token is blocked { try { List <JToken> actual = await QueryTestsBase.QueryWithContinuationTokensAsync <JToken>( container, "SELECT c.age FROM c GROUP BY c.age", new QueryRequestOptions() { MaxConcurrency = 2, MaxItemCount = 1 }); Assert.Fail("Expected an error when trying to drain a GROUP BY query with continuation tokens."); } catch (Exception) { } } }
public void TestOrderByQueryLiterals() { StringBuilder sb = new StringBuilder(); CosmosElement element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosString.Create("asdf") } }); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":""asdf""}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosBoolean.Create(true) } }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":true}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosBoolean.Create(false) } }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":false}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosNull.Create() } }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":null}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosNumber64.Create(1.0) } }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":1}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosNumber64.Create(1L) } }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":1}", sb.ToString()); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosInt8.Create(3) }, { "item2", CosmosInt16.Create(4) }, { "item3", CosmosInt32.Create(5) }, { "item5", CosmosUInt32.Create(7) }, { "item6", CosmosInt64.Create(8) }, { "item7", CosmosFloat32.Create(9.1f) }, { "item8", CosmosFloat64.Create(10.2) }, }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( @"{""item"":C_Int8(3),""item2"":C_Int16(4),""item3"":C_Int32(5),""item5"":C_UInt32(7),""item6"":C_Int64(8)," + @"""item7"":C_Float32(9.1),""item8"":C_Float64(10.2)}", sb.ToString()); Guid guid = Guid.NewGuid(); byte[] randomBytes = Guid.NewGuid().ToByteArray(); string hexString = PartitionKeyInternal.HexConvert.ToHex(randomBytes, 0, randomBytes.Length); element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosGuid.Create(guid) }, { "item2", CosmosBinary.Create(new ReadOnlyMemory <byte>(randomBytes)) }, }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( $@"{{""item"":C_Guid(""{guid.ToString()}""),""item2"":C_Binary(""0x{hexString}"")}}", sb.ToString()); // deeply nested arrays and objects element = CosmosObject.Create( new Dictionary <string, CosmosElement>() { { "item", CosmosGuid.Create(guid) }, // empty array { "item2", CosmosArray.Create(new CosmosElement[] { }) }, // empty object { "item3", CosmosObject.Create(new Dictionary <string, CosmosElement>()) }, // array of objects with numbers { "item4", CosmosArray.Create(new CosmosElement[] { CosmosObject.Create(new Dictionary <string, CosmosElement>() { { "a", CosmosInt8.Create(3) }, { "b", CosmosString.Create("adf") }, }), CosmosInt16.Create(25) }) }, }); sb.Clear(); element.Accept(new CosmosElementToQueryLiteral(sb)); Assert.AreEqual( $@"{{""item"":C_Guid(""{guid.ToString()}""),""item2"":[],""item3"":{{}},""item4"":[{{""a"":C_Int8(3),""b"":""adf""}},C_Int16(25)]}}", sb.ToString()); }
public async Task TestCosmosOrderByQueryExecutionContextWithFailurePageAsync(bool createInitialContinuationToken) { int maxPageSize = 5; List <MockPartitionResponse[]> mockResponsesScenario = MockQueryFactory.GetFailureScenarios(); Mock <CosmosQueryClient> mockQueryClient = new Mock <CosmosQueryClient>(); foreach (MockPartitionResponse[] mockResponse in mockResponsesScenario) { string initialContinuationToken = null; string fullConitnuationToken = null; if (createInitialContinuationToken) { ToDoItem itemToRepresentPreviousQuery = ToDoItem.CreateItems( 1, "itemToRepresentPreviousQuery", MockQueryFactory.DefaultCollectionRid).First(); initialContinuationToken = $" - RID:{itemToRepresentPreviousQuery._rid} ==#RT:1#TRC:1"; CompositeContinuationToken compositeContinuation = new CompositeContinuationToken() { Range = new Documents.Routing.Range <string>( min: MockQueryFactory.DefaultPartitionKeyRange.MinInclusive, max: MockQueryFactory.DefaultPartitionKeyRange.MaxExclusive, isMaxInclusive: false, isMinInclusive: true), Token = initialContinuationToken }; List <OrderByItem> orderByItems = new List <OrderByItem>() { new OrderByItem(CosmosObject.CreateFromBuffer(Encoding.UTF8.GetBytes("{\"item\":\"2c4ce711-13c3-4c93-817c-49287b71b6c3\"}"))) }; OrderByContinuationToken orderByContinuationToken = new OrderByContinuationToken( queryClient: mockQueryClient.Object, compositeContinuationToken: compositeContinuation, orderByItems: orderByItems, rid: itemToRepresentPreviousQuery._rid, skipCount: 0, filter: null); fullConitnuationToken = JsonConvert.SerializeObject(new OrderByContinuationToken[] { orderByContinuationToken }); } IList <ToDoItem> allItems = MockQueryFactory.GenerateAndMockResponse( mockQueryClient, isOrderByQuery: true, sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, containerRid: MockQueryFactory.DefaultCollectionRid, initContinuationToken: initialContinuationToken, maxPageSize: maxPageSize, mockResponseForSinglePartition: mockResponse, cancellationTokenForMocks: this.cancellationToken); // Order by drains the partitions until it finds an item // If there are no items then it's not possible to have a continuation token if (allItems.Count == 0 && createInitialContinuationToken) { continue; } CosmosQueryContext context = MockQueryFactory.CreateContext( mockQueryClient.Object); QueryInfo queryInfo = new QueryInfo() { OrderBy = new SortOrder[] { SortOrder.Ascending }, OrderByExpressions = new string[] { "id" } }; CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams initParams = new CosmosCrossPartitionQueryExecutionContext.CrossPartitionInitParams( sqlQuerySpec: MockQueryFactory.DefaultQuerySpec, collectionRid: MockQueryFactory.DefaultCollectionRid, partitionedQueryExecutionInfo: new PartitionedQueryExecutionInfo() { QueryInfo = queryInfo }, partitionKeyRanges: new List <PartitionKeyRange>() { MockQueryFactory.DefaultPartitionKeyRange }, initialPageSize: maxPageSize, maxConcurrency: null, maxItemCount: maxPageSize, maxBufferedItemCount: null); CosmosOrderByItemQueryExecutionContext executionContext = (await CosmosOrderByItemQueryExecutionContext.TryCreateAsync( context, initParams, fullConitnuationToken, this.cancellationToken)).Result; Assert.IsTrue(!executionContext.IsDone); // Read all the pages from both splits List <ToDoItem> itemsRead = new List <ToDoItem>(); QueryResponseCore?failure = null; while (!executionContext.IsDone) { QueryResponseCore queryResponse = await executionContext.DrainAsync( maxPageSize, this.cancellationToken); if (queryResponse.IsSuccess) { string responseContinuationToken = queryResponse.ContinuationToken; foreach (CosmosElement element in queryResponse.CosmosElements) { string jsonValue = element.ToString(); ToDoItem item = JsonConvert.DeserializeObject <ToDoItem>(jsonValue); itemsRead.Add(item); } } else { Assert.IsNull(failure, "There should only be one error"); failure = queryResponse; } } Assert.IsNotNull(failure); Assert.AreEqual((HttpStatusCode)429, failure.Value.StatusCode); Assert.IsNull(failure.Value.ErrorMessage); Assert.AreEqual(allItems.Count, itemsRead.Count); CollectionAssert.AreEqual(allItems.ToList(), itemsRead, new ToDoItemComparer()); } }
/// <summary> /// Visits a SqlJoinCollectionExpression and transforms the documents accordingly. /// </summary> /// <param name="collectionExpression">The collection expression to visit.</param> /// <param name="documents">The documents to transform.</param> /// <returns>The transformed documents according to the collection expression.</returns> public override IEnumerable <CosmosElement> Visit(SqlJoinCollectionExpression collectionExpression, IEnumerable <CosmosElement> documents) { //If the query was: //SELECT blah //FROM f //JOIN c IN f.children //and the document was //{ // "children" : [{"name" : "John"}, {"name" : "Sally"}] //} //then the results would be: //{ // "f" : { "children" : [{"name" : "John"}, {"name" : "Sally"}] } // "c" : {"name" : "John"} //} //and //{ // "f" : { "children" : [{"name" : "John"}, {"name" : "Sally"}] } // "c" : {"name" : "Sally"} //} //Notice that the result set is larger than the input //This is because we emitted one document for each child in the original document //wrapped it with the provided alias //and merged the results from the source expression. IEnumerable <CosmosElement> collection1 = collectionExpression.Left.Accept(this, documents); // Perform the select many and merge the documents foreach (CosmosObject document1 in collection1) { IEnumerable <CosmosElement> collection2 = collectionExpression.Right.Accept(this, new CosmosElement[] { document1 }); foreach (CosmosObject document2 in collection2) { Dictionary <string, CosmosElement> mergedDocument = new Dictionary <string, CosmosElement>(); foreach (KeyValuePair <string, CosmosElement> property in document1) { if (property.Key != "_rid") { mergedDocument[property.Key] = property.Value; } } foreach (KeyValuePair <string, CosmosElement> property in document2) { if (property.Key != "_rid") { mergedDocument[property.Key] = property.Value; } } // Add the _rid at the end so we can break ties in the sort later. mergedDocument["_rid"] = document1["_rid"]; yield return(CosmosObject.Create(mergedDocument)); } } }
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; }
public static Record Create(long previousResourceIdentifier, CosmosObject payload) { return(new Record(previousResourceIdentifier + 1, DateTime.UtcNow.Ticks, Guid.NewGuid(), payload)); }
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)); }
public JsonType Visit(CosmosObject cosmosObject) => JsonType.Object;
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 void TestCaching() { CosmosArray lazilyDeserializedPeople = CosmosElement.CreateFromBuffer <CosmosArray>(LazyCosmosElementTests.bufferedSerializedPeople); Assert.IsTrue( object.ReferenceEquals(lazilyDeserializedPeople[0], lazilyDeserializedPeople[0]), "Array did not return the item from the cache."); CosmosObject lazilyDeserializedPerson = lazilyDeserializedPeople[0] as CosmosObject; foreach (string key in lazilyDeserializedPerson.Keys) { Assert.IsTrue( object.ReferenceEquals(lazilyDeserializedPerson[key], lazilyDeserializedPerson[key]), "Object property was not served from the cache"); } foreach ((string key1, string key2) in lazilyDeserializedPerson.Keys.Zip(lazilyDeserializedPerson.Keys, (first, second) => (first, second))) { Assert.IsTrue( object.ReferenceEquals(key1, key2), "Object keys are not served from the cache."); } foreach ((CosmosElement value1, CosmosElement value2) in lazilyDeserializedPerson.Values.Zip(lazilyDeserializedPerson.Values, (first, second) => (first, second))) { Assert.IsTrue( object.ReferenceEquals(value1, value2), "Object values are not served from the cache."); } int countFromCount = lazilyDeserializedPerson.Count; int countFromEnumerator = 0; foreach (KeyValuePair <string, CosmosElement> kvp in lazilyDeserializedPerson) { countFromEnumerator++; } Assert.AreEqual(countFromCount, countFromEnumerator); // Can not test for strings, since UtfAnyString allocates a light weight wrapper. int i = 0; foreach (CosmosElement arrayItem in lazilyDeserializedPeople) { Assert.IsTrue( object.ReferenceEquals(arrayItem, lazilyDeserializedPeople[i++])); } Assert.AreEqual(i, lazilyDeserializedPeople.Count); int count = lazilyDeserializedPeople.Count; for (i = 0; i < count; i++) { Assert.IsTrue( object.ReferenceEquals(lazilyDeserializedPeople[i], lazilyDeserializedPeople[i])); } // Numbers is a value type so we don't need to test for the cache. // Booleans are multitons so we don't need to test for the cache. // Nulls are singletons so we don't need to test for the cache. }