introduce localupdate

This commit is contained in:
Erik Winter 2021-08-20 13:46:56 +02:00
parent 0a416d60f2
commit 91e5d86ec1
6 changed files with 128 additions and 67 deletions

View File

@ -5,6 +5,7 @@ import (
"git.ewintr.nl/gte/internal/configuration" "git.ewintr.nl/gte/internal/configuration"
"git.ewintr.nl/gte/internal/process" "git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/storage" "git.ewintr.nl/gte/internal/storage"
"git.ewintr.nl/gte/internal/task"
"git.ewintr.nl/gte/pkg/msend" "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())) disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP()))
fields := process.UpdateFields{"done": "true"}
localTask, err := local.FindByLocalId(localId) localTask, err := local.FindByLocalId(localId)
if err != nil { if err != nil {
return &Done{}, err return &Done{}, err
} }
updater := process.NewUpdate(local, disp, localTask.Id, fields) updater := process.NewUpdate(local, disp, localTask.Id, task.LocalUpdate{Done: true})
return &Done{ return &Done{
doner: updater, doner: updater,

View File

@ -47,8 +47,8 @@ func (u *Update) Do() string {
return "message sent\n" return "message sent\n"
} }
func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) { func ParseTaskFieldArgs(args []string) (task.LocalUpdate, error) {
result := process.UpdateFields{} lu := task.LocalUpdate{}
var action []string var action []string
for _, f := range args { for _, f := range args {
@ -56,15 +56,15 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) {
if len(split) == 2 { if len(split) == 2 {
switch split[0] { switch split[0] {
case "project": case "project":
if _, ok := result[task.FIELD_PROJECT]; ok { if lu.Project != "" {
return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT) return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_PROJECT)
} }
result[task.FIELD_PROJECT] = split[1] lu.Project = split[1]
case "due": case "due":
if _, ok := result[task.FIELD_DUE]; ok { if !lu.Due.IsZero() {
return process.UpdateFields{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE) return task.LocalUpdate{}, fmt.Errorf("%w: %s", ErrFieldAlreadyUsed, task.FIELD_DUE)
} }
result[task.FIELD_DUE] = split[1] lu.Due = task.NewDateFromString(split[1])
} }
} else { } else {
action = append(action, f) action = append(action, f)
@ -72,8 +72,8 @@ func ParseTaskFieldArgs(args []string) (process.UpdateFields, error) {
} }
if len(action) > 0 { if len(action) > 0 {
result[task.FIELD_ACTION] = strings.Join(action, " ") lu.Action = strings.Join(action, " ")
} }
return result, nil return lu, nil
} }

View File

@ -7,57 +7,54 @@ import (
"git.ewintr.nl/go-kit/test" "git.ewintr.nl/go-kit/test"
"git.ewintr.nl/gte/cmd/cli/command" "git.ewintr.nl/gte/cmd/cli/command"
"git.ewintr.nl/gte/internal/process"
"git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/internal/task"
) )
func TestParseTaskFieldArgs(t *testing.T) { func TestParseTaskFieldArgs(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
input string input string
expField process.UpdateFields expUpdate task.LocalUpdate
expErr error expErr error
}{ }{
{ {
name: "empty", name: "empty",
expField: process.UpdateFields{ expUpdate: task.LocalUpdate{},
task.FIELD_ACTION: "",
},
}, },
{ {
name: "join action", name: "join action",
input: "some things to do", input: "some things to do",
expField: process.UpdateFields{ expUpdate: task.LocalUpdate{
task.FIELD_ACTION: "some things to do", Action: "some things to do",
}, },
}, },
{ {
name: "all", name: "all",
input: "project:project do stuff due:2021-08-06", input: "project:project do stuff due:2021-08-06",
expField: process.UpdateFields{ expUpdate: task.LocalUpdate{
task.FIELD_ACTION: "do stuff", Action: "do stuff",
task.FIELD_PROJECT: "project", Project: "project",
task.FIELD_DUE: "2021-08-06", Due: task.NewDate(2021, 8, 6),
}, },
}, },
{ {
name: "no action", name: "no action",
input: "due:2021-08-06", input: "due:2021-08-06",
expField: process.UpdateFields{ expUpdate: task.LocalUpdate{
task.FIELD_DUE: "2021-08-06", Due: task.NewDate(2021, 8, 6),
}, },
}, },
{ {
name: "two projects", name: "two projects",
input: "project:project1 project:project2", input: "project:project1 project:project2",
expField: process.UpdateFields{}, expUpdate: task.LocalUpdate{},
expErr: command.ErrFieldAlreadyUsed, expErr: command.ErrFieldAlreadyUsed,
}, },
} { } {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
args := strings.Split(tc.input, " ") args := strings.Split(tc.input, " ")
act, err := command.ParseTaskFieldArgs(args) 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") test.Assert(t, errors.Is(err, tc.expErr), "wrong err")
}) })
} }

View File

@ -14,20 +14,18 @@ var (
// Update dispatches an updated version of a task // Update dispatches an updated version of a task
type Update struct { type Update struct {
local storage.LocalRepository local storage.LocalRepository
disp *storage.Dispatcher disp *storage.Dispatcher
taskId string taskId string
updates UpdateFields update task.LocalUpdate
} }
type UpdateFields map[string]string func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, update task.LocalUpdate) *Update {
func NewUpdate(local storage.LocalRepository, disp *storage.Dispatcher, taskId string, updates UpdateFields) *Update {
return &Update{ return &Update{
local: local, local: local,
disp: disp, disp: disp,
taskId: taskId, taskId: taskId,
updates: updates, update: update,
} }
} }
@ -36,21 +34,7 @@ func (u *Update) Process() error {
if err != nil { if err != nil {
return fmt.Errorf("%w: %v", ErrUpdateTask, err) return fmt.Errorf("%w: %v", ErrUpdateTask, err)
} }
tsk.Apply(u.update)
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
}
}
if err := u.disp.Dispatch(&tsk.Task); err != nil { if err := u.disp.Dispatch(&tsk.Task); err != nil {
return fmt.Errorf("%w: %v", ErrUpdateTask, err) return fmt.Errorf("%w: %v", ErrUpdateTask, err)

View File

@ -23,13 +23,13 @@ func TestUpdate(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
updates process.UpdateFields updates task.LocalUpdate
exp *task.Task exp *task.Task
}{ }{
{ {
name: "done", name: "done",
updates: process.UpdateFields{ updates: task.LocalUpdate{
task.FIELD_DONE: "true", Done: true,
}, },
exp: &task.Task{ exp: &task.Task{
Id: "id-1", Id: "id-1",
@ -42,10 +42,10 @@ func TestUpdate(t *testing.T) {
}, },
{ {
name: "fields", name: "fields",
updates: process.UpdateFields{ updates: task.LocalUpdate{
task.FIELD_PROJECT: "project2", Project: "project2",
task.FIELD_ACTION: "action2", Action: "action2",
task.FIELD_DUE: "2021-08-01", Due: task.NewDate(2021, 8, 1),
}, },
exp: &task.Task{ exp: &task.Task{
Id: "id-1", Id: "id-1",

View File

@ -1,12 +1,92 @@
package task package task
import (
"database/sql/driver"
"fmt"
"strings"
)
type LocalTask struct { type LocalTask struct {
Task Task
LocalId int 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 type ByDue []*LocalTask
func (lt ByDue) Len() int { return len(lt) } 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) 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) } 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
}