extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Expr, Lit, Meta, Token};
use crate::macro_utils::{from_name_value, name_value_to_string};
use syn::punctuated::Punctuated;
pub fn gen_values_attribute_impl(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let name = &input.ident;
let mut index = 1;
let mut placeholder = "";
let attrs = input
.attrs
.iter()
.find(|attr| attr.path().is_ident("config"))
.expect("必须在结构上设置 `#[config(database = \"/*数据库类型*/\")]` 宏");
let nested = attrs
.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
.map_err(|e| {
println!("分析字段属性时出错");
e
})
.unwrap();
for meta in nested {
match meta {
Meta::NameValue(name_value) if meta.path().is_ident("database") => {
if let Expr::Lit(value) = &name_value.value {
if let Lit::Str(value) = &value.lit {
placeholder = match value.value().as_str() {
"postgres" => "${index}", "mysql" | "mariadb" => "?", "sqlite" => "?", "mssql" => "@p{index}", _ => panic!("未支持的数据库类型"),
};
continue;
}
}
panic!("database 值转换失败")
}
Meta::NameValue(name_value) if meta.path().is_ident("index") => {
if let Some(Lit::Int(value)) = &from_name_value(&name_value) {
index = value.base10_parse::<usize>().unwrap();
}
}
_ => {}
}
}
if placeholder.is_empty() {
panic!("database 值必须设置");
}
let values = if let Data::Struct(data_struct) = &input.data {
let mut fields = Vec::new();
for field in &data_struct.fields {
let mut field_name = Some(placeholder.replace("{index}", &index.to_string()));
let mut value_placeholder = None;
let mut add_index = 1;
let attrs = field
.attrs
.iter()
.find(|attr| attr.path().is_ident("value"));
if let Some(attr) = attrs {
let nested = attr
.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
.map_err(|e| {
println!("分析 'value' 属性时出错");
e
})
.unwrap();
for meta in nested {
match meta {
Meta::Path(_) if meta.path().is_ident("ignore") => {
field_name = None;
break;
}
Meta::NameValue(name_value) if meta.path().is_ident("index") => {
if let Some(Lit::Int(value)) = &from_name_value(&name_value) {
field_name =
Some(placeholder.replace("{index}", &value.to_string()));
add_index = 0;
}
}
Meta::NameValue(name_value) if meta.path().is_ident("value") => {
if let Some(value) = name_value_to_string(&name_value) {
if value.contains("{index}") {
value_placeholder = Some(value.replace(
"{index}",
&placeholder.replace("{index}", &index.to_string()),
));
} else {
value_placeholder = Some(value);
add_index = 0;
}
}
}
_ => {}
}
}
}
if let Some(value) = value_placeholder {
fields.push(value);
index += add_index;
} else if let Some(value) = field_name {
fields.push(value);
index += add_index;
}
}
fields
} else {
Vec::new()
};
let expanded = quote! {
impl ValuesAttributeMacro for #name {
fn generate_values_clause() -> Vec<String> {
vec![#(#values.to_string()),*]
}
}
};
TokenStream::from(expanded)
}