feat(core): add TypeNotCompatible error variants to Decode and Encode Error

This commit is contained in:
Ryan Leckey 2021-02-26 00:04:29 -08:00
parent 2934a18af4
commit ecb4bd0281
No known key found for this signature in database
GPG Key ID: F8AA68C235AB08C9
4 changed files with 56 additions and 16 deletions

View File

@ -3,13 +3,12 @@ use std::fmt::{self, Display, Formatter};
use std::str::Utf8Error;
use crate::database::HasRawValue;
use crate::Database;
use crate::{Database, Type, TypeInfo};
/// A type that can be decoded from a SQL value.
pub trait Decode<'r, Db: Database>: Send + Sync {
fn decode(value: <Db as HasRawValue<'r>>::RawValue) -> Result<Self>
where
Self: Sized;
pub trait Decode<'r, Db: Database>: Sized + Send + Sync {
/// Decode the SQL value into the target type.
fn decode(value: <Db as HasRawValue<'r>>::RawValue) -> Result<Self>;
}
/// A type that can be decoded from a SQL value, without borrowing any data
@ -23,6 +22,11 @@ impl<T, Db: Database> DecodeOwned<Db> for T where T: for<'r> Decode<'r, Db> {}
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
TypeNotCompatible {
rust_type_name: &'static str,
sql_type_name: &'static str,
},
/// An unexpected SQL `NULL` was encountered during decoding.
///
/// To decode potentially `NULL` values, wrap the target type in `Option`.
@ -48,6 +52,14 @@ impl Display for Error {
match self {
Self::UnexpectedNull => f.write_str("unexpected null; try decoding as an `Option`"),
Self::TypeNotCompatible { rust_type_name, sql_type_name } => {
write!(
f,
"Rust type `{}` is not compatible with SQL type `{}`",
rust_type_name, sql_type_name
)
}
Self::NotUtf8(error) => {
write!(f, "{}", error)
}

View File

@ -2,7 +2,7 @@ use std::error::Error as StdError;
use std::fmt::{self, Display, Formatter};
use crate::database::HasOutput;
use crate::Database;
use crate::{Database, Type, TypeInfo};
/// A type that can be encoded into a SQL value.
pub trait Encode<Db: Database>: Send + Sync {
@ -21,6 +21,11 @@ impl<T: Encode<Db>, Db: Database> Encode<Db> for &T {
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
TypeNotCompatible {
rust_type_name: &'static str,
sql_type_name: &'static str,
},
/// A general error raised while encoding a value.
Custom(Box<dyn StdError + Send + Sync>),
}
@ -35,6 +40,14 @@ impl Error {
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::TypeNotCompatible { rust_type_name, sql_type_name } => {
write!(
f,
"Rust type `{}` is not compatible with SQL type `{}`",
rust_type_name, sql_type_name
)
}
Self::Custom(error) => {
write!(f, "{}", error)
}

View File

@ -11,6 +11,8 @@ mod database;
pub use database::DatabaseError;
use crate::Column;
/// Specialized `Result` type returned from fallible methods within SQLx.
pub type Result<T> = std::result::Result<T, Error>;
@ -89,6 +91,15 @@ impl Error {
pub fn opt_msg(message: impl Into<Cow<'static, str>>) -> Self {
Self::ConnectOptions { message: message.into(), source: None }
}
#[doc(hidden)]
pub fn column_decode(column: &impl Column, source: DecodeError) -> Self {
crate::Error::ColumnDecode {
source,
column_index: column.index(),
column_name: column.name().to_owned().into_boxed_str(),
}
}
}
impl Display for Error {
@ -107,41 +118,45 @@ impl Display for Error {
}
Self::RowNotFound => {
f.write_str("no row returned by a query required to return at least one row")
f.write_str("No row returned by a query required to return at least one row")
}
Self::Closed => f.write_str("connection or pool is closed"),
Self::Closed => f.write_str("Connection or pool is closed"),
Self::Decode(error) => {
write!(f, "decode: {}", error)
write!(f, "Decode: {}", error)
}
Self::Encode(error) => {
write!(f, "encode: {}", error)
write!(f, "Encode: {}", error)
}
Self::ColumnIndexOutOfBounds { index, len } => {
write!(
f,
"column index out of bounds: the len is {}, but the index is {}",
"Column index out of bounds: the len is {}, but the index is {}",
len, index
)
}
Self::ColumnNotFound { name } => {
write!(f, "no column found for name `{}`", name)
write!(f, "No column found for name `{}`", name)
}
Self::ColumnDecode { column_index, column_name, source } => {
write!(f, "decode column {} `{}`: {}", column_index, column_name, source)
if column_name.is_empty() {
write!(f, "Decode column {}: {}", column_index, source)
} else {
write!(f, "Decode column {} `{}`: {}", column_index, column_name, source)
}
}
Self::ParameterEncode { parameter: Either::Left(index), source } => {
write!(f, "encode parameter {}: {}", index, source)
write!(f, "Encode parameter {}: {}", index, source)
}
Self::ParameterEncode { parameter: Either::Right(name), source } => {
write!(f, "encode parameter `{}`: {}", name, source)
write!(f, "Encode parameter `{}`: {}", name, source)
}
}
}

View File

@ -34,5 +34,5 @@ pub trait TypeInfo {
///
/// Common type names include `VARCHAR`, `INTEGER`, and `BIGINT`.
///
fn name(&self) -> &str;
fn name(&self) -> &'static str;
}