1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
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 ";
/// create table if not exists, add column if not exists
/// ```rust
/// use rbatis::executor::{Executor, RBatisConnExecutor};
/// use rbatis::RBatis;
/// use rbatis::table_sync::{MysqlTableMapper, SqliteTableMapper, sync};
/// use rbs::to_value;
///
/// /// let rb = RBatis::new();
/// /// let conn = rb.acquire().await;
/// pub async fn do_sync_table(conn: &dyn Executor){
/// let map = rbs::to_value!{
/// "id":"TEXT",
/// "name":"TEXT",
/// };
/// let _ = sync(conn, &SqliteTableMapper{},map,"user").await;
/// }
///
/// ```
///
/// sync table struct
/// ```rust
/// use rbatis::executor::{Executor, RBatisConnExecutor};
/// use rbatis::RBatis;
/// use rbatis::table_sync::{MysqlTableMapper, SqliteTableMapper, sync};
/// use rbs::to_value;
///
/// #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
/// pub struct User{
/// pub id:String,
/// pub name: Option<String>
/// }
///
/// /// let rb = RBatis::new();
/// /// let conn = rb.acquire().await;
/// pub async fn do_sync_table(conn: &dyn Executor){
/// let table = User{id: "".to_string(), name: Some("".to_string())};
/// let _ = sync(conn, &SqliteTableMapper{},to_value!(table),"user").await;
/// }
///
/// ```
///
/// sync table struct (custom string column type)
/// ```rust
/// use rbatis::executor::Executor;
/// use rbatis::RBatis;
/// use rbatis::table_sync::{MysqlTableMapper, sync};
/// use rbs::to_value;
///
/// #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
/// pub struct User{
/// pub id:String,
/// pub name: Option<String>
/// }
///
/// pub async fn do_sync_table_mysql(conn: &dyn Executor){
/// let table = User{id: "".to_string(), name: Some("VARCHAR(50)".to_string())};
/// let _ = sync(conn, &MysqlTableMapper{},to_value!(table),"user").await;
/// }
/// ```
pub fn sync<'a>(
executor: &'a dyn Executor,
mapper: &'a dyn ColumMapper,
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 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 = mapper.get_column(k, &v);
sql_column.push_str(k);
sql_column.push_str(" ");
sql_column.push_str(column_type.as_str());
if column_type.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") {
//TODO have any better way do not Repeated add and compatibility with most databases
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;
}
match executor
.exec(
&format!(
"alter table {} add {} {} {};",
name,
k,
mapper.get_column(k, &v),
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 ColumMapper: Sync + Send {
fn get_column(&self, column: &str, v: &Value) -> String;
}