tiberius/
from_sql.rs

1use crate::{tds::Numeric, xml::XmlData, ColumnData};
2use uuid::Uuid;
3
4/// A conversion trait from a TDS type by-reference.
5///
6/// A `FromSql` implementation for a Rust type is needed for using it as a
7/// return parameter from [`Row#get`] or [`Row#try_get`] methods. The following
8/// Rust types are already implemented to match the given server types:
9///
10/// |Rust type|Server type|
11/// |--------|--------|
12/// |`u8`|`tinyint`|
13/// |`i16`|`smallint`|
14/// |`i32`|`int`|
15/// |`i64`|`bigint`|
16/// |`f32`|`float(24)`|
17/// |`f64`|`float(53)`|
18/// |`bool`|`bit`|
19/// |`String`/`&str`|`nvarchar`/`varchar`/`nchar`/`char`/`ntext`/`text`|
20/// |`Vec<u8>`/`&[u8]`|`binary`/`varbinary`/`image`|
21/// |[`Uuid`]|`uniqueidentifier`|
22/// |[`Numeric`]|`numeric`/`decimal`|
23/// |[`Decimal`] (with feature flag `rust_decimal`)|`numeric`/`decimal`|
24/// |[`XmlData`]|`xml`|
25/// |[`NaiveDateTime`] (with feature flag `chrono`)|`datetime`/`datetime2`/`smalldatetime`|
26/// |[`NaiveDate`] (with feature flag `chrono`)|`date`|
27/// |[`NaiveTime`] (with feature flag `chrono`)|`time`|
28/// |[`DateTime`] (with feature flag `chrono`)|`datetimeoffset`|
29///
30/// See the [`time`] module for more information about the date and time structs.
31///
32/// [`Row#get`]: struct.Row.html#method.get
33/// [`Row#try_get`]: struct.Row.html#method.try_get
34/// [`time`]: time/index.html
35/// [`Uuid`]: struct.Uuid.html
36/// [`Numeric`]: numeric/struct.Numeric.html
37/// [`Decimal`]: numeric/struct.Decimal.html
38/// [`XmlData`]: xml/struct.XmlData.html
39/// [`NaiveDateTime`]: time/chrono/struct.NaiveDateTime.html
40/// [`NaiveDate`]: time/chrono/struct.NaiveDate.html
41/// [`NaiveTime`]: time/chrono/struct.NaiveTime.html
42/// [`DateTime`]: time/chrono/struct.DateTime.html
43pub trait FromSql<'a>
44where
45    Self: Sized + 'a,
46{
47    /// Returns the value, `None` being a null value, copying the value.
48    fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>>;
49}
50
51/// A conversion trait from a TDS type by-value.
52pub trait FromSqlOwned
53where
54    Self: Sized,
55{
56    /// Returns the value, `None` being a null value, taking the ownership.
57    fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>>;
58}
59
60from_sql!(bool: ColumnData::Bit(val) => (*val, val));
61from_sql!(u8: ColumnData::U8(val) => (*val, val), ColumnData::I32(None) => (None, None));
62from_sql!(i16: ColumnData::I16(val) => (*val, val), ColumnData::U8(None) => (None, None), ColumnData::I32(None) => (None, None));
63from_sql!(i32: ColumnData::I32(val) => (*val, val), ColumnData::U8(None) => (None, None));
64from_sql!(i64: ColumnData::I64(val) => (*val, val), ColumnData::U8(None) => (None, None), ColumnData::I32(None) => (None, None));
65from_sql!(f32: ColumnData::F32(val) => (*val, val));
66from_sql!(f64: ColumnData::F64(val) => (*val, val));
67from_sql!(Uuid: ColumnData::Guid(val) => (*val, val));
68from_sql!(Numeric: ColumnData::Numeric(n) => (*n, n));
69
70impl FromSqlOwned for XmlData {
71    fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
72        match value {
73            ColumnData::Xml(data) => Ok(data.map(|data| data.into_owned())),
74            v => Err(crate::Error::Conversion(
75                format!("cannot interpret {:?} as a String value", v).into(),
76            )),
77        }
78    }
79}
80
81impl<'a> FromSql<'a> for &'a XmlData {
82    fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
83        match value {
84            ColumnData::Xml(data) => Ok(data.as_ref().map(|s| s.as_ref())),
85            v => Err(crate::Error::Conversion(
86                format!("cannot interpret {:?} as a String value", v).into(),
87            )),
88        }
89    }
90}
91
92impl FromSqlOwned for String {
93    fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
94        match value {
95            ColumnData::String(s) => Ok(s.map(|s| s.into_owned())),
96            v => Err(crate::Error::Conversion(
97                format!("cannot interpret {:?} as a String value", v).into(),
98            )),
99        }
100    }
101}
102
103impl<'a> FromSql<'a> for &'a str {
104    fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
105        match value {
106            ColumnData::String(s) => Ok(s.as_ref().map(|s| s.as_ref())),
107            v => Err(crate::Error::Conversion(
108                format!("cannot interpret {:?} as a String value", v).into(),
109            )),
110        }
111    }
112}
113
114impl FromSqlOwned for Vec<u8> {
115    fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
116        match value {
117            ColumnData::Binary(b) => Ok(b.map(|s| s.into_owned())),
118            v => Err(crate::Error::Conversion(
119                format!("cannot interpret {:?} as a String value", v).into(),
120            )),
121        }
122    }
123}
124
125impl<'a> FromSql<'a> for &'a [u8] {
126    fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
127        match value {
128            ColumnData::Binary(b) => Ok(b.as_ref().map(|s| s.as_ref())),
129            v => Err(crate::Error::Conversion(
130                format!("cannot interpret {:?} as a &[u8] value", v).into(),
131            )),
132        }
133    }
134}