#![allow(missing_docs)] use std::time::Duration; use fallible_iterator::FallibleIterator; use tokio_postgres::{Column, Notification}; use tokio_postgres::row::RowIndex; use tokio_postgres::types::FromSql; use crate::types::{BorrowToSql, ToSql, Type}; use crate::{ Client, CopyInWriter, CopyOutReader, Error, Row, RowIter, SimpleQueryMessage, Statement, ToStatement, Transaction}; macro_rules! common { ($transaction:ty, $err:ty) => { /// Like `Client::execute`. fn execute(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement; /// Like `Client::query`. fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, $err> where T: ?Sized + ToStatement; /// Like `Client::query_one`. fn query_one(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement; /// Like `Client::query_opt`. fn query_opt( &mut self, query: &T, params: &[&(dyn ToSql + Sync)], ) -> Result, $err> where T: ?Sized + ToStatement; /// Like `Client::query_raw`. fn query_raw(&mut self, query: &T, params: I) -> Result, $err> where T: ?Sized + ToStatement, P: BorrowToSql, I: IntoIterator, I::IntoIter: ExactSizeIterator; /// Like `Client::prepare`. fn prepare(&mut self, query: &str) -> Result; /// Like `Client::prepare_typed`. fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result; /// Like `Client::copy_in`. fn copy_in(&mut self, query: &T) -> Result, $err> where T: ?Sized + ToStatement; /// Like `Client::copy_out`. fn copy_out(&mut self, query: &T) -> Result, $err> where T: ?Sized + ToStatement; /// Like `Client::simple_query`. fn simple_query(&mut self, query: &str) -> Result, $err>; /// Like `Client::batch_execute`. fn batch_execute(&mut self, query: &str) -> Result<(), $err>; /// Like `Client::transaction`. fn transaction(&mut self) -> Result<$transaction, $err>; }; } pub trait GenericRow { type Error: core::fmt::Debug; fn columns(&self) -> &[Column]; fn len(&self) -> usize; fn get<'a, I, T>(&'a self, idx: I) -> T where I: RowIndex + core::fmt::Display, T: FromSql<'a>; fn try_get<'a, I, T>(&'a self, idx: I) -> Result where I: RowIndex + core::fmt::Display, T: FromSql<'a>; } pub trait GenericTransaction<'a> where Self: Sized { type Error: core::fmt::Debug; type NestedTransaction<'b> where Self: 'b; type Row: GenericRow; fn commit(self) -> Result<(), Self::Error>; fn rollback(self) -> Result<(), Self::Error>; common!(Self::NestedTransaction<'_>, Self::Error); } /// A trait allowing abstraction over connections and transactions. pub trait GenericClient { type Error: core::fmt::Debug; type Transaction<'a>: GenericTransaction<'a> where Self: 'a; type Row: GenericRow; common!(Self::Transaction<'_>, Self::Error); fn check_for_notify(&mut self) -> Result, Self::Error>; } impl GenericClient for Client { type Error = Error; type Transaction<'a> = Transaction<'a>; type Row = Row; fn execute(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, { self.execute(query, params) } fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement, { self.query(query, params) } fn query_one(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, { self.query_one(query, params) } fn query_opt( &mut self, query: &T, params: &[&(dyn ToSql + Sync)], ) -> Result, Error> where T: ?Sized + ToStatement, { self.query_opt(query, params) } fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, P: BorrowToSql, I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.query_raw(query, params) } fn prepare(&mut self, query: &str) -> Result { self.prepare(query) } fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result { self.prepare_typed(query, types) } fn copy_in(&mut self, query: &T) -> Result, Error> where T: ?Sized + ToStatement, { self.copy_in(query) } fn copy_out(&mut self, query: &T) -> Result, Error> where T: ?Sized + ToStatement, { self.copy_out(query) } fn simple_query(&mut self, query: &str) -> Result, Error> { self.simple_query(query) } fn batch_execute(&mut self, query: &str) -> Result<(), Error> { self.batch_execute(query) } fn transaction(&mut self) -> Result, Error> { self.transaction() } fn check_for_notify(&mut self) -> Result, Self::Error> { let mut n = self.notifications(); let mut n = n.timeout_iter(Duration::from_millis(500)); n.next() } } macro_rules! transaction_common { ($transaction:ty) => { fn execute(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, { self.execute(query, params) } fn query(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement, { self.query(query, params) } fn query_one(&mut self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement, { self.query_one(query, params) } fn query_opt( &mut self, query: &T, params: &[&(dyn ToSql + Sync)], ) -> Result, Error> where T: ?Sized + ToStatement, { self.query_opt(query, params) } fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, P: BorrowToSql, I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.query_raw(query, params) } fn prepare(&mut self, query: &str) -> Result { self.prepare(query) } fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result { self.prepare_typed(query, types) } fn copy_in(&mut self, query: &T) -> Result, Error> where T: ?Sized + ToStatement, { self.copy_in(query) } fn copy_out(&mut self, query: &T) -> Result, Error> where T: ?Sized + ToStatement, { self.copy_out(query) } fn simple_query(&mut self, query: &str) -> Result, Error> { self.simple_query(query) } fn batch_execute(&mut self, query: &str) -> Result<(), Error> { self.batch_execute(query) } fn transaction(&mut self) -> Result<$transaction, Error> { self.transaction() } }; } impl<'a> GenericTransaction<'a> for Transaction<'a> { type Error = Error; type NestedTransaction<'b> = Transaction<'b> where Self: 'b; type Row = Row; fn commit(self) -> Result<(), Error> {Transaction::commit(self)} fn rollback(self) -> Result<(), Error> {Transaction::rollback(self)} transaction_common!(Self::NestedTransaction<'_>); } impl GenericClient for Transaction<'_> { type Error = Error; type Transaction<'a> = Transaction<'a> where Self: 'a; type Row = Row; transaction_common!(Self::Transaction<'_>); fn check_for_notify(&mut self) -> Result, Self::Error> { Ok(None) } } impl GenericRow for Row { type Error = Error; fn columns(&self) -> &[Column] { self.columns() } fn len(&self) -> usize { self.len() } fn get<'a, I, T>(&'a self, idx: I) -> T where I: RowIndex + core::fmt::Display, T: FromSql<'a> { self.get(idx) } fn try_get<'a, I, T>(&'a self, idx: I) -> Result where I: RowIndex + core::fmt::Display, T: FromSql<'a> { self.try_get(idx) } }