use rbatis::RBatis;
use rbatis::Error;
use serde::Serialize;
#[derive(Debug, Serialize)]
pub struct Page<T> {
pub records: Vec<T>, pub total: u64, pub page_no: u64, pub page_size: u64, pub pages: u64, pub has_next: bool, }
impl<T> Page<T> {
pub fn new(records: Vec<T>, total: u64, page_no: u64, page_size: u64) -> Self {
let pages = (total + page_size - 1) / page_size;
let has_next = page_no < pages;
Self {
records,
total,
page_no,
page_size,
pages,
has_next,
}
}
}
#[derive(Default, Debug, Clone)]
pub struct QueryWrapper {
where_conditions: Vec<String>,
order_by: Vec<String>,
select_columns: Vec<String>,
limit: Option<u64>,
offset: Option<u64>,
custom_sql: Option<String>, join_conditions: Vec<String>, }
impl QueryWrapper {
pub fn new() -> Self {
Self::default()
}
pub fn eq<T: ToString>(mut self, column: &str, value: T) -> Self {
self.where_conditions.push(format!("{} = '{}'", column, value.to_string()));
self
}
pub fn ne<T: ToString>(mut self, column: &str, value: T) -> Self {
self.where_conditions.push(format!("{} != '{}'", column, value.to_string()));
self
}
pub fn gt<T: ToString>(mut self, column: &str, value: T) -> Self {
self.where_conditions.push(format!("{} > '{}'", column, value.to_string()));
self
}
pub fn lt<T: ToString>(mut self, column: &str, value: T) -> Self {
self.where_conditions.push(format!("{} < '{}'", column, value.to_string()));
self
}
pub fn like(mut self, column: &str, value: &str) -> Self {
self.where_conditions.push(format!("{} LIKE '%{}%'", column, value));
self
}
pub fn select(mut self, columns: Vec<&str>) -> Self {
self.select_columns = columns.into_iter().map(String::from).collect();
self
}
pub fn order_by(mut self, column: &str, asc: bool) -> Self {
let order = if asc { "ASC" } else { "DESC" };
self.order_by.push(format!("{} {}", column, order));
self
}
pub fn limit(&mut self, limit: u64) -> &mut Self {
self.limit = Some(limit);
self
}
pub fn offset(&mut self, offset: u64) -> &mut Self {
self.offset = Some(offset);
self
}
pub fn custom_sql(mut self, sql: &str) -> Self {
self.custom_sql = Some(sql.to_string());
self
}
pub fn inner_join(mut self, table: &str, on_condition: &str) -> Self {
self.join_conditions.push(format!("INNER JOIN {} ON {}", table, on_condition));
self
}
pub fn left_join(mut self, table: &str, on_condition: &str) -> Self {
self.join_conditions.push(format!("LEFT JOIN {} ON {}", table, on_condition));
self
}
pub fn right_join(mut self, table: &str, on_condition: &str) -> Self {
self.join_conditions.push(format!("RIGHT JOIN {} ON {}", table, on_condition));
self
}
pub fn build_sql(&self, table_name: &str) -> String {
if let Some(custom_sql) = &self.custom_sql {
let mut sql = custom_sql.clone();
if !self.where_conditions.is_empty() {
if !sql.to_uppercase().contains("WHERE") {
sql.push_str(" WHERE ");
} else {
sql.push_str(" AND ");
}
sql.push_str(&self.where_conditions.join(" AND "));
}
if !self.order_by.is_empty() {
sql.push_str(" ORDER BY ");
sql.push_str(&self.order_by.join(", "));
}
if let Some(limit) = self.limit {
sql.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = self.offset {
sql.push_str(&format!(" OFFSET {}", offset));
}
return sql;
}
let select = if self.select_columns.is_empty() {
"*".to_string()
} else {
self.select_columns.join(", ")
};
let mut sql = format!("SELECT {} FROM {}", select, table_name);
if !self.join_conditions.is_empty() {
sql.push_str(" ");
sql.push_str(&self.join_conditions.join(" "));
}
if !self.where_conditions.is_empty() {
sql.push_str(" WHERE ");
sql.push_str(&self.where_conditions.join(" AND "));
}
if !self.order_by.is_empty() {
sql.push_str(" ORDER BY ");
sql.push_str(&self.order_by.join(", "));
}
if let Some(limit) = self.limit {
sql.push_str(&format!(" LIMIT {}", limit));
}
if let Some(offset) = self.offset {
sql.push_str(&format!(" OFFSET {}", offset));
}
sql
}
pub async fn query<T>(&self, rb: &RBatis, table_name: &str) -> Result<Vec<T>, Error>
where
T: Serialize + for<'de> serde::Deserialize<'de>,
{
let sql = self.build_sql(table_name);
rb.query_decode(&sql, vec![]).await
}
pub async fn get_one<T>(&self, rb: &RBatis, table_name: &str) -> Result<Option<T>, Error>
where
T: Serialize + for<'de> serde::Deserialize<'de>,
{
let sql = self.build_sql(table_name);
rb.query_decode::<Option<T>>(&sql, vec![]).await
}
pub async fn delete(self, rb: &RBatis, table_name: &str) -> Result<u64, Error> {
let delete_sql = format!("delete from {}", table_name);
let sql = self.custom_sql(&delete_sql)
.build_sql(table_name);
Ok(rb.exec(&sql, vec![]).await?.rows_affected)
}
pub async fn page<T>(&self, rb: &RBatis, table_name: &str, page_no: u64, page_size: u64) -> Result<Page<T>, Error>
where
T: Serialize + for<'de> serde::Deserialize<'de>,
{
let count_sql = self.build_count_sql(table_name);
let total: u64 = rb.query_decode(&count_sql, vec![]).await?;
if total > 0 {
let offset = (page_no - 1) * page_size;
let mut wrapper = self.clone();
wrapper.limit(page_size); wrapper.offset(offset);
let records: Vec<T> = wrapper.query(rb, table_name).await?;
Ok(Page::new(records, total, page_no, page_size))
} else {
Ok(Page::new(vec![], 0, page_no, page_size))
}
}
fn build_count_sql(&self, table_name: &str) -> String {
if let Some(custom_sql) = &self.custom_sql {
let mut inner_sql = custom_sql.clone();
if !self.where_conditions.is_empty() {
if !inner_sql.to_uppercase().contains("WHERE") {
inner_sql.push_str(" WHERE ");
} else {
inner_sql.push_str(" AND ");
}
inner_sql.push_str(&self.where_conditions.join(" AND "));
}
format!("SELECT COUNT(*) FROM ({}) as t", inner_sql)
} else {
let mut sql = format!("SELECT COUNT(*) FROM {}", table_name);
if !self.join_conditions.is_empty() {
sql.push_str(" ");
sql.push_str(&self.join_conditions.join(" "));
}
if !self.where_conditions.is_empty() {
sql.push_str(" WHERE ");
sql.push_str(&self.where_conditions.join(" AND "));
}
sql
}
}
}