use async_trait::async_trait;
use sqlx::database::HasArguments;
use sqlx::{Executor, IntoArguments};
use crate::bind::Bind;
use crate::query::{Query, QueryError};
use crate::runtime::sql;
use crate::schema::Table;
use crate::{Error, ForeignKey, Result};
#[async_trait]
pub trait RefersTo<Other>
where
Self: Table + Bind,
Other: Table + Bind + Unpin + Sync,
{
const FOREIGN_KEY: ForeignKey<Self>;
async fn resolve<'e, E>(&self, executor: E) -> Result<Other>
where
E: Executor<'e, Database = crate::Driver>,
for<'q> <crate::Driver as HasArguments<'q>>::Arguments:
IntoArguments<'q, crate::Driver> + Send,
{
let Query { builder, .. } = sql::select::<Other>();
let mut query = sqlx::query_as(builder.sql());
let fk = Self::FOREIGN_KEY.as_col();
query = self.bind(&fk, query).unwrap();
query
.persistent(false)
.fetch_one(executor)
.await
.map_err(QueryError::from)
.map_err(Error::Query)
}
}
#[async_trait]
pub trait ReferredBy<Other>
where
Self: Table + Bind + Unpin + Sync,
Other: Table + Bind + RefersTo<Self> + Unpin + Sync,
{
async fn resolve<'e, E>(&self, executor: E) -> Result<Vec<Other>>
where
E: Executor<'e, Database = crate::Driver>,
for<'q> <crate::Driver as HasArguments<'q>>::Arguments:
IntoArguments<'q, crate::Driver> + Send,
{
let Query { builder, .. } = sql::select_by::<Other>(Other::FOREIGN_KEY.as_col());
let mut query = sqlx::query_as(builder.sql());
let pk = Self::PRIMARY_KEY.as_col();
query = self.bind(&pk, query).unwrap();
query
.persistent(false)
.fetch_all(executor)
.await
.map_err(QueryError::from)
.map_err(Error::Query)
}
async fn resolve_by<'e, E>(pk: &Self::PrimaryKey, executor: E) -> Result<Vec<Other>>
where
E: Executor<'e, Database = crate::Driver>,
for<'q> <crate::Driver as HasArguments<'q>>::Arguments:
IntoArguments<'q, crate::Driver> + Send,
{
let Query { builder, .. } = sql::select_by::<Other>(Other::FOREIGN_KEY.as_col());
sqlx::query_as(builder.sql())
.bind(pk)
.persistent(false)
.fetch_all(executor)
.await
.map_err(QueryError::from)
.map_err(Error::Query)
}
async fn delete_all<'e, E>(
&self,
executor: E,
) -> Result<<crate::Driver as sqlx::Database>::QueryResult>
where
E: Executor<'e, Database = crate::Driver>,
for<'q> <crate::Driver as HasArguments<'q>>::Arguments:
IntoArguments<'q, crate::Driver> + Send,
{
let Query { builder, .. } = sql::delete_by::<Other>(Other::FOREIGN_KEY.as_col());
let mut query = sqlx::query(builder.sql());
let pk = Self::PRIMARY_KEY.as_col();
query = self.bind(&pk, query).unwrap();
query
.persistent(false)
.execute(executor)
.await
.map_err(QueryError::from)
.map_err(Error::Query)
}
}