use std::{str::FromStr, sync::Arc};
use parking_lot::Mutex;
use rusqlite::Connection;
pub use crate::rawhook::Action;
#[derive(Debug)]
pub struct Change<D, T> {
pub action: Action,
pub database: D,
pub table: T,
pub rowid: i64
}
pub trait ChangeLogHook {
type Database;
type Table;
fn changelog(
&mut self,
log: Vec<Change<Self::Database, Self::Table>>
) -> bool;
}
pub fn hook<D, T>(
conn: &Connection,
mut cb: Box<dyn ChangeLogHook<Database = D, Table = T> + Send>
) -> Result<(), rusqlite::Error>
where
D: FromStr + Send + Sized + 'static,
T: FromStr + Send + Sized + 'static
{
let changelog = Arc::new(Mutex::new(Vec::new()));
let chlog = Arc::clone(&changelog);
conn.commit_hook(Some(move || {
let mut g = chlog.lock();
let log = std::mem::take(&mut *g);
drop(g);
cb.changelog(log)
}))?;
let chlog = Arc::clone(&changelog);
conn.rollback_hook(Some(move || {
let mut g = chlog.lock();
g.clear();
drop(g);
}))?;
conn.update_hook(Some(move |action, db: &str, tbl: &str, rowid| {
let (Ok(database), Ok(table)) = (D::from_str(db), T::from_str(tbl)) else {
return;
};
let Ok(action) = Action::try_from(action) else {
return;
};
changelog.lock().push(Change {
action,
database,
table,
rowid
});
}))?;
Ok(())
}