use rusqlite::{params, Connection}; use std::{ ops::{Deref, DerefMut}, path::PathBuf, sync::{Arc, Mutex}, }; pub struct ManagedConnection<'a> { pool: &'a Datumbazo, konekto: Option, } #[derive(Clone)] pub struct Datumbazo { dosierindiko: PathBuf, pool: Arc>>, } impl Datumbazo { pub fn kreu(dosierindiko: PathBuf) -> Result { let mut konekto = Connection::open(dosierindiko.clone())?; let tx = konekto.transaction()?; let versio: i32 = tx.pragma_query_value(None, "user_version", |r| r.get(0))?; println!("versio: {}", versio); if versio == 0 { tx.execute_batch( "CREATE TABLE uzantoj (id string primary key, nomo text, pasvorto text, pasvortsalo text); CREATE TABLE rajtoj (uzanto string, rajto string, foreign key(uzanto) references uzanto(id)); CREATE TABLE sesioj (id string primary key not null, uzanto string, foreign key(uzanto) references uzantoj(id)); PRAGMA user_version = 1;", )?; } let versio: i32 = tx.pragma_query_value(None, "user_version", |r| r.get(0))?; println!("versio: {}", versio); tx.commit()?; Ok(Datumbazo { dosierindiko, pool: Arc::new(Mutex::new(vec![konekto])), }) } pub fn konektu<'a>(&'a self) -> Result, anyhow::Error> { let mut pool = self.pool.lock().unwrap(); match pool.pop() { Some(konekto) => Ok(ManagedConnection { pool: &self, konekto: Some(konekto), }), None => { let konekto = Connection::open(self.dosierindiko.clone())?; Ok(ManagedConnection { pool: &self, konekto: Some(konekto), }) } } } pub fn revenu(&self, konekto: Connection) { let mut pool = self.pool.lock().unwrap(); pool.push(konekto); } } impl Deref for ManagedConnection<'_> { type Target = Connection; fn deref(&self) -> &Connection { self.konekto.as_ref().unwrap() } } impl DerefMut for ManagedConnection<'_> { fn deref_mut(&mut self) -> &mut Connection { self.konekto.as_mut().unwrap() } } impl Drop for ManagedConnection<'_> { fn drop(&mut self) { self.pool.revenu(self.konekto.take().unwrap()); } } #[cfg(test)] mod test { use super::*; use tempfile::NamedTempFile; #[test] fn povas_krei_uzanton() { let vojo = NamedTempFile::new().unwrap().into_temp_path(); let datumbazo = Datumbazo::kreu(vojo.to_path_buf()).unwrap(); let mut konekto = datumbazo.konektu().unwrap(); let tr = konekto.transaction().unwrap(); tr.execute( "INSERT INTO uzantoj VALUES(?, ?, ?, ?)", params!["abcdfeg", "mia-uzantnomo", "pasvorto", "abcdefg"], ) .unwrap(); tr.commit().unwrap(); let konekto = datumbazo.konektu().unwrap(); let id: Option = konekto .query_row( "SELECT id FROM uzantoj WHERE nomo = ?", [String::from("mia-uzantnomo")], |row| row.get("id"), ) .unwrap(); assert_eq!(id, Some(String::from("abcdfeg"))); } }