diff --git a/dist/plan b/dist/plan index 84b7512..b5cb59c 100755 Binary files a/dist/plan and b/dist/plan differ diff --git a/item/task.go b/item/task.go index 556b167..a9eb0d8 100644 --- a/item/task.go +++ b/item/task.go @@ -10,6 +10,7 @@ import ( type TaskBody struct { Title string `json:"title"` + Project string `json:"project"` Time Time `json:"time"` Duration time.Duration `json:"duration"` } diff --git a/item/task_test.go b/item/task_test.go index 664bf75..1caa08c 100644 --- a/item/task_test.go +++ b/item/task_test.go @@ -53,6 +53,7 @@ func TestNewTask(t *testing.T) { Recurrer: item.NewRecurrer("2024-12-08, daily"), Body: `{ "title":"title", + "project":"project", "time":"08:00", "duration":"1h" }`, @@ -63,6 +64,7 @@ func TestNewTask(t *testing.T) { Recurrer: item.NewRecurrer("2024-12-08, daily"), TaskBody: item.TaskBody{ Title: "title", + Project: "project", Time: item.NewTime(8, 0), Duration: oneHour, }, @@ -102,7 +104,7 @@ func TestTaskItem(t *testing.T) { expItem: item.Item{ Kind: item.KindTask, Updated: time.Time{}, - Body: `{"duration":"0s","title":"","time":""}`, + Body: `{"duration":"0s","title":"","project":"","time":""}`, }, }, { @@ -112,6 +114,7 @@ func TestTaskItem(t *testing.T) { Date: item.NewDate(2024, 9, 23), TaskBody: item.TaskBody{ Title: "title", + Project: "project", Time: item.NewTime(8, 0), Duration: oneHour, }, @@ -121,7 +124,7 @@ func TestTaskItem(t *testing.T) { Kind: item.KindTask, Updated: time.Time{}, Date: item.NewDate(2024, 9, 23), - Body: `{"duration":"1h0m0s","title":"title","time":"08:00"}`, + Body: `{"duration":"1h0m0s","title":"title","project":"project","time":"08:00"}`, }, }, } { diff --git a/plan/command/add.go b/plan/command/add.go index ac291b2..c5cbac0 100644 --- a/plan/command/add.go +++ b/plan/command/add.go @@ -19,6 +19,7 @@ func NewAddArgs() AddArgs { fieldTPL: map[string][]string{ "date": {"d", "date", "on"}, "time": {"t", "time", "at"}, + "project": {"p", "project"}, "duration": {"dur", "duration", "for"}, "recurrer": {"rec", "recurrer"}, }, @@ -45,6 +46,9 @@ func (aa AddArgs) Parse(main []string, fields map[string]string) (Command, error }, } + if val, ok := fields["project"]; ok { + tsk.Project = val + } if val, ok := fields["date"]; ok { d := item.NewDateFromString(val) if d.IsZero() { diff --git a/plan/command/add_test.go b/plan/command/add_test.go index 0937cfb..9fd8e7d 100644 --- a/plan/command/add_test.go +++ b/plan/command/add_test.go @@ -38,9 +38,10 @@ func TestAdd(t *testing.T) { expErr: true, }, { - name: "date time duration", + name: "all", main: []string{"add", "title"}, fields: map[string]string{ + "project": "project", "date": aDate.String(), "time": aTime.String(), "duration": anHourStr, @@ -50,6 +51,7 @@ func TestAdd(t *testing.T) { Date: aDate, TaskBody: item.TaskBody{ Title: "title", + Project: "project", Time: aTime, Duration: anHour, }, diff --git a/plan/command/list.go b/plan/command/list.go index 5696dfa..bc741a9 100644 --- a/plan/command/list.go +++ b/plan/command/list.go @@ -105,9 +105,15 @@ type ListResult struct { } func (lr ListResult) Render() string { - data := [][]string{{"id", "date", "dur", "title"}} + data := [][]string{{"id", "project", "date", "dur", "title"}} for _, tl := range lr.Tasks { - data = append(data, []string{fmt.Sprintf("%d", tl.LocalID), tl.Task.Date.String(), tl.Task.Duration.String(), tl.Task.Title}) + data = append(data, []string{ + fmt.Sprintf("%d", tl.LocalID), + tl.Task.Project, + tl.Task.Date.String(), + tl.Task.Duration.String(), + tl.Task.Title, + }) } return fmt.Sprintf("\n%s\n", format.Table(data)) diff --git a/plan/command/show.go b/plan/command/show.go index 0fce2b5..ed7af02 100644 --- a/plan/command/show.go +++ b/plan/command/show.go @@ -72,6 +72,7 @@ func (sr ShowResult) Render() string { data := [][]string{ {"title", sr.Task.Title}, {"local id", fmt.Sprintf("%d", sr.LocalID)}, + {"project", sr.Task.Project}, {"date", sr.Task.Date.String()}, {"time", sr.Task.Time.String()}, {"duration", sr.Task.Duration.String()}, diff --git a/plan/command/update.go b/plan/command/update.go index de9ea75..50f8e30 100644 --- a/plan/command/update.go +++ b/plan/command/update.go @@ -15,6 +15,7 @@ type UpdateArgs struct { fieldTPL map[string][]string LocalID int Title string + Project string Date item.Date Time item.Time Duration time.Duration @@ -24,6 +25,7 @@ type UpdateArgs struct { func NewUpdateArgs() UpdateArgs { return UpdateArgs{ fieldTPL: map[string][]string{ + "project": {"p", "project"}, "date": {"d", "date", "on"}, "time": {"t", "time", "at"}, "duration": {"dur", "duration", "for"}, @@ -49,6 +51,9 @@ func (ua UpdateArgs) Parse(main []string, fields map[string]string) (Command, er Title: strings.Join(main[2:], " "), } + if val, ok := fields["project"]; ok { + args.Project = val + } if val, ok := fields["date"]; ok { d := item.NewDateFromString(val) if d.IsZero() { @@ -102,6 +107,9 @@ func (u *Update) Do(deps Dependencies) (CommandResult, error) { if u.args.Title != "" { tsk.Title = u.args.Title } + if u.args.Project != "" { + tsk.Project = u.args.Project + } if !u.args.Date.IsZero() { tsk.Date = u.args.Date } diff --git a/plan/command/update_test.go b/plan/command/update_test.go index aae062b..d0b1b00 100644 --- a/plan/command/update_test.go +++ b/plan/command/update_test.go @@ -20,6 +20,7 @@ func TestUpdateExecute(t *testing.T) { t.Errorf("exp nil, got %v", err) } title := "title" + project := "project" aDate := item.NewDate(2024, 10, 6) aTime := item.NewTime(10, 0) twoHour, err := time.ParseDuration("2h") @@ -54,6 +55,25 @@ func TestUpdateExecute(t *testing.T) { Date: item.NewDate(2024, 10, 6), TaskBody: item.TaskBody{ Title: "updated", + Project: project, + Time: aTime, + Duration: oneHour, + }, + }, + }, + { + name: "project", + localID: lid, + main: []string{"update", fmt.Sprintf("%d", lid)}, + fields: map[string]string{ + "p": "updated", + }, + expTask: item.Task{ + ID: tskID, + Date: item.NewDate(2024, 10, 2), + TaskBody: item.TaskBody{ + Title: title, + Project: "updated", Time: aTime, Duration: oneHour, }, @@ -80,6 +100,7 @@ func TestUpdateExecute(t *testing.T) { Date: item.NewDate(2024, 10, 2), TaskBody: item.TaskBody{ Title: title, + Project: project, Time: aTime, Duration: oneHour, }, @@ -106,6 +127,7 @@ func TestUpdateExecute(t *testing.T) { Date: item.NewDate(2024, 10, 6), TaskBody: item.TaskBody{ Title: title, + Project: project, Time: item.NewTime(11, 0), Duration: oneHour, }, @@ -132,6 +154,7 @@ func TestUpdateExecute(t *testing.T) { Date: item.NewDate(2024, 10, 6), TaskBody: item.TaskBody{ Title: title, + Project: project, Time: aTime, Duration: twoHour, }, @@ -157,6 +180,7 @@ func TestUpdateExecute(t *testing.T) { Recurrer: item.NewRecurrer("2024-12-08, daily"), TaskBody: item.TaskBody{ Title: title, + Project: project, Time: aTime, Duration: oneHour, }, @@ -173,6 +197,7 @@ func TestUpdateExecute(t *testing.T) { Date: aDate, TaskBody: item.TaskBody{ Title: title, + Project: project, Time: aTime, Duration: oneHour, }, diff --git a/plan/storage/sqlite/migrations.go b/plan/storage/sqlite/migrations.go index de62e57..5a645f3 100644 --- a/plan/storage/sqlite/migrations.go +++ b/plan/storage/sqlite/migrations.go @@ -40,4 +40,5 @@ var migrations = []string{ SELECT id, local_id FROM localids_backup`, `DROP TABLE localids_backup`, `ALTER TABLE items ADD COLUMN date TEXT NOT NULL DEFAULT ''`, + `ALTER TABLE tasks ADD COLUMN project TEXT NOT NULL DEFAULT ''`, } diff --git a/plan/storage/sqlite/task.go b/plan/storage/sqlite/task.go index ecf9a79..a619339 100644 --- a/plan/storage/sqlite/task.go +++ b/plan/storage/sqlite/task.go @@ -20,19 +20,20 @@ func (t *SqliteTask) Store(tsk item.Task) error { } if _, err := t.db.Exec(` INSERT INTO tasks -(id, title, date, time, duration, recurrer) +(id, title, project, date, time, duration, recurrer) VALUES -(?, ?, ?, ?, ?, ?) +(?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET title=?, +project=?, date=?, time=?, duration=?, recurrer=? `, - tsk.ID, tsk.Title, tsk.Date.String(), tsk.Time.String(), tsk.Duration.String(), recurStr, - tsk.Title, tsk.Date.String(), tsk.Time.String(), tsk.Duration.String(), recurStr); err != nil { + tsk.ID, tsk.Title, tsk.Project, tsk.Date.String(), tsk.Time.String(), tsk.Duration.String(), recurStr, + tsk.Title, tsk.Project, tsk.Date.String(), tsk.Time.String(), tsk.Duration.String(), recurStr); err != nil { return fmt.Errorf("%w: %v", ErrSqliteFailure, err) } return nil @@ -42,9 +43,9 @@ func (t *SqliteTask) FindOne(id string) (item.Task, error) { var tsk item.Task var dateStr, timeStr, recurStr, durStr string err := t.db.QueryRow(` -SELECT id, title, date, time, duration, recurrer +SELECT id, title, project, date, time, duration, recurrer FROM tasks -WHERE id = ?`, id).Scan(&tsk.ID, &tsk.Title, &dateStr, &timeStr, &durStr, &recurStr) +WHERE id = ?`, id).Scan(&tsk.ID, &tsk.Title, &tsk.Project, &dateStr, &timeStr, &durStr, &recurStr) switch { case err == sql.ErrNoRows: return item.Task{}, fmt.Errorf("event not found: %w", err) @@ -64,7 +65,7 @@ WHERE id = ?`, id).Scan(&tsk.ID, &tsk.Title, &dateStr, &timeStr, &durStr, &recur } func (t *SqliteTask) FindMany(params storage.TaskListParams) ([]item.Task, error) { - query := `SELECT id, title, date, time, duration, recurrer FROM tasks` + query := `SELECT id, title, project, date, time, duration, recurrer FROM tasks` args := []interface{}{} where := []string{} @@ -96,7 +97,7 @@ func (t *SqliteTask) FindMany(params storage.TaskListParams) ([]item.Task, error for rows.Next() { var tsk item.Task var dateStr, timeStr, recurStr, durStr string - if err := rows.Scan(&tsk.ID, &tsk.Title, &dateStr, &timeStr, &durStr, &recurStr); err != nil { + if err := rows.Scan(&tsk.ID, &tsk.Title, &tsk.Project, &dateStr, &timeStr, &durStr, &recurStr); err != nil { return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) } dur, err := time.ParseDuration(durStr)