2020-10-04 17:59:28 -06:00
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
use eyre::Result;
|
|
|
|
|
|
|
|
use rusqlite::NO_PARAMS;
|
2020-10-05 10:20:48 -06:00
|
|
|
use rusqlite::{params, Connection};
|
2020-10-04 17:59:28 -06:00
|
|
|
|
2020-10-05 10:20:48 -06:00
|
|
|
use crate::History;
|
2020-10-04 17:59:28 -06:00
|
|
|
|
|
|
|
pub trait Database {
|
|
|
|
fn save(&self, h: History) -> Result<()>;
|
|
|
|
fn list(&self) -> Result<()>;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Intended for use on a developer machine and not a sync server.
|
|
|
|
// TODO: implement IntoIterator
|
|
|
|
pub struct SqliteDatabase {
|
|
|
|
conn: Connection,
|
|
|
|
}
|
|
|
|
|
2020-10-05 10:20:48 -06:00
|
|
|
impl SqliteDatabase {
|
|
|
|
pub fn new(path: impl AsRef<Path>) -> Result<SqliteDatabase> {
|
2020-10-04 17:59:28 -06:00
|
|
|
let path = path.as_ref();
|
|
|
|
debug!("opening sqlite database at {:?}", path);
|
|
|
|
|
2020-10-05 10:20:48 -06:00
|
|
|
let create = !path.exists();
|
|
|
|
if create {
|
|
|
|
if let Some(dir) = path.parent() {
|
|
|
|
std::fs::create_dir_all(dir)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-04 17:59:28 -06:00
|
|
|
let conn = Connection::open(path)?;
|
|
|
|
|
|
|
|
if create {
|
|
|
|
Self::setup_db(&conn)?;
|
|
|
|
}
|
|
|
|
|
2020-10-05 10:20:48 -06:00
|
|
|
Ok(SqliteDatabase { conn })
|
2020-10-04 17:59:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
fn setup_db(conn: &Connection) -> Result<()> {
|
|
|
|
debug!("running sqlite database setup");
|
|
|
|
|
|
|
|
conn.execute(
|
|
|
|
"create table if not exists history (
|
2020-10-05 10:20:48 -06:00
|
|
|
id integer primary key,
|
|
|
|
timestamp integer not null,
|
|
|
|
command text not null,
|
|
|
|
cwd text not null
|
|
|
|
)",
|
2020-10-04 17:59:28 -06:00
|
|
|
NO_PARAMS,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Database for SqliteDatabase {
|
|
|
|
fn save(&self, h: History) -> Result<()> {
|
|
|
|
debug!("saving history to sqlite");
|
|
|
|
|
|
|
|
self.conn.execute(
|
|
|
|
"insert into history (
|
2020-10-05 10:20:48 -06:00
|
|
|
timestamp,
|
2020-10-04 17:59:28 -06:00
|
|
|
command,
|
|
|
|
cwd
|
2020-10-05 10:20:48 -06:00
|
|
|
) values (?1, ?2, ?3)",
|
|
|
|
params![h.timestamp, h.command, h.cwd],
|
|
|
|
)?;
|
2020-10-04 17:59:28 -06:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn list(&self) -> Result<()> {
|
|
|
|
debug!("listing history");
|
2020-10-05 10:20:48 -06:00
|
|
|
|
|
|
|
let mut stmt = self
|
|
|
|
.conn
|
|
|
|
.prepare("SELECT timestamp, command, cwd FROM history")?;
|
2020-10-04 17:59:28 -06:00
|
|
|
let history_iter = stmt.query_map(params![], |row| {
|
|
|
|
Ok(History {
|
|
|
|
timestamp: row.get(0)?,
|
|
|
|
command: row.get(1)?,
|
|
|
|
cwd: row.get(2)?,
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
for h in history_iter {
|
|
|
|
let h = h.unwrap();
|
|
|
|
|
|
|
|
println!("{}:{}:{}", h.timestamp, h.cwd, h.command);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|