From 91e5d86ec1b3a878206674903d64adf8488bf5ed Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Fri, 20 Aug 2021 13:46:56 +0200 Subject: [PATCH] introduce localupdate --- cmd/cli/command/done.go | 4 +- cmd/cli/command/update.go | 20 ++++----- cmd/cli/command/update_test.go | 41 ++++++++--------- internal/process/update.go | 36 +++++---------- internal/process/update_test.go | 14 +++--- internal/task/localtask.go | 80 +++++++++++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 67 deletions(-) diff --git a/cmd/cli/command/done.go b/cmd/cli/command/done.go index e15f9f9..1e51a7e 100644 --- a/cmd/cli/command/done.go +++ b/cmd/cli/command/done.go @@ -5,6 +5,7 @@ import ( "git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/storage" + "git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/pkg/msend" ) @@ -20,13 +21,12 @@ func NewDone(localId int, conf *configuration.Configuration) (*Done, error) { } disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP())) - fields := process.UpdateFields{"done": "true"} localTask, err := local.FindByLocalId(localId) if err != nil { return &Done{}, err } - updater := process.NewUpdate(local, disp, localTask.Id, fields) + updater := process.NewUpdate(local, disp, localTask.Id, task.LocalUpdate{Done: true}) return &Done{ doner: updater, diff --git a/cmd/cli/command/update.go b/cmd/cli/command/update.go index e497d37..6fc585f 100644 --- a/cmd/cli/command/update.go +++ b/cmd/cli/command/update.go @@ -47,8 +47,8 @@ func (u *Update) Do() string { return "message sent\n" } -func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) { - result := process.UpdateFields{} +func ParseTaskFieldArgs(args []string) (task.LocalUpdate, error) { + lu := task.LocalUpdate{} var action []string for _, f := range args { @@ -56,15 +56,15 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) { if len(split) == 2 { switch split[0] { case "project": - if _, ok := result[task.FIELD_PROJECT]; ok { - return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT) + if lu.Project != "" { + return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT) } - result[task.FIELD_PROJECT] = split[1] + lu.Project = split[1] case "due": - if _, ok := result[task.FIELD_DUE]; ok { - return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE) + if !lu.Due.IsZero() { + return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE) } - result[task.FIELD_DUE] = split[1] + lu.Due = task.NewDateFromString(split[1]) } } else { action = append(action, f) @@ -72,8 +72,8 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) { } if len(action) > 0 { - result[task.FIELD_ACTION] = strings.Join(action, " ") + lu.Action = strings.Join(action, " ") } - return result, nil + return lu, nil } diff --git a/cmd/cli/command/update_test.go b/cmd/cli/command/update_test.go index 7174bea..e314515 100644 --- a/cmd/cli/command/update_test.go +++ b/cmd/cli/command/update_test.go @@ -7,57 +7,54 @@ import ( "git.ewintr.nl/go-kit/test" "git.ewintr.nl/gte/cmd/cli/command" - "git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/task" ) func TestParseTaskFieldArgs(t *testing.T) { for _, tc := range []struct { - name string - input string - expField process.UpdateFields - expErr error + name string + input string + expUpdate task.LocalUpdate + expErr error }{ { - name: "empty", - expField: process.UpdateFields{ - task.FIELD_ACTION: "", - }, + name: "empty", + expUpdate: task.LocalUpdate{}, }, { name: "join action", input: "some things to do", - expField: process.UpdateFields{ - task.FIELD_ACTION: "some things to do", + expUpdate: task.LocalUpdate{ + Action: "some things to do", }, }, { name: "all", input: "project:project do stuff due:2021-08-06", - expField: process.UpdateFields{ - task.FIELD_ACTION: "do stuff", - task.FIELD_PROJECT: "project", - task.FIELD_DUE: "2021-08-06", + expUpdate: task.LocalUpdate{ + Action: "do stuff", + Project: "project", + Due: task.NewDate(2021, 8, 6), }, }, { name: "no action", input: "due:2021-08-06", - expField: process.UpdateFields{ - task.FIELD_DUE: "2021-08-06", + expUpdate: task.LocalUpdate{ + Due: task.NewDate(2021, 8, 6), }, }, { - name: "two projects", - input: "project:project1 project:project2", - expField: process.UpdateFields{}, - expErr: command.ErrFieldAlreadyUsed, + name: "two projects", + input: "project:project1 project:project2", + expUpdate: task.LocalUpdate{}, + expErr: command.ErrFieldAlreadyUsed, }, } { t.Run(tc.name, func(t *testing.T) { args := strings.Split(tc.input, " ") act, err := command.ParseTaskFieldArgs(args) - test.Equals(t, tc.expField, act) + test.Equals(t, tc.expUpdate, act) test.Assert(t, errors.Is(err, tc.expErr), "wrong err") }) } diff --git a/internal/process/update.go b/internal/process/update.go index 7fe04e6..f9fd696 100644 --- a/internal/process/update.go +++ b/internal/process/update.go @@ -14,20 +14,18 @@ var ( // Update dispatches an updated version of a task type Update struct { - local storage.LocalRepository - disp *storage.Dispatcher - taskId string - updates UpdateFields + local storage.LocalRepository + disp *storage.Dispatcher + taskId string + update task.LocalUpdate } -type UpdateFields map[string]string - -func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, updates UpdateFields) *Update { +func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, update task.LocalUpdate) *Update { return &Update{ - local: local, - disp: disp, - taskId: taskId, - updates: updates, + local: local, + disp: disp, + taskId: taskId, + update: update, } } @@ -36,21 +34,7 @@ func (u *Update) Process() error { if err != nil { return fmt.Errorf("%w: %v", ErrUpdateTask, err) } - - for k, v := range u.updates { - switch k { - case task.FIELD_DONE: - if v == "true" { - tsk.Done = true - } - case task.FIELD_DUE: - tsk.Due = task.NewDateFromString(v) - case task.FIELD_ACTION: - tsk.Action = v - case task.FIELD_PROJECT: - tsk.Project = v - } - } + tsk.Apply(u.update) if err := u.disp.Dispatch(&tsk.Task); err != nil { return fmt.Errorf("%w: %v", ErrUpdateTask, err) diff --git a/internal/process/update_test.go b/internal/process/update_test.go index 450ca33..1508b27 100644 --- a/internal/process/update_test.go +++ b/internal/process/update_test.go @@ -23,13 +23,13 @@ func TestUpdate(t *testing.T) { for _, tc := range []struct { name string - updates process.UpdateFields + updates task.LocalUpdate exp *task.Task }{ { name: "done", - updates: process.UpdateFields{ - task.FIELD_DONE: "true", + updates: task.LocalUpdate{ + Done: true, }, exp: &task.Task{ Id: "id-1", @@ -42,10 +42,10 @@ func TestUpdate(t *testing.T) { }, { name: "fields", - updates: process.UpdateFields{ - task.FIELD_PROJECT: "project2", - task.FIELD_ACTION: "action2", - task.FIELD_DUE: "2021-08-01", + updates: task.LocalUpdate{ + Project: "project2", + Action: "action2", + Due: task.NewDate(2021, 8, 1), }, exp: &task.Task{ Id: "id-1", diff --git a/internal/task/localtask.go b/internal/task/localtask.go index a7eaac8..ab5a72b 100644 --- a/internal/task/localtask.go +++ b/internal/task/localtask.go @@ -1,12 +1,92 @@ package task +import ( + "database/sql/driver" + "fmt" + "strings" +) + type LocalTask struct { Task LocalId int } +func (lt *LocalTask) Apply(lu LocalUpdate) { + if lu.Action != "" { + lt.Action = lu.Action + } + if lu.Project != "" { + lt.Project = lu.Project + } + if lu.Recur != nil { + lt.Recur = lu.Recur + } + if !lu.Due.IsZero() { + lt.Due = lu.Due + } + if lu.Done { + lt.Done = lu.Done + } +} + type ByDue []*LocalTask func (lt ByDue) Len() int { return len(lt) } func (lt ByDue) Swap(i, j int) { lt[i], lt[j] = lt[j], lt[i] } func (lt ByDue) Less(i, j int) bool { return lt[j].Due.After(lt[i].Due) } + +type LocalUpdate struct { + Action string + Project string + Due Date + Recur Recurrer + Done bool +} + +func (lu LocalUpdate) Value() (driver.Value, error) { + return fmt.Sprintf(`action: %s +project: %s +recur: %s +due: %s +done: %t`, + lu.Action, + lu.Project, + lu.Recur.String(), + lu.Due.String(), + lu.Done), nil +} + +func (lu *LocalUpdate) Scan(value interface{}) error { + body, err := driver.String.ConvertValue(value) + if err != nil { + *lu = LocalUpdate{} + return nil + } + + newLu := LocalUpdate{} + for _, line := range strings.Split(body.(string), "\n") { + kv := strings.SplitN(line, ":", 2) + if len(kv) < 2 { + continue + } + k := strings.TrimSpace(kv[0]) + v := strings.TrimSpace(kv[1]) + switch k { + case "action": + newLu.Action = v + case "project": + newLu.Project = v + case "recur": + newLu.Recur = NewRecurrer(v) + case "due": + newLu.Due = NewDateFromString(v) + case "done": + if v == "true" { + newLu.Done = true + } + } + } + *lu = newLu + + return nil +}