use crate::configs::MysqlConfig;
use crate::myjson::*;
use crate::{myok, mysome, db::MyMysql, mystring};
use async_trait::async_trait;
use bevy_reflect::{Reflect, Struct};
use convert_case::{Case, Casing};
use std::default::Default;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use super::const_type_defaults::*;
use super::i_db_model::IDbModel;
use crate::myerror::MyError;
use once_map::OnceMap;
use serde_json::{json, Value as JSONValue};
use futures::lock::Mutex;
use itertools::Itertools;
use crate::db::{QUERY_WITH_OFFSET};
#[async_trait]
pub trait IMysqlDbModel: Reflect + Default + Struct + IDbModel {
fn mysql_config(&self) -> &MysqlConfig;
fn mysql_executor(&self) -> Result<MyMysql, crate::myerror::MyError>;
fn get_table_name(&self) -> String {
let config = self.mysql_config();
let name = self.type_name();
let index = name.rfind(":").unwrap();
let _end = name.len();
let class_name = name.get(index + 1..).unwrap();
let mut table_name = String::from(config.table_prefix.as_str());
table_name.push_str(class_name.to_case(Case::Snake).as_str());
table_name
}
async fn offset(& mut self,digit:i64)->Result<& mut Self,MyError>{
let addr=self.object_key();
crate::db::extra_options_set_string(format!("{}.{}", addr, QUERY_WITH_OFFSET).as_str(), format!("{}", digit).as_str()).await?;
Ok(self)
}
async fn in_array<T:serde::Serialize+Debug+Send+Sync>(& mut self,column_name:&str,column_values:&Vec<T>)->Result<& mut Self,MyError>{
let addr=self.object_key();
let all=column_values.iter().map(|x|mystring::to_database_string(x)).join(",");
crate::db::extra_options_append_value(format!("{}.{}", addr, crate::db::QUERY_WITH_WHERE).as_str(), &JSONValue::String(format!(" `{}`.`{}` in ({}) ", self.get_table_name(), column_name, all))).await?;
Ok(self)
}
async fn order(& mut self,json_map:&JSONValue)->Result<& mut Self,MyError>{
let addr=self.object_key();
let mut order_str =String::new();
for (k,v) in mysome!(json_map.as_object()).iter() {
if order_str.len()==0{
order_str.push_str(" order by");
} else {
order_str.push_str(",");
}
order_str.push_str(format!(" `{}`.`{}` {} ",self.get_table_name(),k,mysome!(v.as_str(),??)).as_str());
}
crate::db::extra_options_set_string(format!("{}.{}", addr, crate::db::QUERY_WITH_ORDER).as_str(), order_str.as_str()).await?;
Ok(self)
}
async fn order_by(& mut self,order_column:&str)->Result<& mut Self,MyError>{
let addr=self.object_key();
crate::db::extra_options_set_string(format!("{}.{}", addr, crate::db::QUERY_WITH_ORDER).as_str(), format!(" `{}`.`{}` ", self.get_table_name(), order_column).as_str()).await?;
Ok(self)
}
async fn order_desc_by(& mut self,order_column:&str)->Result<& mut Self,MyError>{
let addr=self.object_key();
crate::db::extra_options_set_string(format!("{}.{}", addr, crate::db::QUERY_WITH_ORDER).as_str(), format!(" `{}`.`{}` desc ", self.get_table_name(), order_column).as_str()).await?;
Ok(self)
}
async fn limit(& mut self,digit:i64)->Result<& mut Self,MyError>{
let addr=self.object_key();
crate::db::extra_options_set_string(format!("{}.{}", addr, crate::db::QUERY_WITH_LIMIT).as_str(), format!("{}", digit).as_str()).await?;
Ok(self)
}
fn object_key(&self) ->String {
let t=format!("{:p}",self);
t
}
fn get_where(&self) -> Result<OnceMap<String, String>,MyError> {
let map: OnceMap<String, String> = OnceMap::new();
for (i, value) in self.iter_fields().enumerate() {
let column_name = self.name_at(i).unwrap();
let column_type = value.type_name();
match column_type {
"alloc::string::String" => {
let column_val: String = self
.field_at(i)
.unwrap()
.downcast_ref::<String>()
.unwrap()
.to_owned();
if column_val != String::from(STRING_DEFAULT) {
map.insert_cloned(column_name.to_owned(),|_|format!("'{}'",column_val));
}
}
"usc::db::const_type_defaults::Bool" => {
let column_val: &crate::db::Bool = self
.field_at(i)
.unwrap()
.downcast_ref::<crate::db::Bool>()
.unwrap();
if *column_val!=crate::db::Bool::Null {
map.insert_cloned(column_name.to_owned(),|_|{
match *column_val {
crate::db::Bool::True=>return "1".to_owned(),
crate::db::Bool::False=>return "0".to_owned(),
_ => todo!(),
}
});
}
}
"i64" => {
let column_val: i64 = *self.field_at(i).unwrap().downcast_ref().unwrap();
if column_val != crate::db::INT64_DEFAULT {
map.insert_cloned(column_name.to_owned(),|_|format!("{}",column_val));
}
}
"f64" => {
let column_val: f64 = *self.field_at(i).unwrap().downcast_ref().unwrap();
if column_val != FLOAT64_DEFAULT {
map.insert_cloned(column_name.to_owned(),|_|format!("{}",column_val));
}
}
_ => {
return Err(MyError::new(format!(
"mysql:first_mysql_model:column_type: Not Handled type {:?}",
column_type
)));
}
}
}
Ok(map)
}
async fn save(& mut self)->Result<i64,MyError>{
let executor = crate::myok!(self.mysql_executor());
if self.has_id() {
let sql=myok!(executor.get_update_by_id_sql_by_object(self,self.get_table_name(),self.id()).await);
let num=myok!(executor.execute(sql.as_str()).await);
return Ok(num);
} else{
let sql=myok!(executor.get_insert_sql_by_object(self,self.get_table_name()).await);
let id =myok!(executor.execute(sql.as_str()).await);
let field =mysome!( self.field_mut("id"));
let field_i64=mysome!(field.downcast_mut());
* field_i64 = id;
Ok(id)
}
}
}
#[macro_export]
macro_rules! impl_mysql_model {
($t:ty, $b:expr) => {
impl crate::db::i_db_model::IDbModel for $t {}
impl crate::db::i_mysql_db_model::IMysqlDbModel for $t {
fn mysql_config(&self) -> &MysqlConfig {
&$b
}
fn mysql_executor(&self) -> Result<crate::db::my_mysql::MyMysql, crate::myerror::MyError> {
crate::db::my_mysql::MyMysql::new_by_config(&$b)
}
}
impl $t {
pub async fn smaller_than<F>(&self,mut f:F) -> Result<&Self,MyError> where F:FnMut(&mut $t) {
use serde_json::{Value as JSONValue};
use crate::{mysome,myok,myjson::myjson_get,myjson::myjson_set};
use crate::db::i_db_model::IDbModel;
use crate::db::i_mysql_db_model::IMysqlDbModel;
use futures::lock::Mutex;
let mut model=<$t>::default();
let _=model.prepare_with_defaults(|_|());
f(&mut model);
let map=myok!(model.get_where());
let addr=self.object_key();
let where_key=format!("{}.{}",&addr,crate::db::QUERY_WITH_WHERE);
let mut current_value= crate::db::extra_options_get(where_key.as_str(),JSONValue::Array(vec![])).await;
let current=mysome!(current_value.as_array_mut());
if current.len()==0{
let mut arr:Vec<JSONValue>=vec![];
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`<{} ",self.get_table_name(),key,val);
arr.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),&JSONValue::Array(arr)).await;
} else{
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`<{} ",self.get_table_name(),key,val);
current.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),¤t_value).await;
}
Ok(self)
}
pub async fn bigger_than<F>(&self,mut f:F) -> Result<&Self,MyError> where F:FnMut(&mut $t) {
use serde_json::{Value as JSONValue};
use crate::{mysome,myok,myjson::myjson_get,myjson::myjson_set};
use crate::db::i_db_model::IDbModel;
use crate::db::i_mysql_db_model::IMysqlDbModel;
use futures::lock::Mutex;
let mut model=<$t>::default();
let _=model.prepare_with_defaults(|_|());
f(&mut model);
let map=myok!(model.get_where());
let addr=self.object_key();
let where_key=format!("{}.{}",&addr,crate::db::QUERY_WITH_WHERE);
let mut current_value= crate::db::extra_options_get(where_key.as_str(),JSONValue::Array(vec![])).await;
let current=mysome!(current_value.as_array_mut());
if current.len()==0{
let mut arr:Vec<JSONValue>=vec![];
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`>{} ",self.get_table_name(),key,val);
arr.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),&JSONValue::Array(arr)).await;
} else{
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`>{} ",self.get_table_name(),key,val);
current.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),¤t_value).await;
}
Ok(self)
}
pub async fn not<F>(&self,mut f:F) -> Result<&Self,MyError> where F:FnMut(&mut $t) {
use serde_json::{Value as JSONValue};
use crate::{mysome,myok,myjson::myjson_get,myjson::myjson_set};
use crate::db::i_db_model::IDbModel;
use crate::db::i_mysql_db_model::IMysqlDbModel;
use futures::lock::Mutex;
let mut model=<$t>::default();
let _=model.prepare_with_defaults(|_|());
f(&mut model);
let map=myok!(model.get_where());
let addr=self.object_key();
let where_key=format!("{}.{}",&addr,crate::db::QUERY_WITH_WHERE);
let mut current_value= crate::db::extra_options_get(where_key.as_str(),JSONValue::Array(vec![])).await;
let current=mysome!(current_value.as_array_mut());
if current.len()==0{
let mut arr:Vec<JSONValue>=vec![];
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`!={} ",self.get_table_name(),key,val);
arr.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),&JSONValue::Array(arr)).await;
} else{
for (key,val) in map.read_only_view().iter(){
let subsql= format!(" `{}`.`{}`!={} ",self.get_table_name(),key,val);
current.push(JSONValue::String(subsql));
}
let _=crate::db::extra_options_set(where_key.as_str(),¤t_value).await;
}
Ok(self)
}
pub async fn all_mysql_models(&mut self) -> Result<Vec<$t>, MyError> {
use crate::myjson::*;
use crate::{myok, mysome};
use crate::myerror::MyError;
use crate::db::i_mysql_db_model::IMysqlDbModel;
use futures::lock::Mutex;
use crate::mylog;
use crate::db::*;
let table_name = self.get_table_name();
let executor = crate::myok!(self.mysql_executor());
let addr=self.object_key();
let key=format!("{}.{}",addr,crate::db::QUERY_WITH_ORDER);
let order_str=crate::db::extra_options_get_string(key.as_str(),"").await;
if order_str.len()==0{
let _=crate::db::extra_options_set_string(key.as_str(),format!(" `{}`.id desc ",self.get_table_name()).as_str()).await;
}
let sql=myok!(executor.get_select_sql_by_object(self,table_name,& crate::db::extra_options_get(addr.as_str(),serde_json::json!([])).await).await);
let all_result = executor
.select_map(sql.as_str(), |val| {
let json_string_option=crate::myjson::to_string(&val);
let json_string=json_string_option.unwrap();
let json_str=json_string.as_str();
let obj: $t =
crate::myjson::parse(json_str).unwrap();
obj
})
.await;
let all = myok!(all_result);
Ok(all)
}
pub async fn all_mysql<F>(f:F) -> Result<Vec<$t>,MyError> where F: FnMut(& mut Self) {
let mut obj=<$t>::default();
use crate::db::i_db_model::IDbModel;
obj.prepare_with_defaults(f);
let all=obj.all_mysql_models().await?;
Ok(all)
}
pub async fn first_mysql<F>(f:F) -> Result<$t,MyError> where F: FnMut(& mut Self) {
let mut obj=<$t>::default();
use crate::db::i_db_model::IDbModel;
obj.prepare_with_defaults(f);
obj.first_mysql_models().await?;
Ok(obj)
}
pub async fn first_mysql_models(&mut self) -> Result<&$t,MyError> {
use crate::{myok};
use bevy_reflect::{Reflect, Struct};
use bevy_reflect::GetField;
use futures::lock::Mutex;
use crate::myjson::*;
use crate::mylog;
use crate::mysome_or;
use crate::db::i_mysql_db_model::IMysqlDbModel;
let addr=self.object_key();
let key=format!("{}.{}",addr,crate::db::QUERY_WITH_LIMIT);
let _=crate::db::extra_options_set_string(key.as_str(),"1").await;
let all = myok!(self.all_mysql_models().await,??);
if all.len() == 0 {
if let Some(value) = self.get_field_mut::<i64>("id") {
*value = crate::db::INT64_DEFAULT;
}
return Err(MyError::new_str("ERROR:mysql first not found"));
}
let first = mysome_or!(all.get(0), {
return Err(MyError::new(format!("ERROR:mysql first not found")));
});
let mut info = self.clone_dynamic();
for (i, value) in self.iter_fields().enumerate() {
let name = self.name_at(i).unwrap();
match value.type_name() {
"alloc::string::String" => {
let column_val: String = first
.field_at(i)
.unwrap()
.downcast_ref::<String>()
.unwrap()
.to_owned();
info.insert(name, column_val);
}
"usc::db::const_type_defaults::Bool" => {
let column_val: &crate::db::Bool = first
.field_at(i)
.unwrap()
.downcast_ref::<crate::db::Bool>()
.unwrap();
info.insert(name, *column_val);
}
"i64" => {
let column_val: &i64 = first.field_at(i).unwrap().downcast_ref().unwrap();
info.insert(name, *column_val);
}
"f64" => {
let column_val: &f64 = first.field_at(i).unwrap().downcast_ref().unwrap();
info.insert(name, *column_val);
}
_ => {
return Err(MyError::new(format!("mysql type not handled:{}",value.type_name())));
}
}
}
self.apply(&info);
Ok(self)
}
}
};
}