openlark_docs/common/
request_builder.rs1#[macro_export]
76macro_rules! impl_required_builder {
77 (
78 $request_name:ident,
79 $builder_name:ident,
80 required: [$($req_field:ident: $req_type:ty),* $(,)?],
81 optional: [$($opt_field:ident: $opt_type:ty),* $(,)?]
82 ) => {
83 #[derive(Debug, Default)]
84 pub struct $builder_name {
85 $(
86 $req_field: Option<$req_type>,
87 )*
88 $(
89 $opt_field: Option<$opt_type>,
90 )*
91 config: Option<openlark_core::config::Config>,
92 _phantom: std::marker::PhantomData<$request_name>,
93 }
94
95 impl $builder_name {
96 #[deprecated(since = "0.5.0", note = "使用 builder() 替代")]
98 #[allow(dead_code)]
99 pub fn new() -> Self {
100 Self::default()
101 }
102
103 pub fn with_config(mut self, config: openlark_core::config::Config) -> Self {
105 self.config = Some(config);
106 self
107 }
108
109 $(
110 pub fn $req_field(mut self, value: impl Into<$req_type>) -> Self {
112 self.$req_field = Some(value.into());
113 self
114 }
115 )*
116
117 $(
118 pub fn $opt_field(mut self, value: impl Into<$opt_type>) -> Self {
120 self.$opt_field = Some(value.into());
121 self
122 }
123 )*
124
125 pub fn build(self) -> openlark_core::SDKResult<$request_name> {
127 $(
129 let $req_field = self.$req_field.ok_or_else(|| {
130 openlark_core::error::validation_error(
131 stringify!($req_field),
132 concat!("必填字段 '", stringify!($req_field), "' 未设置")
133 )
134 })?;
135 )*
136
137 let config = self.config.ok_or_else(|| {
138 openlark_core::error::validation_error(
139 "config",
140 "Config 未设置,请使用 with_config() 方法"
141 )
142 })?;
143
144 Ok($request_name {
145 $(
146 $req_field,
147 )*
148 $(
149 $opt_field: self.$opt_field,
150 )*
151 config,
152 })
153 }
154 }
155
156 impl $request_name {
157 pub fn builder() -> $builder_name {
159 $builder_name::default()
160 }
161 }
162 };
163}
164
165#[macro_export]
189macro_rules! impl_fluent_builder {
190 (
191 $request_name:ident,
192 config: Config,
193 required: [$($req_field:ident: $req_type:ty),* $(,)?],
194 optional: [$($opt_field:ident: $opt_type:ty),* $(,)?]
195 ) => {
196 impl $request_name {
197 pub fn builder() -> $request_name {
199 Self {
200 $(
201 $req_field: String::new(),
202 )*
203 $(
204 $opt_field: None,
205 )*
206 config: Config::default(),
207 }
208 }
209
210 $(
211 pub fn $req_field(mut self, value: impl Into<$req_type>) -> Self {
213 self.$req_field = value.into();
214 self
215 }
216 )*
217
218 $(
219 pub fn $opt_field(mut self, value: impl Into<$opt_type>) -> Self {
221 self.$opt_field = Some(value.into());
222 self
223 }
224 )*
225 }
226 };
227}
228
229#[cfg(test)]
230mod tests {
231 use openlark_core::config::Config;
232
233 #[derive(Debug, Clone)]
235 pub struct TestRequest {
236 app_token: String,
237 table_id: String,
238 user_id_type: Option<String>,
239 #[allow(dead_code)]
240 config: Config,
241 }
242
243 impl_required_builder!(
245 TestRequest,
246 TestRequestBuilder,
247 required: [
248 app_token: String,
249 table_id: String
250 ],
251 optional: [
252 user_id_type: String
253 ]
254 );
255
256 #[test]
257 fn test_required_builder_success() {
258 let config = Config::builder().app_id("test").app_secret("test").build();
259
260 let request = TestRequest::builder()
261 .with_config(config)
262 .app_token("token")
263 .table_id("table")
264 .build()
265 .unwrap();
266
267 assert_eq!(request.app_token, "token");
268 assert_eq!(request.table_id, "table");
269 assert!(request.user_id_type.is_none());
270 }
271
272 #[test]
273 fn test_required_builder_with_optional() {
274 let config = Config::builder().app_id("test").app_secret("test").build();
275
276 let request = TestRequest::builder()
277 .with_config(config)
278 .app_token("token")
279 .table_id("table")
280 .user_id_type("open_id")
281 .build()
282 .unwrap();
283
284 assert_eq!(request.user_id_type, Some("open_id".to_string()));
285 }
286
287 #[test]
288 fn test_required_builder_missing_required_field() {
289 let config = Config::builder().app_id("test").app_secret("test").build();
290
291 let result = TestRequest::builder()
292 .with_config(config)
293 .app_token("token")
294 .build();
296
297 assert!(result.is_err());
298 assert!(result.unwrap_err().to_string().contains("table_id"));
299 }
300
301 #[test]
302 fn test_required_builder_missing_config() {
303 let result = TestRequest::builder()
304 .app_token("token")
305 .table_id("table")
306 .build();
308
309 assert!(result.is_err());
310 assert!(result.unwrap_err().to_string().contains("Config"));
311 }
312
313 #[test]
314 fn test_required_builder_into_string() {
315 let config = Config::builder().app_id("test").app_secret("test").build();
316
317 let request = TestRequest::builder()
319 .with_config(config)
320 .app_token("token") .table_id(String::from("table")) .build()
323 .unwrap();
324
325 assert_eq!(request.app_token, "token");
326 assert_eq!(request.table_id, "table");
327 }
328}