1use crate::{ColumnType, Error, Result, SqlType};
12use chrono::{DateTime, NaiveDate, Utc};
13use sea_query::Value;
14
15pub trait Row {
22 fn get_bool(&self, col: &str) -> Result<Option<bool>>;
23 fn get_i32(&self, col: &str) -> Result<Option<i32>>;
24 fn get_i64(&self, col: &str) -> Result<Option<i64>>;
25 fn get_u32(&self, col: &str) -> Result<Option<u32>>;
26 fn get_u64(&self, col: &str) -> Result<Option<u64>>;
27 fn get_f64(&self, col: &str) -> Result<Option<f64>>;
28 fn get_string(&self, col: &str) -> Result<Option<String>>;
29 fn get_bytes(&self, col: &str) -> Result<Option<Vec<u8>>>;
30 fn get_datetime(&self, col: &str) -> Result<Option<DateTime<Utc>>>;
31 fn get_naive_date(&self, col: &str) -> Result<Option<NaiveDate>>;
32}
33
34pub trait FromColumn: Sized {
39 fn from_column(row: &dyn Row, col: &str) -> Result<Self>;
40}
41
42macro_rules! from_column {
43 ($t:ty, $getter:ident) => {
44 impl FromColumn for $t {
45 fn from_column(row: &dyn Row, col: &str) -> Result<Self> {
46 row.$getter(col)?.ok_or_else(|| Error::msg(format!("column `{col}` was NULL")))
47 }
48 }
49 };
50}
51
52from_column!(bool, get_bool);
53from_column!(i32, get_i32);
54from_column!(i64, get_i64);
55from_column!(u32, get_u32);
56from_column!(u64, get_u64);
57from_column!(f64, get_f64);
58from_column!(String, get_string);
59from_column!(Vec<u8>, get_bytes);
60from_column!(DateTime<Utc>, get_datetime);
61from_column!(NaiveDate, get_naive_date);
62
63impl<T: FromColumn + SqlType> FromColumn for Option<T> {
70 fn from_column(row: &dyn Row, col: &str) -> Result<Self> {
71 let present = match T::COLUMN_TYPE {
72 ColumnType::Bool => row.get_bool(col)?.is_some(),
73 ColumnType::Int => row.get_i32(col)?.is_some(),
74 ColumnType::BigInt => row.get_i64(col)?.is_some(),
75 ColumnType::Uint => row.get_u32(col)?.is_some(),
76 ColumnType::BigUint => row.get_u64(col)?.is_some(),
77 ColumnType::Double => row.get_f64(col)?.is_some(),
78 ColumnType::Text => row.get_string(col)?.is_some(),
79 ColumnType::Binary => row.get_bytes(col)?.is_some(),
80 ColumnType::Timestamp => row.get_datetime(col)?.is_some(),
81 ColumnType::Date => row.get_naive_date(col)?.is_some(),
82 };
83 if present {
84 Ok(Some(T::from_column(row, col)?))
85 } else {
86 Ok(None)
87 }
88 }
89}
90
91pub trait ToColumn {
100 fn to_value(&self) -> Value;
101}
102
103macro_rules! to_column {
104 ($t:ty) => {
105 impl ToColumn for $t {
106 fn to_value(&self) -> Value {
107 self.clone().into()
108 }
109 }
110 };
111}
112
113to_column!(bool);
114to_column!(i32);
115to_column!(i64);
116to_column!(u32);
117to_column!(u64);
118to_column!(f64);
119to_column!(String);
120to_column!(Vec<u8>);
121to_column!(DateTime<Utc>);
122to_column!(NaiveDate);
123
124impl<T: ToColumn + SqlType> ToColumn for Option<T> {
129 fn to_value(&self) -> Value {
130 match self {
131 Some(v) => v.to_value(),
132 None => null_value(T::COLUMN_TYPE),
133 }
134 }
135}
136
137fn null_value(ty: ColumnType) -> Value {
139 match ty {
140 ColumnType::Bool => Value::Bool(None),
141 ColumnType::Int => Value::Int(None),
142 ColumnType::BigInt => Value::BigInt(None),
143 ColumnType::Uint => Value::Unsigned(None),
144 ColumnType::BigUint => Value::BigUnsigned(None),
145 ColumnType::Double => Value::Double(None),
146 ColumnType::Text => Value::String(None),
147 ColumnType::Binary => Value::Bytes(None),
148 ColumnType::Timestamp => Value::ChronoDateTimeUtc(None),
149 ColumnType::Date => Value::ChronoDate(None),
150 }
151}