fire_postgres/table/column/
column_type.rs

1use 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);
77/*imp!(char, Char(1),// maybe change this to char?
78	|self| {*self as &str},
79	|v| {v.chars().next().ok_or(FromDataError::Custom("no char found, expected 1"))}
80);*/
81
82imp!(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); // maybe should panic???
90
91imp!(f32, F32);
92imp!(i32, I32);
93imp!(u32, I64, |self| { *self as i64 }, |v| {
94	// maybe we dont need to convert
95	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}); // i thing there is another type??
109imp!(u8, I16, |self| { *self as i16 }, |v| {
110	u8::try_from(v)
111		.map_err(|_| FromDataError::Custom("cannot convert i16 to u8"))
112}); // maybe char
113
114impl<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}