robotech_macros/lib.rs
1mod dao;
2mod db;
3mod dto;
4mod log;
5mod svc;
6mod vo;
7mod web;
8
9use crate::dao::{dao_macro, DaoArgs};
10use crate::db::MigrateArgs;
11use crate::dto::crud_dto_macro;
12use crate::log::{log_call_macro, LogCallArgs};
13use crate::svc::{db_unwrap_macro, svc_macro, DbUnwrapArgs};
14use crate::vo::vo_macro;
15use crate::web::{api_doc_macro, ctrl_macro, router_macro, ApiDocArgs, RouterArgs};
16use proc_macro::TokenStream;
17use syn::{parse_macro_input, DeriveInput, ItemFn, ItemStruct};
18
19/// 属性宏:在进入方法时使用 log 库记录方法名、参数及参数值
20///
21/// # 使用示例
22/// ```
23/// // 使用默认 debug 级别
24/// #[log_call]
25/// fn add(a: i32, b: i32) -> i32 {
26/// a + b
27/// }
28///
29/// // 指定日志级别
30/// #[log_call(level = info)]
31/// fn process(data: &str) {
32/// // ...
33/// }
34///
35/// #[log_call(level = warn)]
36/// fn risky_operation() {
37/// // ...
38/// }
39/// ```
40///
41/// 支持的日志级别: trace, debug (默认), info, warn, error
42#[proc_macro_attribute]
43pub fn log_call(args: TokenStream, input: TokenStream) -> TokenStream {
44 // 解析属性参数
45 let args = parse_macro_input!(args as LogCallArgs);
46 let input = parse_macro_input!(input as ItemFn);
47 log_call_macro(args, input).into()
48}
49
50#[proc_macro]
51pub fn db_migrate(args: TokenStream) -> TokenStream {
52 let args = parse_macro_input!(args as MigrateArgs);
53 db::db_migrate_macro(args).into()
54}
55
56/// 属性宏:为XxxDto结构体自动生成XxxAddDto、XxxModifyDto、XxxSaveDto
57///
58/// # 使用示例
59/// ```
60/// #[crud_dto]
61/// pub struct OssBucketDto {
62/// /// 名称
63/// pub name: String,
64/// /// 备注
65/// pub remark: Option<String>,
66/// }
67/// ```
68///
69/// 上述代码会被展开为三个结构体:
70/// - OssBucketAddDto(带验证)
71/// - OssBucketModifyDto(不带验证)
72/// - OssBucketSaveDto(不带验证)
73#[proc_macro_attribute]
74pub fn crud_dto(_args: TokenStream, input: TokenStream) -> TokenStream {
75 let input = parse_macro_input!(input as ItemStruct);
76 crud_dto_macro(input).into()
77}
78
79/// 属性宏:为 VO 结构体自动生成标准属性
80///
81/// 此宏会自动为 VO 结构体添加以下属性和派生宏:
82/// - `#[skip_serializing_none]` - 跳过空字段序列化
83/// - `#[derive(o2o, ToSchema, Debug, Serialize, Clone)]` - 必要的派生宏
84/// - `#[from_owned(Model)]` - o2o 转换配置
85/// - `#[serde(rename_all = "camelCase")]` - 驼峰命名
86/// - `#[serde_as]` - serde_with 支持
87///
88/// 同时会自动为无符号整型字段添加:
89/// - `#[from(~ as u64)]` 或 `#[from(~.to_string())]` - 根据字段名自动判断
90/// - `#[serde_as(as = "String")]` - 避免 JS 精度丢失
91///
92/// # 使用示例
93/// ```
94/// #[vo]
95/// pub struct StudentVo {
96/// /// ID
97/// pub id: u64,
98/// /// 名称
99/// pub name: String,
100/// /// 备注
101/// pub remark: Option<String>,
102/// }
103/// ```
104///
105/// 上述代码会被展开为:
106/// ```
107/// #[skip_serializing_none]
108/// #[derive(o2o, ToSchema, Debug, Serialize, Clone)]
109/// #[from_owned(Model)]
110/// #[serde(rename_all = "camelCase")]
111/// #[serde_as]
112/// pub struct StudentVo {
113/// /// ID
114/// #[from(~ as u64)]
115/// #[serde_as(as = "String")]
116/// pub id: u64,
117/// /// 名称
118/// pub name: String,
119/// /// 备注
120/// pub remark: Option<String>,
121/// }
122/// ```
123#[proc_macro_attribute]
124pub fn vo(_args: TokenStream, input: TokenStream) -> TokenStream {
125 let input = parse_macro_input!(input as DeriveInput);
126 vo_macro(input).into()
127}
128
129/// 属性宏:为DAO结构体生成标准的CRUD方法
130///
131/// # 使用示例
132/// ```
133/// // 生成所有方法
134/// #[dao(all)]
135/// pub struct MyDao;
136///
137/// // 选择性生成方法
138/// #[dao(insert, update, get_by_id)]
139/// pub struct MyDao;
140///
141/// // 只生成查询方法
142/// #[dao(get_by_id)]
143/// pub struct MyDao;
144/// ```
145///
146/// 支持的方法选项:
147/// - insert: 生成插入方法
148/// - update: 生成更新方法
149/// - delete: 生成删除方法
150/// - get_by_id: 生成根据ID查询方法
151/// - all: 生成所有方法
152#[proc_macro_attribute]
153pub fn dao(args: TokenStream, input: TokenStream) -> TokenStream {
154 let args = parse_macro_input!(args as DaoArgs);
155 let input = parse_macro_input!(input as ItemStruct);
156 dao_macro(args, input).into()
157}
158
159/// 属性宏:为Service查询方法生成标准结构
160///
161/// 此宏会自动处理数据库连接逻辑,用户只需编写返回语句
162///
163/// # 使用示例
164/// ```
165/// #[db_unwrap]
166/// pub async fn get_by_name<C>(name: &str, db: Option<&C>) -> Result<Ro<OssBucketVo>, SvcError>
167/// where
168/// C: ConnectionTrait,
169/// {
170/// let one = OssBucketDao::get_by_name(name, db).await?;
171/// Ok(
172/// Ro::success("查询成功".to_string())
173/// .extra(one.map(|value| OssBucketVo::from(value))),
174/// )
175/// }
176/// ```
177/// 注意:用户代码中应该包含完整的返回逻辑
178#[proc_macro_attribute]
179pub fn db_unwrap(args: TokenStream, input: TokenStream) -> TokenStream {
180 let args = parse_macro_input!(args as DbUnwrapArgs);
181 let input = parse_macro_input!(input as ItemFn);
182 db_unwrap_macro(args, input).into()
183}
184
185#[proc_macro_attribute]
186pub fn svc(_args: TokenStream, input: TokenStream) -> TokenStream {
187 let input = parse_macro_input!(input as ItemStruct);
188 svc_macro(input).into()
189}
190
191#[proc_macro_attribute]
192pub fn ctrl(_args: TokenStream, input: TokenStream) -> TokenStream {
193 let input = parse_macro_input!(input as ItemStruct);
194 ctrl_macro(input).into()
195}
196
197#[proc_macro_attribute]
198pub fn router(args: TokenStream, input: TokenStream) -> TokenStream {
199 let args = parse_macro_input!(args as RouterArgs);
200 let input = parse_macro_input!(input as ItemStruct);
201 router_macro(args, input).into()
202}
203
204#[proc_macro_attribute]
205pub fn api_doc(args: TokenStream, input: TokenStream) -> TokenStream {
206 let args = parse_macro_input!(args as ApiDocArgs);
207 let input = parse_macro_input!(input as ItemStruct);
208 api_doc_macro(args, input).into()
209}