Skip to main content

rbdc/
db.rs

1use crate::Error;
2use futures_core::future::BoxFuture;
3use rbs::Value;
4use rbs::value::map::ValueMap;
5use std::any::Any;
6use std::fmt::{Debug, Display, Formatter};
7use std::ops::{Deref, DerefMut};
8
9/// Represents database driver that can be shared between threads, and can therefore implement
10/// a connection pool
11pub trait Driver: Debug + Sync + Send {
12    fn name(&self) -> &str;
13    /// Create a connection to the database. Note that connections are intended to be used
14    /// in a single thread since most database connections are not thread-safe
15    fn connect(&self, url: &str) -> BoxFuture<'_, Result<Box<dyn Connection>, Error>>;
16
17    fn connect_opt<'a>(
18        &'a self,
19        opt: &'a dyn ConnectOptions,
20    ) -> BoxFuture<'a, Result<Box<dyn Connection>, Error>>;
21
22    /// make an default option
23    fn default_option(&self) -> Box<dyn ConnectOptions>;
24}
25
26impl Driver for Box<dyn Driver> {
27    fn name(&self) -> &str {
28        self.deref().name()
29    }
30
31    fn connect(&self, url: &str) -> BoxFuture<'_, Result<Box<dyn Connection>, Error>> {
32        self.deref().connect(url)
33    }
34
35    fn connect_opt<'a>(
36        &'a self,
37        opt: &'a dyn ConnectOptions,
38    ) -> BoxFuture<'a, Result<Box<dyn Connection>, Error>> {
39        self.deref().connect_opt(opt)
40    }
41
42    fn default_option(&self) -> Box<dyn ConnectOptions> {
43        self.deref().default_option()
44    }
45}
46
47#[derive(Debug, Default, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
48pub struct ExecResult {
49    pub rows_affected: u64,
50    /// If some databases do not support last_insert_id, the default value is Null
51    pub last_insert_id: Value,
52}
53
54impl Display for ExecResult {
55    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
56        struct DisplayBox<'a> {
57            inner: &'a Value,
58        }
59        impl<'a> Debug for DisplayBox<'a> {
60            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61                std::fmt::Display::fmt(&self.inner, f)
62            }
63        }
64        f.debug_map()
65            .key(&"rows_affected")
66            .value(&self.rows_affected)
67            .key(&"last_insert_id")
68            .value(&DisplayBox {
69                inner: &self.last_insert_id,
70            })
71            .finish()
72    }
73}
74
75impl From<(u64, Value)> for ExecResult {
76    fn from(value: (u64, Value)) -> Self {
77        Self {
78            rows_affected: value.0,
79            last_insert_id: value.1,
80        }
81    }
82}
83
84/// Represents a connection to a database
85pub trait Connection: Send + Sync {
86    /// Execute a query that is expected to return a result set, such as a `SELECT` statement
87    fn exec_rows(
88        &mut self,
89        sql: &str,
90        params: Vec<Value>,
91    ) -> BoxFuture<'_, Result<Vec<Box<dyn Row>>, Error>>;
92
93    /// Execute a query that is expected to return a result set, such as a `SELECT` statement
94    /// return array of [{'column': 'value'}]
95    fn exec_decode(&mut self, sql: &str, params: Vec<Value>) -> BoxFuture<'_, Result<Value, Error>> {
96       let v = self.exec_rows(sql, params);
97        Box::pin(async move {
98            let v = v.await?;
99            let mut rows = Vec::with_capacity(v.len());
100            for mut x in v {
101                let md = x.meta_data();
102                let mut m = ValueMap::with_capacity(md.column_len());
103                for mut i in 0..md.column_len() {
104                    i = md.column_len() - i - 1;
105                    let n = md.column_name(i);
106                    m.insert(Value::String(n), x.get(i)?);
107                }
108                rows.push(Value::Map(m));
109            }
110            Ok(Value::Array(rows))
111        })
112    }
113
114    /// Execute a query that is expected to update some rows.
115    fn exec(&mut self, sql: &str, params: Vec<Value>) -> BoxFuture<'_, Result<ExecResult, Error>>;
116
117    /// ping
118    fn ping(&mut self) -> BoxFuture<'_, Result<(), Error>>;
119
120    /// close connection
121    /// Normally conn is dropped when the link is dropped,
122    /// but it is recommended to actively close this function so that the database does not report errors.
123    /// If &mut self is not satisfied close, when you need mut self,
124    /// It is recommended to use Option<DataBaseConnection>
125    /// and then call take to take ownership and then if let Some(v) = self.inner.take() {v.lose ().await; }
126    fn close(&mut self) -> BoxFuture<'_, Result<(), Error>>;
127
128    /// an translation impl begin
129    fn begin(&mut self) -> BoxFuture<'_, Result<(), Error>> {
130        Box::pin(async {
131            _ = self.exec("begin", vec![]).await?;
132            Ok(())
133        })
134    }
135
136    /// an translation impl commit
137    fn commit(&mut self) -> BoxFuture<'_, Result<(), Error>> {
138        Box::pin(async {
139            _ = self.exec("commit", vec![]).await?;
140            Ok(())
141        })
142    }
143
144    /// an translation impl rollback
145    fn rollback(&mut self) -> BoxFuture<'_, Result<(), Error>> {
146        Box::pin(async {
147            _ = self.exec("rollback", vec![]).await?;
148            Ok(())
149        })
150    }
151}
152
153impl Connection for Box<dyn Connection> {
154    fn exec_rows(
155        &mut self,
156        sql: &str,
157        params: Vec<Value>,
158    ) -> BoxFuture<'_, Result<Vec<Box<dyn Row>>, Error>> {
159        self.deref_mut().exec_rows(sql, params)
160    }
161
162    fn exec_decode(&mut self, sql: &str, params: Vec<Value>) -> BoxFuture<'_, Result<Value, Error>> {
163        self.deref_mut().exec_decode(sql, params)
164    }
165
166    fn exec(&mut self, sql: &str, params: Vec<Value>) -> BoxFuture<'_, Result<ExecResult, Error>> {
167        self.deref_mut().exec(sql, params)
168    }
169
170    fn ping(&mut self) -> BoxFuture<'_, Result<(), Error>> {
171        self.deref_mut().ping()
172    }
173
174    fn close(&mut self) -> BoxFuture<'_, Result<(), Error>> {
175        self.deref_mut().close()
176    }
177
178    fn begin(&mut self) -> BoxFuture<'_, Result<(), Error>> {
179        self.deref_mut().begin()
180    }
181    fn rollback(&mut self) -> BoxFuture<'_, Result<(), Error>> {
182        self.deref_mut().rollback()
183    }
184    fn commit(&mut self) -> BoxFuture<'_, Result<(), Error>> {
185        self.deref_mut().commit()
186    }
187}
188
189/// Result set from executing a query against a statement
190pub trait Row: 'static + Send + Debug {
191    /// get meta data about this result set
192    fn meta_data(&self) -> Box<dyn MetaData>;
193
194    /// get Value from index
195    fn get(&mut self, i: usize) -> Result<Value, Error>;
196}
197
198/// Meta data for result set
199pub trait MetaData: Debug {
200    fn column_len(&self) -> usize;
201    fn column_name(&self, i: usize) -> String;
202    fn column_type(&self, i: usize) -> String;
203}
204
205/// connect option
206pub trait ConnectOptions: Any + Send + Sync + Debug + 'static {
207    /// Establish a new database connection with the options specified by `self`.
208    fn connect(&self) -> BoxFuture<'_, Result<Box<dyn Connection>, Error>>;
209
210    ///set option
211    ///
212    /// for exmample:
213    ///
214    ///```rust
215    /// use std::any::Any;
216    /// pub struct SqliteConnectOptions{
217    ///   pub immutable:bool,
218    /// };
219    ///  impl SqliteConnectOptions{
220    ///             pub fn new()->Self{
221    ///                 Self{
222    ///                     immutable: false,
223    ///                 }
224    ///             }
225    ///             fn set(&mut self, arg: Box<dyn Any>){
226    ///             }
227    ///         }
228    ///
229    /// let mut d = SqliteConnectOptions{immutable:false};
230    ///         d.set(Box::new({
231    ///             let mut new = SqliteConnectOptions::new();
232    ///             new.immutable=true;
233    ///             new
234    ///         }));
235    /// ```
236    ///
237    #[inline]
238    fn set(&mut self, arg: Box<dyn Any>)
239    where
240        Self: Sized,
241    {
242        *self = *arg.downcast().expect("must be self type!");
243    }
244
245    ///set option from uri
246    fn set_uri(&mut self, uri: &str) -> Result<(), Error>;
247}
248
249/// database driver ConnectOptions
250impl dyn ConnectOptions {
251    pub fn downcast_ref<E: ConnectOptions>(&self) -> Option<&E> {
252        <dyn Any>::downcast_ref::<E>(self)
253    }
254
255    pub fn downcast_ref_mut<E: ConnectOptions>(&mut self) -> Option<&mut E> {
256        <dyn Any>::downcast_mut::<E>(self)
257    }
258}
259
260/// make all database drivers support dialect '?'
261/// you can use util package to impl this
262/// for example:
263/// ```rust
264/// use rbdc::db::Placeholder;
265/// pub struct MyPgDriver{}
266/// impl Placeholder for MyPgDriver{
267///     fn exchange(&self, sql: &str) -> String {
268///         rbdc::impl_exchange("$",1,sql)
269///     }
270/// }
271/// ```
272///
273/// for example: postgres driver
274/// ```log
275///  "select * from  table where name = ?"
276/// ```
277/// to
278/// ```log
279/// "select * from  table where name =  $1"
280pub trait Placeholder {
281    fn exchange(&self, sql: &str) -> String;
282}