diff --git a/serde_avro_derive/tests/derive_schema.rs b/serde_avro_derive/tests/derive_schema.rs index 616a1d9..b7e774c 100644 --- a/serde_avro_derive/tests/derive_schema.rs +++ b/serde_avro_derive/tests/derive_schema.rs @@ -223,7 +223,7 @@ struct LogicalTypes<'a> { uuid: &'a str, #[avro_schema(logical_type = r#"decimal"#, scale = 1, precision = 4)] decimal: f64, - #[avro_schema(logical_type = r#"custom-logical-type"#, has_same_schema_as = "String")] + #[avro_schema(logical_type = r#"custom-logical-type"#, has_same_type_as = "String")] custom: MyCustomString, } struct MyCustomString(String); diff --git a/serde_avro_derive_macros/src/build_schema.rs b/serde_avro_derive_macros/src/build_schema.rs index d976d1c..94e08a2 100644 --- a/serde_avro_derive_macros/src/build_schema.rs +++ b/serde_avro_derive_macros/src/build_schema.rs @@ -31,7 +31,7 @@ pub(crate) struct SchemaDeriveField { scale: Option>, precision: Option>, - has_same_schema_as: Option, + has_same_type_as: Option, } pub(crate) fn schema_impl(input: SchemaDeriveInput) -> Result { @@ -53,7 +53,7 @@ pub(crate) fn schema_impl(input: SchemaDeriveInput) -> Result Result Vec), + ); + } let zero = parse_quote!(0); let mut error = |missing_field: &str| { errors.extend( @@ -141,16 +151,6 @@ pub(crate) fn schema_impl(input: SchemaDeriveInput) -> Result { - ty = Cow::Owned( - // "A `decimal` logical type annotates Avro `bytes` or `fixed` - // types". Because we need to choose an arbitrary one as we - // picked `decimal` because the type was named `Decimal`, we'll - // choose Bytes as we have no information to accurately decide - // the attributes we would give to a `Fixed`. - parse_quote_spanned!(logical_type_litstr.span() => Vec), - ); - } "TimestampMillis" | "TimestampMicros" | "TimeMicros" => { if !matches!(&*ty, syn::Type::Path(p) if p.path.is_ident("i64")) { ty = Cow::Owned( diff --git a/serde_avro_derive_macros/src/lib.rs b/serde_avro_derive_macros/src/lib.rs index 3ef6d91..08e15b2 100644 --- a/serde_avro_derive_macros/src/lib.rs +++ b/serde_avro_derive_macros/src/lib.rs @@ -58,6 +58,79 @@ use darling::FromDeriveInput; /// # let actual_schema = serde_json::to_string_pretty(&Foo::schema_mut()).unwrap(); /// # assert_eq!(actual_schema, schema_str); /// ``` +/// +/// # Customize field schema +/// +/// Field attributes can be used to specify logical type or override the +/// schema that a given field will produce: +/// ``` +/// use serde_avro_derive::BuildSchema; +/// +/// #[derive(BuildSchema)] +/// #[allow(unused)] +/// struct LogicalTypes<'a> { +/// #[avro_schema(logical_type = "Uuid")] +/// uuid: &'a str, +/// #[avro_schema(logical_type = "decimal", scale = 1, precision = 4)] +/// decimal: f64, +/// #[avro_schema(scale = 1, precision = 4)] +/// implicit_decimal: Decimal, // logical type is inferred because of the name of the type +/// #[avro_schema(logical_type = "custom-logical-type", has_same_type_as = "String")] +/// custom: MyCustomString, +/// } +/// struct MyCustomString(String); +/// struct Decimal { +/// _repr: (), +/// } +/// +/// let expected_schema = r#"{ +/// "type": "record", +/// "name": "rust_out.LogicalTypes", +/// "fields": [ +/// { +/// "name": "uuid", +/// "type": { +/// "logicalType": "uuid", +/// "type": "string" +/// } +/// }, +/// { +/// "name": "decimal", +/// "type": { +/// "logicalType": "decimal", +/// "type": "double", +/// "scale": 1, +/// "precision": 4 +/// } +/// }, +/// { +/// "name": "implicit_decimal", +/// "type": { +/// "logicalType": "decimal", +/// "type": "bytes", +/// "scale": 1, +/// "precision": 4 +/// } +/// }, +/// { +/// "name": "custom", +/// "type": { +/// "logicalType": "custom-logical-type", +/// "type": "string" +/// } +/// } +/// ] +/// }"#; +/// +/// # let actual_schema = serde_json::to_string_pretty(&LogicalTypes::schema_mut()).unwrap(); +/// assert_eq!(actual_schema, expected_schema); +/// ``` +/// +/// # Generics +/// +/// Generics are supported - see +/// [the `tests` module](https://github.com/Ten0/serde_avro_fast/blob/master/serde_avro_derive/tests/derive_schema.rs) +/// for more advanced examples pub fn build_schema_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let derive_input = syn::parse_macro_input!(input as syn::DeriveInput);