Skip to content

Commit

Permalink
feat!: Change default mappings for CLR type decimal
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The default mapping for values of CLR type decimal was FLOAT64 and it is now Numeric.
  • Loading branch information
amanda-tarafa committed Apr 18, 2024
1 parent 83700dd commit 9824a9c
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 53 deletions.
Expand Up @@ -132,17 +132,17 @@ public void TypeMappings()
var key = new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k1", Value = 3.14m },
new SpannerParameter { ParameterName = "k2", Value = new DateTime(2022, 06, 08) } });

Assert.Equal(new ListValue { Values = { Value.ForNumber(3.14), Value.ForString("2022-06-08T00:00:00Z") } },
Assert.Equal(new ListValue { Values = { Value.ForString("3.14"), Value.ForString("2022-06-08T00:00:00Z") } },
key.ToProtobuf(builder.ConversionOptions));

// Specify the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
Assert.Equal(new ListValue { Values = { Value.ForString("3.14"), Value.ForString("2022-06-08") } },
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal(new ListValue { Values = { Value.ForNumber(3.14), Value.ForString("2022-06-08") } },
key.ToProtobuf(builder.ConversionOptions));

// Revert the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal(new ListValue { Values = { Value.ForNumber(3.14), Value.ForString("2022-06-08T00:00:00Z") } },
Assert.Equal(new ListValue { Values = { Value.ForString("3.14"), Value.ForString("2022-06-08T00:00:00Z") } },
key.ToProtobuf(builder.ConversionOptions));
}

Expand All @@ -152,15 +152,15 @@ public void ToString_()
var builder = new SpannerConnectionStringBuilder();
var key = new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k1", Value = 3.14m },
new SpannerParameter { ParameterName = "k2", Value = new DateTime(2022, 06, 08) } });
Assert.Equal("[ 3.14, \"2022-06-08T00:00:00Z\" ]", key.ToString(builder));
Assert.Equal("[ \"3.14\", \"2022-06-08T00:00:00Z\" ]", key.ToString(builder));

// Specify the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
Assert.Equal("[ \"3.14\", \"2022-06-08\" ]", key.ToString(builder));
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal("[ 3.14, \"2022-06-08\" ]", key.ToString(builder));

// Revert the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal("[ 3.14, \"2022-06-08T00:00:00Z\" ]", key.ToString(builder));
Assert.Equal("[ \"3.14\", \"2022-06-08T00:00:00Z\" ]", key.ToString(builder));
}
}

Expand Down Expand Up @@ -264,8 +264,8 @@ public void TypeMappings()

Assert.Equal(new V1.KeyRange
{
StartClosed = new ListValue { Values = { new[] { new Value { NumberValue = 3.14 } } } },
EndOpen = new ListValue { Values = { new[] { new Value { NumberValue = 1.71 } } } },
StartClosed = new ListValue { Values = { new[] { new Value { StringValue = "3.14" } } } },
EndOpen = new ListValue { Values = { new[] { new Value { StringValue = "1.71" } } } },
}, range1.ToProtobuf(builder.ConversionOptions));

Assert.Equal(new V1.KeyRange
Expand All @@ -275,11 +275,11 @@ public void TypeMappings()
}, range2.ToProtobuf(builder.ConversionOptions));

// Specifying the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal(new V1.KeyRange
{
StartClosed = new ListValue { Values = { new[] { new Value { StringValue = "3.14" } } } },
EndOpen = new ListValue { Values = { new[] { new Value { StringValue = "1.71" } } } },
StartClosed = new ListValue { Values = { new[] { new Value { NumberValue = 3.14 } } } },
EndOpen = new ListValue { Values = { new[] { new Value { NumberValue = 1.71 } } } },
}, range1.ToProtobuf(builder.ConversionOptions));

