Repository: hamba/avro
Pull request #265 (2023-06-08 14:46:49)

feat: allow array block contain only length
[#264](https://github.com/hamba/avro/issues/264)

meandnano: One question for another potential PR. Right now there's no way to configure `avro.Writer` inside `ocf.Encoder`. I guess it is possible to add `writerConfig API` field to `ocf.encoderConfig` with corresponding `EncoderFunc` and use this config while constructing `avro.Writer` inside `ocf.NewEncoder`.
nrwiersma: I assume it is to expose this option, in which case it would be added like `WithBlockLength`.

Patch:
diff --git a/config.go b/config.go
index a5e79cd..b03a4c6 100644
--- a/config.go
+++ b/config.go
@@ -21,6 +21,13 @@ type Config struct {
 	// This defaults to 100.
 	BlockLength int
 
+	// DisableBlockSizeHeader disables encoding of an array/map size in bytes.
+	// Encoded array/map will be prefixed with only the number of elements in
+	// contrast with default behavior which prefixes them with the number of elements
+	// and the total number of bytes in the array/map. Both approaches are valid according to the
+	// Avro specification, however not all decoders support the latter.
+	DisableBlockSizeHeader bool
+
 	// UnionResolutionError determines if an error will be returned
 	// when a type cannot be resolved while decoding a union.
 	UnionResolutionError bool
diff --git a/writer.go b/writer.go
index 9c8c718..a12d6d0 100644
--- a/writer.go
+++ b/writer.go
@@ -159,7 +159,7 @@ func (w *Writer) WriteString(s string) {
 
 // WriteBlockHeader writes a Block Header to the Writer.
 func (w *Writer) WriteBlockHeader(l, s int64) {
-	if s > 0 {
+	if s > 0 && !w.cfg.config.DisableBlockSizeHeader {
 		w.WriteLong(-l)
 		w.WriteLong(s)
 		return


Test patch:
diff --git a/writer_test.go b/writer_test.go
index cb272eb..428a729 100644
--- a/writer_test.go
+++ b/writer_test.go
@@ -424,9 +424,10 @@ func TestWriter_WriteString(t *testing.T) {
 
 func TestWriter_WriteBlockHeader(t *testing.T) {
 	tests := []struct {
-		len  int64
-		size int64
-		want []byte
+		len         int64
+		size        int64
+		disableSize bool
+		want        []byte
 	}{
 		{
 			len:  64,
@@ -438,10 +439,20 @@ func TestWriter_WriteBlockHeader(t *testing.T) {
 			size: 64,
 			want: []byte{0x7F, 0x80, 0x01},
 		},
+		{
+			len:         64,
+			size:        64,
+			disableSize: true,
+			want:        []byte{0x80, 0x01},
+		},
 	}
 
 	for _, test := range tests {
-		w := avro.NewWriter(nil, 50)
+		cfg := avro.Config{
+			DisableBlockSizeHeader: test.disableSize,
+		}.Freeze()
+
+		w := avro.NewWriter(nil, 50, avro.WithWriterConfig(cfg))
 
 		w.WriteBlockHeader(test.len, test.size)
 
@@ -450,17 +461,47 @@ func TestWriter_WriteBlockHeader(t *testing.T) {
 }
 
 func TestWriter_WriteBlockCB(t *testing.T) {
-	w := avro.NewWriter(nil, 50)
+	tests := []struct {
+		disableSize   bool
+		writeCallback func(w *avro.Writer) int64
+		want          []byte
+		wantLen       int64
+	}{
+		{
+			writeCallback: func(w *avro.Writer) int64 {
+				w.WriteString("foo")
+				w.WriteString("avro")
 
-	wrote := w.WriteBlockCB(func(w *avro.Writer) int64 {
-		w.WriteString("foo")
-		w.WriteString("avro")
+				return 2
+			},
+			want:    []byte{0x03, 0x12, 0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F},
+			wantLen: 2,
+		},
+		{
+			disableSize: true,
+			writeCallback: func(w *avro.Writer) int64 {
+				w.WriteString("foo")
+				w.WriteString("avro")
 
-		return 2
-	})
+				return 2
+			},
+			want:    []byte{0x04, 0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F},
+			wantLen: 2,
+		},
+	}
+
+	for _, test := range tests {
+		cfg := avro.Config{
+			DisableBlockSizeHeader: test.disableSize,
+		}.Freeze()
 
-	assert.Equal(t, []byte{0x03, 0x12, 0x06, 0x66, 0x6F, 0x6F, 0x08, 0x61, 0x76, 0x72, 0x6F}, w.Buffer())
-	assert.Equal(t, int64(2), wrote)
+		w := avro.NewWriter(nil, 50, avro.WithWriterConfig(cfg))
+
+		wrote := w.WriteBlockCB(test.writeCallback)
+
+		assert.Equal(t, test.want, w.Buffer())
+		assert.Equal(t, test.wantLen, wrote)
+	}
 }
 
 type errorWriter struct{}