use std::marker::PhantomData;
use sqlx::mysql::MySqlRow;
use serde_derive::{ Serialize, Deserialize };
use sqlx::{ query, query_as, query_scalar };
use sqlx::{ Error, FromRow };
use sqlx::MySqlPool;
use sqlx_core::mysql::MySqlQueryResult;
use crate::transform::{ struct_to_hashmap, struct_to_btreemap };
use crate::BaseEntity;
use core::fmt::Debug;
pub static SELECT_FROM: &'static str = "SELECT * FROM";
pub static INSERT_INTO: &'static str = "INSERT INTO";
pub static UPDATE: &'static str = "UPDATE";
pub static DELETE_FROM: &'static str = "DELETE FROM";
pub fn mapper<T> (db: MySqlPool) -> BaseMapper<T>
where
T: for<'a> FromRow<'a, MySqlRow> + Send + Unpin + Debug + serde::Serialize + BaseEntity
{
BaseMapper::<T>::new(db)
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct PageData<T: BaseEntity> {
pub total: i64,
pub data: Vec<T>,
}
#[derive(Debug, Clone)]
pub struct BaseMapper<T: BaseEntity> {
db: MySqlPool,
table_name: &'static str,
_marker: PhantomData<T>,
}
impl<T: for<'a> FromRow<'a, MySqlRow> + Send + Unpin + Debug + serde::Serialize + BaseEntity>
BaseMapper<T>
{
pub fn new(db: MySqlPool) -> Self {
Self {
db,
table_name: T::table_name(),
_marker: PhantomData,
}
}
pub async fn insert(self, entity: T) -> Result<MySqlQueryResult, Error> {
let mut key: Vec<String>= Vec::new();
let mut value: Vec<String> = Vec::new();
for (k, v) in struct_to_hashmap(entity) {
if v == "null" {
continue;
}
key.push(k);
value.push(format!("{}", v));
};
let sql_str = format!(
"{} {} ( {} ) VALUES ( {} )",
INSERT_INTO, self.table_name, key.join(", "), value.join(", ").replace('\"', "'")
);
println!("insert sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn insert_batch_some_column(self, entity_vec: Vec<T>) -> Result<MySqlQueryResult, Error> {
let mut keys: Vec<String> = Vec::new();
let mut values: Vec<String> = Vec::new();
let mut key_lock: bool = false;
entity_vec
.iter()
.for_each(|entity| {
let mut value: Vec<String> = Vec::new();
for (k, v) in struct_to_btreemap(entity) {
value.push(format!("{}", v));
if key_lock == false {
keys.push(k);
}
};
values.push(format!("({})", value.join(", ").replace('\"', "'")));
key_lock = true;
});
let sql_str = format!(
"{} {} ({}) VALUES {}",
INSERT_INTO, self.table_name, keys.join(", "), values.join(", ")
);
println!("insert_batch_some_column sql:{}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn update_by_id(self, entity: T) -> Result<MySqlQueryResult, Error> {
let mut id: String = format!("");
let mut set_value = Vec::new();
for (k, v) in struct_to_hashmap(entity) {
if k == "id" {
id = format!("{}", v);
continue;
}
if k == "create_time" || k == "update_time" || v.is_null() {
continue;
}
set_value.push(format!("{} = {}", k, v));
}
let sql_str = format!(
"{} {} SET {} WHERE id = {}",
UPDATE, self.table_name, set_value.join(", ").replace('\"', "'"), id,
);
println!("update_by_id sql:{}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn update(self, entity: T, wrapper: String) -> Result<MySqlQueryResult, Error> {
let mut set_value = Vec::new();
for (k, v) in struct_to_hashmap(entity) {
if k == "id" || k == "create_time" || k == "update_time" || v.is_null() {
continue;
}
set_value.push(format!("{} = {}", k, v));
}
let sql_str = format!(
"{} {} SET {} WHERE is_deleted = '0' {}",
UPDATE, self.table_name, set_value.join(", ").replace('\"', "'"), h_wrapper(wrapper),
);
println!("update sql:{}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_page(self, page: String, wrapper: String) -> Result<PageData<T>, Error> {
let mut err: Option<Error> = None;
let sql_str = format!(
"{} {} WHERE is_deleted = '0' {}{}",
SELECT_FROM,
self.table_name,
h_wrapper(wrapper.clone()),
page,
);
println!("select_page sql: {}", &sql_str);
let mut page_data: PageData<T> = PageData {
total: 0,
data: vec![],
};
let mut pool = self.db.acquire().await?;
match self.total(wrapper).await {
Ok(res) => page_data.total = res,
Err(e) => err = Some(e),
};
match query_as::<_, T>(&sql_str).fetch_all(&mut pool).await {
Ok(res) => page_data.data = res,
Err(e) => err = Some(e),
};
if let Some(e) = err { return Err(e); };
Ok(page_data)
}
pub async fn select_list(self, wrapper: String) -> Result<Vec<T>, Error> {
let sql_str = format!(
"{} {} WHERE is_deleted = '0' {}",
SELECT_FROM, self.table_name, h_wrapper(wrapper),
);
println!("select_list sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_all(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_list_custom(self, sql_str: String) -> Result<Vec<T>, Error> {
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_all(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_one(self, wrapper: String) -> Result<Option<T>, Error> {
let sql_str = format!(
"{} {} WHERE is_deleted = '0' {} LIMIT 1",
SELECT_FROM, self.table_name, h_wrapper(wrapper),
);
println!("select_list sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_optional(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_one_custom(self, sql_str: String) -> Result<Option<T>, Error> {
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_optional(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_batch_ids(self, ids: Vec<u64>) -> Result<Vec<T>, Error> {
let ids = ids.iter().map(|&n| format!("{}", n)).collect::<Vec<String>>().join(",");
let sql_str = format!(
"{} {} WHERE id IN ({})",
SELECT_FROM, self.table_name, ids
);
println!("select_batch_ids sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_all(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_by_map(self, wrapper: String) -> Result<Option<T>, Error> {
let sql_str = format!(
"{} {} WHERE is_deleted = '0' {}",
SELECT_FROM, self.table_name, h_wrapper(wrapper),
);
println!("select_by_map sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_optional(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn select_by_id(self, id: u64) -> Result<Option<T>, Error> {
let sql_str = format!(
"{} {} WHERE id = {} AND is_deleted = 0",
SELECT_FROM, self.table_name, id
);
println!("select_by_id sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_as::<_, T>(&sql_str).fetch_optional(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn total(self, wrapper: String) -> Result<i64, Error> {
let sql_str = format!("SELECT COUNT(*) FROM {} WHERE is_deleted = 0 {}", self.table_name ,h_wrapper(wrapper));
println!("total sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query_scalar(&sql_str).fetch_one(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn delete_by_id(self, id: u64) -> Result<MySqlQueryResult, Error> {
let sql_str = format!(
"{} {} WHERE id = {}",
DELETE_FROM, self.table_name, id
);
println!("delete_by_id sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn delete_batch_ids(self, ids: Vec<u64>) -> Result<MySqlQueryResult, Error> {
let ids = ids.iter().map(|&n| format!("{}", n)).collect::<Vec<String>>().join(",");
let sql_str = format!(
"{} {} WHERE id IN ({})",
DELETE_FROM, self.table_name, ids
);
println!("delete_batch_ids sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
pub async fn delete(self, wrapper: String) -> Result<MySqlQueryResult, Error> {
let sql_str = format!(
"{} {} WHERE is_deleted = '0' {}",
DELETE_FROM, self.table_name, h_wrapper(wrapper),
);
println!("delete sql: {}", &sql_str);
let mut pool = self.db.acquire().await?;
match query(&sql_str).execute(&mut pool).await {
Ok(res) => Ok(res),
Err(err) => Err(err),
}
}
}
fn h_wrapper(mut wrapper: String) -> String{
if wrapper.is_empty() == false {
wrapper = format!("AND {}", wrapper);
};
wrapper
}