use lexa_database::SGBD;
#[cfg(feature = "database-postgres")]
#[async_trait::async_trait]
pub trait ModelInterface {
type Entity: sqlb::HasFields
+ serde::Serialize
+ serde::de::DeserializeOwned
+ Sync
+ Send;
fn new(database: &super::services::postgres::PostgresService) -> Self
where
Self: Sized;
fn database(&self) -> &super::services::postgres::PostgresService;
fn table() -> &'static str;
fn fields() -> &'static [&'static str] {
<Self::Entity as sqlb::HasFields>::field_names()
}
async fn fetch_all<'c>(&self) -> Result<Vec<Self::Entity>, Error>
where
for<'r> <Self as ModelInterface>::Entity:
sqlx::FromRow<'r, sqlx::postgres::PgRow>,
<Self as ModelInterface>::Entity: Unpin,
{
let records: Vec<Self::Entity> = sqlb::select()
.columns(Self::fields())
.table(Self::table())
.fetch_all(self.database().pool())
.await?;
Ok(records)
}
async fn fetch_all_by_id(
&self,
id: impl ToString + Send + Sync,
) -> Result<Vec<Self::Entity>, Error>
where
for<'r> <Self as ModelInterface>::Entity:
sqlx::FromRow<'r, sqlx::postgres::PgRow>,
<Self as ModelInterface>::Entity: Unpin,
{
let records: Vec<Self::Entity> = sqlb::select()
.columns(Self::fields())
.table(Self::table())
.and_where_eq("id", id.to_string())
.fetch_all(self.database().pool())
.await?;
Ok(records)
}
async fn find_by_id(
&self,
id: impl ToString + Send + Sync,
) -> Result<Self::Entity, Error>
where
for<'r> <Self as ModelInterface>::Entity:
sqlx::FromRow<'r, sqlx::postgres::PgRow>,
<Self as ModelInterface>::Entity: Unpin,
{
let record: Self::Entity = sqlb::select()
.columns(Self::fields())
.table(Self::table())
.and_where_eq("id", id.to_string())
.limit(1)
.fetch_one(self.database().pool())
.await?;
Ok(record)
}
async fn create(
&self,
data: impl sqlb::HasFields + Send,
) -> Result<Self::Entity, Error>
where
for<'r> <Self as ModelInterface>::Entity:
sqlx::FromRow<'r, sqlx::postgres::PgRow>,
<Self as ModelInterface>::Entity: Unpin,
{
let record: Self::Entity = sqlb::insert()
.table(Self::table())
.data(data.all_fields())
.returning(Self::fields())
.fetch_one(self.database().pool())
.await?;
Ok(record)
}
async fn delete_by_id(
&self,
id: impl ToString + Send + Sync,
) -> Result<(), Error> {
sqlb::delete()
.table(Self::table())
.and_where_eq("id", id.to_string())
.exec(self.database().pool())
.await?;
Ok(())
}
async fn update_by_id(
&self,
id: impl ToString + Send + Sync,
data: impl sqlb::HasFields + Send,
) -> Result<Self::Entity, Error>
where
for<'r> <Self as ModelInterface>::Entity:
sqlx::FromRow<'r, sqlx::postgres::PgRow>,
<Self as ModelInterface>::Entity: Unpin,
{
let record: Self::Entity = sqlb::update()
.table(Self::table())
.data(data.all_fields())
.and_where_eq("id", id.to_string())
.returning(Self::fields())
.fetch_one(self.database().pool())
.await?;
Ok(record)
}
}
#[cfg(not(feature = "database-postgres"))]
pub trait ModelInterface {
type Entity: serde::Serialize + serde::de::DeserializeOwned + Sync + Send;
type Database;
fn new(database: Self::Database) -> Self
where
Self: Sized;
fn database(&self) -> &Self::Database;
fn table() -> &'static str;
}
#[derive(Debug)]
#[derive(thiserror::Error)]
pub enum Error {
#[error("{0}")]
Sqlx(#[from] sqlx::Error),
}