#[macro_export]
macro_rules! model_option_var {
($struct_name:ident,{$($key:ident:$val:expr),*$(,)?})=>{
{
$struct_name{
$(
$key:Some(&$val),
)*
..$struct_name::none_default()
}
}
};
}
#[macro_export]
macro_rules! model_option_field {
($struct_name:ident,$var:expr,{$($key:ident),*$(,)?})=>{
{
$struct_name{
$(
$key:Some(&$var.$key),
)*
..$struct_name::none_default()
}
}
};
($struct_name:ident,$var:expr,{$($from_key:tt=>$to_key:ident),*$(,)?})=>{
{
$struct_name{
$(
$to_key:Some(&$var.$from_key),
)*
..$struct_name::none_default()
}
}
};
}
#[test]
fn test_model_option_field(){
#[derive(Clone,Debug)]
#[allow(dead_code)]
struct UserModel {
id: u32,
nickname: String,
gender: u8,
headimg: String,
password_id: u32,
}
#[derive(PartialEq,Debug)]
struct UserModelOption<'t>{
id: Option<&'t u32>,
nickname: Option<&'t String>,
gender: Option<&'t u8>,
headimg: Option<&'t String>,
password_id:Option<&'t u32>
}
impl<'t>UserModelOption<'t> {
pub fn none_default()->Self{
UserModelOption {
nickname:None,
gender:None,
id: None,
headimg: None,
password_id:None
}
}
}
let tvar1=(
"option insert".to_string(),
1
);
let tmp=crate::model_option_field!(UserModelOption,tvar1,{0=>nickname,1=>gender});
assert_eq!(tmp.nickname.unwrap(),&tvar1.0);
assert_eq!(tmp.gender.unwrap(),&tvar1.1);
struct TVAR{a:String,b:u8}
let tvar1=TVAR{
a:"option insert".to_string(),
b:1
};
let tmp=crate::model_option_field!(UserModelOption,tvar1,{a=>nickname,b=>gender});
assert_eq!(tmp,UserModelOption{
nickname:Some(&tvar1.a),
gender:Some(&tvar1.b),
id: None,
headimg: None,
password_id:None
});
let nike_name="option insert".to_string();
let gender=1;
let userinsert=crate::model_option_var!(UserModelOption,{
nickname:nike_name,
gender:gender,
});
assert_eq!(userinsert,UserModelOption{
nickname:Some(&tvar1.a),
gender:Some(&tvar1.b),
id: None,
headimg: None,
password_id:None
});
}
#[macro_export]
macro_rules! model_table_option_define {
($self_var:ident,$struct_name:ident,$option_struct_name:ident,{$($name:ident:$type:ty),+})=>{
#[derive(PartialEq,Debug)]
pub struct $option_struct_name<'t> {
$($name:Option<&'t $type>),*
}
impl<'t> $option_struct_name<'t> {
#[allow(dead_code)]
pub fn none_default()->Self{
$option_struct_name {
$($name:None),*
}
}
}
impl<'t> $crate::InsertData<'t,sqlx::MySql> for $option_struct_name<'t>
{
fn columns(&$self_var) -> Vec<$crate::FieldItem> {
let mut vec = vec![];
$(
if !$self_var.$name.is_none() {
vec.push($crate::FieldItem::new(stringify!($name)));
}
) *
vec
}
fn sqlx_bind<'q>(&'q
$self_var,
field:&$crate::FieldItem,
mut res: sqlx::query::Query<'q,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'q>>::Arguments>,
) -> sqlx::query::Query<'q,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'q>>::Arguments>{
$crate::model_table_value_bind_define!(value_bind $self_var, res, field, {$($name),+});
}
}
impl<'t> $crate::ModelInsertData<'t,sqlx::MySql,$option_struct_name<'t>> for $struct_name
{
fn insert_data(&'t $self_var) -> $option_struct_name<'t>{
$option_struct_name {
$(
$name:Some(&$self_var.$name)
),*
}
}
}
impl<'t> $crate::UpdateData<'t,sqlx::MySql> for $option_struct_name<'t>
{
fn diff_columns(&$self_var) -> Vec<$crate::FieldItem> {
let mut vec = vec![];
$(
if !$self_var.$name.is_none() {
vec.push($crate::FieldItem::new(stringify!($name)));
}
) *
vec
}
fn sqlx_bind<'q>(&'q
$self_var,
mut res: sqlx::query::Query<'q,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'q>>::Arguments>,
) -> sqlx::query::Query<'q,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'q>>::Arguments>
{
$(
if let Some(val) = $self_var.$name {
res = res.bind(val.clone());
}
) *
res
}
}
impl<'t> $crate::ModelUpdateData<'t,sqlx::MySql, $option_struct_name<'t>> for $struct_name
{
fn diff(&'t $self_var, source_opt: Option<&Self>) -> $option_struct_name<'t> {
match source_opt {
Some(source) => {
$option_struct_name {$(
$name: if $self_var.$name != source.$name {
Some(&$self_var.$name)
} else {
None
}
),*}
}
None => $option_struct_name {
$(
$name:Some(&$self_var.$name)
),*
},
}
}
}
};
($struct_name:ident,$option_struct_name:ident,{$($name:ident:$type:ty),+$(,)?})=>{
$crate::model_table_option_define!(self,$struct_name,$option_struct_name,{$($name:$type),+});
};
}
#[macro_export]
macro_rules! model_table_value_bind_define {
(value_bind $self_var:ident,$res:expr,$val:expr,{$($name:ident),+})=>{
match $val.name.as_str() {
$(
stringify!($name)=> {
$res=$res.bind(&$self_var.$name);
}
) *
_=>{}
}
return $res
};
($self_var:ident,$struct_name:ident,$table_name:expr,{$($name:ident),+},{$($pk_name:ident),+})=>{
impl $crate::ModelTableName for $struct_name {
fn table_name() -> $crate::TableName {
$crate::TableName::new($table_name)
}
}
impl $crate::ModelTableField<sqlx::MySql> for $struct_name{
fn table_pk() -> $crate::TableFields {
$crate::TableFields::new(vec![
$(
$crate::FieldItem::new(stringify!($pk_name))
),*
])
}
fn table_column() -> $crate::TableFields {
$crate::TableFields::new(vec![
$(
$crate::FieldItem::new(stringify!($name))
),*
])
}
fn query_sqlx_bind<'t>(
&'t
$self_var,
field_val: &$crate::FieldItem,
mut res: sqlx::query::Query<'t,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'t>>::Arguments>,
) -> sqlx::query::Query<'t,sqlx::MySql,<sqlx::MySql as sqlx::database::HasArguments<'t>>::Arguments>
{
$crate::model_table_value_bind_define!(value_bind $self_var, res, field_val, {$($name),+});
}
fn query_as_sqlx_bind<'t, M>(
&'t $self_var,
field_val: &$crate::FieldItem,
mut res: sqlx::query::QueryAs<'t,sqlx::MySql, M,<sqlx::MySql as sqlx::database::HasArguments<'t>>::Arguments>,
) -> sqlx::query::QueryAs<'t,sqlx::MySql, M,<sqlx::MySql as sqlx::database::HasArguments<'t>>::Arguments>
where
for<'r> M: sqlx::FromRow<'r, sqlx::mysql::MySqlRow> + Send + Unpin,
{
$crate::model_table_value_bind_define!(value_bind $self_var, res, field_val,{$($name),+});
}
}
};
($struct_name:ident,$table_name:expr,{$($name:ident),+},{$($pk_name:ident),+$(,)?})=>{
$crate::model_table_value_bind_define!(self ,$struct_name,$table_name,{$($name),+},{$($pk_name),+});
};
}
#[macro_export]
macro_rules! model_sql_bind {
($db:ty,$sql:expr,[$($key:literal),+$(,)?])=>{
{
let mut query_sql=$sql.to_string();
let mut posv:std::collections::HashMap<usize,(String,usize)>=std::collections::HashMap::new();
$(
for (pos,mstr) in query_sql.match_indices($key) {
let len=$key.len();
if let Some((_,vallen))=posv.get(&pos) {
if len>*vallen {
posv.insert(pos, (mstr.to_string(),len));
}
} else {
posv.insert(pos, (mstr.to_string(),len));
}
}
)+
let mut spos = posv.into_iter().collect::<Vec<_>>();
spos.sort_by(|a,b|if a.1.1<b.1.1 {
std::cmp::Ordering::Greater
}else {
std::cmp::Ordering::Less
});
for(pos,val)in spos.iter().enumerate(){
let bsts=$crate::DbType::type_new::<$db>().mark(pos);
query_sql = query_sql.replace(val.1.0.as_str(),bsts.as_str());
}
spos.sort_by_key(|a|a.0);
let mut match_vec = vec![];
for (_,(key,_)) in spos.into_iter(){
match_vec.push(key.clone());
};
(query_sql,match_vec)
}
};
}
#[macro_export]
macro_rules! model_sql_bind_match {
($bind_res:expr,{$($key:literal:$bind:expr),+$(,)?})=>{
{
for key in $bind_res.iter() {
match key.as_str(){
$(
$key=>{$bind},
)+
_=>{},
}
}
}
};
}
#[tokio::test]
async fn test_build_db(){
use crate::SqlQuote;
let db=crate::test::test_db().await;
#[derive(sqlx::FromRow,Clone,Debug,Default)]
struct UserModel {
nickname: String,
gender: u8,
}
let nikename="ddd";
let gender=1;
let gender_group=vec![1,2];
let (sql,bind_res)=model_sql_bind!(
sqlx::MySql,
r#"
select * from (SELECT :nickname as nickname,:gender as gender,1 as gender_group,:nickname as nickname1,:gender as gender1 )
as t where gender in (1) and gender_group in (:gender_group)
"#,
[":nickname",":gender",":gender_group"]
);
let mut res=sqlx::query_as::<_, UserModel>(sql.as_str());
model_sql_bind_match!(bind_res,{
":nickname":{
res=res.bind(&nikename);
}
,
":gender":{
res=res.bind(&gender);
},
":gender_group":{
res=res.bind(gender_group.sql_quote());
}
});
let res=res.fetch_one(&db).await.unwrap();
assert_eq!(res.nickname,nikename.to_string());
assert_eq!(res.gender,gender);
}