rdbc_rs/future/
datasource.rs

1//! SQL driver register center
2//!
3//! Global DataSource api avaliable on feature *global*
4
5use std::{
6    collections::HashMap,
7    sync::{Arc, Mutex},
8};
9
10use crate::{driver, Database};
11
12use anyhow::*;
13
14use super::ConnectionPool;
15
16pub type BoxedDriver = Box<dyn driver::Driver + 'static>;
17
18/// DataSource makes a database driver availiable by the provided name.
19///
20/// If register driver with same name twice, it panics.
21#[derive(Clone, Default)]
22#[allow(dead_code)]
23pub struct DataSource {
24    drivers: Arc<Mutex<HashMap<String, Arc<Mutex<BoxedDriver>>>>>,
25}
26
27impl DataSource {
28    /// Register new driver with driver name.
29    ///
30    /// # Arguments
31    /// * `name` - Driver register name, if register driver name twice, method return [`Err`].
32    ///
33    pub fn register<S>(&self, name: S, driver: impl driver::Driver + 'static) -> Result<()>
34    where
35        S: Into<String> + AsRef<str>,
36    {
37        let mut drivers = self.drivers.lock().unwrap();
38
39        if drivers.contains_key(name.as_ref()) {
40            return Err(anyhow!("register driver {} twice", name.as_ref()));
41        }
42
43        drivers.insert(name.into(), Arc::new(Mutex::new(Box::new(driver))));
44
45        Ok(())
46    }
47
48    /// Create a new connection pool for the `url`
49    /// using given [`ConnectionPool`](super::ConnectionPool)
50    ///
51    /// # Arguments
52    ///
53    /// * `name` - Driver name
54    /// * `url` - SQL driver connection url
55    ///
56    pub fn open_with<S, DB>(&self, name: S, url: S) -> Result<DB>
57    where
58        S: Into<String> + AsRef<str>,
59        DB: ConnectionPool + Sync + Send,
60    {
61        let drivers = self.drivers.lock().unwrap();
62        let driver = drivers.get(name.as_ref());
63
64        if let Some(driver) = driver {
65            DB::new(name, driver.clone(), url)
66        } else {
67            return Err(anyhow!("driver {} not found", name.as_ref()));
68        }
69    }
70
71    /// Create a new connection pool for the connection string
72    /// using default [`ConnectionPool`](super::ConnectionPool) implementation [`Database`](super::Database)
73    pub fn open<S>(&self, name: S, url: S) -> Result<Database>
74    where
75        S: Into<String> + AsRef<str>,
76    {
77        self.open_with(name, url)
78    }
79}
80
81mod global {
82
83    use super::*;
84
85    fn global_datasource() -> &'static mut DataSource {
86        static mut CONF: std::mem::MaybeUninit<DataSource> = std::mem::MaybeUninit::uninit();
87        static ONCE: std::sync::Once = std::sync::Once::new();
88        ONCE.call_once(|| unsafe {
89            CONF.as_mut_ptr().write(DataSource::default());
90        });
91        unsafe { &mut *CONF.as_mut_ptr() }
92    }
93
94    pub fn register<S>(name: S, driver: impl driver::Driver + 'static) -> Result<()>
95    where
96        S: Into<String> + AsRef<str>,
97    {
98        global_datasource().register(name, driver)
99    }
100
101    pub fn open_with<S, DB>(name: S, url: S) -> Result<DB>
102    where
103        S: Into<String> + AsRef<str>,
104        DB: ConnectionPool + Sync + Send,
105    {
106        global_datasource().open_with(name, url)
107    }
108
109    pub fn open<S>(name: S, url: S) -> Result<Database>
110    where
111        S: Into<String> + AsRef<str>,
112    {
113        global_datasource().open_with(name, url)
114    }
115}
116
117pub use global::*;
118
119#[cfg(test)]
120mod tests {
121
122    use crate::driver::Driver;
123
124    use super::DataSource;
125
126    struct NullDriver {}
127
128    impl Driver for NullDriver {
129        fn open(&mut self, _url: &str) -> anyhow::Result<Box<dyn crate::driver::Connection>> {
130            unimplemented!()
131        }
132    }
133
134    #[test]
135    fn test_register() {
136        let ds = DataSource::default();
137
138        _ = ds.register("".to_owned(), NullDriver {});
139    }
140}