use tokio::runtime::{Builder, Runtime};
use crate::command::Command;
use crate::config::Config;
use crate::dataset::DataSet;
use crate::error::{Error, Result};
use crate::row::Row;
use crate::transaction::IsolationLevel;
use crate::value::{FromSql, ToSql};
fn build_runtime() -> Result<Runtime> {
Builder::new_multi_thread()
.worker_threads(1)
.enable_all()
.thread_name("tdsql-connection")
.build()
.map_err(Error::Io)
}
pub struct Client {
runtime: Runtime,
inner: crate::Client,
}
impl std::fmt::Debug for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("blocking::Client")
.field("inner", &self.inner)
.finish()
}
}
impl Client {
pub fn connect(config: &Config) -> Result<Self> {
if tokio::runtime::Handle::try_current().is_ok() {
return Err(Error::BlockingInAsync);
}
let runtime = build_runtime()?;
let inner = runtime.block_on(crate::Client::connect(config))?;
Ok(Self { runtime, inner })
}
pub fn connect_str(connection_string: &str) -> Result<Self> {
Self::connect(&Config::from_ado_string(connection_string))
}
pub fn query(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Vec<Row>> {
self.runtime.block_on(self.inner.query(sql, params))
}
pub fn query_one(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Row> {
self.runtime.block_on(self.inner.query_one(sql, params))
}
pub fn query_opt(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Option<Row>> {
self.runtime.block_on(self.inner.query_opt(sql, params))
}
pub fn query_scalar<T: FromSql>(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<T> {
self.runtime.block_on(self.inner.query_scalar(sql, params))
}
pub fn execute(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<u64> {
self.runtime.block_on(self.inner.execute(sql, params))
}
pub fn batch(&mut self, sql: &str) -> Result<Vec<Row>> {
self.runtime.block_on(self.inner.batch(sql))
}
pub fn batch_dataset(&mut self, sql: &str) -> Result<DataSet> {
self.runtime.block_on(self.inner.batch_dataset(sql))
}
pub fn query_dataset(&mut self, command: &Command) -> Result<DataSet> {
self.runtime.block_on(self.inner.query_dataset(command))
}
pub fn execute_command(&mut self, command: &Command) -> Result<u64> {
self.runtime.block_on(self.inner.execute_command(command))
}
pub fn transaction(&mut self) -> Result<Transaction<'_>> {
self.transaction_with_isolation(IsolationLevel::Unspecified)
}
pub fn transaction_with_isolation(&mut self, level: IsolationLevel) -> Result<Transaction<'_>> {
let Self { runtime, inner } = self;
let tx = runtime.block_on(inner.transaction_with_isolation(level))?;
Ok(Transaction { runtime, inner: tx })
}
pub fn close(self) -> Result<()> {
let Self { runtime, inner } = self;
runtime.block_on(inner.close())
}
}
pub struct Transaction<'a> {
runtime: &'a Runtime,
inner: crate::Transaction<'a>,
}
impl std::fmt::Debug for Transaction<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("blocking::Transaction")
.field("inner", &self.inner)
.finish()
}
}
impl Transaction<'_> {
pub fn commit(self) -> Result<()> {
let Self { runtime, inner } = self;
runtime.block_on(inner.commit())
}
pub fn rollback(self) -> Result<()> {
let Self { runtime, inner } = self;
runtime.block_on(inner.rollback())
}
pub fn transaction(&mut self) -> Result<Transaction<'_>> {
let Self { runtime, inner } = self;
let tx = runtime.block_on(inner.transaction())?;
Ok(Transaction { runtime, inner: tx })
}
pub fn savepoint(&mut self, name: impl Into<String>) -> Result<Transaction<'_>> {
let Self { runtime, inner } = self;
let tx = runtime.block_on(inner.savepoint(name))?;
Ok(Transaction { runtime, inner: tx })
}
pub fn query(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Vec<Row>> {
self.runtime.block_on(self.inner.query(sql, params))
}
pub fn query_one(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Row> {
self.runtime.block_on(self.inner.query_one(sql, params))
}
pub fn query_opt(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<Option<Row>> {
self.runtime.block_on(self.inner.query_opt(sql, params))
}
pub fn query_scalar<T: FromSql>(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<T> {
self.runtime.block_on(self.inner.query_scalar(sql, params))
}
pub fn execute(&mut self, sql: &str, params: &[&dyn ToSql]) -> Result<u64> {
self.runtime.block_on(self.inner.execute(sql, params))
}
pub fn batch(&mut self, sql: &str) -> Result<Vec<Row>> {
self.runtime.block_on(self.inner.batch(sql))
}
pub fn batch_dataset(&mut self, sql: &str) -> Result<DataSet> {
self.runtime.block_on(self.inner.batch_dataset(sql))
}
pub fn query_dataset(&mut self, command: &Command) -> Result<DataSet> {
self.runtime.block_on(self.inner.query_dataset(command))
}
pub fn execute_command(&mut self, command: &Command) -> Result<u64> {
self.runtime.block_on(self.inner.execute_command(command))
}
}