rename event to task

This commit is contained in:
Erik Winter 2024-12-24 08:00:23 +01:00
parent 5985356c99
commit dcdc75887f
27 changed files with 430 additions and 428 deletions

BIN
dist/plan vendored

Binary file not shown.

BIN
dist/plannersync vendored

Binary file not shown.

View File

@ -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 {

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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)

View File

@ -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 {

View File

@ -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()

View File

@ -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)

View File

@ -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()

View File

@ -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),
},
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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{

114
plan/storage/sqlite/task.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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:],
},

View File

@ -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)},
},
},
} {

View File

@ -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 (

View File

@ -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)
}