Detailed changes
@@ -30,6 +30,10 @@ pub enum Command {
#[arg(short, long, default_value_t = 2)]
priority: i32,
+ /// Effort level (1=low, 2=medium, 3=high)
+ #[arg(short, long, default_value_t = 2)]
+ effort: i32,
+
/// Task type
#[arg(short = 't', long = "type", default_value = "task")]
task_type: String,
@@ -6,6 +6,7 @@ use crate::db;
pub struct Opts<'a> {
pub title: Option<&'a str>,
pub priority: i32,
+ pub effort: i32,
pub task_type: &'a str,
pub desc: Option<&'a str>,
pub parent: Option<&'a str>,
@@ -34,14 +35,15 @@ pub fn run(root: &Path, opts: Opts) -> Result<()> {
};
conn.execute(
- "INSERT INTO tasks (id, title, description, type, priority, status, parent, created, updated)
- VALUES (?1, ?2, ?3, ?4, ?5, 'open', ?6, ?7, ?8)",
+ "INSERT INTO tasks (id, title, description, type, priority, status, effort, parent, created, updated)
+ VALUES (?1, ?2, ?3, ?4, ?5, 'open', ?6, ?7, ?8, ?9)",
rusqlite::params![
id,
title,
desc,
opts.task_type,
opts.priority,
+ opts.effort,
opts.parent.unwrap_or(""),
ts,
ts
@@ -68,6 +70,7 @@ pub fn run(root: &Path, opts: Opts) -> Result<()> {
task_type: opts.task_type.to_string(),
priority: opts.priority,
status: "open".to_string(),
+ effort: opts.effort,
parent: opts.parent.unwrap_or("").to_string(),
created: ts.clone(),
updated: ts,
@@ -7,7 +7,7 @@ pub fn run(root: &Path) -> Result<()> {
let conn = db::open(root)?;
let mut stmt = conn.prepare(
- "SELECT id, title, description, type, priority, status, parent, created, updated
+ "SELECT id, title, description, type, priority, status, effort, parent, created, updated
FROM tasks ORDER BY id",
)?;
@@ -26,6 +26,7 @@ pub fn run(root: &Path) -> Result<()> {
task_type: t.task_type.clone(),
priority: t.priority,
status: t.status.clone(),
+ effort: t.effort,
parent: t.parent.clone(),
created: t.created.clone(),
updated: t.updated.clone(),
@@ -17,6 +17,8 @@ struct ImportTask {
priority: i32,
#[serde(default = "default_status")]
status: String,
+ #[serde(default = "default_effort")]
+ effort: i32,
#[serde(default)]
parent: String,
created: String,
@@ -36,6 +38,9 @@ fn default_priority() -> i32 {
fn default_status() -> String {
"open".into()
}
+fn default_effort() -> i32 {
+ 2
+}
pub fn run(root: &Path, file: &str) -> Result<()> {
let conn = db::open(root)?;
@@ -58,8 +63,8 @@ pub fn run(root: &Path, file: &str) -> Result<()> {
conn.execute(
"INSERT OR REPLACE INTO tasks
- (id, title, description, type, priority, status, parent, created, updated)
- VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
+ (id, title, description, type, priority, status, effort, parent, created, updated)
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
rusqlite::params![
t.id,
t.title,
@@ -67,6 +72,7 @@ pub fn run(root: &Path, file: &str) -> Result<()> {
t.task_type,
t.priority,
t.status,
+ t.effort,
t.parent,
t.created,
t.updated,
@@ -13,7 +13,7 @@ pub fn run(
let conn = db::open(root)?;
let mut sql = String::from(
- "SELECT id, title, description, type, priority, status, parent, created, updated
+ "SELECT id, title, description, type, priority, status, effort, parent, created, updated
FROM tasks WHERE 1=1",
);
let mut params: Vec<Box<dyn rusqlite::types::ToSql>> = Vec::new();
@@ -32,6 +32,7 @@ pub fn dispatch(cli: &Cli) -> Result<()> {
Command::Create {
title,
priority,
+ effort,
task_type,
desc,
parent,
@@ -43,6 +44,7 @@ pub fn dispatch(cli: &Cli) -> Result<()> {
create::Opts {
title: title.as_deref(),
priority: *priority,
+ effort: *effort,
task_type,
desc: desc.as_deref(),
parent: parent.as_deref(),
@@ -7,7 +7,7 @@ pub fn run(root: &Path, json: bool) -> Result<()> {
let conn = db::open(root)?;
let mut stmt = conn.prepare(
- "SELECT id, title, description, type, priority, status, parent, created, updated
+ "SELECT id, title, description, type, priority, status, effort, parent, created, updated
FROM tasks
WHERE status = 'open'
AND id NOT IN (
@@ -8,7 +8,7 @@ pub fn run(root: &Path, query: &str, json: bool) -> Result<()> {
let pattern = format!("%{query}%");
let mut stmt = conn.prepare(
- "SELECT id, title, description, type, priority, status, parent, created, updated
+ "SELECT id, title, description, type, priority, status, effort, parent, created, updated
FROM tasks
WHERE title LIKE ?1 OR description LIKE ?1",
)?;
@@ -25,6 +25,7 @@ pub fn run(root: &Path, id: &str, json: bool) -> Result<()> {
println!("{} title{} = {}", c.bold, c.reset, t.title);
println!("{} status{} = {}", c.bold, c.reset, t.status);
println!("{} priority{} = {}", c.bold, c.reset, t.priority);
+ println!("{} effort{} = {}", c.bold, c.reset, t.effort);
println!("{} type{} = {}", c.bold, c.reset, t.task_type);
if !t.description.is_empty() {
println!("{} description{} = {}", c.bold, c.reset, t.description);
@@ -19,6 +19,7 @@ pub struct Task {
pub task_type: String,
pub priority: i32,
pub status: String,
+ pub effort: i32,
pub parent: String,
pub created: String,
pub updated: String,
@@ -62,6 +63,7 @@ pub fn row_to_task(row: &rusqlite::Row) -> rusqlite::Result<Task> {
task_type: row.get("type")?,
priority: row.get("priority")?,
status: row.get("status")?,
+ effort: row.get("effort")?,
parent: row.get("parent")?,
created: row.get("created")?,
updated: row.get("updated")?,
@@ -89,7 +91,7 @@ pub fn load_blockers(conn: &Connection, task_id: &str) -> Result<Vec<String>> {
/// Load a full task with labels and blockers.
pub fn load_task_detail(conn: &Connection, id: &str) -> Result<TaskDetail> {
let task = conn.query_row(
- "SELECT id, title, description, type, priority, status, parent, created, updated
+ "SELECT id, title, description, type, priority, status, effort, parent, created, updated
FROM tasks WHERE id = ?1",
[id],
row_to_task,
@@ -26,6 +26,13 @@ static MIGRATIONS: &[Migration] = &[
post_hook_up: None,
post_hook_down: None,
},
+ // 1 → 2: add effort column (integer-backed, default medium)
+ Migration {
+ up_sql: include_str!("migrations/0002_add_effort.up.sql"),
+ down_sql: include_str!("migrations/0002_add_effort.down.sql"),
+ post_hook_up: None,
+ post_hook_down: None,
+ },
];
/// Read the current schema version from the database.
@@ -0,0 +1 @@
+ALTER TABLE tasks DROP COLUMN effort;
@@ -0,0 +1 @@
+ALTER TABLE tasks ADD COLUMN effort INTEGER NOT NULL DEFAULT 2;