#[macro_export]
macro_rules! crud {
($table:ty{}) => {
$crate::impl_insert!($table {});
$crate::impl_select!($table {});
$crate::impl_update!($table {});
$crate::impl_delete!($table {});
};
($table:ty{},$table_name:expr) => {
$crate::impl_insert!($table {}, $table_name);
$crate::impl_select!($table {}, $table_name);
$crate::impl_update!($table {}, $table_name);
$crate::impl_delete!($table {}, $table_name);
};
}
#[macro_export]
macro_rules! impl_insert {
($table:ty{}) => {
$crate::impl_insert!($table {}, "");
};
($table:ty{},$table_name:expr) => {
impl $table {
pub async fn insert_batch(
executor: &dyn $crate::executor::Executor,
tables: &[$table],
batch_size: u64,
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
use $crate::crud_traits::ColumnSet;
#[$crate::py_sql(
"`insert into ${table_name} `
trim ',':
bind columns = tables.column_sets():
for idx,table in tables:
if idx == 0:
`(`
trim ',':
for _,v in columns:
${v},
`) VALUES `
(
trim ',':
for _,v in columns:
#{table[v]},
),
"
)]
async fn insert_batch(
executor: &dyn $crate::executor::Executor,
tables: &[$table],
table_name: &str,
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error>
{
impled!()
}
if tables.is_empty() {
return Err($crate::rbdc::Error::from(
"insert can not insert empty array tables!",
));
}
let mut table_name = $table_name.to_string();
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
let mut result = $crate::rbdc::db::ExecResult {
rows_affected: 0,
last_insert_id: rbs::Value::Null,
};
let ranges = $crate::plugin::Page::<()>::make_ranges(tables.len() as u64, batch_size);
for (offset, limit) in ranges {
let exec_result = insert_batch(
executor,
&tables[offset as usize..limit as usize],
table_name.as_str(),
)
.await?;
result.rows_affected += exec_result.rows_affected;
result.last_insert_id = exec_result.last_insert_id;
}
Ok(result)
}
pub async fn insert(
executor: &dyn $crate::executor::Executor,
table: &$table,
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
<$table>::insert_batch(executor, std::slice::from_ref(table), 1).await
}
}
};
}
#[macro_export]
macro_rules! impl_select {
($table:ty{}) => {
$crate::impl_select!($table{},"");
};
($table:ty{},$table_name:expr) => {
$crate::impl_select!($table{select_all() => ""},$table_name);
impl $table {
pub async fn select_by_map(executor: &dyn $crate::executor::Executor, mut condition: rbs::Value) -> std::result::Result<Vec<$table>, $crate::rbdc::Error> {
use rbatis::crud_traits::ValueOperatorSql;
let table_column = {
let mut columns = String::new();
let mut clean_map = rbs::value::map::ValueMap::with_capacity(condition.len());
for (k, v) in condition {
match k.as_str() {
Some("column") => {
columns = match v {
rbs::Value::String(s) => s.clone(),
rbs::Value::Array(arr) => {
let cols: Vec<&str> = arr.iter()
.filter_map(|v| v.as_str())
.collect();
if cols.is_empty() { "*".to_string() } else { cols.join(", ") }
}
_ => "*".to_string(),
};
}
_ => { clean_map.insert(k.clone(), v.clone()); }
}
}
if columns.is_empty() { columns = "*".to_string(); }
condition = rbs::Value::Map(clean_map);
columns
};
#[$crate::py_sql(
"`select ${table_column} from ${table_name}`
trim end=' where ':
` where `
trim ' and ': for key,item in condition:
if item == null:
continue:
if !item.is_array():
` and ${key.operator_sql()}#{item}`
if item.is_array():
` and ${key} in (`
trim ',': for _,item_array in item:
#{item_array},
`)`
")]
async fn select_by_map(
executor: &dyn $crate::executor::Executor,
table_name: String,
table_column: &str,
condition: &rbs::Value
) -> std::result::Result<Vec<$table>, $crate::rbdc::Error> {
for (_,v) in condition {
if v.is_array() && v.is_empty(){
return Ok(vec![]);
}
}
impled!()
}
let mut table_name = $table_name.to_string();
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
select_by_map(executor, table_name, &table_column, &condition).await
}
}
};
($table:ty{$fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty $(,)?)*) => $sql:expr}$(,$table_name:expr)?) => {
$crate::impl_select!($table{$fn_name$(<$($gkey:$gtype,)*>)?($($param_key:$param_type,)*) ->Vec => $sql}$(,$table_name)?);
};
($table:ty{$fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty $(,)?)*) -> $container:tt => $sql:expr}$(,$table_name:expr)?) => {
impl $table{
pub async fn $fn_name $(<$($gkey:$gtype,)*>)? (executor: &dyn $crate::executor::Executor,$($param_key:$param_type,)*) -> std::result::Result<$container<$table>,$crate::rbdc::Error>
{
use rbatis::crud_traits::ValueOperatorSql;
#[$crate::py_sql("`select ${table_column} from ${table_name} `\n",$sql)]
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!()}
let mut table_column = "*".to_string();
let mut table_name = String::new();
$(table_name = $table_name.to_string();)?
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
$fn_name(executor,&table_column,&table_name,$($param_key ,)*).await
}
}
};
}
#[macro_export]
macro_rules! impl_update {
($table:ty{}) => {
$crate::impl_update!(
$table{},
""
);
};
($table:ty{},$table_name:expr) => {
impl $table {
pub async fn update_by_map(
executor: &dyn $crate::executor::Executor,
table: &$table,
mut condition: rbs::Value
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
use rbatis::crud_traits::{ValueOperatorSql, FilterByColumns};
let set_columns = {
let mut columns = rbs::Value::Null;
let mut clean_map = rbs::value::map::ValueMap::with_capacity(condition.len());
for (k, v) in condition {
match k.as_str() {
Some("column") => {
columns = match v {
rbs::Value::String(s) => {
rbs::Value::Array(vec![rbs::Value::String(s.clone())])
}
rbs::Value::Array(arr) => {
let filtered_array: Vec<rbs::Value> = arr.iter()
.filter(|v| v.as_str().is_some())
.cloned()
.collect();
if filtered_array.is_empty() {
rbs::Value::Null
} else {
rbs::Value::Array(filtered_array)
}
}
_ => rbs::Value::Null,
};
}
_ => { clean_map.insert(k.clone(), v.clone()); }
}
}
condition = rbs::Value::Map(clean_map);
columns
};
#[$crate::py_sql(
"`update ${table_name}
if skip_null == false:
set collection='table',skips='id',skip_null=false:
if skip_null == true:
set collection='table',skips='id':
trim end=' where ':
` where `
trim ' and ': for key,item in condition:
if item == null:
continue:
if !item.is_array():
` and ${key.operator_sql()}#{item}`
if item.is_array():
` and ${key} in (`
trim ',': for _,item_array in item:
#{item_array},
`)`
"
)]
async fn update_by_map_internal(
executor: &dyn $crate::executor::Executor,
table_name: String,
table: &rbs::Value,
condition: &rbs::Value,
skip_null: bool,
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
for (_,v) in condition {
if v.is_array() && v.is_empty(){
return Ok($crate::rbdc::db::ExecResult::default());
}
}
impled!()
}
let mut table_name = $table_name.to_string();
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
let table_value = rbs::value!(table);
let mut skip_null = true;
let table = if set_columns != rbs::Value::Null {
skip_null = false;
table_value.filter_by_columns(&set_columns)
} else {
table_value
};
update_by_map_internal(executor, table_name, &table, &condition, skip_null).await
}
}
};
($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $sql_where:expr}$(,$table_name:expr)?) => {
impl $table {
pub async fn $fn_name(
executor: &dyn $crate::executor::Executor,
table: &$table,
$($param_key:$param_type,)*
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
use rbatis::crud_traits::ValueOperatorSql;
if $sql_where.is_empty(){
return Err($crate::rbdc::Error::from("sql_where can't be empty!"));
}
#[$crate::py_sql("`update ${table_name}`\n set collection='table',skips='id':\n",$sql_where)]
async fn $fn_name(
executor: &dyn $crate::executor::Executor,
table_name: String,
table: &rbs::Value,
$($param_key:$param_type,)*
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
impled!()
}
let mut table_name = String::new();
$(table_name = $table_name.to_string();)?
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
let table = rbs::value!(table);
$fn_name(executor, table_name, &table, $($param_key,)*).await
}
}
};
}
#[macro_export]
macro_rules! impl_delete {
($table:ty{}) => {
$crate::impl_delete!(
$table{},
""
);
};
($table:ty{},$table_name:expr) => {
impl $table {
pub async fn delete_by_map(executor: &dyn $crate::executor::Executor, condition: rbs::Value) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
use rbatis::crud_traits::ValueOperatorSql;
#[$crate::py_sql(
"`delete from ${table_name}`
trim end=' where ':
` where `
trim ' and ': for key,item in condition:
if item == null:
continue:
if !item.is_array():
` and ${key.operator_sql()}#{item}`
if item.is_array():
` and ${key} in (`
trim ',': for _,item_array in item:
#{item_array},
`)`
")]
async fn delete_by_map(
executor: &dyn $crate::executor::Executor,
table_name: String,
condition: &rbs::Value
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
for (_,v) in condition {
if v.is_array() && v.is_empty(){
return Ok($crate::rbdc::db::ExecResult::default());
}
}
impled!()
}
let mut table_name = $table_name.to_string();
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
delete_by_map(executor, table_name, &condition).await
}
}
};
( $ table:ty{$ fn_name:ident $(< $($gkey:ident:$gtype:path $(,)?)* >)? ($($param_key:ident:$param_type:ty$(,)?)*) => $sql_where:expr}$(,$table_name:expr)?) => {
impl $table {
pub async fn $fn_name$(<$($gkey:$gtype,)*>)?(
executor: &dyn $crate::executor::Executor,
$($param_key:$param_type,)*
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
use rbatis::crud_traits::ValueOperatorSql;
if $sql_where.is_empty(){
return Err($crate::rbdc::Error::from("sql_where can't be empty!"));
}
#[$crate::py_sql("`delete from ${table_name} `\n",$sql_where)]
async fn $fn_name$(<$($gkey: $gtype,)*>)?(
executor: &dyn $crate::executor::Executor,
table_name: String,
$($param_key:$param_type,)*
) -> std::result::Result<$crate::rbdc::db::ExecResult, $crate::rbdc::Error> {
impled!()
}
let mut table_name = String::new();
$(table_name = $table_name.to_string();)?
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
$fn_name(executor, table_name, $($param_key,)*).await
}
}
};
}
#[macro_export]
macro_rules! impl_select_page {
($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $where_sql:expr}) => {
$crate::impl_select_page!(
$table{$fn_name($($param_key:$param_type,)*)=> $where_sql},
""
);
};
($table:ty{$fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) => $where_sql:expr}$(,$table_name:expr)?) => {
impl $table {
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> {
let mut table_column = "*".to_string();
let mut table_name = String::new();
let mut table_name = String::new();
$(table_name = $table_name.to_string();)?
if table_name.is_empty(){
#[$crate::snake_name($table)]
fn snake_name(){}
table_name = snake_name();
}
$crate::pysql_select_page!($fn_name(
table_column:&str,
table_name: &str,
$($param_key:&$param_type,)*) -> $table =>
"`select ${table_column} from ${table_name} `\n",$where_sql);
let page = $fn_name(executor,page_request,&table_column,&table_name,$(&$param_key,)*).await?;
Ok(page)
}
}
};
}
#[macro_export]
macro_rules! htmlsql_select_page {
($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $table:ty => $($html_file:expr$(,)?)*) => {
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> {
#[$crate::html_sql($($html_file,)*)]
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>{
$crate::impled!()
}
let mut executor = executor;
let mut conn = None;
if executor.name().eq($crate::executor::Executor::name(executor.rb_ref())){
conn = Some(executor.rb_ref().acquire().await?);
match &conn {
Some(c) => {
executor = c;
}
None => {}
}
}
let mut total = 0;
if page_request.do_count() {
if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
intercept.count_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
}
let total_value = $fn_name(executor, true, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
total = $crate::decode(total_value).unwrap_or(0);
}
if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
intercept.select_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
}
let mut page = $crate::plugin::Page::<$table>::new(page_request.page_no(), page_request.page_size(), total,vec![]);
let records_value = $fn_name(executor, false, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
page.records = rbs::from_value(records_value)?;
Ok(page)
}
}
}
#[macro_export]
macro_rules! pysql_select_page {
($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $table:ty => $($py_file:expr$(,)?)*) => {
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> {
#[$crate::py_sql($($py_file,)*)]
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>{
$crate::impled!()
}
let mut executor = executor;
let mut conn = None;
if executor.name().eq($crate::executor::Executor::name(executor.rb_ref())){
conn = Some(executor.rb_ref().acquire().await?);
match &conn {
Some(c) => {
executor = c;
}
None => {}
}
}
let mut total = 0;
if page_request.do_count() {
if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
intercept.count_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
}
let total_value = $fn_name(executor, true, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
total = $crate::decode(total_value).unwrap_or(0);
}
if let Some(intercept) = executor.rb_ref().get_intercept::<$crate::plugin::intercept_page::PageIntercept>(){
intercept.select_ids.insert(executor.id(),$crate::plugin::PageRequest::new(page_request.page_no(), page_request.page_size()));
}
let mut page = $crate::plugin::Page::<$table>::new(page_request.page_no(), page_request.page_size(), total,vec![]);
let records_value = $fn_name(executor, false, page_request.offset(), page_request.page_size(), $(&$param_key,)*).await?;
page.records = rbs::from_value(records_value)?;
Ok(page)
}
}
}
#[macro_export]
macro_rules! raw_sql {
($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $sql_file:expr) => {
#[$crate::sql($sql_file)]
pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
impled!()
}
}
}
#[macro_export]
macro_rules! pysql {
($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $py_file:expr) => {
#[$crate::py_sql($py_file)]
pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
impled!()
}
}
}
#[macro_export]
macro_rules! htmlsql {
($fn_name:ident($($param_key:ident:$param_type:ty$(,)?)*) -> $return_type:ty => $html_file:expr) => {
#[$crate::html_sql($html_file)]
pub async fn $fn_name($($param_key: $param_type,)*) -> $return_type{
impled!()
}
}
}