Assert.Equal(new V1.KeyRange
Expand All @@ -292,8 +292,8 @@ public void TypeMappings()
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal(new V1.KeyRange
{
StartClosed = new ListValue { Values = { new[] { new Value { NumberValue = 3.14 } } } },
EndOpen = new ListValue { Values = { new[] { new Value { NumberValue = 1.71 } } } },
StartClosed = new ListValue { Values = { new[] { new Value { StringValue = "3.14" } } } },
EndOpen = new ListValue { Values = { new[] { new Value { StringValue = "1.71" } } } },
}, range1.ToProtobuf(builder.ConversionOptions));

Assert.Equal(new V1.KeyRange
Expand All @@ -312,17 +312,17 @@ public void ToString_()
var range2 = KeyRange.ClosedClosed(new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k3", Value = new DateTime(2022, 06, 08) } }),
new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k4", Value = new DateTime(2024, 06, 08) } }));

Assert.Equal("[[ 3.14 ], [ 1.71 ])", range1.ToString(builder));
Assert.Equal("[[ \"3.14\" ], [ \"1.71\" ])", range1.ToString(builder));
Assert.Equal("[[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]", range2.ToString(builder));

// Specify the type mappings.(Numeric for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
Assert.Equal("[[ \"3.14\" ], [ \"1.71\" ])", range1.ToString(builder));
// Specify the type mappings. (double for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal("[[ 3.14 ], [ 1.71 ])", range1.ToString(builder));
Assert.Equal("[[ \"2022-06-08\" ], [ \"2024-06-08\" ]]", range2.ToString(builder));

// Revert to default. (double for decimal, Timestamp for DateTime)
// Revert to default. (Numeric for decimal, Timestamp for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal("[[ 3.14 ], [ 1.71 ])", range1.ToString(builder));
Assert.Equal("[[ \"3.14\" ], [ \"1.71\" ])", range1.ToString(builder));
Assert.Equal("[[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]", range2.ToString(builder));
}
}
Expand Down Expand Up @@ -358,19 +358,19 @@ public void TypeMappings()
new SpannerParameter { ParameterName = "k2", Value = new DateTime(2022, 06, 08) } });

var protobufValues = keySet.ToProtobuf(builder.ConversionOptions);
Assert.Equal(3.14d, protobufValues.Keys[0].Values[0].NumberValue); // default to double.
Assert.Equal("3.14", protobufValues.Keys[0].Values[0].StringValue); // default to Numeric.
Assert.Equal("2022-06-08T00:00:00Z", protobufValues.Keys[0].Values[1].StringValue); // default to Timestamp.

// Specifying the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
protobufValues = keySet.ToProtobuf(builder.ConversionOptions);
Assert.Equal("3.14", protobufValues.Keys[0].Values[0].StringValue); // Numeric string.
Assert.Equal(3.14d, protobufValues.Keys[0].Values[0].NumberValue); // double value.
Assert.Equal("2022-06-08", protobufValues.Keys[0].Values[1].StringValue); // Date string.

// Revert the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "";
protobufValues = keySet.ToProtobuf(builder.ConversionOptions);
Assert.Equal(3.14d, protobufValues.Keys[0].Values[0].NumberValue); // default to double.
Assert.Equal("3.14", protobufValues.Keys[0].Values[0].StringValue); // default to Numeric.
Assert.Equal("2022-06-08T00:00:00Z", protobufValues.Keys[0].Values[1].StringValue); // default to Timestamp.
}

Expand All @@ -394,17 +394,17 @@ public void ToStringKeySetWithBuilder()
new SpannerParameter { ParameterName = "k2", Value = new DateTime(2022, 06, 08) } });

Assert.Collection(keySet.Keys,
key1 => Assert.Equal("[ 3.14, \"2022-06-08T00:00:00Z\" ]", key1.ToString(builder)));
key1 => Assert.Equal("[ \"3.14\", \"2022-06-08T00:00:00Z\" ]", key1.ToString(builder)));

// Specify the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Collection(keySet.Keys,
key1 => Assert.Equal("[ \"3.14\", \"2022-06-08\" ]", key1.ToString(builder)));
key1 => Assert.Equal("[ 3.14, \"2022-06-08\" ]", key1.ToString(builder)));

