From 921355a71f21a5899908c878bcedef77b690d548 Mon Sep 17 00:00:00 2001 From: Reda Laanait Date: Sun, 15 Sep 2024 19:46:45 +0100 Subject: [PATCH 1/2] fix: decode in the case of field missing in both writer binary and reader struct --- codec_record.go | 12 +++++++++-- schema_compatibility_test.go | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/codec_record.go b/codec_record.go index 4a01b12..d07a4aa 100644 --- a/codec_record.go +++ b/codec_record.go @@ -76,9 +76,17 @@ func decoderOfStruct(d *decoderContext, schema Schema, typ reflect2.Type) ValDec } } } - - // Skip field if it doesnt exist + // Skip field if it doesn't exist if sf == nil { + // If the field value doesn't exist in the binary, ignore it instead of + // appending a 'SkipDecoder'. + // + // Note: 'SkipDecoder' performs a read and moves the cursor, which, + // in this case, will lead to a dirty read. + if field.action == FieldSetDefault { + continue + } + fields = append(fields, &structFieldDecoder{ decoder: createSkipDecoder(field.Type()), }) diff --git a/schema_compatibility_test.go b/schema_compatibility_test.go index 83485cd..5b862a4 100644 --- a/schema_compatibility_test.go +++ b/schema_compatibility_test.go @@ -976,3 +976,45 @@ func TestSchemaCompatibility_ResolveWithComplexUnion(t *testing.T) { want := map[string]any{"b": []byte("foo")} assert.Equal(t, want, result) } + +func TestSchemaCompatibility_ResolveWithFieldMissingInWriterAndReaderStruct(t *testing.T) { + + w := avro.MustParse(`{ + "type":"record", "name":"test", "namespace": "org.hamba.avro", + "fields":[ + {"name": "a", "type": "string"} + ] + }`) + + r := avro.MustParse(`{ + "type":"record", "name":"test", "namespace": "org.hamba.avro", + "fields":[ + {"name": "a", "type": "string"}, + {"name": "b", "type": "int", "default": 10}, + {"name": "c", "type": "string", "default": "foo"} + ] + }`) + + type TW struct { + A string `avro:"a"` + } + value := TW{A: "abc"} + + b, err := avro.Marshal(w, value) + assert.NoError(t, err) + + sch, err := avro.NewSchemaCompatibility().Resolve(r, w) + assert.NoError(t, err) + + type TR struct { + A string `avro:"a"` + C string `avro:"c"` + } + want := TR{A: "abc", C: "foo"} + + var result TR + err = avro.Unmarshal(sch, b, &result) + assert.NoError(t, err) + + assert.Equal(t, want, result) +} From c45059c9c215987d4e4ec0fb73917291dce26797 Mon Sep 17 00:00:00 2001 From: Reda Laanait Date: Mon, 16 Sep 2024 18:52:14 +0100 Subject: [PATCH 2/2] clean up test --- schema_compatibility_test.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/schema_compatibility_test.go b/schema_compatibility_test.go index 5b862a4..0b48254 100644 --- a/schema_compatibility_test.go +++ b/schema_compatibility_test.go @@ -978,13 +978,12 @@ func TestSchemaCompatibility_ResolveWithComplexUnion(t *testing.T) { } func TestSchemaCompatibility_ResolveWithFieldMissingInWriterAndReaderStruct(t *testing.T) { - w := avro.MustParse(`{ - "type":"record", "name":"test", "namespace": "org.hamba.avro", - "fields":[ - {"name": "a", "type": "string"} - ] - }`) + "type":"record", "name":"test", "namespace": "org.hamba.avro", + "fields":[ + {"name": "a", "type": "string"} + ] + }`) r := avro.MustParse(`{ "type":"record", "name":"test", "namespace": "org.hamba.avro", @@ -995,25 +994,25 @@ func TestSchemaCompatibility_ResolveWithFieldMissingInWriterAndReaderStruct(t *t ] }`) - type TW struct { + type TestW struct { A string `avro:"a"` } - value := TW{A: "abc"} + value := TestW{A: "abc"} b, err := avro.Marshal(w, value) assert.NoError(t, err) - sch, err := avro.NewSchemaCompatibility().Resolve(r, w) + schema, err := avro.NewSchemaCompatibility().Resolve(r, w) assert.NoError(t, err) - type TR struct { + type TestR struct { A string `avro:"a"` C string `avro:"c"` } - want := TR{A: "abc", C: "foo"} + want := TestR{A: "abc", C: "foo"} - var result TR - err = avro.Unmarshal(sch, b, &result) + var result TestR + err = avro.Unmarshal(schema, b, &result) assert.NoError(t, err) assert.Equal(t, want, result)