private Number64 GetObfuscatedNumber(Number64 value)
        {
            Number64 obfuscatedNumber;

            // Leave NaN, Infinity, numbers in epsilon range, and small integers unchanged
            if (value.IsInfinity ||
                (value.IsInteger && (Number64.ToLong(value) == long.MinValue)) ||
                (value.IsInteger && (Math.Abs(Number64.ToLong(value)) < 100)) ||
                (value.IsDouble && (Math.Abs(Number64.ToDouble(value)) < 100) && ((long)Number64.ToDouble(value) == Number64.ToDouble(value))) ||
                (value.IsDouble && (Math.Abs(Number64.ToDouble(value)) <= Double.Epsilon)))
            {
                obfuscatedNumber = value;
            }
            else
            {
                if (!this.obfuscatedNumbers.TryGetValue(value, out obfuscatedNumber))
                {
                    double doubleValue = Number64.ToDouble(value);

                    int sequenceNumber = ++this.numberSequenceNumber;

                    double log10            = Math.Floor(Math.Log10(Math.Abs(doubleValue)));
                    double adjustedSequence = Math.Pow(10, log10) * sequenceNumber / 1e4;

                    obfuscatedNumber = Math.Round(doubleValue, 2) + adjustedSequence;
                    this.obfuscatedNumbers.Add(value, obfuscatedNumber);
                }
            }

            return(obfuscatedNumber);
        }
        public static double ToDouble(this CosmosElement element)
        {
            if (!(element is CosmosNumber cosmosNumber))
            {
                throw new ArgumentException($"Expected cosmos number: {element}.");
            }

            return(Number64.ToDouble(cosmosNumber.Value));
        }
예제 #3
0
 /// <summary>
 /// Writes a number to the internal buffer.
 /// </summary>
 /// <param name="value">The value of the number to write.</param>
 public override void WriteNumberValue(Number64 value)
 {
     if (value.IsInteger)
     {
         this.WriteIntegerInternal(Number64.ToLong(value));
     }
     else
     {
         this.WriteDoubleInternal(Number64.ToDouble(value));
     }
 }
 public override void WriteNumber64Value(Number64 value)
 {
     if (value.IsInteger)
     {
         this.writer.WriteValue(Number64.ToLong(value));
     }
     else
     {
         this.writer.WriteValue(Number64.ToDouble(value));
     }
 }
예제 #5
0
            /// <inheritdoc />
            public override void WriteNumberValue(Number64 value)
            {
                if (value.IsInteger)
                {
                    this.WriteIntegerInternal(Number64.ToLong(value));
                }
                else
                {
                    this.WriteDoubleInternal(Number64.ToDouble(value));
                }

                this.bufferedContexts.Peek().Count++;
            }
예제 #6
0
        private static CosmosElement PerformUnaryNumberOperation(
            Func <double, double> unaryOperation,
            CosmosElement operand)
        {
            if (!(operand is CosmosNumber operandAsNumber))
            {
                return(Undefined);
            }

            double result = unaryOperation(Number64.ToDouble(operandAsNumber.Value));

            return(CosmosNumber64.Create(result));
        }
예제 #7
0
        /// <summary>
        /// Reads the next number token but returns null at the end of an array.
        /// </summary>
        /// <returns>The next number token but returns null at the end of an array.</returns>
        private double?ReadNumberValue()
        {
            this.Read();
            if (this.jsonReader.CurrentTokenType == JsonTokenType.EndArray)
            {
                return(null);
            }

            Number64 value       = this.jsonReader.GetNumberValue();
            double   doubleValue = Number64.ToDouble(value);

            return(doubleValue);
        }
예제 #8
0
        public bool Visit(CosmosNumber cosmosNumber)
        {
            if (cosmosNumber.Value.IsInteger)
            {
                return(false);
            }

            double value = Number64.ToDouble(cosmosNumber.Value);

            return
                (double.IsInfinity(value) ||
                 double.IsNaN(value) ||
                 double.IsNegativeInfinity(value) ||
                 double.IsPositiveInfinity(value));
        }
