Skip to content

Commit 8a67be4

Browse files
authored
Merge pull request #4 from remkop22/development
add `from` and `try_from` attributes
2 parents ae58403 + 669f972 commit 8a67be4

File tree

1 file changed

+63
-25
lines changed
  • postgres-from-row-derive/src

1 file changed

+63
-25
lines changed

postgres-from-row-derive/src/lib.rs

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use darling::ast::{self, Style};
2-
use darling::{FromDeriveInput, FromField};
2+
use darling::{FromDeriveInput, FromField, ToTokens};
33
use proc_macro::TokenStream;
44
use quote::quote;
55
use syn::{parse_macro_input, DeriveInput, Ident};
@@ -60,18 +60,33 @@ impl DeriveFromRow {
6060
Style::Struct => fields.fields,
6161
};
6262

63-
let from_row_fields = fields.iter().map(|f| f.generate_from_row(&module));
64-
let try_from_row_fields = fields.iter().map(|f| f.generate_try_from_row(&module));
63+
let from_row_fields = fields
64+
.iter()
65+
.map(|f| f.generate_from_row(&module))
66+
.collect::<syn::Result<Vec<_>>>()?;
67+
68+
let try_from_row_fields = fields
69+
.iter()
70+
.map(|f| f.generate_try_from_row(&module))
71+
.collect::<syn::Result<Vec<_>>>()?;
72+
6573
let original_predicates = where_clause.clone().map(|w| &w.predicates).into_iter();
6674
let mut predicates = Vec::new();
6775

6876
for field in fields.iter() {
77+
let target_ty = &field.target_ty()?;
6978
let ty = &field.ty;
7079
predicates.push(if field.flatten {
71-
quote! (#ty: postgres_from_row::FromRow)
80+
quote! (#target_ty: postgres_from_row::FromRow)
7281
} else {
73-
quote! (#ty: for<'a> #module::types::FromSql<'a>)
82+
quote! (#target_ty: for<'a> #module::types::FromSql<'a>)
7483
});
84+
85+
if field.from.is_some() {
86+
predicates.push(quote!(#ty: std::convert::From<#target_ty>))
87+
} else if field.try_from.is_some() {
88+
predicates.push(quote!(#ty: std::convert::From<#target_ty>))
89+
}
7590
}
7691

7792
Ok(quote! {
@@ -101,38 +116,61 @@ struct FromRowField {
101116
ty: syn::Type,
102117
#[darling(default)]
103118
flatten: bool,
119+
try_from: Option<String>,
120+
from: Option<String>,
104121
}
105122

106123
impl FromRowField {
107-
fn generate_from_row(&self, module: &Ident) -> proc_macro2::TokenStream {
124+
fn target_ty(&self) -> syn::Result<proc_macro2::TokenStream> {
125+
if let Some(from) = &self.from {
126+
Ok(from.parse()?)
127+
} else if let Some(try_from) = &self.try_from {
128+
Ok(try_from.parse()?)
129+
} else {
130+
Ok(self.ty.to_token_stream())
131+
}
132+
}
133+
134+
fn generate_from_row(&self, module: &Ident) -> syn::Result<proc_macro2::TokenStream> {
108135
let ident = self.ident.as_ref().unwrap();
109136
let str_ident = ident.to_string();
110-
let ty = &self.ty;
137+
let field_ty = &self.ty;
111138

112-
if self.flatten {
113-
quote! {
114-
#ident: <#ty as postgres_from_row::FromRow>::from_row(row)
115-
}
139+
let target_ty = self.target_ty()?;
140+
141+
let mut base = if self.flatten {
142+
quote!(<#target_ty as postgres_from_row::FromRow>::from_row(row))
116143
} else {
117-
quote! {
118-
#ident: #module::Row::get::<&str, #ty>(row, #str_ident)
119-
}
120-
}
144+
quote!(#module::Row::get::<&str, #target_ty>(row, #str_ident))
145+
};
146+
147+
if self.from.is_some() {
148+
base = quote!(<#field_ty as std::convert::From<#target_ty>>::from(#base));
149+
} else if self.try_from.is_some() {
150+
base = quote!(<#field_ty as std::convert::TryFrom<#target_ty>>::try_from(#base).expect("could not convert column"));
151+
};
152+
153+
Ok(quote!(#ident: #base))
121154
}
122155

123-
fn generate_try_from_row(&self, module: &Ident) -> proc_macro2::TokenStream {
156+
fn generate_try_from_row(&self, module: &Ident) -> syn::Result<proc_macro2::TokenStream> {
124157
let ident = self.ident.as_ref().unwrap();
125158
let str_ident = ident.to_string();
126-
let ty = &self.ty;
159+
let field_ty = &self.ty;
160+
let target_ty = self.target_ty()?;
127161

128-
if self.flatten {
129-
quote! {
130-
#ident: <#ty as postgres_from_row::FromRow>::try_from_row(row)?
131-
}
162+
let mut base = if self.flatten {
163+
quote!(<#target_ty as postgres_from_row::FromRow>::try_from_row(row)?)
132164
} else {
133-
quote! {
134-
#ident: #module::Row::try_get::<&str, #ty>(row, #str_ident)?
135-
}
136-
}
165+
quote!(#module::Row::try_get::<&str, #target_ty>(row, #str_ident)?)
166+
};
167+
168+
if self.from.is_some() {
169+
base = quote!(<#field_ty as std::convert::From<#target_ty>>::from(#base));
170+
} else if self.try_from.is_some() {
171+
base = quote!(<#field_ty as std::convert::TryFrom<#target_ty>>::try_from(#base)?);
172+
};
173+
174+
Ok(quote!(#ident: #base))
137175
}
138176
}

0 commit comments

Comments
 (0)