use sqlite::Connection; use crate::BString; use crate::date::DateTime; use std::env::current_dir; use std::path::PathBuf; fn db_file() -> PathBuf { crate::basedir::data_dir().join("history.db") } #[derive(Clone)] pub struct HistoryEntry { /// time of execution pub time: DateTime, /// absolute path where the command was executed pub loc: BString, /// the command pub cmd: BString, } impl HistoryEntry { pub fn new(cmd: BString) -> Self { Self { time: DateTime::now(), loc: current_dir() .unwrap() .as_os_str() .as_encoded_bytes() .to_vec(), cmd, } } } fn try_db() -> sqlite::Result { sqlite::open(db_file()) } fn db() -> Connection { try_db().unwrap() } pub fn setup() { let db = db(); db.execute( " CREATE TABLE IF NOT EXISTS history ( ts INTEGER NOT NULL, loc BLOB NOT NULL, cmd BLOB NOT NULL ) ", ) .unwrap(); db.execute("CREATE INDEX IF NOT EXISTS idx_history_ts ON history(ts)") .unwrap(); } fn try_persist(entry: &HistoryEntry) -> sqlite::Result<()> { let db = try_db()?; let mut s = db.prepare("INSERT INTO history (ts, loc, cmd) VALUES (?, ?, ?)")?; s.bind((1, entry.time.unix() as i64))?; s.bind((2, entry.loc.as_slice()))?; s.bind((3, entry.cmd.as_slice()))?; s.next()?; Ok(()) } pub fn persist(entry: &HistoryEntry) { // keep quiet in case db fails let _ = try_persist(entry); }