Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unions can't have records? #190

Open
kitsuneninetails opened this issue Jun 21, 2021 · 1 comment
Open

Unions can't have records? #190

kitsuneninetails opened this issue Jun 21, 2021 · 1 comment

Comments

@kitsuneninetails
Copy link

kitsuneninetails commented Jun 21, 2021

As far as I know, the following schema is perfectly acceptable in avro:

{
  "type": "record",
  "name": "Test",
  "fields": [
    {
      "name": "event",
      "type": [
        "null", 
        {
          "type": "record",
          "name": "Updated",
          "fields": [
            {
              "name": "id",
              "type": "string"
            }, 
          ]
        }
      ]
    }

But, the fact that I have a union where one type is not a primitive type (i.e. a record), seems to return "unsupported Union" errors when trying to deserialize (it builds the schema just fine, apparently).

Looking at the code, it indeed has:


            Value::Union(u) => match **u {
                Value::Null => visitor.visit_unit(),
                Value::Boolean(b) => visitor.visit_bool(b),
                Value::Int(i) => visitor.visit_i32(i),
                Value::Long(i) => visitor.visit_i64(i),
                Value::Float(f) => visitor.visit_f32(f),
                Value::Double(d) => visitor.visit_f64(d),
                _ => Err(de::Error::custom("Unsupported union")),
            },

in the deserialize code (deserialize_any).

Why isn't this supported? Wouldn't it be easy to just have the Record type run a recursive parser on the body underneath?

Edit:

I found some code in deserialize struct that has:

        match *self.input {
            Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
            Value::Union(ref inner) => match **inner {
                Value::Record(ref fields) => visitor.visit_map(StructDeserializer::new(fields)),
                _ => Err(de::Error::custom("not a record")),
            },
            _ => Err(de::Error::custom("not a record")),
        }

Is this saying that I have to deserialize unions with records straight into a struct (or, I assume, an Option to handle unions with "null"?)? So, basically, skip the enum in the deserialized data structure and go straight to the one variant that matches the struct?

@lerouxrgd
Copy link
Contributor

Just FYI this should match your schema:

#[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct Updated {
    pub id: String,
}

impl Default for Updated {
    fn default() -> Updated {
        Updated {
            id: String::default(),
        }
    }
}

#[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]
#[serde(default)]
pub struct Test {
    pub event: Option<Updated>,
}

impl Default for Test {
    fn default() -> Test {
        Test {
            event: None,
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants