use drizzle_core::error::DrizzleError;
use drizzle_core::traits::ToSQL;
#[cfg(feature = "sqlite")]
use drizzle_sqlite::builder::{DeleteInitial, InsertInitial, SelectInitial, UpdateInitial};
#[cfg(feature = "sqlite")]
use drizzle_sqlite::traits::SQLiteTable;
use std::marker::PhantomData;
use turso::Row;
pub mod delete;
pub mod insert;
pub mod select;
pub mod update;
#[cfg(feature = "sqlite")]
use drizzle_sqlite::{
builder::{
self, QueryBuilder, delete::DeleteBuilder, insert::InsertBuilder, select::SelectBuilder,
update::UpdateBuilder,
},
connection::SQLiteTransactionType,
values::SQLiteValue,
};
#[derive(Debug)]
pub struct TransactionBuilder<'a, 'conn, Schema, Builder, State> {
transaction: &'a Transaction<'conn, Schema>,
builder: Builder,
_phantom: PhantomData<(Schema, State)>,
}
#[derive(Debug)]
pub struct Transaction<'conn, Schema = ()> {
tx: turso::transaction::Transaction<'conn>,
tx_type: SQLiteTransactionType,
_schema: PhantomData<Schema>,
}
impl<'conn, Schema> Transaction<'conn, Schema> {
pub(crate) fn new(
tx: turso::transaction::Transaction<'conn>,
tx_type: SQLiteTransactionType,
) -> Self {
Self {
tx,
tx_type,
_schema: PhantomData,
}
}
#[inline]
pub fn tx(&self) -> &turso::transaction::Transaction<'conn> {
&self.tx
}
#[inline]
pub fn tx_type(&self) -> SQLiteTransactionType {
self.tx_type
}
#[cfg(feature = "sqlite")]
pub fn select<'a, 'b, T>(
&'a self,
query: T,
) -> TransactionBuilder<'a, 'a, Schema, SelectBuilder<'b, Schema, SelectInitial>, SelectInitial>
where
T: ToSQL<'b, SQLiteValue<'b>>,
{
use drizzle_sqlite::builder::QueryBuilder;
let builder = QueryBuilder::new::<Schema>().select(query);
TransactionBuilder {
transaction: self,
builder,
_phantom: PhantomData,
}
}
#[cfg(feature = "sqlite")]
pub fn insert<'a, Table>(
&'a self,
table: Table,
) -> TransactionBuilder<
'a,
'a,
Schema,
InsertBuilder<'a, Schema, InsertInitial, Table>,
InsertInitial,
>
where
Table: SQLiteTable<'a>,
{
let builder = QueryBuilder::new::<Schema>().insert(table);
TransactionBuilder {
transaction: self,
builder,
_phantom: PhantomData,
}
}
#[cfg(feature = "sqlite")]
pub fn update<'a, Table>(
&'a self,
table: Table,
) -> TransactionBuilder<
'a,
'a,
Schema,
UpdateBuilder<'a, Schema, UpdateInitial, Table>,
UpdateInitial,
>
where
Table: SQLiteTable<'a>,
{
let builder = QueryBuilder::new::<Schema>().update(table);
TransactionBuilder {
transaction: self,
builder,
_phantom: PhantomData,
}
}
#[cfg(feature = "sqlite")]
pub fn delete<'a, T>(
&'a self,
table: T,
) -> TransactionBuilder<
'a,
'a,
Schema,
DeleteBuilder<'a, Schema, DeleteInitial, T>,
DeleteInitial,
>
where
T: SQLiteTable<'a>,
{
let builder = QueryBuilder::new::<Schema>().delete(table);
TransactionBuilder {
transaction: self,
builder,
_phantom: PhantomData,
}
}
pub async fn execute<'a, T>(&'a self, query: T) -> Result<u64, DrizzleError>
where
T: ToSQL<'a, SQLiteValue<'a>>,
{
let query = query.to_sql();
let sql = query.sql();
let params: Vec<turso::Value> = query.params().map(|p| p.into()).collect();
Ok(self.tx.execute(&sql, params).await?)
}
pub async fn all<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<Vec<R>>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let sql_str = sql.sql();
let params: Vec<turso::Value> = sql.params().map(|p| p.into()).collect();
let mut rows = self.tx.query(&sql_str, params).await?;
let mut results = Vec::new();
while let Some(row) = rows.next().await? {
let converted = R::try_from(&row).map_err(Into::into)?;
results.push(converted);
}
Ok(results)
}
pub async fn get<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let sql_str = sql.sql();
let params: Vec<turso::Value> = sql.params().map(|p| p.into()).collect();
let mut rows = self.tx.query(&sql_str, params).await?;
if let Some(row) = rows.next().await? {
R::try_from(&row).map_err(Into::into)
} else {
Err(DrizzleError::NotFound)
}
}
pub async fn commit(self) -> Result<(), DrizzleError> {
Ok(self.tx.commit().await?)
}
pub async fn rollback(self) -> Result<(), DrizzleError> {
Ok(self.tx.rollback().await?)
}
}
#[cfg(feature = "turso")]
impl<'a, 'conn, S, Schema, State, Table>
TransactionBuilder<'a, 'conn, S, QueryBuilder<'a, Schema, State, Table>, State>
where
State: builder::ExecutableState,
{
pub async fn execute(self) -> drizzle_core::error::Result<u64> {
let sql = self.builder.sql.sql();
let params: Vec<turso::Value> = self.builder.sql.params().map(|p| p.into()).collect();
Ok(self.transaction.tx.execute(&sql, params).await?)
}
pub async fn all<R>(self) -> drizzle_core::error::Result<Vec<R>>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
{
let sql = &self.builder.sql;
let sql_str = sql.sql();
let params: Vec<turso::Value> = sql.params().map(|p| p.into()).collect();
let mut rows = self.transaction.tx.query(&sql_str, params).await?;
let mut results = Vec::new();
while let Some(row) = rows.next().await? {
let converted = R::try_from(&row).map_err(Into::into)?;
results.push(converted);
}
Ok(results)
}
pub async fn get<R>(self) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r Row>,
for<'r> <R as TryFrom<&'r Row>>::Error: Into<DrizzleError>,
{
let sql = &self.builder.sql;
let sql_str = sql.sql();
let params: Vec<turso::Value> = sql.params().map(|p| p.into()).collect();
let mut rows = self.transaction.tx.query(&sql_str, params).await?;
if let Some(row) = rows.next().await? {
R::try_from(&row).map_err(Into::into)
} else {
Err(DrizzleError::NotFound)
}
}
}