visions-vtt/servilo/src/datumbazo.rs

117 lines
3.3 KiB
Rust
Raw Normal View History

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, 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<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!["abcdfeg", "mia-uzantnomo", "pasvorto", "abcdefg"],
)
.unwrap();
tr.commit().unwrap();
let konekto = datumbazo.konektu().unwrap();
let id: Option<String> = 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")));
}
}