1use crate::error::{HematiteError, Result};
4use crate::query::{
5 DateTimeValue, DateValue, DecimalValue, JournalMode, TimeValue, TimeWithTimeZoneValue, Value,
6};
7use crate::sql::connection::{Connection, PreparedStatement, Transaction};
8use crate::sql::result::{ExecutedStatement, FromRow, ResultSet, Row, StatementResult};
9use crate::sql::script::ScriptIter;
10
11pub struct Hematite {
13 pub connection: Connection,
14}
15
16impl Hematite {
17 pub fn new_in_memory() -> Result<Self> {
19 let connection = Connection::new_in_memory()?;
20 Ok(Self { connection })
21 }
22
23 pub fn new(database_path: &str) -> Result<Self> {
25 let connection = Connection::new(database_path)?;
26 Ok(Self { connection })
27 }
28
29 pub fn execute(&mut self, sql: &str) -> Result<StatementResult> {
31 match self.connection.execute_result(sql)? {
32 ExecutedStatement::Statement(result) => Ok(result),
33 ExecutedStatement::Query(_) => Err(HematiteError::ParseError(
34 "Use query() method for SELECT statements".to_string(),
35 )),
36 }
37 }
38
39 pub fn query(&mut self, sql: &str) -> Result<ResultSet> {
41 match self.connection.execute_result(sql)? {
42 ExecutedStatement::Query(result_set) => Ok(result_set),
43 ExecutedStatement::Statement(_) => Err(HematiteError::ParseError(
44 "Use execute() method for non-SELECT statements".to_string(),
45 )),
46 }
47 }
48
49 pub fn query_row<F, R>(&mut self, sql: &str, f: F) -> Result<Option<R>>
51 where
52 F: FnOnce(&Row) -> Result<R>,
53 {
54 let result_set = self.query(sql)?;
55
56 if let Some(row) = result_set.get_row(0) {
57 Ok(Some(f(row)?))
58 } else {
59 Ok(None)
60 }
61 }
62
63 pub fn query_one<T>(&mut self, sql: &str) -> Result<Option<T>>
65 where
66 T: FromValue,
67 {
68 self.query_row(sql, |row| {
69 if let Some(value) = row.get(0) {
70 T::from_value(value)
71 } else {
72 Err(HematiteError::ParseError("No value found".to_string()))
73 }
74 })
75 }
76
77 pub fn query_as<T>(&mut self, sql: &str) -> Result<Vec<T>>
78 where
79 T: FromRow,
80 {
81 self.query(sql)?.to_structs()
82 }
83
84 pub fn query_one_as<T>(&mut self, sql: &str) -> Result<Option<T>>
85 where
86 T: FromRow,
87 {
88 self.query(sql)?.get_row(0).map(T::from_row).transpose()
89 }
90
91 pub fn prepare(&mut self, sql: &str) -> Result<PreparedStatement> {
93 self.connection.prepare(sql)
94 }
95
96 pub fn execute_prepared(&mut self, stmt: &mut PreparedStatement) -> Result<StatementResult> {
98 match ExecutedStatement::from_query_result(stmt.execute(&mut self.connection)?) {
99 ExecutedStatement::Statement(result) => Ok(result),
100 ExecutedStatement::Query(_) => Err(HematiteError::ParseError(
101 "Use query_prepared() method for SELECT statements".to_string(),
102 )),
103 }
104 }
105
106 pub fn execute_result(&mut self, sql: &str) -> Result<ExecutedStatement> {
107 self.connection.execute_result(sql)
108 }
109
110 pub fn iter_script<'a>(&'a mut self, sql: &str) -> Result<ScriptIter<'a>> {
111 self.connection.iter_script(sql)
112 }
113
114 pub fn transaction(&'_ mut self) -> Result<Transaction<'_>> {
116 self.connection.begin_transaction()
117 }
118
119 pub fn journal_mode(&self) -> Result<JournalMode> {
120 self.connection.journal_mode()
121 }
122
123 pub fn set_journal_mode(&mut self, journal_mode: JournalMode) -> Result<()> {
124 self.connection.set_journal_mode(journal_mode)
125 }
126
127 pub fn checkpoint_wal(&mut self) -> Result<()> {
128 self.connection.checkpoint_wal()
129 }
130
131 pub fn execute_batch(&mut self, sql: &str) -> Result<()> {
133 self.connection.execute_batch(sql)
134 }
135}
136
137pub trait FromValue: Sized {
139 fn from_value(value: &Value) -> Result<Self>;
140}
141
142impl FromValue for i32 {
143 fn from_value(value: &Value) -> Result<Self> {
144 match value {
145 Value::Integer(i) => Ok(*i),
146 _ => Err(HematiteError::ParseError(format!(
147 "Expected INT, found {:?}",
148 value
149 ))),
150 }
151 }
152}
153
154impl FromValue for String {
155 fn from_value(value: &Value) -> Result<Self> {
156 match value {
157 Value::Text(s) => Ok(s.clone()),
158 Value::Enum(s) => Ok(s.clone()),
159 Value::Decimal(s) => Ok(s.to_string()),
160 Value::Date(s) => Ok(s.to_string()),
161 Value::Time(s) => Ok(s.to_string()),
162 Value::DateTime(s) => Ok(s.to_string()),
163 Value::TimeWithTimeZone(s) => Ok(s.to_string()),
164 _ => Err(HematiteError::ParseError(format!(
165 "Expected TEXT, found {:?}",
166 value
167 ))),
168 }
169 }
170}
171
172impl FromValue for bool {
173 fn from_value(value: &Value) -> Result<Self> {
174 match value {
175 Value::Boolean(b) => Ok(*b),
176 _ => Err(HematiteError::ParseError(format!(
177 "Expected BOOLEAN, found {:?}",
178 value
179 ))),
180 }
181 }
182}
183
184impl FromValue for f64 {
185 fn from_value(value: &Value) -> Result<Self> {
186 match value {
187 Value::Float32(f) => Ok(*f as f64),
188 Value::Float(f) => Ok(*f),
189 Value::Integer(i) => Ok(*i as f64), Value::UInteger(i) => Ok(*i as f64),
191 Value::BigInt(i) => Ok(*i as f64),
192 Value::UBigInt(i) => Ok(*i as f64),
193 Value::Int128(i) => Ok(*i as f64),
194 Value::UInt128(i) => Ok(*i as f64),
195 _ => Err(HematiteError::ParseError(format!(
196 "Expected FLOAT, found {:?}",
197 value
198 ))),
199 }
200 }
201}
202
203impl FromValue for Value {
204 fn from_value(value: &Value) -> Result<Self> {
205 Ok(value.clone())
206 }
207}
208
209impl FromValue for i64 {
210 fn from_value(value: &Value) -> Result<Self> {
211 match value {
212 Value::BigInt(i) => Ok(*i),
213 Value::Integer(i) => Ok(*i as i64),
214 Value::UInteger(i) => Ok(*i as i64),
215 _ => Err(HematiteError::ParseError(format!(
216 "Expected INT64, found {:?}",
217 value
218 ))),
219 }
220 }
221}
222
223impl FromValue for i128 {
224 fn from_value(value: &Value) -> Result<Self> {
225 match value {
226 Value::Int128(i) => Ok(*i),
227 Value::BigInt(i) => Ok(*i as i128),
228 Value::Integer(i) => Ok(*i as i128),
229 Value::UInteger(i) => Ok(*i as i128),
230 Value::UBigInt(i) => Ok(*i as i128),
231 _ => Err(HematiteError::ParseError(format!(
232 "Expected INT128, found {:?}",
233 value
234 ))),
235 }
236 }
237}
238
239impl FromValue for u32 {
240 fn from_value(value: &Value) -> Result<Self> {
241 match value {
242 Value::UInteger(i) => Ok(*i),
243 Value::Integer(i) if *i >= 0 => Ok(*i as u32),
244 _ => Err(HematiteError::ParseError(format!(
245 "Expected UINT, found {:?}",
246 value
247 ))),
248 }
249 }
250}
251
252impl FromValue for u64 {
253 fn from_value(value: &Value) -> Result<Self> {
254 match value {
255 Value::UBigInt(i) => Ok(*i),
256 Value::UInteger(i) => Ok(*i as u64),
257 Value::Integer(i) if *i >= 0 => Ok(*i as u64),
258 _ => Err(HematiteError::ParseError(format!(
259 "Expected UINT64, found {:?}",
260 value
261 ))),
262 }
263 }
264}
265
266impl FromValue for u128 {
267 fn from_value(value: &Value) -> Result<Self> {
268 match value {
269 Value::UInt128(i) => Ok(*i),
270 Value::UBigInt(i) => Ok(*i as u128),
271 Value::UInteger(i) => Ok(*i as u128),
272 Value::Integer(i) if *i >= 0 => Ok(*i as u128),
273 _ => Err(HematiteError::ParseError(format!(
274 "Expected UINT128, found {:?}",
275 value
276 ))),
277 }
278 }
279}
280
281impl FromValue for DecimalValue {
282 fn from_value(value: &Value) -> Result<Self> {
283 match value {
284 Value::Decimal(value) => Ok(value.clone()),
285 _ => Err(HematiteError::ParseError(format!(
286 "Expected DECIMAL, found {:?}",
287 value
288 ))),
289 }
290 }
291}
292
293impl FromValue for Vec<u8> {
294 fn from_value(value: &Value) -> Result<Self> {
295 match value {
296 Value::Blob(value) => Ok(value.clone()),
297 _ => Err(HematiteError::ParseError(format!(
298 "Expected BLOB, found {:?}",
299 value
300 ))),
301 }
302 }
303}
304
305impl FromValue for DateValue {
306 fn from_value(value: &Value) -> Result<Self> {
307 match value {
308 Value::Date(value) => Ok(*value),
309 _ => Err(HematiteError::ParseError(format!(
310 "Expected DATE, found {:?}",
311 value
312 ))),
313 }
314 }
315}
316
317impl FromValue for DateTimeValue {
318 fn from_value(value: &Value) -> Result<Self> {
319 match value {
320 Value::DateTime(value) => Ok(*value),
321 _ => Err(HematiteError::ParseError(format!(
322 "Expected DATETIME, found {:?}",
323 value
324 ))),
325 }
326 }
327}
328
329impl FromValue for TimeValue {
330 fn from_value(value: &Value) -> Result<Self> {
331 match value {
332 Value::Time(value) => Ok(*value),
333 _ => Err(HematiteError::ParseError(format!(
334 "Expected TIME, found {:?}",
335 value
336 ))),
337 }
338 }
339}
340
341impl FromValue for TimeWithTimeZoneValue {
342 fn from_value(value: &Value) -> Result<Self> {
343 match value {
344 Value::TimeWithTimeZone(value) => Ok(*value),
345 _ => Err(HematiteError::ParseError(format!(
346 "Expected TIME WITH TIME ZONE, found {:?}",
347 value
348 ))),
349 }
350 }
351}
352
353pub struct HematiteBuilder {
355 database_path: String,
356}
357
358impl HematiteBuilder {
359 pub fn new() -> Self {
360 Self {
361 database_path: "_test.db".to_string(),
362 }
363 }
364
365 pub fn database_path(mut self, path: &str) -> Self {
366 self.database_path = path.to_string();
367 self
368 }
369
370 pub fn build(self) -> Result<Hematite> {
371 Hematite::new(&self.database_path)
372 }
373}
374
375impl Default for HematiteBuilder {
376 fn default() -> Self {
377 Self::new()
378 }
379}