#![deny(missing_docs)]
#![forbid(unsafe_code)]
use std::fmt;
use std::sync::Arc;
pub use bb8;
pub use oracle;
#[derive(Debug)]
pub struct OracleConnectionManager {
connector: oracle::Connector,
}
impl OracleConnectionManager {
pub fn new<U: Into<String>, P: Into<String>, C: Into<String>>(username: U, password: P, connect_string: C) -> OracleConnectionManager {
let connector = oracle::Connector::new(username, password, connect_string);
OracleConnectionManager {
connector,
}
}
pub fn from_connector(connector: oracle::Connector) -> OracleConnectionManager {
OracleConnectionManager { connector }
}
}
#[derive(Debug)]
pub enum Error {
Database(oracle::Error),
Panic(tokio::task::JoinError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Database(e) => write!(f, "database error: {}", e),
Self::Panic(e) => write!(f, "operation panicked: {}", e),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Database(e) => Some(e),
Self::Panic(e) => Some(e),
}
}
}
impl bb8::ManageConnection for OracleConnectionManager {
type Connection = Arc<oracle::Connection>;
type Error = Error;
async fn connect(&self) -> Result<Self::Connection, Self::Error> {
let connector_clone = self.connector.clone();
let result = tokio::task::spawn_blocking(move || {
connector_clone.connect()
}).await;
match result {
Ok(Ok(c)) => Ok(Arc::new(c)),
Ok(Err(e)) => Err(Error::Database(e)),
Err(e) => Err(Error::Panic(e)),
}
}
async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> {
let conn_clone = Arc::clone(&conn);
let result = tokio::task::spawn_blocking(move || {
conn_clone.ping()
}).await;
match result {
Ok(Ok(())) => Ok(()),
Ok(Err(e)) => Err(Error::Database(e)),
Err(e) => Err(Error::Panic(e)),
}
}
fn has_broken(&self, conn: &mut Self::Connection) -> bool {
!matches!(conn.status(), Ok(oracle::ConnStatus::Normal))
}
}