use super::query::{Arg, builder, condition::Kwargs};
use super::{Connection, PLACEHOLDER};
use crate::{Error, FutureResult, utils};
use serde::Serialize;
#[async_trait::async_trait]
pub trait Model {
const UP: &'static str;
const DOWN: &'static str;
const NAME: &'static str;
const PK: &'static str;
fn up(conn: &'_ Connection) -> FutureResult<'_, ()>
where
Self: Sized,
{
Box::pin(async move {
#[cfg(debug_assertions)]
{
let formatted_sql = sqlformat::format(
Self::UP,
&sqlformat::QueryParams::None,
&sqlformat::FormatOptions::default(),
);
println!("{formatted_sql}");
}
#[cfg(not(feature = "turso"))]
sqlx::query(Self::UP).execute(conn).await?;
#[cfg(feature = "turso")]
conn.execute(Self::UP, ()).await?;
Ok(())
})
}
fn down(conn: &'_ Connection) -> FutureResult<'_, ()>
where
Self: Sized,
{
Box::pin(async move {
#[cfg(debug_assertions)]
{
let formatted_sql = sqlformat::format(
Self::DOWN,
&sqlformat::QueryParams::None,
&sqlformat::FormatOptions::default(),
);
println!("{formatted_sql}");
}
#[cfg(not(feature = "turso"))]
sqlx::query(Self::DOWN).execute(conn).await?;
#[cfg(feature = "turso")]
conn.execute(Self::DOWN, ()).await?;
Ok(())
})
}
async fn save(&self, conn: &Connection) -> Result<(), Error>
where
Self: Sized;
async fn create(kw: Vec<Kwargs>, conn: &Connection) -> Result<(), Error>
where
Self: Sized,
{
let insert_query = builder::to_insert_query(kw);
let query = format!(
"insert into {name} ({fields}) values ({placeholders});",
name = Self::NAME,
fields = insert_query.fields,
placeholders = insert_query.placeholders,
);
#[cfg(not(feature = "turso"))]
{
let mut stream = sqlx::query(&query);
binds!(insert_query.args.iter(), stream);
stream.execute(conn).await?;
}
#[cfg(feature = "turso")]
{
let params = binds!(insert_query.args.iter());
conn.execute(&query, params).await?;
}
Ok(())
}
async fn update(&self, conn: &Connection) -> Result<(), Error>
where
Self: Sized;
async fn set<T: Serialize + Clone + Send + Sync>(
id: T,
kw: Vec<Kwargs>,
conn: &Connection,
) -> Result<(), Error> {
let mut update_query = builder::to_update_query(kw);
update_query.args = update_query
.args
.into_iter()
.chain([Arg {
value: serde_json::json!(id.clone()).to_string(),
ty: utils::get_type_name(id).to_string(),
}])
.collect();
let index_id = update_query.args.len();
let query = format!(
"update {name} set {placeholders} where {id}={PLACEHOLDER}{index_id};",
id = Self::PK,
name = Self::NAME,
placeholders = update_query.placeholders,
);
#[cfg(not(feature = "turso"))]
{
let mut stream = sqlx::query(&query);
binds!(update_query.args, stream);
stream.execute(conn).await?;
}
#[cfg(feature = "turso")]
{
let params = binds!(update_query.args.iter());
conn.execute(&query, params).await?;
}
Ok(())
}
async fn delete(&self, conn: &Connection) -> Result<(), Error>
where
Self: Sized;
#[cfg(not(feature = "turso"))]
async fn all(conn: &Connection) -> Result<Vec<Self>, Error>
where
Self: Sized + Unpin + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Clone,
{
let query = format!("select * from {name}", name = Self::NAME);
Ok(sqlx::query_as::<_, Self>(&query).fetch_all(conn).await?)
}
#[cfg(feature = "turso")]
async fn all(conn: &Connection) -> Result<Vec<Self>, Error>
where
Self: Sized + for<'de> serde::Deserialize<'de>,
{
let query = format!("select * from {name}", name = Self::NAME);
let rows = conn.query(&query, ()).await?;
let results = utils::libsql_from_row(rows).await?;
Ok(results)
}
#[cfg(not(feature = "turso"))]
async fn filter(kw: Vec<Kwargs>, conn: &Connection) -> Result<Vec<Self>, Error>
where
Self: Sized + Unpin + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Clone,
{
let select_query = builder::to_select_query(kw);
let query = format!(
"SELECT * FROM {name} WHERE {placeholders};",
name = Self::NAME,
placeholders = select_query.placeholders,
);
let mut stream = sqlx::query_as::<_, Self>(&query);
binds!(select_query.args, stream);
Ok(stream.fetch_all(conn).await?)
}
#[cfg(feature = "turso")]
async fn filter(kw: Vec<Kwargs>, conn: &Connection) -> Result<Vec<Self>, Error>
where
Self: Sized + for<'de> serde::Deserialize<'de>,
{
let select_query = builder::to_select_query(kw);
let query = format!(
"SELECT * FROM {name} WHERE {placeholders};",
name = Self::NAME,
placeholders = select_query.placeholders,
);
let params = binds!(select_query.args.iter());
let rows = conn.query(&query, params).await?;
let results = utils::libsql_from_row(rows).await?;
Ok(results)
}
#[cfg(not(feature = "turso"))]
async fn get(kw: Vec<Kwargs>, conn: &Connection) -> Result<Option<Self>, Error>
where
Self: Sized + Unpin + for<'r> sqlx::FromRow<'r, sqlx::any::AnyRow> + Clone,
{
Ok(Self::filter(kw, conn).await?.first().cloned())
}
#[cfg(feature = "turso")]
async fn get(kw: Vec<Kwargs>, conn: &Connection) -> Result<Option<Self>, Error>
where
Self: Sized + Clone + for<'de> serde::Deserialize<'de>,
{
Ok(Self::filter(kw, conn).await?.first().cloned())
}
async fn count(conn: &Connection) -> Result<i64, Error>
where
Self: Sized,
{
let query = format!("select count(*) from {name}", name = Self::NAME);
#[cfg(not(feature = "turso"))]
{
let slf = sqlx::query(&query).fetch_one(conn).await?;
Ok(sqlx::Row::try_get(&slf, 0)?)
}
#[cfg(feature = "turso")]
{
let row = conn
.query(&query, ())
.await?
.next()
.await?
.ok_or("no rows returned")?;
Ok(row.get(0)?)
}
}
}
#[async_trait::async_trait]
pub trait Delete {
async fn delete(&self, conn: &Connection) -> Result<(), Error>;
}
#[async_trait::async_trait]
impl<T> Delete for Vec<T>
where
T: Model + Sync,
{
async fn delete(&self, conn: &Connection) -> Result<(), Error> {
let query = format!("delete from {name}", name = T::NAME);
#[cfg(not(feature = "turso"))]
sqlx::query(&query).execute(conn).await?;
#[cfg(feature = "turso")]
conn.execute(&query, ()).await?;
Ok(())
}
}