indicate modified local task - first step
This commit is contained in:
parent
f8bb80a803
commit
5fcd6de546
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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":
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue