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 rusqlite::params_from_iter;
use std::marker::PhantomData;
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: rusqlite::Transaction<'conn>,
tx_type: SQLiteTransactionType,
_schema: PhantomData<Schema>,
}
impl<'conn, Schema> Transaction<'conn, Schema> {
pub(crate) fn new(tx: rusqlite::Transaction<'conn>, tx_type: SQLiteTransactionType) -> Self {
Self {
tx,
tx_type,
_schema: PhantomData,
}
}
#[inline]
pub fn inner(&self) -> &rusqlite::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,
'conn,
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,
'conn,
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,
'conn,
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,
'conn,
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 fn execute<'a, T>(&'a self, query: T) -> rusqlite::Result<usize>
where
T: ToSQL<'a, SQLiteValue<'a>>,
{
let query = query.to_sql();
let sql = query.sql();
let params = query.params();
self.tx.execute(&sql, params_from_iter(params))
}
pub fn all<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<Vec<R>>
where
R: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let sql_str = sql.sql();
let params = sql.params();
let mut stmt = self
.tx
.prepare(&sql_str)
.map_err(|e| DrizzleError::Other(e.to_string().into()))?;
let rows = stmt.query_map(params_from_iter(params), |row| {
Ok(R::try_from(row).map_err(Into::into))
})?;
let mut results = Vec::new();
for row in rows {
results.push(row??);
}
Ok(results)
}
pub fn get<'a, T, R>(&'a self, query: T) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
T: ToSQL<'a, SQLiteValue<'a>>,
{
let sql = query.to_sql();
let sql_str = sql.sql();
let params = sql.params();
let mut stmt = self.tx.prepare(&sql_str)?;
stmt.query_row(params_from_iter(params), |row| {
Ok(R::try_from(row).map_err(Into::into))
})?
}
pub fn commit(self) -> rusqlite::Result<()> {
self.tx.commit()
}
pub fn rollback(self) -> rusqlite::Result<()> {
self.tx.rollback()
}
}
#[cfg(feature = "rusqlite")]
impl<'a, 'conn, S, Schema, State, Table>
TransactionBuilder<'a, 'conn, S, QueryBuilder<'a, Schema, State, Table>, State>
where
State: builder::ExecutableState,
{
pub fn execute(self) -> drizzle_core::error::Result<usize> {
let sql = self.builder.sql.sql();
let params = self.builder.sql.params();
Ok(self
.transaction
.tx
.execute(&sql, params_from_iter(params))?)
}
pub fn all<R>(self) -> drizzle_core::error::Result<Vec<R>>
where
R: for<'r> TryFrom<&'r ::rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r ::rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
{
let sql = &self.builder.sql;
let sql_str = sql.sql();
let params = sql.params();
let mut stmt = self
.transaction
.tx
.prepare(&sql_str)
.map_err(|e| DrizzleError::Other(e.to_string().into()))?;
let rows = stmt
.query_map(params_from_iter(params), |row| {
Ok(R::try_from(row).map_err(Into::into))
})
.map_err(|e| DrizzleError::Other(e.to_string().into()))?;
let mut results = Vec::new();
for row in rows {
results.push(row??);
}
Ok(results)
}
pub fn get<R>(self) -> drizzle_core::error::Result<R>
where
R: for<'r> TryFrom<&'r rusqlite::Row<'r>>,
for<'r> <R as TryFrom<&'r rusqlite::Row<'r>>>::Error:
Into<drizzle_core::error::DrizzleError>,
{
let sql = &self.builder.sql;
let sql_str = sql.sql();
let params = sql.params();
let mut stmt = self.transaction.tx.prepare(&sql_str)?;
stmt.query_row(params_from_iter(params), |row| {
Ok(R::try_from(row).map_err(Into::into))
})?
}
}