diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByContinuationToken.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByContinuationToken.cs index 7d9879b612..863204d506 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByContinuationToken.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByContinuationToken.cs @@ -45,12 +45,12 @@ namespace Microsoft.Azure.Cosmos.Query.Core.Pipeline.CrossPartition.OrderBy /// 2. All partitions, that have greater Range.Min than that of the target partition, have exhausted all values less than or equal to X /// /// - /// Given this background, below is an example of order by continuation token. The class members below explains the different + /// Given this background, below is an example of orderby continuation token. The class members below explains the different /// component/states of the continuation token. /// /// /// - /// Order by continuation token example. + /// OrderBy continuation token example. /// 1"} /// ]]> @@ -71,8 +71,8 @@ private static class PropertyNames /// Initializes a new instance of the OrderByContinuationToken struct. /// /// The composite continuation token (refer to property documentation). - /// The order by items (refer to property documentation). - /// Order By property values the query needs to resume from in the next round trip + /// The orderby items (refer to property documentation). + /// OrderBy property values the query needs to resume from in the next round trip /// The rid (refer to property documentation). /// The skip count (refer to property documentation). /// The filter (refer to property documentation). @@ -97,21 +97,28 @@ public OrderByContinuationToken( //// filter is allowed to be null. this.ParallelContinuationToken = compositeContinuationToken ?? throw new ArgumentNullException(nameof(compositeContinuationToken)); - if ((resumeValues != null) && (resumeValues.Count > 0)) + if (resumeValues != null) { + if (resumeValues.Count == 0) + { + throw new ArgumentException($"{nameof(resumeValues)} can not be empty."); + } + this.ResumeValues = resumeValues; - this.OrderByItems = null; } - else + else if (orderByItems != null) { - if ((orderByItems == null) || (orderByItems.Count == 0)) + if (orderByItems.Count == 0) { throw new ArgumentException($"{nameof(orderByItems)} can not be empty."); } - this.ResumeValues = null; this.OrderByItems = orderByItems; } + else + { + throw new ArgumentException($"Either {nameof(orderByItems)} or {nameof(resumeValues)} needs to be provided."); + } this.Rid = rid; this.SkipCount = skipCount; @@ -144,7 +151,7 @@ public ParallelContinuationToken ParallelContinuationToken /// ]]> /// /// - /// This is an array to support multi item order by. + /// This is an array to support multi item orderby. /// > [JsonProperty(PropertyNames.OrderByItems)] public IReadOnlyList OrderByItems @@ -157,13 +164,13 @@ public IReadOnlyList OrderByItems /// resumeValues is used for filtering when we resume. /// /// - /// The below array has one value "2" which was the last order by value returned. + /// The below array has one value "2" which was the last orderby value returned. /// /// /// - /// This is an array to support multi item order by. + /// This is an array to support multi item orderby. /// > [JsonProperty(PropertyNames.ResumeValues)] public IReadOnlyList ResumeValues @@ -201,7 +208,7 @@ public string Rid /// online to understand this better. /// /// - /// This behavior has implications on how pagination work for CosmosDB queries, especially for order by queries across + /// This behavior has implications on how pagination work for CosmosDB queries, especially for orderby queries across /// multiple partition. /// /// @@ -247,27 +254,33 @@ public string Filter public static CosmosElement ToCosmosElement(OrderByContinuationToken orderByContinuationToken) { CosmosElement compositeContinuationToken = ParallelContinuationToken.ToCosmosElement(orderByContinuationToken.ParallelContinuationToken); - List orderByItemsRaw = new List(); + + List orderByItemsRaw; + List resumeValuesRaw; if (orderByContinuationToken.OrderByItems != null) { + orderByItemsRaw = new List(orderByContinuationToken.OrderByItems.Count); foreach (OrderByItem orderByItem in orderByContinuationToken.OrderByItems) { orderByItemsRaw.Add(OrderByItem.ToCosmosElement(orderByItem)); } - } - List resumeValuesRaw; - if (orderByContinuationToken.ResumeValues != null) + resumeValuesRaw = null; + } + else { + if (orderByContinuationToken.ResumeValues == null) + { + throw new ArgumentException($"Either {nameof(orderByContinuationToken.ResumeValues)} or {nameof(orderByContinuationToken.OrderByItems)} needs to be specified."); + } + resumeValuesRaw = new List(orderByContinuationToken.ResumeValues.Count); foreach (SqlQueryResumeValue resumeValue in orderByContinuationToken.ResumeValues) { resumeValuesRaw.Add(SqlQueryResumeValue.ToCosmosElement(resumeValue)); } - } - else - { - resumeValuesRaw = null; + + orderByItemsRaw = null; } CosmosElement filter = orderByContinuationToken.Filter == null ? CosmosNull.Create() : CosmosString.Create(orderByContinuationToken.Filter); @@ -315,7 +328,7 @@ public static TryCatch TryCreateFromCosmosElement(Cosm ParallelContinuationToken compositeContinuationToken = tryCompositeContinuation.Result; - // Try to get ResumeValues first, if it is not present then try to get order by items + // Try to get ResumeValues first, if it is not present then try to get orderby items List resumeValues; if (cosmosObject.TryGetValue(PropertyNames.ResumeValues, out CosmosArray resumeValuesRaw)) { diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs index 1ee91cd33f..cb7985b219 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/Pipeline/CrossPartition/OrderBy/OrderByCrossPartitionQueryPipelineStage.cs @@ -404,7 +404,7 @@ private ValueTask MoveNextAsync_DrainPageAsync(ITrace trace) this.uninitializedEnumeratorsAndTokens.Enqueue((currentEnumerator, (OrderByContinuationToken)null)); // Use the token for the next page, since we fully drained the enumerator. - OrderByContinuationToken orderByContinuationToken = CreateContinuationToken( + OrderByContinuationToken orderByContinuationToken = CreateOrderByContinuationToken( new ParallelContinuationToken( token: ((CosmosString)currentEnumerator.FeedRangeState.State.Value).Value, range: ((FeedRangeEpk)currentEnumerator.FeedRangeState.FeedRange).Range), @@ -455,7 +455,7 @@ private ValueTask MoveNextAsync_DrainPageAsync(ITrace trace) } else { - OrderByContinuationToken orderByContinuationToken = CreateContinuationToken( + OrderByContinuationToken orderByContinuationToken = CreateOrderByContinuationToken( new ParallelContinuationToken( token: currentEnumerator.StartOfPageState != null ? ((CosmosString)currentEnumerator.StartOfPageState.Value).Value : null, range: ((FeedRangeEpk)currentEnumerator.FeedRangeState.FeedRange).Range), @@ -877,9 +877,7 @@ private static TryCatch> MonadicExtractOrderByTok foreach (OrderByContinuationToken suppliedOrderByContinuationToken in orderByContinuationTokens) { - int orderByCount = suppliedOrderByContinuationToken.ResumeValues != null ? - suppliedOrderByContinuationToken.ResumeValues.Count : suppliedOrderByContinuationToken.OrderByItems.Count; - + int orderByCount = GetOrderByItemCount(suppliedOrderByContinuationToken); if (orderByCount != numOrderByColumns) { return TryCatch>.FromException( @@ -891,6 +889,12 @@ private static TryCatch> MonadicExtractOrderByTok return TryCatch>.FromResult(orderByContinuationTokens); } + private static int GetOrderByItemCount(OrderByContinuationToken orderByContinuationToken) + { + return orderByContinuationToken.ResumeValues != null ? + orderByContinuationToken.ResumeValues.Count : orderByContinuationToken.OrderByItems.Count; + } + private static void AppendToBuilders((StringBuilder leftFilter, StringBuilder targetFilter, StringBuilder rightFilter) builders, object str) { OrderByCrossPartitionQueryPipelineStage.AppendToBuilders(builders, str, str, str); @@ -1143,7 +1147,7 @@ private static (string leftFilter, string targetFilter, string rightFilter) GetF return (left.ToString(), target.ToString(), right.ToString()); } - private static OrderByContinuationToken CreateContinuationToken( + private static OrderByContinuationToken CreateOrderByContinuationToken( ParallelContinuationToken parallelToken, OrderByQueryResult orderByQueryResult, int skipCount, diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/SqlQueryResumeValue.cs b/Microsoft.Azure.Cosmos/src/Query/Core/SqlQueryResumeValue.cs index 4c6f4ec60e..9151f5d08e 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/SqlQueryResumeValue.cs +++ b/Microsoft.Azure.Cosmos/src/Query/Core/SqlQueryResumeValue.cs @@ -17,107 +17,58 @@ internal class SqlQueryResumeValue : IComparable { private static class PropertyNames { - public const string Type = "type"; public const string ArrayType = "array"; - public const string ObjectType = "object"; - public const string Low = "low"; public const string High = "high"; + public const string Low = "low"; + public const string ObjectType = "object"; + public const string Type = "type"; } - private class UndefinedResumeValue : SqlQueryResumeValue - { - } - - private class NullResumeValue : SqlQueryResumeValue - { - } - - private class BooleanResumeValue : SqlQueryResumeValue - { - public bool Value { get; } - - public BooleanResumeValue(bool value) - { - this.Value = value; - } - } - - private class NumberResumeValue : SqlQueryResumeValue - { - public Number64 Value { get; } - - public NumberResumeValue(Number64 value) - { - this.Value = value; - } - } - - private class StringResumeValue : SqlQueryResumeValue - { - public UtfAnyString Value { get; } - - public StringResumeValue(UtfAnyString value) - { - this.Value = value; - } - } - - private class ArrayResumeValue : SqlQueryResumeValue + private SqlQueryResumeValue(CosmosElement element) { - public UInt128 HashValue { get; } - - public ArrayResumeValue(UInt128 hashValue) - { - this.HashValue = hashValue; - } + this.resumeValue = element; } - private class ObjectResumeValue : SqlQueryResumeValue - { - public UInt128 HashValue { get; } - - public ObjectResumeValue(UInt128 hashValue) - { - this.HashValue = hashValue; - } - } + private readonly CosmosElement resumeValue; public int CompareTo(CosmosElement cosmosElement) { - // Convert ResumeValue to CosmosElement and invoke ItemComparer to compare the cosmoselements - switch (this) + switch (this.resumeValue) { - case UndefinedResumeValue: - return ItemComparer.Instance.Compare(CosmosUndefined.Create(), cosmosElement); - - case NullResumeValue: - return ItemComparer.Instance.Compare(CosmosNull.Create(), cosmosElement); - - case BooleanResumeValue booleanValue: - return ItemComparer.Instance.Compare(CosmosBoolean.Create(booleanValue.Value), cosmosElement); - - case NumberResumeValue numberValue: - return ItemComparer.Instance.Compare(CosmosNumber64.Create(numberValue.Value), cosmosElement); + case CosmosUndefined: + case CosmosNull: + case CosmosBoolean: + case CosmosNumber: + case CosmosString: + return ItemComparer.Instance.Compare(this.resumeValue, cosmosElement); + + case CosmosObject: + { + CosmosObject cosmosObject = (CosmosObject)this.resumeValue; - case StringResumeValue stringValue: - return ItemComparer.Instance.Compare(CosmosString.Create(stringValue.Value), cosmosElement); + if (!cosmosObject.TryGetValue(PropertyNames.Type, out CosmosString objectType) + || !cosmosObject.TryGetValue(PropertyNames.Low, out CosmosNumber64 lowValue) + || !cosmosObject.TryGetValue(PropertyNames.High, out CosmosNumber64 highValue)) + { + throw new ArgumentException($"Incorrect Array / Object Resume Value. One or more of the required properties are missing."); + } - case ArrayResumeValue arrayValue: + UInt128 hashValue = UInt128.Create((ulong)Number64.ToLong(lowValue.Value), (ulong)Number64.ToLong(highValue.Value)); + if (string.Equals(objectType.Value, PropertyNames.ArrayType)) { // If the order by result is also of array type, then compare the hash values // For other types create an empty array and call CosmosElement comparer which // will take care of ordering based on types. if (cosmosElement is CosmosArray arrayResult) { - return UInt128BinaryComparer.Singleton.Compare(arrayValue.HashValue, DistinctHash.GetHash(arrayResult)); + return UInt128BinaryComparer.Singleton.Compare(hashValue, DistinctHash.GetHash(arrayResult)); } else { return ItemComparer.Instance.Compare(CosmosArray.Empty, cosmosElement); } } - - case ObjectResumeValue objectValue: + else if (string.Equals(objectType.Value, PropertyNames.ObjectType)) { // If the order by result is also of object type, then compare the hash values // For other types create an empty object and call CosmosElement comparer which @@ -125,13 +76,18 @@ public int CompareTo(CosmosElement cosmosElement) if (cosmosElement is CosmosObject objectResult) { // same type so compare the hash values - return UInt128BinaryComparer.Singleton.Compare(objectValue.HashValue, DistinctHash.GetHash(objectResult)); + return UInt128BinaryComparer.Singleton.Compare(hashValue, DistinctHash.GetHash(objectResult)); } else { return ItemComparer.Instance.Compare(CosmosObject.Create(new Dictionary()), cosmosElement); } } + else + { + throw new ArgumentException($"Incorrect value for {PropertyNames.Type} property. Value is {objectType.Value}."); + } + } default: throw new ArgumentException($"Invalid {nameof(SqlQueryResumeValue)} type."); @@ -141,27 +97,10 @@ public int CompareTo(CosmosElement cosmosElement) // Utility method that converts SqlQueryResumeValue to CosmosElement which can then be serialized to string public static CosmosElement ToCosmosElement(SqlQueryResumeValue resumeValue) { - return resumeValue switch + return resumeValue.resumeValue switch { - UndefinedResumeValue => CosmosArray.Create(new List()), - NullResumeValue => CosmosNull.Create(), - BooleanResumeValue booleanValue => CosmosBoolean.Create(booleanValue.Value), - NumberResumeValue numberValue => CosmosNumber64.Create(numberValue.Value), - StringResumeValue stringValue => CosmosString.Create(stringValue.Value), - ArrayResumeValue arrayValue => CosmosObject.Create( - new Dictionary() - { - { PropertyNames.Type, CosmosString.Create(PropertyNames.ArrayType) }, - { PropertyNames.Low, CosmosNumber64.Create((long)arrayValue.HashValue.GetLow()) }, - { PropertyNames.High, CosmosNumber64.Create((long)arrayValue.HashValue.GetHigh()) } - }), - ObjectResumeValue objectValue => CosmosObject.Create( - new Dictionary() - { - { PropertyNames.Type, CosmosString.Create(PropertyNames.ObjectType) }, - { PropertyNames.Low, CosmosNumber64.Create((long)objectValue.HashValue.GetLow()) }, - { PropertyNames.High, CosmosNumber64.Create((long)objectValue.HashValue.GetHigh()) } - }), + CosmosUndefined => CosmosArray.Create(new List()), + CosmosBoolean or CosmosNull or CosmosNumber or CosmosString or CosmosObject => resumeValue.resumeValue, _ => throw new ArgumentException($"Invalid {nameof(SqlQueryResumeValue)} type."), }; } @@ -178,53 +117,31 @@ public static SqlQueryResumeValue FromOrderByValue(CosmosElement orderByValue) public static void Serialize(JsonWriter writer, SqlQueryResumeValue value, JsonSerializer serializer) { - switch (value) + switch (value.resumeValue) { - case UndefinedResumeValue: + case CosmosUndefined: writer.WriteStartArray(); writer.WriteEndArray(); break; - case NullResumeValue: + case CosmosNull: writer.WriteNull(); break; - case BooleanResumeValue booleanValue: + case CosmosBoolean booleanValue: serializer.Serialize(writer, booleanValue.Value); break; - case NumberResumeValue numberValue: + case CosmosNumber numberValue: serializer.Serialize(writer, numberValue.Value); break; - case StringResumeValue stringValue: + case CosmosString stringValue: serializer.Serialize(writer, stringValue.Value.ToString()); break; - case ArrayResumeValue arrayValue: - { - writer.WriteStartObject(); - writer.WritePropertyName(PropertyNames.Type); - writer.WriteValue(PropertyNames.ArrayType); - writer.WritePropertyName(PropertyNames.Low); - writer.WriteValue((long)arrayValue.HashValue.GetLow()); - writer.WritePropertyName(PropertyNames.High); - writer.WriteValue((long)arrayValue.HashValue.GetHigh()); - writer.WriteEndObject(); - } - break; - - case ObjectResumeValue objectValue: - { - writer.WriteStartObject(); - writer.WritePropertyName(PropertyNames.Type); - writer.WriteValue(PropertyNames.ObjectType); - writer.WritePropertyName(PropertyNames.Low); - writer.WriteValue((long)objectValue.HashValue.GetLow()); - writer.WritePropertyName(PropertyNames.High); - writer.WriteValue((long)objectValue.HashValue.GetHigh()); - writer.WriteEndObject(); - } + case CosmosObject objectValue: + serializer.Serialize(writer, objectValue); break; default: @@ -249,7 +166,7 @@ public SqlQueryResumeValue Visit(CosmosArray cosmosArray) throw new ArgumentException($"Only empty arrays can be converted to ResumeValue. Array has {cosmosArray.Count} elements."); } - return new UndefinedResumeValue(); + return new SqlQueryResumeValue(CosmosUndefined.Create()); } public SqlQueryResumeValue Visit(CosmosBinary cosmosBinary) @@ -259,7 +176,7 @@ public SqlQueryResumeValue Visit(CosmosBinary cosmosBinary) public SqlQueryResumeValue Visit(CosmosBoolean cosmosBoolean) { - return new BooleanResumeValue(cosmosBoolean.Value); + return new SqlQueryResumeValue(cosmosBoolean); } public SqlQueryResumeValue Visit(CosmosGuid cosmosGuid) @@ -269,51 +186,40 @@ public SqlQueryResumeValue Visit(CosmosGuid cosmosGuid) public SqlQueryResumeValue Visit(CosmosNull cosmosNull) { - return new NullResumeValue(); + return new SqlQueryResumeValue(cosmosNull); } public SqlQueryResumeValue Visit(CosmosUndefined cosmosUndefined) { - return new UndefinedResumeValue(); + return new SqlQueryResumeValue(cosmosUndefined); } public SqlQueryResumeValue Visit(CosmosNumber cosmosNumber) { - return new NumberResumeValue(cosmosNumber.Value); + return new SqlQueryResumeValue(cosmosNumber); } public SqlQueryResumeValue Visit(CosmosObject cosmosObject) { + // Validate if the object is in the expected format if (!cosmosObject.TryGetValue(PropertyNames.Type, out CosmosString objectType) - || !cosmosObject.TryGetValue(PropertyNames.Low, out CosmosNumber64 lowValue) - || !cosmosObject.TryGetValue(PropertyNames.High, out CosmosNumber64 highValue)) + || !cosmosObject.TryGetValue(PropertyNames.Low, out CosmosNumber64 _) + || !cosmosObject.TryGetValue(PropertyNames.High, out CosmosNumber64 _)) { throw new ArgumentException($"Incorrect Array / Object Resume Value. One or more of the required properties are missing."); } - if (string.Equals(objectType.Value, PropertyNames.ArrayType)) - { - return new ArrayResumeValue( - UInt128.Create( - (ulong)Number64.ToLong(lowValue.Value), - (ulong)Number64.ToLong(highValue.Value))); - } - else if (string.Equals(objectType.Value, PropertyNames.ObjectType)) - { - return new ObjectResumeValue( - UInt128.Create( - (ulong)Number64.ToLong(lowValue.Value), - (ulong)Number64.ToLong(highValue.Value))); - } - else + if (!string.Equals(objectType.Value, PropertyNames.ArrayType) && !string.Equals(objectType.Value, PropertyNames.ObjectType)) { throw new ArgumentException($"Incorrect value for {PropertyNames.Type} property. Value is {objectType.Value}."); } + + return new SqlQueryResumeValue(cosmosObject); } public SqlQueryResumeValue Visit(CosmosString cosmosString) { - return new StringResumeValue(cosmosString.Value); + return new SqlQueryResumeValue(cosmosString); } } @@ -329,7 +235,14 @@ private OrderByValueToResumeValueVisitor() public SqlQueryResumeValue Visit(CosmosArray cosmosArray) { - return new ArrayResumeValue(DistinctHash.GetHash(cosmosArray)); + UInt128 hashValue = DistinctHash.GetHash(cosmosArray); + return new SqlQueryResumeValue(CosmosObject.Create( + new Dictionary() + { + { PropertyNames.Type, CosmosString.Create(PropertyNames.ArrayType) }, + { PropertyNames.Low, CosmosNumber64.Create((long)hashValue.GetLow()) }, + { PropertyNames.High, CosmosNumber64.Create((long)hashValue.GetHigh()) } + })); } public SqlQueryResumeValue Visit(CosmosBinary cosmosBinary) @@ -339,7 +252,7 @@ public SqlQueryResumeValue Visit(CosmosBinary cosmosBinary) public SqlQueryResumeValue Visit(CosmosBoolean cosmosBoolean) { - return new BooleanResumeValue(cosmosBoolean.Value); + return new SqlQueryResumeValue(cosmosBoolean); } public SqlQueryResumeValue Visit(CosmosGuid cosmosGuid) @@ -349,27 +262,34 @@ public SqlQueryResumeValue Visit(CosmosGuid cosmosGuid) public SqlQueryResumeValue Visit(CosmosNull cosmosNull) { - return new NullResumeValue(); + return new SqlQueryResumeValue(cosmosNull); } public SqlQueryResumeValue Visit(CosmosUndefined cosmosUndefined) { - return new UndefinedResumeValue(); + return new SqlQueryResumeValue(cosmosUndefined); } public SqlQueryResumeValue Visit(CosmosNumber cosmosNumber) { - return new NumberResumeValue(cosmosNumber.Value); + return new SqlQueryResumeValue(cosmosNumber); } public SqlQueryResumeValue Visit(CosmosObject cosmosObject) { - return new ObjectResumeValue(DistinctHash.GetHash(cosmosObject)); + UInt128 hashValue = DistinctHash.GetHash(cosmosObject); + return new SqlQueryResumeValue(CosmosObject.Create( + new Dictionary() + { + { PropertyNames.Type, CosmosString.Create(PropertyNames.ObjectType) }, + { PropertyNames.Low, CosmosNumber64.Create((long)hashValue.GetLow()) }, + { PropertyNames.High, CosmosNumber64.Create((long)hashValue.GetHigh()) } + })); } public SqlQueryResumeValue Visit(CosmosString cosmosString) { - return new StringResumeValue(cosmosString.Value); + return new SqlQueryResumeValue(cosmosString); } } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/CosmosUndefinedQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/CosmosUndefinedQueryTests.cs index 1b44c773fa..ed0db5f3fe 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/CosmosUndefinedQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Query/CosmosUndefinedQueryTests.cs @@ -23,7 +23,11 @@ public sealed class CosmosUndefinedQueryTests : QueryTestsBase private const int IntegerValue = 42; - private const string StringValue = "string"; + private const string StringValue = "string"; + + private const string ArrayValue = "[10, 20]"; + + private const string ObjectValue = "{'type':'object'}"; private static readonly int[] PageSizes = new[] { 5, 10, -1 }; @@ -423,6 +427,14 @@ private static List CreateDocuments(int count) case 4: mixedTypeElement = CosmosString.Create(StringValue); break; + + case 5: + mixedTypeElement = CosmosArray.Parse(ArrayValue); + break; + + case 6: + mixedTypeElement = CosmosObject.Parse(ObjectValue); + break; default: mixedTypeElement = null;