use crate::value::{Value, ValueRef};
pub enum RowCell<'a> {
Borrowed(ValueRef<'a>),
Owned(Value),
}
impl<'a> RowCell<'a> {
pub fn as_ref(&'a self) -> ValueRef<'a> {
match self {
RowCell::Borrowed(value) => *value,
RowCell::Owned(value) => ValueRef::from(value),
}
}
pub fn into_owned(self) -> Value {
match self {
RowCell::Borrowed(value) => value.to_owned(),
RowCell::Owned(value) => value,
}
}
}
pub trait RowLike {
fn cell<'a>(&'a self, name: &str) -> Result<RowCell<'a>, RowError>;
fn get_typed<T>(&self, name: &str) -> Result<T, RowError>
where
T: for<'a> TryFrom<ValueRef<'a>, Error = RowError>,
{
let cell = self.cell(name)?;
let value_ref = cell.as_ref();
T::try_from(value_ref)
}
fn try_get_typed<T>(&self, name: &str) -> Result<Option<T>, RowError>
where
T: for<'a> TryFrom<ValueRef<'a>, Error = RowError>,
{
match self.get_typed(name) {
Ok(value) => Ok(Some(value)),
Err(err) if matches!(err, RowError::ColumnNotFound { .. }) => Ok(None),
Err(err) => Err(err),
}
}
fn get_value(&self, name: &str) -> Result<Value, RowError> {
Ok(self.cell(name)?.into_owned())
}
fn try_get_value(&self, name: &str) -> Result<Option<Value>, RowError> {
match self.get_value(name) {
Ok(value) => Ok(Some(value)),
Err(err) if matches!(err, RowError::ColumnNotFound { .. }) => Ok(None),
Err(err) => Err(err),
}
}
}
pub trait FromRow: Sized {
fn from_row<R: RowLike>(row: &R) -> Result<Self, RowError>;
}
#[derive(Debug)]
pub enum RowError {
ColumnNotFound {
name: String,
},
TypeMismatch {
expected: &'static str,
found: String,
},
Any(String),
}
impl std::fmt::Display for RowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RowError::ColumnNotFound { name } => {
write!(f, "Column '{}' not found", name)
}
RowError::TypeMismatch { expected, found } => {
write!(f, "Type mismatch: expected {}, found {}", expected, found)
}
RowError::Any(msg) => write!(f, "Error: {}", msg),
}
}
}
impl std::error::Error for RowError {}
impl TryFrom<Value> for String {
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Text(s) => Ok(s),
other => Err(RowError::TypeMismatch {
expected: "Text",
found: format!("{:?}", other),
}),
}
}
}
impl<'a> TryFrom<ValueRef<'a>> for String {
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Text(s) => Ok(s.to_string()),
other => Err(RowError::TypeMismatch {
expected: "Text",
found: format!("{:?}", other),
}),
}
}
}
macro_rules! impl_try_from_int {
($($t:ty),*) => {
$(
impl TryFrom<Value> for $t {
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Int(i) => i.try_into().map_err(|_| RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", i),
}),
other => Err(RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", other),
}),
}
}
}
impl<'a> TryFrom<ValueRef<'a>> for $t {
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Int(i) => i.try_into().map_err(|_| RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", i),
}),
other => Err(RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", other),
}),
}
}
}
)*
};
}
impl_try_from_int!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
macro_rules! impl_try_from_float {
($($t:ty),*) => {
$(
impl TryFrom<Value> for $t {
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Float(f) => Ok(f as $t),
other => Err(RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", other),
}),
}
}
}
impl<'a> TryFrom<ValueRef<'a>> for $t {
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Float(f) => Ok(f as $t),
other => Err(RowError::TypeMismatch {
expected: stringify!($t),
found: format!("{:?}", other),
}),
}
}
}
)*
};
}
impl_try_from_float!(f32, f64);
impl TryFrom<Value> for bool {
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Bool(b) => Ok(b),
Value::Int(i) => Ok(i != 0),
other => Err(RowError::TypeMismatch {
expected: "Bool",
found: format!("{:?}", other),
}),
}
}
}
impl<'a> TryFrom<ValueRef<'a>> for bool {
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Bool(b) => Ok(b),
ValueRef::Int(i) => Ok(i != 0),
other => Err(RowError::TypeMismatch {
expected: "Bool",
found: format!("{:?}", other),
}),
}
}
}
impl TryFrom<Value> for Vec<u8> {
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Blob(b) => Ok(b),
other => Err(RowError::TypeMismatch {
expected: "Blob",
found: format!("{:?}", other),
}),
}
}
}
impl<'a> TryFrom<ValueRef<'a>> for Vec<u8> {
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Blob(b) => Ok(b.to_vec()),
other => Err(RowError::TypeMismatch {
expected: "Blob",
found: format!("{:?}", other),
}),
}
}
}
impl<T> TryFrom<Value> for Option<T>
where
T: TryFrom<Value, Error = RowError>,
{
type Error = RowError;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Null => Ok(None),
other => Ok(Some(T::try_from(other)?)),
}
}
}
impl<'a, T> TryFrom<ValueRef<'a>> for Option<T>
where
T: TryFrom<ValueRef<'a>, Error = RowError>,
{
type Error = RowError;
fn try_from(value: ValueRef<'a>) -> Result<Self, Self::Error> {
match value {
ValueRef::Null => Ok(None),
other => Ok(Some(T::try_from(other)?)),
}
}
}