Skip to main content

robotech_macros/
lib.rs

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