diff --git a/dist/plan b/dist/plan index d151fe6..2154802 100755 Binary files a/dist/plan and b/dist/plan differ diff --git a/dist/plannersync b/dist/plannersync index 23f87a5..54b1796 100755 Binary files a/dist/plannersync and b/dist/plannersync differ diff --git a/item/item.go b/item/item.go index c6b20aa..10d3cc8 100644 --- a/item/item.go +++ b/item/item.go @@ -10,12 +10,12 @@ import ( type Kind string const ( - KindTask Kind = "task" - KindEvent Kind = "event" + KindSchedule Kind = "schedule" + KindTask Kind = "task" ) var ( - KnownKinds = []Kind{KindTask, KindEvent} + KnownKinds = []Kind{KindSchedule, KindTask} ) type Item struct { diff --git a/item/event.go b/item/task.go similarity index 53% rename from item/event.go rename to item/task.go index 8241645..31fbfa0 100644 --- a/item/event.go +++ b/item/task.go @@ -8,14 +8,14 @@ import ( "github.com/google/go-cmp/cmp" ) -type EventBody struct { +type TaskBody struct { Title string `json:"title"` Time Time `json:"time"` Duration time.Duration `json:"duration"` } -func (e EventBody) MarshalJSON() ([]byte, error) { - type Alias EventBody +func (e TaskBody) MarshalJSON() ([]byte, error) { + type Alias TaskBody return json.Marshal(&struct { Duration string `json:"duration"` *Alias @@ -25,8 +25,8 @@ func (e EventBody) MarshalJSON() ([]byte, error) { }) } -func (e *EventBody) UnmarshalJSON(data []byte) error { - type Alias EventBody +func (e *TaskBody) UnmarshalJSON(data []byte) error { + type Alias TaskBody aux := &struct { Duration string `json:"duration"` *Alias @@ -45,70 +45,70 @@ func (e *EventBody) UnmarshalJSON(data []byte) error { return nil } -type Event struct { +type Task struct { ID string `json:"id"` Date Date `json:"date"` Recurrer Recurrer `json:"recurrer"` RecurNext Date `json:"recurNext"` - EventBody + TaskBody } -func NewEvent(i Item) (Event, error) { - if i.Kind != KindEvent { - return Event{}, fmt.Errorf("item is not an event") +func NewTask(i Item) (Task, error) { + if i.Kind != KindTask { + return Task{}, fmt.Errorf("item is not an task") } - var e Event - if err := json.Unmarshal([]byte(i.Body), &e); err != nil { - return Event{}, fmt.Errorf("could not unmarshal item body: %v", err) + var t Task + if err := json.Unmarshal([]byte(i.Body), &t); err != nil { + return Task{}, fmt.Errorf("could not unmarshal item body: %v", err) } - e.ID = i.ID - e.Date = i.Date - e.Recurrer = i.Recurrer - e.RecurNext = i.RecurNext + t.ID = i.ID + t.Date = i.Date + t.Recurrer = i.Recurrer + t.RecurNext = i.RecurNext - return e, nil + return t, nil } -func (e Event) Item() (Item, error) { - body, err := json.Marshal(e.EventBody) +func (t Task) Item() (Item, error) { + body, err := json.Marshal(t.TaskBody) if err != nil { - return Item{}, fmt.Errorf("could not marshal event body to json") + return Item{}, fmt.Errorf("could not marshal task body to json") } return Item{ - ID: e.ID, - Kind: KindEvent, - Date: e.Date, - Recurrer: e.Recurrer, - RecurNext: e.RecurNext, + ID: t.ID, + Kind: KindTask, + Date: t.Date, + Recurrer: t.Recurrer, + RecurNext: t.RecurNext, Body: string(body), }, nil } -func (e Event) Valid() bool { - if e.Title == "" { +func (t Task) Valid() bool { + if t.Title == "" { return false } - if e.Date.IsZero() { + if t.Date.IsZero() { return false } - if e.Duration.Seconds() < 1 { + if t.Duration.Seconds() < 1 { return false } return true } -func EventDiff(a, b Event) string { +func TaskDiff(a, b Task) string { aJSON, _ := json.Marshal(a) bJSON, _ := json.Marshal(b) return cmp.Diff(string(aJSON), string(bJSON)) } -func EventDiffs(a, b []Event) string { +func TaskDiffs(a, b []Task) string { aJSON, _ := json.Marshal(a) bJSON, _ := json.Marshal(b) diff --git a/item/event_test.go b/item/task_test.go similarity index 78% rename from item/event_test.go rename to item/task_test.go index 7c20bda..d4e342e 100644 --- a/item/event_test.go +++ b/item/task_test.go @@ -8,7 +8,7 @@ import ( "go-mod.ewintr.nl/planner/item" ) -func TestNewEvent(t *testing.T) { +func TestNewTask(t *testing.T) { t.Parallel() oneHour, err := time.ParseDuration("1h") @@ -16,17 +16,17 @@ func TestNewEvent(t *testing.T) { t.Errorf("exp nil, got %v", err) } for _, tc := range []struct { - name string - it item.Item - expEvent item.Event - expErr bool + name string + it item.Item + expTask item.Task + expErr bool }{ { name: "wrong kind", it: item.Item{ ID: "a", Date: item.NewDate(2024, 9, 20), - Kind: item.KindTask, + Kind: item.KindSchedule, Body: `{ "title":"title", "time":"08:00", @@ -39,7 +39,7 @@ func TestNewEvent(t *testing.T) { name: "invalid json", it: item.Item{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Body: `{"id":"a"`, }, expErr: true, @@ -48,7 +48,7 @@ func TestNewEvent(t *testing.T) { name: "valid", it: item.Item{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Date: item.NewDate(2024, 9, 20), Recurrer: item.NewRecurrer("2024-12-08, daily"), Body: `{ @@ -57,11 +57,11 @@ func TestNewEvent(t *testing.T) { "duration":"1h" }`, }, - expEvent: item.Event{ + expTask: item.Task{ ID: "a", Date: item.NewDate(2024, 9, 20), Recurrer: item.NewRecurrer("2024-12-08, daily"), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: item.NewTime(8, 0), Duration: oneHour, @@ -70,21 +70,21 @@ func TestNewEvent(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - actEvent, actErr := item.NewEvent(tc.it) + actTask, actErr := item.NewTask(tc.it) if tc.expErr != (actErr != nil) { t.Errorf("exp nil, got %v", actErr) } if tc.expErr { return } - if diff := item.EventDiff(tc.expEvent, actEvent); diff != "" { + if diff := item.TaskDiff(tc.expTask, actTask); diff != "" { t.Errorf("(+exp, -got)\n%s", diff) } }) } } -func TestEventItem(t *testing.T) { +func TestTaskItem(t *testing.T) { t.Parallel() oneHour, err := time.ParseDuration("1h") @@ -93,24 +93,24 @@ func TestEventItem(t *testing.T) { } for _, tc := range []struct { name string - event item.Event + tsk item.Task expItem item.Item expErr bool }{ { name: "empty", expItem: item.Item{ - Kind: item.KindEvent, + Kind: item.KindTask, Updated: time.Time{}, Body: `{"duration":"0s","title":"","time":"00:00"}`, }, }, { name: "normal", - event: item.Event{ + tsk: item.Task{ ID: "a", Date: item.NewDate(2024, 9, 23), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: item.NewTime(8, 0), Duration: oneHour, @@ -118,7 +118,7 @@ func TestEventItem(t *testing.T) { }, expItem: item.Item{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Updated: time.Time{}, Date: item.NewDate(2024, 9, 23), Body: `{"duration":"1h0m0s","title":"title","time":"08:00"}`, @@ -126,7 +126,7 @@ func TestEventItem(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - actItem, actErr := tc.event.Item() + actItem, actErr := tc.tsk.Item() if tc.expErr != (actErr != nil) { t.Errorf("exp nil, got %v", actErr) } @@ -140,7 +140,7 @@ func TestEventItem(t *testing.T) { } } -func TestEventValidate(t *testing.T) { +func TestTaskValidate(t *testing.T) { t.Parallel() oneHour, err := time.ParseDuration("1h") @@ -149,19 +149,19 @@ func TestEventValidate(t *testing.T) { } for _, tc := range []struct { - name string - event item.Event - exp bool + name string + tsk item.Task + exp bool }{ { name: "empty", }, { name: "missing title", - event: item.Event{ + tsk: item.Task{ ID: "a", Date: item.NewDate(2024, 9, 20), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Time: item.NewTime(8, 0), Duration: oneHour, }, @@ -169,9 +169,9 @@ func TestEventValidate(t *testing.T) { }, { name: "no date", - event: item.Event{ + tsk: item.Task{ ID: "a", - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: item.NewTime(8, 0), Duration: oneHour, @@ -180,10 +180,10 @@ func TestEventValidate(t *testing.T) { }, { name: "no duration", - event: item.Event{ + tsk: item.Task{ ID: "a", Date: item.NewDate(2024, 9, 20), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: item.NewTime(8, 0), }, @@ -191,10 +191,10 @@ func TestEventValidate(t *testing.T) { }, { name: "valid", - event: item.Event{ + tsk: item.Task{ ID: "a", Date: item.NewDate(2024, 9, 20), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: item.NewTime(8, 0), Duration: oneHour, @@ -204,7 +204,7 @@ func TestEventValidate(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - if act := tc.event.Valid(); tc.exp != act { + if act := tc.tsk.Valid(); tc.exp != act { t.Errorf("exp %v, got %v", tc.exp, act) } diff --git a/plan/command/add.go b/plan/command/add.go index 8568c9e..53c39b0 100644 --- a/plan/command/add.go +++ b/plan/command/add.go @@ -11,15 +11,15 @@ import ( type Add struct { localIDRepo storage.LocalID - eventRepo storage.Event + taskRepo storage.Task syncRepo storage.Sync argSet *ArgSet } -func NewAdd(localRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { +func NewAdd(localRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { return &Add{ localIDRepo: localRepo, - eventRepo: eventRepo, + taskRepo: taskRepo, syncRepo: syncRepo, argSet: &ArgSet{ Flags: map[string]Flag{ @@ -75,21 +75,21 @@ func (add *Add) Execute(main []string, flags map[string]string) error { func (add *Add) do() error { as := add.argSet rec := as.GetRecurrer(FlagRec) - e := item.Event{ + tsk := item.Task{ ID: uuid.New().String(), Date: as.GetDate(FlagOn), Recurrer: rec, - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: as.Main, Time: as.GetTime(FlagAt), Duration: as.GetDuration(FlagFor), }, } if rec != nil { - e.RecurNext = rec.First() + tsk.RecurNext = rec.First() } - if err := add.eventRepo.Store(e); err != nil { + if err := add.taskRepo.Store(tsk); err != nil { return fmt.Errorf("could not store event: %v", err) } @@ -97,11 +97,11 @@ func (add *Add) do() error { if err != nil { return fmt.Errorf("could not create next local id: %v", err) } - if err := add.localIDRepo.Store(e.ID, localID); err != nil { + if err := add.localIDRepo.Store(tsk.ID, localID); err != nil { return fmt.Errorf("could not store local id: %v", err) } - it, err := e.Item() + it, err := tsk.Item() if err != nil { return fmt.Errorf("could not convert event to sync item: %v", err) } diff --git a/plan/command/add_test.go b/plan/command/add_test.go index 212ad69..6af038d 100644 --- a/plan/command/add_test.go +++ b/plan/command/add_test.go @@ -19,11 +19,11 @@ func TestAdd(t *testing.T) { anHour := time.Hour for _, tc := range []struct { - name string - main []string - flags map[string]string - expErr bool - expEvent item.Event + name string + main []string + flags map[string]string + expErr bool + expTask item.Task }{ { name: "empty", @@ -48,10 +48,10 @@ func TestAdd(t *testing.T) { flags: map[string]string{ command.FlagOn: aDate.String(), }, - expEvent: item.Event{ + expTask: item.Task{ ID: "title", Date: aDate, - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Duration: aDay, }, @@ -65,10 +65,10 @@ func TestAdd(t *testing.T) { command.FlagAt: aTime.String(), command.FlagFor: anHourStr, }, - expEvent: item.Event{ + expTask: item.Task{ ID: "title", Date: aDate, - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Time: aTime, Duration: anHour, @@ -86,10 +86,10 @@ func TestAdd(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() localRepo := memory.NewLocalID() syncRepo := memory.NewSync() - cmd := command.NewAdd(localRepo, eventRepo, syncRepo) + cmd := command.NewAdd(localRepo, taskRepo, syncRepo) actParseErr := cmd.Execute(tc.main, tc.flags) != nil if tc.expErr != actParseErr { t.Errorf("exp %v, got %v", tc.expErr, actParseErr) @@ -98,12 +98,12 @@ func TestAdd(t *testing.T) { return } - actEvents, err := eventRepo.FindAll() + actTasks, err := taskRepo.FindAll() if err != nil { t.Errorf("exp nil, got %v", err) } - if len(actEvents) != 1 { - t.Errorf("exp 1, got %d", len(actEvents)) + if len(actTasks) != 1 { + t.Errorf("exp 1, got %d", len(actTasks)) } actLocalIDs, err := localRepo.FindAll() @@ -113,15 +113,15 @@ func TestAdd(t *testing.T) { if len(actLocalIDs) != 1 { t.Errorf("exp 1, got %v", len(actLocalIDs)) } - if _, ok := actLocalIDs[actEvents[0].ID]; !ok { + if _, ok := actLocalIDs[actTasks[0].ID]; !ok { t.Errorf("exp true, got %v", ok) } - if actEvents[0].ID == "" { + if actTasks[0].ID == "" { t.Errorf("exp string not te be empty") } - tc.expEvent.ID = actEvents[0].ID - if diff := item.EventDiff(tc.expEvent, actEvents[0]); diff != "" { + tc.expTask.ID = actTasks[0].ID + if diff := item.TaskDiff(tc.expTask, actTasks[0]); diff != "" { t.Errorf("(exp -, got +)\n%s", diff) } diff --git a/plan/command/delete.go b/plan/command/delete.go index 9490b56..e6325fd 100644 --- a/plan/command/delete.go +++ b/plan/command/delete.go @@ -9,15 +9,15 @@ import ( type Delete struct { localIDRepo storage.LocalID - eventRepo storage.Event + taskRepo storage.Task syncRepo storage.Sync localID int } -func NewDelete(localIDRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { +func NewDelete(localIDRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { return &Delete{ localIDRepo: localIDRepo, - eventRepo: eventRepo, + taskRepo: taskRepo, syncRepo: syncRepo, } } @@ -41,23 +41,23 @@ func (del *Delete) do() error { if err != nil { return fmt.Errorf("could not get local ids: %v", err) } - for eid, lid := range idMap { + for tskID, lid := range idMap { if del.localID == lid { - id = eid + id = tskID } } if id == "" { return fmt.Errorf("could not find local id") } - e, err := del.eventRepo.Find(id) + tsk, err := del.taskRepo.Find(id) if err != nil { - return fmt.Errorf("could not get event: %v", err) + return fmt.Errorf("could not get task: %v", err) } - it, err := e.Item() + it, err := tsk.Item() if err != nil { - return fmt.Errorf("could not convert event to sync item: %v", err) + return fmt.Errorf("could not convert task to sync item: %v", err) } it.Deleted = true if err := del.syncRepo.Store(it); err != nil { @@ -68,8 +68,8 @@ func (del *Delete) do() error { return fmt.Errorf("could not delete local id: %v", err) } - if err := del.eventRepo.Delete(id); err != nil { - return fmt.Errorf("could not delete event: %v", err) + if err := del.taskRepo.Delete(id); err != nil { + return fmt.Errorf("could not delete task: %v", err) } return nil diff --git a/plan/command/delete_test.go b/plan/command/delete_test.go index 9005498..ae6963c 100644 --- a/plan/command/delete_test.go +++ b/plan/command/delete_test.go @@ -13,10 +13,10 @@ import ( func TestDelete(t *testing.T) { t.Parallel() - e := item.Event{ + e := item.Task{ ID: "id", Date: item.NewDate(2024, 10, 7), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "name", }, } @@ -43,7 +43,7 @@ func TestDelete(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - eventRepo := memory.NewEvent() + eventRepo := memory.NewTask() syncRepo := memory.NewSync() if err := eventRepo.Store(e); err != nil { t.Errorf("exp nil, got %v", err) diff --git a/plan/command/list.go b/plan/command/list.go index a41ae66..e5cf8d5 100644 --- a/plan/command/list.go +++ b/plan/command/list.go @@ -8,13 +8,13 @@ import ( type List struct { localIDRepo storage.LocalID - eventRepo storage.Event + taskRepo storage.Task } -func NewList(localIDRepo storage.LocalID, eventRepo storage.Event) Command { +func NewList(localIDRepo storage.LocalID, taskRepo storage.Task) Command { return &List{ localIDRepo: localIDRepo, - eventRepo: eventRepo, + taskRepo: taskRepo, } } @@ -31,7 +31,7 @@ func (list *List) do() error { if err != nil { return fmt.Errorf("could not get local ids: %v", err) } - all, err := list.eventRepo.FindAll() + all, err := list.taskRepo.FindAll() if err != nil { return err } diff --git a/plan/command/list_test.go b/plan/command/list_test.go index 67033ad..652432b 100644 --- a/plan/command/list_test.go +++ b/plan/command/list_test.go @@ -11,16 +11,16 @@ import ( func TestList(t *testing.T) { t.Parallel() - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() localRepo := memory.NewLocalID() - e := item.Event{ + e := item.Task{ ID: "id", Date: item.NewDate(2024, 10, 7), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "name", }, } - if err := eventRepo.Store(e); err != nil { + if err := taskRepo.Store(e); err != nil { t.Errorf("exp nil, got %v", err) } if err := localRepo.Store(e.ID, 1); err != nil { @@ -47,7 +47,7 @@ func TestList(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewList(localRepo, eventRepo) + cmd := command.NewList(localRepo, taskRepo) actErr := cmd.Execute(tc.main, nil) != nil if tc.expErr != actErr { t.Errorf("exp %v, got %v", tc.expErr, actErr) diff --git a/plan/command/sync.go b/plan/command/sync.go index 1f100fb..4147028 100644 --- a/plan/command/sync.go +++ b/plan/command/sync.go @@ -14,15 +14,15 @@ type Sync struct { client client.Client syncRepo storage.Sync localIDRepo storage.LocalID - eventRepo storage.Event + taskRepo storage.Task } -func NewSync(client client.Client, syncRepo storage.Sync, localIDRepo storage.LocalID, eventRepo storage.Event) Command { +func NewSync(client client.Client, syncRepo storage.Sync, localIDRepo storage.LocalID, taskRepo storage.Task) Command { return &Sync{ client: client, syncRepo: syncRepo, localIDRepo: localIDRepo, - eventRepo: eventRepo, + taskRepo: taskRepo, } } @@ -52,7 +52,7 @@ func (sync *Sync) do() error { if err != nil { return fmt.Errorf("could not find timestamp of last update: %v", err) } - recItems, err := sync.client.Updated([]item.Kind{item.KindEvent}, ts) + recItems, err := sync.client.Updated([]item.Kind{item.KindTask}, ts) if err != nil { return fmt.Errorf("could not receive updates: %v", err) } @@ -63,8 +63,8 @@ func (sync *Sync) do() error { if err := sync.localIDRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { return fmt.Errorf("could not delete local id: %v", err) } - if err := sync.eventRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { - return fmt.Errorf("could not delete event: %v", err) + if err := sync.taskRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) { + return fmt.Errorf("could not delete task: %v", err) } continue } @@ -76,16 +76,16 @@ func (sync *Sync) do() error { return fmt.Errorf("could not get local ids: %v", err) } for _, u := range updated { - var eBody item.EventBody - if err := json.Unmarshal([]byte(u.Body), &eBody); err != nil { - return fmt.Errorf("could not unmarshal event body: %v", err) + var tskBody item.TaskBody + if err := json.Unmarshal([]byte(u.Body), &tskBody); err != nil { + return fmt.Errorf("could not unmarshal task body: %v", err) } - e := item.Event{ - ID: u.ID, - EventBody: eBody, + tsk := item.Task{ + ID: u.ID, + TaskBody: tskBody, } - if err := sync.eventRepo.Store(e); err != nil { - return fmt.Errorf("could not store event: %v", err) + if err := sync.taskRepo.Store(tsk); err != nil { + return fmt.Errorf("could not store task: %v", err) } lid, ok := lidMap[u.ID] if !ok { diff --git a/plan/command/sync_test.go b/plan/command/sync_test.go index 080d04a..7463ea1 100644 --- a/plan/command/sync_test.go +++ b/plan/command/sync_test.go @@ -17,7 +17,7 @@ func TestSyncParse(t *testing.T) { syncClient := client.NewMemory() syncRepo := memory.NewSync() localIDRepo := memory.NewLocalID() - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() for _, tc := range []struct { name string @@ -39,7 +39,7 @@ func TestSyncParse(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, eventRepo) + cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) actErr := cmd.Execute(tc.main, nil) != nil if tc.expErr != actErr { t.Errorf("exp %v, got %v", tc.expErr, actErr) @@ -54,11 +54,11 @@ func TestSyncSend(t *testing.T) { syncClient := client.NewMemory() syncRepo := memory.NewSync() localIDRepo := memory.NewLocalID() - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() it := item.Item{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Body: `{ "title":"title", "start":"2024-10-18T08:00:00Z", @@ -77,12 +77,12 @@ func TestSyncSend(t *testing.T) { }{ { name: "single", - ks: []item.Kind{item.KindEvent}, + ks: []item.Kind{item.KindTask}, expItems: []item.Item{it}, }, } { t.Run(tc.name, func(t *testing.T) { - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, eventRepo) + cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) if err := cmd.Execute([]string{"sync"}, nil); err != nil { t.Errorf("exp nil, got %v", err) } @@ -115,31 +115,31 @@ func TestSyncReceive(t *testing.T) { for _, tc := range []struct { name string - present []item.Event + present []item.Task updated []item.Item - expEvent []item.Event + expTask []item.Task expLocalID map[string]int }{ { name: "no new", - expEvent: []item.Event{}, + expTask: []item.Task{}, expLocalID: map[string]int{}, }, { name: "new", updated: []item.Item{{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Body: `{ "title":"title", "start":"2024-10-23T08:00:00Z", "duration":"1h" }`, }}, - expEvent: []item.Event{{ + expTask: []item.Task{{ ID: "a", Date: item.NewDate(2024, 10, 23), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Duration: oneHour, }, @@ -150,27 +150,27 @@ func TestSyncReceive(t *testing.T) { }, { name: "update existing", - present: []item.Event{{ + present: []item.Task{{ ID: "a", Date: item.NewDate(2024, 10, 23), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "title", Duration: oneHour, }, }}, updated: []item.Item{{ ID: "a", - Kind: item.KindEvent, + Kind: item.KindTask, Body: `{ "title":"new title", "start":"2024-10-23T08:00:00Z", "duration":"1h" }`, }}, - expEvent: []item.Event{{ + expTask: []item.Task{{ ID: "a", Date: item.NewDate(2024, 10, 23), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "new title", Duration: oneHour, }, @@ -185,10 +185,10 @@ func TestSyncReceive(t *testing.T) { syncClient := client.NewMemory() syncRepo := memory.NewSync() localIDRepo := memory.NewLocalID() - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() for i, p := range tc.present { - if err := eventRepo.Store(p); err != nil { + if err := taskRepo.Store(p); err != nil { t.Errorf("exp nil, got %v", err) } if err := localIDRepo.Store(p.ID, i+1); err != nil { @@ -200,17 +200,17 @@ func TestSyncReceive(t *testing.T) { } // sync - cmd := command.NewSync(syncClient, syncRepo, localIDRepo, eventRepo) + cmd := command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo) if err := cmd.Execute([]string{"sync"}, nil); err != nil { t.Errorf("exp nil, got %v", err) } // check result - actEvents, err := eventRepo.FindAll() + actTasks, err := taskRepo.FindAll() if err != nil { t.Errorf("exp nil, got %v", err) } - if diff := item.EventDiffs(tc.expEvent, actEvents); diff != "" { + if diff := item.TaskDiffs(tc.expTask, actTasks); diff != "" { t.Errorf("(exp +, got -)\n%s", diff) } actLocalIDs, err := localIDRepo.FindAll() diff --git a/plan/command/update.go b/plan/command/update.go index 16a4749..60a50a3 100644 --- a/plan/command/update.go +++ b/plan/command/update.go @@ -10,16 +10,16 @@ import ( type Update struct { localIDRepo storage.LocalID - eventRepo storage.Event + taskRepo storage.Task syncRepo storage.Sync argSet *ArgSet localID int } -func NewUpdate(localIDRepo storage.LocalID, eventRepo storage.Event, syncRepo storage.Sync) Command { +func NewUpdate(localIDRepo storage.LocalID, taskRepo storage.Task, syncRepo storage.Sync) Command { return &Update{ localIDRepo: localIDRepo, - eventRepo: eventRepo, + taskRepo: taskRepo, syncRepo: syncRepo, argSet: &ArgSet{ Flags: map[string]Flag{ @@ -67,47 +67,47 @@ func (update *Update) do() error { if err != nil { return fmt.Errorf("could not get local ids: %v", err) } - for eid, lid := range idMap { + for tid, lid := range idMap { if update.localID == lid { - id = eid + id = tid } } if id == "" { return fmt.Errorf("could not find local id") } - e, err := update.eventRepo.Find(id) + tsk, err := update.taskRepo.Find(id) if err != nil { - return fmt.Errorf("could not find event") + return fmt.Errorf("could not find task") } if as.Main != "" { - e.Title = as.Main + tsk.Title = as.Main } if as.IsSet(FlagOn) { - e.Date = as.GetDate(FlagOn) + tsk.Date = as.GetDate(FlagOn) } if as.IsSet(FlagAt) { - e.Time = as.GetTime(FlagAt) + tsk.Time = as.GetTime(FlagAt) } if as.IsSet(FlagFor) { - e.Duration = as.GetDuration(FlagFor) + tsk.Duration = as.GetDuration(FlagFor) } if as.IsSet(FlagRec) { - e.Recurrer = as.GetRecurrer(FlagRec) + tsk.Recurrer = as.GetRecurrer(FlagRec) } - if !e.Valid() { - return fmt.Errorf("event is unvalid") + if !tsk.Valid() { + return fmt.Errorf("task is unvalid") } - if err := update.eventRepo.Store(e); err != nil { - return fmt.Errorf("could not store event: %v", err) + if err := update.taskRepo.Store(tsk); err != nil { + return fmt.Errorf("could not store task: %v", err) } - it, err := e.Item() + it, err := tsk.Item() if err != nil { - return fmt.Errorf("could not convert event to sync item: %v", err) + return fmt.Errorf("could not convert task to sync item: %v", err) } if err := update.syncRepo.Store(it); err != nil { return fmt.Errorf("could not store sync item: %v", err) diff --git a/plan/command/update_test.go b/plan/command/update_test.go index 98db5c1..7b7fc88 100644 --- a/plan/command/update_test.go +++ b/plan/command/update_test.go @@ -13,7 +13,7 @@ import ( func TestUpdateExecute(t *testing.T) { t.Parallel() - eid := "c" + tskID := "c" lid := 3 oneHour, err := time.ParseDuration("1h") if err != nil { @@ -28,12 +28,12 @@ func TestUpdateExecute(t *testing.T) { } for _, tc := range []struct { - name string - localID int - main []string - flags map[string]string - expEvent item.Event - expErr bool + name string + localID int + main []string + flags map[string]string + expTask item.Task + expErr bool }{ { name: "no args", @@ -48,10 +48,10 @@ func TestUpdateExecute(t *testing.T) { name: "name", localID: lid, main: []string{"update", fmt.Sprintf("%d", lid), "updated"}, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: item.NewDate(2024, 10, 6), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: "updated", Time: aTime, Duration: oneHour, @@ -74,10 +74,10 @@ func TestUpdateExecute(t *testing.T) { flags: map[string]string{ "on": "2024-10-02", }, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: item.NewDate(2024, 10, 2), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: aTime, Duration: oneHour, @@ -100,10 +100,10 @@ func TestUpdateExecute(t *testing.T) { flags: map[string]string{ "at": "11:00", }, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: item.NewDate(2024, 10, 6), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: item.NewTime(11, 0), Duration: oneHour, @@ -118,10 +118,10 @@ func TestUpdateExecute(t *testing.T) { "on": "2024-10-02", "at": "11:00", }, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: item.NewDate(2024, 10, 2), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: item.NewTime(11, 0), Duration: oneHour, @@ -144,10 +144,10 @@ func TestUpdateExecute(t *testing.T) { flags: map[string]string{ "for": "2h", }, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: item.NewDate(2024, 10, 6), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: aTime, Duration: twoHour, @@ -168,11 +168,11 @@ func TestUpdateExecute(t *testing.T) { flags: map[string]string{ "rec": "2024-12-08, daily", }, - expEvent: item.Event{ - ID: eid, + expTask: item.Task{ + ID: tskID, Date: aDate, Recurrer: item.NewRecurrer("2024-12-08, daily"), - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: aTime, Duration: oneHour, @@ -181,13 +181,13 @@ func TestUpdateExecute(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - eventRepo := memory.NewEvent() + taskRepo := memory.NewTask() localIDRepo := memory.NewLocalID() syncRepo := memory.NewSync() - if err := eventRepo.Store(item.Event{ - ID: eid, + if err := taskRepo.Store(item.Task{ + ID: tskID, Date: aDate, - EventBody: item.EventBody{ + TaskBody: item.TaskBody{ Title: title, Time: aTime, Duration: oneHour, @@ -195,11 +195,11 @@ func TestUpdateExecute(t *testing.T) { }); err != nil { t.Errorf("exp nil, got %v", err) } - if err := localIDRepo.Store(eid, lid); err != nil { + if err := localIDRepo.Store(tskID, lid); err != nil { t.Errorf("exp nil, ,got %v", err) } - cmd := command.NewUpdate(localIDRepo, eventRepo, syncRepo) + cmd := command.NewUpdate(localIDRepo, taskRepo, syncRepo) actParseErr := cmd.Execute(tc.main, tc.flags) != nil if tc.expErr != actParseErr { t.Errorf("exp %v, got %v", tc.expErr, actParseErr) @@ -208,11 +208,11 @@ func TestUpdateExecute(t *testing.T) { return } - actEvent, err := eventRepo.Find(eid) + actTask, err := taskRepo.Find(tskID) if err != nil { t.Errorf("exp nil, got %v", err) } - if diff := item.EventDiff(tc.expEvent, actEvent); diff != "" { + if diff := item.TaskDiff(tc.expTask, actTask); diff != "" { t.Errorf("(exp -, got +)\n%s", diff) } updated, err := syncRepo.FindAll() diff --git a/plan/main.go b/plan/main.go index 9f94df2..f87ca57 100644 --- a/plan/main.go +++ b/plan/main.go @@ -27,7 +27,7 @@ func main() { os.Exit(1) } - localIDRepo, eventRepo, syncRepo, err := sqlite.NewSqlites(conf.DBPath) + localIDRepo, taskRepo, syncRepo, err := sqlite.NewSqlites(conf.DBPath) if err != nil { fmt.Printf("could not open db file: %s\n", err) os.Exit(1) @@ -37,11 +37,11 @@ func main() { cli := command.CLI{ Commands: []command.Command{ - command.NewAdd(localIDRepo, eventRepo, syncRepo), - command.NewList(localIDRepo, eventRepo), - command.NewUpdate(localIDRepo, eventRepo, syncRepo), - command.NewDelete(localIDRepo, eventRepo, syncRepo), - command.NewSync(syncClient, syncRepo, localIDRepo, eventRepo), + command.NewAdd(localIDRepo, taskRepo, syncRepo), + command.NewList(localIDRepo, taskRepo), + command.NewUpdate(localIDRepo, taskRepo, syncRepo), + command.NewDelete(localIDRepo, taskRepo, syncRepo), + command.NewSync(syncClient, syncRepo, localIDRepo, taskRepo), }, } diff --git a/plan/storage/memory/event.go b/plan/storage/memory/event.go deleted file mode 100644 index 2a3afdb..0000000 --- a/plan/storage/memory/event.go +++ /dev/null @@ -1,67 +0,0 @@ -package memory - -import ( - "sort" - "sync" - - "go-mod.ewintr.nl/planner/item" - "go-mod.ewintr.nl/planner/plan/storage" -) - -type Event struct { - events map[string]item.Event - mutex sync.RWMutex -} - -func NewEvent() *Event { - return &Event{ - events: make(map[string]item.Event), - } -} - -func (r *Event) Find(id string) (item.Event, error) { - r.mutex.RLock() - defer r.mutex.RUnlock() - - event, exists := r.events[id] - if !exists { - return item.Event{}, storage.ErrNotFound - } - return event, nil -} - -func (r *Event) FindAll() ([]item.Event, error) { - r.mutex.RLock() - defer r.mutex.RUnlock() - - events := make([]item.Event, 0, len(r.events)) - for _, event := range r.events { - events = append(events, event) - } - sort.Slice(events, func(i, j int) bool { - return events[i].ID < events[j].ID - }) - - return events, nil -} - -func (r *Event) Store(e item.Event) error { - r.mutex.Lock() - defer r.mutex.Unlock() - - r.events[e.ID] = e - - return nil -} - -func (r *Event) Delete(id string) error { - r.mutex.Lock() - defer r.mutex.Unlock() - - if _, exists := r.events[id]; !exists { - return storage.ErrNotFound - } - delete(r.events, id) - - return nil -} diff --git a/plan/storage/memory/task.go b/plan/storage/memory/task.go new file mode 100644 index 0000000..184fa40 --- /dev/null +++ b/plan/storage/memory/task.go @@ -0,0 +1,67 @@ +package memory + +import ( + "sort" + "sync" + + "go-mod.ewintr.nl/planner/item" + "go-mod.ewintr.nl/planner/plan/storage" +) + +type Task struct { + tasks map[string]item.Task + mutex sync.RWMutex +} + +func NewTask() *Task { + return &Task{ + tasks: make(map[string]item.Task), + } +} + +func (t *Task) Find(id string) (item.Task, error) { + t.mutex.RLock() + defer t.mutex.RUnlock() + + task, exists := t.tasks[id] + if !exists { + return item.Task{}, storage.ErrNotFound + } + return task, nil +} + +func (t *Task) FindAll() ([]item.Task, error) { + t.mutex.RLock() + defer t.mutex.RUnlock() + + tasks := make([]item.Task, 0, len(t.tasks)) + for _, event := range t.tasks { + tasks = append(tasks, event) + } + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].ID < tasks[j].ID + }) + + return tasks, nil +} + +func (t *Task) Store(tsk item.Task) error { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.tasks[tsk.ID] = tsk + + return nil +} + +func (t *Task) Delete(id string) error { + t.mutex.Lock() + defer t.mutex.Unlock() + + if _, exists := t.tasks[id]; !exists { + return storage.ErrNotFound + } + delete(t.tasks, id) + + return nil +} diff --git a/plan/storage/memory/event_test.go b/plan/storage/memory/task_test.go similarity index 50% rename from plan/storage/memory/event_test.go rename to plan/storage/memory/task_test.go index a7dea4d..265ab67 100644 --- a/plan/storage/memory/event_test.go +++ b/plan/storage/memory/task_test.go @@ -6,50 +6,50 @@ import ( "go-mod.ewintr.nl/planner/item" ) -func TestEvent(t *testing.T) { +func TestTask(t *testing.T) { t.Parallel() - mem := NewEvent() + mem := NewTask() t.Log("empty") - actEvents, actErr := mem.FindAll() + actTasks, actErr := mem.FindAll() if actErr != nil { t.Errorf("exp nil, got %v", actErr) } - if len(actEvents) != 0 { - t.Errorf("exp 0, got %d", len(actEvents)) + if len(actTasks) != 0 { + t.Errorf("exp 0, got %d", len(actTasks)) } t.Log("store") - e1 := item.Event{ + tsk1 := item.Task{ ID: "id-1", } - if err := mem.Store(e1); err != nil { + if err := mem.Store(tsk1); err != nil { t.Errorf("exp nil, got %v", err) } - e2 := item.Event{ + tsk2 := item.Task{ ID: "id-2", } - if err := mem.Store(e2); err != nil { + if err := mem.Store(tsk2); err != nil { t.Errorf("exp nil, got %v", err) } t.Log("find one") - actEvent, actErr := mem.Find(e1.ID) + actTask, actErr := mem.Find(tsk1.ID) if actErr != nil { t.Errorf("exp nil, got %v", actErr) } - if actEvent.ID != e1.ID { - t.Errorf("exp %v, got %v", e1.ID, actEvent.ID) + if actTask.ID != tsk1.ID { + t.Errorf("exp %v, got %v", tsk1.ID, actTask.ID) } t.Log("find all") - actEvents, actErr = mem.FindAll() + actTasks, actErr = mem.FindAll() if actErr != nil { t.Errorf("exp nil, got %v", actErr) } - if diff := item.EventDiffs([]item.Event{e1, e2}, actEvents); diff != "" { + if diff := item.TaskDiffs([]item.Task{tsk1, tsk2}, actTasks); diff != "" { t.Errorf("(exp -, got +)\n%s", diff) } } diff --git a/plan/storage/sqlite/event.go b/plan/storage/sqlite/event.go deleted file mode 100644 index 595ad41..0000000 --- a/plan/storage/sqlite/event.go +++ /dev/null @@ -1,114 +0,0 @@ -package sqlite - -import ( - "database/sql" - "fmt" - "time" - - "go-mod.ewintr.nl/planner/item" - "go-mod.ewintr.nl/planner/plan/storage" -) - -type SqliteEvent struct { - db *sql.DB -} - -func (s *SqliteEvent) Store(event item.Event) error { - var recurStr string - if event.Recurrer != nil { - recurStr = event.Recurrer.String() - } - if _, err := s.db.Exec(` -INSERT INTO events -(id, title, date, time, duration, recurrer) -VALUES -(?, ?, ?, ?, ?, ?) -ON CONFLICT(id) DO UPDATE -SET -title=?, -date=?, -time=?, -duration=?, -recurrer=? -`, - event.ID, event.Title, event.Date.String(), event.Time.String(), event.Duration.String(), recurStr, - event.Title, event.Date.String(), event.Time.String(), event.Duration.String(), recurStr); err != nil { - return fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - return nil -} - -func (s *SqliteEvent) Find(id string) (item.Event, error) { - var event item.Event - var dateStr, timeStr, recurStr, durStr string - err := s.db.QueryRow(` -SELECT id, title, date, time, duration, recurrer -FROM events -WHERE id = ?`, id).Scan(&event.ID, &event.Title, &dateStr, &timeStr, &durStr, &recurStr) - switch { - case err == sql.ErrNoRows: - return item.Event{}, fmt.Errorf("event not found: %w", err) - case err != nil: - return item.Event{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - event.Date = item.NewDateFromString(dateStr) - event.Time = item.NewTimeFromString(timeStr) - dur, err := time.ParseDuration(durStr) - if err != nil { - return item.Event{}, fmt.Errorf("could not unmarshal recurrer: %v", err) - } - event.Duration = dur - event.Recurrer = item.NewRecurrer(recurStr) - - return event, nil -} - -func (s *SqliteEvent) FindAll() ([]item.Event, error) { - rows, err := s.db.Query(` -SELECT id, title, date, time, duration, recurrer -FROM events`) - if err != nil { - return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - result := make([]item.Event, 0) - defer rows.Close() - for rows.Next() { - var event item.Event - var dateStr, timeStr, recurStr, durStr string - if err := rows.Scan(&event.ID, &event.Title, &dateStr, &timeStr, &durStr, &recurStr); err != nil { - return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - dur, err := time.ParseDuration(durStr) - if err != nil { - return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - event.Date = item.NewDateFromString(dateStr) - event.Time = item.NewTimeFromString(timeStr) - event.Duration = dur - event.Recurrer = item.NewRecurrer(recurStr) - - result = append(result, event) - } - - return result, nil -} - -func (s *SqliteEvent) Delete(id string) error { - result, err := s.db.Exec(` -DELETE FROM events -WHERE id = ?`, id) - if err != nil { - return fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - - rowsAffected, err := result.RowsAffected() - if err != nil { - return fmt.Errorf("%w: %v", ErrSqliteFailure, err) - } - - if rowsAffected == 0 { - return storage.ErrNotFound - } - - return nil -} diff --git a/plan/storage/sqlite/sqlite.go b/plan/storage/sqlite/sqlite.go index bec4db3..34e2a5e 100644 --- a/plan/storage/sqlite/sqlite.go +++ b/plan/storage/sqlite/sqlite.go @@ -42,6 +42,7 @@ var migrations = []string{ `ALTER TABLE events ADD COLUMN date TEXT NOT NULL DEFAULT ''`, `ALTER TABLE events ADD COLUMN time TEXT NOT NULL DEFAULT ''`, `ALTER TABLE items ADD COLUMN recur_next TEXT NOT NULL DEFAULT ''`, + `ALTER TABLE events RENAME TO tasks`, } var ( @@ -51,7 +52,7 @@ var ( ErrSqliteFailure = errors.New("sqlite returned an error") ) -func NewSqlites(dbPath string) (*LocalID, *SqliteEvent, *SqliteSync, error) { +func NewSqlites(dbPath string) (*LocalID, *SqliteTask, *SqliteSync, error) { db, err := sql.Open("sqlite", dbPath) if err != nil { return nil, nil, nil, fmt.Errorf("%w: %v", ErrInvalidConfiguration, err) @@ -60,7 +61,7 @@ func NewSqlites(dbPath string) (*LocalID, *SqliteEvent, *SqliteSync, error) { sl := &LocalID{ db: db, } - se := &SqliteEvent{ + se := &SqliteTask{ db: db, } ss := &SqliteSync{ diff --git a/plan/storage/sqlite/task.go b/plan/storage/sqlite/task.go new file mode 100644 index 0000000..9b23b50 --- /dev/null +++ b/plan/storage/sqlite/task.go @@ -0,0 +1,114 @@ +package sqlite + +import ( + "database/sql" + "fmt" + "time" + + "go-mod.ewintr.nl/planner/item" + "go-mod.ewintr.nl/planner/plan/storage" +) + +type SqliteTask struct { + db *sql.DB +} + +func (t *SqliteTask) Store(tsk item.Task) error { + var recurStr string + if tsk.Recurrer != nil { + recurStr = tsk.Recurrer.String() + } + if _, err := t.db.Exec(` +INSERT INTO tasks +(id, title, date, time, duration, recurrer) +VALUES +(?, ?, ?, ?, ?, ?) +ON CONFLICT(id) DO UPDATE +SET +title=?, +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 { + return fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + return nil +} + +func (t *SqliteTask) Find(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 +FROM tasks +WHERE id = ?`, id).Scan(&tsk.ID, &tsk.Title, &dateStr, &timeStr, &durStr, &recurStr) + switch { + case err == sql.ErrNoRows: + return item.Task{}, fmt.Errorf("event not found: %w", err) + case err != nil: + return item.Task{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + tsk.Date = item.NewDateFromString(dateStr) + tsk.Time = item.NewTimeFromString(timeStr) + dur, err := time.ParseDuration(durStr) + if err != nil { + return item.Task{}, fmt.Errorf("could not unmarshal recurrer: %v", err) + } + tsk.Duration = dur + tsk.Recurrer = item.NewRecurrer(recurStr) + + return tsk, nil +} + +func (t *SqliteTask) FindAll() ([]item.Task, error) { + rows, err := t.db.Query(` +SELECT id, title, date, time, duration, recurrer +FROM tasks`) + if err != nil { + return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + result := make([]item.Task, 0) + defer rows.Close() + 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 { + return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + dur, err := time.ParseDuration(durStr) + if err != nil { + return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + tsk.Date = item.NewDateFromString(dateStr) + tsk.Time = item.NewTimeFromString(timeStr) + tsk.Duration = dur + tsk.Recurrer = item.NewRecurrer(recurStr) + + result = append(result, tsk) + } + + return result, nil +} + +func (s *SqliteTask) Delete(id string) error { + result, err := s.db.Exec(` +DELETE FROM tasks +WHERE id = ?`, id) + if err != nil { + return fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + return fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + + if rowsAffected == 0 { + return storage.ErrNotFound + } + + return nil +} diff --git a/plan/storage/storage.go b/plan/storage/storage.go index 9dc2794..ed7fbff 100644 --- a/plan/storage/storage.go +++ b/plan/storage/storage.go @@ -27,10 +27,10 @@ type Sync interface { LastUpdate() (time.Time, error) } -type Event interface { - Store(event item.Event) error - Find(id string) (item.Event, error) - FindAll() ([]item.Event, error) +type Task interface { + Store(task item.Task) error + Find(id string) (item.Task, error) + FindAll() ([]item.Task, error) Delete(id string) error } diff --git a/sync/client/memory_test.go b/sync/client/memory_test.go index c1f451c..dc26f8b 100644 --- a/sync/client/memory_test.go +++ b/sync/client/memory_test.go @@ -16,9 +16,9 @@ func TestMemory(t *testing.T) { now := time.Now() items := []item.Item{ - {ID: "a", Kind: item.KindTask, Updated: now.Add(-15 * time.Minute)}, - {ID: "b", Kind: item.KindEvent, Updated: now.Add(-10 * time.Minute)}, - {ID: "c", Kind: item.KindTask, Updated: now.Add(-5 * time.Minute)}, + {ID: "a", Kind: item.KindSchedule, Updated: now.Add(-15 * time.Minute)}, + {ID: "b", Kind: item.KindTask, Updated: now.Add(-10 * time.Minute)}, + {ID: "c", Kind: item.KindSchedule, Updated: now.Add(-5 * time.Minute)}, } if err := mem.Update(items); err != nil { t.Errorf("exp nil, got %v", err) @@ -37,12 +37,12 @@ func TestMemory(t *testing.T) { }, { name: "kind", - ks: []item.Kind{item.KindEvent}, + ks: []item.Kind{item.KindTask}, expItems: []item.Item{items[1]}, }, { name: "timestamp", - ks: []item.Kind{item.KindTask, item.KindEvent}, + ks: []item.Kind{item.KindSchedule, item.KindTask}, ts: now.Add(-10 * time.Minute), expItems: items[1:], }, diff --git a/sync/service/handler_test.go b/sync/service/handler_test.go index 750970f..0a899ed 100644 --- a/sync/service/handler_test.go +++ b/sync/service/handler_test.go @@ -59,9 +59,9 @@ func TestSyncGet(t *testing.T) { mem := NewMemory() items := []item.Item{ - {ID: "id-0", Kind: item.KindEvent, Updated: now.Add(-10 * time.Minute)}, - {ID: "id-1", Kind: item.KindEvent, Updated: now.Add(-5 * time.Minute)}, - {ID: "id-2", Kind: item.KindTask, Updated: now.Add(time.Minute)}, + {ID: "id-0", Kind: item.KindTask, Updated: now.Add(-10 * time.Minute)}, + {ID: "id-1", Kind: item.KindTask, Updated: now.Add(-5 * time.Minute)}, + {ID: "id-2", Kind: item.KindSchedule, Updated: now.Add(time.Minute)}, } for _, item := range items { @@ -93,7 +93,7 @@ func TestSyncGet(t *testing.T) { }, { name: "kind", - ks: []string{string(item.KindTask)}, + ks: []string{string(item.KindSchedule)}, expStatus: http.StatusOK, expItems: []item.Item{items[2]}, }, @@ -171,20 +171,20 @@ func TestSyncPost(t *testing.T) { { name: "invalid item", reqBody: []byte(`[ - {"id":"id-1","kind":"event","updated":"2024-09-06T08:00:00Z"}, + {"id":"id-1","kind":"task","updated":"2024-09-06T08:00:00Z"}, ]`), expStatus: http.StatusBadRequest, }, { name: "normal", reqBody: []byte(`[ - {"id":"id-1","kind":"event","updated":"2024-09-06T08:00:00Z","deleted":false,"body":"item"}, - {"id":"id-2","kind":"event","updated":"2024-09-06T08:12:00Z","deleted":false,"body":"item2"} + {"id":"id-1","kind":"task","updated":"2024-09-06T08:00:00Z","deleted":false,"body":"item"}, + {"id":"id-2","kind":"task","updated":"2024-09-06T08:12:00Z","deleted":false,"body":"item2"} ]`), expStatus: http.StatusNoContent, expItems: []item.Item{ - {ID: "id-1", Kind: item.KindEvent, Updated: time.Date(2024, 9, 6, 8, 0, 0, 0, time.UTC)}, - {ID: "id-2", Kind: item.KindEvent, Updated: time.Date(2024, 9, 6, 12, 0, 0, 0, time.UTC)}, + {ID: "id-1", Kind: item.KindTask, Updated: time.Date(2024, 9, 6, 8, 0, 0, 0, time.UTC)}, + {ID: "id-2", Kind: item.KindTask, Updated: time.Date(2024, 9, 6, 12, 0, 0, 0, time.UTC)}, }, }, } { diff --git a/sync/service/postgres.go b/sync/service/postgres.go index faa15b0..30d6598 100644 --- a/sync/service/postgres.go +++ b/sync/service/postgres.go @@ -27,6 +27,7 @@ var migrations = []string{ ALTER COLUMN recur_next SET NOT NULL, ALTER COLUMN recur_next SET DEFAULT ''`, `ALTER TABLE items ADD COLUMN date TEXT NOT NULL DEFAULT ''`, + `UPDATE items SET kind='task'`, } var ( diff --git a/sync/service/recur_test.go b/sync/service/recur_test.go index 2aabe14..75702b0 100644 --- a/sync/service/recur_test.go +++ b/sync/service/recur_test.go @@ -19,12 +19,12 @@ func TestRecur(t *testing.T) { testItem := item.Item{ ID: "test-1", - Kind: item.KindEvent, + Kind: item.KindTask, Updated: now, Deleted: false, Recurrer: item.NewRecurrer("2024-01-01, daily"), RecurNext: today, - Body: `{"title":"Test Event","start":"2024-01-01T10:00:00Z","duration":"30m"}`, + Body: `{"title":"Test task","start":"2024-01-01T10:00:00Z","duration":"30m"}`, } // Store the item @@ -38,7 +38,7 @@ func TestRecur(t *testing.T) { } // Verify results - items, err := mem.Updated([]item.Kind{item.KindEvent}, now) + items, err := mem.Updated([]item.Kind{item.KindTask}, now) if err != nil { t.Errorf("failed to get updated items: %v", err) }