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