mydb 0.0.1

This is a plugin that works with mydb_sqlx to make database operation easier
Documentation
use proc_macro2::{TokenTree, Ident, Span, TokenStream};
use quote::quote;
use syn::{
  spanned::Spanned, Attribute, Data, Fields, Field, GenericArgument, Meta, PathArguments, Type
};

use crate::derives::TableField;

pub fn get_table_list(data: Data) -> Vec<TableField> {
  let mut table_list: Vec<TableField> = vec![];
  match data {
    Data::Struct(data_struct) => {
      match data_struct.fields {
        Fields::Named(fields) => {
          for field in fields.named {
            let name = get_field_name(&field);
            let mut field_type = format!("");
            let mut exist = true;
            let mut _option = false;

            field.attrs.iter()
            .filter(| attr | attr.path().is_ident("table_field"))
            .for_each(|attr| {

              if let Meta::List(lits) = &attr.meta {
                let mut table_field_content = format!("");
                let _ = &lits.tokens.clone().into_iter().for_each(| ts | {
                  table_field_content += &ts.span().source_text().unwrap_or(format!(""));
                });
                table_field_content = table_field_content.replace(" ", "");
                let exist_vec: &Vec<&str> = &table_field_content.split(',').collect();
                if exist_vec.contains(&"exist=false") {
                  exist = false;
                }
              }
            });
    
            // getting field is field type
            if let Type::Path(_ty) = &field.ty {
              _ty.path.segments.iter().for_each(|ps| {
                if let Some(_o) = &ps.span().source_text() {
                  if _o == &"Option".to_string() {
                    _option = true;
                  } else {
                    // If it is not Option, it is the base type
                    field_type = ps.ident.to_string();
                    _option = false;
                    return;
                  }
                  if let PathArguments::AngleBracketed(_abga) = &ps.arguments {
                    _abga.args.iter().for_each(|b| {
                      if let GenericArgument::Type(path) = &b {
                        if let Type::Path(_path) = &path {
                          if let Some(text) = _path.span().source_text() {
                            field_type = text;
                          };
                        }
                      }
                    })
                  }
                }
              });
            }
            table_list.push( TableField {
              name,
              field_type,
              exist,
              _option
            })
          }
        },
        _ => ()
      }
    },
    _ => ()
  }
  table_list
}

fn get_field_name(field: &Field) -> String {
  if let Some(ident) = &field.ident {
    if let Some(text) = ident.span().source_text() {
      return text;
    }
  }
  format!("")
}

pub fn get_table_name(attrs: Vec<Attribute>) -> String {
  let mut table_name = format!("");
  attrs
  .iter()
  .filter(|attr| attr.path().is_ident("mydb"))
  .into_iter()
  .for_each(| attr | {
    if let Meta::List(lits) = &attr.meta {
      let _ = &lits.tokens.clone().into_iter().for_each(| ts | {
        if let TokenTree::Literal(l_name) = ts {
          if l_name.to_string().len() > 0 {
            table_name = l_name.to_string().replace('"', "");
          } else {
            eprintln!("no setting table_name")
          }
        }
      });
    }
  });
  table_name
}

pub fn set_ident(name: &String) -> Ident {
  Ident::new(&name, Span::call_site())
}

pub fn type_value(_option: bool, field_type: &String) -> TokenStream {
  if _option {
    if field_type == "DateTime" {
      quote! { Option<DateTime<Utc>> }
    } else {
      let f_type = set_ident(field_type);
      quote! { Option<#f_type> }
    }
  } else {
    if field_type == "DateTime" {
      quote! { DateTime<Utc> }
    } else {
      let f_type = set_ident(field_type);
      quote! { #f_type }
    }
  }
}