예제 #9
0
        public override double?AsFloatingPoint()
        {
            double?value;

            if (this.IsFloatingPoint)
            {
                value = Number64.ToDouble(this.GetValue());
            }
            else
            {
                value = null;
            }

            return(value);
        }
        /// <summary>
        /// Reads the next number token but returns null at the end of an array.
        /// </summary>
        /// <returns>The next number token but returns null at the end of an array.</returns>
        private double?ReadNumberValue()
        {
            this.Read();
            double?value;

            if (this.jsonReader.CurrentTokenType == JsonTokenType.EndArray)
            {
                value = null;
            }
            else
            {
                value = Number64.ToDouble(this.jsonReader.GetNumberValue());
            }

            return(value);
        }
        /// <summary>
        /// Adds a local sum to the global sum.
        /// </summary>
        /// <param name="localSum">The local sum.</param>
        public void Aggregate(CosmosElement localSum)
        {
            // If someone tried to add an undefined just set the globalSum to NaN and it will stay that way for the duration of the aggregation.
            if (localSum == null)
            {
                this.globalSum = double.NaN;
            }
            else
            {
                if (!(localSum is CosmosNumber cosmosNumber))
                {
                    throw new ArgumentException("localSum must be a number.");
                }

                this.globalSum += Number64.ToDouble(cosmosNumber.Value);
            }
        }
예제 #12
0
        private static CosmosElement PerformBinaryNumberOperation(
            Func <double, double, double> operation,
            CosmosElement left,
            CosmosElement right)
        {
            if (!(left is CosmosNumber leftAsNumber))
            {
                return(Undefined);
            }

            if (!(right is CosmosNumber rightAsNumber))
            {
                return(Undefined);
            }

            double result = operation(Number64.ToDouble(leftAsNumber.Value), Number64.ToDouble(rightAsNumber.Value));

            return(CosmosNumber64.Create(result));
        }
        public static SqlNumberLiteral Create(Number64 number64)
        {
            SqlNumberLiteral sqlNumberLiteral;

            if (number64.IsDouble)
            {
                if (!SqlNumberLiteral.FrequentDoubles.TryGetValue(Number64.ToDouble(number64), out sqlNumberLiteral))
                {
                    sqlNumberLiteral = new SqlNumberLiteral(number64);
                }
            }
            else
            {
                if (!SqlNumberLiteral.FrequentLongs.TryGetValue(Number64.ToLong(number64), out sqlNumberLiteral))
                {
                    sqlNumberLiteral = new SqlNumberLiteral(number64);
                }
            }

            return(sqlNumberLiteral);
        }
            /// <summary>
            /// Initializes a new instance of the AverageInfo class.
            /// </summary>
            public static TryCatch <AverageInfo> TryCreateFromCosmosElement(CosmosElement cosmosElement)
            {
                if (cosmosElement == null)
                {
                    throw new ArgumentNullException($"{nameof(cosmosElement)} must not be null.");
                }

                if (!(cosmosElement is CosmosObject cosmosObject))
                {
                    return(TryCatch <AverageInfo> .FromException(
                               new ArgumentException($"{nameof(cosmosElement)} must be an object.")));
                }

                double?sum;

                if (cosmosObject.TryGetValue(SumName, out CosmosElement sumPropertyValue))
                {
                    if (!(sumPropertyValue is CosmosNumber cosmosSum))
                    {
                        return(TryCatch <AverageInfo> .FromException(
                                   new ArgumentException($"value for the {SumName} field was not a number")));
                    }

                    sum = Number64.ToDouble(cosmosSum.Value);
                }
                else
                {
                    sum = null;
                }

                if (!cosmosObject.TryGetValue(CountName, out CosmosNumber cosmosCount))
                {
                    return(TryCatch <AverageInfo> .FromException(
                               new ArgumentException($"value for the {CountName} field was not a number")));
                }

                long count = Number64.ToLong(cosmosCount.Value);

                return(TryCatch <AverageInfo> .FromResult(new AverageInfo(sum, count)));
            }
