Are Avro Union fields supported?
Closed this issue · 6 comments
Trying to generate a model for this example schema that uses a Union of Foo and Bar...
require 'avromatic'
json = '[{
"type": "record",
"name": "Foo",
"fields": [
{"name": "fooMessage", "type": "string"}
]
},
{
"type": "record",
"name": "Bar",
"fields": [
{"name": "barMessage", "type": "string"}
]
},
{
"type": "record",
"name": "Root",
"fields": [
{"name": "header", "type": "string"},
{"name": "message", "type": ["Foo", "Bar"]}
]
}
]
'
Avromatic::Model.model(schema: Avro::Schema.parse(json))
...I encounter an exception:
/Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/attributes.rb:54:in `define_avro_attributes': undefined method `fields' for #<Avro::S
chema::UnionSchema:0x007f9b789eb040> (NoMethodError)
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/attributes.rb:27:in `add_avro_fields'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:57:in `block (2 levels) in define_included_method'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:22:in `include'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:22:in `block in model'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:21:in `initialize'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:21:in `new'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model/builder.rb:21:in `model'
from /Users/ascassidy/.rvm/gems/ruby-2.3.0/gems/avromatic-0.7.0/lib/avromatic/model.rb:47:in `model'
from lib/test/avro/generate.rb:32:in `<main>'
After some initial digging I've come to a couple of conclusions:
- AvroTurf (and/or Avromatic) does not like the syntax where multiple types are defined in an array (though it works fine with the avro-tools.jar utility)
- Avromatic currently only supports union of null and a single type
Can you confirm please? And is point (2) likely to be addressed in the near future? I can try to take a look at it but I'm not a Ruby guy by trade
@cyclops23 Sorry for the delay responding to this.
The json that you have here represents a union type of Foo
, Bar
and Root
at the top-level. Avromatic only works with record types currently. It should provide an error that explains this, and I'll be committing a fix to provide that error.
My suspicion is that you want a model for the Root
record type in this union. To define that type by itself using Avro JSON the Foo
and Bar
definitions must be embedded:
{
"type": "record",
"name": "Root",
"fields": [
{
"name": "header",
"type": "string"
},
{
"name": "message",
"type": [
{
"type": "record",
"name": "Foo",
"fields": [
{
"name": "foo_message",
"type": "string"
}
]
},
{
"type": "record",
"name": "Bar",
"fields": [
{
"name": "bar_message",
"type": "string"
}
]
}
]
}
]
}
Using avro-builder you could define that in Ruby as:
record :Foo do
required :foo_message, :string
end
record :Bar do
required :bar_message, :string
end
record :Root do
required :header, :string
required :message, :union, types: [:Foo, :Bar]
end
However you are correct that Avromatic currently only supports a union of null and one other type, so this type will not work with the current version. It looks like that union functionality is something that we will need in the near future, so I expect that I will be implementing it soon.
I'll keep this issue open and update it when that happens.
Thanks for the follow up!
@cyclops23 I just pushed a pre-release (0.9.0.rc0) that has union support. We'll be testing it with a project internally before it gets an official release.
Pushed another pre-release (0.9.0.rc1) with some fixes for handling nested, complex types.
Union support is marked as experimental, but included in v0.9.0.