2021-06-21 11:12:30 -05:00
|
|
|
use std::path::Path;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
2021-06-21 19:54:10 -05:00
|
|
|
use rusqlite::{Connection, ToSql, types::{FromSql, ValueRef, FromSqlResult}};
|
|
|
|
use chrono::DateTime;
|
2021-06-21 11:12:30 -05:00
|
|
|
|
|
|
|
use crate::error;
|
|
|
|
use crate::models::{Entry, Meta};
|
|
|
|
use crate::types::Time;
|
2021-06-18 11:27:19 -05:00
|
|
|
|
|
|
|
pub trait Database {
|
2021-06-21 11:12:30 -05:00
|
|
|
/// This is used to create tables and insert rows
|
|
|
|
fn execute(&mut self, query: &str, params: &[&dyn ToSql]) -> error::Result<()>;
|
|
|
|
|
|
|
|
/// And this is used to retrieve data
|
|
|
|
fn entry_query(&self, query: &str, params: &[&dyn ToSql]) -> error::Result<Vec<Entry>>;
|
|
|
|
fn meta_query(&self, query: &str, params: &[&dyn ToSql]) -> error::Result<Vec<Meta>>;
|
|
|
|
|
2021-06-21 17:38:51 -05:00
|
|
|
// Entry queries
|
|
|
|
|
2021-06-21 19:54:10 -05:00
|
|
|
fn entries_by_sheet(&self, sheet: &str) -> error::Result<Vec<Entry>> {
|
2021-06-21 21:35:05 -05:00
|
|
|
self.entry_query("select * from entries where sheet=?1 order by start asc", &[&sheet])
|
2021-06-21 11:12:30 -05:00
|
|
|
}
|
|
|
|
|
2021-06-21 19:54:10 -05:00
|
|
|
fn entries_all_visible(&self) -> error::Result<Vec<Entry>> {
|
2021-06-21 21:35:05 -05:00
|
|
|
self.entry_query("select * from entries where sheet not like '!_%' escape \"!\" order by sheet asc, start asc", &[])
|
2021-06-21 19:54:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn entries_full(&self) -> error::Result<Vec<Entry>> {
|
2021-06-21 21:35:05 -05:00
|
|
|
self.entry_query("select * from entries order by sheet asc, start asc", &[])
|
2021-06-21 19:54:10 -05:00
|
|
|
}
|
|
|
|
|
2021-06-21 11:12:30 -05:00
|
|
|
fn entry_insert(&mut self, at: Time, note: String) -> error::Result<()> {
|
|
|
|
self.execute("", &[])
|
|
|
|
}
|
2021-06-21 17:38:51 -05:00
|
|
|
|
|
|
|
// Meta queries
|
|
|
|
fn current_sheet(&self) -> error::Result<Option<String>> {
|
|
|
|
let results = self.meta_query("select * from meta where key=?1", &[&"current_sheet"])?;
|
|
|
|
|
|
|
|
Ok(results.into_iter().next().map(|m| m.value))
|
|
|
|
}
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SqliteDatabase {
|
2021-06-21 11:12:30 -05:00
|
|
|
connection: Connection,
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SqliteDatabase {
|
|
|
|
pub fn from_memory() -> error::Result<impl Database> {
|
|
|
|
Ok(SqliteDatabase {
|
2021-06-21 11:12:30 -05:00
|
|
|
connection: Connection::open_in_memory()?,
|
2021-06-18 11:27:19 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-06-21 11:12:30 -05:00
|
|
|
pub fn from_path<P: AsRef<Path>>(path: P) -> error::Result<impl Database> {
|
2021-06-18 11:27:19 -05:00
|
|
|
Ok(SqliteDatabase {
|
2021-06-21 11:12:30 -05:00
|
|
|
connection: Connection::open(path)?,
|
2021-06-18 11:27:19 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Database for SqliteDatabase {
|
2021-06-21 11:12:30 -05:00
|
|
|
fn execute(&mut self, query: &str, params: &[&dyn ToSql]) -> error::Result<()> {
|
|
|
|
self.connection.execute(query, params)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn entry_query(&self, query: &str, params: &[&dyn ToSql]) -> error::Result<Vec<Entry>> {
|
|
|
|
let mut stmt = self.connection.prepare(query)?;
|
|
|
|
|
2021-06-21 17:38:51 -05:00
|
|
|
let results = stmt.query_map(params, |row| {
|
2021-06-21 11:12:30 -05:00
|
|
|
let x = Ok(Entry {
|
|
|
|
id: row.get("id")?,
|
|
|
|
note: row.get("note")?,
|
|
|
|
start: row.get("start")?,
|
|
|
|
end: row.get("end")?,
|
|
|
|
sheet: row.get("sheet")?,
|
|
|
|
});
|
|
|
|
|
|
|
|
x})?.filter_map(|r| r.ok()).collect();
|
|
|
|
|
|
|
|
Ok(results)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn meta_query(&self, query: &str, params: &[&dyn ToSql]) -> error::Result<Vec<Meta>> {
|
|
|
|
let mut stmt = self.connection.prepare(query)?;
|
|
|
|
|
2021-06-21 17:38:51 -05:00
|
|
|
let results = stmt.query_map(params, |row| Ok(Meta {
|
2021-06-21 11:12:30 -05:00
|
|
|
id: row.get("id")?,
|
|
|
|
key: row.get("key")?,
|
|
|
|
value: row.get("value")?,
|
|
|
|
}))?.filter_map(|r| r.ok()).collect();
|
|
|
|
|
|
|
|
Ok(results)
|
2021-06-18 11:27:19 -05:00
|
|
|
}
|
|
|
|
}
|
2021-06-21 19:54:10 -05:00
|
|
|
|
|
|
|
impl FromSql for Time {
|
|
|
|
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
|
|
|
|
Ok(DateTime::column_result(value)?.into())
|
|
|
|
}
|
|
|
|
}
|