derive_sql_common/derive/
fields.rs1use super::*;
2
3use attribute_derive::{Attribute};
4
5#[derive(Attribute)]
6#[attribute(ident = derive_sqlite)]
7struct FieldAttrs {
8 #[attribute(default = false)]
9 is_primary_key: bool,
10 #[attribute(default = false)]
11 is_unique: bool,
12 on_insert: Option<syn::PatPath>,
13 on_update: Option<syn::PatPath>,
14}
15
16pub struct Fields<'a> {
17 ident: &'a syn::Ident,
18 sql_type: SqlType,
19 attrs: FieldAttrs,
20 raw_type: String,
21}
22
23impl<'a> std::convert::TryFrom<&'a syn::Field> for Fields<'a> {
24 type Error = Box<dyn std::error::Error>;
25 fn try_from(f: &'a syn::Field) -> Result<Self, Self::Error> {
26 let sql_type: SqlType = f.into();
27 let raw_type: String = extract_type(&f.ty).ok_or(format!("Unable to retrieve raw type for {:#?}", &f.ty))?;
28 if matches!(sql_type, SqlType::Unsupported) { return Err("Type is not supported".into()); }
29 Ok(
30 Fields {
31 ident: f.ident.as_ref().ok_or("Field does not have an ident")?,
32 sql_type,
33 attrs: FieldAttrs::from_attributes(&f.attrs)?,
34 raw_type,
35 }
36 )
37 }
38}
39
40impl<'a> Fields<'a> {
41 pub fn name(&'a self) -> String { format!("{}", self.ident) }
42 pub fn ident(&'a self) -> &'a syn::Ident { self.ident }
43 pub fn raw_type(&'a self) -> &'a str { self.raw_type.as_str() }
44 pub fn sql_type(&'a self) -> &'a SqlType { &self.sql_type }
45 pub fn is_primary_key(&'a self) -> bool { self.attrs.is_primary_key }
46 pub fn is_unique(&self) -> bool { self.attrs.is_unique }
47 pub fn on_insert(&'a self) -> &'a Option<syn::PatPath> { &self.attrs.on_insert }
48 pub fn on_update(&'a self) -> &'a Option<syn::PatPath> { &self.attrs.on_update }
49 pub fn as_pub_static_member(&'a self) -> proc_macro2::TokenStream {
50 let key: syn::Ident = syn::Ident::new(self.name().to_ascii_uppercase().as_str(), self.ident.span());
51 let value = self.name();
52 quote::quote! {
53 pub const #key : &'static str = #value;
54 }
55 }
56}
57
58fn extract_type(ty: &syn::Type) -> Option<String> {
60 match ty {
61 syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. } , .. }) => {
62 match segments.last() {
63 Some(syn::PathSegment { ident,
64 arguments: syn::PathArguments::AngleBracketed( syn::AngleBracketedGenericArguments { args, .. } )
65 }) if ident == "Option" => {
66 match args.last() {
67 Some(syn::GenericArgument::Type(syn::Type::Path(syn::TypePath { path, .. }))) => path.get_ident().map(|i| i.to_string()),
68 _ => None,
69 }
70 },
71 Some(syn::PathSegment { ident, ..}) => Some(ident.to_string()),
72 _ => None,
73 }
74 },
75 _ => None,
77 }
78}
79