avro icon indicating copy to clipboard operation
avro copied to clipboard

Lack of clarity on Register and union

Open lkiii opened this issue 8 months ago • 1 comments

I have a schema:

{
  "type": "record",
  "name": "Event",
  "fields": [
    {
      "name": "type",
      "type": {
        "type": "enum",
        "name": "EventType",
        "symbols": [
          "A",
          "B",
          "UNKNOWN"
        ],
        "default": "UNKNOWN"
      }
    },
    {
      "name": "payload",
      "type": [
        {
          "type": "record",
          "name": "APayload",
          "fields": [
            {
              "name": "a_field",
              "type": "string"
            }
          ]
        },
        {
          "type": "record",
          "name": "BPayload",
          "fields": [
            {
              "name": "b_field",
              "type": "string"
            }
          ]
        }
      ]
    }
  ]
}

Then my logic to test out:

package main

//go:generate go tool avrogen -tags json:snake -pkg main -o event.go event.avsc

import (
	"log"

	"github.com/hamba/avro/v2"
)

func main() {
	schema, err := avro.ParseFiles("event.avsc")
	if err != nil {
		log.Fatal(err)
	}
	events := map[string]Event{
		"A Works":            {Type: "A", Payload: map[string]any{"APayload": &APayload{AField: "value"}}},
		"B Works":            {Type: "B", Payload: map[string]any{"BPayload": &BPayload{BField: "value"}}},
		"A Expected to work": {Type: "A", Payload: &APayload{AField: "value"}},
		"B Expected to work": {Type: "B", Payload: &BPayload{BField: "value"}},
	}
	avro.Register("main.APayload", &APayload{})
	avro.Register("main.BPayload", &BPayload{})
	for testCase, event := range events {
		data, err := avro.Marshal(schema, event)
		if err != nil {
			log.Printf("ERROR Test case '%s' failed with: %v", testCase, err)
		} else {
			log.Printf("Test case '%s' Marshaled successfully: %v", testCase, data)
			var unmarshaledEvent Event
			err = avro.Unmarshal(schema, data, &unmarshaledEvent)
			if err != nil {
				log.Printf("ERROR Test case '%s' failed with: %v", testCase, err)
			}
			log.Printf("Test case '%s' Unmarshaled event: %+v", testCase, unmarshaledEvent)
		}

		log.Printf("Test case '%s' finished\n\n", testCase)
	}
}

and my event type generated with go generate ./...

// Code generated by avro/gen. DO NOT EDIT.
package main

// APayload is a generated struct.
type APayload struct {
	AField string `avro:"a_field" json:"a_field"`
}

// BPayload is a generated struct.
type BPayload struct {
	BField string `avro:"b_field" json:"b_field"`
}

// Event is a generated struct.
type Event struct {
	Type    string `avro:"type" json:"type"`
	Payload any    `avro:"payload" json:"payload"`
}

is there something I could do to avoid that additional interface in the middle?

What does the error Payload: avro: unknown union type main.APayload mean for the items marked with Expected to work?

I was not able to fully understand the approach looking at the readme

lkiii avatar Jun 12 '25 11:06 lkiii

is there something I could do to avoid that additional interface in the middle?

Do no use the generator, which want to use registration instead of maps, as it is more performant.

What does the error Payload: avro: unknown union type main.APayload mean for the items marked with Expected to work?

avro.Register("main.APayload", &APayload{}) is wrong, as there is no avro type main.APayload but instead APayload.

nrwiersma avatar Jun 12 '25 17:06 nrwiersma

Assuming this is solved.

nrwiersma avatar Oct 07 '25 04:10 nrwiersma