bb8_libsql/
lib.rs

1#![deny(warnings)]
2//! # Sqlite support for the `bb8` connection pool.
3//!
4//! Library crate: [bb8-libsql]()
5//!
6//! Integrated with: [bb8](https://crates.io/crates/bb8)
7//! and [libsql](https://crates.io/crates/libsql)
8//!
9//! ## Example
10//!
11//! ```rust,no_run
12//! use std::{env, error::Error};
13//! use r2d2_libsql::LibsqlConnectionManager;
14//!  
15//! use dotenvy::dotenv;
16//!  
17//! #[tokio::main]
18//! async fn main() -> Result<(), Box<dyn Error>> {
19//!     dotenv().ok();
20//!  
21//!     let url = env::var("LIBSQL_CLIENT_URL").unwrap();
22//!     let token = env::var("LIBSQL_CLIENT_TOKEN").unwrap();
23//!  
24//!     let manager = LibsqlConnectionManager::remote(&url, &token);
25//!     let pool = bb8::Pool::builder()
26//!         .max_size(15)
27//!         .build(manager)
28//!         .await
29//!         .unwrap();
30//!  
31//!     let conn = pool.get().await?;
32//!     let mut rows = conn.query("SELECT 1;", ()).await?;
33//!  
34//!     let value_found = rows.next().await?
35//!         .map(|row| row.get::<u64>(0))
36//!         .transpose()?;
37//!  
38//!     dbg!(value_found);
39//!  
40//!     Ok(())
41//! }
42//! ```
43pub use libsql;
44use async_trait::async_trait;
45use libsql::Connection;
46use std::fmt;
47use std::path::{Path, PathBuf};
48use std::time::Duration;
49
50pub mod errors;
51
52#[derive(Debug, Clone)]
53enum Source {
54    Local(PathBuf),
55    Remote(String, String),
56    LocalReplica(PathBuf),
57    RemoteReplica(PathBuf, String, String, Duration),
58}
59
60/// An `bb8::ManageConnection` for `libsql::Connection`s.
61pub struct LibsqlConnectionManager { source: Source }
62
63impl fmt::Debug for LibsqlConnectionManager {
64    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65        let mut builder = f.debug_struct("LibsqlConnectionManager");
66        let _ = builder.field("source", &self.source);
67        builder.finish()
68    }
69}
70
71impl LibsqlConnectionManager {
72    /// Creates a new `LibsqlConnectionManager` from local file.
73    /// See `libsql::Builder::new_local`
74    pub fn local<P: AsRef<Path>>(path: P) -> Self {
75        Self {
76            source: Source::Local(
77                path.as_ref().to_path_buf()
78            ),
79        }
80    }
81
82    /// Creates a new `LibsqlConnectionManager` from remote.
83    /// See `libsql::Builder::new_remote`
84    pub fn remote(url: &str, token: &str) -> Self {
85        Self {
86            source: Source::Remote(
87                url.to_string(), 
88                token.to_string()
89            ),
90        }
91    }
92
93    /// Creates a new `LibsqlConnectionManager` from local replica.
94    /// See `libsql::Builder::new_local_replica`
95    pub fn local_replica<P: AsRef<Path>>(path: P) -> Self {
96        Self {
97            source: Source::LocalReplica(
98                path.as_ref().to_path_buf(),
99            ),
100        }
101    }
102
103    /// Creates a new `LibsqlConnectionManager` from remote replica.
104    /// See `libsql::Builder::new_remote_replica`
105    pub fn remote_replica<P: AsRef<Path>>(path: P, url: &str, token: &str, sync_interval: Duration) -> Self {
106        Self {
107            source: Source::RemoteReplica(
108                path.as_ref().to_path_buf(),
109                url.to_string(),
110                token.to_string(),
111                sync_interval
112            ),
113        }
114    }
115}
116
117#[async_trait]
118impl bb8::ManageConnection for LibsqlConnectionManager {
119    type Connection = Connection;
120    type Error = errors::ConnectionManagerError;
121
122    async fn connect(&self) -> Result<Connection, errors::ConnectionManagerError> {
123        Ok(match &self.source {
124            Source::Local(ref path) => {
125                libsql::Builder::new_local(path)
126                    .build().await
127                    .and_then(|builder| builder.connect())
128            },
129            Source::Remote(url, token) => {
130                libsql::Builder::new_remote(url.to_string(), token.to_string())
131                    .build().await
132                    .and_then(|builder| builder.connect())
133            },
134            Source::LocalReplica(path) => {
135                libsql::Builder::new_local_replica(path)
136                    .build().await
137                    .and_then(|builder| builder.connect())
138            },
139            Source::RemoteReplica(path, url, token, sync_interval) => {
140                libsql::Builder::new_remote_replica(path, url.to_string(), token.to_string())
141                    .sync_interval(sync_interval.clone())
142                    .build().await
143                    .and_then(|builder| builder.connect())
144            },
145        }?)
146    }
147
148    async fn is_valid(&self, conn: &mut Connection) -> Result<(), errors::ConnectionManagerError> {
149        Ok(conn.execute_batch("SELECT 1;").await.map(|_| ())?)
150    }
151
152    fn has_broken(&self, _: &mut Connection) -> bool { false }
153}