diff --git a/lang/rust/avro/src/decode.rs b/lang/rust/avro/src/decode.rs index 4f9e7e94556..31b76243a3a 100644 --- a/lang/rust/avro/src/decode.rs +++ b/lang/rust/avro/src/decode.rs @@ -18,7 +18,10 @@ use crate::{ decimal::Decimal, duration::Duration, - schema::{Name, Namespace, ResolvedSchema, Schema}, + schema::{ + DecimalSchema, EnumSchema, FixedSchema, Name, Namespace, RecordSchema, ResolvedSchema, + Schema, + }, types::Value, util::{safe_len, zag_i32, zag_i64}, AvroResult, Error, @@ -98,7 +101,7 @@ pub(crate) fn decode_internal>( } } } - Schema::Decimal { ref inner, .. } => match &**inner { + Schema::Decimal(DecimalSchema { ref inner, .. }) => match &**inner { Schema::Fixed { .. } => { match decode_internal(inner, names, enclosing_namespace, reader)? { Value::Fixed(_, bytes) => Ok(Value::Decimal(Decimal::from(bytes))), @@ -164,7 +167,7 @@ pub(crate) fn decode_internal>( } } } - Schema::Fixed { size, .. } => { + Schema::Fixed(FixedSchema { size, .. }) => { let mut buf = vec![0u8; size]; reader .read_exact(&mut buf) @@ -232,11 +235,11 @@ pub(crate) fn decode_internal>( } Err(io_err) => Err(io_err), }, - Schema::Record { + Schema::Record(RecordSchema { ref name, ref fields, .. - } => { + }) => { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); // Benchmarks indicate ~10% improvement using this method. let mut items = Vec::with_capacity(fields.len()); @@ -254,7 +257,7 @@ pub(crate) fn decode_internal>( } Ok(Value::Record(items)) } - Schema::Enum { ref symbols, .. } => { + Schema::Enum(EnumSchema { ref symbols, .. }) => { Ok(if let Value::Int(raw_index) = decode_int(reader)? { let index = usize::try_from(raw_index) .map_err(|e| Error::ConvertI32ToUsize(e, raw_index))?; @@ -293,7 +296,7 @@ mod tests { use crate::{ decode::decode, encode::{encode, tests::success}, - schema::Schema, + schema::{DecimalSchema, FixedSchema, Schema}, types::{ Value, Value::{Array, Int, Map}, @@ -339,18 +342,18 @@ mod tests { fn test_negative_decimal_value() { use crate::{encode::encode, schema::Name}; use num_bigint::ToBigInt; - let inner = Box::new(Schema::Fixed { + let inner = Box::new(Schema::Fixed(FixedSchema { size: 2, doc: None, name: Name::new("decimal").unwrap(), aliases: None, attributes: Default::default(), - }); - let schema = Schema::Decimal { + })); + let schema = Schema::Decimal(DecimalSchema { inner, precision: 4, scale: 2, - }; + }); let bigint = (-423).to_bigint().unwrap(); let value = Value::Decimal(Decimal::from(bigint.to_signed_bytes_be())); @@ -366,18 +369,18 @@ mod tests { fn test_decode_decimal_with_bigger_than_necessary_size() { use crate::{encode::encode, schema::Name}; use num_bigint::ToBigInt; - let inner = Box::new(Schema::Fixed { + let inner = Box::new(Schema::Fixed(FixedSchema { size: 13, name: Name::new("decimal").unwrap(), aliases: None, doc: None, attributes: Default::default(), - }); - let schema = Schema::Decimal { + })); + let schema = Schema::Decimal(DecimalSchema { inner, precision: 4, scale: 2, - }; + }); let value = Value::Decimal(Decimal::from( ((-423).to_bigint().unwrap()).to_signed_bytes_be(), )); diff --git a/lang/rust/avro/src/encode.rs b/lang/rust/avro/src/encode.rs index 40f4ee0f777..94436b86f72 100644 --- a/lang/rust/avro/src/encode.rs +++ b/lang/rust/avro/src/encode.rs @@ -16,7 +16,10 @@ // under the License. use crate::{ - schema::{Name, Namespace, ResolvedSchema, Schema, SchemaKind}, + schema::{ + DecimalSchema, EnumSchema, FixedSchema, Name, Namespace, RecordSchema, ResolvedSchema, + Schema, SchemaKind, + }, types::{Value, ValueKind}, util::{zig_i32, zig_i64}, AvroResult, Error, @@ -78,8 +81,8 @@ pub(crate) fn encode_internal>( Value::Float(x) => buffer.extend_from_slice(&x.to_le_bytes()), Value::Double(x) => buffer.extend_from_slice(&x.to_le_bytes()), Value::Decimal(decimal) => match schema { - Schema::Decimal { inner, .. } => match *inner.clone() { - Schema::Fixed { size, .. } => { + Schema::Decimal(DecimalSchema { inner, .. }) => match *inner.clone() { + Schema::Fixed(FixedSchema { size, .. }) => { let bytes = decimal.to_sign_extended_bytes_with_len(size).unwrap(); let num_bytes = bytes.len(); if num_bytes != size { @@ -125,7 +128,7 @@ pub(crate) fn encode_internal>( Schema::String | Schema::Uuid => { encode_bytes(s, buffer); } - Schema::Enum { ref symbols, .. } => { + Schema::Enum(EnumSchema { ref symbols, .. }) => { if let Some(index) = symbols.iter().position(|item| item == s) { encode_int(index as i32, buffer); } else { @@ -194,12 +197,12 @@ pub(crate) fn encode_internal>( } } Value::Record(fields) => { - if let Schema::Record { + if let Schema::Record(RecordSchema { ref name, fields: ref schema_fields, ref lookup, .. - } = *schema + }) = *schema { let record_namespace = name.fully_qualified_name(enclosing_namespace).namespace; for (name, value) in fields.iter() { diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs index a035a55ca5a..629647abc5c 100644 --- a/lang/rust/avro/src/schema.rs +++ b/lang/rust/avro/src/schema.rs @@ -98,43 +98,14 @@ pub enum Schema { /// A `union` Avro schema. Union(UnionSchema), /// A `record` Avro schema. - /// - /// The `lookup` table maps field names to their position in the `Vec` - /// of `fields`. - Record { - name: Name, - aliases: Aliases, - doc: Documentation, - fields: Vec, - lookup: BTreeMap, - attributes: BTreeMap, - }, + Record(RecordSchema), /// An `enum` Avro schema. - Enum { - name: Name, - aliases: Aliases, - doc: Documentation, - symbols: Vec, - attributes: BTreeMap, - }, + Enum(EnumSchema), /// A `fixed` Avro schema. - Fixed { - name: Name, - aliases: Aliases, - doc: Documentation, - size: usize, - attributes: BTreeMap, - }, + Fixed(FixedSchema), /// Logical type which represents `Decimal` values. The underlying type is serialized and /// deserialized as `Schema::Bytes` or `Schema::Fixed`. - /// - /// `scale` defaults to 0 and is an integer greater than or equal to 0 and `precision` is an - /// integer greater than 0. - Decimal { - precision: DecimalMetadata, - scale: DecimalMetadata, - inner: Box, - }, + Decimal(DecimalSchema), /// A universally unique identifier, annotating a string. Uuid, /// Logical type which represents the number of days since the unix epoch. @@ -452,7 +423,7 @@ impl<'s> ResolvedSchema<'s> { Self::from_internal(vec![schema], names_ref, enclosing_namespace)? } } - Schema::Enum { name, .. } | Schema::Fixed { name, .. } => { + Schema::Enum(EnumSchema { name, .. }) | Schema::Fixed(FixedSchema { name, .. }) => { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); if names_ref .insert(fully_qualified_name.clone(), schema) @@ -461,7 +432,7 @@ impl<'s> ResolvedSchema<'s> { return Err(Error::AmbiguousSchemaDefinition(fully_qualified_name)); } } - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); if names_ref .insert(fully_qualified_name.clone(), schema) @@ -530,7 +501,7 @@ impl ResolvedOwnedSchema { } Ok(()) } - Schema::Enum { name, .. } | Schema::Fixed { name, .. } => { + Schema::Enum(EnumSchema { name, .. }) | Schema::Fixed(FixedSchema { name, .. }) => { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); if names .insert(fully_qualified_name.clone(), schema.clone()) @@ -541,7 +512,7 @@ impl ResolvedOwnedSchema { Ok(()) } } - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); if names .insert(fully_qualified_name.clone(), schema.clone()) @@ -666,8 +637,72 @@ impl RecordField { } } +/// A description of an Enum schema. +#[derive(Debug, Clone)] +pub struct RecordSchema { + /// The name of the schema + pub name: Name, + /// The aliases of the schema + pub aliases: Aliases, + /// The documentation of the schema + pub doc: Documentation, + /// The set of fields of the schema + pub fields: Vec, + /// The `lookup` table maps field names to their position in the `Vec` + /// of `fields`. + pub lookup: BTreeMap, + /// The custom attributes of the schema + pub attributes: BTreeMap, +} + +/// A description of an Enum schema. +#[derive(Debug, Clone)] +pub struct EnumSchema { + /// The name of the schema + pub name: Name, + /// The aliases of the schema + pub aliases: Aliases, + /// The documentation of the schema + pub doc: Documentation, + /// The set of symbols of the schema + pub symbols: Vec, + /// The custom attributes of the schema + pub attributes: BTreeMap, +} + +/// A description of a Union schema. +#[derive(Debug, Clone)] +pub struct FixedSchema { + /// The name of the schema + pub name: Name, + /// The aliases of the schema + pub aliases: Aliases, + /// The documentation of the schema + pub doc: Documentation, + /// The size of the fixed schema + pub size: usize, + /// The custom attributes of the schema + pub attributes: BTreeMap, +} + +/// A description of a Union schema. +/// +/// `scale` defaults to 0 and is an integer greater than or equal to 0 and `precision` is an +/// integer greater than 0. +#[derive(Debug, Clone)] +pub struct DecimalSchema { + /// The number of digits in the unscaled value + pub precision: DecimalMetadata, + /// The number of digits to the right of the decimal point + pub scale: DecimalMetadata, + /// The inner schema of the decimal (fixed or bytes) + pub inner: Box, +} + +/// A description of a Union schema #[derive(Debug, Clone)] pub struct UnionSchema { + /// The schemas that make up this union pub(crate) schemas: Vec, // Used to ensure uniqueness of schema inputs, and provide constant time finding of the // schema index given a value. @@ -851,9 +886,9 @@ impl Schema { /// Returns the custom attributes (metadata) if the schema supports them. pub fn custom_attributes(&self) -> Option<&BTreeMap> { match self { - Schema::Record { attributes, .. } - | Schema::Enum { attributes, .. } - | Schema::Fixed { attributes, .. } => Some(attributes), + Schema::Record(RecordSchema { attributes, .. }) + | Schema::Enum(EnumSchema { attributes, .. }) + | Schema::Fixed(FixedSchema { attributes, .. }) => Some(attributes), _ => None, } } @@ -862,9 +897,9 @@ impl Schema { pub fn name(&self) -> Option<&Name> { match self { Schema::Ref { ref name, .. } - | Schema::Record { ref name, .. } - | Schema::Enum { ref name, .. } - | Schema::Fixed { ref name, .. } => Some(name), + | Schema::Record(RecordSchema { ref name, .. }) + | Schema::Enum(EnumSchema { ref name, .. }) + | Schema::Fixed(FixedSchema { ref name, .. }) => Some(name), _ => None, } } @@ -960,9 +995,9 @@ impl Parser { ) -> AvroResult { fn get_schema_ref(parsed: &Schema) -> Schema { match &parsed { - Schema::Record { ref name, .. } - | Schema::Enum { ref name, .. } - | Schema::Fixed { ref name, .. } => Schema::Ref { name: name.clone() }, + Schema::Record(RecordSchema { ref name, .. }) + | Schema::Enum(EnumSchema { ref name, .. }) + | Schema::Fixed(FixedSchema { ref name, .. }) => Schema::Ref { name: name.clone() }, _ => parsed.clone(), } } @@ -1116,11 +1151,11 @@ impl Parser { let (precision, scale) = Self::parse_precision_and_scale(complex)?; - return Ok(Schema::Decimal { + return Ok(Schema::Decimal(DecimalSchema { precision, scale, inner, - }); + })); } "uuid" => { logical_verify_type(complex, &[SchemaKind::String], self, enclosing_namespace)?; @@ -1313,14 +1348,14 @@ impl Parser { } } - let schema = Schema::Record { + let schema = Schema::Record(RecordSchema { name, aliases: aliases.clone(), doc: complex.doc(), fields, lookup, attributes: self.get_custom_attributes(complex, vec!["fields"]), - }; + }); self.register_parsed_schema(&fully_qualified_name, &schema, &aliases); Ok(schema) @@ -1387,13 +1422,13 @@ impl Parser { existing_symbols.insert(symbol); } - let schema = Schema::Enum { + let schema = Schema::Enum(EnumSchema { name, aliases: aliases.clone(), doc: complex.doc(), symbols, attributes: self.get_custom_attributes(complex, vec!["symbols"]), - }; + }); self.register_parsed_schema(&fully_qualified_name, &schema, &aliases); @@ -1490,13 +1525,13 @@ impl Parser { let fully_qualified_name = name.fully_qualified_name(enclosing_namespace); let aliases = fix_aliases_namespace(complex.aliases(), &name.namespace); - let schema = Schema::Fixed { + let schema = Schema::Fixed(FixedSchema { name, aliases: aliases.clone(), doc, size: size as usize, attributes: self.get_custom_attributes(complex, vec!["size"]), - }; + }); self.register_parsed_schema(&fully_qualified_name, &schema, &aliases); @@ -1573,13 +1608,13 @@ impl Serialize for Schema { } seq.end() } - Schema::Record { + Schema::Record(RecordSchema { ref name, ref aliases, ref doc, ref fields, .. - } => { + }) => { let mut map = serializer.serialize_map(None)?; map.serialize_entry("type", "record")?; if let Some(ref n) = name.namespace { @@ -1595,12 +1630,12 @@ impl Serialize for Schema { map.serialize_entry("fields", fields)?; map.end() } - Schema::Enum { + Schema::Enum(EnumSchema { ref name, ref symbols, ref aliases, .. - } => { + }) => { let mut map = serializer.serialize_map(None)?; map.serialize_entry("type", "enum")?; if let Some(ref n) = name.namespace { @@ -1614,13 +1649,13 @@ impl Serialize for Schema { } map.end() } - Schema::Fixed { + Schema::Fixed(FixedSchema { ref name, ref doc, ref size, ref aliases, .. - } => { + }) => { let mut map = serializer.serialize_map(None)?; map.serialize_entry("type", "fixed")?; if let Some(ref n) = name.namespace { @@ -1637,11 +1672,11 @@ impl Serialize for Schema { } map.end() } - Schema::Decimal { + Schema::Decimal(DecimalSchema { ref scale, ref precision, ref inner, - } => { + }) => { let mut map = serializer.serialize_map(None)?; map.serialize_entry("type", &*inner.clone())?; map.serialize_entry("logicalType", "decimal")?; @@ -1690,13 +1725,13 @@ impl Serialize for Schema { // the Avro doesn't indicate what the name of the underlying fixed type of a // duration should be or typically is. - let inner = Schema::Fixed { + let inner = Schema::Fixed(FixedSchema { name: Name::new("duration").unwrap(), aliases: None, doc: None, size: 12, attributes: Default::default(), - }; + }); map.serialize_entry("type", &inner)?; map.serialize_entry("logicalType", "duration")?; map.end() @@ -2185,7 +2220,7 @@ mod tests { .unwrap() .clone(); - let schema_c_expected = Schema::Record { + let schema_c_expected = Schema::Record(RecordSchema { name: Name::new("C").unwrap(), aliases: None, doc: None, @@ -2211,7 +2246,7 @@ mod tests { }], lookup: BTreeMap::from_iter(vec![("field_one".to_string(), 0)]), attributes: Default::default(), - }; + }); assert_eq!(schema_c, schema_c_expected); } @@ -2237,7 +2272,7 @@ mod tests { let schema_a = list.first().unwrap().clone(); match schema_a { - Schema::Record { fields, .. } => { + Schema::Record(RecordSchema { fields, .. }) => { let f1 = fields.get(0); let ref_schema = Schema::Ref { @@ -2277,7 +2312,7 @@ mod tests { .unwrap() .clone(); - let schema_option_a_expected = Schema::Record { + let schema_option_a_expected = Schema::Record(RecordSchema { name: Name::new("OptionA").unwrap(), aliases: None, doc: None, @@ -2301,7 +2336,7 @@ mod tests { }], lookup: BTreeMap::from_iter(vec![("field_one".to_string(), 0)]), attributes: Default::default(), - }; + }); assert_eq!(schema_option_a, schema_option_a_expected); } @@ -2326,7 +2361,7 @@ mod tests { lookup.insert("a".to_owned(), 0); lookup.insert("b".to_owned(), 1); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name::new("test").unwrap(), aliases: None, doc: None, @@ -2354,7 +2389,7 @@ mod tests { ], lookup, attributes: Default::default(), - }; + }); assert_eq!(parsed, expected); } @@ -2390,7 +2425,7 @@ mod tests { node_lookup.insert("children".to_owned(), 1); node_lookup.insert("label".to_owned(), 0); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name::new("test").unwrap(), aliases: None, doc: None, @@ -2399,7 +2434,7 @@ mod tests { doc: None, default: None, aliases: None, - schema: Schema::Record { + schema: Schema::Record(RecordSchema { name: Name::new("Node").unwrap(), aliases: None, doc: None, @@ -2429,14 +2464,14 @@ mod tests { ], lookup: node_lookup, attributes: Default::default(), - }, + }), order: RecordFieldOrder::Ascending, position: 0, custom_attributes: Default::default(), }], lookup, attributes: Default::default(), - }; + }); assert_eq!(schema, expected); let canonical_form = &schema.canonical_form(); @@ -2566,7 +2601,7 @@ mod tests { lookup.insert("value".to_owned(), 0); lookup.insert("next".to_owned(), 1); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name { name: "LongList".to_owned(), namespace: None, @@ -2608,7 +2643,7 @@ mod tests { ], lookup, attributes: Default::default(), - }; + }); assert_eq!(schema, expected); let canonical_form = &schema.canonical_form(); @@ -2637,7 +2672,7 @@ mod tests { lookup.insert("value".to_owned(), 0); lookup.insert("next".to_owned(), 1); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name { name: "record".to_owned(), namespace: None, @@ -2673,7 +2708,7 @@ mod tests { ], lookup, attributes: Default::default(), - }; + }); assert_eq!(schema, expected); let canonical_form = &schema.canonical_form(); @@ -2706,7 +2741,7 @@ mod tests { lookup.insert("enum".to_owned(), 0); lookup.insert("next".to_owned(), 1); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name { name: "record".to_owned(), namespace: None, @@ -2719,7 +2754,7 @@ mod tests { doc: None, default: None, aliases: None, - schema: Schema::Enum { + schema: Schema::Enum(EnumSchema { name: Name { name: "enum".to_owned(), namespace: None, @@ -2728,7 +2763,7 @@ mod tests { doc: None, symbols: vec!["one".to_string(), "two".to_string(), "three".to_string()], attributes: Default::default(), - }, + }), order: RecordFieldOrder::Ascending, position: 0, custom_attributes: Default::default(), @@ -2738,7 +2773,7 @@ mod tests { doc: None, default: None, aliases: None, - schema: Schema::Enum { + schema: Schema::Enum(EnumSchema { name: Name { name: "enum".to_owned(), namespace: None, @@ -2747,7 +2782,7 @@ mod tests { doc: None, symbols: vec!["one".to_string(), "two".to_string(), "three".to_string()], attributes: Default::default(), - }, + }), order: RecordFieldOrder::Ascending, position: 1, custom_attributes: Default::default(), @@ -2755,7 +2790,7 @@ mod tests { ], lookup, attributes: Default::default(), - }; + }); assert_eq!(schema, expected); let canonical_form = &schema.canonical_form(); @@ -2788,7 +2823,7 @@ mod tests { lookup.insert("fixed".to_owned(), 0); lookup.insert("next".to_owned(), 1); - let expected = Schema::Record { + let expected = Schema::Record(RecordSchema { name: Name { name: "record".to_owned(), namespace: None, @@ -2801,7 +2836,7 @@ mod tests { doc: None, default: None, aliases: None, - schema: Schema::Fixed { + schema: Schema::Fixed(FixedSchema { name: Name { name: "fixed".to_owned(), namespace: None, @@ -2810,7 +2845,7 @@ mod tests { doc: None, size: 456, attributes: Default::default(), - }, + }), order: RecordFieldOrder::Ascending, position: 0, custom_attributes: Default::default(), @@ -2820,7 +2855,7 @@ mod tests { doc: None, default: None, aliases: None, - schema: Schema::Fixed { + schema: Schema::Fixed(FixedSchema { name: Name { name: "fixed".to_owned(), namespace: None, @@ -2829,7 +2864,7 @@ mod tests { doc: None, size: 456, attributes: Default::default(), - }, + }), order: RecordFieldOrder::Ascending, position: 1, custom_attributes: Default::default(), @@ -2837,7 +2872,7 @@ mod tests { ], lookup, attributes: Default::default(), - }; + }); assert_eq!(schema, expected); let canonical_form = &schema.canonical_form(); @@ -2851,7 +2886,7 @@ mod tests { r#"{"type": "enum", "name": "Suit", "symbols": ["diamonds", "spades", "clubs", "hearts"]}"#, ).unwrap(); - let expected = Schema::Enum { + let expected = Schema::Enum(EnumSchema { name: Name::new("Suit").unwrap(), aliases: None, doc: None, @@ -2862,7 +2897,7 @@ mod tests { "hearts".to_owned(), ], attributes: Default::default(), - }; + }); assert_eq!(expected, schema); } @@ -2889,13 +2924,13 @@ mod tests { fn test_fixed_schema() { let schema = Schema::parse_str(r#"{"type": "fixed", "name": "test", "size": 16}"#).unwrap(); - let expected = Schema::Fixed { + let expected = Schema::Fixed(FixedSchema { name: Name::new("test").unwrap(), aliases: None, doc: None, size: 16usize, attributes: Default::default(), - }; + }); assert_eq!(expected, schema); } @@ -2907,13 +2942,13 @@ mod tests { ) .unwrap(); - let expected = Schema::Fixed { + let expected = Schema::Fixed(FixedSchema { name: Name::new("test").unwrap(), aliases: None, doc: Some(String::from("FixedSchema documentation")), size: 16usize, attributes: Default::default(), - }; + }); assert_eq!(expected, schema); } @@ -2925,7 +2960,7 @@ mod tests { .unwrap(); let doc = match schema { - Schema::Enum { doc, .. } => doc, + Schema::Enum(EnumSchema { doc, .. }) => doc, _ => return, }; @@ -2939,7 +2974,7 @@ mod tests { ).unwrap(); let doc = match schema { - Schema::Enum { doc, .. } => doc, + Schema::Enum(EnumSchema { doc, .. }) => doc, _ => None, }; @@ -3103,7 +3138,7 @@ mod tests { "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, .. } = schema { + if let Schema::Record(RecordSchema { name, .. }) = schema { assert_eq!(name.name, "name"); assert_eq!(name.namespace, Some("space".to_string())); } else { @@ -3128,7 +3163,7 @@ mod tests { "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, .. } = schema { + if let Schema::Record(RecordSchema { name, .. }) = schema { assert_eq!(name.namespace, Some("space1".to_string())); } else { panic!("Expected a record schema!"); @@ -3152,7 +3187,7 @@ mod tests { "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, .. } = schema { + if let Schema::Record(RecordSchema { name, .. }) = schema { assert_eq!(name.namespace, Some("space2".to_string())); } else { panic!("Expected a record schema!"); @@ -3870,7 +3905,7 @@ mod tests { ) .unwrap(); - if let Schema::Record { ref aliases, .. } = schema { + if let Schema::Record(RecordSchema { ref aliases, .. }) = schema { assert_avro_3512_aliases(aliases); } else { panic!("The Schema should be a record: {schema:?}"); @@ -3894,7 +3929,7 @@ mod tests { ) .unwrap(); - if let Schema::Enum { ref aliases, .. } = schema { + if let Schema::Enum(EnumSchema { ref aliases, .. }) = schema { assert_avro_3512_aliases(aliases); } else { panic!("The Schema should be an enum: {schema:?}"); @@ -3916,7 +3951,7 @@ mod tests { ) .unwrap(); - if let Schema::Fixed { ref aliases, .. } = schema { + if let Schema::Fixed(FixedSchema { ref aliases, .. }) = schema { assert_avro_3512_aliases(aliases); } else { panic!("The Schema should be a fixed: {schema:?}"); @@ -4028,7 +4063,7 @@ mod tests { "#; let schema = Schema::parse_str(schema_str).unwrap(); - if let Schema::Record { name, fields, .. } = schema { + if let Schema::Record(RecordSchema { name, fields, .. }) = schema { assert_eq!(name, Name::new("AccountEvent").unwrap()); let field = &fields[0]; @@ -4187,7 +4222,7 @@ mod tests { Schema::parse_str(schema_str.replace("{{{}}}", CUSTOM_ATTRS_SUFFIX).as_str()).unwrap(); match schema { - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { assert_eq!(name, Name::new("Rec").unwrap()); assert_eq!(fields.len(), 1); let field = &fields[0]; @@ -4215,7 +4250,7 @@ mod tests { let schema = Schema::parse_str(&schema_str).unwrap(); match schema { - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { assert_eq!(name, Name::new("union_schema_test").unwrap()); assert_eq!(fields.len(), 1); let field = &fields[0]; @@ -4252,7 +4287,7 @@ mod tests { let schema = Schema::parse_str(&schema_str).unwrap(); match schema { - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { assert_eq!(name, Name::new("union_schema_test").unwrap()); assert_eq!(fields.len(), 1); let field = &fields[0]; @@ -4288,7 +4323,7 @@ mod tests { let schema = Schema::parse_str(&schema_str).unwrap(); match schema { - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { assert_eq!(name, Name::new("union_schema_test").unwrap()); assert_eq!(fields.len(), 1); let field = &fields[0]; @@ -4325,7 +4360,7 @@ mod tests { let schema = Schema::parse_str(&schema_str).unwrap(); match schema { - Schema::Record { name, fields, .. } => { + Schema::Record(RecordSchema { name, fields, .. }) => { assert_eq!(name, Name::new("union_schema_test").unwrap()); assert_eq!(fields.len(), 1); let field = &fields[0]; @@ -4361,7 +4396,7 @@ mod tests { "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { fields, .. } = schema { + if let Schema::Record(RecordSchema { fields, .. }) = schema { let num_field = &fields[0]; assert_eq!(num_field.name, "num"); assert_eq!(num_field.aliases, Some(vec!("num1".into(), "num2".into()))); diff --git a/lang/rust/avro/src/schema_compatibility.rs b/lang/rust/avro/src/schema_compatibility.rs index b691041e543..aad8fde36b9 100644 --- a/lang/rust/avro/src/schema_compatibility.rs +++ b/lang/rust/avro/src/schema_compatibility.rs @@ -16,7 +16,7 @@ // under the License. //! Logic for checking schema compatibility -use crate::schema::{Schema, SchemaKind}; +use crate::schema::{EnumSchema, FixedSchema, RecordSchema, Schema, SchemaKind}; use std::{ collections::{hash_map::DefaultHasher, HashSet}, hash::Hasher, @@ -88,13 +88,13 @@ impl Checker { SchemaKind::Union => self.match_union_schemas(writers_schema, readers_schema), SchemaKind::Enum => { // reader's symbols must contain all writer's symbols - if let Schema::Enum { + if let Schema::Enum(EnumSchema { symbols: w_symbols, .. - } = writers_schema + }) = writers_schema { - if let Schema::Enum { + if let Schema::Enum(EnumSchema { symbols: r_symbols, .. - } = readers_schema + }) = readers_schema { return !w_symbols.iter().any(|e| !r_symbols.contains(e)); } @@ -121,15 +121,15 @@ impl Checker { return false; } - if let Schema::Record { + if let Schema::Record(RecordSchema { fields: w_fields, lookup: w_lookup, .. - } = writers_schema + }) = writers_schema { - if let Schema::Record { + if let Schema::Record(RecordSchema { fields: r_fields, .. - } = readers_schema + }) = readers_schema { for field in r_fields.iter() { if let Some(pos) = w_lookup.get(&field.name) { @@ -219,8 +219,8 @@ impl SchemaCompatibility { match r_type { SchemaKind::Record => { - if let Schema::Record { name: w_name, .. } = writers_schema { - if let Schema::Record { name: r_name, .. } = readers_schema { + if let Schema::Record(RecordSchema { name: w_name, .. }) = writers_schema { + if let Schema::Record(RecordSchema { name: r_name, .. }) = readers_schema { return w_name.fullname(None) == r_name.fullname(None); } else { unreachable!("readers_schema should have been Schema::Record") @@ -230,21 +230,21 @@ impl SchemaCompatibility { } } SchemaKind::Fixed => { - if let Schema::Fixed { + if let Schema::Fixed(FixedSchema { name: w_name, aliases: _, doc: _w_doc, size: w_size, attributes: _, - } = writers_schema + }) = writers_schema { - if let Schema::Fixed { + if let Schema::Fixed(FixedSchema { name: r_name, aliases: _, doc: _r_doc, size: r_size, attributes: _, - } = readers_schema + }) = readers_schema { return w_name.fullname(None) == r_name.fullname(None) && w_size == r_size; @@ -256,8 +256,8 @@ impl SchemaCompatibility { } } SchemaKind::Enum => { - if let Schema::Enum { name: w_name, .. } = writers_schema { - if let Schema::Enum { name: r_name, .. } = readers_schema { + if let Schema::Enum(EnumSchema { name: w_name, .. }) = writers_schema { + if let Schema::Enum(EnumSchema { name: r_name, .. }) = readers_schema { return w_name.fullname(None) == r_name.fullname(None); } else { unreachable!("readers_schema should have been Schema::Enum") diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs index ee322b331a6..d44826be1ef 100644 --- a/lang/rust/avro/src/types.rs +++ b/lang/rust/avro/src/types.rs @@ -20,8 +20,8 @@ use crate::{ decimal::Decimal, duration::Duration, schema::{ - Name, NamesRef, Namespace, Precision, RecordField, ResolvedSchema, Scale, Schema, - SchemaKind, UnionSchema, + DecimalSchema, EnumSchema, FixedSchema, Name, NamesRef, Namespace, Precision, RecordField, + RecordSchema, ResolvedSchema, Scale, Schema, SchemaKind, UnionSchema, }, AvroResult, Error, }; @@ -221,11 +221,11 @@ impl<'a> Record<'a> { /// If the `Schema` is not a `Schema::Record` variant, `None` will be returned. pub fn new(schema: &Schema) -> Option { match *schema { - Schema::Record { + Schema::Record(RecordSchema { fields: ref schema_fields, lookup: ref schema_lookup, .. - } => { + }) => { let mut fields = Vec::with_capacity(schema_fields.len()); for schema_field in schema_fields.iter() { fields.push((schema_field.name.clone(), Value::Null)); @@ -282,7 +282,7 @@ impl From for Value { } /// Convert Avro values to Json values -impl std::convert::TryFrom for JsonValue { +impl TryFrom for JsonValue { type Error = crate::error::Error; fn try_from(value: Value) -> AvroResult { match value { @@ -415,7 +415,7 @@ impl Value { (&Value::Bytes(_), &Schema::Decimal { .. }) => None, (&Value::String(_), &Schema::String) => None, (&Value::String(_), &Schema::Uuid) => None, - (&Value::Fixed(n, _), &Schema::Fixed { size, .. }) => { + (&Value::Fixed(n, _), &Schema::Fixed(FixedSchema { size, .. })) => { if n != size { Some(format!( "The value's size ({n}) is different than the schema's size ({size})" @@ -424,7 +424,7 @@ impl Value { None } } - (Value::Bytes(b), &Schema::Fixed { size, .. }) => { + (Value::Bytes(b), &Schema::Fixed(FixedSchema { size, .. })) => { if b.len() != size { Some(format!( "The bytes' length ({}) is different than the schema's size ({})", @@ -446,14 +446,14 @@ impl Value { } // TODO: check precision against n (&Value::Fixed(_n, _), &Schema::Decimal { .. }) => None, - (Value::String(s), Schema::Enum { symbols, .. }) => { + (Value::String(s), Schema::Enum(EnumSchema { symbols, .. })) => { if !symbols.contains(s) { Some(format!("'{s}' is not a member of the possible symbols")) } else { None } } - (&Value::Enum(i, ref s), Schema::Enum { symbols, .. }) => symbols + (&Value::Enum(i, ref s), Schema::Enum(EnumSchema { symbols, .. })) => symbols .get(i as usize) .map(|ref symbol| { if symbol != &s { @@ -487,7 +487,7 @@ impl Value { ) }) } - (Value::Record(record_fields), Schema::Record { fields, lookup, .. }) => { + (Value::Record(record_fields), Schema::Record(RecordSchema { fields, lookup, .. })) => { let non_nullable_fields_count = fields.iter().filter(|&rf| !rf.is_nullable()).count(); @@ -527,7 +527,7 @@ impl Value { } }) } - (Value::Map(items), Schema::Record { fields, .. }) => { + (Value::Map(items), Schema::Record(RecordSchema { fields, .. })) => { fields.iter().fold(None, |acc, field| { if let Some(item) = items.get(&field.name) { let res = item.validate_internal(&field.schema, names, enclosing_namespace); @@ -598,19 +598,19 @@ impl Value { Schema::Double => self.resolve_double(), Schema::Bytes => self.resolve_bytes(), Schema::String => self.resolve_string(), - Schema::Fixed { size, .. } => self.resolve_fixed(size), + Schema::Fixed(FixedSchema { size, .. }) => self.resolve_fixed(size), Schema::Union(ref inner) => self.resolve_union(inner, names, enclosing_namespace), - Schema::Enum { ref symbols, .. } => self.resolve_enum(symbols), + Schema::Enum(EnumSchema { ref symbols, .. }) => self.resolve_enum(symbols), Schema::Array(ref inner) => self.resolve_array(inner, names, enclosing_namespace), Schema::Map(ref inner) => self.resolve_map(inner, names, enclosing_namespace), - Schema::Record { ref fields, .. } => { + Schema::Record(RecordSchema { ref fields, .. }) => { self.resolve_record(fields, names, enclosing_namespace) } - Schema::Decimal { + Schema::Decimal(DecimalSchema { scale, precision, ref inner, - } => self.resolve_decimal(precision, scale, inner), + }) => self.resolve_decimal(precision, scale, inner), Schema::Date => self.resolve_date(), Schema::TimeMillis => self.resolve_time_millis(), Schema::TimeMicros => self.resolve_time_micros(), @@ -657,7 +657,7 @@ impl Value { return Err(Error::GetScaleAndPrecision { scale, precision }); } match inner { - &Schema::Fixed { size, .. } => { + &Schema::Fixed(FixedSchema { size, .. }) => { if max_prec_for_len(size)? < precision { return Err(Error::GetScaleWithFixedSize { size, precision }); } @@ -960,7 +960,7 @@ impl Value { Some(value) => value, None => match field.default { Some(ref value) => match field.schema { - Schema::Enum { ref symbols, .. } => { + Schema::Enum(EnumSchema { ref symbols, .. }) => { Value::from(value.clone()).resolve_enum(symbols)? } Schema::Union(ref union_schema) => { @@ -1106,7 +1106,7 @@ mod tests { ), ( Value::Record(vec![("unknown_field_name".to_string(), Value::Null)]), - Schema::Record { + Schema::Record(RecordSchema { name: Name::new("record_name").unwrap(), aliases: None, doc: None, @@ -1122,13 +1122,13 @@ mod tests { }], lookup: Default::default(), attributes: Default::default(), - }, + }), false, - r#"Invalid value: Record([("unknown_field_name", Null)]) for schema: Record { name: Name { name: "record_name", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: None, default: None, schema: Int, order: Ignore, position: 0, custom_attributes: {} }], lookup: {}, attributes: {} }. Reason: There is no schema field for field 'unknown_field_name'"#, + r#"Invalid value: Record([("unknown_field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: None, default: None, schema: Int, order: Ignore, position: 0, custom_attributes: {} }], lookup: {}, attributes: {} }). Reason: There is no schema field for field 'unknown_field_name'"#, ), ( Value::Record(vec![("field_name".to_string(), Value::Null)]), - Schema::Record { + Schema::Record(RecordSchema { name: Name::new("record_name").unwrap(), aliases: None, doc: None, @@ -1146,9 +1146,9 @@ mod tests { }], lookup: [("field_name".to_string(), 0)].iter().cloned().collect(), attributes: Default::default(), - }, + }), false, - r#"Invalid value: Record([("field_name", Null)]) for schema: Record { name: Name { name: "record_name", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: None, default: None, schema: Ref { name: Name { name: "missing", namespace: None } }, order: Ignore, position: 0, custom_attributes: {} }], lookup: {"field_name": 0}, attributes: {} }. Reason: Unresolved schema reference: 'Name { name: "missing", namespace: None }'. Parsed names: []"#, + r#"Invalid value: Record([("field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "field_name", doc: None, aliases: None, default: None, schema: Ref { name: Name { name: "missing", namespace: None } }, order: Ignore, position: 0, custom_attributes: {} }], lookup: {"field_name": 0}, attributes: {} }). Reason: Unresolved schema reference: 'Name { name: "missing", namespace: None }'. Parsed names: []"#, ), ]; @@ -1170,13 +1170,13 @@ mod tests { #[test] fn validate_fixed() { - let schema = Schema::Fixed { + let schema = Schema::Fixed(FixedSchema { size: 4, name: Name::new("some_fixed").unwrap(), aliases: None, doc: None, attributes: Default::default(), - }; + }); assert!(Value::Fixed(4, vec![0, 0, 0, 0]).validate(&schema)); let value = Value::Fixed(5, vec![0, 0, 0, 0, 0]); @@ -1203,7 +1203,7 @@ mod tests { #[test] fn validate_enum() { - let schema = Schema::Enum { + let schema = Schema::Enum(EnumSchema { name: Name::new("some_enum").unwrap(), aliases: None, doc: None, @@ -1214,7 +1214,7 @@ mod tests { "clubs".to_string(), ], attributes: Default::default(), - }; + }); assert!(Value::Enum(0, "spades".to_string()).validate(&schema)); assert!(Value::String("spades".to_string()).validate(&schema)); @@ -1249,7 +1249,7 @@ mod tests { .as_str(), ); - let other_schema = Schema::Enum { + let other_schema = Schema::Enum(EnumSchema { name: Name::new("some_other_enum").unwrap(), aliases: None, doc: None, @@ -1260,7 +1260,7 @@ mod tests { "spades".to_string(), ], attributes: Default::default(), - }; + }); let value = Value::Enum(0, "spades".to_string()); assert!(!value.validate(&other_schema)); @@ -1287,7 +1287,7 @@ mod tests { // } // ] // } - let schema = Schema::Record { + let schema = Schema::Record(RecordSchema { name: Name::new("some_record").unwrap(), aliases: None, doc: None, @@ -1334,7 +1334,7 @@ mod tests { .cloned() .collect(), attributes: Default::default(), - }; + }); assert!(Value::Record(vec![ ("a".to_string(), Value::Long(42i64)), @@ -1354,7 +1354,7 @@ mod tests { ]); assert!(!value.validate(&schema)); assert_logged( - r#"Invalid value: Record([("a", Boolean(false)), ("b", String("foo"))]) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }. Reason: Unsupported value-schema combination"#, + r#"Invalid value: Record([("a", Boolean(false)), ("b", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }). Reason: Unsupported value-schema combination"#, ); let value = Value::Record(vec![ @@ -1363,7 +1363,7 @@ mod tests { ]); assert!(!value.validate(&schema)); assert_logged( - r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }. Reason: Could not find matching type in union"#, + r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }). Reason: Could not find matching type in union"#, ); assert_not_logged( r#"Invalid value: String("foo") for schema: Int. Reason: Unsupported value-schema combination"#, @@ -1375,7 +1375,7 @@ mod tests { ]); assert!(!value.validate(&schema)); assert_logged( - r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }. Reason: There is no schema field for field 'd'"#, + r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }). Reason: There is no schema field for field 'd'"#, ); let value = Value::Record(vec![ @@ -1386,7 +1386,7 @@ mod tests { ]); assert!(!value.validate(&schema)); assert_logged( - r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null), ("d", Null)]) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }. Reason: The value's records length (4) is greater than the schema's (3 fields)"#, + r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null), ("d", Null)]) for schema: Record(RecordSchema { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }). Reason: The value's records length (4) is greater than the schema's (3 fields)"#, ); assert!(Value::Map( @@ -1406,7 +1406,7 @@ mod tests { ) .validate(&schema)); assert_logged( - r#"Invalid value: Map({"d": Long(123)}) for schema: Record { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }. Reason: Field with name '"a"' is not a member of the map items + r#"Invalid value: Map({"d": Long(123)}) for schema: Record(RecordSchema { name: Name { name: "some_record", namespace: None }, aliases: None, doc: None, fields: [RecordField { name: "a", doc: None, aliases: None, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, aliases: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, aliases: None, default: Some(Null), schema: Union(UnionSchema { schemas: [Null, Int], variant_index: {Null: 0, Int: 1} }), order: Ascending, position: 2, custom_attributes: {} }], lookup: {"a": 0, "b": 1, "c": 2}, attributes: {} }). Reason: Field with name '"a"' is not a member of the map items Field with name '"b"' is not a member of the map items"#, ); @@ -1473,11 +1473,11 @@ Field with name '"b"' is not a member of the map items"#, let value = Value::Decimal(Decimal::from(vec![1, 2])); value .clone() - .resolve(&Schema::Decimal { + .resolve(&Schema::Decimal(DecimalSchema { precision: 10, scale: 4, inner: Box::new(Schema::Bytes), - }) + })) .unwrap(); assert!(value.resolve(&Schema::String).is_err()); } @@ -1486,11 +1486,11 @@ Field with name '"b"' is not a member of the map items"#, fn resolve_decimal_invalid_scale() { let value = Value::Decimal(Decimal::from(vec![1])); assert!(value - .resolve(&Schema::Decimal { + .resolve(&Schema::Decimal(DecimalSchema { precision: 2, scale: 3, inner: Box::new(Schema::Bytes), - }) + })) .is_err()); } @@ -1498,11 +1498,11 @@ Field with name '"b"' is not a member of the map items"#, fn resolve_decimal_invalid_precision_for_length() { let value = Value::Decimal(Decimal::from((1u8..=8u8).rev().collect::>())); assert!(value - .resolve(&Schema::Decimal { + .resolve(&Schema::Decimal(DecimalSchema { precision: 1, scale: 0, inner: Box::new(Schema::Bytes), - }) + })) .is_err()); } @@ -1511,17 +1511,17 @@ Field with name '"b"' is not a member of the map items"#, let value = Value::Decimal(Decimal::from(vec![1, 2])); assert!(value .clone() - .resolve(&Schema::Decimal { + .resolve(&Schema::Decimal(DecimalSchema { precision: 10, scale: 1, - inner: Box::new(Schema::Fixed { + inner: Box::new(Schema::Fixed(FixedSchema { name: Name::new("decimal").unwrap(), aliases: None, size: 20, doc: None, attributes: Default::default(), - }) - }) + })) + })) .is_ok()); assert!(value.resolve(&Schema::String).is_err()); } diff --git a/lang/rust/avro/src/writer.rs b/lang/rust/avro/src/writer.rs index 795fd09f246..58d13d40f06 100644 --- a/lang/rust/avro/src/writer.rs +++ b/lang/rust/avro/src/writer.rs @@ -632,7 +632,7 @@ mod tests { use crate::{ decimal::Decimal, duration::{Days, Duration, Millis, Months}, - schema::Name, + schema::{DecimalSchema, FixedSchema, Name}, types::Record, util::zig_i64, }; @@ -781,21 +781,21 @@ mod tests { #[test] fn decimal_fixed() -> TestResult<()> { let size = 30; - let inner = Schema::Fixed { + let inner = Schema::Fixed(FixedSchema { name: Name::new("decimal").unwrap(), aliases: None, doc: None, size, attributes: Default::default(), - }; + }); let value = vec![0u8; size]; logical_type_test( r#"{"type": {"type": "fixed", "size": 30, "name": "decimal"}, "logicalType": "decimal", "precision": 20, "scale": 5}"#, - &Schema::Decimal { + &Schema::Decimal(DecimalSchema { precision: 20, scale: 5, inner: Box::new(inner.clone()), - }, + }), Value::Decimal(Decimal::from(value.clone())), &inner, Value::Fixed(size, value), @@ -808,11 +808,11 @@ mod tests { let value = vec![0u8; 10]; logical_type_test( r#"{"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 3}"#, - &Schema::Decimal { + &Schema::Decimal(DecimalSchema { precision: 4, scale: 3, inner: Box::new(inner.clone()), - }, + }), Value::Decimal(Decimal::from(value.clone())), &inner, value, @@ -821,13 +821,13 @@ mod tests { #[test] fn duration() -> TestResult<()> { - let inner = Schema::Fixed { + let inner = Schema::Fixed(FixedSchema { name: Name::new("duration").unwrap(), aliases: None, doc: None, size: 12, attributes: Default::default(), - }; + }); let value = Value::Duration(Duration::new( Months::new(256), Days::new(512), diff --git a/lang/rust/avro/tests/schema.rs b/lang/rust/avro/tests/schema.rs index 95ba18c2f4b..5018dc5dd9d 100644 --- a/lang/rust/avro/tests/schema.rs +++ b/lang/rust/avro/tests/schema.rs @@ -16,7 +16,7 @@ // under the License. use apache_avro::{ - schema::{Name, RecordField}, + schema::{EnumSchema, FixedSchema, Name, RecordField, RecordSchema}, to_avro_datum, to_value, types::{Record, Value}, Codec, Error, Reader, Schema, Writer, @@ -634,21 +634,21 @@ fn test_correct_recursive_extraction() { ] }"#; let outer_schema = Schema::parse_str(raw_outer_schema).unwrap(); - if let Schema::Record { + if let Schema::Record(RecordSchema { fields: outer_fields, .. - } = outer_schema + }) = outer_schema { let inner_schema = &outer_fields[0].schema; - if let Schema::Record { + if let Schema::Record(RecordSchema { fields: inner_fields, .. - } = inner_schema + }) = inner_schema { - if let Schema::Record { + if let Schema::Record(RecordSchema { name: recursive_type, .. - } = &inner_fields[0].schema + }) = &inner_fields[0].schema { assert_eq!("X", recursive_type.name.as_str()); } @@ -880,14 +880,14 @@ fn test_parse_reused_record_schema_by_fullname() { let schema = Schema::parse_str(schema_str); assert!(schema.is_ok()); match schema.unwrap() { - Schema::Record { + Schema::Record(RecordSchema { ref name, aliases: _, doc: _, ref fields, lookup: _, attributes: _, - } => { + }) => { assert_eq!(name.fullname(None), "test.Weather", "Name does not match!"); assert_eq!(fields.len(), 3, "The number of the fields is not correct!"); @@ -1199,9 +1199,9 @@ fn test_doc_attributes() { init(); fn assert_doc(schema: &Schema) { match schema { - Schema::Enum { doc, .. } => assert!(doc.is_some()), - Schema::Record { doc, .. } => assert!(doc.is_some()), - Schema::Fixed { doc, .. } => assert!(doc.is_some()), + Schema::Enum(EnumSchema { doc, .. }) => assert!(doc.is_some()), + Schema::Record(RecordSchema { doc, .. }) => assert!(doc.is_some()), + Schema::Fixed(FixedSchema { doc, .. }) => assert!(doc.is_some()), Schema::String => (), _ => unreachable!("Unexpected schema type: {:?}", schema), } @@ -1210,7 +1210,7 @@ fn test_doc_attributes() { for (raw_schema, _) in DOC_EXAMPLES.iter() { let original_schema = Schema::parse_str(raw_schema).unwrap(); assert_doc(&original_schema); - if let Schema::Record { fields, .. } = original_schema { + if let Schema::Record(RecordSchema { fields, .. }) = original_schema { for f in fields { assert_doc(&f.schema) } diff --git a/lang/rust/avro_derive/src/lib.rs b/lang/rust/avro_derive/src/lib.rs index 5f900473cb6..5e80e70af13 100644 --- a/lang/rust/avro_derive/src/lib.rs +++ b/lang/rust/avro_derive/src/lib.rs @@ -190,14 +190,14 @@ fn get_data_struct_schema_def( .iter() .map(|field| (field.name.to_owned(), field.position)) .collect(); - apache_avro::schema::Schema::Record { + apache_avro::schema::Schema::Record(apache_avro::schema::RecordSchema { name, aliases: #record_aliases, doc: #record_doc, fields: schema_fields, lookup, attributes: Default::default(), - } + }) }) } @@ -217,13 +217,13 @@ fn get_data_enum_schema_def( .map(|variant| variant.ident.to_string()) .collect(); Ok(quote! { - apache_avro::schema::Schema::Enum { + apache_avro::schema::Schema::Enum(apache_avro::schema::EnumSchema { name: apache_avro::schema::Name::new(#full_schema_name).expect(&format!("Unable to parse enum name for schema {}", #full_schema_name)[..]), aliases: #enum_aliases, doc: #doc, symbols: vec![#(#symbols.to_owned()),*], attributes: Default::default(), - } + }) }) } else { Err(vec![syn::Error::new( diff --git a/lang/rust/avro_derive/tests/derive.rs b/lang/rust/avro_derive/tests/derive.rs index dcf599092bd..3dc217b6ad8 100644 --- a/lang/rust/avro_derive/tests/derive.rs +++ b/lang/rust/avro_derive/tests/derive.rs @@ -30,7 +30,7 @@ extern crate serde; #[cfg(test)] mod test_derive { - use apache_avro::schema::Alias; + use apache_avro::schema::{Alias, EnumSchema, RecordSchema}; use std::{ borrow::{Borrow, Cow}, sync::Mutex, @@ -144,7 +144,7 @@ mod test_derive { "#; let schema = Schema::parse_str(schema).unwrap(); assert_eq!(schema, TestBasicNamespace::get_schema()); - if let Schema::Record { name, .. } = TestBasicNamespace::get_schema() { + if let Schema::Record(RecordSchema { name, .. }) = TestBasicNamespace::get_schema() { assert_eq!("com.testing.namespace".to_owned(), name.namespace.unwrap()) } else { panic!("TestBasicNamespace schema must be a record schema") @@ -191,7 +191,9 @@ mod test_derive { "#; let schema = Schema::parse_str(schema).unwrap(); assert_eq!(schema, TestComplexNamespace::get_schema()); - if let Schema::Record { name, fields, .. } = TestComplexNamespace::get_schema() { + if let Schema::Record(RecordSchema { name, fields, .. }) = + TestComplexNamespace::get_schema() + { assert_eq!( "com.testing.complex.namespace".to_owned(), name.namespace.unwrap() @@ -201,7 +203,7 @@ mod test_derive { .filter(|field| field.name == "a") .map(|field| &field.schema) .next(); - if let Some(Schema::Record { name, .. }) = inner_schema { + if let Some(Schema::Record(RecordSchema { name, .. })) = inner_schema { assert_eq!( "com.testing.namespace".to_owned(), name.namespace.clone().unwrap() @@ -944,7 +946,9 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, doc, .. } = TestBasicWithAttributes::get_schema() { + if let Schema::Record(RecordSchema { name, doc, .. }) = + TestBasicWithAttributes::get_schema() + { assert_eq!("com.testing.namespace".to_owned(), name.namespace.unwrap()); assert_eq!("A Documented Record", doc.unwrap()) } else { @@ -987,7 +991,7 @@ mod test_derive { let schema = Schema::parse_str(schema).unwrap(); let derived_schema = TestBasicWithOuterDocAttributes::get_schema(); assert_eq!(&schema, &derived_schema); - if let Schema::Record { name, doc, .. } = derived_schema { + if let Schema::Record(RecordSchema { name, doc, .. }) = derived_schema { assert_eq!("com.testing.namespace".to_owned(), name.namespace.unwrap()); assert_eq!("A Documented Record", doc.unwrap()) } else { @@ -1029,7 +1033,8 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, doc, .. } = TestBasicWithLargeDoc::get_schema() { + if let Schema::Record(RecordSchema { name, doc, .. }) = TestBasicWithLargeDoc::get_schema() + { assert_eq!("com.testing.namespace".to_owned(), name.namespace.unwrap()); assert_eq!( "A Documented Record\nthat spans\nmultiple lines", @@ -1069,7 +1074,7 @@ mod test_derive { let schema = Schema::parse_str(schema).unwrap(); let derived_schema = TestBasicWithBool::get_schema(); - if let Schema::Record { name, .. } = derived_schema { + if let Schema::Record(RecordSchema { name, .. }) = derived_schema { assert_eq!("TestBasicWithBool", name.fullname(None)) } else { panic!("TestBasicWithBool schema must be a record schema") @@ -1100,7 +1105,7 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, .. } = TestBasicWithU32::get_schema() { + if let Schema::Record(RecordSchema { name, .. }) = TestBasicWithU32::get_schema() { assert_eq!("TestBasicWithU32", name.fullname(None)) } else { panic!("TestBasicWithU32 schema must be a record schema") @@ -1132,7 +1137,9 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, aliases, .. } = TestBasicStructWithAliases::get_schema() { + if let Schema::Record(RecordSchema { name, aliases, .. }) = + TestBasicStructWithAliases::get_schema() + { assert_eq!("TestBasicStructWithAliases", name.fullname(None)); assert_eq!( Some(vec![ @@ -1174,7 +1181,9 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, aliases, .. } = TestBasicStructWithAliases2::get_schema() { + if let Schema::Record(RecordSchema { name, aliases, .. }) = + TestBasicStructWithAliases2::get_schema() + { assert_eq!("TestBasicStructWithAliases2", name.fullname(None)); assert_eq!( Some(vec![ @@ -1213,7 +1222,9 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Enum { name, aliases, .. } = TestBasicEnumWithAliases::get_schema() { + if let Schema::Enum(EnumSchema { name, aliases, .. }) = + TestBasicEnumWithAliases::get_schema() + { assert_eq!("TestBasicEnumWithAliases", name.fullname(None)); assert_eq!( Some(vec![ @@ -1254,7 +1265,9 @@ mod test_derive { } "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Enum { name, aliases, .. } = TestBasicEnumWithAliases2::get_schema() { + if let Schema::Enum(EnumSchema { name, aliases, .. }) = + TestBasicEnumWithAliases2::get_schema() + { assert_eq!("TestBasicEnumWithAliases2", name.fullname(None)); assert_eq!( Some(vec![ @@ -1358,7 +1371,8 @@ mod test_derive { "#; let schema = Schema::parse_str(schema).unwrap(); - if let Schema::Record { name, fields, .. } = TestBasicStructWithDefaultValues::get_schema() + if let Schema::Record(RecordSchema { name, fields, .. }) = + TestBasicStructWithDefaultValues::get_schema() { assert_eq!("TestBasicStructWithDefaultValues", name.fullname(None)); use serde_json::json; @@ -1455,7 +1469,7 @@ mod test_derive { let schema = Schema::parse_str(schema).unwrap(); let derived_schema = TestBasicStructWithSkipAttribute::get_schema(); - if let Schema::Record { name, fields, .. } = &derived_schema { + if let Schema::Record(RecordSchema { name, fields, .. }) = &derived_schema { assert_eq!("TestBasicStructWithSkipAttribute", name.fullname(None)); for field in fields { match field.name.as_str() { @@ -1522,7 +1536,7 @@ mod test_derive { let schema = Schema::parse_str(schema).unwrap(); let derived_schema = TestBasicStructWithRenameAttribute::get_schema(); - if let Schema::Record { name, fields, .. } = &derived_schema { + if let Schema::Record(RecordSchema { name, fields, .. }) = &derived_schema { assert_eq!("TestBasicStructWithRenameAttribute", name.fullname(None)); for field in fields { match field.name.as_str() { @@ -1553,7 +1567,7 @@ mod test_derive { } let derived_schema = TestRawIdent::get_schema(); - if let Schema::Record { fields, .. } = derived_schema { + if let Schema::Record(RecordSchema { fields, .. }) = derived_schema { let field = fields.get(0).expect("TestRawIdent must contain a field"); assert_eq!(field.name, "type"); } else {