use rbatis::rbatis_sql::ops::AsProxy;
use rbson::Bson;
use std::collections::HashMap;
use std::fmt::Debug;
use serde::Serialize;
use rbatis::core::convert::StmtConvert;
use rbatis::core::db::DriverType;
#[derive(Clone)]
pub struct DynamicWrapper {
pub driver_type: DriverType,
pub dml: String,
pub sql: String,
pub args: Vec<Bson>,
pub formats: HashMap<String, String>,
}
macro_rules! push_sql {
($i:expr,$($v:expr$(,)?)*) => {
$($i.push_str($v);)*
};
}
impl Debug for DynamicWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut formats = HashMap::new();
for (k, v) in &self.formats {
formats.insert(k.to_string(), v.clone());
}
f.debug_struct("DynamicWrapper")
.field("driver_type", &self.driver_type)
.field("sql", &self.sql)
.field("args", &self.args)
.field("dml", &self.dml)
.finish()
}
}
impl DynamicWrapper {
pub fn new(driver_type: &DriverType) -> Self {
Self {
driver_type: *driver_type,
dml: "where".to_string(),
sql: String::with_capacity(200),
args: Vec::with_capacity(5),
formats: Default::default(),
}
}
pub fn trim_value(mut self, from: &str, to: &str) -> Self {
self.sql = self.sql.replace(from, to);
self
}
pub fn set_formats(mut self, formats: HashMap<String, String>) -> Self {
self.formats = formats;
self
}
pub fn set_dml(mut self, dml: &str) -> Self {
self.dml = dml.to_string();
self
}
pub fn push_wrapper(self, arg: DynamicWrapper) -> Self {
self.push(&arg.sql, arg.args)
}
pub fn push(mut self, sql: &str, args: Vec<rbson::Bson>) -> Self {
let mut new_sql = sql.to_string();
match self.driver_type {
DriverType::None => {}
DriverType::Mysql => {}
DriverType::Postgres | DriverType::Mssql => {
for index_target in 0..args.len() {
let mut convert_column = String::new();
self.driver_type
.stmt_convert(index_target, &mut convert_column);
let mut convert_column_new = String::new();
self.driver_type
.stmt_convert(index_target + self.args.len(), &mut convert_column_new);
new_sql = new_sql.replace(convert_column.as_str(), convert_column_new.as_str());
}
}
DriverType::Sqlite => {}
}
self.sql.push_str(new_sql.as_str());
for x in args {
self.args.push(x);
}
self
}
pub fn do_if<F>(self, test: bool, method: F) -> Self
where
F: FnOnce(Self) -> Self,
{
if test {
return method(self);
}
self
}
pub fn r#if<F>(self, test: bool, method: F) -> Self
where
F: FnOnce(Self) -> Self,
{
self.do_if(test, method)
}
pub fn do_if_else<F>(self, test: bool, method_if: F, method_else: fn(Self) -> Self) -> Self
where
F: FnOnce(Self) -> Self,
{
if test {
method_if(self)
} else {
method_else(self)
}
}
pub fn r#if_else<F>(self, test: bool, method_if: F, method_else: fn(Self) -> Self) -> Self
where
F: FnOnce(Self) -> Self,
{
self.do_if_else(test, method_if, method_else)
}
pub fn do_match<F>(
self,
cases: &[(bool, fn(DynamicWrapper) -> DynamicWrapper)],
default: F,
) -> Self
where
F: FnOnce(Self) -> Self,
{
for (test, case) in cases {
if *test {
return case(self);
}
}
default(self)
}
pub fn set_sql(mut self, sql: &str) -> Self {
self.sql = sql.to_string();
self
}
pub fn push_sql(mut self, sql: &str) -> Self {
self.sql.push_str(sql);
self
}
pub fn set_args<T>(mut self, args: &[T]) -> Self
where
T: Serialize,
{
let v = rbatis::as_bson!(args);
match v {
Bson::Null => {
return self;
}
Bson::Array(ref _arr) => {
self.args = v.as_array().unwrap_or(&vec![]).to_owned();
}
_ => {}
}
self
}
pub fn push_arg<T>(mut self, arg: T) -> Self
where
T: Serialize,
{
let v = rbatis::as_bson!(&arg);
self.args.push(v);
self
}
pub fn pop_arg(mut self) -> Self {
self.args.pop();
self
}
pub fn not_allow_add_and_on_end(&self) -> bool {
let sql = self.sql.trim_end();
if sql.is_empty() {
return true;
}
sql.ends_with(rbatis::sql::TEMPLATE.r#where.left_space)
|| sql.ends_with(rbatis::sql::TEMPLATE.and.left_space)
|| sql.ends_with(rbatis::sql::TEMPLATE.or.left_space)
|| sql.ends_with('(')
|| sql.ends_with(',')
|| sql.ends_with('=')
|| sql.ends_with('+')
|| sql.ends_with('-')
|| sql.ends_with('*')
|| sql.ends_with('/')
|| sql.ends_with('%')
|| sql.ends_with('^')
|| sql.ends_with('>')
|| sql.ends_with('<')
|| sql.ends_with('&')
|| sql.ends_with('|')
}
pub fn and(mut self) -> Self {
if !self.not_allow_add_and_on_end() {
self.sql
.push_str(rbatis::sql::TEMPLATE.and.left_right_space);
}
self
}
pub fn or(mut self) -> Self {
if !self.not_allow_add_and_on_end() {
self.sql.push_str(rbatis::sql::TEMPLATE.or.left_right_space);
}
self
}
pub fn having(mut self, sql_having: &str) -> Self {
self = self.and();
push_sql!(
self.sql,
rbatis::sql::TEMPLATE.having.value,
" ",
sql_having
);
self
}
pub fn all_eq<T>(mut self, arg: T) -> Self
where
T: Serialize,
{
self = self.and();
let v = rbatis::as_bson!(&arg);
if v.is_null() {
return self;
}
if !v.is_object() {
return self;
}
let map = v.as_document().unwrap();
if map.is_empty() {
return self;
}
self.sql.push('(');
let len = map.len();
let mut index = 0;
for (k, v) in map {
self = self.eq(k.as_str(), v);
if (index + 1) != len {
self.sql.push_str(" and ");
index += 1;
}
}
self.sql.push(')');
self
}
pub fn do_format_column(&self, column: &str, data: &mut String) {
if let Some(source) = self.formats.get(column) {
*data = source.replace("{}", data);
}
}
pub fn eq<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " = ", convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn ne<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " <> ", convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn order_by(mut self, is_asc: bool, columns: &[&str]) -> Self {
let len = columns.len();
if len == 0 {
return self;
}
let mut index = 0;
self.sql = self
.sql
.trim_end()
.trim_end_matches(rbatis::sql::TEMPLATE.r#where.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.or.left_space)
.to_string();
self.sql
.push_str(rbatis::sql::TEMPLATE.order_by.left_right_space);
for x in columns {
if is_asc {
push_sql!(self.sql, x, " ", rbatis::sql::TEMPLATE.asc.value,);
} else {
push_sql!(self.sql, x, " ", rbatis::sql::TEMPLATE.desc.value,);
}
if (index + 1) != len {
self.sql.push(',');
index += 1;
}
}
self.sql.push(' ');
self
}
pub fn order_bys(mut self, column_asc: &[(&str, bool)]) -> Self {
let len = column_asc.len();
if len == 0 {
return self;
}
let mut index = 0;
self.sql = self
.sql
.trim_end()
.trim_end_matches(rbatis::sql::TEMPLATE.r#where.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.or.left_space)
.to_string();
self.sql
.push_str(rbatis::sql::TEMPLATE.order_by.left_right_space);
for (x, is_asc) in column_asc {
if *is_asc {
push_sql!(self.sql, x, " ", rbatis::sql::TEMPLATE.asc.value,);
} else {
push_sql!(self.sql, x, " ", rbatis::sql::TEMPLATE.desc.value,);
}
if (index + 1) != len {
self.sql.push(',');
index += 1;
}
}
self.sql.push(' ');
self
}
pub fn group_by(mut self, columns: &[&str]) -> Self {
let len = columns.len();
if len == 0 {
return self;
}
let mut index = 0;
self.sql = self
.sql
.trim()
.trim_end_matches(rbatis::sql::TEMPLATE.r#where.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.trim_end_matches(rbatis::sql::TEMPLATE.or.left_space)
.to_string();
self.sql
.push_str(rbatis::sql::TEMPLATE.group_by.left_right_space);
for x in columns {
self.sql.push_str(x);
if (index + 1) != len {
self.sql.push(',');
index += 1;
}
}
self.sql.push(' ');
self
}
pub fn gt<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " > ", &convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn ge<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " >= ", &convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn lt<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " < ", &convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn le<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, column, " <= ", &convert_column.as_str(),);
self.args.push(rbatis::as_bson!(&obj));
self
}
pub fn between<T>(mut self, column: &str, min: T, max: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.between.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&min));
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
" ",
rbatis::sql::TEMPLATE.and.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&max));
self
}
pub fn not_between<T>(mut self, column: &str, min: T, max: T) -> Self
where
T: Serialize,
{
self = self.and();
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.not.value,
" ",
rbatis::sql::TEMPLATE.between.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&min));
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
" ",
rbatis::sql::TEMPLATE.and.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&max));
self
}
pub fn like<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let v = rbatis::as_bson!(&obj);
let mut v_str = String::new();
if v.as_str().is_some() {
v_str.push_str(format!("{}%", v.as_str().unwrap()).as_str());
} else {
v_str.push_str(format!("{}%", v).as_str());
}
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.like.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&v_str));
self
}
pub fn like_left<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let v = rbatis::as_bson!(&obj);
let mut v_str = String::new();
if v.as_str().is_some() {
v_str.push_str(format!("{}%", v.as_str().unwrap()).as_str());
} else {
v_str.push_str(format!("{}%", v).as_str());
}
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.like.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&v_str));
self
}
pub fn like_right<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let v = rbatis::as_bson!(&obj);
let mut v_str = String::new();
if v.as_str().is_some() {
v_str.push_str(format!("{}%", v.as_str().unwrap()).as_str());
} else {
v_str.push_str(format!("{}%", v).as_str());
}
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.like.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&v_str));
self
}
pub fn not_like<T>(mut self, column: &str, obj: T) -> Self
where
T: Serialize,
{
self = self.and();
let v = rbatis::as_bson!(&obj);
let mut v_str = String::new();
if v.as_str().is_some() {
v_str.push_str(format!("%{}%", v.as_str().unwrap()).as_str());
} else {
v_str.push_str(format!("%{}%", v).as_str());
}
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.not.value,
" ",
rbatis::sql::TEMPLATE.like.value,
" ",
&convert_column.as_str(),
);
self.args.push(rbatis::as_bson!(&v_str));
self
}
pub fn is_null(mut self, column: &str) -> Self {
self = self.and();
self.sql.push_str(column);
self.sql.push_str(rbatis::sql::TEMPLATE.is.left_space);
self.sql.push_str(rbatis::sql::TEMPLATE.null.left_space);
self
}
pub fn is_not_null(mut self, column: &str) -> Self {
self = self.and();
self.sql.push_str(column);
self.sql.push_str(rbatis::sql::TEMPLATE.is.left_space);
self.sql.push_str(rbatis::sql::TEMPLATE.not.left_space);
self.sql.push_str(rbatis::sql::TEMPLATE.null.left_space);
self
}
pub fn in_array<T>(mut self, column: &str, obj: &[T]) -> Self
where
T: Serialize,
{
if obj.is_empty() {
return self;
}
self = self.and();
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.r#in.value,
" (",
);
for x in obj {
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, " ", &convert_column.as_str(), " ",);
self.sql.push(',');
self.args.push(rbatis::as_bson!(x));
}
self.sql.pop();
push_sql!(self.sql, ")",);
self
}
pub fn in_<T>(self, column: &str, obj: &[T]) -> Self
where
T: Serialize,
{
self.in_array(column, obj)
}
pub fn r#in<T>(self, column: &str, obj: &[T]) -> Self
where
T: Serialize,
{
self.in_array(column, obj)
}
pub fn not_in<T>(mut self, column: &str, obj: &[T]) -> Self
where
T: Serialize,
{
if obj.is_empty() {
return self;
}
self = self.and();
push_sql!(
self.sql,
column,
" ",
rbatis::sql::TEMPLATE.not.value,
" ",
rbatis::sql::TEMPLATE.r#in.value,
" (",
);
for x in obj {
let mut convert_column = String::new();
self.driver_type
.stmt_convert(self.args.len(), &mut convert_column);
self.do_format_column(column, &mut convert_column);
push_sql!(self.sql, " ", &convert_column.as_str(), " ",);
self.sql.push(',');
self.args.push(rbatis::as_bson!(x));
}
self.sql.pop();
push_sql!(self.sql, ")",);
self
}
pub fn trim_space(mut self) -> Self {
self.sql = self.sql.replace(" ", " ");
self
}
pub fn trim_and(mut self) -> Self {
self.sql = self
.sql
.trim()
.trim_start_matches(rbatis::sql::TEMPLATE.and.right_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.to_string();
self
}
pub fn trim_or(mut self) -> Self {
self.sql = self
.sql
.trim()
.trim_start_matches(rbatis::sql::TEMPLATE.or.right_space)
.trim_end_matches(rbatis::sql::TEMPLATE.or.left_space)
.to_owned();
self
}
pub fn trim_and_or(mut self) -> Self {
self.sql = self
.sql
.trim()
.trim_start_matches(rbatis::sql::TEMPLATE.and.right_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.trim_start_matches(rbatis::sql::TEMPLATE.and.right_space)
.trim_end_matches(rbatis::sql::TEMPLATE.and.left_space)
.to_owned();
self
}
pub fn insert_into(mut self, table_name: &str, columns: &str, values: &str) -> Self {
self.sql = format!(
"{} {} ({}) {} ({})",
rbatis::sql::TEMPLATE.insert_into.value,
table_name,
columns,
rbatis::sql::TEMPLATE.values.value,
values
);
self
}
pub fn limit(mut self, limit: u64) -> Self {
use std::fmt::Write;
push_sql!(self.sql, " ", rbatis::sql::TEMPLATE.limit.value, " ",);
let _ = self.sql.write_fmt(format_args!("{}", limit)).is_ok();
self.sql.push(' ');
self
}
}