display all, full, sheet and current active

This commit is contained in:
Abraham Toriz 2021-06-21 19:54:10 -05:00
parent a29c3c40ab
commit bfe80c10e1
No known key found for this signature in database
GPG Key ID: D5B4A746DB5DD42A
9 changed files with 125 additions and 16 deletions

View File

@ -1,5 +1,6 @@
use std::convert::TryFrom;
use std::io::Write;
use std::str::FromStr;
use clap::ArgMatches;
@ -11,12 +12,31 @@ use crate::config::Config;
use super::Command;
enum Sheet {
All,
Full,
Sheet(String),
}
impl FromStr for Sheet {
type Err = error::Error;
fn from_str(name: &str) -> error::Result<Sheet> {
Ok(match name {
"all" => Sheet::All,
"full" => Sheet::Full,
name => Sheet::Sheet(name.into()),
})
}
}
pub struct Args {
ids: bool,
start: Option<Time>,
end: Option<Time>,
format: Formatter,
grep: Option<String>,
sheet: Option<Sheet>,
}
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
@ -29,6 +49,7 @@ impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
end: matches.value_of("at").map(|s| s.parse()).transpose()?,
format: matches.value_of("format").unwrap().parse()?,
grep: matches.value_of("grep").map(|s| s.into()),
sheet: matches.value_of("sheet").map(|s| s.parse()).transpose()?,
})
}
}
@ -44,8 +65,17 @@ impl<'a> Command<'a> for DisplayCommand {
D: Database,
W: Write,
{
let current_sheet = db.current_sheet()?.unwrap_or("default".into());
let sheets_to_display = match args.sheet {
Some(Sheet::All) => db.entries_all_visible()?,
Some(Sheet::Full) => db.entries_full()?,
Some(Sheet::Sheet(name)) => db.entries_by_sheet(&name)?,
None => {
let current_sheet = db.current_sheet()?.unwrap_or("default".into());
args.format.print_formatted(db.entries_by_sheet(&current_sheet)?, out)
db.entries_by_sheet(&current_sheet)?
}
};
args.format.print_formatted(sheets_to_display, out)
}
}

View File

