117 lines
3.3 KiB
Rust
117 lines
3.3 KiB
Rust
|
use rusqlite::{params, Connection};
|
||
|
use std::{
|
||
|
ops::{Deref, DerefMut},
|
||
|
path::PathBuf,
|
||
|
sync::{Arc, Mutex},
|
||
|
};
|
||
|
|
||
|
pub struct ManagedConnection<'a> {
|
||
|
pool: &'a Datumbazo,
|
||
|
konekto: Option<Connection>,
|
||
|
}
|
||
|
|
||
|
#[derive(Clone)]
|
||
|
pub struct Datumbazo {
|
||
|
dosierindiko: PathBuf,
|
||
|
pool: Arc<Mutex<Vec<Connection>>>,
|
||
|
}
|
||
|
|
||
|
impl Datumbazo {
|
||
|
pub fn kreu(dosierindiko: PathBuf) -> Result<Datumbazo, anyhow::Error> {
|
||
|
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);
|
||
|
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<ManagedConnection<'a>, 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![1, String::from("mia-uzantnomo")],
|
||
|
)
|
||
|
.unwrap();
|
||
|
tr.commit().unwrap();
|
||
|
|
||
|
let konekto = datumbazo.konektu().unwrap();
|
||
|
let id: Option<u32> = konekto
|
||
|
.query_row(
|
||
|
"SELECT id FROM uzantoj WHERE nomo = ?",
|
||
|
[String::from("mia-uzantnomo")],
|
||
|
|row| row.get("id"),
|
||
|
)
|
||
|
.unwrap();
|
||
|
assert_eq!(id, Some(1));
|
||
|
}
|
||
|
}
|