implement kill command

This commit is contained in:
Abraham Toriz 2021-07-30 17:55:19 -05:00
parent f184d5b6a3
commit 63154cc1fc
No known key found for this signature in database
GPG Key ID: D5B4A746DB5DD42A
4 changed files with 117 additions and 4 deletions

View File

@ -19,6 +19,7 @@ pub mod list;
pub mod out;
pub mod resume;
pub mod backend;
pub mod kill;
pub trait Command<'a> {
type Args: TryFrom<&'a ArgMatches<'a>>;

79
src/commands/kill.rs Normal file
View File

@ -0,0 +1,79 @@
use std::convert::TryFrom;
use std::io::{self, Write};
use clap::ArgMatches;
use chrono::{DateTime, Utc};
use crate::error::{Error, Result};
use crate::database::Database;
use crate::config::Config;
use super::Command;
fn read_line() -> String {
let mut pre_n = String::new();
io::stdin().read_line(&mut pre_n).unwrap();
pre_n
}
#[derive(Debug)]
pub enum Args {
Id(u64),
Sheet(String),
}
impl<'a> TryFrom<&'a ArgMatches<'a>> for Args {
type Error = Error;
fn try_from(args: &'a ArgMatches) -> Result<Args> {
Ok(args.value_of("id").map(|v| {
Args::Id(v.parse().unwrap())
}).unwrap_or_else(|| {
Args::Sheet(args.value_of("sheet").unwrap().to_owned())
}))
}
}
pub struct KillCommand;
impl<'a> Command<'a> for KillCommand {
type Args = Args;
fn handle<D, O, E>(args: Args, db: &mut D, out: &mut O, _err: &mut E, _config: &Config, _now: DateTime<Utc>) -> Result<()>
where
D: Database,
O: Write,
E: Write,
{
match args {
Args::Id(id) => {
if let Some(entry) = db.entry_by_id(id)? {
writeln!(out, "are you sure you want to delete entry {}? ({}) [y/n]", entry.id, entry.note.unwrap_or("".into()))?;
if read_line().to_lowercase().starts_with("y") {
db.delete_entry_by_id(id)?;
writeln!(out, "It's dead")?;
} else {
writeln!(out, "Don't worry, it's still there")?;
}
} else {
writeln!(out, "There's no entry with id {}. Someone found it before we did.", id)?;
}
},
Args::Sheet(sheet) => {
let n = db.entries_by_sheet(&sheet, None, None)?.len();
writeln!(out, "are you sure you want to delete {} entries on sheet \"{}\"?", n, sheet)?;
if read_line().to_lowercase().starts_with("y") {
db.delete_entries_in_sheet(&sheet)?;
writeln!(out, "They're gone")?;
} else {
writeln!(out, "Don't worry, they're still there")?;
}
}
}
Ok(())
}
}

View File

@ -169,6 +169,22 @@ pub trait Database {
Ok(self.entry_query("select * from entries where end is not null and sheet=?1 order by end desc limit 1", &[&sheet])?.into_iter().next())
}
fn delete_entry_by_id(&mut self, id: u64) -> Result<()> {
Ok(self.execute("delete from entries where id=?1", &[&id])?)
}
fn delete_entries_in_sheet(&mut self, sheet: &str) -> Result<()> {
self.execute("delete from entries where sheet=?1", &[&sheet])?;
if let Some(last) = self.last_sheet()? {
if last == sheet {
self.unset_last_sheet()?;
}
}
Ok(())
}
// Meta queries
fn current_sheet(&self) -> Result<Option<String>> {
let results = self.meta_query("select * from meta where key='current_sheet'", &[])?;
@ -196,6 +212,10 @@ pub trait Database {
Ok(())
}
fn unset_last_sheet(&mut self) -> Result<()> {
Ok(self.execute("delete from meta where key='last_sheet'", &[])?)
}
fn version(&self) -> Result<DBVersion> {
let results = self.meta_query("select * from meta where key='database_version'", &[])?;

View File

@ -13,7 +13,7 @@ use tiempo::commands::{
Command, r#in::InCommand, display::DisplayCommand, sheet::SheetCommand,
today::TodayCommand, yesterday::YesterdayCommand, week::WeekCommand,
month::MonthCommand, list::ListCommand, out::OutCommand,
resume::ResumeCommand, backend::BackendCommand,
resume::ResumeCommand, backend::BackendCommand, kill::KillCommand,
};
fn error_trap(matches: ArgMatches) -> error::Result<()> {
@ -41,6 +41,7 @@ fn error_trap(matches: ArgMatches) -> error::Result<()> {
("sheet", Some(matches)) => SheetCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
("list", Some(matches)) => ListCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
("kill", Some(matches)) => KillCommand::handle(matches.try_into()?, &mut conn, &mut out, &mut err, &config, now),
(cmd, _) => Err(error::Error::UnimplementedCommand(cmd.into())),
}
@ -97,8 +98,7 @@ fn main() {
Ok(())
} else {
Err(format!("the --id arg must be a number. '{}' is not a valid number", v))
})
.help("Use entry with ID instead of the last entry");
});
// Now declar this app's cli
let matches = App::new("Tiempo")
@ -249,7 +249,7 @@ fn main() {
.visible_alias("r")
.about("Restart the timer for an entry. Defaults to the last active entry")
.arg(at_arg.clone())
.arg(id_arg.clone())
.arg(id_arg.clone().help("Use entry with ID instead of the last entry"))
)
.subcommand(SubCommand::with_name("out")
@ -272,6 +272,19 @@ fn main() {
.help("List archive sheets also"))
)
.subcommand(SubCommand::with_name("kill")
.visible_alias("k")
.about("Delete an entry or an entire sheet")
.arg(id_arg.clone().help("Delete entry with this ID instead of sheet"))
.arg(Arg::with_name("sheet")
.takes_value(true).value_name("SHEET")
.conflicts_with("id")
.required_unless("id")
.help(
"Delete an entire sheet by its name"
))
)
.get_matches();
if let Err(e) = error_trap(matches) {