예제 #15
0
        public override Output ExecuteTest(Input input)
        {
            CosmosElement value = input.PartitionKeyValue;

            PartitionKeyHash partitionKeyHashV1;
            PartitionKeyHash partitionKeyHashV2;

            switch (value)
            {
            case null:
                partitionKeyHashV1 = PartitionKeyHash.V1.HashUndefined();
                partitionKeyHashV2 = PartitionKeyHash.V2.HashUndefined();
                break;

            case CosmosNull cosmosNull:
                partitionKeyHashV1 = PartitionKeyHash.V1.HashNull();
                partitionKeyHashV2 = PartitionKeyHash.V2.HashNull();
                break;

            case CosmosBoolean cosmosBoolean:
                partitionKeyHashV1 = PartitionKeyHash.V1.Hash(cosmosBoolean.Value);
                partitionKeyHashV2 = PartitionKeyHash.V2.Hash(cosmosBoolean.Value);
                break;

            case CosmosString cosmosString:
                partitionKeyHashV1 = PartitionKeyHash.V1.Hash(cosmosString.Value);
                partitionKeyHashV2 = PartitionKeyHash.V2.Hash(cosmosString.Value);
                break;

            case CosmosNumber cosmosNumber:
                partitionKeyHashV1 = PartitionKeyHash.V1.Hash(Number64.ToDouble(cosmosNumber.Value));
                partitionKeyHashV2 = PartitionKeyHash.V2.Hash(Number64.ToDouble(cosmosNumber.Value));
                break;

            default:
                throw new ArgumentOutOfRangeException($"Unknown {nameof(CosmosElement)} type: {value.GetType()}.");
            }

            return(new Output(partitionKeyHashV1, partitionKeyHashV2));
        }
예제 #16
0
        /// <summary>
        /// Adds a local sum to the global sum.
        /// </summary>
        /// <param name="localSum">The local sum.</param>
        public void Aggregate(CosmosElement localSum)
        {
            if (double.IsNaN(this.globalSum))
            {
                // Global sum is undefined and nothing is going to change that.
                return;
            }

            // If someone tried to add an undefined just set the globalSum to NaN and it will stay that way for the duration of the aggregation.
            if (localSum == null)
            {
                this.globalSum = double.NaN;
                return;
            }

            if (!(localSum is CosmosNumber cosmosNumber))
            {
                throw new ArgumentException("localSum must be a number.");
            }

            this.globalSum += Number64.ToDouble(cosmosNumber.Value);
        }
        public static TryCatch <IAggregator> TryCreate(CosmosElement requestContinuationToken)
        {
            double partialSum;

            if (requestContinuationToken != null)
            {
                if (!(requestContinuationToken is CosmosNumber cosmosNumber))
                {
                    return(TryCatch <IAggregator> .FromException(
                               new MalformedContinuationTokenException($"Malformed {nameof(SumAggregator)} continuation token: {requestContinuationToken}")));
                }

                partialSum = Number64.ToDouble(cosmosNumber.Value);
            }
            else
            {
                partialSum = 0.0;
            }

            return(TryCatch <IAggregator> .FromResult(
                       new SumAggregator(partialSum)));
        }
예제 #18
0
        public static TryCatch <IAggregator> TryCreate(CosmosElement requestContinuationToken)
        {
            double partialSum;

            if (requestContinuationToken != null)
            {
                if (requestContinuationToken is CosmosNumber cosmosNumber)
                {
                    partialSum = Number64.ToDouble(cosmosNumber.Value);
                }
                else if (requestContinuationToken is CosmosString cosmosString)
                {
                    if (!double.TryParse(
                            cosmosString.Value,
                            NumberStyles.Float | NumberStyles.AllowThousands,
                            CultureInfo.InvariantCulture,
                            out partialSum))
                    {
                        return(TryCatch <IAggregator> .FromException(
                                   new MalformedContinuationTokenException(
                                       $"Malformed {nameof(SumAggregator)} continuation token: {requestContinuationToken}")));
                    }
                }
                else
                {
                    return(TryCatch <IAggregator> .FromException(
                               new MalformedContinuationTokenException(
                                   $"Malformed {nameof(SumAggregator)} continuation token: {requestContinuationToken}")));
                }
            }
            else
            {
                partialSum = 0.0;
            }

            return(TryCatch <IAggregator> .FromResult(
                       new SumAggregator(partialSum)));
        }
        public override void Visit(SqlNumberLiteral sqlNumberLiteral)
        {
            // We have to use InvariantCulture due to number formatting.
            // "1234.1234" is correct while "1234,1234" is incorrect.
            if (sqlNumberLiteral.Value.IsDouble)
            {
                string literalString = sqlNumberLiteral.Value.ToString(CultureInfo.InvariantCulture);
                double literalValue  = 0.0;
                if (!sqlNumberLiteral.Value.IsNaN &&
                    !sqlNumberLiteral.Value.IsInfinity &&
                    (!double.TryParse(literalString, NumberStyles.Number, CultureInfo.InvariantCulture, out literalValue) ||
                     !Number64.ToDouble(sqlNumberLiteral.Value).Equals(literalValue)))
                {
                    literalString = sqlNumberLiteral.Value.ToString("G17", CultureInfo.InvariantCulture);
                }

                this.writer.Write(literalString);
            }
            else
            {
                this.writer.Write(sqlNumberLiteral.Value.ToString(CultureInfo.InvariantCulture));
            }
        }