// Revert the type mappings.
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Collection(keySet.Keys,
key1 => Assert.Equal("[ 3.14, \"2022-06-08T00:00:00Z\" ]", key1.ToString(builder)));
key1 => Assert.Equal("[ \"3.14\", \"2022-06-08T00:00:00Z\" ]", key1.ToString(builder)));
}

[Fact]
Expand All @@ -427,15 +427,15 @@ public void ToStringKeySetFromKeysWithBuilder()
var keys = KeySet.FromKeys(new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k1", Value = 3.14m } }),
new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k2", Value = new DateTime(2022, 06, 08) } }));

Assert.Equal("KeySet {Keys = [[ 3.14 ], [ \"2022-06-08T00:00:00Z\" ]]}", keys.ToString(builder));
Assert.Equal("KeySet {Keys = [[ \"3.14\" ], [ \"2022-06-08T00:00:00Z\" ]]}", keys.ToString(builder));

// Specify the type mappings.(Numeric for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
Assert.Equal("KeySet {Keys = [[ \"3.14\" ], [ \"2022-06-08\" ]]}", keys.ToString(builder));
// Specify the type mappings. (double for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal("KeySet {Keys = [[ 3.14 ], [ \"2022-06-08\" ]]}", keys.ToString(builder));

// Revert to default. (double for decimal, Timestamp for DateTime)
// Revert to default. (Numeric for decimal, Timestamp for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal("KeySet {Keys = [[ 3.14 ], [ \"2022-06-08T00:00:00Z\" ]]}", keys.ToString(builder));
Assert.Equal("KeySet {Keys = [[ \"3.14\" ], [ \"2022-06-08T00:00:00Z\" ]]}", keys.ToString(builder));
}

[Fact]
Expand All @@ -456,15 +456,15 @@ public void ToStringKeySetFromRangesWithBuilder()
KeyRange.ClosedClosed(new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k3", Value = new DateTime(2022, 06, 08) } }),
new Key(new SpannerParameterCollection { new SpannerParameter { ParameterName = "k4", Value = new DateTime(2024, 06, 08) } })));

Assert.Equal("KeySet {Ranges = [[[ 3.14 ], [ 1.71 ]), [[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]]}", ranges.ToString(builder));
Assert.Equal("KeySet {Ranges = [[[ \"3.14\" ], [ \"1.71\" ]), [[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]]}", ranges.ToString(builder));

// Specify the type mappings.(Numeric for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToNumeric,DateTimeToDate";
Assert.Equal("KeySet {Ranges = [[[ \"3.14\" ], [ \"1.71\" ]), [[ \"2022-06-08\" ], [ \"2024-06-08\" ]]]}", ranges.ToString(builder));
// Specify the type mappings. (double for decimal, Date for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "DecimalToFloat64,DateTimeToDate";
Assert.Equal("KeySet {Ranges = [[[ 3.14 ], [ 1.71 ]), [[ \"2022-06-08\" ], [ \"2024-06-08\" ]]]}", ranges.ToString(builder));

// Revert to default. (double for decimal, Timestamp for DateTime)
// Revert to default. (Numeric for decimal, Timestamp for DateTime)
builder.ClrToSpannerTypeDefaultMappings = "";
Assert.Equal("KeySet {Ranges = [[[ 3.14 ], [ 1.71 ]), [[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]]}", ranges.ToString(builder));
Assert.Equal("KeySet {Ranges = [[[ \"3.14\" ], [ \"1.71\" ]), [[ \"2022-06-08T00:00:00Z\" ], [ \"2024-06-08T00:00:00Z\" ]]]}", ranges.ToString(builder));
}
}
}
Expand Up @@ -1368,7 +1368,7 @@ public static IEnumerable<object[]> ConfiguredSpannerDbTypes()
{
// Format : ClrToSpannerTypeDefaultMappings value, Parameter value, expected SpannerDbType.
// Decimal mappings.
yield return new object[] { default, 3.14m, SpannerDbType.Float64 };
yield return new object[] { default, 3.14m, SpannerDbType.Numeric };
yield return new object[] { DecimalToFloat64, 3.14m, SpannerDbType.Float64 };
yield return new object[] { DecimalToNumeric, 3.14m, SpannerDbType.Numeric };
yield return new object[] { DecimalToPgNumeric, 3.14m, SpannerDbType.PgNumeric };
Expand Down
Expand Up @@ -26,7 +26,7 @@ public void Defaults()

Assert.True(options.UseDBNull);
Assert.Equal(SpannerDbType.Float32, options.SingleToConfiguredSpannerType);
Assert.Equal(SpannerDbType.Float64, options.DecimalToConfiguredSpannerType);
Assert.Equal(SpannerDbType.Numeric, options.DecimalToConfiguredSpannerType);
Assert.Equal(SpannerDbType.Timestamp, options.DateTimeToConfiguredSpannerType);
Assert.Equal(typeof(DateTime), options.DateToConfiguredClrType);
}
Expand Down
Expand Up @@ -70,7 +70,8 @@ public static IEnumerable<object[]> GetValueConversions()
yield return new object[] { 2.718f, SpannerDbType.Float32, DbType.Single, typeof(float) };

