Compare commits
5 Commits
c209ba6197
...
e49562b7f6
Author | SHA1 | Date |
---|---|---|
Erik Winter | e49562b7f6 | |
Erik Winter | c8e5058445 | |
Erik Winter | e2ce33899f | |
Erik Winter | 45d0bdfc34 | |
Erik Winter | bd1c0136a9 |
|
@ -86,26 +86,26 @@ type Add struct {
|
|||
args AddArgs
|
||||
}
|
||||
|
||||
func (a *Add) Do(deps Dependencies) error {
|
||||
func (a *Add) Do(deps Dependencies) ([][]string, error) {
|
||||
if err := deps.TaskRepo.Store(a.args.task); err != nil {
|
||||
return fmt.Errorf("could not store event: %v", err)
|
||||
return nil, fmt.Errorf("could not store event: %v", err)
|
||||
}
|
||||
|
||||
localID, err := deps.LocalIDRepo.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create next local id: %v", err)
|
||||
return nil, fmt.Errorf("could not create next local id: %v", err)
|
||||
}
|
||||
if err := deps.LocalIDRepo.Store(a.args.task.ID, localID); err != nil {
|
||||
return fmt.Errorf("could not store local id: %v", err)
|
||||
return nil, fmt.Errorf("could not store local id: %v", err)
|
||||
}
|
||||
|
||||
it, err := a.args.task.Item()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert event to sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not convert event to sync item: %v", err)
|
||||
}
|
||||
if err := deps.SyncRepo.Store(it); err != nil {
|
||||
return fmt.Errorf("could not store sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not store sync item: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/command"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
"go-mod.ewintr.nl/planner/plan/storage/memory"
|
||||
)
|
||||
|
||||
|
@ -66,7 +67,7 @@ func TestAdd(t *testing.T) {
|
|||
if tc.expErr {
|
||||
return
|
||||
}
|
||||
if err := cmd.Do(command.Dependencies{
|
||||
if _, err := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localIDRepo,
|
||||
SyncRepo: syncRepo,
|
||||
|
@ -74,7 +75,7 @@ func TestAdd(t *testing.T) {
|
|||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
|
||||
actTasks, err := taskRepo.FindAll()
|
||||
actTasks, err := taskRepo.FindMany(storage.TaskListParams{})
|
||||
if err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"slices"
|
||||
"strings"
|
||||
|
||||
"go-mod.ewintr.nl/planner/plan/format"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
"go-mod.ewintr.nl/planner/sync/client"
|
||||
)
|
||||
|
@ -32,7 +33,7 @@ type CommandArgs interface {
|
|||
}
|
||||
|
||||
type Command interface {
|
||||
Do(deps Dependencies) error
|
||||
Do(deps Dependencies) ([][]string, error)
|
||||
}
|
||||
|
||||
type CLI struct {
|
||||
|
@ -44,6 +45,7 @@ func NewCLI(deps Dependencies) *CLI {
|
|||
return &CLI{
|
||||
deps: deps,
|
||||
cmdArgs: []CommandArgs{
|
||||
NewShowArgs(),
|
||||
NewAddArgs(), NewDeleteArgs(), NewListArgs(),
|
||||
NewSyncArgs(), NewUpdateArgs(),
|
||||
},
|
||||
|
@ -51,17 +53,29 @@ func NewCLI(deps Dependencies) *CLI {
|
|||
}
|
||||
|
||||
func (cli *CLI) Run(args []string) error {
|
||||
main, flags := FindFields(args)
|
||||
main, fields := FindFields(args)
|
||||
for _, ca := range cli.cmdArgs {
|
||||
cmd, err := ca.Parse(main, flags)
|
||||
cmd, err := ca.Parse(main, fields)
|
||||
switch {
|
||||
case errors.Is(err, ErrWrongCommand):
|
||||
continue
|
||||
case err != nil:
|
||||
return err
|
||||
default:
|
||||
return cmd.Do(cli.deps)
|
||||
}
|
||||
|
||||
data, err := cmd.Do(cli.deps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch {
|
||||
case len(data) == 0:
|
||||
case len(data) == 1 && len(data[0]) == 1:
|
||||
fmt.Println(data[0][0])
|
||||
default:
|
||||
fmt.Printf("\n%s\n", format.Table(data))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("could not find matching command")
|
||||
|
|
|
@ -34,11 +34,11 @@ type Delete struct {
|
|||
args DeleteArgs
|
||||
}
|
||||
|
||||
func (del *Delete) Do(deps Dependencies) error {
|
||||
func (del *Delete) Do(deps Dependencies) ([][]string, error) {
|
||||
var id string
|
||||
idMap, err := deps.LocalIDRepo.FindAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get local ids: %v", err)
|
||||
return nil, fmt.Errorf("could not get local ids: %v", err)
|
||||
}
|
||||
for tskID, lid := range idMap {
|
||||
if del.args.LocalID == lid {
|
||||
|
@ -46,30 +46,30 @@ func (del *Delete) Do(deps Dependencies) error {
|
|||
}
|
||||
}
|
||||
if id == "" {
|
||||
return fmt.Errorf("could not find local id")
|
||||
return nil, fmt.Errorf("could not find local id")
|
||||
}
|
||||
|
||||
tsk, err := deps.TaskRepo.Find(id)
|
||||
tsk, err := deps.TaskRepo.FindOne(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get task: %v", err)
|
||||
return nil, fmt.Errorf("could not get task: %v", err)
|
||||
}
|
||||
|
||||
it, err := tsk.Item()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert task to sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not convert task to sync item: %v", err)
|
||||
}
|
||||
it.Deleted = true
|
||||
if err := deps.SyncRepo.Store(it); err != nil {
|
||||
return fmt.Errorf("could not store sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not store sync item: %v", err)
|
||||
}
|
||||
|
||||
if err := deps.LocalIDRepo.Delete(id); err != nil {
|
||||
return fmt.Errorf("could not delete local id: %v", err)
|
||||
return nil, fmt.Errorf("could not delete local id: %v", err)
|
||||
}
|
||||
|
||||
if err := deps.TaskRepo.Delete(id); err != nil {
|
||||
return fmt.Errorf("could not delete task: %v", err)
|
||||
return nil, fmt.Errorf("could not delete task: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -61,19 +61,19 @@ func TestDelete(t *testing.T) {
|
|||
if tc.expParseErr {
|
||||
return
|
||||
}
|
||||
actDoErr := cmd.Do(command.Dependencies{
|
||||
_, actDoErr := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localIDRepo,
|
||||
SyncRepo: syncRepo,
|
||||
}) != nil
|
||||
if tc.expDoErr != actDoErr {
|
||||
})
|
||||
if tc.expDoErr != (actDoErr != nil) {
|
||||
t.Errorf("exp false, got %v", actDoErr)
|
||||
}
|
||||
if tc.expDoErr {
|
||||
return
|
||||
}
|
||||
|
||||
_, repoErr := taskRepo.Find(e.ID)
|
||||
_, repoErr := taskRepo.FindOne(e.ID)
|
||||
if !errors.Is(repoErr, storage.ErrNotFound) {
|
||||
t.Errorf("exp %v, got %v", storage.ErrNotFound, repoErr)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
)
|
||||
|
||||
type ListArgs struct {
|
||||
|
@ -22,22 +24,22 @@ func (la ListArgs) Parse(main []string, flags map[string]string) (Command, error
|
|||
type List struct {
|
||||
}
|
||||
|
||||
func (list *List) Do(deps Dependencies) error {
|
||||
func (list *List) Do(deps Dependencies) ([][]string, error) {
|
||||
localIDs, err := deps.LocalIDRepo.FindAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get local ids: %v", err)
|
||||
return nil, fmt.Errorf("could not get local ids: %v", err)
|
||||
}
|
||||
all, err := deps.TaskRepo.FindAll()
|
||||
all, err := deps.TaskRepo.FindMany(storage.TaskListParams{})
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range all {
|
||||
lid, ok := localIDs[e.ID]
|
||||
if !ok {
|
||||
return fmt.Errorf("could not find local id for %s", e.ID)
|
||||
return nil, fmt.Errorf("could not find local id for %s", e.ID)
|
||||
}
|
||||
fmt.Printf("%s\t%d\t%s\t%s\t%s\n", e.ID, lid, e.Title, e.Date.String(), e.Duration.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ func TestList(t *testing.T) {
|
|||
if tc.expErr {
|
||||
return
|
||||
}
|
||||
if err := cmd.Do(command.Dependencies{
|
||||
if _, err := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localRepo,
|
||||
}); err != nil {
|
||||
|
|
|
@ -1 +1,68 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
)
|
||||
|
||||
type ShowArgs struct {
|
||||
localID int
|
||||
}
|
||||
|
||||
func NewShowArgs() ShowArgs {
|
||||
return ShowArgs{}
|
||||
}
|
||||
|
||||
func (sa ShowArgs) Parse(main []string, fields map[string]string) (Command, error) {
|
||||
if len(main) != 1 {
|
||||
return nil, ErrWrongCommand
|
||||
}
|
||||
lid, err := strconv.Atoi(main[0])
|
||||
if err != nil {
|
||||
return nil, ErrWrongCommand
|
||||
}
|
||||
|
||||
return &Show{
|
||||
args: ShowArgs{
|
||||
localID: lid,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Show struct {
|
||||
args ShowArgs
|
||||
}
|
||||
|
||||
func (s *Show) Do(deps Dependencies) ([][]string, error) {
|
||||
id, err := deps.LocalIDRepo.FindOne(s.args.localID)
|
||||
switch {
|
||||
case errors.Is(err, storage.ErrNotFound):
|
||||
return nil, fmt.Errorf("could not find local id")
|
||||
case err != nil:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tsk, err := deps.TaskRepo.FindOne(id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not find task")
|
||||
}
|
||||
|
||||
var recurStr string
|
||||
if tsk.Recurrer != nil {
|
||||
recurStr = tsk.Recurrer.String()
|
||||
}
|
||||
data := [][]string{
|
||||
{"title", tsk.Title},
|
||||
{"local id", fmt.Sprintf("%d", s.args.localID)},
|
||||
{"date", tsk.Date.String()},
|
||||
{"time", tsk.Time.String()},
|
||||
{"duration", tsk.Duration.String()},
|
||||
{"recur", recurStr},
|
||||
// {"id", tsk.ID},
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package command_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/command"
|
||||
"go-mod.ewintr.nl/planner/plan/storage/memory"
|
||||
)
|
||||
|
||||
func TestShow(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
taskRepo := memory.NewTask()
|
||||
localRepo := memory.NewLocalID()
|
||||
tsk := item.Task{
|
||||
ID: "id",
|
||||
Date: item.NewDate(2024, 10, 7),
|
||||
TaskBody: item.TaskBody{
|
||||
Title: "name",
|
||||
},
|
||||
}
|
||||
if err := taskRepo.Store(tsk); err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
if err := localRepo.Store(tsk.ID, 1); err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
main []string
|
||||
expData [][]string
|
||||
expParseErr bool
|
||||
expDoErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
main: []string{},
|
||||
expParseErr: true,
|
||||
},
|
||||
{
|
||||
name: "wrong",
|
||||
main: []string{"delete"},
|
||||
expParseErr: true,
|
||||
},
|
||||
{
|
||||
name: "local id",
|
||||
main: []string{"1"},
|
||||
expData: [][]string{
|
||||
{"title", tsk.Title},
|
||||
{"local id", fmt.Sprintf("%d", 1)},
|
||||
{"date", tsk.Date.String()},
|
||||
{"time", tsk.Time.String()},
|
||||
{"duration", tsk.Duration.String()},
|
||||
{"recur", ""},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
cmd, actParseErr := command.NewShowArgs().Parse(tc.main, nil)
|
||||
if tc.expParseErr != (actParseErr != nil) {
|
||||
t.Errorf("exp %v, got %v", tc.expParseErr, actParseErr != nil)
|
||||
}
|
||||
if tc.expParseErr {
|
||||
return
|
||||
}
|
||||
actData, actDoErr := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localRepo,
|
||||
})
|
||||
if tc.expDoErr != (actDoErr != nil) {
|
||||
t.Errorf("exp %v, got %v", tc.expDoErr, actDoErr != nil)
|
||||
}
|
||||
if tc.expDoErr {
|
||||
return
|
||||
}
|
||||
if diff := cmp.Diff(tc.expData, actData); diff != "" {
|
||||
t.Errorf("(+exp, -got)%s\n", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -25,37 +25,37 @@ func (sa SyncArgs) Parse(main []string, flags map[string]string) (Command, error
|
|||
|
||||
type Sync struct{}
|
||||
|
||||
func (s *Sync) Do(deps Dependencies) error {
|
||||
func (s *Sync) Do(deps Dependencies) ([][]string, error) {
|
||||
// local new and updated
|
||||
sendItems, err := deps.SyncRepo.FindAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get updated items: %v", err)
|
||||
return nil, fmt.Errorf("could not get updated items: %v", err)
|
||||
}
|
||||
if err := deps.SyncClient.Update(sendItems); err != nil {
|
||||
return fmt.Errorf("could not send updated items: %v", err)
|
||||
return nil, fmt.Errorf("could not send updated items: %v", err)
|
||||
}
|
||||
if err := deps.SyncRepo.DeleteAll(); err != nil {
|
||||
return fmt.Errorf("could not clear updated items: %v", err)
|
||||
return nil, fmt.Errorf("could not clear updated items: %v", err)
|
||||
}
|
||||
|
||||
// get new/updated items
|
||||
ts, err := deps.SyncRepo.LastUpdate()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find timestamp of last update: %v", err)
|
||||
return nil, fmt.Errorf("could not find timestamp of last update: %v", err)
|
||||
}
|
||||
recItems, err := deps.SyncClient.Updated([]item.Kind{item.KindTask}, ts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not receive updates: %v", err)
|
||||
return nil, fmt.Errorf("could not receive updates: %v", err)
|
||||
}
|
||||
|
||||
updated := make([]item.Item, 0)
|
||||
for _, ri := range recItems {
|
||||
if ri.Deleted {
|
||||
if err := deps.LocalIDRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) {
|
||||
return fmt.Errorf("could not delete local id: %v", err)
|
||||
return nil, fmt.Errorf("could not delete local id: %v", err)
|
||||
}
|
||||
if err := deps.TaskRepo.Delete(ri.ID); err != nil && !errors.Is(err, storage.ErrNotFound) {
|
||||
return fmt.Errorf("could not delete task: %v", err)
|
||||
return nil, fmt.Errorf("could not delete task: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ func (s *Sync) Do(deps Dependencies) error {
|
|||
|
||||
lidMap, err := deps.LocalIDRepo.FindAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get local ids: %v", err)
|
||||
return nil, fmt.Errorf("could not get local ids: %v", err)
|
||||
}
|
||||
for _, u := range updated {
|
||||
var tskBody item.TaskBody
|
||||
if err := json.Unmarshal([]byte(u.Body), &tskBody); err != nil {
|
||||
return fmt.Errorf("could not unmarshal task body: %v", err)
|
||||
return nil, fmt.Errorf("could not unmarshal task body: %v", err)
|
||||
}
|
||||
tsk := item.Task{
|
||||
ID: u.ID,
|
||||
|
@ -79,20 +79,20 @@ func (s *Sync) Do(deps Dependencies) error {
|
|||
TaskBody: tskBody,
|
||||
}
|
||||
if err := deps.TaskRepo.Store(tsk); err != nil {
|
||||
return fmt.Errorf("could not store task: %v", err)
|
||||
return nil, fmt.Errorf("could not store task: %v", err)
|
||||
}
|
||||
lid, ok := lidMap[u.ID]
|
||||
if !ok {
|
||||
lid, err = deps.LocalIDRepo.Next()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get next local id: %v", err)
|
||||
return nil, fmt.Errorf("could not get next local id: %v", err)
|
||||
}
|
||||
|
||||
if err := deps.LocalIDRepo.Store(u.ID, lid); err != nil {
|
||||
return fmt.Errorf("could not store local id: %v", err)
|
||||
return nil, fmt.Errorf("could not store local id: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/google/go-cmp/cmp"
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/command"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
"go-mod.ewintr.nl/planner/plan/storage/memory"
|
||||
"go-mod.ewintr.nl/planner/sync/client"
|
||||
)
|
||||
|
@ -80,7 +81,7 @@ func TestSyncSend(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
if err := cmd.Do(command.Dependencies{
|
||||
if _, err := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localIDRepo,
|
||||
SyncRepo: syncRepo,
|
||||
|
@ -206,7 +207,7 @@ func TestSyncReceive(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
if err := cmd.Do(command.Dependencies{
|
||||
if _, err := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localIDRepo,
|
||||
SyncRepo: syncRepo,
|
||||
|
@ -216,7 +217,7 @@ func TestSyncReceive(t *testing.T) {
|
|||
}
|
||||
|
||||
// check result
|
||||
actTasks, err := taskRepo.FindAll()
|
||||
actTasks, err := taskRepo.FindMany(storage.TaskListParams{})
|
||||
if err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
)
|
||||
|
||||
type UpdateArgs struct {
|
||||
|
@ -83,24 +85,18 @@ type Update struct {
|
|||
args UpdateArgs
|
||||
}
|
||||
|
||||
func (u *Update) Do(deps Dependencies) error {
|
||||
var id string
|
||||
idMap, err := deps.LocalIDRepo.FindAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get local ids: %v", err)
|
||||
}
|
||||
for tid, lid := range idMap {
|
||||
if u.args.LocalID == lid {
|
||||
id = tid
|
||||
}
|
||||
}
|
||||
if id == "" {
|
||||
return fmt.Errorf("could not find local id")
|
||||
func (u *Update) Do(deps Dependencies) ([][]string, error) {
|
||||
id, err := deps.LocalIDRepo.FindOne(u.args.LocalID)
|
||||
switch {
|
||||
case errors.Is(err, storage.ErrNotFound):
|
||||
return nil, fmt.Errorf("could not find local id")
|
||||
case err != nil:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tsk, err := deps.TaskRepo.Find(id)
|
||||
tsk, err := deps.TaskRepo.FindOne(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find task")
|
||||
return nil, fmt.Errorf("could not find task")
|
||||
}
|
||||
|
||||
if u.args.Title != "" {
|
||||
|
@ -121,20 +117,20 @@ func (u *Update) Do(deps Dependencies) error {
|
|||
}
|
||||
|
||||
if !tsk.Valid() {
|
||||
return fmt.Errorf("task is unvalid")
|
||||
return nil, fmt.Errorf("task is unvalid")
|
||||
}
|
||||
|
||||
if err := deps.TaskRepo.Store(tsk); err != nil {
|
||||
return fmt.Errorf("could not store task: %v", err)
|
||||
return nil, fmt.Errorf("could not store task: %v", err)
|
||||
}
|
||||
|
||||
it, err := tsk.Item()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not convert task to sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not convert task to sync item: %v", err)
|
||||
}
|
||||
if err := deps.SyncRepo.Store(it); err != nil {
|
||||
return fmt.Errorf("could not store sync item: %v", err)
|
||||
return nil, fmt.Errorf("could not store sync item: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -189,19 +189,19 @@ func TestUpdateExecute(t *testing.T) {
|
|||
if tc.expParseErr {
|
||||
return
|
||||
}
|
||||
actDoErr := cmd.Do(command.Dependencies{
|
||||
_, actDoErr := cmd.Do(command.Dependencies{
|
||||
TaskRepo: taskRepo,
|
||||
LocalIDRepo: localIDRepo,
|
||||
SyncRepo: syncRepo,
|
||||
}) != nil
|
||||
if tc.expDoErr != actDoErr {
|
||||
})
|
||||
if tc.expDoErr != (actDoErr != nil) {
|
||||
t.Errorf("exp %v, got %v", tc.expDoErr, actDoErr)
|
||||
}
|
||||
if tc.expDoErr {
|
||||
return
|
||||
}
|
||||
|
||||
actTask, err := taskRepo.Find(tskID)
|
||||
actTask, err := taskRepo.FindOne(tskID)
|
||||
if err != nil {
|
||||
t.Errorf("exp nil, got %v", err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package format
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Table(data [][]string) string {
|
||||
if len(data) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// make all cells in a column the same width
|
||||
max := make([]int, len(data[0]))
|
||||
for _, row := range data {
|
||||
for c, cell := range row {
|
||||
if len(cell) > max[c] {
|
||||
max[c] = len(cell)
|
||||
}
|
||||
}
|
||||
}
|
||||
for r, row := range data {
|
||||
for c, cell := range row {
|
||||
for s := len(cell); s < max[c]; s++ {
|
||||
data[r][c] += " "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make it smaller if the result is too wide
|
||||
// only by making the widest column smaller for now
|
||||
maxWidth := findTermWidth()
|
||||
if maxWidth != 0 {
|
||||
width := len(max) - 1
|
||||
for _, m := range max {
|
||||
width += m
|
||||
}
|
||||
shortenWith := width - maxWidth
|
||||
widestColNo, widestColLen := 0, 0
|
||||
for i, m := range max {
|
||||
if m > widestColLen {
|
||||
widestColNo, widestColLen = i, m
|
||||
}
|
||||
}
|
||||
newTaskColWidth := max[widestColNo] - shortenWith
|
||||
if newTaskColWidth < 0 {
|
||||
return "table is too wide to display\n"
|
||||
}
|
||||
if newTaskColWidth < max[widestColNo] {
|
||||
for r, row := range data {
|
||||
data[r][widestColNo] = row[widestColNo][:newTaskColWidth]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// print the rows
|
||||
var output string
|
||||
for r, row := range data {
|
||||
if r%3 == 0 {
|
||||
output += fmt.Sprintf("%s", "\x1b[48;5;237m")
|
||||
}
|
||||
for c, col := range row {
|
||||
output += col
|
||||
if c != len(row)-1 {
|
||||
output += " "
|
||||
}
|
||||
}
|
||||
if r%3 == 0 {
|
||||
output += fmt.Sprintf("%s", "\x1b[49m")
|
||||
}
|
||||
output += "\n"
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func findTermWidth() int {
|
||||
cmd := exec.Command("stty", "size")
|
||||
cmd.Stdin = os.Stdin
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
s := string(out)
|
||||
s = strings.TrimSpace(s)
|
||||
sArr := strings.Split(s, " ")
|
||||
|
||||
width, err := strconv.Atoi(sArr[1])
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return width
|
||||
}
|
|
@ -18,6 +18,19 @@ func NewLocalID() *LocalID {
|
|||
}
|
||||
}
|
||||
|
||||
func (ml *LocalID) FindOne(lid int) (string, error) {
|
||||
ml.mutex.RLock()
|
||||
defer ml.mutex.RUnlock()
|
||||
|
||||
for id, l := range ml.ids {
|
||||
if lid == l {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", storage.ErrNotFound
|
||||
}
|
||||
|
||||
func (ml *LocalID) FindAll() (map[string]int, error) {
|
||||
ml.mutex.RLock()
|
||||
defer ml.mutex.RUnlock()
|
||||
|
|
|
@ -54,6 +54,21 @@ func TestLocalID(t *testing.T) {
|
|||
t.Errorf("exp 2, got %v", actLid)
|
||||
}
|
||||
|
||||
t.Log("find by local id")
|
||||
actID, actErr := repo.FindOne(1)
|
||||
if actErr != nil {
|
||||
t.Errorf("exp nil, got %v", actErr)
|
||||
}
|
||||
if actID != "test" {
|
||||
t.Errorf("exp test, got %v", actID)
|
||||
}
|
||||
|
||||
t.Log("unknown local id")
|
||||
actID, actErr = repo.FindOne(2)
|
||||
if !errors.Is(actErr, storage.ErrNotFound) {
|
||||
t.Errorf("exp ErrNotFound, got %v", actErr)
|
||||
}
|
||||
|
||||
actIDs, actErr = repo.FindAll()
|
||||
if actErr != nil {
|
||||
t.Errorf("exp nil, got %v", actErr)
|
||||
|
|
|
@ -19,7 +19,7 @@ func NewTask() *Task {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *Task) Find(id string) (item.Task, error) {
|
||||
func (t *Task) FindOne(id string) (item.Task, error) {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
|
@ -30,14 +30,16 @@ func (t *Task) Find(id string) (item.Task, error) {
|
|||
return task, nil
|
||||
}
|
||||
|
||||
func (t *Task) FindAll() ([]item.Task, error) {
|
||||
func (t *Task) FindMany(params storage.TaskListParams) ([]item.Task, error) {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
tasks := make([]item.Task, 0, len(t.tasks))
|
||||
for _, tsk := range t.tasks {
|
||||
if storage.Match(tsk, params) {
|
||||
tasks = append(tasks, tsk)
|
||||
}
|
||||
}
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].ID < tasks[j].ID
|
||||
})
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
)
|
||||
|
||||
func TestTask(t *testing.T) {
|
||||
|
@ -12,7 +13,7 @@ func TestTask(t *testing.T) {
|
|||
mem := NewTask()
|
||||
|
||||
t.Log("empty")
|
||||
actTasks, actErr := mem.FindAll()
|
||||
actTasks, actErr := mem.FindMany(storage.TaskListParams{})
|
||||
if actErr != nil {
|
||||
t.Errorf("exp nil, got %v", actErr)
|
||||
}
|
||||
|
@ -36,7 +37,7 @@ func TestTask(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Log("find one")
|
||||
actTask, actErr := mem.Find(tsk1.ID)
|
||||
actTask, actErr := mem.FindOne(tsk1.ID)
|
||||
if actErr != nil {
|
||||
t.Errorf("exp nil, got %v", actErr)
|
||||
}
|
||||
|
@ -45,7 +46,7 @@ func TestTask(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Log("find all")
|
||||
actTasks, actErr = mem.FindAll()
|
||||
actTasks, actErr = mem.FindMany(storage.TaskListParams{})
|
||||
if actErr != nil {
|
||||
t.Errorf("exp nil, got %v", actErr)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package sqlite
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
|
@ -11,6 +12,23 @@ type LocalID struct {
|
|||
db *sql.DB
|
||||
}
|
||||
|
||||
func (l *LocalID) FindOne(lid int) (string, error) {
|
||||
var id string
|
||||
err := l.db.QueryRow(`
|
||||
SELECT id
|
||||
FROM localids
|
||||
WHERE local_id = ?
|
||||
`, lid).Scan(&id)
|
||||
switch {
|
||||
case errors.Is(err, sql.ErrNoRows):
|
||||
return "", storage.ErrNotFound
|
||||
case err != nil:
|
||||
return "", fmt.Errorf("%w: %v", ErrSqliteFailure, err)
|
||||
}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (l *LocalID) FindAll() (map[string]int, error) {
|
||||
rows, err := l.db.Query(`
|
||||
SELECT id, local_id
|
||||
|
|
|
@ -38,7 +38,7 @@ recurrer=?
|
|||
return nil
|
||||
}
|
||||
|
||||
func (t *SqliteTask) Find(id string) (item.Task, error) {
|
||||
func (t *SqliteTask) FindOne(id string) (item.Task, error) {
|
||||
var tsk item.Task
|
||||
var dateStr, timeStr, recurStr, durStr string
|
||||
err := t.db.QueryRow(`
|
||||
|
@ -63,7 +63,7 @@ WHERE id = ?`, id).Scan(&tsk.ID, &tsk.Title, &dateStr, &timeStr, &durStr, &recur
|
|||
return tsk, nil
|
||||
}
|
||||
|
||||
func (t *SqliteTask) FindAll() ([]item.Task, error) {
|
||||
func (t *SqliteTask) FindMany(params storage.TaskListParams) ([]item.Task, error) {
|
||||
rows, err := t.db.Query(`
|
||||
SELECT id, title, date, time, duration, recurrer
|
||||
FROM tasks`)
|
||||
|
|
|
@ -13,6 +13,7 @@ var (
|
|||
)
|
||||
|
||||
type LocalID interface {
|
||||
FindOne(lid int) (string, error)
|
||||
FindAll() (map[string]int, error)
|
||||
FindOrNext(id string) (int, error)
|
||||
Next() (int, error)
|
||||
|
@ -27,13 +28,29 @@ type Sync interface {
|
|||
LastUpdate() (time.Time, error)
|
||||
}
|
||||
|
||||
type TaskListParams struct {
|
||||
Recurrer bool
|
||||
Date item.Date
|
||||
}
|
||||
|
||||
type Task interface {
|
||||
Store(task item.Task) error
|
||||
Find(id string) (item.Task, error)
|
||||
FindAll() ([]item.Task, error)
|
||||
FindOne(id string) (item.Task, error)
|
||||
FindMany(params TaskListParams) ([]item.Task, error)
|
||||
Delete(id string) error
|
||||
}
|
||||
|
||||
func Match(tsk item.Task, req TaskListParams) bool {
|
||||
if req.Recurrer && tsk.Recurrer == nil {
|
||||
return false
|
||||
}
|
||||
if !req.Date.IsZero() && !req.Date.Equal(tsk.Date) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func NextLocalID(used []int) int {
|
||||
if len(used) == 0 {
|
||||
return 1
|
||||
|
|
|
@ -3,10 +3,60 @@ package storage_test
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"go-mod.ewintr.nl/planner/item"
|
||||
"go-mod.ewintr.nl/planner/plan/storage"
|
||||
)
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tskMatch := item.Task{
|
||||
ID: "id",
|
||||
Date: item.NewDate(2024, 12, 29),
|
||||
Recurrer: item.NewRecurrer("2024-12-29, daily"),
|
||||
TaskBody: item.TaskBody{
|
||||
Title: "name",
|
||||
},
|
||||
}
|
||||
tskNotMatch := item.Task{
|
||||
ID: "id",
|
||||
Date: item.NewDate(2024, 12, 28),
|
||||
TaskBody: item.TaskBody{
|
||||
Title: "name",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
params storage.TaskListParams
|
||||
}{
|
||||
{
|
||||
name: "date",
|
||||
params: storage.TaskListParams{
|
||||
Date: item.NewDate(2024, 12, 29),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "recurrer",
|
||||
params: storage.TaskListParams{
|
||||
Recurrer: true,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if !storage.Match(tskMatch, tc.params) {
|
||||
t.Errorf("exp tsk to match")
|
||||
}
|
||||
if storage.Match(tskNotMatch, tc.params) {
|
||||
t.Errorf("exp tsk to not match")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextLocalId(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
used []int
|
||||
|
|
Loading…
Reference in New Issue