rbatis/crud.rs
1///PySql: gen select*,update*,insert*,delete* ... methods
2///```rust
3/// use rbs::value;
4/// use rbatis::{Error, RBatis};
5///
6/// #[derive(serde::Serialize, serde::Deserialize)]
7/// pub struct MockTable{
8/// pub id: Option<String>
9/// }
10/// rbatis::crud!(MockTable{}); //or crud!(MockTable{},"mock_table");
11///
12/// //use
13/// async fn test_use(rb:&RBatis) -> Result<(),Error>{
14/// let table = MockTable{id: Some("1".to_string())};
15/// let r = MockTable::insert(rb, &table).await;
16/// let r = MockTable::insert_batch(rb, std::slice::from_ref(&table),10).await;
17///
18/// let tables = MockTable::select_by_map(rb,value!{"id":"1"}).await;
19/// let tables = MockTable::select_all(rb).await;
20/// let tables = MockTable::select_by_map(rb,value!{"id":["1","2","3"]}).await;
21/// let tables = MockTable::select_by_map(rb,value!{"id":"1", "column": ["id", "name"]}).await?;
22///
23/// let r = MockTable::update_by_map(rb, &table, value!{"id":"1"}).await;
24///
25/// let r = MockTable::delete_by_map(rb, value!{"id":"1"}).await;
26/// //... and more
27/// Ok(())
28/// }
29///
30///
31/// ```
32#[macro_export]
33macro_rules! crud {
34 ($table:ty{}) => {
35 $crate::impl_insert!($table {});
36 $crate::impl_select!($table {});
37 $crate::impl_update!($table {});
38 $crate::impl_delete!($table {});
39 };
40 ($table:ty{},$table_name:expr) => {
41 $crate::impl_insert!($table {}, $table_name);
42 $crate::impl_select!($table {}, $table_name);
43 $crate::impl_update!($table {}, $table_name);
44 $crate::impl_delete!($table {}, $table_name);
45 };
46}
47
48///PySql: gen sql => INSERT INTO table_name (column1,column2,column3,...) VALUES (value1,value2,value3,...);
49///
50/// example:
51///```rust
52/// use rbatis::{Error, RBatis};
53/// #[derive(serde::Serialize, serde::Deserialize)]
54/// pub struct MockTable{
55/// pub id: Option<String>
56/// }
57/// rbatis::impl_insert!(MockTable{});
58///
59/// //use
60/// async fn test_use(rb:&RBatis) -> Result<(),Error>{
61/// let table = MockTable{id: Some("1".to_string())};
62/// let r = MockTable::insert(rb, &table).await;
63/// let r = MockTable::insert_batch(rb, std::slice::from_ref(&table),10).await;
64/// Ok(())
65/// }
66/// ```
67///
68#[macro_export]
69macro_rules! impl_insert {
70 ($table:ty{}) => {
71 $crate::impl_insert!($table {}, "");
72 };
73 ($table:ty{},$table_name:expr) => {
74 impl $table {
75 pub async fn insert_batch(
76 executor: &dyn $crate::executor::Executor,
77 tables: &[$table],
78 batch_size: u64,
79 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
80 use $crate::crud_traits::ColumnSet;
81 #[$crate::py_sql(
82 "`insert into ${table_name} `
83 trim ',':
84 bind columns = tables.column_sets():
85 for idx,table in tables:
86 if idx == 0:
87 `(`
88 trim ',':
89 for _,v in columns:
90 ${v},
91 `) VALUES `
92 (
93 trim ',':
94 for _,v in columns:
95 #{table[v]},
96 ),
97 "
98 )]
99 async fn insert_batch(
100 executor: &dyn $crate::executor::Executor,
101 tables: &[$table],
102 table_name: &str,
103 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error>
104 {
105 impled!()
106 }
107 if tables.is_empty() {
108 return Err($crate::rbdc::Error::from(
109 "insert can not insert empty array tables!",
110 ));
111 }
112 let mut table_name = $table_name.to_string();
113 if table_name.is_empty(){
114 #[$crate::snake_name($table)]
115 fn snake_name(){}
116 table_name = snake_name();
117 }
118 let mut result = $crate::rbdc::db::ExecResult {
119 rows_affected: 0,
120 last_insert_id: rbs::Value::Null,
121 };
122 let ranges = $crate::plugin::Page::<()>::make_ranges(tables.len() as u64, batch_size);
123 for (offset, limit) in ranges {
124 let exec_result = insert_batch(
125 executor,
126 &tables[offset as usize..limit as usize],
127 table_name.as_str(),
128 )
129 .await?;
130 result.rows_affected += exec_result.rows_affected;
131 result.last_insert_id = exec_result.last_insert_id;
132 }
133 Ok(result)
134 }
135
136 pub async fn insert(
137 executor: &dyn $crate::executor::Executor,
138 table: &$table,
139 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
140 <$table>::insert_batch(executor, std::slice::from_ref(table), 1).await
141 }
142 }
143 };
144}
145
146///PySql: gen sql => SELECT (column1,column2,column3,...) FROM table_name (column1,column2,column3,...) *** WHERE ***
147///
148/// Supports selective column queries by specifying "column" key in condition:
149///```rust
150/// use rbs::value;
151/// use rbatis::{Error, RBatis};
152/// #[derive(serde::Serialize, serde::Deserialize)]
153/// pub struct MockTable{
154/// pub id: Option<String>,
155/// pub name: Option<String>,
156/// pub status: Option<String>
157/// }
158/// /// default
159///rbatis::impl_select!(MockTable{});
160///rbatis::impl_select!(MockTable{select_all_by_id(id:&str,name:&str) => "`where id = #{id} and name = #{name}`"});
161/// /// container result
162///rbatis::impl_select!(MockTable{select_by_id(id:String) -> Option => "`where id = #{id} limit 1`"});
163///rbatis::impl_select!(MockTable{select_by_id2(id:String) -> Vec => "`where id = #{id} limit 1`"});
164///
165/// //usage
166/// async fn test_select(rb:&RBatis) -> Result<(),Error>{
167/// // Select all columns
168/// let r = MockTable::select_by_map(rb,value!{"id":"1"}).await?;
169///
170/// // Select only specific columns (id and name)
171/// let r = MockTable::select_by_map(rb,value!{"id":"1", "column": ["id", "name"]}).await?;
172///
173/// let r = MockTable::select_all_by_id(rb,"1","xxx").await?;
174/// let r:Option<MockTable> = MockTable::select_by_id(rb,"1".to_string()).await?;
175/// let r:Vec<MockTable> = MockTable::select_by_id2(rb,"1".to_string()).await?;
176/// Ok(())
177/// }
178/// ```
179///
180#[macro_export]
181macro_rules! impl_select {
182 ($table:ty{}) => {
183 $crate::impl_select!($table{},"");
184 };
185 ($table:ty{},$table_name:expr) => {
186 $crate::impl_select!($table{select_all() => ""},$table_name);
187 impl $table {
188 pub async fn select_by_map(executor: &dyn $crate::executor::Executor, mut condition: rbs::Value) -> std::result::Result<Vec<$table>, $crate::rbdc::Error> {
189 use rbatis::crud_traits::ValueOperatorSql;
190
191 // Extract column specification and remove it from condition
192 let table_column = {
193 let mut columns = String::new();
194 let mut clean_map = rbs::value::map::ValueMap::with_capacity(condition.len());
195 for (k, v) in condition {
196 match k.as_str() {
197 Some("column") => {
198 columns = match v {
199 rbs::Value::String(s) => s.clone(),
200 rbs::Value::Array(arr) => {
201 let cols: Vec<&str> = arr.iter()
202 .filter_map(|v| v.as_str())
203 .collect();
204 if cols.is_empty() { "*".to_string() } else { cols.join(", ") }
205 }
206 _ => "*".to_string(),
207 };
208 }
209 _ => { clean_map.insert(k.clone(), v.clone()); }
210 }
211 }
212 if columns.is_empty() { columns = "*".to_string(); }
213 condition = rbs::Value::Map(clean_map);
214 columns
215 };
216
217 #[$crate::py_sql(
218 "`select ${table_column} from ${table_name}`
219 trim end=' where ':
220 ` where `
221 trim ' and ': for key,item in condition:
222 if item == null:
223 continue:
224 if !item.is_array():
225 ` and ${key.operator_sql()}#{item}`
226 if item.is_array():
227 ` and ${key} in (`
228 trim ',': for _,item_array in item:
229 #{item_array},
230 `)`
231 ")]
232 async fn select_by_map(
233 executor: &dyn $crate::executor::Executor,
234 table_name: String,
235 table_column: &str,
236 condition: &rbs::Value
237 ) -> std::result::Result<Vec<$table>, $crate::rbdc::Error> {
238 for (_,v) in condition {
239 if v.is_array() && v.is_empty(){
240 return Ok(vec![]);
241 }
242 }
243 impled!()
244 }
245 let mut table_name = $table_name.to_string();
246 if table_name.is_empty(){
247 #[$crate::snake_name($table)]
248 fn snake_name(){}
249 table_name = snake_name();
250 }
251 select_by_map(executor, table_name, &table_column, &condition).await
252 }
253 }
254 };
255 ($table:ty{$fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty $(,)?)*) => $sql:expr}$(,$table_name:expr)?) => {
256 $crate::impl_select!($table{$fn_name$(<$($gkey:$gtype,)*>)?($($param_key:$param_type,)*) ->Vec => $sql}$(,$table_name)?);
257 };
258 ($table:ty{$fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty $(,)?)*) -> $container:tt => $sql:expr}$(,$table_name:expr)?) => {
259 impl $table{
260 pub async fn $fn_name $(<$($gkey:$gtype,)*>)? (executor: &dyn $crate::executor::Executor,$($param_key:$param_type,)*) -> std::result::Result<$container<$table>,$crate::rbdc::Error>
261 {
262 use rbatis::crud_traits::ValueOperatorSql;
263 #[$crate::py_sql("`select ${table_column} from ${table_name} `\n",$sql)]
264 async fn $fn_name$(<$($gkey: $gtype,)*>)?(executor: &dyn $crate::executor::Executor,table_column:&str,table_name:&str,$($param_key:$param_type,)*) -> std::result::Result<$container<$table>,$crate::rbdc::Error> {impled!()}
265
266 let mut table_column = "*".to_string();
267 let mut table_name = String::new();
268 $(table_name = $table_name.to_string();)?
269 if table_name.is_empty(){
270 #[$crate::snake_name($table)]
271 fn snake_name(){}
272 table_name = snake_name();
273 }
274 $fn_name(executor,&table_column,&table_name,$($param_key ,)*).await
275 }
276 }
277 };
278}
279
280/// PySql: gen sql = UPDATE table_name SET column1=value1,column2=value2,... WHERE some_column=some_value;
281///
282/// Supports selective column updates by specifying "column" key in condition (GitHub issue #591):
283/// ```rust
284/// use rbs::value;
285/// use rbatis::{Error, RBatis};
286/// #[derive(serde::Serialize, serde::Deserialize)]
287/// pub struct MockTable{
288/// pub id: Option<String>,
289/// pub name: Option<String>,
290/// pub status: Option<String>
291/// }
292/// rbatis::impl_update!(MockTable{});
293/// //use
294/// async fn test_use(rb:&RBatis) -> Result<(),Error>{
295/// let table = MockTable{
296/// id: Some("1".to_string()),
297/// name: Some("test".to_string()),
298/// status: Some("active".to_string())
299/// };
300/// // Update all columns
301/// let r = MockTable::update_by_map(rb, &table, value!{"id":"1"}).await;
302///
303/// // Update only specific columns (name and status)
304/// let r = MockTable::update_by_map(rb, &table, value!{"id":"1", "column": ["name", "status"]}).await;
305/// Ok(())
306/// }
307/// ```
308#[macro_export]
309macro_rules! impl_update {
310 ($table:ty{}) => {
311 $crate::impl_update!(
312 $table{},
313 ""
314 );
315 };
316 ($table:ty{},$table_name:expr) => {
317 impl $table {
318 pub async fn update_by_map(
319 executor: &dyn $crate::executor::Executor,
320 table: &$table,
321 mut condition: rbs::Value
322 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
323 use rbatis::crud_traits::{ValueOperatorSql, FilterByColumns};
324
325 // Extract column list for selective updates - implements GitHub issue #591
326 // This allows updating only specific columns by specifying them in the condition
327 // Example: update_by_map(&rb, &activity, value!{"id": "123", "column": ["name", "status"]})
328 let set_columns = {
329 let mut columns = rbs::Value::Null;
330 let mut clean_map = rbs::value::map::ValueMap::with_capacity(condition.len());
331 for (k, v) in condition {
332 match k.as_str() {
333 Some("column") => {
334 // Normalize column specification to Array format for filter_by_columns
335 columns = match v {
336 rbs::Value::String(s) => {
337 rbs::Value::Array(vec![rbs::Value::String(s.clone())])
338 }
339 rbs::Value::Array(arr) => {
340 let filtered_array: Vec<rbs::Value> = arr.iter()
341 .filter(|v| v.as_str().is_some())
342 .cloned()
343 .collect();
344 if filtered_array.is_empty() {
345 rbs::Value::Null
346 } else {
347 rbs::Value::Array(filtered_array)
348 }
349 }
350 _ => rbs::Value::Null,
351 };
352 }
353 _ => { clean_map.insert(k.clone(), v.clone()); }
354 }
355 }
356 condition = rbs::Value::Map(clean_map);
357 columns
358 };
359 #[$crate::py_sql(
360 "`update ${table_name}
361 if skip_null == false:
362 set collection='table',skips='id',skip_null=false:
363 if skip_null == true:
364 set collection='table',skips='id':
365 trim end=' where ':
366 ` where `
367 trim ' and ': for key,item in condition:
368 if item == null:
369 continue:
370 if !item.is_array():
371 ` and ${key.operator_sql()}#{item}`
372 if item.is_array():
373 ` and ${key} in (`
374 trim ',': for _,item_array in item:
375 #{item_array},
376 `)`
377 "
378 )]
379 async fn update_by_map_internal(
380 executor: &dyn $crate::executor::Executor,
381 table_name: String,
382 table: &rbs::Value,
383 condition: &rbs::Value,
384 skip_null: bool,
385 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
386 for (_,v) in condition {
387 if v.is_array() && v.is_empty(){
388 return Ok($crate::rbdc::db::ExecResult::default());
389 }
390 }
391 impled!()
392 }
393 let mut table_name = $table_name.to_string();
394 if table_name.is_empty(){
395 #[$crate::snake_name($table)]
396 fn snake_name(){}
397 table_name = snake_name();
398 }
399 let table_value = rbs::value!(table);
400 let mut skip_null = true;
401 let table = if set_columns != rbs::Value::Null {
402 skip_null = false;
403 table_value.filter_by_columns(&set_columns)
404 } else {
405 table_value
406 };
407 update_by_map_internal(executor, table_name, &table, &condition, skip_null).await
408 }
409 }
410 };
411 ($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $sql_where:expr}$(,$table_name:expr)?) => {
412 impl $table {
413 pub async fn $fn_name(
414 executor: &dyn $crate::executor::Executor,
415 table: &$table,
416 $($param_key:$param_type,)*
417 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
418 use rbatis::crud_traits::ValueOperatorSql;
419 if $sql_where.is_empty(){
420 return Err($crate::rbdc::Error::from("sql_where can't be empty!"));
421 }
422 #[$crate::py_sql("`update ${table_name}`\n set collection='table',skips='id':\n",$sql_where)]
423 async fn $fn_name(
424 executor: &dyn $crate::executor::Executor,
425 table_name: String,
426 table: &rbs::Value,
427 $($param_key:$param_type,)*
428 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
429 impled!()
430 }
431 let mut table_name = String::new();
432 $(table_name = $table_name.to_string();)?
433 if table_name.is_empty(){
434 #[$crate::snake_name($table)]
435 fn snake_name(){}
436 table_name = snake_name();
437 }
438 let table = rbs::value!(table);
439 $fn_name(executor, table_name, &table, $($param_key,)*).await
440 }
441 }
442 };
443}
444
445/// PySql: gen sql = DELETE FROM table_name WHERE some_column=some_value;
446///
447/// ```rust
448/// use rbs::value;
449/// use rbatis::{Error, RBatis};
450/// #[derive(serde::Serialize, serde::Deserialize)]
451/// pub struct MockTable{}
452/// rbatis::impl_delete!(MockTable{});
453///
454/// //use
455/// async fn test_use(rb:&RBatis) -> Result<(),Error>{
456/// let r = MockTable::delete_by_map(rb, value!{"id":"1"}).await;
457/// //... and more
458/// Ok(())
459/// }
460/// ```
461#[macro_export]
462macro_rules! impl_delete {
463 ($table:ty{}) => {
464 $crate::impl_delete!(
465 $table{},
466 ""
467 );
468 };
469 ($table:ty{},$table_name:expr) => {
470 impl $table {
471 pub async fn delete_by_map(executor: &dyn $crate::executor::Executor, condition: rbs::Value) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
472 use rbatis::crud_traits::ValueOperatorSql;
473 #[$crate::py_sql(
474 "`delete from ${table_name}`
475 trim end=' where ':
476 ` where `
477 trim ' and ': for key,item in condition:
478 if item == null:
479 continue:
480 if !item.is_array():
481 ` and ${key.operator_sql()}#{item}`
482 if item.is_array():
483 ` and ${key} in (`
484 trim ',': for _,item_array in item:
485 #{item_array},
486 `)`
487 ")]
488 async fn delete_by_map(
489 executor: &dyn $crate::executor::Executor,
490 table_name: String,
491 condition: &rbs::Value
492 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
493 for (_,v) in condition {
494 if v.is_array() && v.is_empty(){
495 return Ok($crate::rbdc::db::ExecResult::default());
496 }
497 }
498 impled!()
499 }
500 let mut table_name = $table_name.to_string();
501 if table_name.is_empty(){
502 #[$crate::snake_name($table)]
503 fn snake_name(){}
504 table_name = snake_name();
505 }
506 delete_by_map(executor, table_name, &condition).await
507 }
508 }
509};
510( $ table:ty{$ fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty$(,)?)*) => $sql_where:expr}$(,$table_name:expr)?) => {
511 impl $table {
512 pub async fn $fn_name$(<$($gkey:$gtype,)*>)?(
513 executor: &dyn $crate::executor::Executor,
514 $($param_key:$param_type,)*
515 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
516 use rbatis::crud_traits::ValueOperatorSql;
517 if $sql_where.is_empty(){
518 return Err($crate::rbdc::Error::from("sql_where can't be empty!"));
519 }
520 #[$crate::py_sql("`delete from ${table_name} `\n",$sql_where)]
521 async fn $fn_name$(<$($gkey: $gtype,)*>)?(
522 executor: &dyn $crate::executor::Executor,
523 table_name: String,
524 $($param_key:$param_type,)*
525 ) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
526 impled!()
527 }
528 let mut table_name = String::new();
529 $(table_name = $table_name.to_string();)?
530 if table_name.is_empty(){
531 #[$crate::snake_name($table)]
532 fn snake_name(){}
533 table_name = snake_name();
534 }
535 $fn_name(executor, table_name, $($param_key,)*).await
536 }
537 }
538 };
539}
540
541
542/// pysql impl_select_page
543///
544/// do_count: default do_count is a bool param value to determine the statement type
545///
546/// ```rust
547/// #[derive(serde::Serialize, serde::Deserialize)]
548/// pub struct MockTable{}
549/// rbatis::impl_select_page!(MockTable{select_page() =>"
550/// if do_count == false:
551/// `order by create_time desc`"});
552/// ```
553///
554/// you can see ${page_no} = (page_no -1) * page_size;
555/// you can see ${page_size} = page_size;
556#[macro_export]
557macro_rules! impl_select_page {
558 ($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $where_sql:expr}) => {
559 $crate::impl_select_page!(
560 $table{$fn_name($($param_key:$param_type,)*)=> $where_sql},
561 ""
562 );
563 };
564 ($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $where_sql:expr}$(,$table_name:expr)?) => {
565 impl $table {
566 pub async fn $fn_name(
567 executor: &dyn $crate::executor::Executor,
568 page_request: &dyn $crate::plugin::IPageRequest,
569 $($param_key:$param_type,)*
570 ) -> std::result::Result<$crate::plugin::Page::<$table>, $crate::rbdc::Error> {
571 let mut table_column = "*".to_string();
572 let mut table_name = String::new();
573 let mut table_name = String::new();
574 $(table_name = $table_name.to_string();)?
575 if table_name.is_empty(){
576 #[$crate::snake_name($table)]
577 fn snake_name(){}
578 table_name = snake_name();
579 }
580 $crate::pysql_select_page!($fn_name(
581 table_column:&str,
582 table_name: &str,
583 $($param_key:&$param_type,)*) -> $table =>
584 "`select ${table_column} from ${table_name} `\n",$where_sql);
585
586 let page = $fn_name(executor,page_request,&table_column,&table_name,$(&$param_key,)*).await?;
587 Ok(page)
588 }
589 }
590 };
591}
592
593/// impl html_sql select page.
594///
595/// you must deal with 3 param:
596/// (do_count:bool,page_no:u64,page_size:u64)
597///
598/// you must deal with sql:
599/// return Vec<Record>(if param do_count = false)
600/// return u64(if param do_count = true)
601///
602/// you can see ${page_no} = (page_no -1) * page_size;
603/// you can see ${page_size} = page_size;
604///
605/// just like this example:
606/// ```html
607/// <select id="select_page_data">
608/// `select `
609/// <if test="do_count == true">
610/// `count(1) from table`
611/// </if>
612/// <if test="do_count == false">
613/// `* from table limit ${page_no},${page_size}`
614/// </if>
615/// </select>
616/// ```
617/// ```
618/// #[derive(serde::Serialize, serde::Deserialize)]
619/// pub struct MockTable{}
620/// //rbatis::htmlsql_select_page!(select_page_data(name: &str) -> MockTable => "example.html");
621/// rbatis::htmlsql_select_page!(select_page_data(name: &str) -> MockTable => r#"
622/// <select id="select_page_data">
623/// `select * from table where id > 1 limit ${page_no},${page_size} `
624/// </select>"#);
625///
626/// rbatis::pysql_select_page!(pysql_select_page(name:&str) -> MockTable =>
627/// r#"`select * from activity where delete_flag = 0`
628/// if name != '':
629/// ` and name=#{name}`
630/// ` limit ${page_no},${page_size}`
631/// "#);
632/// ```
633#[macro_export]
634macro_rules! htmlsql_select_page {
635 ($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $table:ty => $($html_file:expr$(,)?)*) => {
636 pub async fn $fn_name(executor: &dyn $crate::executor::Executor, page_request: &dyn $crate::plugin::IPageRequest, $($param_key:$param_type,)*) -> std::result::Result<$crate::plugin::Page<$table>, $crate::rbdc::Error> {
637 #[$crate::html_sql($($html_file,)*)]
638 pub async fn $fn_name(executor: &dyn $crate::executor::Executor,do_count:bool,page_no:u64,page_size:u64,$($param_key: &$param_type,)*) -> std::result::Result<rbs::Value, $crate::rbdc::Error>{
639 $crate::impled!()
640 }
641 let mut executor = executor;
642 let mut conn = None;
643 if executor.name().eq($crate::executor::Executor::name(executor.rb_ref())){
644 conn = Some(executor.rb_ref().acquire().await?);
645 match &conn {
646 Some(c) => {
647 executor = c;
648 }
649 None => {}
650 }
651 }
652 let mut total = 0;
653 if page_request.do_count() {
654 if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
655 intercept.count_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
656 }
657 let total_value = $fn_name(executor, true, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
658 total = $crate::decode(total_value).unwrap_or(0);
659 }
660 if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
661 intercept.select_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
662 }
663 let mut page = $crate::plugin::Page::<$table>::new(page_request.page_no(), page_request.page_size(), total,vec![]);
664 let records_value = $fn_name(executor, false, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
665 page.records = rbs::from_value(records_value)?;
666 Ok(page)
667 }
668 }
669}
670
671/// impl py_sql select page.
672///
673/// you must deal with 3 param:
674/// (do_count:bool,page_no:u64,page_size:u64)
675///
676/// you must deal with sql:
677/// return Vec<Record>(if param do_count = false)
678/// return u64(if param do_count = true)·
679///
680/// you can see ${page_no} = (page_no -1) * page_size;
681/// you can see ${page_size} = page_size;
682///
683/// just like this example:
684/// ```py
685/// `select * from activity where delete_flag = 0`
686/// if name != '':
687/// ` and name=#{name}`
688/// if !ids.is_empty():
689/// ` and id in `
690/// ${ids.sql()}
691/// ```
692/// ```
693/// #[derive(serde::Serialize, serde::Deserialize)]
694/// pub struct MockTable{}
695/// rbatis::pysql_select_page!(pysql_select_page(name:&str) -> MockTable =>
696/// r#"`select * from activity where delete_flag = 0`
697/// if name != '':
698/// ` and name=#{name}`
699/// ` limit ${page_no},${page_size}`
700/// "#);
701/// ```
702#[macro_export]
703macro_rules! pysql_select_page {
704 ($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $table:ty => $($py_file:expr$(,)?)*) => {
705 pub async fn $fn_name(executor: &dyn $crate::executor::Executor, page_request: &dyn $crate::plugin::IPageRequest, $($param_key:$param_type,)*) -> std::result::Result<$crate::plugin::Page<$table>, $crate::rbdc::Error> {
706 #[$crate::py_sql($($py_file,)*)]
707 pub async fn $fn_name(executor: &dyn $crate::executor::Executor,do_count:bool,page_no:u64,page_size:u64,$($param_key: &$param_type,)*) -> std::result::Result<rbs::Value, $crate::rbdc::Error>{
708 $crate::impled!()
709 }
710 let mut executor = executor;
711 let mut conn = None;
712 if executor.name().eq($crate::executor::Executor::name(executor.rb_ref())){
713 conn = Some(executor.rb_ref().acquire().await?);
714 match &conn {
715 Some(c) => {
716 executor = c;
717 }
718 None => {}
719 }
720 }
721 let mut total = 0;
722 if page_request.do_count() {
723 if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
724 intercept.count_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
725 }
726 let total_value = $fn_name(executor, true, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
727 total = $crate::decode(total_value).unwrap_or(0);
728 }
729 if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
730 intercept.select_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
731 }
732 let mut page = $crate::plugin::Page::<$table>::new(page_request.page_no(), page_request.page_size(), total,vec![]);
733 let records_value = $fn_name(executor, false, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
734 page.records = rbs::from_value(records_value)?;
735 Ok(page)
736 }
737 }
738}
739
740/// use macro wrapper #[sql]
741/// for example:
742/// ```rust
743/// use rbatis::executor::Executor;
744/// rbatis::raw_sql!(test_same_id(rb: &dyn Executor, id: &u64) -> Result<rbs::Value, rbatis::Error> =>
745/// "select * from table where id = ?"
746/// );
747/// ```
748#[macro_export]
749macro_rules! raw_sql {
750 ($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $sql_file:expr) => {
751 #[$crate::sql($sql_file)]
752 pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
753 impled!()
754 }
755 }
756}
757
758/// use macro wrapper #[py_sql]
759/// for query example:
760/// ```rust
761/// use rbatis::executor::Executor;
762/// rbatis::pysql!(test_same_id(rb: &dyn Executor, id: &u64) -> Result<rbs::Value, rbatis::Error> =>
763/// "select * from table where ${id} = 1
764/// if id != 0:
765/// `id = #{id}`"
766/// );
767/// ```
768/// for exec example:
769/// ```rust
770/// use rbatis::executor::Executor;
771/// use rbdc::db::ExecResult;
772/// rbatis::pysql!(test_same_id(rb: &dyn Executor, id: &u64) -> Result<ExecResult, rbatis::Error> =>
773/// "`update activity set name = '1' where id = #{id}`"
774/// );
775/// ```
776#[macro_export]
777macro_rules! pysql {
778 ($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $py_file:expr) => {
779 #[$crate::py_sql($py_file)]
780 pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
781 impled!()
782 }
783 }
784}
785
786/// use macro wrapper #[html_sql]
787/// for example query rbs::Value:
788/// ```rust
789/// use rbatis::executor::Executor;
790/// rbatis::htmlsql!(test_select(rb: &dyn Executor, id: &u64) -> Result<rbs::Value, rbatis::Error> => r#"
791/// <mapper>
792/// <select id="test_same_id">
793/// `select ${id} from my_table`
794/// </select>
795/// </mapper>"#);
796/// ```
797/// exec (from file)
798/// ```rust
799/// use rbatis::executor::Executor;
800/// use rbdc::db::ExecResult;
801/// rbatis::htmlsql!(update_by_id(rb: &dyn Executor, id: &u64) -> Result<ExecResult, rbatis::Error> => "example/example.html");
802/// ```
803/// query
804/// ```rust
805/// use rbatis::executor::Executor;
806/// #[derive(serde::Serialize, serde::Deserialize)]
807/// pub struct MyTable{
808/// pub id:Option<u64>,
809/// pub name:Option<String>,
810/// }
811/// rbatis::htmlsql!(test_select_table(rb: &dyn Executor, id: &u64) -> Result<Vec<MyTable>, rbatis::Error> => r#"
812/// <mapper>
813/// <select id="test_same_id">
814/// `select * from my_table`
815/// </select>
816/// </mapper>"#);
817/// ```
818#[macro_export]
819macro_rules! htmlsql {
820 ($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $html_file:expr) => {
821 #[$crate::html_sql($html_file)]
822 pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
823 impled!()
824 }
825 }
826}