use std::sync::Arc;
use tokio::sync::Mutex;
use crate::adapters::params::convert_params;
use crate::middleware::{ConversionMode, ResultSet, RowValues, SqlMiddlewareDbError};
use crate::query_utils::extract_column_names;
use super::params::Params as TursoParams;
#[derive(Clone)]
pub struct TursoNonTxPreparedStatement {
_connection: turso::Connection,
statement: Arc<Mutex<turso::Statement>>,
columns: Arc<Vec<String>>,
sql: Arc<String>,
}
impl std::fmt::Debug for TursoNonTxPreparedStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TursoNonTxPreparedStatement")
.field("_connection", &"<turso::Connection>")
.field("statement", &"<turso::Statement>")
.field("columns", &self.columns)
.field("sql", &self.sql)
.finish()
}
}
impl TursoNonTxPreparedStatement {
pub(crate) async fn prepare(
connection: turso::Connection,
sql: &str,
) -> Result<Self, SqlMiddlewareDbError> {
let sql_arc = Arc::new(sql.to_owned());
let statement = connection.prepare(sql).await.map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso prepare error: {e}"))
})?;
let columns = extract_column_names(statement.columns().iter(), |col| col.name());
Ok(Self {
_connection: connection,
statement: Arc::new(Mutex::new(statement)),
columns: Arc::new(columns),
sql: sql_arc,
})
}
pub async fn query(&self, params: &[RowValues]) -> Result<ResultSet, SqlMiddlewareDbError> {
let converted = convert_params::<TursoParams>(params, ConversionMode::Query)?;
let rows = {
let mut stmt = self.statement.lock().await;
stmt.query(converted.0).await.map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso prepared query error: {e}"))
})?
};
let result = crate::turso::query::build_result_set(rows, Some(self.columns.clone())).await;
self.reset().await?;
result
}
pub async fn execute(&self, params: &[RowValues]) -> Result<usize, SqlMiddlewareDbError> {
let converted = convert_params::<TursoParams>(params, ConversionMode::Execute)?;
let affected = {
let mut stmt = self.statement.lock().await;
let affected = stmt.execute(converted.0).await.map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso prepared execute error: {e}"))
})?;
stmt.reset().map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso reset error: {e}"))
})?;
affected
};
usize::try_from(affected).map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!(
"Turso affected rows conversion error: {e}"
))
})
}
#[must_use]
pub fn sql(&self) -> &str {
self.sql.as_str()
}
async fn reset(&self) -> Result<(), SqlMiddlewareDbError> {
let stmt = self.statement.lock().await;
stmt.reset().map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso reset error: {e}"))
})
}
}