Repository: launchbadge/sqlx
File: sqlx-core/src/error.rs (Rust)

Code before:
    }

    pub fn as_database_error(&self) -> Option<&(dyn DatabaseError + 'static)> {
        match self {
            Error::Database(err) => Some(&**err),
            _ => None,
        }
    }

    #[allow(dead_code)]
    #[inline]
    pub(crate) fn protocol(err: impl Display) -> Self {
        Error::Protocol(err.to_string())
    }

    #[allow(dead_code)]
    #[inline]
    pub(crate) fn config(err: impl StdError + Send + Sync + 'static) -> Self {
        Error::Configuration(err.into())
    }
}

pub(crate) fn mismatched_types<DB: Database, T: Type<DB>>(ty: &DB::TypeInfo) -> BoxDynError {
    // TODO: `#name` only produces `TINYINT` but perhaps we want to show `TINYINT(1)`
    format!(
        "mismatched types; Rust type `{}` is not compatible with SQL type `{}`",
        type_name::<T>(),
        ty.name()
    )
    .into()
}

/// An error that was returned from the database.
pub trait DatabaseError: 'static + Send + Sync + StdError {
    /// The primary, human-readable error message.
    fn message(&self) -> &str;

    /// The (SQLSTATE) code for the error.
    fn code(&self) -> Option<Cow<'_, str>> {
        None
    }

    #[doc(hidden)]
    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static);

    #[doc(hidden)]
    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static);

    #[doc(hidden)]
    fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static>;


Review comment (bug):
I'm loathe to lose this information as I think it could be really helpful with debugging.

I think instead we should fix this one level up, calling this function with the underlying `DB` type instead of `Any`:

* Override [`Row::try_get()`](https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/row.rs#L124) in [the impl for `AnyRow`](https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/any/row.rs#L40)
* Override [`Value::try_decode`](https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/value.rs#L71) in [the impl for `AnyValue`](https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/any/value.rs#L56)

I'd probably make a version of this function as a method on [`AnyTypeInfo`](https://github.com/launchbadge/sqlx/blob/master/sqlx-core/src/any/type_info.rs) and match on `AnyTypeInfoKind`, then you can just call that method from the overridden trait methods above.

Code after:
    }

    pub fn as_database_error(&self) -> Option<&(dyn DatabaseError + 'static)> {
        match self {
            Error::Database(err) => Some(&**err),
            _ => None,
        }
    }

    #[allow(dead_code)]
    #[inline]
    pub(crate) fn protocol(err: impl Display) -> Self {
        Error::Protocol(err.to_string())
    }

    #[allow(dead_code)]
    #[inline]
    pub(crate) fn config(err: impl StdError + Send + Sync + 'static) -> Self {
        Error::Configuration(err.into())
    }
}

pub(crate) fn mismatched_types<DB: Database, T: Type<DB>>(ty: &DB::TypeInfo) -> BoxDynError {
    // TODO: `#name` only produces `TINYINT` but perhaps we want to show `TINYINT(1)`
    format!(
        "mismatched types; Rust type `{}` (as SQL type `{}`) is not compatible with SQL type `{}`",
        type_name::<T>(),
        T::type_info().name(),
        ty.name()
    )
    .into()
}

/// An error that was returned from the database.
pub trait DatabaseError: 'static + Send + Sync + StdError {
    /// The primary, human-readable error message.
    fn message(&self) -> &str;

    /// The (SQLSTATE) code for the error.
    fn code(&self) -> Option<Cow<'_, str>> {
        None
    }

    #[doc(hidden)]
    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static);

    #[doc(hidden)]
    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static);

    #[doc(hidden)]
    fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static>;