This is an automated email from the ASF dual-hosted git repository. mgrigorov pushed a commit to branch avro-3709-add-aliases-to-record-fields in repository https://gitbox.apache.org/repos/asf/avro.git
commit d8654cfae86e23daf680c24bb8de71e76f656cbe Author: Martin Tzvetanov Grigorov <[email protected]> AuthorDate: Tue Feb 7 11:58:32 2023 +0200 AVRO-3709: [Rust] Add 'aliases' field to RecordField Signed-off-by: Martin Tzvetanov Grigorov <[email protected]> --- lang/rust/avro/src/schema.rs | 38 ++++++++++++++++++++++++++++++++++++++ lang/rust/avro/src/types.rs | 19 ++++++++++++------- lang/rust/avro/tests/schema.rs | 1 + lang/rust/avro_derive/src/lib.rs | 4 ++++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs index 51a87cd6d..44e22efc7 100644 --- a/lang/rust/avro/src/schema.rs +++ b/lang/rust/avro/src/schema.rs @@ -563,6 +563,9 @@ pub struct RecordField { pub name: String, /// Documentation of the field. pub doc: Documentation, + + /// Aliases of the field. + pub aliases: Aliases, /// Default value of the field. /// This value will be used when reading Avro datum if schema resolution /// is enabled. @@ -603,6 +606,16 @@ impl RecordField { let default = field.get("default").cloned(); + let aliases = field.get("aliases").and_then(|aliases| { + aliases.as_array().map(|aliases| { + aliases + .iter() + .flat_map(|alias| alias.as_str()) + .map(|alias| Alias::new(alias).expect("Alias is not valid")) + .collect::<Vec<Alias>>() + }) + }); + let order = field .get("order") .and_then(|order| order.as_str()) @@ -613,6 +626,7 @@ impl RecordField { name, doc: field.doc(), default, + aliases, schema, order, position, @@ -1268,6 +1282,13 @@ impl Parser { for field in &fields { lookup.insert(field.name.clone(), field.position); + + if let Some(ref field_aliases) = field.aliases { + for alias in field_aliases { + let alias = alias.fullname(enclosing_namespace.clone()); + lookup.insert(alias, field.position); + } + } } let schema = Schema::Record { @@ -2067,6 +2088,7 @@ mod tests { name: "next".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Union( UnionSchema::new(vec![ Schema::Null, @@ -2090,6 +2112,7 @@ mod tests { name: "next".to_string(), doc: None, default: Some(json!(2)), + aliases: None, schema: Schema::Long, order: RecordFieldOrder::Ascending, position: 1, @@ -2144,6 +2167,7 @@ mod tests { name: "field_one".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Union( UnionSchema::new(vec![ Schema::Ref { @@ -2235,6 +2259,7 @@ mod tests { name: "field_one".to_string(), doc: None, default: Some(Value::Null), + aliases: None, schema: Schema::Union( UnionSchema::new(vec![ Schema::Null, @@ -2284,6 +2309,7 @@ mod tests { name: "a".to_string(), doc: None, default: Some(Value::Number(42i64.into())), + aliases: None, schema: Schema::Long, order: RecordFieldOrder::Ascending, position: 0, @@ -2293,6 +2319,7 @@ mod tests { name: "b".to_string(), doc: None, default: None, + aliases: None, schema: Schema::String, order: RecordFieldOrder::Ascending, position: 1, @@ -2345,6 +2372,7 @@ mod tests { name: "recordField".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Record { name: Name::new("Node").unwrap(), aliases: None, @@ -2354,6 +2382,7 @@ mod tests { name: "label".to_string(), doc: None, default: None, + aliases: None, schema: Schema::String, order: RecordFieldOrder::Ascending, position: 0, @@ -2363,6 +2392,7 @@ mod tests { name: "children".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Array(Box::new(Schema::Ref { name: Name::new("Node").unwrap(), })), @@ -2522,6 +2552,7 @@ mod tests { name: "value".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Long, order: RecordFieldOrder::Ascending, position: 0, @@ -2531,6 +2562,7 @@ mod tests { name: "next".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Union( UnionSchema::new(vec![ Schema::Null, @@ -2591,6 +2623,7 @@ mod tests { name: "value".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Long, order: RecordFieldOrder::Ascending, position: 0, @@ -2600,6 +2633,7 @@ mod tests { name: "next".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Ref { name: Name { name: "record".to_owned(), @@ -2658,6 +2692,7 @@ mod tests { name: "enum".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Enum { name: Name { name: "enum".to_owned(), @@ -2676,6 +2711,7 @@ mod tests { name: "next".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Enum { name: Name { name: "enum".to_owned(), @@ -2738,6 +2774,7 @@ mod tests { name: "fixed".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Fixed { name: Name { name: "fixed".to_owned(), @@ -2756,6 +2793,7 @@ mod tests { name: "next".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Fixed { name: Name { name: "fixed".to_owned(), diff --git a/lang/rust/avro/src/types.rs b/lang/rust/avro/src/types.rs index 9f3f3d253..60f94ecf8 100644 --- a/lang/rust/avro/src/types.rs +++ b/lang/rust/avro/src/types.rs @@ -1107,6 +1107,7 @@ mod tests { name: "field_name".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Int, order: RecordFieldOrder::Ignore, position: 0, @@ -1116,7 +1117,7 @@ mod tests { 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, 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 { 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)]), @@ -1128,6 +1129,7 @@ mod tests { name: "field_name".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Ref { name: Name::new("missing").unwrap(), }, @@ -1139,7 +1141,7 @@ mod tests { 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, 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 { 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 } [...] ), ]; @@ -1287,6 +1289,7 @@ mod tests { name: "a".to_string(), doc: None, default: None, + aliases: None, schema: Schema::Long, order: RecordFieldOrder::Ascending, position: 0, @@ -1296,6 +1299,7 @@ mod tests { name: "b".to_string(), doc: None, default: None, + aliases: None, schema: Schema::String, order: RecordFieldOrder::Ascending, position: 1, @@ -1305,6 +1309,7 @@ mod tests { name: "c".to_string(), doc: None, default: Some(JsonValue::Null), + aliases: None, schema: Schema::Union( UnionSchema::new(vec![Schema::Null, Schema::Int]).unwrap(), ), @@ -1342,7 +1347,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, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, default: Some(Null) [...] + 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", [...] ); let value = Value::Record(vec![ @@ -1351,7 +1356,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, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, default: Some(Null), sche [...] + 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: N [...] ); assert_not_logged( r#"Invalid value: String("foo") for schema: Int. Reason: Unsupported value-schema combination"#, @@ -1363,7 +1368,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, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, default: Some(Null), sche [...] + 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: N [...] ); let value = Value::Record(vec![ @@ -1374,7 +1379,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, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, [...] + 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: {} }, Recor [...] ); assert!(Value::Map( @@ -1394,7 +1399,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, default: None, schema: Long, order: Ascending, position: 0, custom_attributes: {} }, RecordField { name: "b", doc: None, default: None, schema: String, order: Ascending, position: 1, custom_attributes: {} }, RecordField { name: "c", doc: None, default: Some(Null), schema: Union(UnionSchema { sc [...] + 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, defaul [...] Field with name '"b"' is not a member of the map items"#, ); diff --git a/lang/rust/avro/tests/schema.rs b/lang/rust/avro/tests/schema.rs index 83cd6c502..95ba18c2f 100644 --- a/lang/rust/avro/tests/schema.rs +++ b/lang/rust/avro/tests/schema.rs @@ -896,6 +896,7 @@ fn test_parse_reused_record_schema_by_fullname() { ref name, doc: _, default: _, + aliases: _, ref schema, order: _, position: _, diff --git a/lang/rust/avro_derive/src/lib.rs b/lang/rust/avro_derive/src/lib.rs index 77b0c6a24..5f8c0bc1c 100644 --- a/lang/rust/avro_derive/src/lib.rs +++ b/lang/rust/avro_derive/src/lib.rs @@ -30,6 +30,8 @@ struct FieldOptions { doc: Option<String>, #[darling(default)] default: Option<String>, + // #[darling(default)] + // aliases: Option<Vec<String>>, #[darling(default)] rename: Option<String>, #[darling(default)] @@ -148,6 +150,7 @@ fn get_data_struct_schema_def( } None => quote! { None }, }; + let aliases = quote! { None }; let schema_expr = type_to_schema_expr(&field.ty)?; let position = index; record_field_exprs.push(quote! { @@ -155,6 +158,7 @@ fn get_data_struct_schema_def( name: #name.to_string(), doc: #doc, default: #default_value, + aliases: #aliases, schema: #schema_expr, order: apache_avro::schema::RecordFieldOrder::Ascending, position: #position,
