indicate modified local task - first step

This commit is contained in:
Erik Winter 2021-08-21 20:47:29 +02:00
parent f8bb80a803
commit 5fcd6de546
9 changed files with 135 additions and 33 deletions

View File

@ -20,7 +20,11 @@ func FormatTaskTable(tasks []*task.LocalTask) string {
var output string var output string
for _, t := range tasks { for _, t := range tasks {
output += fmt.Sprintf("%d\t%s\t%s (%s)\n", t.LocalId, t.Due.String(), t.Action, t.Project) var updateStr string
if t.LocalUpdate.ForVersion != 0 {
updateStr = " *"
}
output += fmt.Sprintf("%d%s\t%s\t%s (%s)\n", t.LocalId, updateStr, t.Due.String(), t.Action, t.Project)
} }
return output return output

View File

@ -34,6 +34,11 @@ 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)
} }
u.update.ForVersion = tsk.Version
if err := u.local.SetLocalUpdate(tsk.LocalId, &u.update); err != nil {
return fmt.Errorf("%w: %v", ErrUpdateTask, err)
}
tsk.Apply(u.update) tsk.Apply(u.update)
if err := u.disp.Dispatch(&tsk.Task); err != nil { if err := u.disp.Dispatch(&tsk.Task); err != nil {

View File

@ -19,6 +19,7 @@ type LocalRepository interface {
FindAllInProject(project string) ([]*task.LocalTask, error) FindAllInProject(project string) ([]*task.LocalTask, error)
FindById(id string) (*task.LocalTask, error) FindById(id string) (*task.LocalTask, error)
FindByLocalId(id int) (*task.LocalTask, error) FindByLocalId(id int) (*task.LocalTask, error)
SetLocalUpdate(localId int, localUpdate *task.LocalUpdate) error
} }
func NextLocalId(used []int) int { func NextLocalId(used []int) int {

View File

@ -6,17 +6,22 @@ import (
"git.ewintr.nl/gte/internal/task" "git.ewintr.nl/gte/internal/task"
) )
type localData struct {
LocalId int
LocalUpdate *task.LocalUpdate
}
// Memory is an in memory implementation of LocalRepository // Memory is an in memory implementation of LocalRepository
type Memory struct { type Memory struct {
tasks []*task.Task tasks []*task.Task
latestSync time.Time latestSync time.Time
localIds map[string]int localData map[string]localData
} }
func NewMemory() *Memory { func NewMemory() *Memory {
return &Memory{ return &Memory{
tasks: []*task.Task{}, tasks: []*task.Task{},
localIds: map[string]int{}, localData: map[string]localData{},
} }
} }
@ -40,12 +45,14 @@ func (m *Memory) SetTasks(tasks []*task.Task) error {
func (m *Memory) setLocalId(id string) { func (m *Memory) setLocalId(id string) {
used := []int{} used := []int{}
for _, id := range m.localIds { for _, ld := range m.localData {
used = append(used, id) used = append(used, ld.LocalId)
} }
next := NextLocalId(used) next := NextLocalId(used)
m.localIds[id] = next m.localData[id] = localData{
LocalId: next,
}
} }
func (m *Memory) FindAllInFolder(folder string) ([]*task.LocalTask, error) { func (m *Memory) FindAllInFolder(folder string) ([]*task.LocalTask, error) {
@ -53,8 +60,9 @@ func (m *Memory) FindAllInFolder(folder string) ([]*task.LocalTask, error) {
for _, t := range m.tasks { for _, t := range m.tasks {
if t.Folder == folder { if t.Folder == folder {
tasks = append(tasks, &task.LocalTask{ tasks = append(tasks, &task.LocalTask{
Task: *t, Task: *t,
LocalId: m.localIds[t.Id], LocalId: m.localData[t.Id].LocalId,
LocalUpdate: m.localData[t.Id].LocalUpdate,
}) })
} }
} }
@ -67,8 +75,9 @@ func (m *Memory) FindAllInProject(project string) ([]*task.LocalTask, error) {
for _, t := range m.tasks { for _, t := range m.tasks {
if t.Project == project { if t.Project == project {
tasks = append(tasks, &task.LocalTask{ tasks = append(tasks, &task.LocalTask{
Task: *t, Task: *t,
LocalId: m.localIds[t.Id], LocalId: m.localData[t.Id].LocalId,
LocalUpdate: m.localData[t.Id].LocalUpdate,
}) })
} }
} }
@ -80,8 +89,9 @@ func (m *Memory) FindById(id string) (*task.LocalTask, error) {
for _, t := range m.tasks { for _, t := range m.tasks {
if t.Id == id { if t.Id == id {
return &task.LocalTask{ return &task.LocalTask{
Task: *t, Task: *t,
LocalId: m.localIds[t.Id], LocalId: m.localData[t.Id].LocalId,
LocalUpdate: m.localData[t.Id].LocalUpdate,
}, nil }, nil
} }
} }
@ -91,13 +101,28 @@ func (m *Memory) FindById(id string) (*task.LocalTask, error) {
func (m *Memory) FindByLocalId(localId int) (*task.LocalTask, error) { func (m *Memory) FindByLocalId(localId int) (*task.LocalTask, error) {
for _, t := range m.tasks { for _, t := range m.tasks {
if m.localIds[t.Id] == localId { if m.localData[t.Id].LocalId == localId {
return &task.LocalTask{ return &task.LocalTask{
Task: *t, Task: *t,
LocalId: localId, LocalId: localId,
LocalUpdate: m.localData[t.Id].LocalUpdate,
}, nil }, nil
} }
} }
return &task.LocalTask{}, ErrTaskNotFound return &task.LocalTask{}, ErrTaskNotFound
} }
func (m *Memory) SetLocalUpdate(localId int, localUpdate *task.LocalUpdate) error {
t, err := m.FindByLocalId(localId)
if err != nil {
return err
}
m.localData[t.Id] = localData{
LocalId: localId,
LocalUpdate: localUpdate,
}
return nil
}

View File

@ -97,4 +97,21 @@ func TestMemory(t *testing.T) {
test.OK(t, err) test.OK(t, err)
test.Equals(t, localTask2, act) test.Equals(t, localTask2, act)
}) })
t.Run("setlocalupdate", func(t *testing.T) {
mem := storage.NewMemory()
test.OK(t, mem.SetTasks(tasks))
expUpdate := &task.LocalUpdate{
ForVersion: 1,
Action: "update action",
Project: "update project",
Due: task.NewDate(2021, 8, 21),
Recur: task.NewRecurrer("today, weekly, monday"),
Done: true,
}
test.OK(t, mem.SetLocalUpdate(2, expUpdate))
actTask, err := mem.FindByLocalId(2)
test.OK(t, err)
test.Equals(t, expUpdate, actTask.LocalUpdate)
})
} }

View File

@ -18,6 +18,7 @@ var sqliteMigrations = []sqliteMigration{
`INSERT INTO system (latest_sync) VALUES (0)`, `INSERT INTO system (latest_sync) VALUES (0)`,
`CREATE TABLE local_id ("id" TEXT UNIQUE, "local_id" INTEGER UNIQUE)`, `CREATE TABLE local_id ("id" TEXT UNIQUE, "local_id" INTEGER UNIQUE)`,
`ALTER TABLE local_id RENAME TO local_task`, `ALTER TABLE local_id RENAME TO local_task`,
`ALTER TABLE local_task ADD COLUMN local_update TEXT`,
} }
var ( var (
@ -153,7 +154,7 @@ SET latest_sync = ?`,
func (s *Sqlite) FindAllInFolder(folder string) ([]*task.LocalTask, error) { func (s *Sqlite) FindAllInFolder(folder string) ([]*task.LocalTask, error) {
rows, err := s.db.Query(` rows, err := s.db.Query(`
SELECT task.id, local_task.local_id, version, folder, action, project, due, recur SELECT task.id, local_task.local_id, version, folder, action, project, due, recur, local_task.local_update
FROM task FROM task
LEFT JOIN local_task ON task.id = local_task.id LEFT JOIN local_task ON task.id = local_task.id
WHERE folder = ?`, folder) WHERE folder = ?`, folder)
@ -166,7 +167,7 @@ WHERE folder = ?`, folder)
func (s *Sqlite) FindAllInProject(project string) ([]*task.LocalTask, error) { func (s *Sqlite) FindAllInProject(project string) ([]*task.LocalTask, error) {
rows, err := s.db.Query(` rows, err := s.db.Query(`
SELECT task.id, local_task.local_id, version, folder, action, project, due, recur SELECT task.id, local_task.local_id, version, folder, action, project, due, recur, local_task.local_update
FROM task FROM task
LEFT JOIN local_task ON task.id = local_task.id LEFT JOIN local_task ON task.id = local_task.id
WHERE project = ?`, project) WHERE project = ?`, project)
@ -180,13 +181,14 @@ WHERE project = ?`, project)
func (s *Sqlite) FindById(id string) (*task.LocalTask, error) { func (s *Sqlite) FindById(id string) (*task.LocalTask, error) {
var folder, action, project, due, recur string var folder, action, project, due, recur string
var localId, version int var localId, version int
var localUpdate task.LocalUpdate
row := s.db.QueryRow(` row := s.db.QueryRow(`
SELECT local_task.local_id, version, folder, action, project, due, recur SELECT local_task.local_id, version, folder, action, project, due, recur, local_task.local_update
FROM task FROM task
LEFT JOIN local_task ON task.id = local_task.id LEFT JOIN local_task ON task.id = local_task.id
WHERE task.id = ? WHERE task.id = ?
LIMIT 1`, id) LIMIT 1`, id)
if err := row.Scan(&localId, &version, &folder, &action, &project, &due, &recur); err != nil { if err := row.Scan(&localId, &version, &folder, &action, &project, &due, &recur, &localUpdate); err != nil {
return &task.LocalTask{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) return &task.LocalTask{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err)
} }
@ -200,7 +202,8 @@ LIMIT 1`, id)
Due: task.NewDateFromString(due), Due: task.NewDateFromString(due),
Recur: task.NewRecurrer(recur), Recur: task.NewRecurrer(recur),
}, },
LocalId: localId, LocalId: localId,
LocalUpdate: &localUpdate,
}, nil }, nil
} }
@ -219,6 +222,17 @@ func (s *Sqlite) FindByLocalId(localId int) (*task.LocalTask, error) {
return t, nil return t, nil
} }
func (s *Sqlite) SetLocalUpdate(localId int, localUpdate *task.LocalUpdate) error {
if _, err := s.db.Exec(`
UPDATE local_task
SET local_update = ?
WHERE local_id = ?`, localUpdate, localId); err != nil {
return fmt.Errorf("%w: %v", ErrSqliteFailure, err)
}
return nil
}
func tasksFromRows(rows *sql.Rows) ([]*task.LocalTask, error) { func tasksFromRows(rows *sql.Rows) ([]*task.LocalTask, error) {
tasks := []*task.LocalTask{} tasks := []*task.LocalTask{}
@ -226,7 +240,8 @@ func tasksFromRows(rows *sql.Rows) ([]*task.LocalTask, error) {
for rows.Next() { for rows.Next() {
var id, folder, action, project, due, recur string var id, folder, action, project, due, recur string
var localId, version int var localId, version int
if err := rows.Scan(&id, &localId, &version, &folder, &action, &project, &due, &recur); err != nil { var localUpdate task.LocalUpdate
if err := rows.Scan(&id, &localId, &version, &folder, &action, &project, &due, &recur, &localUpdate); err != nil {
return []*task.LocalTask{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) return []*task.LocalTask{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err)
} }
tasks = append(tasks, &task.LocalTask{ tasks = append(tasks, &task.LocalTask{
@ -239,7 +254,8 @@ func tasksFromRows(rows *sql.Rows) ([]*task.LocalTask, error) {
Due: task.NewDateFromString(due), Due: task.NewDateFromString(due),
Recur: task.NewRecurrer(recur), Recur: task.NewRecurrer(recur),
}, },
LocalId: localId, LocalId: localId,
LocalUpdate: &localUpdate,
}) })
} }

View File

@ -3,12 +3,14 @@ package task
import ( import (
"database/sql/driver" "database/sql/driver"
"fmt" "fmt"
"strconv"
"strings" "strings"
) )
type LocalTask struct { type LocalTask struct {
Task Task
LocalId int LocalId int
LocalUpdate *LocalUpdate
} }
func (lt *LocalTask) Apply(lu LocalUpdate) { func (lt *LocalTask) Apply(lu LocalUpdate) {
@ -52,22 +54,30 @@ func (lt ByDefault) Less(i, j int) bool {
} }
type LocalUpdate struct { type LocalUpdate struct {
Action string ForVersion int
Project string Action string
Due Date Project string
Recur Recurrer Due Date
Done bool Recur Recurrer
Done bool
} }
func (lu LocalUpdate) Value() (driver.Value, error) { func (lu LocalUpdate) Value() (driver.Value, error) {
return fmt.Sprintf(`action: %s var recurStr string
if lu.Recur != nil {
recurStr = lu.Recur.String()
}
return fmt.Sprintf(`forversion: %d
action: %s
project: %s project: %s
recur: %s recur: %s
due: %s due: %s
done: %t`, done: %t`,
lu.ForVersion,
lu.Action, lu.Action,
lu.Project, lu.Project,
lu.Recur.String(), recurStr,
lu.Due.String(), lu.Due.String(),
lu.Done), nil lu.Done), nil
} }
@ -88,6 +98,9 @@ func (lu *LocalUpdate) Scan(value interface{}) error {
k := strings.TrimSpace(kv[0]) k := strings.TrimSpace(kv[0])
v := strings.TrimSpace(kv[1]) v := strings.TrimSpace(kv[1])
switch k { switch k {
case "forversion":
d, _ := strconv.Atoi(v)
newLu.ForVersion = d
case "action": case "action":
newLu.Action = v newLu.Action = v
case "project": case "project":

View File

@ -214,12 +214,16 @@ func (im *IMAP) Messages(folder string) ([]*Message, error) {
// above sometimes returns the same message twice, but with a different uid. // above sometimes returns the same message twice, but with a different uid.
dedupMessages := []*Message{} dedupMessages := []*Message{}
for _, m := range messages { for _, m := range messages {
var isDupe bool
for _, dm := range dedupMessages { for _, dm := range dedupMessages {
if m.Equal(dm) { if m.Equal(dm) {
continue isDupe = true
break
} }
} }
dedupMessages = append(dedupMessages, m) if !isDupe {
dedupMessages = append(dedupMessages, m)
}
} }
return dedupMessages, nil return dedupMessages, nil

View File

@ -2,6 +2,7 @@ package mstore
import ( import (
"errors" "errors"
"fmt"
) )
var ( var (
@ -24,13 +25,29 @@ func (m *Message) Valid() bool {
} }
func (m *Message) Equal(n *Message) bool { func (m *Message) Equal(n *Message) bool {
var prt bool
if m.Uid == 156 && n.Uid == 155 {
prt = true
}
if m.Uid == 155 && n.Uid == 156 {
prt = true
}
if m.Folder != n.Folder { if m.Folder != n.Folder {
if prt {
fmt.Println("folder")
}
return false return false
} }
if m.Subject != n.Subject { if m.Subject != n.Subject {
if prt {
fmt.Println("subject")
}
return false return false
} }
if m.Body != n.Body { if m.Body != n.Body {
if prt {
fmt.Println("body")
}
return false return false
} }