Repository: hamba/avro
Pull request #423 (2024-07-30 10:20:17)

Register Go int as long in type resolver
I noticed that `int` types are not resolved as `long` in unions, so I registered it in the type resolver.

Follow-up to https://github.com/hamba/avro/pull/422.
Related to https://github.com/hamba/avro/issues/421.


Patch:
diff --git a/resolver.go b/resolver.go
index aabf466..c1b6ab6 100644
--- a/resolver.go
+++ b/resolver.go
@@ -26,6 +26,7 @@ func NewTypeResolver() *TypeResolver {
 	r.Register(string(Int), int16(0))
 	r.Register(string(Int), int32(0))
 	r.Register(string(Int), int(0))
+	r.Register(string(Long), int(0))
 	r.Register(string(Long), int64(0))
 	r.Register(string(Float), float32(0))
 	r.Register(string(Double), float64(0))


Test patch:
diff --git a/encoder_union_test.go b/encoder_union_test.go
index ca9327a..72c9d6e 100644
--- a/encoder_union_test.go
+++ b/encoder_union_test.go
@@ -550,3 +550,136 @@ func TestEncoder_UnionInterfaceNotInSchema(t *testing.T) {
 
 	assert.Error(t, err)
 }
+
+func TestEncoder_UnionResolver(t *testing.T) {
+	testCases := []struct {
+		name   string
+		schema string
+		value  any
+		want   []byte
+	}{
+		{
+			name:   "Go int8 as Avro int",
+			schema: `["null","int"]`,
+			value:  int8(27),
+			want:   []byte{0x2, 0x36},
+		},
+		{
+			name:   "Go int16 as Avro int",
+			schema: `["null","int"]`,
+			value:  int16(27),
+			want:   []byte{0x2, 0x36},
+		},
+		{
+			name:   "Go int32 as Avro int",
+			schema: `["null","int"]`,
+			value:  int32(27),
+			want:   []byte{0x2, 0x36},
+		},
+		{
+			name:   "Go int as Avro int",
+			schema: `["null","int"]`,
+			value:  int(27),
+			want:   []byte{0x2, 0x36},
+		},
+		{
+			name:   "Go int as Avro long",
+			schema: `["null","long"]`,
+			value:  int(2147483648),
+			want:   []byte{0x2, 0x80, 0x80, 0x80, 0x80, 0x10},
+		},
+		{
+			name:   "Go int64 as Avro long",
+			schema: `["null","long"]`,
+			value:  int64(2147483648),
+			want:   []byte{0x2, 0x80, 0x80, 0x80, 0x80, 0x10},
+		},
+		{
+			name:   "Go float32 as Avro float",
+			schema: `["null","float"]`,
+			value:  float32(1.15),
+			want:   []byte{0x2, 0x33, 0x33, 0x93, 0x3F},
+		},
+		{
+			name:   "Go float64 as Avro float",
+			schema: `["null","double"]`,
+			value:  float64(1.15),
+			want:   []byte{0x2, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F},
+		},
+		{
+			name:   "Go string as Avro string",
+			schema: `["null","string"]`,
+			value:  "foo",
+			want:   []byte{0x2, 0x06, 0x66, 0x6F, 0x6F},
+		},
+		{
+			name:   "Go []byte as Avro bytes",
+			schema: `["null","bytes"]`,
+			value:  []byte{0xEC, 0xAB, 0x44, 0x00},
+			want:   []byte{0x2, 0x08, 0xEC, 0xAB, 0x44, 0x00},
+		},
+		{
+			name:   "Go bool as Avro boolean",
+			schema: `["null","boolean"]`,
+			value:  true,
+			want:   []byte{0x2, 0x01},
+		},
+		{
+			name:   "Go time.Time as Avro int.date",
+			schema: `["null",{"type":"int","logicalType":"date"}]`,
+			value:  time.Date(2920, 1, 2, 0, 0, 0, 0, time.UTC),
+			want:   []byte{0x2, 0xCA, 0xAD, 0x2A},
+		},
+		{
+			name:   "Go time.Duration as Avro int.time-millis",
+			schema: `["null",{"type":"int","logicalType":"time-millis"}]`,
+			value:  123456789 * time.Millisecond,
+			want:   []byte{0x2, 0xAA, 0xB4, 0xDE, 0x75},
+		},
+		{
+			name:   "Go time.Time as Avro long.timestamp-millis",
+			schema: `["null",{"type":"long","logicalType":"timestamp-millis"}]`,
+			value:  time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
+			want:   []byte{0x2, 0x90, 0xB2, 0xAE, 0xC3, 0xEC, 0x5B},
+		},
+		{
+			name:   "Go time.Time as Avro long.timestamp-micros",
+			schema: `["null",{"type":"long","logicalType":"timestamp-micros"}]`,
+			value:  time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
+			want:   []byte{0x2, 0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05},
+		},
+		{
+			name:   "Go time.Duration as Avro long.time-micros",
+			schema: `["null",{"type":"long","logicalType":"time-micros"}]`,
+			value:  123456789123 * time.Microsecond,
+			want:   []byte{0x2, 0x86, 0xEA, 0xC8, 0xE9, 0x97, 0x07},
+		},
+		{
+			name:   "Go big.Rat as Avro bytes.decimal",
+			schema: `["null",{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}]`,
+			value:  big.NewRat(1734, 5),
+			want:   []byte{0x2, 0x6, 0x00, 0x87, 0x78},
+		},
+		{
+			name:   "Go string as Avro string.uuid",
+			schema: `["null",{"type":"string","logicalType":"uuid"}]`,
+			value:  "f36e589a-3a52-492b-b95c-dad345e8d2ac",
+			want:   []byte{0x2, 0x48, 0x66, 0x33, 0x36, 0x65, 0x35, 0x38, 0x39, 0x61, 0x2d, 0x33, 0x61, 0x35, 0x32, 0x2d, 0x34, 0x39, 0x32, 0x62, 0x2d, 0x62, 0x39, 0x35, 0x63, 0x2d, 0x64, 0x61, 0x64, 0x33, 0x34, 0x35, 0x65, 0x38, 0x64, 0x32, 0x61, 0x63},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			defer ConfigTeardown()
+
+			buf := bytes.NewBuffer([]byte{})
+			enc, err := avro.NewEncoder(tc.schema, buf)
+			require.NoError(t, err)
+
+			err = enc.Encode(tc.value)
+
+			require.NoError(t, err)
+			assert.Equal(t, tc.want, buf.Bytes())
+		})
+	}
+}