예제 #20
0
        public async Task TestAggregateFunctionsAsync()
        {
            AggregateTestArgs args = new AggregateTestArgs()
            {
                NumberOfDocsWithSamePartitionKey       = 37,
                NumberOfDocumentsDifferentPartitionKey = 43,
                PartitionKey       = "key",
                UniquePartitionKey = "uniquePartitionKey",
                Field  = "field",
                Values = new object[] { false, true, "abc", "cdfg", "opqrs", "ttttttt", "xyz" },
            };

            List <string> documents = new List <string>(args.NumberOfDocumentsDifferentPartitionKey + args.NumberOfDocsWithSamePartitionKey);

            foreach (object val in args.Values)
            {
                Document doc;
                doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, val);
                doc.SetPropertyValue("id", Guid.NewGuid().ToString());

                documents.Add(doc.ToString());
            }

            for (int i = 0; i < args.NumberOfDocsWithSamePartitionKey; ++i)
            {
                Document doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, args.UniquePartitionKey);
                documents.Add(doc.ToString());
            }

            Random random = new Random();

            for (int i = 0; i < args.NumberOfDocumentsDifferentPartitionKey; ++i)
            {
                Document doc = new Document();
                doc.SetPropertyValue(args.PartitionKey, random.NextDouble());
                documents.Add(doc.ToString());
            }

            await this.CreateIngestQueryDeleteAsync <AggregateTestArgs>(
                ConnectionModes.Direct | ConnectionModes.Gateway,
                CollectionTypes.SinglePartition | CollectionTypes.MultiPartition,
                documents,
                ImplementationAsync,
                args,
                "/" + args.PartitionKey);

            async Task ImplementationAsync(
                Container container,
                IReadOnlyList <CosmosObject> inputDocuments,
                AggregateTestArgs aggregateTestArgs)
            {
                IReadOnlyList <CosmosObject> documentsWherePkIsANumber = inputDocuments
                                                                         .Where(doc =>
                {
                    return(double.TryParse(
                               doc[aggregateTestArgs.PartitionKey].ToString(),
                               out double result));
                })
                                                                         .ToList();
                double numberSum = documentsWherePkIsANumber
                                   .Sum(doc =>
                {
                    if (!doc.TryGetValue(aggregateTestArgs.PartitionKey, out CosmosNumber number))
                    {
                        Assert.Fail("Failed to get partition key from document");
                    }

                    return(Number64.ToDouble(number.Value));
                });
                double count = documentsWherePkIsANumber.Count();

                AggregateQueryArguments[] aggregateQueryArgumentsList = new AggregateQueryArguments[]
                {
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "AVG",
                        ExpectedValue     = CosmosNumber64.Create(numberSum / count),
                        Predicate         = $"IS_NUMBER(r.{aggregateTestArgs.PartitionKey})",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "AVG",
                        ExpectedValue     = null,
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "COUNT",
                        ExpectedValue     = CosmosNumber64.Create(documents.Count()),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "MAX",
                        ExpectedValue     = CosmosString.Create("xyz"),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "MIN",
                        ExpectedValue     = CosmosBoolean.Create(false),
                        Predicate         = "true",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "SUM",
                        ExpectedValue     = CosmosNumber64.Create(numberSum),
                        Predicate         = $"IS_NUMBER(r.{aggregateTestArgs.PartitionKey})",
                    },
                    new AggregateQueryArguments()
                    {
                        AggregateOperator = "SUM",
                        ExpectedValue     = null,
                        Predicate         = $"true",
                    },
                };

                foreach (int maxDoP in new[] { 0, 10 })
                {
                    foreach (AggregateQueryArguments argument in aggregateQueryArgumentsList)
                    {
                        string[] queryFormats = new[]
                        {
                            "SELECT VALUE {0}(r.{1}) FROM r WHERE {2}",
                            "SELECT VALUE {0}(r.{1}) FROM r WHERE {2} ORDER BY r.{1}"
                        };

                        foreach (string queryFormat in queryFormats)
                        {
                            string query = string.Format(
                                CultureInfo.InvariantCulture,
                                queryFormat,
                                argument.AggregateOperator,
                                aggregateTestArgs.PartitionKey,
                                argument.Predicate);
                            string message = string.Format(
                                CultureInfo.InvariantCulture,
                                "query: {0}, data: {1}",
                                query,
                                JsonConvert.SerializeObject(argument));

                            List <CosmosElement> items = await QueryTestsBase.RunQueryAsync(
                                container,
                                query,
                                new QueryRequestOptions()
                            {
                                MaxConcurrency = maxDoP,
                            });

                            if (argument.ExpectedValue == null)
                            {
                                Assert.AreEqual(0, items.Count, message);
                            }
                            else
                            {
                                Assert.AreEqual(1, items.Count, message);
                                CosmosElement expected = argument.ExpectedValue;
                                CosmosElement actual   = items.Single();

                                if ((expected is CosmosNumber expectedNumber) && (actual is CosmosNumber actualNumber))
                                {
                                    Assert.AreEqual(Number64.ToDouble(expectedNumber.Value), Number64.ToDouble(actualNumber.Value), .01);
                                }
                public override SqlScalarExpression Visit(SqlFunctionCallScalarExpression sqlFunctionCallScalarExpression)
                {
                    SqlScalarExpression rewrittenExpression;

                    // If the function call is an aggregate just evaluate the aggregate first and return that
                    if (
                        !sqlFunctionCallScalarExpression.IsUdf &&
                        Enum.TryParse(value: sqlFunctionCallScalarExpression.Name.Value, ignoreCase: true, result: out Aggregate aggregate))
                    {
                        IReadOnlyList <SqlScalarExpression> arguments = sqlFunctionCallScalarExpression.Arguments;
                        if (arguments.Count != 1)
                        {
                            throw new ArgumentException("Aggregates only accept one argument.");
                        }

                        IEnumerable <CosmosElement> results = this.dataSource
                                                              .Select((element) => arguments[0].Accept(
                                                                          ScalarExpressionEvaluator.Singleton,
                                                                          element));

                        // If aggregates are pushed to the index, then we only get back defined results
                        results = results.Where((result) => result != Undefined);

                        CosmosElement aggregationResult;
                        switch (aggregate)
                        {
                        case Aggregate.Min:
                        case Aggregate.Max:
                            if (results.Count() == 0)
                            {
                                aggregationResult = Undefined;
                            }
                            else if (results.Any(result => !Utils.IsPrimitive(result)))
                            {
                                aggregationResult = Undefined;
                            }
                            else
                            {
                                aggregationResult = results.First();
                                foreach (CosmosElement result in results)
                                {
                                    // First compare the types
                                    int comparison = result.CompareTo(aggregationResult);

                                    if (aggregate == Aggregate.Min)
                                    {
                                        if (comparison < 0)
                                        {
                                            aggregationResult = result;
                                        }
                                    }
                                    else if (aggregate == Aggregate.Max)
                                    {
                                        if (comparison > 0)
                                        {
                                            aggregationResult = result;
                                        }
                                    }
                                    else
                                    {
                                        throw new InvalidOperationException("Should not get here");
                                    }
                                }
                            }

                            break;

                        case Aggregate.Avg:
                        case Aggregate.Sum:
                            CosmosNumber sum   = CosmosNumber64.Create(0);
                            double       count = 0;
                            foreach (CosmosElement result in results)
                            {
                                if ((result is CosmosNumber resultAsNumber) && (sum != Undefined))
                                {
                                    sum = CosmosNumber64.Create(Number64.ToDouble(sum.Value) + Number64.ToDouble(resultAsNumber.Value));
                                    count++;
                                }
                                else
                                {
                                    sum = Undefined;
                                }
                            }
예제 #22
0
        /// <summary>
        /// Reads the next token from the reader.
        /// </summary>
        /// <returns>True if a token was read, else false.</returns>
        public override bool Read()
        {
            bool read = this.jsonReader.Read();

            if (!read)
            {
                this.SetToken(JsonToken.None);
                return(false);
            }

            JsonTokenType jsonTokenType = this.jsonReader.CurrentTokenType;
            JsonToken     newtonsoftToken;
            object        value;

            switch (jsonTokenType)
            {
            case JsonTokenType.BeginArray:
                newtonsoftToken = JsonToken.StartArray;
                value           = CosmosDBToNewtonsoftReader.Null;
                break;

            case JsonTokenType.EndArray:
                newtonsoftToken = JsonToken.EndArray;
                value           = CosmosDBToNewtonsoftReader.Null;
                break;

            case JsonTokenType.BeginObject:
                newtonsoftToken = JsonToken.StartObject;
                value           = CosmosDBToNewtonsoftReader.Null;
                break;

            case JsonTokenType.EndObject:
                newtonsoftToken = JsonToken.EndObject;
                value           = CosmosDBToNewtonsoftReader.Null;
                break;

            case JsonTokenType.String:
                newtonsoftToken = JsonToken.String;
                value           = this.jsonReader.GetStringValue();
                break;

            case JsonTokenType.Number:
                Number64 number64Value = this.jsonReader.GetNumberValue();
                if (number64Value.IsInteger)
                {
                    value           = Number64.ToLong(number64Value);
                    newtonsoftToken = JsonToken.Integer;
                }
                else
                {
                    value           = Number64.ToDouble(number64Value);
                    newtonsoftToken = JsonToken.Float;
                }
                break;

            case JsonTokenType.True:
                newtonsoftToken = JsonToken.Boolean;
                value           = CosmosDBToNewtonsoftReader.True;
                break;

            case JsonTokenType.False:
                newtonsoftToken = JsonToken.Boolean;
                value           = CosmosDBToNewtonsoftReader.False;
                break;

            case JsonTokenType.Null:
                newtonsoftToken = JsonToken.Null;
                value           = CosmosDBToNewtonsoftReader.Null;
                break;

            case JsonTokenType.FieldName:
                newtonsoftToken = JsonToken.PropertyName;
                value           = this.jsonReader.GetStringValue();
                break;

            case JsonTokenType.Int8:
                newtonsoftToken = JsonToken.Integer;
                value           = this.jsonReader.GetInt8Value();
                break;

            case JsonTokenType.Int16:
                newtonsoftToken = JsonToken.Integer;
                value           = this.jsonReader.GetInt16Value();
                break;

            case JsonTokenType.Int32:
                newtonsoftToken = JsonToken.Integer;
                value           = this.jsonReader.GetInt32Value();
                break;

            case JsonTokenType.Int64:
                newtonsoftToken = JsonToken.Integer;
                value           = this.jsonReader.GetInt64Value();
                break;

            case JsonTokenType.UInt32:
                newtonsoftToken = JsonToken.Integer;
                value           = this.jsonReader.GetUInt32Value();
                break;

            case JsonTokenType.Float32:
                newtonsoftToken = JsonToken.Float;
                value           = this.jsonReader.GetFloat32Value();
                break;

            case JsonTokenType.Float64:
                newtonsoftToken = JsonToken.Float;
                value           = this.jsonReader.GetFloat64Value();
                break;

            case JsonTokenType.Guid:
                newtonsoftToken = JsonToken.String;
                value           = this.jsonReader.GetGuidValue().ToString();
                break;

            case JsonTokenType.Binary:
                newtonsoftToken = JsonToken.Bytes;
                value           = this.jsonReader.GetBinaryValue().ToArray();
                break;

            default:
                throw new ArgumentException($"Unexpected jsonTokenType: {jsonTokenType}");
            }

            this.SetToken(newtonsoftToken, value);
            return(read);
        }
 public override SqlObject Visit(SqlNumberLiteral sqlNumberLiteral)
 {
     return(SqlNumberLiteral.Create(
                Number64.ToDouble(
                    this.GetObfuscatedNumber(sqlNumberLiteral.Value))));
 }
        /// <summary>
        /// Compares to objects and returns their partial sort relationship.
        /// </summary>
        /// <param name="element1">The first element to compare.</param>
        /// <param name="element2">The second element to compare.</param>
        /// <returns>
        /// Less than zero if obj1 comes before obj2 in the sort order.
        /// Zero if obj1 and obj2 are interchangeable in the sort order.
        /// Greater than zero if obj2 comes before obj1 in the sort order.
        /// </returns>
        public int Compare(CosmosElement element1, CosmosElement element2)
        {
            if (object.ReferenceEquals(element1, element2))
            {
                return(0);
            }

            if (object.ReferenceEquals(element1, MinValueItem.Singleton))
            {
                return(-1);
            }

            if (object.ReferenceEquals(element2, MinValueItem.Singleton))
            {
                return(1);
            }

            if (object.ReferenceEquals(element1, MaxValueItem.Singleton))
            {
                return(1);
            }

            if (object.ReferenceEquals(element2, MaxValueItem.Singleton))
            {
                return(-1);
            }

            if (element1 == Undefined)
            {
                return(-1);
            }

            if (element2 == Undefined)
            {
                return(1);
            }

            CosmosElementType type1 = element1.Type;

            int cmp = CompareTypes(element1, element2);

            if (cmp == 0)
            {
                // If they are the same type then you need to break the tie.
                switch (type1)
                {
                case CosmosElementType.Boolean:
                    cmp = Comparer <bool> .Default.Compare(
                        (element1 as CosmosBoolean).Value,
                        (element2 as CosmosBoolean).Value);

                    break;

                case CosmosElementType.Null:
                    // All nulls are the same.
                    cmp = 0;
                    break;

                case CosmosElementType.Number:
                    CosmosNumber number1 = element1 as CosmosNumber;
                    CosmosNumber number2 = element2 as CosmosNumber;
                    if (number1.NumberType == CosmosNumberType.Number64)
                    {
                        // Both are Number64, so compare as Number64
                        cmp = number1.Value.CompareTo(number2.Value);
                    }
                    else
                    {
                        // We have a number with precision
                        if (number2.Value.IsInteger)
                        {
                            // compare as longs, since all types have an implicit conversion with full fidelity.
                            long integer1 = Number64.ToLong(number1.Value);
                            long integer2 = Number64.ToLong(number2.Value);
                            cmp = Comparer <long> .Default.Compare(integer1, integer2);
                        }
                        else
                        {
                            // compare as doubles, since all types have an implicit conversion with full fidelity.
                            double double1 = Number64.ToDouble(number1.Value);
                            double double2 = Number64.ToDouble(number2.Value);
                            cmp = Comparer <double> .Default.Compare(double1, double2);
                        }
                    }

                    break;

                case CosmosElementType.String:
                    CosmosString string1 = element1 as CosmosString;
                    CosmosString string2 = element2 as CosmosString;
                    cmp = string.CompareOrdinal(
                        string1.Value,
                        string2.Value);
                    break;

                case CosmosElementType.Guid:
                    CosmosGuid guid1 = element1 as CosmosGuid;
                    CosmosGuid guid2 = element2 as CosmosGuid;
                    cmp = guid1.Value.CompareTo(guid2.Value);
                    break;

                case CosmosElementType.Binary:
                    CosmosBinary binary1 = element1 as CosmosBinary;
                    CosmosBinary binary2 = element2 as CosmosBinary;
                    cmp = ItemComparer.CompareTo(binary1, binary2);
                    break;

                case CosmosElementType.Array:
                case CosmosElementType.Object:
                {
                    UInt128 hash1 = DistinctHash.GetHash(element1);
                    UInt128 hash2 = DistinctHash.GetHash(element2);
                    return(hash1.CompareTo(hash2));
                }

                default:
                    throw new ArgumentException($"Unknown: {nameof(CosmosElementType)}: {type1}");
                }
            }

            return(cmp);
        }
 public override double?AsFloatingPoint()
 {
     return(Number64.ToDouble(this.number));
 }