fire_postgres/table/column/
column_type.rs1use super::{ColumnData, ColumnKind};
2
3#[derive(Debug)]
4pub enum FromDataError {
5 ExpectedType(&'static str),
6 Custom(&'static str),
7 CustomString(String),
8}
9
10pub trait ColumnType: Sized {
11 fn column_kind() -> ColumnKind;
12 fn to_data(&self) -> ColumnData<'_>;
13 fn from_data(data: ColumnData<'_>) -> Result<Self, FromDataError>;
14}
15
16macro_rules! imp {
17 ($type:ty, $kind:ident) => (
18 imp!($type, $kind, |self| { *self }, |v| { Ok(v) });
19 );
20 (
21 $type:ty, $kind:ident,
22 |$self:ident| $block:block,
23 |$v:ident| $from_block:block
24 ) => (
25 impl ColumnType for $type {
26 #[inline(always)]
27 fn column_kind() -> ColumnKind {
28 ColumnKind::$kind
29 }
30 fn to_data(&$self) -> ColumnData<'static> {
31 ColumnData::$kind($block)
32 }
33 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
34 match data {
35 ColumnData::$kind($v) => {$from_block},
36 _ => Err(FromDataError::ExpectedType(stringify!($kind)))
37 }
38 }
39 }
40 );
41}
42
43impl ColumnType for String {
44 #[inline(always)]
45 fn column_kind() -> ColumnKind {
46 ColumnKind::Text
47 }
48 fn to_data(&self) -> ColumnData<'_> {
49 ColumnData::Text(self.as_str().into())
50 }
51 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
52 match data {
53 ColumnData::Text(v) => Ok(v.into_string()),
54 _ => Err(FromDataError::ExpectedType("Text")),
55 }
56 }
57}
58
59impl ColumnType for &str {
60 #[inline(always)]
61 fn column_kind() -> ColumnKind {
62 ColumnKind::Text
63 }
64 fn to_data(&self) -> ColumnData<'_> {
65 ColumnData::Text((*self).into())
66 }
67 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
68 match data {
69 ColumnData::Text(_) => Err(FromDataError::Custom(
70 "cannot convert string to &'static str",
71 )),
72 _ => Err(FromDataError::ExpectedType("Text")),
73 }
74 }
75}
76imp!(bool, Boolean);
77imp!(f64, F64);
83imp!(i64, I64);
84imp!(
85 u64,
86 I64,
87 |self| { i64::try_from(*self).expect("u64 to i64 overflowed") },
88 |v| { Ok(v as u64) }
89); imp!(f32, F32);
92imp!(i32, I32);
93imp!(u32, I64, |self| { *self as i64 }, |v| {
94 u32::try_from(v)
96 .map_err(|_| FromDataError::Custom("cannot convert i64 to u32"))
97});
98
99imp!(i16, I16);
100imp!(u16, I32, |self| { *self as i32 }, |v| {
101 u16::try_from(v)
102 .map_err(|_| FromDataError::Custom("cannot convert i32 to u32"))
103});
104
105imp!(i8, I16, |self| { *self as i16 }, |v| {
106 i8::try_from(v)
107 .map_err(|_| FromDataError::Custom("cannot convert i16 to i8"))
108}); imp!(u8, I16, |self| { *self as i16 }, |v| {
110 u8::try_from(v)
111 .map_err(|_| FromDataError::Custom("cannot convert i16 to u8"))
112}); impl<T> ColumnType for Option<T>
115where
116 T: ColumnType,
117{
118 #[inline(always)]
119 fn column_kind() -> ColumnKind {
120 ColumnKind::Option(Box::new(T::column_kind()))
121 }
122
123 fn to_data(&self) -> ColumnData<'_> {
124 ColumnData::Option(self.as_ref().map(|t| Box::new(t.to_data())))
125 }
126
127 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
128 match data {
129 ColumnData::Option(v) => match v {
130 Some(v) => Ok(Some(T::from_data(*v)?)),
131 None => Ok(None),
132 },
133 v => Ok(Some(T::from_data(v)?)),
134 }
135 }
136}
137
138impl ColumnType for Vec<String> {
139 #[inline(always)]
140 fn column_kind() -> ColumnKind {
141 ColumnKind::TextArray
142 }
143
144 fn to_data(&self) -> ColumnData<'_> {
145 ColumnData::TextArray(self.as_slice().into())
146 }
147
148 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
149 match data {
150 ColumnData::TextArray(v) => Ok(v.into_vec_owned()),
151 _ => Err(FromDataError::ExpectedType("expected TextArray")),
152 }
153 }
154}
155
156#[cfg(feature = "json")]
157impl ColumnType for serde_json::Value {
158 fn column_kind() -> ColumnKind {
159 ColumnKind::Json
160 }
161
162 fn to_data(&self) -> ColumnData<'_> {
163 let s = serde_json::to_string(self)
164 .expect("could not serialize serde_json::Value");
165 ColumnData::Text(s.into())
166 }
167
168 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
169 match data {
170 ColumnData::Text(s) => serde_json::from_str(s.as_str())
171 .map_err(|e| FromDataError::CustomString(e.to_string())),
172 _ => Err(FromDataError::ExpectedType("json string")),
173 }
174 }
175}
176
177#[cfg(feature = "email")]
178impl ColumnType for email_address::EmailAddress {
179 fn column_kind() -> ColumnKind {
180 ColumnKind::Text
181 }
182
183 fn to_data(&self) -> ColumnData<'_> {
184 ColumnData::Text(self.as_ref().into())
185 }
186
187 fn from_data(data: ColumnData) -> Result<Self, FromDataError> {
188 match data {
189 ColumnData::Text(s) => {
190 s.as_str().parse().map_err(|e: email_address::Error| {
191 FromDataError::CustomString(e.to_string())
192 })
193 }
194 _ => Err(FromDataError::ExpectedType("EmailAddress")),
195 }
196 }
197}