yield return new object[] { 3.14d, SpannerDbType.Float64, DbType.Double, typeof(double) };
yield return new object[] { 3.14m, SpannerDbType.Float64, DbType.Double, typeof(double) };

yield return new object[] { 3.14m, SpannerDbType.Numeric, DbType.VarNumeric, typeof(SpannerNumeric) };

yield return new object[] { (short)1, SpannerDbType.Int64, DbType.Int64, typeof(long) };
yield return new object[] { (ushort)1, SpannerDbType.Int64, DbType.Int64, typeof(long) };
Expand Down Expand Up @@ -208,7 +209,7 @@ public static IEnumerable<object[]> ConfiguredSpannerDbTypes()
yield return new object[] { new SpannerParameter { Value = 2.718f },
GetSpannerConversionOptions(SingleToFloat64), SpannerDbType.Float64 };
yield return new object[] { new SpannerParameter { Value = 3.14M },
GetSpannerConversionOptions(default), SpannerDbType.Float64 };
GetSpannerConversionOptions(default), SpannerDbType.Numeric };
yield return new object[] { new SpannerParameter { Value = 3.14M },
GetSpannerConversionOptions(DecimalToFloat64), SpannerDbType.Float64 };
yield return new object[] { new SpannerParameter { Value = 3.14M },
Expand Down
Expand Up @@ -139,7 +139,7 @@ internal SpannerConversionOptions WithSpannerToClrMappings(string spannerToClrMa
internal void SetClrToSpannerTypeDefaults()
{
SingleToConfiguredSpannerType = SpannerDbType.Float32;
DecimalToConfiguredSpannerType = SpannerDbType.Float64;
DecimalToConfiguredSpannerType = SpannerDbType.Numeric;
DateTimeToConfiguredSpannerType = SpannerDbType.Timestamp;
}

Expand Down
Expand Up @@ -251,11 +251,6 @@ internal Value ToProtobufValue(object value)
}
if (value is float || value is double || value is decimal)
{
// TODO: Check with Jon if LossOfPrecisionHandling needs to be changed.
// We throw if there's a loss of precision. We could use
// LossOfPrecisionHandling.Truncate but GoogleSQL documentation requests to
// use half-away-from-zero rounding but the SpannerNumeric implementation
// truncates instead.
return Value.ForString(SpannerNumeric.FromDecimal(
Convert.ToDecimal(value, InvariantCulture), LossOfPrecisionHandling.Truncate).ToString());
}
Expand Down
Expand Up @@ -352,7 +352,7 @@ public static SpannerDbType FromClrType(System.Type type)
{
return Float32;
}
if (type == typeof(double) || type == typeof(decimal))
if (type == typeof(double))
{
return Float64;
}
Expand All @@ -361,7 +361,7 @@ public static SpannerDbType FromClrType(System.Type type)
{
return Int64;
}
if (type == typeof(SpannerNumeric))
if (type == typeof(SpannerNumeric) || type == typeof(decimal))
{
return Numeric;
}
Expand Down

0 comments on commit 9824a9c

Please sign in to comment.