diff --git a/Cargo.toml b/Cargo.toml index 5da5ac6a..a3c6f254 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ features = ["gnome_46"] [dependencies.sqlite] package = "rusqlite" -version = "0.32.1" +version = "0.34.0" [dependencies.sourceview] package = "sourceview5" @@ -38,6 +38,8 @@ itertools = "0.14.0" libspelling = "0.3.0" openssl = "0.10.70" plurify = "0.2.0" +r2d2 = "0.8.10" +r2d2_sqlite = "0.27.0" syntect = "5.2.0" # development diff --git a/src/app.rs b/src/app.rs index 470ae7d7..c4a6a9cb 100644 --- a/src/app.rs +++ b/src/app.rs @@ -42,7 +42,7 @@ impl App { let profile = profile.clone(); move |this| { // Init readable connection - match profile.database.connection.read() { + match profile.database.pool.get() { Ok(connection) => { // Create transaction match connection.unchecked_transaction() { @@ -77,7 +77,7 @@ impl App { let profile = profile.clone(); move |_| { match profile.save() { - Ok(_) => match profile.database.connection.write() { + Ok(_) => match profile.database.pool.get() { Ok(mut connection) => { // Create transaction match connection.transaction() { @@ -266,7 +266,7 @@ impl App { pub fn run(&self) -> Result { // Begin database migration @TODO { - let mut connection = self.profile.database.connection.write().unwrap(); + let mut connection = self.profile.database.pool.get()?; let transaction = connection.transaction()?; migrate(&transaction)?; transaction.commit()?; diff --git a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save.rs b/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save.rs index f6da5e50..89140c60 100644 --- a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save.rs +++ b/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save.rs @@ -46,7 +46,7 @@ impl Save { button.set_sensitive(false); // Create PEM file based on option ID selected - match Certificate::new(profile.clone(), profile_identity_id) { + match Certificate::build(profile.clone(), profile_identity_id) { Ok(certificate) => { // Init file filters related with PEM extension let filters = ListStore::new::(); diff --git a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate.rs b/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate.rs index 22cdd6e3..bc9be18e 100644 --- a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate.rs +++ b/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate.rs @@ -1,5 +1,4 @@ -mod error; -pub use error::Error; +use anyhow::{bail, Result}; use crate::profile::Profile; use gtk::{gio::TlsCertificate, prelude::TlsCertificateExt}; @@ -15,19 +14,17 @@ impl Certificate { // Constructors /// Create new `Self` - pub fn new(profile: Rc, profile_identity_id: i64) -> Result { - match profile.identity.database.record(profile_identity_id) { - Ok(record) => match record { - Some(identity) => match TlsCertificate::from_pem(&identity.pem) { - Ok(certificate) => Ok(Self { - data: identity.pem, - name: certificate.subject_name().unwrap().replace("CN=", ""), - }), - Err(e) => Err(Error::TlsCertificate(e)), - }, - None => Err(Error::NotFound(profile_identity_id)), - }, - Err(e) => Err(Error::Database(e)), + pub fn build(profile: Rc, profile_identity_id: i64) -> Result { + let record = profile.identity.database.record(profile_identity_id)?; + match record { + Some(identity) => Ok(Self { + name: TlsCertificate::from_pem(&identity.pem)? + .subject_name() + .unwrap_or_default() + .replace("CN=", ""), + data: identity.pem, + }), + None => bail!("Identity not found!"), } } } diff --git a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate/error.rs b/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate/error.rs deleted file mode 100644 index 118b9c41..00000000 --- a/src/app/browser/window/tab/item/page/navigation/request/identity/common/form/save/certificate/error.rs +++ /dev/null @@ -1,25 +0,0 @@ -use gtk::glib; -use std::fmt::{Display, Formatter, Result}; - -#[derive(Debug)] -pub enum Error { - Database(sqlite::Error), - NotFound(i64), - TlsCertificate(glib::Error), -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> Result { - match self { - Self::Database(e) => { - write!(f, "Database error: {e}") - } - Self::NotFound(profile_identity_id) => { - write!(f, "Record for `{profile_identity_id}` not found") - } - Self::TlsCertificate(e) => { - write!(f, "TLS certificate error: {e}") - } - } - } -} diff --git a/src/profile.rs b/src/profile.rs index dca5076a..6e3c72b1 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -4,16 +4,17 @@ mod history; mod identity; mod search; +use anyhow::Result; use bookmark::Bookmark; use database::Database; +use gtk::glib::{user_config_dir, DateTime}; use history::History; use identity::Identity; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; use search::Search; - -use anyhow::Result; -use gtk::glib::{user_config_dir, DateTime}; -use sqlite::{Connection, Transaction}; -use std::{fs::create_dir_all, path::PathBuf, rc::Rc, sync::RwLock}; +use sqlite::Transaction; +use std::{fs::create_dir_all, path::PathBuf}; const VENDOR: &str = "YGGverse"; const APP_ID: &str = "Yoda"; @@ -53,23 +54,24 @@ impl Profile { database_path.push(DB_NAME); // Init database connection - let connection = Rc::new(RwLock::new(Connection::open(database_path.as_path())?)); + let database_pool = + Pool::new(SqliteConnectionManager::file(database_path.as_path())).unwrap(); // Init profile components { // Init writable connection - let mut connection = connection.write().unwrap(); // @TODO handle + let mut connection = database_pool.get()?; // Init new transaction - let transaction = connection.transaction()?; + let tx = connection.transaction()?; // Begin migration - migrate(&transaction)?; - transaction.commit()?; + migrate(&tx)?; + tx.commit()?; } // unlock database // Init model - let database = Database::build(&connection); + let database = Database::build(&database_pool); // Get active profile or create new one let profile_id = match database.active()? { @@ -78,10 +80,10 @@ impl Profile { }; // Init components - let bookmark = Bookmark::build(&connection, profile_id)?; - let history = History::build(&connection, profile_id)?; - let search = Search::build(&connection, profile_id)?; - let identity = Identity::build(&connection, profile_id)?; + let bookmark = Bookmark::build(&database_pool, profile_id)?; + let history = History::build(&database_pool, profile_id)?; + let search = Search::build(&database_pool, profile_id)?; + let identity = Identity::build(&database_pool, profile_id)?; // Result Ok(Self { diff --git a/src/profile/bookmark.rs b/src/profile/bookmark.rs index 98fa88bd..845216ec 100644 --- a/src/profile/bookmark.rs +++ b/src/profile/bookmark.rs @@ -7,11 +7,10 @@ use database::Database; use gtk::glib::DateTime; use item::Item; use memory::Memory; -use sqlite::{Connection, Transaction}; -use std::{ - rc::Rc, - sync::{Arc, RwLock}, -}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; +use std::sync::{Arc, RwLock}; pub struct Bookmark { database: Database, // permanent storage @@ -22,9 +21,9 @@ impl Bookmark { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_id: i64) -> Result { + pub fn build(database_pool: &Pool, profile_id: i64) -> Result { // Init children components - let database = Database::new(connection, profile_id); + let database = Database::new(database_pool, profile_id); let memory = Arc::new(RwLock::new(Memory::new())); // Build initial index diff --git a/src/profile/bookmark/database.rs b/src/profile/bookmark/database.rs index 84159ea5..a488f5bc 100644 --- a/src/profile/bookmark/database.rs +++ b/src/profile/bookmark/database.rs @@ -1,11 +1,12 @@ use super::Item; use anyhow::Result; use gtk::glib::DateTime; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Database { - connection: Rc>, + pool: Pool, profile_id: i64, } @@ -13,9 +14,9 @@ impl Database { // Constructors /// Create new `Self` - pub fn new(connection: &Rc>, profile_id: i64) -> Self { + pub fn new(pool: &Pool, profile_id: i64) -> Self { Self { - connection: connection.clone(), + pool: pool.clone(), profile_id, } } @@ -24,9 +25,12 @@ impl Database { /// Get bookmark records from database with optional filter by `request` pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result> { - let readable = self.connection.read().unwrap(); // @TODO - let tx = readable.unchecked_transaction()?; - select(&tx, self.profile_id, request, title) + select( + &self.pool.get()?.unchecked_transaction()?, + self.profile_id, + request, + title, + ) } // Setters @@ -34,8 +38,8 @@ impl Database { /// Create new bookmark record in database /// * return last insert ID on success pub fn add(&self, time: DateTime, request: &str, title: Option<&str>) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; let id = insert(&tx, self.profile_id, time, request, title)?; tx.commit()?; Ok(id) @@ -43,8 +47,8 @@ impl Database { /// Delete bookmark record from database pub fn delete(&self, id: i64) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; let usize = delete(&tx, id)?; tx.commit()?; Ok(usize) diff --git a/src/profile/database.rs b/src/profile/database.rs index 7c0114c8..b34039bf 100644 --- a/src/profile/database.rs +++ b/src/profile/database.rs @@ -1,7 +1,8 @@ use anyhow::Result; use gtk::glib::DateTime; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Table { pub id: i64, @@ -11,26 +12,22 @@ pub struct Table { } pub struct Database { - pub connection: Rc>, + pub pool: Pool, } impl Database { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>) -> Self { - Self { - connection: connection.clone(), - } + pub fn build(pool: &Pool) -> Self { + Self { pool: pool.clone() } } // Getters /// Get all records pub fn records(&self) -> Result> { - let readable = self.connection.read().unwrap(); - let tx = readable.unchecked_transaction()?; - select(&tx) + select(&self.pool.get()?.unchecked_transaction()?) } /// Get active profile record if exist @@ -43,8 +40,8 @@ impl Database { /// Create new record in `Self` database connected pub fn add(&self, is_active: bool, time: DateTime, name: Option) -> Result { - let mut writable = self.connection.write().unwrap(); - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; if is_active { for record in select(&tx)? { update(&tx, record.id, false, record.time, record.name)?; diff --git a/src/profile/history.rs b/src/profile/history.rs index 876b1bb2..0d7cacf0 100644 --- a/src/profile/history.rs +++ b/src/profile/history.rs @@ -7,11 +7,10 @@ use database::Database; use gtk::glib::GString; use item::{Event, Item}; use memory::Memory; -use sqlite::{Connection, Transaction}; -use std::{ - rc::Rc, - sync::{Arc, RwLock}, -}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; +use std::sync::{Arc, RwLock}; pub struct History { database: Database, // permanent storage @@ -22,9 +21,9 @@ impl History { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_id: i64) -> Result { + pub fn build(database_pool: &Pool, profile_id: i64) -> Result { // Init children components - let database = Database::build(connection, profile_id); + let database = Database::build(database_pool, profile_id); let memory = Arc::new(RwLock::new(Memory::new())); for item in database.records(None, None)? { diff --git a/src/profile/history/database.rs b/src/profile/history/database.rs index 9e3f442e..7273d838 100644 --- a/src/profile/history/database.rs +++ b/src/profile/history/database.rs @@ -1,11 +1,12 @@ use super::{item::Event, Item}; use anyhow::Result; use gtk::glib::DateTime; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Database { - connection: Rc>, + pool: Pool, profile_id: i64, } @@ -13,9 +14,9 @@ impl Database { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_id: i64) -> Self { + pub fn build(pool: &Pool, profile_id: i64) -> Self { Self { - connection: connection.clone(), + pool: pool.clone(), profile_id, } } @@ -24,9 +25,12 @@ impl Database { /// Get history records from database with optional filter by `request` pub fn records(&self, request: Option<&str>, title: Option<&str>) -> Result> { - let readable = self.connection.read().unwrap(); // @TODO - let tx = readable.unchecked_transaction()?; - select(&tx, self.profile_id, request, title) + select( + &self.pool.get()?.unchecked_transaction()?, + self.profile_id, + request, + title, + ) } // Actions @@ -34,16 +38,16 @@ impl Database { /// Create new history record in database /// * return last insert ID on success pub fn add(&self, item: &Item) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; let id = insert(&tx, self.profile_id, item)?; tx.commit()?; Ok(id) } pub fn update(&self, item: &Item) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; let affected = update(&tx, self.profile_id, item)?; tx.commit()?; Ok(affected) diff --git a/src/profile/identity.rs b/src/profile/identity.rs index 9d44545a..68d03d81 100644 --- a/src/profile/identity.rs +++ b/src/profile/identity.rs @@ -10,8 +10,9 @@ use database::Database; use gtk::glib::DateTime; use item::Item; use memory::Memory; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; /// Authorization wrapper for Gemini protocol /// @@ -26,10 +27,13 @@ impl Identity { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_identity_id: i64) -> Result { + pub fn build( + database_pool: &Pool, + profile_identity_id: i64, + ) -> Result { // Init components - let auth = Auth::build(connection)?; - let database = Database::build(connection, profile_identity_id); + let auth = Auth::build(database_pool)?; + let database = Database::build(database_pool, profile_identity_id); let memory = Memory::new(); // Init `Self` diff --git a/src/profile/identity/auth.rs b/src/profile/identity/auth.rs index 5b54a8a9..8ce523dc 100644 --- a/src/profile/identity/auth.rs +++ b/src/profile/identity/auth.rs @@ -6,24 +6,25 @@ mod memory; use anyhow::Result; use database::Database; use memory::Memory; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; /// Auth pair operations pub struct Auth { - database: Rc, - memory: Rc, + database: Database, + memory: Memory, } impl Auth { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>) -> Result { + pub fn build(database_pool: &Pool) -> Result { // Init `Self` let this = Self { - database: Rc::new(Database::build(connection)), - memory: Rc::new(Memory::new()), + database: Database::build(database_pool), + memory: Memory::new(), }; // Build initial index diff --git a/src/profile/identity/auth/database.rs b/src/profile/identity/auth/database.rs index 45631178..ac4faae7 100644 --- a/src/profile/identity/auth/database.rs +++ b/src/profile/identity/auth/database.rs @@ -1,6 +1,7 @@ use anyhow::Result; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Table { pub id: i64, @@ -10,25 +11,23 @@ pub struct Table { /// Storage for `profile_identity_id` + `scope` auth pairs pub struct Database { - connection: Rc>, + pool: Pool, } impl Database { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>) -> Self { - Self { - connection: connection.clone(), - } + pub fn build(pool: &Pool) -> Self { + Self { pool: pool.clone() } } // Actions /// Create new record in database pub fn add(&self, profile_identity_id: i64, scope: &str) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; let id = insert(&tx, profile_identity_id, scope)?; tx.commit()?; Ok(id) @@ -36,8 +35,8 @@ impl Database { /// Delete record with given `id` from database pub fn delete(&self, id: i64) -> Result<()> { - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; delete(&tx, id)?; tx.commit()?; Ok(()) @@ -47,16 +46,15 @@ impl Database { /// Get records from database match current `profile_id` optionally filtered by `scope` pub fn records_scope(&self, scope: Option<&str>) -> Result> { - let readable = self.connection.read().unwrap(); // @TODO - let tx = readable.unchecked_transaction()?; - select_scope(&tx, scope) + select_scope(&self.pool.get()?.unchecked_transaction()?, scope) } /// Get records from database match current `profile_id` optionally filtered by `scope` pub fn records_ref(&self, profile_identity_id: i64) -> Result> { - let readable = self.connection.read().unwrap(); // @TODO - let tx = readable.unchecked_transaction()?; - select_ref(&tx, profile_identity_id) + select_ref( + &self.pool.get()?.unchecked_transaction()?, + profile_identity_id, + ) } } diff --git a/src/profile/identity/database.rs b/src/profile/identity/database.rs index 90324a57..718aaf11 100644 --- a/src/profile/identity/database.rs +++ b/src/profile/identity/database.rs @@ -1,5 +1,7 @@ -use sqlite::{Connection, Error, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use anyhow::Result; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Table { pub id: i64, @@ -9,7 +11,7 @@ pub struct Table { /// Storage for Gemini auth certificates pub struct Database { - connection: Rc>, + pool: Pool, profile_id: i64, } @@ -17,9 +19,9 @@ impl Database { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_id: i64) -> Self { + pub fn build(pool: &Pool, profile_id: i64) -> Self { Self { - connection: connection.clone(), + pool: pool.clone(), profile_id, } } @@ -27,10 +29,10 @@ impl Database { // Actions /// Create new record in database - pub fn add(&self, pem: &str) -> Result { + pub fn add(&self, pem: &str) -> Result { // Begin new transaction - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; // Create new record insert(&tx, self.profile_id, pem)?; @@ -39,55 +41,45 @@ impl Database { let id = last_insert_id(&tx); // Done - match tx.commit() { - Ok(_) => Ok(id), - Err(e) => Err(e), - } + tx.commit()?; + Ok(id) } /// Delete record with given `id` from database - pub fn delete(&self, id: i64) -> Result<(), Error> { + pub fn delete(&self, id: i64) -> Result<()> { // Begin new transaction - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; // Create new record delete(&tx, id)?; // Done - match tx.commit() { - Ok(_) => Ok(()), - Err(e) => Err(e), - } + tx.commit()?; + Ok(()) } /// Get single record match `id` - pub fn record(&self, id: i64) -> Result, Error> { - let readable = self.connection.read().unwrap(); - let tx = readable.unchecked_transaction()?; - let records = select(&tx, self.profile_id)?; // @TODO single record query - + pub fn record(&self, id: i64) -> Result> { + let records = select(&self.pool.get()?.unchecked_transaction()?, self.profile_id)?; // @TODO single record query for record in records { if record.id == id { return Ok(Some(record)); } } - Ok(None) } /// Get all records match current `profile_id` - pub fn records(&self) -> Result, Error> { - let readable = self.connection.read().unwrap(); // @TODO - let tx = readable.unchecked_transaction()?; - select(&tx, self.profile_id) + pub fn records(&self) -> Result> { + select(&self.pool.get()?.unchecked_transaction()?, self.profile_id) } } // Low-level DB API -pub fn init(tx: &Transaction) -> Result { - tx.execute( +pub fn init(tx: &Transaction) -> Result { + Ok(tx.execute( "CREATE TABLE IF NOT EXISTS `profile_identity` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -97,24 +89,24 @@ pub fn init(tx: &Transaction) -> Result { FOREIGN KEY (`profile_id`) REFERENCES `profile`(`id`) )", [], - ) + )?) } -pub fn insert(tx: &Transaction, profile_id: i64, pem: &str) -> Result { - tx.execute( +pub fn insert(tx: &Transaction, profile_id: i64, pem: &str) -> Result { + Ok(tx.execute( "INSERT INTO `profile_identity` ( `profile_id`, `pem` ) VALUES (?, ?)", (profile_id, pem), - ) + )?) } -pub fn delete(tx: &Transaction, id: i64) -> Result { - tx.execute("DELETE FROM `profile_identity` WHERE `id` = ?", [id]) +pub fn delete(tx: &Transaction, id: i64) -> Result { + Ok(tx.execute("DELETE FROM `profile_identity` WHERE `id` = ?", [id])?) } -pub fn select(tx: &Transaction, profile_id: i64) -> Result, Error> { +pub fn select(tx: &Transaction, profile_id: i64) -> Result> { let mut stmt = tx.prepare( "SELECT `id`, `profile_id`, diff --git a/src/profile/search.rs b/src/profile/search.rs index f60ef71a..0e04f1c4 100644 --- a/src/profile/search.rs +++ b/src/profile/search.rs @@ -5,8 +5,9 @@ use anyhow::Result; use database::Database; use gtk::glib::Uri; use memory::Memory; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; pub struct Search { database: Database, // permanent storage @@ -17,8 +18,8 @@ impl Search { // Constructors /// Create new `Self` - pub fn build(connection: &Rc>, profile_id: i64) -> Result { - let database = Database::init(connection, profile_id)?; + pub fn build(database_pool: &Pool, profile_id: i64) -> Result { + let database = Database::init(database_pool, profile_id)?; // Init fast search index let memory = Memory::init(); // Build initial index diff --git a/src/profile/search/database.rs b/src/profile/search/database.rs index c15adc54..25429ad7 100644 --- a/src/profile/search/database.rs +++ b/src/profile/search/database.rs @@ -1,6 +1,7 @@ use anyhow::Result; -use sqlite::{Connection, Transaction}; -use std::{rc::Rc, sync::RwLock}; +use r2d2::Pool; +use r2d2_sqlite::SqliteConnectionManager; +use sqlite::Transaction; #[derive(Clone)] pub struct Row { @@ -11,7 +12,7 @@ pub struct Row { } pub struct Database { - connection: Rc>, + pool: Pool, profile_id: i64, } @@ -19,9 +20,9 @@ impl Database { // Constructors /// Create new `Self` - pub fn init(connection: &Rc>, profile_id: i64) -> Result { - let mut writable = connection.write().unwrap(); // @TODO handle - let tx = writable.transaction()?; + pub fn init(pool: &Pool, profile_id: i64) -> Result { + let mut connection = pool.get()?; + let tx = connection.transaction()?; let records = select(&tx, profile_id)?; @@ -31,7 +32,7 @@ impl Database { } Ok(Self { - connection: connection.clone(), + pool: pool.clone(), profile_id, }) } @@ -40,9 +41,7 @@ impl Database { /// Get records from database pub fn records(&self) -> Result> { - let readable = self.connection.read().unwrap(); // @TODO handle - let tx = readable.unchecked_transaction()?; - select(&tx, self.profile_id) + select(&self.pool.get()?.unchecked_transaction()?, self.profile_id) } // Setters @@ -50,8 +49,8 @@ impl Database { /// Create new record in database /// * return last insert ID on success pub fn add(&self, query: String, is_default: bool) -> Result { - let mut writable = self.connection.write().unwrap(); // @TODO handle - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; if is_default { reset(&tx, self.profile_id, !is_default)?; } @@ -63,8 +62,8 @@ impl Database { /// Delete record from database pub fn delete(&self, id: i64) -> Result<()> { // Begin new transaction - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; // Delete record by ID delete(&tx, id)?; @@ -97,8 +96,8 @@ impl Database { /// Delete record from database pub fn set_default(&self, id: i64) -> Result<()> { // Begin new transaction - let mut writable = self.connection.write().unwrap(); // @TODO - let tx = writable.transaction()?; + let mut connection = self.pool.get()?; + let tx = connection.transaction()?; // Make sure only one default provider in set reset(&tx, self.profile_id, false)?;