1use crate::error::Result;
2use async_trait::async_trait;
3use serde_json::Value;
4use std::collections::HashMap;
5
6#[derive(Debug, Clone)]
8pub struct QueryRow {
9 pub columns: HashMap<String, Value>,
10}
11
12impl QueryRow {
13 pub fn new() -> Self {
14 Self {
15 columns: HashMap::new(),
16 }
17 }
18
19 pub fn insert(&mut self, key: String, value: Value) {
20 self.columns.insert(key, value);
21 }
22
23 pub fn get<T>(&self, key: &str) -> Option<T>
24 where
25 T: serde::de::DeserializeOwned,
26 {
27 self.columns
28 .get(key)
29 .and_then(|v| serde_json::from_value(v.clone()).ok())
30 }
31
32 pub fn get_string(&self, key: &str) -> Option<String> {
33 self.columns
34 .get(key)
35 .and_then(|v| v.as_str().map(String::from))
36 }
37
38 pub fn get_i64(&self, key: &str) -> Option<i64> {
39 self.columns.get(key).and_then(|v| v.as_i64())
40 }
41
42 pub fn get_f64(&self, key: &str) -> Option<f64> {
43 self.columns.get(key).and_then(|v| v.as_f64())
44 }
45
46 pub fn get_bool(&self, key: &str) -> Option<bool> {
47 self.columns.get(key).and_then(|v| v.as_bool())
48 }
49}
50
51impl Default for QueryRow {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57pub type QueryResult = Vec<QueryRow>;
59
60#[async_trait]
62pub trait DatabaseBackend: Send + Sync {
63 async fn connect(url: &str) -> Result<Self>
65 where
66 Self: Sized;
67
68 async fn execute(&mut self, sql: &str) -> Result<u64>;
70
71 async fn query(&mut self, sql: &str) -> Result<QueryResult>;
73
74 async fn begin_transaction(&mut self) -> Result<()>;
76
77 async fn commit(&mut self) -> Result<()>;
79
80 async fn rollback(&mut self) -> Result<()>;
82
83 fn is_connected(&self) -> bool;
85
86 async fn close(self) -> Result<()>;
88}
89
90pub struct Transaction<'a, B: DatabaseBackend> {
92 backend: &'a mut B,
93 committed: bool,
94}
95
96impl<'a, B: DatabaseBackend> Transaction<'a, B> {
97 pub async fn new(backend: &'a mut B) -> Result<Self> {
98 backend.begin_transaction().await?;
99 Ok(Self {
100 backend,
101 committed: false,
102 })
103 }
104
105 pub async fn commit(mut self) -> Result<()> {
106 self.backend.commit().await?;
107 self.committed = true;
108 Ok(())
109 }
110
111 pub async fn execute(&mut self, sql: &str) -> Result<u64> {
112 self.backend.execute(sql).await
113 }
114
115 pub async fn query(&mut self, sql: &str) -> Result<QueryResult> {
116 self.backend.query(sql).await
117 }
118}
119
120impl<'a, B: DatabaseBackend> Drop for Transaction<'a, B> {
121 fn drop(&mut self) {
122 if !self.committed {
123 }
127 }
128}