use std::collections::HashMap;
use std::future::Future;
use std::pin::Pin;
use hdbconnect_async::{Connection as HanaConn, HdbError};
use sz_orm_core::{Connection, DbError, QueryRows, Value};
pub struct SapHanaConnection {
conn: HanaConn,
}
fn map_err(e: HdbError) -> DbError {
DbError::QueryError(format!("SAP HANA: {e}"))
}
impl SapHanaConnection {
pub async fn connect(url: &str) -> Result<Self, DbError> {
let conn = HanaConn::new(url).await.map_err(map_err)?;
Ok(Self { conn })
}
}
impl Connection for SapHanaConnection {
fn execute<'a>(
&'a mut self,
sql: &'a str,
) -> Pin<Box<dyn Future<Output = Result<u64, DbError>> + Send + 'a>> {
Box::pin(async move {
let n = self.conn.dml(sql).await.map_err(map_err)?;
Ok(n as u64)
})
}
fn query<'a>(
&'a mut self,
sql: &'a str,
) -> Pin<Box<dyn Future<Output = Result<QueryRows, DbError>> + Send + 'a>> {
Box::pin(async move {
let rs = self.conn.query(sql).await.map_err(map_err)?;
let rows: Vec<HashMap<String, String>> = rs.try_into().await.map_err(map_err)?;
Ok(rows
.into_iter()
.map(|m| m.into_iter().map(|(k, v)| (k, Value::String(v))).collect())
.collect())
})
}
fn begin_transaction<'a>(
&'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), DbError>> + Send + 'a>> {
Box::pin(async move {
self.conn.set_auto_commit(false).await;
Ok(())
})
}
fn commit<'a>(
&'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), DbError>> + Send + 'a>> {
Box::pin(async move {
self.conn.commit().await.map_err(map_err)?;
self.conn.set_auto_commit(true).await;
Ok(())
})
}
fn rollback<'a>(
&'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), DbError>> + Send + 'a>> {
Box::pin(async move {
self.conn.rollback().await.map_err(map_err)?;
self.conn.set_auto_commit(true).await;
Ok(())
})
}
fn is_connected(&self) -> bool {
true
}
fn ping<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
Box::pin(async move { !self.conn.is_broken().await })
}
fn close<'a>(
&'a mut self,
) -> Pin<Box<dyn Future<Output = Result<(), DbError>> + Send + 'a>> {
Box::pin(async move {
Ok(())
})
}
}