diff --git a/sqlx-macros-core/src/derives/attributes.rs b/sqlx-macros-core/src/derives/attributes.rs index cf18cffca4..fcb70bf58c 100644 --- a/sqlx-macros-core/src/derives/attributes.rs +++ b/sqlx-macros-core/src/derives/attributes.rs @@ -1,8 +1,7 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote_spanned; use syn::{ - punctuated::Punctuated, token::Comma, Attribute, DeriveInput, Field, LitStr, Meta, Token, Type, - Variant, + parenthesized, parse::discouraged::AnyDelimiter, punctuated::Punctuated, token::{self, Comma}, Attribute, DeriveInput, Field, LitStr, Meta, Token, Type, Variant }; macro_rules! assert_attribute { @@ -61,13 +60,18 @@ pub struct SqlxContainerAttributes { pub default: bool, } +pub enum JsonAttribute { + Mandatory, + Optional +} + pub struct SqlxChildAttributes { pub rename: Option, pub default: bool, pub flatten: bool, pub try_from: Option, pub skip: bool, - pub json: bool, + pub json: Option, } pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result { @@ -144,7 +148,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result syn::Result - (false, None, false) => { + (false, None, None) => { predicates .push(parse_quote!(#ty: ::sqlx::decode::Decode<#lifetime, R::Database>)); predicates.push(parse_quote!(#ty: ::sqlx::types::Type)); @@ -107,12 +107,12 @@ fn expand_derive_from_row_struct( parse_quote!(__row.try_get(#id_s)) } // Flatten - (true, None, false) => { + (true, None, None) => { predicates.push(parse_quote!(#ty: ::sqlx::FromRow<#lifetime, R>)); parse_quote!(<#ty as ::sqlx::FromRow<#lifetime, R>>::from_row(__row)) } // Flatten + Try from - (true, Some(try_from), false) => { + (true, Some(try_from), None) => { predicates.push(parse_quote!(#try_from: ::sqlx::FromRow<#lifetime, R>)); parse_quote!( <#try_from as ::sqlx::FromRow<#lifetime, R>>::from_row(__row) @@ -130,11 +130,11 @@ fn expand_derive_from_row_struct( ) } // Flatten + Json - (true, _, true) => { + (true, _, Some(_)) => { panic!("Cannot use both flatten and json") } // Try from - (false, Some(try_from), false) => { + (false, Some(try_from), None) => { predicates .push(parse_quote!(#try_from: ::sqlx::decode::Decode<#lifetime, R::Database>)); predicates.push(parse_quote!(#try_from: ::sqlx::types::Type)); @@ -154,8 +154,8 @@ fn expand_derive_from_row_struct( }) ) } - // Try from + Json - (false, Some(try_from), true) => { + // Try from + Json mandatory + (false, Some(try_from), Some(JsonAttribute::Mandatory)) => { predicates .push(parse_quote!(::sqlx::types::Json<#try_from>: ::sqlx::decode::Decode<#lifetime, R::Database>)); predicates.push(parse_quote!(::sqlx::types::Json<#try_from>: ::sqlx::types::Type)); @@ -175,14 +175,25 @@ fn expand_derive_from_row_struct( }) ) }, + // Try from + Json optional + (false, Some(try_from), Some(JsonAttribute::Optional)) => { + panic!("Cannot use both try from and json optional") + }, // Json - (false, None, true) => { + (false, None, Some(JsonAttribute::Mandatory)) => { predicates .push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::decode::Decode<#lifetime, R::Database>)); predicates.push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::types::Type)); parse_quote!(__row.try_get::<::sqlx::types::Json<_>, _>(#id_s).map(|x| x.0)) }, + (false, None, Some(JsonAttribute::Optional)) => { + predicates + .push(parse_quote!(::core::Option<::sqlx::types::Json<#ty>>: ::sqlx::decode::Decode<#lifetime, R::Database>)); + predicates.push(parse_quote!(::core::Option<::sqlx::types::Json<#ty>>: ::sqlx::types::Type)); + + parse_quote!(__row.try_get::<::core::Option<::sqlx::types::Json<_>>, _>(#id_s).map(|x| x.map(|y| y.0))) + }, }; if attributes.default {