use crate::table_dao::table_util;
use crate::utils;
use serde::Serialize;
#[derive(Debug, Default, Clone, Serialize)]
pub struct Entity {
pub name: String,
pub columns: Vec<Column>,
pub comment: String,
}
#[derive(Debug, Default, Clone, Serialize)]
pub struct Column {
pub name: String,
pub nick: String,
pub data_type: String,
pub is_primary_key: bool,
pub is_auto_increment: bool,
pub default_value: Option<String>,
pub is_nullable: bool,
pub comment: String,
}
impl Entity {
pub fn has_version(&self) -> bool {
self.columns.iter().any(|it| it.name == "version")
}
pub fn has_deleted(&self) -> bool {
self.columns.iter().any(|it| it.name == "deleted")
}
pub fn has_deleted_at(&self) -> bool {
self.columns.iter().any(|it| it.name == "deleted_at")
}
pub fn has_deleted_by(&self) -> bool {
self.columns.iter().any(|it| it.name == "deleted_by")
}
fn primary_key_columns(&self) -> impl Iterator<Item = &Column> {
self.columns.iter().filter(|it| it.is_primary_key)
}
pub fn entity_name(&self) -> String {
utils::snake_to_pascal(&self.name, "_")
}
pub fn make_entity_struct(&self) -> String {
let member_src = self
.columns
.iter()
.map(|it| it.make_member_src())
.collect::<Vec<_>>()
.join("");
r#"
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize, sqlx::FromRow)]
pub struct [NAME] {
[MEMBER]
}
/// 给 结构体 实现 AsRef
impl AsRef<[NAME]> for [NAME] {
#[inline]
fn as_ref(&self) -> &[NAME] {
self
}
}
"#
.replace("[NAME]", self.entity_name().as_str())
.replace("[MEMBER]", member_src.as_str())
.to_string()
}
pub fn make_query_entity_src(&self) -> String {
let mut entity_src = String::new();
entity_src.push_str("#[derive(Default)]\n");
entity_src.push_str(&format!(
"pub struct {}Query {{\n",
utils::snake_to_pascal(&self.name, "_")
));
self.columns.iter().for_each(|it| {
let mut field_type = table_util::db_type_to_rust(&it.data_type, &it.name).to_string();
field_type = format!("QueryModel<{}>", field_type);
entity_src.push_str(&format!(" pub {}: {},\n", it.name, field_type));
});
entity_src.push_str("}\n");
entity_src
}
fn auto_increment_and_primary_column(&self) -> Option<String> {
self.columns.iter().find_map(|column| {
if column.is_auto_increment && column.is_primary_key {
Some(column.name.clone())
} else {
None
}
})
}
pub fn make_insert_func(&self) -> String {
let mut insert_columns: Vec<&str> = Vec::new(); let mut insert_params_replace: Vec<&str> = Vec::new(); let mut insert_params: Vec<String> = Vec::new();
let mut need_now = false; self.columns
.iter()
.filter(|it| {
if it.is_auto_increment && it.is_primary_key {
return false;
}
if it.name == "deleted_at" {
return false;
}
if it.name == "deleted_by" {
return false;
}
if it.name == "deleted" {
return false;
}
if it.name == "version" {
return false;
}
true
})
.for_each(|it| {
insert_columns.push(it.name.as_str());
insert_params_replace.push("?");
if it.name == "created_at" {
need_now = true;
insert_params.push("timestamp".to_string());
} else if it.name == "updated_at" {
need_now = true;
insert_params.push("timestamp".to_string());
} else {
insert_params.push(format!("entity.{}", it.name));
}
});
let mut insert_sql = format!(
"INSERT INTO {} ({}) VALUES ({})",
self.name,
insert_columns.join(", "),
insert_params_replace.join(", ")
);
let fn_template = if let Some(key) = self.auto_increment_and_primary_column() {
insert_sql.push_str(&format!(" RETURNING {}", key));
r#"
/// 插入数据
pub async fn insert(ctx: &mut sqlx_context::DbContext, entity: impl AsRef<[ENTITY]>) -> Result<i64, sqlx::Error>{
[TIME_CODE]
let entity = entity.as_ref();
sqlx::query_scalar!("[SQL]", [PARAM]).fetch_one(ctx).await
}"#
} else {
r#"
/// 插入数据
pub async fn insert(ctx: &mut sqlx_context::DbContext, entity: impl AsRef<[ENTITY]>) -> Result<(),sqlx::Error>{
[TIME_CODE]
let entity = entity.as_ref();
sqlx::query!("[SQL]", [PARAM]).execute(ctx).await?;
Ok(())
}"#
};
let time_code = if need_now {
"let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64;"
} else {
""
};
fn_template
.replace("[TIME_CODE]", time_code)
.replace("[SQL]", &insert_sql)
.replace("[PARAM]", &(insert_params.join(", ")))
.replace("[ENTITY]", &utils::snake_to_pascal(&self.name, "_"))
}
pub fn make_select_one_func(&self) -> String {
let mut where_params: Vec<&str> = Vec::new(); let mut func_params: Vec<String> = Vec::new();
let where_columns: Vec<String> = self
.primary_key_columns()
.map(|it| {
where_params.push(it.name.as_str());
func_params.push(format!(
"{}:{}",
it.name,
table_util::db_type_to_rust(&it.data_type, &it.name)
));
format!("{} = ?", it.name)
})
.collect();
if where_columns.is_empty() {
return String::new();
}
let filed_columns: Vec<&str> = self.columns.iter().map(|it| it.name.as_str()).collect();
let select_one_template = r##"
/// 通过主键查询一条数据
pub async fn select_one(ctx: &mut sqlx_context::DbContext, [FUNC_PARAMS]) -> Result<[ENTITY], sqlx::Error>
{
sqlx::query_as!(
[ENTITY],
"SELECT [FIELDS] FROM [TABLE] WHERE [WHERE]",
[PARAM]
).fetch_one(ctx).await
}
"##;
select_one_template
.replace("[FUNC_PARAMS]", &func_params.join(", "))
.replace("[TABLE]", &self.name)
.replace("[FIELDS]", &filed_columns.join(", "))
.replace("[ENTITY]", &utils::snake_to_pascal(&self.name, "_"))
.replace("[WHERE]", &where_columns.join(" AND "))
.replace("[PARAM]", &where_params.join(", "))
}
pub fn make_select_all_func(&self) -> String {
let mut templates = Vec::new();
if self.has_deleted() {
let select_all_template = r##"
/// 查询所有未删除的数据
pub async fn select_all(ctx: &mut sqlx_context::DbContext) -> Result<Vec<[ENTITY]>, sqlx::Error>
{
sqlx::query_as!([ENTITY], "SELECT * FROM [TABLE] where deleted = 0")
.fetch_all(ctx)
.await
}
"##;
let select_all_include_deleted_template = r##"
/// 查询所有数据,包括已删除的数据
pub async fn select_all_include_deleted(ctx: &mut sqlx_context::DbContext) -> Result<Vec<[ENTITY]>, sqlx::Error>
{
sqlx::query_as!([ENTITY], "SELECT * FROM [TABLE]")
.fetch_all(ctx)
.await
}
"##;
templates.push(select_all_template);
templates.push(select_all_include_deleted_template);
} else {
templates.push(
r##"
/// 查询所有
pub async fn select_all(ctx: &mut sqlx_context::DbContext) -> Result<Vec<[ENTITY]>, sqlx::Error>
{
sqlx::query_as!([ENTITY], "SELECT * FROM [TABLE]")
.fetch_all(ctx)
.await
}
"##,
);
}
templates
.iter()
.map(|it| -> String {
it.replace("[TABLE]", &self.name)
.replace("[ENTITY]", &utils::snake_to_pascal(&self.name, "_"))
})
.collect::<Vec<_>>()
.join("\n")
}
pub fn make_update_func(&self) -> String {
let mut update_columns: Vec<String> = Vec::new(); let mut update_params: Vec<String> = Vec::new(); let mut where_columns: Vec<String> = Vec::new();
let has_version = self.has_version();
if has_version {
update_columns.push("version = version + 1".to_string());
}
let mut timestamp = String::new();
self.columns
.iter()
.filter(|it| {
if it.is_primary_key {
return false;
}
if it.name == "created_at" {
return false;
}
if it.name == "deleted_at" {
return false;
}
if it.name == "deleted" {
return false;
}
if it.name == "version" {
return false;
}
true
})
.for_each(|it| {
update_columns.push(format!("{} = ?", it.name));
if it.name == "updated_at" {
timestamp = "let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64;".to_string();
update_params.push("timestamp".to_string());
} else {
update_params.push(format!("entity.{}", it.name));
}
});
self.columns
.iter()
.filter(|it| it.is_primary_key)
.for_each(|it| {
where_columns.push(format!("{} = ?", it.name));
update_params.push(format!("entity.{}", it.name));
});
if has_version {
where_columns.push("version = ?".to_string());
update_params.push("entity.version".to_string());
}
if self.has_deleted() {
where_columns.push("deleted = 0".to_string());
}
let update_sql = format!(
"UPDATE {} SET {} WHERE {}",
self.name,
update_columns.join(", "),
where_columns.join(" AND ")
);
if where_columns.is_empty() {
return String::new();
}
r##"
/// 更新数据
pub async fn update(ctx: &mut sqlx_context::DbContext, entity: impl AsRef<[ENTITY]>) -> Result<u64, sqlx::Error>
{
[TIMESTAMP]
let entity = entity.as_ref();
let rs = sqlx::query!(
"[SQL]",
[PARAM]
).execute(ctx).await?;
let count = rs.rows_affected();
Ok(count)
}
"##
.replace("[TIMESTAMP]", timestamp.as_str())
.replace("[SQL]", &update_sql)
.replace("[PARAM]", &(update_params.join(", ")))
.replace("[ENTITY]", self.entity_name().as_str())
}
pub fn make_set_delete_func(&self) -> String {
if !self.has_deleted() {
return String::new();
}
let mut where_columns = Vec::new(); let mut sql_params: Vec<&str> = Vec::new(); let mut func_params: Vec<String> = Vec::new(); let mut update_fields = vec!["deleted = 1"]; self.primary_key_columns().for_each(|it| {
func_params.push(format!(
"{}: {}",
it.name,
table_util::db_type_to_rust(&it.data_type, &it.name)
));
where_columns.push(format!("{} = ?", it.name));
});
if where_columns.is_empty() {
return String::new();
}
if self.has_version() {
func_params.push("version: i64".to_string());
where_columns.push("version = ?".to_string());
update_fields.push("version = version + 1");
}
let mut timestamp = String::new();
if self.has_deleted_at() {
timestamp = "let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64;".to_string();
update_fields.push("deleted_at = ?");
}
if self.has_deleted_by() {
update_fields.push("deleted_by = ?");
func_params.push("deleted_by: String".to_string());
}
where_columns.push("deleted = 0".to_string());
if self.has_deleted_at() {
sql_params.push("timestamp");
}
if self.has_deleted_by() {
sql_params.push("deleted_by");
}
self.primary_key_columns().for_each(|it| {
sql_params.push(it.name.as_str());
});
if self.has_version() {
sql_params.push("version");
}
let delete_sql = format!(
"UPDATE {} SET {} WHERE {}",
self.name,
update_fields.join(", "),
where_columns.join(" AND ")
);
r##"
/// 逻辑删除数据
pub async fn set_delete(
ctx: &mut sqlx_context::DbContext,
[FUNC_PARAMS]
) -> Result<u64, sqlx::Error>
{
[TIMESTAMP]
let rs = sqlx::query!("[SQL]", [PARAM])
.execute(ctx)
.await?;
let count = rs.rows_affected();
Ok(count)
}
"##
.replace("[TIMESTAMP]", ×tamp)
.replace("[SQL]", &delete_sql)
.replace("[PARAM]", &sql_params.join(", "))
.replace("[FUNC_PARAMS]", &func_params.join(", "))
}
pub fn make_set_delete_ignore_version_func(&self) -> String {
if !self.has_deleted() {
return String::new();
}
let mut where_columns = Vec::new(); let mut sql_params: Vec<&str> = Vec::new(); let mut func_params: Vec<String> = Vec::new(); let mut update_fields = vec!["deleted = 1"]; self.primary_key_columns().for_each(|it| {
func_params.push(format!(
"{}: {}",
it.name,
table_util::db_type_to_rust(&it.data_type, &it.name)
));
where_columns.push(format!("{} = ?", it.name));
});
if where_columns.is_empty() {
return String::new();
}
if self.has_version() {
update_fields.push("version = version + 1");
}
let mut timestamp = String::new();
if self.has_deleted_at() {
timestamp = "let timestamp = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis() as i64;".to_string();
update_fields.push("deleted_at = ?");
}
if self.has_deleted_by() {
update_fields.push("deleted_by = ?");
func_params.push("deleted_by: String".to_string());
}
where_columns.push("deleted = 0".to_string());
if self.has_deleted_at() {
sql_params.push("timestamp");
}
if self.has_deleted_by() {
sql_params.push("deleted_by");
}
self.primary_key_columns().for_each(|it| {
sql_params.push(it.name.as_str());
});
let delete_sql = format!(
"UPDATE {} SET {} WHERE {}",
self.name,
update_fields.join(", "),
where_columns.join(" AND ")
);
r##"
/// 逻辑删除数据
pub async fn set_delete_ignone_version(
ctx: &mut sqlx_context::DbContext,
[FUNC_PARAMS]
) -> Result<u64, sqlx::Error>
{
[TIMESTAMP]
let rs = sqlx::query!("[SQL]", [PARAM])
.execute(ctx)
.await?;
let count = rs.rows_affected();
Ok(count)
}
"##
.replace("[TIMESTAMP]", ×tamp)
.replace("[SQL]", &delete_sql)
.replace("[PARAM]", &sql_params.join(", "))
.replace("[FUNC_PARAMS]", &func_params.join(", "))
}
pub fn make_delete_func(&self) -> String {
let mut where_columns = Vec::new(); let mut sql_params: Vec<&str> = Vec::new(); let mut func_params: Vec<String> = Vec::new(); self.columns
.iter()
.filter(|it| it.is_primary_key)
.for_each(|it| {
sql_params.push(it.name.as_str());
func_params.push(format!(
"{}: {}",
it.name,
table_util::db_type_to_rust(&it.data_type, &it.name)
));
where_columns.push(format!("{} = ?", it.name));
});
if where_columns.is_empty() {
return String::new();
}
let delete_sql = format!(
"DELETE FROM {} WHERE {}",
self.name,
where_columns.join(" AND ")
);
r##"
/// 物理删除数据
pub async fn delete(ctx: &mut sqlx_context::DbContext, [FUNC_PARAMS]) -> Result<u64, sqlx::Error>
{
let rs = sqlx::query!("[SQL]", [PARAM])
.execute(ctx)
.await?;
let count = rs.rows_affected();
Ok(count)
}
"##
.replace("[SQL]", &delete_sql)
.replace("[PARAM]", &sql_params.join(", "))
.replace("[FUNC_PARAMS]", &func_params.join(", "))
}
}
impl Column {
pub fn make_member_src(&self) -> String {
let mut field_type = table_util::db_type_to_rust(&self.data_type, &self.name).to_string();
if self.is_nullable {
field_type = format!(": Option<{}>", field_type);
} else {
field_type = format!(": {}", field_type);
}
let mut comment = self.comment.clone();
if !comment.is_empty() {
comment = format!("/// {}", comment)
}
format!("{}\n pub {} {},\n", comment, self.name, field_type)
}
}