#![warn(missing_docs)]
use sqlx::Executor;
#[cfg(feature = "mysql")]
use sqlx::MySqlPool;
#[cfg(feature = "postgres")]
use sqlx::PgPool;
#[cfg(feature = "sqlite")]
use sqlx::SqlitePool;
use std::{fmt::Debug, sync::Arc};
pub mod error;
use crate::{
database::error::DatabaseError,
dialects::get_dialect,
operations::{
delete::Delete,
insert::{Insert, InsertMany},
query::Query,
update::Update,
},
row::Row,
schema::{ColumnInfo, Schema, Select, UpdateTrait},
table::get_all_tables,
};
pub struct Database {
#[cfg(feature = "mysql")]
pub(crate) connection: Arc<MySqlPool>,
#[cfg(feature = "postgres")]
pub(crate) connection: Arc<PgPool>,
#[cfg(feature = "sqlite")]
pub(crate) connection: Arc<SqlitePool>,
}
impl Database {
pub fn query<T: Schema + Debug, S: Select + Debug>(&self) -> Query<T, S> {
Query::new(Arc::clone(&self.connection))
}
pub fn insert<T: Schema + Debug>(&self, data: T) -> Insert<T> {
Insert::new(data, Arc::clone(&self.connection))
}
pub fn delete<T: Schema + Debug>(&self) -> Delete<T> {
Delete::new(Arc::clone(&self.connection))
}
pub fn update<T: Schema + Debug, U: UpdateTrait + Debug>(&self) -> Update<T, U> {
Update::new(Arc::clone(&self.connection))
}
pub fn insert_many<T: Schema + Debug, I>(&self, data: I) -> InsertMany<T>
where
I: IntoIterator<Item = T>,
{
InsertMany::new(data.into_iter().collect(), Arc::clone(&self.connection))
}
pub async fn sql<T: Schema + Debug>(&self, sql: &str) -> Result<Vec<Row<T>>, DatabaseError> {
let conn = self.connection.acquire().await;
if let Err(e) = conn {
return Err(DatabaseError::ConnectionError(e));
}
let mut conn = conn.unwrap();
let rows = conn.fetch_all(sql).await;
if let Err(e) = rows {
return Err(DatabaseError::QueryError(e.to_string()));
}
let rows = rows.unwrap();
#[cfg(feature = "mysql")]
let rows = Row::from_mysql_row(rows, None);
#[cfg(feature = "postgres")]
let rows = Row::from_postgres_row(rows, None);
#[cfg(feature = "sqlite")]
let rows = Row::from_sqlite_row(rows, None);
Ok(rows)
}
pub async fn register_table<T: Schema>(&self) -> Result<(), DatabaseError> {
T::ensure_registered();
let sql = Database::generate_migration_sql();
for stmt in sql.split(';').map(str::trim).filter(|s| !s.is_empty()) {
sqlx::query(stmt)
.execute(&*self.connection)
.await
.map_err(|e| DatabaseError::ExecutionError(e.to_string()))?;
}
Ok(())
}
pub(crate) fn generate_migration_sql() -> String {
let tables = get_all_tables();
#[allow(unused_mut)]
let mut statements: Vec<String> =
tables.iter().map(|table| table.to_create_sql()).collect();
let sql = statements.join("\n\n");
get_dialect().adapt_sql(sql)
}
pub fn get_table_info<'a>(table_name: &str) -> Option<Vec<ColumnInfo<'a>>> {
for table in get_all_tables() {
if table.table_name() == table_name {
let columns = table.get_columns();
return Some(columns);
}
}
None
}
pub fn list_tables() -> Vec<String> {
let tables = get_all_tables();
tables
.iter()
.map(|table| table.table_name().to_string())
.collect()
}
pub async fn connect(url: &str) -> Result<Database, DatabaseError> {
#[cfg(feature = "mysql")]
let conn = MySqlPool::connect(url)
.await
.map_err(|e| DatabaseError::ConnectionError(e))?;
#[cfg(feature = "postgres")]
let conn = PgPool::connect(url)
.await
.map_err(|e| DatabaseError::ConnectionError(e))?;
#[cfg(feature = "sqlite")]
let conn = SqlitePool::connect(url)
.await
.map_err(|e| DatabaseError::ConnectionError(e))?;
Ok(Database {
connection: Arc::new(conn),
})
}
}