rorm-db 0.11.0

The inner database abstraction layer from rorm.
Documentation
use std::any::type_name;

use sqlx::{ColumnIndex, Type, TypeInfo, ValueRef};

use crate::internal::any::AnyRow;
use crate::row::{Decode, RowError, RowIndex};
use crate::Row;

pub(crate) type Impl = AnyRow;

/// Implementation of [Row::get]
pub(crate) fn get<'r, 'i, T>(row: &'r Row, index: RowIndex<'i>) -> Result<T, RowError<'i>>
where
    T: Decode<'r>,
{
    match &row.0 {
        #[cfg(feature = "postgres")]
        AnyRow::Postgres(row) => try_get(row, index),
        #[cfg(feature = "mysql")]
        AnyRow::MySql(row) => try_get(row, index),
        #[cfg(feature = "sqlite")]
        AnyRow::Sqlite(row) => try_get(row, index),
    }
}

fn try_get<'r, 'i, R, T>(row: &'r R, index: RowIndex<'i>) -> Result<T, RowError<'i>>
where
    R: sqlx::Row,
    usize: ColumnIndex<R>,
    &'i str: ColumnIndex<R>,
    T: sqlx::Decode<'r, R::Database> + Type<R::Database>,
{
    let value = match index {
        RowIndex::Position(index) => row.try_get_raw(index),
        RowIndex::Name(index) => row.try_get_raw(index),
    }
    .map_err(|error| match error {
        sqlx::Error::ColumnIndexOutOfBounds { .. } | sqlx::Error::ColumnNotFound(_) => {
            RowError::NotFound { index }
        }
        _ => RowError::Unknown {
            index,
            source: Box::new(error),
        },
    })?;

    if !value.is_null() {
        let ty = value.type_info();

        if !ty.is_null() && !T::compatible(&ty) {
            return Err(RowError::MismatchedTypes {
                index,
                rust_type: type_name::<T>(),
            });
        }
    }

    T::decode(value).map_err(|source| {
        if source.is::<sqlx::error::UnexpectedNullError>() {
            RowError::UnexpectedNull { index }
        } else {
            RowError::Decode { index, source }
        }
    })
}