diff --git a/src/templates.rs b/src/templates.rs index 47166cb..c685672 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -146,6 +146,9 @@ pub const UNION_TEMPLATE: &str = r#" #[serde(remote = "Self")] pub enum {{ name }} { {%- for s in symbols %} + {%- if aliases[s] %} + #[serde(alias = "{{ aliases[s] }}")] + {%- endif %} {{ s }}, {%- endfor %} } @@ -1087,6 +1090,7 @@ impl Templater { let e_name = union_type(union, gen_state, false)?; let mut symbols = vec![]; + let mut aliases = HashMap::new(); let mut visitors = vec![]; for mut sc in schemas { // Resolve potentially nested schema ref @@ -1123,22 +1127,43 @@ impl Templater { format!("{u}({u})", u = union_type(union, gen_state, false)?) } Schema::Record(RecordSchema { - name: Name { name, .. }, + name: Name { name, namespace }, .. }) => { - format!("{rec}({rec})", rec = name.to_upper_camel_case()) + let symbol = format!("{rec}({rec})", rec = name.to_upper_camel_case()); + if let Some(namespace) = namespace { + let full_name = format!("{}.{}", namespace, name); + if aliases.insert(symbol.clone(), full_name).is_some() { + err!("Names must be unique within a Union: '{}'", name)? + } + } + symbol } Schema::Enum(EnumSchema { - name: Name { name, .. }, + name: Name { name, namespace }, .. }) => { - format!("{e}({e})", e = sanitize(name.to_upper_camel_case())) + let symbol = format!("{e}({e})", e = sanitize(name.to_upper_camel_case())); + if let Some(namespace) = namespace { + let full_name = format!("{}.{}", namespace, name); + if aliases.insert(symbol.clone(), full_name).is_some() { + err!("Names must be unique within a Union: '{}'", name)? + } + } + symbol } Schema::Fixed(FixedSchema { - name: Name { name, .. }, + name: Name { name, namespace }, .. }) => { - format!("{f}({f})", f = sanitize(name.to_upper_camel_case())) + let symbol = format!("{f}({f})", f = sanitize(name.to_upper_camel_case())); + if let Some(namespace) = namespace { + let full_name = format!("{}.{}", namespace, name); + if aliases.insert(symbol.clone(), full_name).is_some() { + err!("Names must be unique within a Union: '{}'", name)? + } + } + symbol } Schema::Decimal { .. } => "Decimal(apache_avro::Decimal)".into(), Schema::BigDecimal => "BigDecimal(apache_avro::BigDecimal)".into(), @@ -1223,6 +1248,7 @@ impl Templater { let mut ctx = Context::new(); ctx.insert("name", &e_name); ctx.insert("symbols", &symbols); + ctx.insert("aliases", &aliases); ctx.insert("visitors", &visitors); ctx.insert("use_avro_rs_unions", &self.use_avro_rs_unions); ctx.insert("is_eq_derivable", &gen_state.is_eq_derivable(schema)); diff --git a/tests/invalid.rs b/tests/invalid.rs index 8d1eced..0464d55 100644 --- a/tests/invalid.rs +++ b/tests/invalid.rs @@ -75,3 +75,33 @@ fn bad_default_for_record() { let mut buf = vec![]; g.generate(&src, &mut buf).map_err(|e| panic!("{e}")).ok(); } + +#[test] +#[should_panic(expected = r#"Names must be unique within a Union: 'MyRecord'"#)] +fn duplicate_names_for_union() { + let raw_schema = r#" +[ + { + "type": "record", + "name": "MyRecord", + "namespace": "com.foo", + "fields": [ + { "name": "foo", "type": "string" } + ] + }, + { + "type": "record", + "name": "MyRecord", + "namespace": "com.bar", + "fields": [ + { "name": "bar", "type": "string" } + ] + } +] +"#; + + let g = Generator::new().unwrap(); + let src = Source::SchemaStr(raw_schema); + let mut buf = vec![]; + g.generate(&src, &mut buf).unwrap(); +} diff --git a/tests/schemas/multi_valued_union_records.avsc b/tests/schemas/multi_valued_union_records.avsc index be670b5..0703fb4 100644 --- a/tests/schemas/multi_valued_union_records.avsc +++ b/tests/schemas/multi_valued_union_records.avsc @@ -10,10 +10,12 @@ { "type": "record", "name": "Bar", + "namespace": "com.bar", "fields": [ {"name": "c", "type": "long"} ] }, { "type": "record", "name": "Baz", + "namespace": "com.baz", "fields": [ {"name": "d", "type": "float"} ] } ] } ] diff --git a/tests/schemas/multi_valued_union_records.rs b/tests/schemas/multi_valued_union_records.rs index c8f0194..db80027 100644 --- a/tests/schemas/multi_valued_union_records.rs +++ b/tests/schemas/multi_valued_union_records.rs @@ -13,7 +13,9 @@ pub struct Bar { #[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)] #[serde(remote = "Self")] pub enum UnionBarBaz { + #[serde(alias = "com.bar.Bar")] Bar(Bar), + #[serde(alias = "com.baz.Baz")] Baz(Baz), }