sqlw 0.1.0

Compile-time SQL query building with schema-safe field references and automatic parameter binding
Documentation
//! SQL value types and conversions.
//!
//! Provides [`Value`] for owned SQL values and [`ValueRef`] for borrowed ones.
//! Automatic conversions from Rust primitives are supported via `From` impls.

/// An owned SQL value.
///
/// Used for parameter binding in queries. Converted automatically
/// from Rust types via the [`query_qmark!`](crate::query_qmark!) or
/// [`query_numbered!`](crate::query_numbered!) macros.
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
    /// A UTF-8 string value.
    Text(String),
    /// A 64-bit signed integer value.
    Int(i64),
    /// A 64-bit floating-point value.
    Float(f64),
    /// A boolean value.
    Bool(bool),
    /// A binary byte array value.
    Blob(Vec<u8>),
    /// A null value.
    Null,
}

impl From<&str> for Value {
    fn from(s: &str) -> Value {
        Value::Text(s.to_string())
    }
}

impl From<String> for Value {
    fn from(s: String) -> Value {
        Value::Text(s)
    }
}

impl From<&String> for Value {
    fn from(s: &String) -> Value {
        Value::Text(s.clone())
    }
}

macro_rules! impl_from_int {
    ($($t:ty),*) => {
        $(
            impl From<$t> for Value {
                fn from(i: $t) -> Value {
                    Value::Int(i as i64)
                }
            }
        )*
    };
}

impl_from_int!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);

impl From<f32> for Value {
    fn from(f: f32) -> Value {
        Value::Float(f as f64)
    }
}

impl From<f64> for Value {
    fn from(f: f64) -> Value {
        Value::Float(f)
    }
}

impl From<bool> for Value {
    fn from(b: bool) -> Value {
        Value::Bool(b)
    }
}

impl From<Vec<u8>> for Value {
    fn from(b: Vec<u8>) -> Value {
        Value::Blob(b)
    }
}

impl From<&[u8]> for Value {
    fn from(b: &[u8]) -> Value {
        Value::Blob(b.to_vec())
    }
}

impl<T> From<Option<T>> for Value
where
    T: Into<Value>,
{
    fn from(opt: Option<T>) -> Value {
        match opt {
            Some(v) => v.into(),
            None => Value::Null,
        }
    }
}

impl<'a, T> From<&'a Option<T>> for Value
where
    T: Clone + Into<Value>,
{
    fn from(opt: &'a Option<T>) -> Value {
        match opt {
            Some(v) => v.clone().into(),
            None => Value::Null,
        }
    }
}

/// A borrowed SQL value.
///
/// Used when extracting values from result rows. Convert to owned
/// via [`to_owned`](Self::to_owned).
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ValueRef<'a> {
    /// A borrowed UTF-8 string value.
    Text(&'a str),
    /// A borrowed 64-bit signed integer value.
    Int(i64),
    /// A borrowed 64-bit floating-point value.
    Float(f64),
    /// A borrowed boolean value.
    Bool(bool),
    /// A borrowed binary byte array value.
    Blob(&'a [u8]),
    /// A null value.
    Null,
}

impl<'a> ValueRef<'a> {
    /// Converts to an owned [`Value`].
    pub fn to_owned(&self) -> Value {
        match self {
            ValueRef::Text(s) => Value::Text(s.to_string()),
            ValueRef::Int(i) => Value::Int(*i),
            ValueRef::Float(f) => Value::Float(*f),
            ValueRef::Bool(b) => Value::Bool(*b),
            ValueRef::Blob(b) => Value::Blob(b.to_vec()),
            ValueRef::Null => Value::Null,
        }
    }
}

impl<'a> From<&'a Value> for ValueRef<'a> {
    fn from(v: &'a Value) -> Self {
        match v {
            Value::Text(s) => ValueRef::Text(s),
            Value::Int(i) => ValueRef::Int(*i),
            Value::Float(f) => ValueRef::Float(*f),
            Value::Bool(b) => ValueRef::Bool(*b),
            Value::Blob(b) => ValueRef::Blob(b),
            Value::Null => ValueRef::Null,
        }
    }
}

#[cfg(feature = "chrono")]
pub(crate) mod chrono_adapter {
    use super::Value;
    use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime};

    impl From<NaiveDateTime> for Value {
        fn from(dt: NaiveDateTime) -> Value {
            Value::Text(dt.to_string())
        }
    }

    impl From<&NaiveDateTime> for Value {
        fn from(dt: &NaiveDateTime) -> Value {
            Value::Text(dt.to_string())
        }
    }

    impl From<NaiveDate> for Value {
        fn from(date: NaiveDate) -> Value {
            Value::Text(date.to_string())
        }
    }

    impl From<&NaiveDate> for Value {
        fn from(date: &NaiveDate) -> Value {
            Value::Text(date.to_string())
        }
    }

    impl From<NaiveTime> for Value {
        fn from(time: NaiveTime) -> Value {
            Value::Text(time.to_string())
        }
    }

    impl From<&NaiveTime> for Value {
        fn from(time: &NaiveTime) -> Value {
            Value::Text(time.to_string())
        }
    }

    impl<T: chrono::TimeZone> From<DateTime<T>> for Value {
        fn from(dt: DateTime<T>) -> Value {
            Value::Text(dt.to_rfc3339())
        }
    }

    impl<T: chrono::TimeZone> From<&DateTime<T>> for Value {
        fn from(dt: &DateTime<T>) -> Value {
            Value::Text(dt.to_rfc3339())
        }
    }
}