rbatis_macro_driver/macros/
sql_impl.rs

1use crate::ParseArgs;
2use proc_macro2::{Ident, Span};
3use quote::quote;
4use quote::ToTokens;
5use syn::{FnArg, ItemFn, Pat};
6
7use crate::proc_macro::TokenStream;
8use crate::util::{find_fn_body, find_return_type, get_fn_args, is_query, is_rb_ref};
9
10//impl sql macro
11pub(crate) fn impl_macro_sql(target_fn: &ItemFn, args: &ParseArgs) -> TokenStream {
12    let return_ty = find_return_type(target_fn);
13    let func_name_ident = target_fn.sig.ident.to_token_stream();
14
15    let mut rbatis_ident = "".to_token_stream();
16    let mut rbatis_name = String::new();
17    for x in &target_fn.sig.inputs {
18        match x {
19            FnArg::Receiver(_) => {}
20            FnArg::Typed(t) => {
21                let ty_stream = t.ty.to_token_stream().to_string();
22                if is_rb_ref(&ty_stream) {
23                    rbatis_ident = t.pat.to_token_stream();
24                    rbatis_name = rbatis_ident
25                        .to_string()
26                        .trim_start_matches("mut ")
27                        .to_string();
28                    break;
29                }
30            }
31        }
32    }
33
34    let mut sql_ident = quote!();
35    if args.sqls.len() >= 1 {
36        if rbatis_name.is_empty() {
37            panic!("[rb] you should add rbatis ref param  `rb:&dyn Executor`  on '{}()'!", target_fn.sig.ident);
38        }
39        let mut s = "".to_string();
40        for v in &args.sqls {
41            s = s + v.value().as_str();
42        }
43        sql_ident = quote!(#s);
44    } else {
45        panic!("[rb] Incorrect macro parameter length!");
46    }
47
48    let func_args_stream = target_fn.sig.inputs.to_token_stream();
49    let fn_body = find_fn_body(target_fn);
50    let is_async = target_fn.sig.asyncness.is_some();
51    if !is_async {
52        panic!(
53            "[rbaits] 'fn {}({})' must be  async fn! ",
54            func_name_ident, func_args_stream
55        );
56    }
57    if rbatis_ident.to_string().starts_with("mut ") {
58        rbatis_ident = Ident::new(
59            &rbatis_ident.to_string().trim_start_matches("mut "),
60            Span::call_site(),
61        )
62        .to_token_stream();
63    }
64    let mut decode = quote! {};
65    let mut call_method = quote! {};
66    let is_query = is_query(&return_ty.to_string());
67    if is_query {
68        call_method = quote! {query};
69        decode = quote! { Ok(rbatis::decode::decode(r)?)}
70    } else {
71        call_method = quote! {exec};
72        decode = quote! { Ok(r)}
73    }
74    //check use page method
75    let page_req_str = String::new();
76    let page_req = quote! {};
77    //append all args
78    let sql_args_gen =
79        filter_args_context_id(&rbatis_name, &get_fn_args(target_fn), &[page_req_str]);
80    let generic = target_fn.sig.generics.clone();
81    //gen rust code templete
82    let gen_token_temple = quote! {
83       pub async fn #func_name_ident #generic(#func_args_stream) -> #return_ty{
84           let mut rb_args =vec![];
85           #sql_args_gen
86           #fn_body
87           use rbatis::executor::{Executor};
88           let r= #rbatis_ident.#call_method(&#sql_ident,rb_args #page_req).await?;
89           #decode
90       }
91    };
92    return gen_token_temple.into();
93}
94
95fn filter_args_context_id(
96    rbatis_name: &str,
97    fn_arg_name_vec: &Vec<Box<Pat>>,
98    skip_names: &[String],
99) -> proc_macro2::TokenStream {
100    let mut sql_args_gen = quote! {};
101    for item in fn_arg_name_vec {
102        let item_ident_name = item
103            .to_token_stream()
104            .to_string()
105            .trim()
106            .trim_start_matches("mut ")
107            .to_string();
108        if item_ident_name.eq(rbatis_name) {
109            continue;
110        }
111        let mut do_continue = false;
112        for x in skip_names {
113            if x.eq(&item_ident_name) {
114                do_continue = true;
115                break;
116            }
117        }
118        if do_continue {
119            continue;
120        }
121        sql_args_gen = quote! {
122             #sql_args_gen
123             rb_args.push(rbs::value(#item)?);
124        };
125    }
126    sql_args_gen
127}