pub mod pg;
pub mod query;
pub mod relation;
use crate::query::{CreateTable, DropTable, Select};
#[async_trait::async_trait]
pub trait ToTable: Send + std::fmt::Debug + Sized {
fn from_row_with_offset(row: &tokio_postgres::Row, offset: usize) -> Self;
fn from_row(row: &tokio_postgres::Row) -> Self {
Self::from_row_with_offset(row, 0)
}
fn table_name() -> &'static str;
fn id_name() -> &'static str;
fn id(&self) -> i32;
fn create_table() -> CreateTable;
fn drop_table() -> DropTable;
fn select() -> Select<Self>;
}
pub use async_trait;
pub use bytes;
pub use tokio;
pub use tokio_postgres;
pub use ergol_proc_macro::ergol;
pub use ergol_proc_macro::PgEnum;
pub mod prelude {
pub use crate::pg::Pg;
pub use crate::query::Query;
pub use crate::{ergol, Ergol, PgEnum, Queryable, ToTable};
}
use tokio_postgres::{tls::MakeTlsConnect, Connection, Error, Socket};
pub trait Queryable<T: tokio_postgres::GenericClient> {
fn client(&self) -> &T;
}
pub struct Ergol {
pub client: tokio_postgres::Client,
}
impl Queryable<tokio_postgres::Client> for Ergol {
fn client(&self) -> &tokio_postgres::Client {
&self.client
}
}
impl Ergol {
pub async fn transaction<'a>(&'a mut self) -> Result<Transaction<'a>, tokio_postgres::Error> {
Ok(Transaction {
inner: self.client.transaction().await?,
})
}
}
pub struct Transaction<'a> {
pub inner: tokio_postgres::Transaction<'a>,
}
impl<'a> Queryable<tokio_postgres::Transaction<'a>> for Transaction<'a> {
fn client(&self) -> &tokio_postgres::Transaction<'a> {
&self.inner
}
}
impl<'a> Transaction<'a> {
pub async fn commit(self) -> Result<(), tokio_postgres::Error> {
self.inner.commit().await
}
pub async fn rollback(self) -> Result<(), tokio_postgres::Error> {
self.inner.rollback().await
}
}
pub async fn connect<T: MakeTlsConnect<Socket>>(
config: &str,
tls: T,
) -> Result<(Ergol, Connection<Socket, T::Stream>), Error> {
let (a, b) = tokio_postgres::connect(config, tls).await?;
Ok((Ergol { client: a }, b))
}
#[cfg(feature = "with-rocket")]
pub mod pool {
use crate::tokio_postgres::NoTls;
use crate::{connect, Ergol, Error};
use async_trait::async_trait;
pub struct Manager {
url: String,
}
impl Manager {
pub fn new(url: &str) -> Manager {
Manager {
url: url.to_string(),
}
}
}
pub fn pool(
url: &str,
connections: usize,
) -> Result<Pool, deadpool::managed::BuildError<Error>> {
Pool::builder(Manager::new(url))
.max_size(connections)
.build()
}
#[async_trait]
impl deadpool::managed::Manager for Manager {
type Type = Ergol;
type Error = Error;
async fn create(&self) -> Result<Ergol, Error> {
let (client, connection) = connect(&self.url, NoTls).await?;
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
Ok(client)
}
async fn recycle(&self, conn: &mut Ergol) -> deadpool::managed::RecycleResult<Error> {
if conn.client.is_closed() {
Err(deadpool::managed::RecycleError::Message(
"Connection was closed".to_string(),
))
} else {
Ok(())
}
}
}
pub type Pool = deadpool::managed::Pool<Manager>;
}
#[cfg(feature = "with-rocket")]
pub use pool::{pool, Pool};
#[cfg(feature = "with-rocket")]
pub use deadpool;