pub mod mssql_mapper;
pub mod mysql_mapper;
pub mod pg_mapper;
pub mod sqlite_mapper;
use crate::executor::Executor;
use crate::Error;
use futures_core::future::BoxFuture;
use log::debug;
pub use mssql_mapper::*;
pub use mysql_mapper::*;
pub use pg_mapper::*;
use rbs::Value;
pub use sqlite_mapper::*;
const PRIMARY_KEY: &'static str = " PRIMARY KEY ";
pub fn sync<'a>(
executor: &'a dyn Executor,
mapper: &'a dyn ColumnMapper,
table: Value,
table_name: &str,
) -> BoxFuture<'a, Result<(), Error>> {
let name = table_name.to_owned();
Box::pin(async move {
match table {
Value::Map(m) => {
let db_driver_type = executor.driver_type()?;
if db_driver_type != mapper.driver_type() {
return Err(Error::from(format!(
"table sync mapper driver='{}',db driver='{}'",
mapper.driver_type(),
db_driver_type
)));
}
let mut sql_create = format!("CREATE TABLE {} ", name);
let mut sql_column = format!("");
for (k, v) in &m {
let k = k.as_str().unwrap_or_default();
let column_type_value = mapper.get_column_type(k, &v);
sql_column.push_str(k);
sql_column.push_str(" ");
sql_column.push_str(column_type_value.as_str());
if column_type_value.is_empty() && k.eq("id")
|| v.as_str().unwrap_or_default() == "id"
{
sql_column.push_str(&PRIMARY_KEY);
}
sql_column.push_str(",");
}
if sql_column.ends_with(",") {
sql_column = sql_column.trim_end_matches(",").to_string();
}
sql_create = sql_create + &format!("({});", sql_column);
let result_create = executor.exec(&sql_create, vec![]).await;
match result_create {
Ok(_) => {}
Err(e) => {
if e.to_string().to_lowercase().contains("already") {
for (k, v) in &m {
let k = k.as_str().unwrap_or_default();
let mut id_key = "";
if k.eq("id") || v.as_str().unwrap_or_default() == "id" {
id_key = &PRIMARY_KEY;
}
let column_type = mapper.get_column_type(k, &v);
match executor
.exec(
&format!(
"alter table {} add {} {} {};",
name, k, column_type, id_key
),
vec![],
)
.await
{
Ok(_) => {}
Err(e) => {
debug!("ADD COLUMN fail={}", e);
continue;
}
}
}
return Ok(());
}
return Err(e);
}
}
Ok(())
}
_ => Err(Error::from("table not is an struct or map!")),
}
})
}
pub trait ColumnMapper: Sync + Send {
fn driver_type(&self) -> String;
fn get_column_type(&self, field: &str, v: &Value) -> String;
}