use crate::errors::{AkitaError, Result};
use crate::{database_err, tokio_err};
use tiberius::ToSql;
use tokio::runtime::Runtime;
use tokio_util::compat::{Compat, TokioAsyncReadCompatExt};
pub struct SyncMssqlClient {
inner: tokio::sync::Mutex<tiberius::Client<Compat<tokio::net::TcpStream>>>,
runtime: Runtime,
}
impl SyncMssqlClient {
pub fn connect(config: tiberius::Config) -> Result<Self> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.map_err(|e| tokio_err!(format!("Failed to create runtime: {}", e)))?;
let client = runtime.block_on(async {
let tcp = tokio::net::TcpStream::connect(config.get_addr())
.await
.map_err(|e| tokio_err!(format!("TCP connection failed: {}", e)))?;
tcp.set_nodelay(true)
.map_err(|e| tokio_err!(format!("Failed to set TCP no delay: {}", e)))?;
let compat_tcp = tcp.compat();
tiberius::Client::connect(config, compat_tcp)
.await
.map_err(|e| database_err!(format!("Database connection failed: {}", e)))
})?;
Ok(Self {
inner: tokio::sync::Mutex::new(client),
runtime,
})
}
pub fn query(&self, sql: &str, params: &[&dyn ToSql]) -> Result<Vec<tiberius::Row>> {
let mut client = self.runtime.block_on(async { self.inner.lock().await });
self.runtime.block_on(async {
let stream = client
.query(sql, params)
.await
.map_err(|e| database_err!(format!("Query failed: {}", e)))?;
let rows: Vec<tiberius::Row> = stream
.into_first_result()
.await
.map_err(|e| database_err!(format!("Failed to get result: {}", e)))?;
Ok(rows)
})
}
pub fn simple_query(&self, sql: &str) -> Result<Vec<tiberius::Row>> {
let mut client = self.runtime.block_on(async { self.inner.lock().await });
self.runtime.block_on(async {
let stream = client
.simple_query(sql)
.await
.map_err(|e| database_err!(format!("Simple Query failed: {}", e)))?;
let rows: Vec<tiberius::Row> = stream
.into_first_result()
.await
.map_err(|e| database_err!(format!("Failed to get result: {}", e)))?;
Ok(rows)
})
}
pub fn execute(&self, sql: &str, params: &[&dyn ToSql]) -> Result<u64> {
let mut client = self.runtime.block_on(async { self.inner.lock().await });
self.runtime.block_on(async {
let result = client
.execute(sql, params)
.await
.map_err(|e| database_err!(format!("Execute failed: {}", e)))?;
Ok(result.total())
})
}
}