Improve docs around errors

This commit is contained in:
Ryan Leckey 2019-09-02 17:18:33 -07:00
parent 9d7eff2ca7
commit abb7d12087
6 changed files with 49 additions and 18 deletions

View file

@ -8,9 +8,8 @@ use crate::{
use crossbeam_queue::SegQueue; use crossbeam_queue::SegQueue;
use crossbeam_utils::atomic::AtomicCell; use crossbeam_utils::atomic::AtomicCell;
use futures_channel::oneshot::{channel, Sender}; use futures_channel::oneshot::{channel, Sender};
use futures_util::TryFutureExt;
use futures_core::{future::BoxFuture, stream::BoxStream}; use futures_core::{future::BoxFuture, stream::BoxStream};
use futures_util::stream::StreamExt; use futures_util::{stream::StreamExt, TryFutureExt};
use std::{ use std::{
io, io,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
@ -37,13 +36,19 @@ pub trait RawConnection: Send {
/// ///
/// This method is not required to be called. A database server will eventually notice /// This method is not required to be called. A database server will eventually notice
/// and clean up not fully closed connections. /// and clean up not fully closed connections.
/// ///
/// It is safe to close an already closed connection. /// It is safe to close an already closed connection.
fn close<'c>(&'c mut self) -> BoxFuture<'c, Result<(), Error>>; fn close<'c>(&'c mut self) -> BoxFuture<'c, Result<(), Error>>;
/// Verifies a connection to the database is still alive. /// Verifies a connection to the database is still alive.
fn ping<'c>(&'c mut self) -> BoxFuture<'c, Result<(), Error>> { fn ping<'c>(&'c mut self) -> BoxFuture<'c, Result<(), Error>> {
Box::pin(self.execute("SELECT 1", <Self::Backend as Backend>::QueryParameters::new()).map_ok(|_| ())) Box::pin(
self.execute(
"SELECT 1",
<Self::Backend as Backend>::QueryParameters::new(),
)
.map_ok(|_| ()),
)
} }
fn execute<'c>( fn execute<'c>(
@ -103,7 +108,7 @@ where
/// ///
/// This method is not required to be called. A database server will eventually notice /// This method is not required to be called. A database server will eventually notice
/// and clean up not fully closed connections. /// and clean up not fully closed connections.
/// ///
/// It is safe to close an already closed connection. /// It is safe to close an already closed connection.
pub async fn close(&self) -> crate::Result<()> { pub async fn close(&self) -> crate::Result<()> {
let mut conn = self.acquire().await; let mut conn = self.acquire().await;

View file

@ -4,8 +4,10 @@ use std::{
io, io,
}; };
/// A convenient Result instantiation appropriate for SQLx.
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
/// A generic error that represents all the ways a method can fail inside of SQLx.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
/// Error communicating with the database backend. /// Error communicating with the database backend.
@ -24,23 +26,46 @@ pub enum Error {
Io(io::Error), Io(io::Error),
/// An error was returned by the database backend. /// An error was returned by the database backend.
Database(Box<dyn DbError + Send + Sync>), Database(Box<dyn DatabaseError + Send + Sync>),
/// No rows were returned by a query expected to return at least one row. /// No rows were returned by a query expected to return at least one row.
NotFound, NotFound,
/// More than one row was returned by a query expected to return exactly one row.
FoundMoreThanOne,
// TODO: Remove and replace with `#[non_exhaustive]` when possible // TODO: Remove and replace with `#[non_exhaustive]` when possible
#[doc(hidden)] #[doc(hidden)]
__Nonexhaustive, __Nonexhaustive,
} }
// TODO: Forward causes where present impl StdError for Error {
impl StdError for Error {} fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Error::Io(error) => Some(error),
_ => None
}
}
}
// TODO: Don't just forward to debug
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) match self {
Error::Io(error) => write!(f, "{}", error),
Error::Database(error) => f.write_str(error.message()),
Error::NotFound => f.write_str("found no rows when we expected at least one"),
Error::FoundMoreThanOne => {
f.write_str("found more than one row when we expected exactly one")
}
Error::__Nonexhaustive => {
unreachable!()
}
}
} }
} }
@ -53,7 +78,7 @@ impl From<io::Error> for Error {
impl<T> From<T> for Error impl<T> From<T> for Error
where where
T: 'static + DbError, T: 'static + DatabaseError,
{ {
#[inline] #[inline]
fn from(err: T) -> Self { fn from(err: T) -> Self {
@ -62,7 +87,7 @@ where
} }
/// An error that was returned by the database backend. /// An error that was returned by the database backend.
pub trait DbError: Debug + Send + Sync { pub trait DatabaseError: Debug + Send + Sync {
fn message(&self) -> &str; fn message(&self) -> &str;
// TODO: Expose more error properties // TODO: Expose more error properties

View file

@ -30,6 +30,7 @@ pub mod serialize;
mod sql; mod sql;
pub mod types; pub mod types;
#[doc(inline)]
pub use self::{ pub use self::{
connection::Connection, connection::Connection,
error::{Error, Result}, error::{Error, Result},

View file

@ -1,6 +1,6 @@
use super::{ use super::{
protocol::{self, Decode, Encode, Message, Terminate}, protocol::{self, Decode, Encode, Message, Terminate},
Postgres, PostgresError, PostgresQueryParameters, PostgresRow, Postgres, PostgresDatabaseError, PostgresQueryParameters, PostgresRow,
}; };
use crate::{ use crate::{
connection::RawConnection, connection::RawConnection,
@ -200,7 +200,7 @@ impl PostgresRawConnection {
Message::Response(body) => { Message::Response(body) => {
if body.severity().is_error() { if body.severity().is_error() {
// This is an error, stop the world and bubble as an error // This is an error, stop the world and bubble as an error
return Err(PostgresError(body).into()); return Err(PostgresDatabaseError(body).into());
} else { } else {
// This is a _warning_ // This is a _warning_
// TODO: Do we *want* to do anything with these // TODO: Do we *want* to do anything with these

View file

@ -1,10 +1,10 @@
use super::protocol::Response; use super::protocol::Response;
use crate::error::DbError; use crate::error::DatabaseError;
#[derive(Debug)] #[derive(Debug)]
pub struct PostgresError(pub(super) Box<Response>); pub struct PostgresDatabaseError(pub(super) Box<Response>);
impl DbError for PostgresError { impl DatabaseError for PostgresDatabaseError {
fn message(&self) -> &str { fn message(&self) -> &str {
self.0.message() self.0.message()
} }

View file

@ -7,7 +7,7 @@ mod row;
pub mod types; pub mod types;
pub use self::{ pub use self::{
backend::Postgres, connection::PostgresRawConnection, error::PostgresError, backend::Postgres, connection::PostgresRawConnection, error::PostgresDatabaseError,
query::PostgresQueryParameters, row::PostgresRow, query::PostgresQueryParameters, row::PostgresRow,
}; };