use core::marker::PhantomData;
pub use async_trait::async_trait;
pub use schema::*;
pub use tokio_postgres::{self as postgres, *};
pub mod prelude {
pub use super::{Exec, Fetch, Table, TableHelper};
}
pub mod key;
pub mod schema;
pub mod untyped_key;
pub struct Statement<'a> {
pub code: &'static str,
pub vals: &'a [&'a (dyn types::ToSql + Sync)],
}
impl<'a> Statement<'a> {
#[doc(hidden)]
pub fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
Self { code, vals }
}
}
pub struct Query<'a, O: From<Row>> {
pub code: &'static str,
pub vals: &'a [&'a (dyn types::ToSql + Sync)],
_phantom: PhantomData<O>,
}
impl<'a, O: From<Row> + Send + Sync> Query<'a, O> {
#[doc(hidden)]
pub fn new(code: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
Self {
code,
vals,
_phantom: PhantomData,
}
}
pub async fn execute_on(self, client: &mut Client) -> Result<u64, Error> {
client.execute(self.code, self.vals).await
}
}
impl<'a, O: From<Row>> Query<'a, O> {
#[doc(hidden)]
pub fn casted<T: From<Row>>(self) -> Query<'a, T> {
Query {
code: self.code,
vals: self.vals,
_phantom: PhantomData,
}
}
}
#[async_trait]
pub trait Fetch {
async fn fetch<'a, O: From<row::Row> + Send + Sync>(
&self,
query: Query<'a, O>,
) -> Result<Vec<O>, Error>;
}
#[async_trait]
impl<C: GenericClient + Sync> Fetch for C {
async fn fetch<'a, O: From<Row> + Send + Sync>(
&self,
query: Query<'a, O>,
) -> Result<Vec<O>, Error> {
let res = self
.query(query.code, query.vals)
.await?
.into_iter()
.map(Into::into)
.collect();
Ok(res)
}
}
#[async_trait]
pub trait Exec {
async fn exec<'a>(&self, stmt: Statement<'a>) -> Result<u64, Error>;
}
#[async_trait]
impl<C: GenericClient + Sync> Exec for C {
async fn exec<'a>(&self, stmt: Statement<'a>) -> Result<u64, Error> {
self.execute(stmt.code, stmt.vals).await
}
}
pub struct WhereClause<'a> {
pub clause: &'static str,
pub vals: &'a [&'a (dyn types::ToSql + Sync)],
}
impl<'a> WhereClause<'a> {
#[doc(hidden)]
pub fn new(santa: &'static str, vals: &'a [&'a (dyn types::ToSql + Sync)]) -> Self {
Self {
clause: santa,
vals,
}
}
}
#[derive(Default, Debug, PartialEq, Eq, Clone)]
pub struct InsertOptions {
pub on_conflict_do_nothing: bool,
pub on_conflict_do_update: bool,
}
#[async_trait]
pub trait Table: From<Row> + Sync + Send {
fn key(&self) -> key::Key<Self>;
async fn fetch_by_key<C: postgres::GenericClient + Sync>(
key: key::Key<Self>,
client: &C,
) -> Result<Option<Self>, postgres::Error>;
async fn fetch_where<C: postgres::GenericClient + Sync>(
client: &C,
where_clause: WhereClause<'_>,
) -> Result<Vec<Self>, postgres::Error>;
async fn delete_by_key<C: postgres::GenericClient + Sync>(
key: key::Key<Self>,
client: &C,
) -> Result<u64, postgres::Error>;
async fn delete<C: postgres::GenericClient + Sync>(
&self,
client: &C,
) -> Result<u64, postgres::Error> {
Self::delete_by_key(self.key(), client).await
}
async fn insert<C: postgres::GenericClient + Sync>(
&self,
client: &C,
) -> Result<u64, postgres::Error>;
async fn update<C: postgres::GenericClient + Sync>(
&self,
client: &C,
) -> Result<u64, postgres::Error>;
async fn upsert<C: postgres::GenericClient + Sync>(
&self,
client: &C,
) -> Result<u64, postgres::Error>;
async fn create_table<C: postgres::GenericClient + Sync>(
client: &C,
) -> Result<(), postgres::Error>;
async fn bulk_insert<C: postgres::GenericClient + Sync>(
client: &C,
values: &[Self],
) -> Result<(), postgres::Error> {
Self::bulk_insert_opt(client, values, InsertOptions::default()).await
}
async fn bulk_insert_opt<C: postgres::GenericClient + Sync>(
client: &C,
values: &[Self],
options: InsertOptions,
) -> Result<(), postgres::Error>;
}
#[async_trait]
pub trait TableHelper<T: 'static + Table>: Sync + Send {
async fn delete_by_key(&self, key: key::Key<T>) -> Result<u64, postgres::Error>;
async fn delete(&self, record: T) -> Result<u64, postgres::Error> {
self.delete_by_key(record.key()).await
}
async fn insert(&self, record: &T) -> Result<u64, postgres::Error>;
async fn update(&self, record: &T) -> Result<u64, postgres::Error>;
async fn upsert(&self, record: &T) -> Result<u64, postgres::Error>;
async fn fetch_table(&self, where_clause: WhereClause<'_>) -> Result<Vec<T>, postgres::Error>;
async fn bulk_insert(&self, records: &[T]) -> Result<(), postgres::Error>;
}
#[async_trait]
impl<T: 'static + Table, C: GenericClient + Send + Sync> TableHelper<T> for C {
async fn delete_by_key(&self, key: key::Key<T>) -> Result<u64, postgres::Error> {
key.delete(self).await
}
async fn insert(&self, record: &T) -> Result<u64, postgres::Error> {
record.insert(self).await
}
async fn update(&self, record: &T) -> Result<u64, postgres::Error> {
record.update(self).await
}
async fn upsert(&self, record: &T) -> Result<u64, postgres::Error> {
record.upsert(self).await
}
async fn fetch_table(&self, where_clause: WhereClause<'_>) -> Result<Vec<T>, postgres::Error> {
T::fetch_where(self, where_clause).await
}
async fn bulk_insert(&self, records: &[T]) -> Result<(), postgres::Error> {
T::bulk_insert(self, records).await
}
}
#[derive(Debug)]
pub struct Ref<T: Table + std::fmt::Debug> {
pub fk: untyped_key::Key,
_phantom: PhantomData<T>,
}