aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--src/cli/mod.rs35
-rw-r--r--src/db/categories.rs4
-rw-r--r--src/db/event_colors.rs10
-rw-r--r--src/db/events.rs64
-rw-r--r--src/main.rs20
6 files changed, 93 insertions, 44 deletions
diff --git a/README.md b/README.md
index 43eccf4..8f54d46 100644
--- a/README.md
+++ b/README.md
@@ -30,10 +30,10 @@ Run tests with:
cargo test
```
-Get today’s events with:
+Show options:
```bash
-cargo run -- --list-today
+cargo run -- --help
```
# TODO
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index 3674a08..8069a10 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -1,14 +1,25 @@
use anyhow::Result;
-use chrono::{Local, NaiveDate, NaiveDateTime, TimeZone};
+use chrono::{Local, NaiveDate, NaiveDateTime, TimeDelta, TimeZone};
use rusqlite::Connection;
+use std::ops::{Add, Sub};
use crate::model::event::Event;
+use crate::model::category::Category;
use crate::{db, model::event};
-pub fn today(conn: &Connection) -> Result<String> {
- let today = Local::now().date_naive();
- let events = between_inclusive(conn, today, today)?;
- Ok(format_events(events))
+pub fn parse_date(s: String) -> Option<NaiveDate> {
+ match s.as_str() {
+ "yesterday" => Some(Local::now().sub(TimeDelta::days(1)).date_naive()),
+ "today" => Some(Local::now().date_naive()),
+ "tomorrow" => Some(Local::now().add(TimeDelta::days(1)).date_naive()),
+ _ => NaiveDate::parse_from_str(&s, "%Y-%m-%d").ok(),
+ }
+}
+
+pub fn started_at_date(conn: &Connection, date: NaiveDate) -> Result<String> {
+ let events = between_inclusive(conn, date, date)?;
+ let categories = db::categories::list(conn)?;
+ Ok(format_events(events, categories))
}
pub fn parse_timestamp_range(s: String) -> Option<(NaiveDateTime, NaiveDateTime)> {
@@ -41,7 +52,8 @@ pub fn start_between(conn: &Connection, from: NaiveDateTime, to: NaiveDateTime)
})
.cloned()
.collect::<Vec<Event>>();
- Ok(format_events(events))
+ let categories = db::categories::list(conn)?;
+ Ok(format_events(events, categories))
}
fn between_inclusive(conn: &Connection, from: NaiveDate, to: NaiveDate) -> Result<Vec<Event>> {
@@ -60,12 +72,19 @@ fn between_inclusive(conn: &Connection, from: NaiveDate, to: NaiveDate) -> Resul
Ok(events)
}
-fn format_events(events: Vec<Event>) -> String {
+fn format_events(events: Vec<Event>, categories: Vec<Category>) -> String {
let mut events = events;
events.sort_by_key(|e| e.local_timestamp());
events
.iter()
- .map(|e| format!("{}\n", e.pprint()))
+ .map(|e| {
+ let category = e.category.and_then(|c| categories.clone().into_iter().find(|c2| c == c2.id));
+ let category_str = match category {
+ Some(c) => format!("[{}] ", c.name),
+ None => "".to_string()
+ };
+ return format!("{}{}\n", category_str, e.pprint())
+ })
.collect::<Vec<String>>()
.join("")
}
diff --git a/src/db/categories.rs b/src/db/categories.rs
index ebefb6d..f81b855 100644
--- a/src/db/categories.rs
+++ b/src/db/categories.rs
@@ -5,7 +5,8 @@ use uuid::Uuid;
use crate::model::category::Category;
pub fn list(conn: &Connection) -> Result<Vec<Category>> {
- let mut stmt = conn.prepare("SELECT id, name, color FROM categories")?;
+ let query = r#"SELECT id, name, color FROM categories"#;
+ let mut stmt = conn.prepare(query)?;
let iter = stmt.query_map([], |row| {
Ok(read_category(row.get(0)?, row.get(1)?, row.get(2)?))
@@ -20,6 +21,5 @@ pub fn list(conn: &Connection) -> Result<Vec<Category>> {
fn read_category(id: String, name: String, color: String) -> Result<Category> {
let id = Uuid::parse_str(&id)?;
-
Ok(Category { id, name, color })
}
diff --git a/src/db/event_colors.rs b/src/db/event_colors.rs
index 62b6146..bf7f541 100644
--- a/src/db/event_colors.rs
+++ b/src/db/event_colors.rs
@@ -3,12 +3,10 @@ use rusqlite::Connection;
pub fn get_default_color(conn: &Connection) -> Result<String> {
let mut stmt = conn.prepare("SELECT * FROM event_colors LIMIT 1")?;
+ let mut iter = stmt.query_map([], |row| row.get(0))?;
- let iter = stmt.query_map([], |row| row.get(0))?;
-
- let mut res = vec![];
- for color in iter {
- res.push(color?)
+ match iter.next() {
+ Some(Ok(color)) => Ok(color),
+ _ => Ok("blue".to_string()),
}
- Ok(res.first().unwrap_or(&"blue".to_string()).clone())
}
diff --git a/src/db/events.rs b/src/db/events.rs
index 1721967..7f09466 100644
--- a/src/db/events.rs
+++ b/src/db/events.rs
@@ -1,11 +1,16 @@
use anyhow::Result;
use chrono::{NaiveDate, NaiveTime};
-use rusqlite::{params, Connection};
+use rusqlite::{named_params, Connection};
use uuid::Uuid;
use crate::model::event::Event;
pub fn insert(conn: &Connection, event: &Event) -> Result<()> {
+ let query = r#"
+ INSERT INTO events (id, date, start, end, name, repetition, category, created, updated)
+ VALUES (:id, :date, :start, :end, :name, :repetition, :category, datetime(), datetime())
+ "#;
+
let repetition = match &event.repetition {
Some(r) => Some(serde_json::to_string(&r)?),
None => None,
@@ -14,14 +19,35 @@ pub fn insert(conn: &Connection, event: &Event) -> Result<()> {
let category = event.category.map(|id| id.hyphenated().to_string());
conn.execute(
- "INSERT INTO events (id, date, start, end, name, repetition, category, created, updated) VALUES (?, ?, ?, ?, ?, ?, ?, datetime(), datetime())",
- params![event.id.hyphenated().to_string(), event.date, event.start, event.end, event.name, repetition, category]
+ query,
+ named_params![
+ ":id": event.id.hyphenated().to_string(),
+ ":date": event.date,
+ ":start": event.start,
+ ":end": event.end,
+ ":name": event.name,
+ ":repetition": repetition,
+ ":category": category
+ ],
)?;
Ok(())
}
pub fn update(conn: &Connection, event: &Event) -> Result<()> {
+ let query = r#"
+ UPDATE events
+ SET
+ date = :date,
+ start = :start,
+ end = :end,
+ name = :name,
+ repetition = :repetition,
+ category = :category,
+ updated = datetime()
+ WHERE id = :id
+ "#;
+
let repetition = match &event.repetition {
Some(r) => Some(serde_json::to_string(&r)?),
None => None,
@@ -30,29 +56,35 @@ pub fn update(conn: &Connection, event: &Event) -> Result<()> {
let category = event.category.map(|id| id.hyphenated().to_string());
conn.execute(
- "UPDATE events SET date = ?, start = ?, end = ?, name = ?, repetition = ?, category = ?, updated = datetime() WHERE id = ?",
- params![event.date, event.start, event.end, event.name, repetition, category, event.id.hyphenated().to_string()]
+ query,
+ named_params![
+ ":date": event.date,
+ ":start": event.start,
+ ":end": event.end,
+ ":name": event.name,
+ ":repetition": repetition,
+ ":category": category,
+ ":id": event.id.hyphenated().to_string()
+ ],
)?;
Ok(())
}
pub fn delete(conn: &Connection, id: &Uuid) -> Result<()> {
- conn.execute(
- "DELETE FROM events WHERE id = ?",
- params![id.hyphenated().to_string()],
- )?;
-
+ let query = r#"DELETE FROM events WHERE id = :id"#;
+ conn.execute(query, named_params![":id": id.hyphenated().to_string()])?;
Ok(())
}
pub fn list_recurring(conn: &Connection) -> Result<Vec<Event>> {
- let mut stmt = conn.prepare(
- "
+ let query = r#"
SELECT id, date, start, end, name, repetition, category
FROM events
- WHERE repetition IS NOT NULL",
- )?;
+ WHERE repetition IS NOT NULL
+ "#;
+
+ let mut stmt = conn.prepare(query)?;
let iter = stmt.query_map([], |row| {
Ok(read_event(
@@ -82,8 +114,8 @@ pub fn list_non_recurring_between(
"
SELECT id, date, start, end, name, category
FROM events
- WHERE
- repetition IS NULL
+ WHERE
+ repetition IS NULL
AND date >= ?
AND date <= ?
",
diff --git a/src/main.rs b/src/main.rs
index 8eafd77..e61a771 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -14,11 +14,11 @@ struct Opt {
#[clap(long = "database", default_value = "database.sqlite3")]
db_path: String,
- /// List today’s events as plain text
- #[clap(long = "list-today")]
- list_today: bool,
+ /// Started at events as plain text
+ #[clap(long = "date")]
+ date: Option<String>,
- /// Start between <timestamp..timestamp> events as plain text
+ /// Started between <timestamp..timestamp> events as plain text
#[clap(long = "start-between")]
start_between: Option<String>,
}
@@ -26,17 +26,17 @@ struct Opt {
fn main() -> Result<()> {
let Opt {
db_path,
- list_today,
+ date,
start_between,
} = Opt::parse();
let conn = db::init(&db_path)?;
- if list_today {
- print!("{}", cli::today(&conn)?);
- } else {
- match start_between.and_then(cli::parse_timestamp_range) {
+
+ match date.and_then(cli::parse_date) {
+ Some(date) => print!("{}", cli::started_at_date(&conn, date)?),
+ None => match start_between.and_then(cli::parse_timestamp_range) {
Some((from, to)) => print!("{}", cli::start_between(&conn, from, to)?),
None => gui::run(conn),
- }
+ },
};
Ok(())
}