1#[macro_export]
2macro_rules! model_table_ref_define {
7 ($db_type:ty,$self_var:ident,$struct_name:ident,$option_struct_name:ident,{$($name:ident[$column_name:literal]:$type:ty),+})=>{
8 #[derive(PartialEq,Eq,Debug)]
9 pub struct $option_struct_name<'t> {
10 $(pub $name:Option<&'t $type>),*
11 }
12 impl<'t> $option_struct_name<'t> {
13 #[allow(dead_code)]
14 pub fn none_default()->Self{
15 $option_struct_name {
16 $($name:None),*
17 }
18 }
19 }
20 impl<'t> $crate::InsertData<'t,$db_type> for $option_struct_name<'t>
21 {
22 fn columns(&$self_var) -> Vec<$crate::FieldItem> {
23 let mut vec = vec![];
24 $(
25 if !$self_var.$name.is_none() {
26 vec.push($crate::FieldItem::new(stringify!($name),$column_name));
27 }
28 ) *
29 vec
30 }
31 fn sqlx_bind<'q>(&'q
32 $self_var,
33 field:&$crate::FieldItem,
34 mut res: sqlx::query::Query<'q,$db_type,<$db_type as sqlx::database::HasArguments<'q>>::Arguments>,
35 ) -> sqlx::query::Query<'q,$db_type,<$db_type as sqlx::database::HasArguments<'q>>::Arguments>{
36 $crate::model_table_value_bind_define!(value_bind $self_var, res, field, {$($name),+});
37 }
38 fn sqlx_string(&$self_var,
39 field:&$crate::FieldItem
40 ) -> Option<String>{
41 use $crate::SqlQuote;
42 match field.name.as_str() {
43 $(
44 stringify!($name)=> {
45 Some($self_var.$name.map_or("".to_string(),|e|{
46 e.sql_quote().to_string()
47 }))
48 }
49 ) *
50 _=>None
51 }
52 }
53 }
54 impl<'t> $crate::ModelInsertData<'t,$db_type,$option_struct_name<'t>> for $struct_name
55 {
56 fn insert_data(&'t $self_var) -> $option_struct_name<'t>{
57 $option_struct_name {
58 $(
59 $name:Some(&$self_var.$name)
60 ),*
61 }
62 }
63 }
64 impl<'t> $crate::UpdateData<'t,$db_type> for $option_struct_name<'t>
65 {
66 fn diff_columns(&$self_var) -> Vec<$crate::FieldItem> {
67 let mut vec = vec![];
68 $(
69 if !$self_var.$name.is_none() {
70 vec.push($crate::FieldItem::new(stringify!($name),$column_name));
71 }
72 ) *
73 vec
74 }
75 fn sqlx_bind<'q>(&'q
76 $self_var,
77 mut res: sqlx::query::Query<'q,$db_type,<$db_type as sqlx::database::HasArguments<'q>>::Arguments>,
78 ) -> sqlx::query::Query<'q,$db_type,<$db_type as sqlx::database::HasArguments<'q>>::Arguments>
79 {
80 $(
81 if let Some(val) = $self_var.$name {
82 res = res.bind(val.clone());
83 }
84 ) *
85 res
86 }
87 fn sqlx_string(&$self_var,field:&$crate::FieldItem) -> Option<String>
88 {
89 use $crate::SqlQuote;
90 match(field.name.as_str()){
91 $(
92 stringify!($name)=>{
93 if let Some(val) = $self_var.$name {
94 return Some(val.sql_quote().to_string())
95 }
96 }
97 ) *
98 _=>{}
99 }
100 None
101 }
102 }
103 impl<'t> $crate::ModelUpdateData<'t,$db_type, $option_struct_name<'t>> for $struct_name
104 {
105 fn diff(&'t $self_var, source_opt: &Option<&Self>) -> $option_struct_name<'t> {
106
107 match source_opt {
108 Some(source) => {
109 $option_struct_name {$(
110 $name: if $self_var.$name != source.$name {
111 Some(&$self_var.$name)
112 } else {
113 None
114 }
115 ),*}
116 }
117 None => $option_struct_name {
118 $(
119 $name:Some(&$self_var.$name)
120 ),*
121 },
122 }
123 }
124 }
125 };
126 ($db_type:ty,$struct_name:ident,$option_struct_name:ident,{$($name:ident[$column_name:literal]:$type:ty),+$(,)?})=>{
127 $crate::model_table_ref_define!($db_type,self,$struct_name,$option_struct_name,{$($name[$column_name]:$type),+});
128 };
129}
130
131#[macro_export]
132macro_rules! model_table_value_bind_define {
138 (value_bind $self_var:ident,$res:expr,$val:expr,{$($name:ident),+})=>{
139 match $val.name.as_str() {
140 $(
141 stringify!($name)=> {
142 $res=$res.bind(&$self_var.$name);
143 }
144 ) *
145 _=>{}
146 }
147 return $res
148 };
149 ($db_type:ty,$self_var:ident,$struct_name:ident,$table_name:expr,{$($name:ident[$column_name:literal]),+},{$($pk_name:ident[$pk_column_name:literal]),+})=>{
150 impl $crate::ModelTableName for $struct_name {
151 fn table_name() -> $crate::TableName {
152 $crate::TableName::new($table_name)
153 }
154 }
155 impl $crate::ModelTableField<$db_type> for $struct_name{
156 fn table_pk() -> $crate::TableFields {
157 $crate::TableFields::new(vec![
158 $(
159 $crate::FieldItem::new(stringify!($pk_name),$pk_column_name)
160 ),*
161 ])
162 }
163 fn table_column() -> $crate::TableFields {
164 $crate::TableFields::new(vec![
165 $(
166 $crate::FieldItem::new(stringify!($name),$column_name)
167 ),*
168 ])
169 }
170 fn query_sqlx_bind<'t>(
171 &'t
172 $self_var,
173 field_val: &$crate::FieldItem,
174 mut res: sqlx::query::Query<'t,$db_type,<$db_type as sqlx::database::HasArguments<'t>>::Arguments>,
175 ) -> sqlx::query::Query<'t,$db_type,<$db_type as sqlx::database::HasArguments<'t>>::Arguments>
176 {
177 $crate::model_table_value_bind_define!(value_bind $self_var, res, field_val, {$($name),+});
178 }
179 fn query_as_sqlx_bind<'t, M>(
180 &'t $self_var,
181 field_val: &$crate::FieldItem,
182 mut res: sqlx::query::QueryAs<'t,$db_type, M,<$db_type as sqlx::database::HasArguments<'t>>::Arguments>,
183 ) -> sqlx::query::QueryAs<'t,$db_type, M,<$db_type as sqlx::database::HasArguments<'t>>::Arguments>
184 where
185 for<'r> M: sqlx::FromRow<'r, <$db_type as sqlx::Database>::Row> + Send + Unpin,
186 {
187 $crate::model_table_value_bind_define!(value_bind $self_var, res, field_val,{$($name),+});
188 }
189 }
190 };
191 ($db_type:ty,$struct_name:ident,$table_name:expr,{$($name:ident[$column_name:literal]),+},{$($pk_name:ident[$pk_column_name:literal]),+$(,)?})=>{
192 $crate::model_table_value_bind_define!($db_type,self ,$struct_name,$table_name,{$($name[$column_name]),+},{$($pk_name[$pk_column_name]),+});
193 };
194}
195
196#[test]
197fn test_model_define_bind_macro() {
198 pub struct UserModel {
199 pub id: u32,
200 pub nickname: String,
201 pub gender: u8,
202 pub headimg: Option<String>,
203 pub password_id: u32,
204 }
205 crate::model_table_value_bind_define!(sqlx::MySql,UserModel,"user",{
206 id["id"],
207 nickname["nickname"],
208 gender["gender"],
209 headimg["headimg"],
210 password_id["password_id"]
211 },{
212 id["id"]
213 });
214 crate::model_table_ref_define!(sqlx::MySql,UserModel,UserModelRef,{
215 id["id"]: u32,
216 nickname["nickname"]: String,
217 gender["gender"]: u8,
218 headimg["headimg"]: Option<String>,
219 password_id["password_id"]: u32,
220 });
221}
222
223#[macro_export]
224macro_rules! model_option_set {
229 ($struct_name:ident,{$($key:ident:$val:expr),*$(,)?})=>{
230 {
231 $struct_name{
232 $(
233 $key:Some(&$val),
234 )*
235 ..$struct_name::none_default()
236 }
237 }
238 };
239}
240
241#[macro_export]
242macro_rules! model_option_map {
247 ($struct_name:ident,$var:expr,{$($key:ident),*$(,)?})=>{
248 {
249 $struct_name{
250 $(
251 $key:Some(&$var.$key),
252 )*
253 ..$struct_name::none_default()
254 }
255 }
256 };
257 ($struct_name:ident,$var:expr,{$($from_key:tt=>$to_key:ident),*$(,)?})=>{
258 {
259 $struct_name{
260 $(
261 $to_key:Some(&$var.$from_key),
262 )*
263 ..$struct_name::none_default()
264 }
265 }
266 };
267}
268
269#[test]
270fn test_model_option_macro() {
271 #[derive(Clone, Debug)]
272 #[allow(dead_code)]
273 struct UserModel {
274 id: u32,
275 nickname: String,
276 gender: u8,
277 headimg: String,
278 password_id: u32,
279 }
280 #[derive(PartialEq, Eq, Debug)]
281 struct UserModelOption<'t> {
282 id: Option<&'t u32>,
283 nickname: Option<&'t String>,
284 gender: Option<&'t u8>,
285 headimg: Option<&'t String>,
286 password_id: Option<&'t u32>,
287 }
288 impl<'t> UserModelOption<'t> {
289 pub fn none_default() -> Self {
290 UserModelOption {
291 nickname: None,
292 gender: None,
293 id: None,
294 headimg: None,
295 password_id: None,
296 }
297 }
298 }
299
300 let tvar1 = ("option insert".to_string(), 1);
302 let tmp = crate::model_option_map!(UserModelOption,tvar1,{0=>nickname,1=>gender});
303 assert_eq!(tmp.nickname.unwrap(), &tvar1.0);
304 assert_eq!(tmp.gender.unwrap(), &tvar1.1);
305
306 struct Tvar {
308 a: String,
309 b: u8,
310 }
311 let tvar1 = Tvar {
312 a: "option insert".to_string(),
313 b: 1,
314 };
315 let tmp = crate::model_option_map!(UserModelOption,tvar1,{a=>nickname,b=>gender});
316 assert_eq!(
317 tmp,
318 UserModelOption {
319 nickname: Some(&tvar1.a),
320 gender: Some(&tvar1.b),
321 id: None,
322 headimg: None,
323 password_id: None
324 }
325 );
326
327 let nike_name = "option insert".to_string();
329 let gender = 1;
330 let userinsert = crate::model_option_set!(UserModelOption,{
331 nickname:nike_name,
332 gender:gender,
333 });
334 assert_eq!(
335 userinsert,
336 UserModelOption {
337 nickname: Some(&tvar1.a),
338 gender: Some(&tvar1.b),
339 id: None,
340 headimg: None,
341 password_id: None
342 }
343 );
344
345 struct TVAR1 {
347 nickname: String,
348 gender: u8,
349 }
350 let tvar1 = TVAR1 {
351 nickname: "option insert".to_string(),
352 gender: 1,
353 };
354 let tmp = crate::model_option_map!(UserModelOption,tvar1,{nickname,gender});
355 assert_eq!(
356 tmp,
357 UserModelOption {
358 nickname: Some(&tvar1.nickname),
359 gender: Some(&tvar1.gender),
360 id: None,
361 headimg: None,
362 password_id: None
363 }
364 );
365}
366
367#[macro_export]
368macro_rules! model_enum_status_define {
373 ($self_var:ident,$enum_name:ident,$type:ty,{$($item:expr),*$(,)?})=>{
374 impl $enum_name{
375 pub fn eq(self,eq:$type)->bool{
376 return self.to()==eq;
377 }
378 pub fn to(self)->$type{
379 return self as $type
380 }
381 }
382 impl $crate::SqlQuote<$type> for $enum_name {
383 fn sql_quote(&self) -> $type {
384 *self as $type
385 }
386 }
387 impl std::convert::TryFrom<$type> for $enum_name {
388 type Error=sqlx::Error;
389 fn try_from(value: $type) -> Result<Self, Self::Error> {
390 $(
391 if ($item as $type) ==value {
392 return Ok($item);
393 }
394 )*
395 return Err(sqlx::Error::TypeNotFound { type_name: format!("{}[{}]->{}",stringify!(i8),value,stringify!($enum_name)) })
396 }
397 }
398 };
399 ($enum_name:ident,$type:ty,{$($item:expr),*$(,)?})=>{
400 $crate::model_enum_status_define!(self ,$enum_name,$type,{$(
401 $item,
402 )*});
403 };
404 ($enum_name:ident,$type:ty)=>{
405 $crate::model_enum_status_define!(self ,$enum_name,$type,{});
406 };
407}
408
409#[test]
410fn test_model_enum_status() {
411 #[derive(PartialEq, Eq, Clone, Copy)]
412 enum UserModelStatus {
413 Statu1 = 1,
414 Statu2 = 2,
415 }
416 crate::model_enum_status_define!(UserModelStatus,u8,{
417 UserModelStatus::Statu1,
418 UserModelStatus::Statu2
419 });
420 assert!(UserModelStatus::Statu1.eq(1));
421 assert!(!UserModelStatus::Statu1.eq(2));
422 assert!(UserModelStatus::Statu2.eq(2));
423 let status: UserModelStatus = 2.try_into().unwrap();
424 assert!(status == UserModelStatus::Statu2);
425 let status: Result<UserModelStatus, _> = 3.try_into();
426 assert!(status.is_err());
427}