use std::sync::Arc;
use tokio::sync::Mutex;
use crate::adapters::params::convert_params;
use crate::middleware::{ConversionMode, CustomDbRow, ResultSet, RowValues, SqlMiddlewareDbError};
use crate::types::StatementCacheMode;
use super::params::{Params as TursoParams, TursoParamsBuf};
#[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_with_cache_mode(
connection: turso::Connection,
sql: &str,
statement_cache_mode: StatementCacheMode,
) -> Result<Self, SqlMiddlewareDbError> {
let sql_arc = Arc::new(sql.to_owned());
let statement = match statement_cache_mode {
StatementCacheMode::Cached => connection.prepare_cached(sql).await,
StatementCacheMode::Uncached => connection.prepare(sql).await,
}
.map_err(|e| SqlMiddlewareDbError::ExecutionError(format!("Turso prepare error: {e}")))?;
let columns = statement.column_names();
Ok(Self {
_connection: connection,
statement: Arc::new(Mutex::new(statement)),
columns: Arc::new(columns),
sql: sql_arc,
})
}
#[must_use]
pub fn select(&self) -> TursoPreparedSelect<'_, '_> {
TursoPreparedSelect {
statement: self,
params: TursoPreparedParams::None,
}
}
#[must_use]
pub fn execute(&self) -> TursoPreparedExecute<'_, '_> {
TursoPreparedExecute {
statement: self,
params: TursoPreparedParams::None,
}
}
pub(crate) async fn query(
&self,
params: &[RowValues],
) -> Result<ResultSet, SqlMiddlewareDbError> {
let converted = convert_params::<TursoParams>(params, ConversionMode::Query)?;
self.query_driver_params(converted.0).await
}
pub(crate) async fn query_params(
&self,
params: &TursoParamsBuf,
) -> Result<ResultSet, SqlMiddlewareDbError> {
self.query_driver_params(params.to_params()).await
}
async fn query_driver_params(
&self,
params: turso::params::Params,
) -> Result<ResultSet, SqlMiddlewareDbError> {
let rows = {
let mut stmt = self.statement.lock().await;
stmt.query(params).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(crate) async fn query_optional(
&self,
params: &[RowValues],
) -> Result<Option<CustomDbRow>, SqlMiddlewareDbError> {
self.query(params).await.map(ResultSet::into_optional)
}
pub(crate) async fn query_optional_params(
&self,
params: &TursoParamsBuf,
) -> Result<Option<CustomDbRow>, SqlMiddlewareDbError> {
self.query_params(params)
.await
.map(ResultSet::into_optional)
}
pub(crate) async fn query_one(
&self,
params: &[RowValues],
) -> Result<CustomDbRow, SqlMiddlewareDbError> {
self.query(params).await?.into_one()
}
pub(crate) async fn query_one_params(
&self,
params: &TursoParamsBuf,
) -> Result<CustomDbRow, SqlMiddlewareDbError> {
self.query_params(params).await?.into_one()
}
pub(crate) async fn query_map_one<T, F>(
&self,
params: &[RowValues],
mapper: F,
) -> Result<T, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
self.query_map_optional(params, mapper)
.await?
.ok_or_else(|| SqlMiddlewareDbError::ExecutionError("query returned no rows".into()))
}
pub(crate) async fn query_map_one_params<T, F>(
&self,
params: &TursoParamsBuf,
mapper: F,
) -> Result<T, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
self.query_map_optional_params(params, mapper)
.await?
.ok_or_else(|| SqlMiddlewareDbError::ExecutionError("query returned no rows".into()))
}
pub(crate) async fn query_map_optional<T, F>(
&self,
params: &[RowValues],
mapper: F,
) -> Result<Option<T>, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
let converted = convert_params::<TursoParams>(params, ConversionMode::Query)?;
self.query_map_optional_driver_params(converted.0, mapper)
.await
}
pub(crate) async fn query_map_optional_params<T, F>(
&self,
params: &TursoParamsBuf,
mapper: F,
) -> Result<Option<T>, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
self.query_map_optional_driver_params(params.to_params(), mapper)
.await
}
async fn query_map_optional_driver_params<T, F>(
&self,
params: turso::params::Params,
mapper: F,
) -> Result<Option<T>, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
let rows = {
let mut stmt = self.statement.lock().await;
stmt.query(params).await.map_err(|e| {
SqlMiddlewareDbError::ExecutionError(format!("Turso prepared query error: {e}"))
})?
};
let result = crate::turso::query::query_map_optional(rows, mapper).await;
self.reset().await?;
result
}
pub(crate) async fn execute_values(
&self,
params: &[RowValues],
) -> Result<usize, SqlMiddlewareDbError> {
let converted = convert_params::<TursoParams>(params, ConversionMode::Execute)?;
self.execute_driver_params(converted.0).await
}
pub(crate) async fn execute_params(
&self,
params: &TursoParamsBuf,
) -> Result<usize, SqlMiddlewareDbError> {
self.execute_driver_params(params.to_params()).await
}
async fn execute_driver_params(
&self,
params: turso::params::Params,
) -> Result<usize, SqlMiddlewareDbError> {
let affected = {
let mut stmt = self.statement.lock().await;
let affected = stmt.execute(params).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}")))
}
}
pub struct TursoPreparedExecute<'stmt, 'params> {
statement: &'stmt TursoNonTxPreparedStatement,
params: TursoPreparedParams<'params>,
}
impl<'stmt, 'params> TursoPreparedExecute<'stmt, 'params> {
#[must_use]
pub fn params<'next>(self, params: &'next [RowValues]) -> TursoPreparedExecute<'stmt, 'next> {
TursoPreparedExecute {
statement: self.statement,
params: TursoPreparedParams::RowValues(params),
}
}
#[must_use]
pub fn params_buf<'next>(
self,
params: &'next TursoParamsBuf,
) -> TursoPreparedExecute<'stmt, 'next> {
TursoPreparedExecute {
statement: self.statement,
params: TursoPreparedParams::Buffer(params),
}
}
pub async fn run(self) -> Result<usize, SqlMiddlewareDbError> {
match self.params {
TursoPreparedParams::None => self.statement.execute_values(&[]).await,
TursoPreparedParams::RowValues(params) => self.statement.execute_values(params).await,
TursoPreparedParams::Buffer(params) => self.statement.execute_params(params).await,
}
}
}
enum TursoPreparedParams<'params> {
None,
RowValues(&'params [RowValues]),
Buffer(&'params TursoParamsBuf),
}
pub struct TursoPreparedSelect<'stmt, 'params> {
statement: &'stmt TursoNonTxPreparedStatement,
params: TursoPreparedParams<'params>,
}
impl<'stmt, 'params> TursoPreparedSelect<'stmt, 'params> {
#[must_use]
pub fn params<'next>(self, params: &'next [RowValues]) -> TursoPreparedSelect<'stmt, 'next> {
TursoPreparedSelect {
statement: self.statement,
params: TursoPreparedParams::RowValues(params),
}
}
#[must_use]
pub fn params_buf<'next>(
self,
params: &'next TursoParamsBuf,
) -> TursoPreparedSelect<'stmt, 'next> {
TursoPreparedSelect {
statement: self.statement,
params: TursoPreparedParams::Buffer(params),
}
}
pub async fn all(self) -> Result<ResultSet, SqlMiddlewareDbError> {
match self.params {
TursoPreparedParams::None => self.statement.query(&[]).await,
TursoPreparedParams::RowValues(params) => self.statement.query(params).await,
TursoPreparedParams::Buffer(params) => self.statement.query_params(params).await,
}
}
pub async fn optional(self) -> Result<Option<CustomDbRow>, SqlMiddlewareDbError> {
match self.params {
TursoPreparedParams::None => self.statement.query_optional(&[]).await,
TursoPreparedParams::RowValues(params) => self.statement.query_optional(params).await,
TursoPreparedParams::Buffer(params) => {
self.statement.query_optional_params(params).await
}
}
}
pub async fn one(self) -> Result<CustomDbRow, SqlMiddlewareDbError> {
match self.params {
TursoPreparedParams::None => self.statement.query_one(&[]).await,
TursoPreparedParams::RowValues(params) => self.statement.query_one(params).await,
TursoPreparedParams::Buffer(params) => self.statement.query_one_params(params).await,
}
}
pub async fn map_one<T, F>(self, mapper: F) -> Result<T, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
match self.params {
TursoPreparedParams::None => self.statement.query_map_one(&[], mapper).await,
TursoPreparedParams::RowValues(params) => {
self.statement.query_map_one(params, mapper).await
}
TursoPreparedParams::Buffer(params) => {
self.statement.query_map_one_params(params, mapper).await
}
}
}
pub async fn map_optional<T, F>(self, mapper: F) -> Result<Option<T>, SqlMiddlewareDbError>
where
F: FnOnce(&turso::Row) -> Result<T, SqlMiddlewareDbError>,
{
match self.params {
TursoPreparedParams::None => self.statement.query_map_optional(&[], mapper).await,
TursoPreparedParams::RowValues(params) => {
self.statement.query_map_optional(params, mapper).await
}
TursoPreparedParams::Buffer(params) => {
self.statement
.query_map_optional_params(params, mapper)
.await
}
}
}
}