rbatis_macro_driver/
lib.rs

1#![allow(unused_assignments)]
2extern crate proc_macro;
3extern crate rbatis_codegen;
4
5use syn::parse::{Parse, ParseStream};
6use syn::punctuated::Punctuated;
7use syn::{parse_macro_input, ItemFn, Token};
8
9use crate::macros::html_sql_impl::impl_macro_html_sql;
10use crate::macros::py_sql_impl::impl_macro_py_sql;
11use crate::macros::sql_impl::impl_macro_sql;
12use crate::proc_macro::TokenStream;
13
14mod macros;
15mod util;
16
17struct ParseArgs {
18    pub sqls: Vec<syn::LitStr>,
19}
20
21impl Parse for ParseArgs {
22    fn parse(input: ParseStream) -> syn::Result<Self> {
23        let r = Punctuated::<syn::LitStr, Token![,]>::parse_terminated(input)?;
24        Ok(Self {
25            sqls: r.into_iter().collect(),
26        })
27    }
28}
29
30/// auto create sql macro,this macro use RB.query_prepare and RB.exec_prepare
31/// for example:
32///```log
33///     use rbatis::plugin;
34///     use rbatis::executor::Executor;
35///     #[derive(serde::Serialize,serde::Deserialize)]
36///     pub struct MockTable{}
37///
38///     #[sql("select * from biz_activity where id = ?")]
39///     async fn select(rb:&dyn Executor, name: &str) -> MockTable {}
40///```
41#[proc_macro_attribute]
42pub fn sql(args: TokenStream, func: TokenStream) -> TokenStream {
43    let args = parse_macro_input!(args as ParseArgs);
44    let target_fn: ItemFn = syn::parse(func).unwrap();
45    let stream = impl_macro_sql(&target_fn, &args);
46    #[cfg(feature = "println_gen")]
47    if cfg!(debug_assertions) {
48        use quote::ToTokens;
49        let func_name_ident = target_fn.sig.ident.to_token_stream();
50        println!("............#[sql] '{}'...................\n {}", func_name_ident, stream);
51        println!(".......................................................");
52    }
53
54    stream
55}
56
57/// py sql create macro,this macro use RB.py_query and RB.py_exec
58///```log
59/// use rbatis::executor::Executor;
60/// use rbatis::py_sql;
61/// #[derive(serde::Serialize,serde::Deserialize)]
62/// pub struct MockTable{}
63///
64/// #[py_sql("select * from biz_activity where delete_flag = 0")]
65/// async fn py_select_page(rb: &dyn Executor, name: &str) -> Vec<MockTable> { }
66///```
67///  or more example:
68///```log
69/// use rbatis::executor::Executor;
70/// use rbatis::py_sql;
71/// #[derive(serde::Serialize,serde::Deserialize)]
72/// pub struct MockTable{}
73///
74/// #[py_sql("
75///     SELECT * FROM biz_activity
76///     if  name != null:
77///       AND delete_flag = #{del}
78///       AND version = 1
79///       if  age!=1:
80///         AND version = 1
81///       AND version = 1
82///     AND a = 0
83///       AND version = 1
84///     and id in (
85///     trim ',': for item in ids:
86///       #{item},
87///     )
88///     and id in (
89///     trim ',': for index,item in ids:
90///       #{item},
91///     )
92///     trim 'AND':
93///       AND delete_flag = #{del2}
94///     choose:
95///         when age==27:
96///           AND age = 27
97///         otherwise:
98///           AND age = 0
99///     WHERE id  = '2'")]
100///   pub async fn py_select_rb(rb: &dyn Executor, name: &str) -> Option<MockTable> {}
101/// ```
102/// or read from file
103/// ```rust
104/// //#[rbatis::py_sql(r#"include!("C:/rs/rbatis/target/debug/xx.py_sql")"#)]
105/// //pub async fn test_same_id(rb: &dyn Executor, id: &u64) -> Result<Value, Error> { impled!() }
106/// ```
107#[proc_macro_attribute]
108pub fn py_sql(args: TokenStream, func: TokenStream) -> TokenStream {
109    let args = parse_macro_input!(args as ParseArgs);
110    let target_fn: ItemFn = syn::parse(func).unwrap();
111    let stream = impl_macro_py_sql(&target_fn, args);
112    #[cfg(feature = "println_gen")]
113    if cfg!(debug_assertions) {
114        use quote::ToTokens;
115        use rust_format::{Formatter, RustFmt};
116        let func_name_ident = target_fn.sig.ident.to_token_stream();
117        let stream_str = stream.to_string().replace("$crate", "rbatis");
118        let code = RustFmt::default()
119            .format_str(&stream_str)
120            .unwrap_or_else(|_e| stream_str.to_string());
121        println!("............#[py_sql] '{}'............\n {}", func_name_ident, code);
122        println!(".......................................................");
123    }
124    stream
125}
126
127/// html sql create macro,this macro use RB.py_query and RB.py_exec
128/// for example:
129/// ```log
130/// use rbatis::executor::Executor;
131/// use rbatis::html_sql;
132/// #[derive(serde::Serialize,serde::Deserialize)]
133/// pub struct MockTable{}
134///
135/// #[html_sql(r#"
136/// <select id="select_by_condition">
137///         `select * from activity`
138///         <where>
139///             <if test="name != ''">
140///                 ` and name like #{name}`
141///             </if>
142///             <if test="dt >= '2023-11-03T21:13:09.9357266+08:00'">
143///                 ` and create_time < #{dt}`
144///             </if>
145///             <choose>
146///                 <when test="true">
147///                     ` and id != '-1'`
148///                 </when>
149///                 <otherwise>and id != -2</otherwise>
150///             </choose>
151///             ` and `
152///             <trim prefixOverrides=" and">
153///                 ` and name != '' `
154///             </trim>
155///         </where>
156///   </select>"#)]
157/// pub async fn select_by_name(rbatis: &dyn Executor, name: &str) -> Option<MockTable> {}
158/// ```
159/// or from file
160/// ```log
161/// #[html_sql("xxxx.html")]
162/// pub async fn select_by_name(rbatis: &dyn Executor, name: &str) -> Option<MockTable> {}
163/// ```
164#[proc_macro_attribute]
165pub fn html_sql(args: TokenStream, func: TokenStream) -> TokenStream {
166    let args = parse_macro_input!(args as ParseArgs);
167    let target_fn: ItemFn = syn::parse(func).unwrap();
168    let stream = impl_macro_html_sql(&target_fn, &args);
169    #[cfg(feature = "println_gen")]
170    if cfg!(debug_assertions) {
171        use quote::ToTokens;
172        use rust_format::{Formatter, RustFmt};
173        let func_name_ident = target_fn.sig.ident.to_token_stream();
174        let stream_str = stream.to_string().replace("$crate", "rbatis");
175        let code = RustFmt::default()
176            .format_str(&stream_str)
177            .unwrap_or_else(|_e| stream_str.to_string());
178        println!("............#[html_sql] '{}'............\n {}", func_name_ident, code);
179        println!(".......................................................");
180    }
181    stream
182}
183
184/// proxy rbatis_codegen rb_py
185#[proc_macro_attribute]
186pub fn rb_py(args: TokenStream, func: TokenStream) -> TokenStream {
187    rbatis_codegen::rb_py(args, func)
188}
189
190/// proxy rbatis_codegen rb_html
191#[proc_macro_attribute]
192pub fn rb_html(args: TokenStream, func: TokenStream) -> TokenStream {
193    rbatis_codegen::rb_html(args, func)
194}
195
196#[proc_macro_attribute]
197pub fn snake_name(args: TokenStream, func: TokenStream) -> TokenStream {
198    macros::snake_name::snake_name(args, func)
199}