Skip to content

Commit

Permalink
add json optional attribute parser and expansion
Browse files Browse the repository at this point in the history
  • Loading branch information
seanaye committed Jan 10, 2025
1 parent 6b33766 commit 5c5fd3f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 14 deletions.
21 changes: 16 additions & 5 deletions sqlx-macros-core/src/derives/attributes.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -61,13 +60,18 @@ pub struct SqlxContainerAttributes {
pub default: bool,
}

pub enum JsonAttribute {
Mandatory,
Optional
}

pub struct SqlxChildAttributes {
pub rename: Option<String>,
pub default: bool,
pub flatten: bool,
pub try_from: Option<Type>,
pub skip: bool,
pub json: bool,
pub json: Option<JsonAttribute>,
}

pub fn parse_container_attributes(input: &[Attribute]) -> syn::Result<SqlxContainerAttributes> {
Expand Down Expand Up @@ -144,7 +148,7 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttri
let mut try_from = None;
let mut flatten = false;
let mut skip: bool = false;
let mut json = false;
let mut json = None;

for attr in input.iter().filter(|a| a.path().is_ident("sqlx")) {
attr.parse_nested_meta(|meta| {
Expand All @@ -163,7 +167,14 @@ pub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttri
} else if meta.path.is_ident("skip") {
skip = true;
} else if meta.path.is_ident("json") {
json = true;
if meta.input.peek(syn::token::Paren) {
let content;
parenthesized!(content in meta.input);
let literal: Token![optional] = content.parse()?;
json = Some(JsonAttribute::Optional);
} else {
json = Some(JsonAttribute::Mandatory);
}
}

Ok(())
Expand Down
29 changes: 20 additions & 9 deletions sqlx-macros-core/src/derives/row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use syn::{
};

use super::{
attributes::{parse_child_attributes, parse_container_attributes},
attributes::{parse_child_attributes, parse_container_attributes, JsonAttribute},
rename_all,
};

Expand Down Expand Up @@ -99,20 +99,20 @@ fn expand_derive_from_row_struct(

let expr: Expr = match (attributes.flatten, attributes.try_from, attributes.json) {
// <No attributes>
(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<R::Database>));

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)
Expand All @@ -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<R::Database>));
Expand All @@ -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<R::Database>));
Expand All @@ -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<R::Database>));

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<R::Database>));

parse_quote!(__row.try_get::<::core::Option<::sqlx::types::Json<_>>, _>(#id_s).map(|x| x.map(|y| y.0)))
},
};

if attributes.default {
Expand Down

0 comments on commit 5c5fd3f

Please sign in to comment.