@ -37,11 +37,10 @@ impl<'a> Command<'a> for InCommand {
W: Write,
{
let at = args.at.unwrap_or(Time::now());
let note = if let Some(note) = args.note {
note
} else {
editor::get_string()?
editor::get_string(config)?
};
db.entry_insert(at, note)?;

View File

@ -1,6 +1,7 @@
use std::path::Path;
use rusqlite::{Connection, ToSql};
use rusqlite::{Connection, ToSql, types::{FromSql, ValueRef, FromSqlResult}};
use chrono::DateTime;
use crate::error;
use crate::models::{Entry, Meta};
@ -16,10 +17,18 @@ pub trait Database {
// Entry queries
fn entries_by_sheet(&mut self, sheet: &str) -> error::Result<Vec<Entry>> {
fn entries_by_sheet(&self, sheet: &str) -> error::Result<Vec<Entry>> {
self.entry_query("select * from entries where sheet=?1", &[&sheet])
}
fn entries_all_visible(&self) -> error::Result<Vec<Entry>> {
self.entry_query("select * from entries where sheet not like '!_%' escape \"!\"", &[])
}
fn entries_full(&self) -> error::Result<Vec<Entry>> {
self.entry_query("select * from entries", &[])
}
fn entry_insert(&mut self, at: Time, note: String) -> error::Result<()> {
self.execute("", &[])
}
@ -86,3 +95,9 @@ impl Database for SqliteDatabase {
Ok(results)
}
}
impl FromSql for Time {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
Ok(DateTime::column_result(value)?.into())
}
}

View File

@ -1,5 +1,6 @@
use crate::error;
use crate::config::Config;
pub fn get_string() -> error::Result<String> {
pub fn get_string(config: &Config) -> error::Result<String> {
unimplemented!()
}

View File

@ -28,6 +28,9 @@ pub enum Error {
#[error("Could not parse datetime: {0}")]
DateTimeParseError(#[from] chrono::format::ParseError),
#[error("IOError: {0}")]
IOError(#[from] std::io::Error)
}
pub type Result<T> = result::Result<T, Error>;

View File

@ -18,7 +18,7 @@ impl Formatter {
match &self {
Formatter::Text => {
for entry in entries {
writeln!(out, "{:?}", entry);
writeln!(out, "{:?}", entry)?;
}
}
Formatter::Custom(name) => {
@ -41,3 +41,35 @@ impl FromStr for Formatter {
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::Time;
#[test]
fn test_text_output() {
let formatter = Formatter::Text;
let mut output = Vec::new();
let entries = vec![
Entry::new_sample(1, Time::new(2008, 10, 3, 12, 0, 0), Some(Time::new(2008, 10, 3, 14, 0, 0))),
Entry::new_sample(2, Time::new(2008, 10, 3, 12, 0, 0), Some(Time::new(2008, 10, 3, 14, 0, 0))),
Entry::new_sample(3, Time::new(2008, 10, 5, 16, 0, 0), Some(Time::new(2008, 10, 3, 18, 0, 0))),
Entry::new_sample(4, Time::new(2008, 10, 5, 18, 0, 0), None),
];
formatter.print_formatted(entries, &mut output).unwrap();
assert_eq!(String::from_utf8_lossy(&output), "Timesheet: SpecSheet
Day Start End Duration Notes
Fri Oct 03, 2008 12:00:00 - 14:00:00 2:00:00 entry 1
16:00:00 - 18:00:00 2:00:00 entry 2
4:00:00
Sun Oct 05, 2008 16:00:00 - 18:00:00 2:00:00 entry 3
18:00:00 - 2:00:00 entry 4
4:00:00
-----------------------------------------------------------
Total 8:00:00
");
}
}

View File

@ -106,9 +106,7 @@ fn main() {
.subcommand(SubCommand::with_name("display")
.visible_alias("d")
.about("Display the current timesheet or a specific. Pass `all' as SHEET
to display all unarchived sheets or `full' to display archived and
unarchived sheets.")
.about("Display the current timesheet or a specific. Pass `all' as SHEET to display all unarchived sheets or `full' to display archived and unarchived sheets.")
.arg(Arg::with_name("ids")
.short("v").long("ids")
.help("Print database ids (for use with edit)"))
@ -129,6 +127,9 @@ fn main() {
.short("g").long("grep")
.takes_value(true).value_name("REGEXP")
.help("Include entries where the note matches this regexp."))
.arg(Arg::with_name("sheet")
.takes_value(true).value_name("SHEET")
.help("The sheet to display. Pass 'all' to see entries from all sheets or 'full' to see hidden entries"))
)
.subcommand(SubCommand::with_name("in")

View File

@ -1,11 +1,11 @@
use chrono::{DateTime, Utc};
use crate::types::Time;
#[derive(Debug)]
pub struct Entry {
pub id: u64,
pub note: String,
pub start: DateTime<Utc>,
pub end: DateTime<Utc>,
pub start: Time,
pub end: Option<Time>,
pub sheet: String,
}
@ -15,3 +15,15 @@ pub struct Meta {
pub key: String,
pub value: String,
}
impl Entry {
#[cfg(test)]
pub fn new_sample(id: u64, start: Time, end: Option<Time>) -> Entry {
Entry {
id,
note: format!("entry {}", id),
start, end,
sheet: "default".into(),
}
}
}

View File

@ -1,12 +1,28 @@
use std::str::FromStr;
use chrono::{DateTime, Utc, TimeZone};
use crate::error;
pub struct Time;
/// A time in UTC.
///
/// Just a wrapper around Chrono::Utc
#[derive(Debug)]
pub struct Time(DateTime<Utc>);
impl Time {
pub fn now() -> Time {
Time
Time(Utc::now())
}
pub fn new(y: i32, mo: u32, d: u32, h: u32, mi: u32, s: u32) -> Time {
Time(Utc.ymd(y, mo, d).and_hms(h, mi, s))
}
}
impl From<DateTime<Utc>> for Time {
fn from(dt: DateTime<Utc>) -> Time {
Time(dt)
}
}