[go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more test and error type #1105

Merged
merged 3 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions postgres/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,35 @@ pub trait ClientBorrowMut {
fn _borrow_mut(&mut self) -> &mut Client;
}

/// Client is a handler type for [`Driver`]. it interacts with latter using channel and message for IO operation
/// and de/encoding of postgres protocol in byte format.
///
/// Client expose a set of high level API to make the interaction represented in Rust function and types.
///
/// # Lifetime
/// Client and [`Driver`] have a dependent lifetime where either side can trigger the other part to shutdown.
/// From Client side it's in the form of dropping ownership.
/// ## Examples
/// ```
/// # use core::future::IntoFuture;
/// # use xitca_postgres::{error::Error, Config, Postgres};
/// # async fn shut_down(cfg: Config) -> Result<(), Error> {
/// // connect to a database and spawn driver as async task
/// let (cli, drv) = Postgres::new(cfg).connect().await?;
/// let handle = tokio::spawn(drv.into_future());
///
/// // drop client after finished usage
/// drop(cli);
///
/// // client would notify driver to shutdown when it's dropped.
/// // await on the handle would return a Result of the shutdown outcome from driver side.
/// let _ = handle.await.unwrap();
///
/// # Ok(())
/// # }
/// ```
///
/// [`Driver`]: crate::driver::Driver
pub struct Client {
pub(crate) tx: DriverTx,
pub(crate) cache: Box<ClientCache>,
Expand Down
12 changes: 10 additions & 2 deletions postgres/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use xitca_io::{
use super::{
client::Client,
config::{Config, SslMode},
error::{unexpected_eof_err, Error},
error::{unexpected_eof_err, ConfigError, Error},
iter::AsyncLendingIterator,
session::{ConnectInfo, Session},
};
Expand All @@ -45,6 +45,14 @@ use xitca_tls::rustls::{ClientConnection, TlsStream};
use xitca_io::net::UnixStream;

pub(super) async fn connect(cfg: &mut Config) -> Result<(Client, Driver), Error> {
if cfg.get_hosts().is_empty() {
return Err(ConfigError::EmptyHost.into());
}

if cfg.get_ports().is_empty() {
return Err(ConfigError::EmptyPort.into());
}

let mut err = None;
let hosts = cfg.get_hosts().to_vec();
for host in hosts {
Expand Down Expand Up @@ -140,7 +148,7 @@ async fn dns_resolve<'p>(host: &'p str, ports: &'p [u16]) -> Result<impl Iterato
/// it handles IO and emit server sent message that do not belong to any query with [AsyncLendingIterator]
/// trait impl.
///
/// # Examples:
/// # Examples
/// ```
/// use std::future::IntoFuture;
/// use xitca_postgres::{AsyncLendingIterator, Driver};
Expand Down
31 changes: 29 additions & 2 deletions postgres/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ impl fmt::Debug for DriverDown {

impl fmt::Display for DriverDown {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Driver is dropped and unaccessible. Associated query has not been sent to database.")
f.write_str("Client's Driver is dropped and unaccessible. Associated query has not been sent to database.")
}
}

Expand All @@ -128,7 +128,7 @@ pub struct DriverDownReceiving;

impl fmt::Display for DriverDownReceiving {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Driver is dropped and unaccessible. Associated query has been sent to database.")
f.write_str("Client's Driver is dropped and unaccessible. Associated query MAY have been sent to database.")
}
}

Expand Down Expand Up @@ -200,6 +200,33 @@ impl From<FromSqlError> for Error {
}
}

/// error happens when [`Config`] fail to provide necessary information.
///
/// [`Config`]: crate::config::Config
#[derive(Debug)]
pub enum ConfigError {
EmptyHost,
EmptyPort,
}

impl fmt::Display for ConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Config error: ")?;
match self {
Self::EmptyHost => f.write_str("no available host name found"),
Self::EmptyPort => f.write_str("no available host port found"),
}
}
}

impl error::Error for ConfigError {}

impl From<ConfigError> for Error {
fn from(e: ConfigError) -> Self {
Self(Box::new(e))
}
}

/// error happens when library user failed to provide valid authentication info to database server.
#[derive(Debug)]
pub enum AuthenticationError {
Expand Down
45 changes: 43 additions & 2 deletions postgres/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub mod compat {
//! # Ok(())
//! # }
//! ```
//!
//! [`futures::Stream`]: futures_core::stream::Stream

pub use crate::query::compat::RowStreamOwned;
pub use crate::row::compat::RowOwned;
Expand Down Expand Up @@ -135,8 +137,7 @@ impl Postgres {
}

impl Postgres {
/// Connect to database. The returned values are [Client] and a detached async task
/// that drives the client communication to db and it needs to spawn on an async runtime.
/// Connect to database, returning [Client] and [Driver] on success
///
/// # Examples:
/// ```rust
Expand Down Expand Up @@ -258,3 +259,43 @@ fn _assert_driver_send() {
// handle.await.unwrap();
// }
// }

#[cfg(test)]
mod test {
use core::future::IntoFuture;

use super::*;

#[tokio::test]
async fn config_error() {
let mut cfg = Config::new();

cfg.dbname("postgres").user("postgres").password("postgres");

let mut cfg1 = cfg.clone();
cfg1.host("localhost");
Postgres::new(cfg1).connect().await.err().unwrap();

cfg.port(5432);
Postgres::new(cfg).connect().await.err().unwrap();
}

#[tokio::test]
async fn client_shutdown() {
let mut cfg = Config::new();

cfg.dbname("postgres")
.user("postgres")
.password("postgres")
.host("localhost")
.port(5432);

let (cli, drv) = Postgres::new(cfg).connect().await.unwrap();

let handle = tokio::spawn(drv.into_future());

drop(cli);

handle.await.unwrap().unwrap();
}
}
Loading