ft_sys_shared/
sqlite.rs

1/// Determines how a bind parameter is given to SQLite
2///
3/// Diesel deals with bind parameters after serialization as opaque blobs of
4/// bytes. However, SQLite instead has several functions where it expects the
5/// relevant C types.
6///
7/// The variants of this struct determine what bytes are expected from
8/// `ToSql` impls.
9#[allow(missing_debug_implementations)]
10#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, serde::Deserialize, serde::Serialize)]
11pub enum SqliteType {
12    Null,
13    Integer,
14    Real,
15    Text,
16    Blob,
17}
18
19#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
20pub enum SqliteRawValue {
21    Null,
22    Integer(i64),
23    Real(f64),
24    Text(String),
25    Blob(Vec<u8>),
26}
27
28impl SqliteRawValue {
29    pub fn kind(&self) -> SqliteType {
30        match self {
31            SqliteRawValue::Null => SqliteType::Null,
32            SqliteRawValue::Integer(_) => SqliteType::Integer,
33            SqliteRawValue::Real(_) => SqliteType::Real,
34            SqliteRawValue::Text(_) => SqliteType::Text,
35            SqliteRawValue::Blob(_) => SqliteType::Blob,
36        }
37    }
38
39    pub fn as_str(&self) -> Option<&str> {
40        match self {
41            SqliteRawValue::Text(s) => Some(s),
42            _ => None,
43        }
44    }
45}
46
47impl From<i32> for SqliteRawValue {
48    fn from(i: i32) -> Self {
49        SqliteRawValue::Integer(i as i64)
50    }
51}
52
53impl From<i64> for SqliteRawValue {
54    fn from(i: i64) -> Self {
55        SqliteRawValue::Integer(i)
56    }
57}
58
59impl TryFrom<&SqliteRawValue> for i64 {
60    type Error = String;
61    fn try_from(v: &SqliteRawValue) -> Result<Self, Self::Error> {
62        match v {
63            SqliteRawValue::Integer(i) => Ok(*i),
64            _ => Err("not an integer".to_string()),
65        }
66    }
67}
68
69impl From<f64> for SqliteRawValue {
70    fn from(f: f64) -> Self {
71        SqliteRawValue::Real(f)
72    }
73}
74
75impl<T> From<Option<T>> for SqliteRawValue
76where
77    T: Into<SqliteRawValue>,
78{
79    fn from(o: Option<T>) -> Self {
80        match o {
81            Some(v) => v.into(),
82            None => SqliteRawValue::Null,
83        }
84    }
85}
86
87impl<'a> From<&'a str> for SqliteRawValue {
88    fn from(s: &'a str) -> Self {
89        SqliteRawValue::Text(s.to_string())
90    }
91}
92
93impl<'a> TryFrom<&'a SqliteRawValue> for &'a str {
94    type Error = String;
95    fn try_from(v: &'a SqliteRawValue) -> Result<Self, Self::Error> {
96        match v {
97            SqliteRawValue::Text(s) => Ok(s),
98            _ => Err("unknown value".to_string()),
99        }
100    }
101}
102
103impl From<String> for SqliteRawValue {
104    fn from(s: String) -> Self {
105        SqliteRawValue::Text(s)
106    }
107}
108
109impl TryFrom<&SqliteRawValue> for String {
110    type Error = String;
111
112    fn try_from(v: &SqliteRawValue) -> Result<Self, Self::Error> {
113        match v {
114            SqliteRawValue::Text(s) => Ok(s.clone()),
115            _ => Err("unknown value".to_string()),
116        }
117    }
118}
119
120impl From<Vec<u8>> for SqliteRawValue {
121    fn from(b: Vec<u8>) -> Self {
122        SqliteRawValue::Blob(b)
123    }
124}
125
126impl TryFrom<&SqliteRawValue> for Vec<u8> {
127    type Error = String;
128
129    fn try_from(v: &SqliteRawValue) -> Result<Self, Self::Error> {
130        match v {
131            SqliteRawValue::Blob(b) => Ok(b.clone()),
132            SqliteRawValue::Text(b) => Ok(b.to_string().into_bytes()),
133            _ => Err(format!("not a blob or string, found: {v:?}")),
134        }
135    }
136}
137
138impl<'a> From<&'a [u8]> for SqliteRawValue {
139    fn from(b: &'a [u8]) -> Self {
140        SqliteRawValue::Blob(b.to_vec())
141    }
142}
143
144impl From<&chrono::DateTime<chrono::Utc>> for SqliteRawValue {
145    fn from(d: &chrono::DateTime<chrono::Utc>) -> Self {
146        SqliteRawValue::Integer(d.timestamp_nanos_opt().unwrap())
147    }
148}
149
150impl From<&mut chrono::DateTime<chrono::Utc>> for SqliteRawValue {
151    fn from(d: &mut chrono::DateTime<chrono::Utc>) -> Self {
152        SqliteRawValue::Integer(d.timestamp_nanos_opt().unwrap())
153    }
154}
155
156impl From<chrono::DateTime<chrono::Utc>> for SqliteRawValue {
157    fn from(d: chrono::DateTime<chrono::Utc>) -> Self {
158        SqliteRawValue::Integer(d.timestamp_nanos_opt().unwrap())
159    }
160}
161
162impl<'a> TryFrom<&'a SqliteRawValue> for chrono::DateTime<chrono::Utc> {
163    type Error = String;
164    fn try_from(v: &'a SqliteRawValue) -> Result<Self, Self::Error> {
165        match v {
166            SqliteRawValue::Integer(i) => Ok(chrono::DateTime::from_timestamp_nanos(*i)),
167            _ => Err("unknown value".to_string()),
168        }
169    }
170}
171
172impl<'a> TryFrom<&'a SqliteRawValue> for bool {
173    type Error = String;
174    fn try_from(v: &'a SqliteRawValue) -> Result<Self, Self::Error> {
175        match v {
176            SqliteRawValue::Integer(0) => Ok(false),
177            SqliteRawValue::Integer(1) => Ok(true),
178            _ => Err("unknown value".to_string()),
179        }
180    }
181}
182
183#[cfg(feature = "rusqlite")]
184impl rusqlite::ToSql for SqliteRawValue {
185    fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
186        match self {
187            SqliteRawValue::Null => Ok(rusqlite::types::ToSqlOutput::Owned(
188                rusqlite::types::Value::Null,
189            )),
190            SqliteRawValue::Integer(i) => Ok(rusqlite::types::ToSqlOutput::Owned(
191                rusqlite::types::Value::Integer(*i),
192            )),
193            SqliteRawValue::Real(f) => Ok(rusqlite::types::ToSqlOutput::Owned(
194                rusqlite::types::Value::Real(*f),
195            )),
196            SqliteRawValue::Text(s) => Ok(rusqlite::types::ToSqlOutput::Owned(
197                rusqlite::types::Value::Text(s.clone()),
198            )),
199            SqliteRawValue::Blob(b) => Ok(rusqlite::types::ToSqlOutput::Owned(
200                rusqlite::types::Value::Blob(b.clone()),
201            )),
202        }
203    }
204}