good_ormning/runtime/
sqlite.rs1#[cfg(feature = "chrono")]
2use chrono::{
3 DateTime,
4 Utc,
5 FixedOffset,
6};
7#[cfg(feature = "jiff")]
8use jiff::{
9 Zoned,
10 Timestamp,
11};
12
13pub trait GoodErrorQuery<T> {
14 fn to_good_error_query(self, query: &str) -> Result<T, loga::Error>;
15}
16
17impl<T> GoodErrorQuery<T> for Result<T, rusqlite::Error> {
18 fn to_good_error_query(self, query: &str) -> Result<T, loga::Error> {
19 match self {
20 Ok(v) => Ok(v),
21 Err(e) => Err(loga::err(e).context(format!("Error executing query: {}", query))),
22 }
23 }
24}
25
26pub trait SqliteConnection {
27 fn execute(&mut self, query: &str, params: impl rusqlite::Params) -> rusqlite::Result<usize>;
28 fn query<
29 T,
30 F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>,
31 >(&mut self, query: &str, params: impl rusqlite::Params, f: F) -> rusqlite::Result<Vec<T>>;
32 fn load_array_module(&mut self) -> rusqlite::Result<()>;
33}
34
35impl SqliteConnection for rusqlite::Connection {
36 fn execute(&mut self, query: &str, params: impl rusqlite::Params) -> rusqlite::Result<usize> {
37 rusqlite::Connection::execute(self, query, params)
38 }
39
40 fn query<
41 T,
42 F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>,
43 >(&mut self, query: &str, params: impl rusqlite::Params, mut f: F) -> rusqlite::Result<Vec<T>> {
44 let mut stmt = self.prepare(query)?;
45 let rows = stmt.query_map(params, |row| f(row))?;
46 let mut res = vec![];
47 for row in rows {
48 res.push(row?);
49 }
50 Ok(res)
51 }
52
53 fn load_array_module(&mut self) -> rusqlite::Result<()> {
54 rusqlite::vtab::array::load_module(self)
55 }
56}
57
58impl SqliteConnection for rusqlite::Transaction<'_> {
59 fn execute(&mut self, query: &str, params: impl rusqlite::Params) -> rusqlite::Result<usize> {
60 rusqlite::Connection::execute(self, query, params)
61 }
62
63 fn query<
64 T,
65 F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>,
66 >(&mut self, query: &str, params: impl rusqlite::Params, mut f: F) -> rusqlite::Result<Vec<T>> {
67 let mut stmt = self.prepare(query)?;
68 let rows = stmt.query_map(params, |row| f(row))?;
69 let mut res = vec![];
70 for row in rows {
71 res.push(row?);
72 }
73 Ok(res)
74 }
75
76 fn load_array_module(&mut self) -> rusqlite::Result<()> {
77 Ok(())
79 }
80}
81
82pub enum GoodOrmningSqliteTimestamp {
83 String(String),
84 I64(i64),
85}
86
87impl rusqlite::types::ToSql for GoodOrmningSqliteTimestamp {
88 fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
89 match self {
90 GoodOrmningSqliteTimestamp::String(s) => Ok(
91 rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Text(s.clone())),
92 ),
93 GoodOrmningSqliteTimestamp::I64(i) => Ok(
94 rusqlite::types::ToSqlOutput::Owned(rusqlite::types::Value::Integer(*i)),
95 ),
96 }
97 }
98}
99
100impl rusqlite::types::FromSql for GoodOrmningSqliteTimestamp {
101 fn column_result(value: rusqlite::types::ValueRef<'_>) -> Result<Self, rusqlite::types::FromSqlError> {
102 match value {
103 rusqlite::types::ValueRef::Text(s) => {
104 let s = std::str::from_utf8(s).map_err(|e| rusqlite::types::FromSqlError::Other(Box::new(e)))?;
105 Ok(GoodOrmningSqliteTimestamp::String(s.to_string()))
106 },
107 rusqlite::types::ValueRef::Integer(i) => {
108 Ok(GoodOrmningSqliteTimestamp::I64(i))
109 },
110 _ => Err(rusqlite::types::FromSqlError::InvalidType),
111 }
112 }
113}
114
115impl From<GoodOrmningSqliteTimestamp> for rusqlite::types::Value {
116 fn from(val: GoodOrmningSqliteTimestamp) -> Self {
117 match val {
118 GoodOrmningSqliteTimestamp::String(s) => rusqlite::types::Value::Text(s),
119 GoodOrmningSqliteTimestamp::I64(i) => rusqlite::types::Value::Integer(i),
120 }
121 }
122}
123
124pub trait GoodOrmningCustomAuto<T> {
125 fn to_sql(value: &T) -> i64;
126 fn from_sql(value: i64) -> Result<T, String>;
127}
128
129pub trait GoodOrmningCustomBool<T> {
130 fn to_sql(value: &T) -> bool;
131 fn from_sql(value: bool) -> Result<T, String>;
132}
133
134pub trait GoodOrmningCustomI16<T> {
135 fn to_sql(value: &T) -> i16;
136 fn from_sql(value: i16) -> Result<T, String>;
137}
138
139pub trait GoodOrmningCustomI32<T> {
140 fn to_sql(value: &T) -> i32;
141 fn from_sql(value: i32) -> Result<T, String>;
142}
143
144pub trait GoodOrmningCustomI64<T> {
145 fn to_sql(value: &T) -> i64;
146 fn from_sql(value: i64) -> Result<T, String>;
147}
148
149pub trait GoodOrmningCustomU32<T> {
150 fn to_sql(value: &T) -> u32;
151 fn from_sql(value: u32) -> Result<T, String>;
152}
153
154pub trait GoodOrmningCustomF32<T> {
155 fn to_sql(value: &T) -> f32;
156 fn from_sql(value: f32) -> Result<T, String>;
157}
158
159pub trait GoodOrmningCustomF64<T> {
160 fn to_sql(value: &T) -> f64;
161 fn from_sql(value: f64) -> Result<T, String>;
162}
163
164pub trait GoodOrmningCustomString<T> {
165 fn to_sql<'a>(value: &'a T) -> String;
166 fn from_sql(value: String) -> Result<T, String>;
167}
168
169pub trait GoodOrmningCustomBytes<T> {
170 fn to_sql<'a>(value: &'a T) -> Vec<u8>;
171 fn from_sql(value: Vec<u8>) -> Result<T, String>;
172}
173
174#[cfg(feature = "chrono")]
175pub trait GoodOrmningCustomUtcTimeChrono<T> {
176 fn to_sql(value: &T) -> DateTime<Utc>;
177 fn from_sql(value: DateTime<Utc>) -> Result<T, String>;
178}
179
180#[cfg(feature = "chrono")]
181pub trait GoodOrmningCustomFixedOffsetTimeChrono<T> {
182 fn to_sql(value: &T) -> DateTime<FixedOffset>;
183 fn from_sql(value: DateTime<FixedOffset>) -> Result<T, String>;
184}
185
186#[cfg(feature = "jiff")]
187pub trait GoodOrmningCustomUtcTimeJiff<T> {
188 fn to_sql(value: &T) -> Timestamp;
189 fn from_sql(value: Timestamp) -> Result<T, String>;
190}
191
192#[cfg(feature = "jiff")]
193pub trait GoodOrmningCustomFixedOffsetTimeJiff<T> {
194 fn to_sql(value: &T) -> Zoned;
195 fn from_sql(value: Zoned) -> Result<T, String>;
196}