use crate::error::LrefResult;
use async_trait::async_trait;
use std::fmt;
#[derive(Debug, Clone)]
pub enum DbValue {
Null,
Bool(bool),
I16(i16),
I32(i32),
I64(i64),
F32(f32),
F64(f64),
String(String),
Bytes(Vec<u8>),
}
impl fmt::Display for DbValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DbValue::Null => write!(f, "NULL"),
DbValue::Bool(v) => write!(f, "{}", if *v { "TRUE" } else { "FALSE" }),
DbValue::I16(v) => write!(f, "{}", v),
DbValue::I32(v) => write!(f, "{}", v),
DbValue::I64(v) => write!(f, "{}", v),
DbValue::F32(v) => write!(f, "{}", v),
DbValue::F64(v) => write!(f, "{}", v),
DbValue::String(v) => write!(f, "'{}'", v.replace('\'', "''")),
DbValue::Bytes(v) => write!(f, "{}", hex::encode(v)),
}
}
}
mod hex {
pub fn encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
}
impl From<i32> for DbValue {
fn from(v: i32) -> Self { DbValue::I32(v) }
}
impl From<i64> for DbValue {
fn from(v: i64) -> Self { DbValue::I64(v) }
}
impl From<String> for DbValue {
fn from(v: String) -> Self { DbValue::String(v) }
}
impl From<&str> for DbValue {
fn from(v: &str) -> Self { DbValue::String(v.to_string()) }
}
impl From<bool> for DbValue {
fn from(v: bool) -> Self { DbValue::Bool(v) }
}
impl From<f64> for DbValue {
fn from(v: f64) -> Self { DbValue::F64(v) }
}
impl From<f32> for DbValue {
fn from(v: f32) -> Self { DbValue::F32(v) }
}
impl From<i16> for DbValue {
fn from(v: i16) -> Self { DbValue::I16(v) }
}
impl From<Vec<u8>> for DbValue {
fn from(v: Vec<u8>) -> Self { DbValue::Bytes(v) }
}
impl<T> From<Option<T>> for DbValue
where
T: Into<DbValue>,
{
fn from(v: Option<T>) -> Self {
match v {
Some(val) => val.into(),
None => DbValue::Null,
}
}
}
pub trait SqlGenerator: Send + Sync {
fn select(&self, table: &str, columns: &[&str]) -> String;
fn insert(&self, table: &str, columns: &[&str], returning: bool) -> String;
fn update(&self, table: &str, set_columns: &[&str], where_clause: &str) -> String;
fn delete(&self, table: &str, where_clause: &str) -> String;
fn create_table(&self, table: &str, columns: &[(String, String)]) -> String;
fn drop_table(&self, table: &str) -> String;
fn pagination(&self, skip: Option<usize>, take: Option<usize>) -> String;
fn parameter_placeholder(&self, index: usize) -> String;
fn quote_identifier(&self, identifier: &str) -> String;
fn auto_increment_syntax(&self) -> &'static str;
}
#[async_trait]
pub trait AsyncConnection: Send + Sync {
async fn execute(&mut self, sql: &str, params: &[DbValue]) -> LrefResult<u64>;
async fn query(&mut self, sql: &str, params: &[DbValue]) -> LrefResult<Vec<Vec<String>>>;
async fn begin_transaction(&mut self) -> LrefResult<()>;
async fn commit_transaction(&mut self) -> LrefResult<()>;
async fn rollback_transaction(&mut self) -> LrefResult<()>;
}
#[async_trait]
pub trait DatabaseProvider: Send + Sync {
fn sql_generator(&self) -> Box<dyn SqlGenerator>;
async fn get_connection(&self) -> LrefResult<Box<dyn AsyncConnection>>;
async fn execute_migration_command(&self, sql: &str) -> LrefResult<()>;
fn name(&self) -> &str;
}