Example #1
0
        private object ConvertToClrTypeImpl(Value wireValue, System.Type targetClrType, SpannerConversionOptions options)
        {
            //If the wireValue itself is assignable to the target type, just return it
            //This covers both typeof(Value) and typeof(object).
            if (wireValue == null || targetClrType == null || targetClrType == typeof(Value))
            {
                return(wireValue);
            }

            if (wireValue.KindCase == Value.KindOneofCase.StructValue)
            {
                throw new InvalidOperationException($"google.protobuf.Struct values are invalid in Spanner");
            }

            // targetClrType should be one of the values returned by DefaultClrType
            if (targetClrType == typeof(bool))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(default(bool));

                case Value.KindOneofCase.StringValue:
                    if (TypeCode == TypeCode.Int64)
                    {
                        return(Convert.ToBoolean(Convert.ToInt64(wireValue.StringValue, InvariantCulture)));
                    }
                    return(Convert.ToBoolean(wireValue.StringValue));

                case Value.KindOneofCase.BoolValue:
                    return(wireValue.BoolValue);

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToBoolean(wireValue.NumberValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(char))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToChar(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToChar(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(char));

                case Value.KindOneofCase.StringValue:
                    if (TypeCode == TypeCode.Int64)
                    {
                        return(Convert.ToChar(Convert.ToInt64(wireValue.StringValue, InvariantCulture)));
                    }
                    return(Convert.ToChar(wireValue.StringValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(long))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToInt64(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToInt64(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(long));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToInt64(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(ulong))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToUInt64(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToUInt64(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(ulong));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToUInt64(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(decimal))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToDecimal(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToDecimal(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(decimal));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToDecimal(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(double))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToDouble(wireValue.BoolValue));

                case Value.KindOneofCase.NullValue:
                    return(default(double));

                case Value.KindOneofCase.NumberValue:
                    return(wireValue.NumberValue);

                case Value.KindOneofCase.StringValue:
                    if (string.Compare(wireValue.StringValue, "NaN", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.NaN);
                    }

                    if (string.Compare(wireValue.StringValue, "Infinity", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.PositiveInfinity);
                    }

                    if (string.Compare(wireValue.StringValue, "-Infinity", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.NegativeInfinity);
                    }

                    return(Convert.ToDouble(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(DateTime))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(XmlConvert.ToDateTime(wireValue.StringValue, XmlDateTimeSerializationMode.Utc));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(Timestamp))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(Protobuf.WellKnownTypes.Timestamp.Parser.ParseJson(wireValue.StringValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(string))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.NumberValue:
                    return(wireValue.NumberValue.ToString(InvariantCulture));

                case Value.KindOneofCase.StringValue:
                    return(wireValue.StringValue);

                case Value.KindOneofCase.BoolValue:
                    return(wireValue.BoolValue.ToString());

                default:
                    return(wireValue.ToString());
                }
            }

            if (targetClrType == typeof(byte[]))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(Convert.FromBase64String(wireValue.StringValue));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            if (targetClrType == typeof(SpannerStruct))
            {
                if (TypeCode != TypeCode.Struct)
                {
                    throw new ArgumentException(
                              $"{targetClrType.FullName} can only be used for struct results");
                }
                if (wireValue.KindCase != Value.KindOneofCase.ListValue)
                {
                    throw new ArgumentException(
                              $"Invalid conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
                var values = wireValue.ListValue.Values;
                // StructFields will definitely be non-null, as we can only construct SpannerDbTypes of structs
                // by passing them fields.
                var ret = new SpannerStruct();
                if (StructFields.Count != values.Count)
                {
                    throw new InvalidOperationException(
                              $"Incorrect number of struct fields. SpannerDbType has {StructFields.Count}; list has {values.Count}");
                }
                // Could use Zip, but this is probably simpler.
                for (int i = 0; i < values.Count; i++)
                {
                    var field = StructFields[i];
                    ret.Add(field.Name, field.Type, field.Type.ConvertToClrType(values[i], typeof(object), options, topLevel: false));
                }
                return(ret);
            }

            // It's questionable as to whether we want to support this, but it does no harm to do so.
            if (typeof(IDictionary).IsAssignableFrom(targetClrType))
            {
                if (targetClrType == typeof(IDictionary))
                {
                    // Default type depends on whether it's a struct or not.
                    targetClrType = TypeCode == TypeCode.Struct
                        ? typeof(Dictionary <string, object>)
                        : typeof(Dictionary <int, object>);
                }
                //a bit of recursion here...
                IDictionary dictionary = (IDictionary)Activator.CreateInstance(targetClrType);
                var         itemType   = targetClrType.GetGenericArguments().Skip(1).FirstOrDefault() ?? typeof(object);
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.ListValue:
                    if (TypeCode == TypeCode.Struct)
                    {
                        for (int i = 0; i < StructFields.Count; i++)
                        {
                            var elementValue = wireValue.ListValue.Values[i];
                            var field        = StructFields[i];
                            dictionary[field.Name] = field.Type.ConvertToClrType(elementValue, itemType, options, topLevel: false);
                        }
                    }
                    else
                    {
                        var i = 0;
                        foreach (var listItemValue in wireValue.ListValue.Values)
                        {
                            dictionary[i] = ArrayElementType.ConvertToClrType(listItemValue, itemType, options, topLevel: false);
                            i++;
                        }
                    }
                    return(dictionary);

                default:
                    throw new ArgumentException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            if (targetClrType.IsArray)
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue: return(null);

                case Value.KindOneofCase.ListValue:
                    var newArray = Array.CreateInstance(
                        targetClrType.GetElementType(),
                        wireValue.ListValue.Values.Count);

                    var i = 0;
                    foreach (var obj in wireValue.ListValue.Values.Select(
                                 x => ArrayElementType.ConvertToClrType(x, targetClrType.GetElementType(), options, topLevel: false)))
                    {
                        newArray.SetValue(obj, i);
                        i++;
                    }
                    return(newArray);

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            if (targetClrType == typeof(SpannerNumeric))
            {
                if (TypeCode != TypeCode.Numeric)
                {
                    throw new ArgumentException($"{targetClrType.FullName} can only be used for numeric results");
                }
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(SpannerNumeric.Parse(wireValue.StringValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            if (typeof(IList).IsAssignableFrom(targetClrType))
            {
                if (targetClrType == typeof(IList))
                {
                    targetClrType = typeof(List <object>);
                }
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue: return(null);

                case Value.KindOneofCase.ListValue:
                    var newList  = (IList)Activator.CreateInstance(targetClrType);
                    var itemType = targetClrType.GetGenericArguments().FirstOrDefault() ?? typeof(object);
                    foreach (var obj in wireValue.ListValue.Values.Select(
                                 x => ArrayElementType.ConvertToClrType(x, itemType, options, topLevel: false)))
                    {
                        newList.Add(obj);
                    }
                    return(newList);

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            throw new ArgumentException(
                      $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
        }
Example #2
0
        private object ConvertToClrTypeImpl(Value wireValue, System.Type targetClrType)
        {
            //If the wireValue itself is assignable to the target type, just return it
            //This covers both typeof(Value) and typeof(object).
            if (wireValue == null || targetClrType == null || targetClrType == typeof(Value))
            {
                return(wireValue);
            }

            //targetClrType should be one of the values returned by GetDefaultClrTypeFromSpannerType
            if (targetClrType == typeof(bool))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(default(bool));

                case Value.KindOneofCase.StringValue:
                    if (TypeCode == TypeCode.Int64)
                    {
                        return(Convert.ToBoolean(Convert.ToInt64(wireValue.StringValue, InvariantCulture)));
                    }
                    return(Convert.ToBoolean(wireValue.StringValue));

                case Value.KindOneofCase.BoolValue:
                    return(wireValue.BoolValue);

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToBoolean(wireValue.NumberValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(char))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToChar(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToChar(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(char));

                case Value.KindOneofCase.StringValue:
                    if (TypeCode == TypeCode.Int64)
                    {
                        return(Convert.ToChar(Convert.ToInt64(wireValue.StringValue, InvariantCulture)));
                    }
                    return(Convert.ToChar(wireValue.StringValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(long))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToInt64(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToInt64(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(long));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToInt64(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(ulong))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToUInt64(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToUInt64(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(ulong));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToUInt64(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(decimal))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToDecimal(wireValue.BoolValue));

                case Value.KindOneofCase.NumberValue:
                    return(Convert.ToDecimal(wireValue.NumberValue));

                case Value.KindOneofCase.NullValue:
                    return(default(decimal));

                case Value.KindOneofCase.StringValue:
                    return(Convert.ToDecimal(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(double))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.BoolValue:
                    return(Convert.ToDouble(wireValue.BoolValue));

                case Value.KindOneofCase.NullValue:
                    return(default(double));

                case Value.KindOneofCase.NumberValue:
                    return(wireValue.NumberValue);

                case Value.KindOneofCase.StringValue:
                    if (string.Compare(wireValue.StringValue, "NaN", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.NaN);
                    }

                    if (string.Compare(wireValue.StringValue, "Infinity", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.PositiveInfinity);
                    }

                    if (string.Compare(wireValue.StringValue, "-Infinity", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return(double.NegativeInfinity);
                    }

                    return(Convert.ToDouble(wireValue.StringValue, InvariantCulture));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(DateTime))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(XmlConvert.ToDateTime(wireValue.StringValue, XmlDateTimeSerializationMode.Utc));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(Timestamp))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(Protobuf.WellKnownTypes.Timestamp.Parser.ParseJson(wireValue.StringValue));

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }

            if (targetClrType == typeof(string))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.NumberValue:
                    return(wireValue.NumberValue.ToString(InvariantCulture));

                case Value.KindOneofCase.StringValue:
                    return(wireValue.StringValue);

                case Value.KindOneofCase.BoolValue:
                    return(wireValue.BoolValue.ToString());

                default:
                    return(wireValue.ToString());
                }
            }

            if (targetClrType == typeof(byte[]))
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue:
                    return(null);

                case Value.KindOneofCase.StringValue:
                    return(Convert.FromBase64String(wireValue.StringValue));

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            if (typeof(IDictionary).IsAssignableFrom(targetClrType))
            {
                if (targetClrType == typeof(IDictionary))
                {
#pragma warning disable DE0006
                    targetClrType = typeof(Hashtable);
#pragma warning restore DE0006
                }
                //a bit of recursion here...
                IDictionary dictionary = (IDictionary)Activator.CreateInstance(targetClrType);
                var         itemType   = targetClrType.GetGenericArguments().Skip(1).FirstOrDefault() ?? typeof(object);
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.StructValue:
                    foreach (var structField in StructMembers)
                    {
                        dictionary[structField.Key] = structField.Value.ConvertToClrType(
                            wireValue.StructValue.Fields[structField.Key], itemType);
                    }

                    return(dictionary);

                case Value.KindOneofCase.ListValue:
                    if (TypeCode == TypeCode.Struct)
                    {
                        for (var i = 0; i < StructOrder?.Count; i++)
                        {
                            dictionary[StructOrder[i]] =
                                StructMembers[StructOrder[i]].ConvertToClrType(wireValue
                                                                               .ListValue.Values[i], itemType);
                        }
                    }
                    else
                    {
                        var i = 0;
                        foreach (var listItemValue in wireValue.ListValue.Values)
                        {
                            dictionary[i] = ArrayElementType.ConvertToClrType(listItemValue, itemType);
                            i++;
                        }
                    }
                    return(dictionary);

                default:
                    throw new ArgumentException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            if (targetClrType.IsArray)
            {
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue: return(null);

                case Value.KindOneofCase.ListValue:
                    var newArray = Array.CreateInstance(
                        targetClrType.GetElementType(),
                        wireValue.ListValue.Values.Count);

                    var i = 0;
                    foreach (var obj in wireValue.ListValue.Values.Select(
                                 x => ArrayElementType.ConvertToClrType(x, targetClrType.GetElementType())))
                    {
                        newArray.SetValue(obj, i);
                        i++;
                    }
                    return(newArray);

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            if (typeof(IList).IsAssignableFrom(targetClrType))
            {
                if (targetClrType == typeof(IList))
                {
                    targetClrType = typeof(List <object>);
                }
                switch (wireValue.KindCase)
                {
                case Value.KindOneofCase.NullValue: return(null);

                case Value.KindOneofCase.ListValue:
                    var newList  = (IList)Activator.CreateInstance(targetClrType);
                    var itemType = targetClrType.GetGenericArguments().FirstOrDefault() ?? typeof(object);
                    foreach (var obj in wireValue.ListValue.Values.Select(
                                 x => ArrayElementType.ConvertToClrType(x, itemType)))
                    {
                        newList.Add(obj);
                    }
                    return(newList);

                default:
                    throw new InvalidOperationException(
                              $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
                }
            }
            throw new ArgumentException(
                      $"Invalid Type conversion from {wireValue.KindCase} to {targetClrType.FullName}");
        }