From 55fe158f7993300e83b537ba60262edd5167d687 Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Thu, 19 Dec 2024 12:06:03 +0100 Subject: [PATCH] wip --- plan/command/command_test.go | 167 +++++++++++++--------------------- plan/storage/sqlite/event.go | 48 ++++++++-- plan/storage/sqlite/sqlite.go | 9 ++ 3 files changed, 110 insertions(+), 114 deletions(-) diff --git a/plan/command/command_test.go b/plan/command/command_test.go index 09241e0..54af244 100644 --- a/plan/command/command_test.go +++ b/plan/command/command_test.go @@ -1,109 +1,68 @@ package command_test -// func TestArgSet(t *testing.T) { -// t.Parallel() +import ( + "testing" -// as := command.ArgSet{ -// Main: "main", -// Flags: map[string]string{ -// "name 1": "value 1", -// "name 2": "value 2", -// "name 3": "value 3", -// }, -// } + "github.com/google/go-cmp/cmp" + "go-mod.ewintr.nl/planner/plan/command" +) -// t.Run("hasflag", func(t *testing.T) { -// t.Run("true", func(t *testing.T) { -// if has := as.HasFlag("name 1"); !has { -// t.Errorf("exp true, got %v", has) -// } -// }) -// t.Run("false", func(t *testing.T) { -// if has := as.HasFlag("unknown"); has { -// t.Errorf("exp false, got %v", has) -// } -// }) -// }) +func TestParseArgs(t *testing.T) { + t.Parallel() -// t.Run("flag", func(t *testing.T) { -// t.Run("known", func(t *testing.T) { -// if val := as.Flag("name 1"); val != "value 1" { -// t.Errorf("exp value 1, got %v", val) -// } -// }) -// t.Run("unknown", func(t *testing.T) { -// if val := as.Flag("unknown"); val != "" { -// t.Errorf(`exp "", got %v`, val) -// } -// }) -// }) - -// t.Run("setflag", func(t *testing.T) { -// exp := "new value" -// as.SetFlag("new name", exp) -// if act := as.Flag("new name"); exp != act { -// t.Errorf("exp %v, got %v", exp, act) -// } -// }) -// } - -// func TestParseArgs(t *testing.T) { -// t.Parallel() - -// for _, tc := range []struct { -// name string -// args []string -// expAS *command.ArgSet -// expErr bool -// }{ -// { -// name: "empty", -// expAS: &command.ArgSet{ -// Flags: map[string]string{}, -// }, -// }, -// { -// name: "just main", -// args: []string{"one", "two three", "four"}, -// expAS: &command.ArgSet{ -// Main: "one two three four", -// Flags: map[string]string{}, -// }, -// }, -// { -// name: "with flags", -// args: []string{"-flag1", "value1", "one", "two", "-flag2", "value2", "-flag3", "value3"}, -// expAS: &command.ArgSet{ -// Main: "one two", -// Flags: map[string]string{ -// "flag1": "value1", -// "flag2": "value2", -// "flag3": "value3", -// }, -// }, -// }, -// { -// name: "flag without value", -// args: []string{"one", "two", "-flag1"}, -// expErr: true, -// }, -// { -// name: "split main", -// args: []string{"one", "-flag1", "value1", "two"}, -// expErr: true, -// }, -// } { -// t.Run(tc.name, func(t *testing.T) { -// actAS, actErr := command.ParseArgs(tc.args) -// if tc.expErr != (actErr != nil) { -// t.Errorf("exp %v, got %v", tc.expErr, actErr) -// } -// if tc.expErr { -// return -// } -// if diff := cmp.Diff(tc.expAS, actAS); diff != "" { -// t.Errorf("(exp +, got -)\n%s", diff) -// } -// }) -// } -// } + for _, tc := range []struct { + name string + args []string + expMain []string + expFlags map[string]string + expErr bool + }{ + { + name: "empty", + expMain: []string{}, + expFlags: map[string]string{}, + }, + { + name: "just main", + args: []string{"one", "two three", "four"}, + expMain: []string{"one", "two three", "four"}, + expFlags: map[string]string{}, + }, + { + name: "with flags", + args: []string{"-flag1", "value1", "one", "two", "-flag2", "value2", "-flag3", "value3"}, + expMain: []string{"one", "two"}, + expFlags: map[string]string{ + "flag1": "value1", + "flag2": "value2", + "flag3": "value3", + }, + }, + { + name: "flag without value", + args: []string{"one", "two", "-flag1"}, + expErr: true, + }, + { + name: "split main", + args: []string{"one", "-flag1", "value1", "two"}, + expErr: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + actMain, actFlags, actErr := command.ParseFlags(tc.args) + if tc.expErr != (actErr != nil) { + t.Errorf("exp %v, got %v", tc.expErr, actErr) + } + if tc.expErr { + return + } + if diff := cmp.Diff(tc.expMain, actMain); diff != "" { + t.Errorf("(exp +, got -)\n%s", diff) + } + if diff := cmp.Diff(tc.expFlags, actFlags); diff != "" { + t.Errorf("(exp +, got -)\n%s", diff) + } + }) + } +} diff --git a/plan/storage/sqlite/event.go b/plan/storage/sqlite/event.go index 6f553b2..70deea9 100644 --- a/plan/storage/sqlite/event.go +++ b/plan/storage/sqlite/event.go @@ -2,6 +2,7 @@ package sqlite import ( "database/sql" + "encoding/json" "fmt" "time" @@ -14,18 +15,29 @@ type SqliteEvent struct { } func (s *SqliteEvent) Store(event item.Event) error { + var recurStr *string + if event.Recurrer != nil { + recurBytes, err := json.Marshal(event.Recurrer) + if err != nil { + return fmt.Errorf("could not marshal recurrer: %v", err) + } + rs := string(recurBytes) + recurStr = &rs + } if _, err := s.db.Exec(` INSERT INTO events -(id, title, start, duration) +(id, title, start, duration, recur) VALUES -(?, ?, ?, ?) +(?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET title=?, start=?, -duration=?`, - event.ID, event.Title, event.Start.Format(timestampFormat), event.Duration.String(), - event.Title, event.Start.Format(timestampFormat), event.Duration.String()); err != nil { +duration=?, +recur=? +`, + event.ID, event.Title, event.Start.Format(timestampFormat), event.Duration.String(), recurStr, + event.Title, event.Start.Format(timestampFormat), event.Duration.String(), recurStr); err != nil { return fmt.Errorf("%w: %v", ErrSqliteFailure, err) } return nil @@ -34,10 +46,11 @@ duration=?`, func (s *SqliteEvent) Find(id string) (item.Event, error) { var event item.Event var durStr string + var recurStr *string err := s.db.QueryRow(` -SELECT id, title, start, duration +SELECT id, title, start, duration, recur FROM events -WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &durStr) +WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &durStr, &recurStr) switch { case err == sql.ErrNoRows: return item.Event{}, fmt.Errorf("event not found: %w", err) @@ -46,16 +59,23 @@ WHERE id = ?`, id).Scan(&event.ID, &event.Title, &event.Start, &durStr) } dur, err := time.ParseDuration(durStr) if err != nil { - return item.Event{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + return item.Event{}, fmt.Errorf("could not unmarshal recurrer: %v", err) } event.Duration = dur + if recurStr != nil { + var rec item.Recur + if err := json.Unmarshal([]byte(*recurStr), &rec); err != nil { + return item.Event{}, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + event.Recurrer = &rec + } return event, nil } func (s *SqliteEvent) FindAll() ([]item.Event, error) { rows, err := s.db.Query(` -SELECT id, title, start, duration +SELECT id, title, start, duration, recur FROM events`) if err != nil { return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) @@ -65,7 +85,8 @@ FROM events`) for rows.Next() { var event item.Event var durStr string - if err := rows.Scan(&event.ID, &event.Title, &event.Start, &durStr); err != nil { + var recurStr *string + if err := rows.Scan(&event.ID, &event.Title, &event.Start, &durStr, &recurStr); err != nil { return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) } dur, err := time.ParseDuration(durStr) @@ -73,6 +94,13 @@ FROM events`) return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) } event.Duration = dur + if recurStr != nil { + var rec item.Recur + if err := json.Unmarshal([]byte(*recurStr), &rec); err != nil { + return nil, fmt.Errorf("could not unmarshal recurrer: %v", err) + } + event.Recurrer = &rec + } result = append(result, event) } diff --git a/plan/storage/sqlite/sqlite.go b/plan/storage/sqlite/sqlite.go index f976280..cfdd967 100644 --- a/plan/storage/sqlite/sqlite.go +++ b/plan/storage/sqlite/sqlite.go @@ -25,6 +25,15 @@ var migrations = []string{ deleted BOOLEAN NOT NULL, body TEXT NOT NULL )`, + `ALTER TABLE events ADD COLUMN recur_period TEXT`, + `ALTER TABLE events ADD COLUMN recur_count INTEGER`, + `ALTER TABLE events ADD COLUMN recur_start TIMESTAMP`, + `ALTER TABLE events ADD COLUMN recur_next TIMESTAMP`, + `ALTER TABLE events DROP COLUMN recur_period`, + `ALTER TABLE events DROP COLUMN recur_count`, + `ALTER TABLE events DROP COLUMN recur_start`, + `ALTER TABLE events DROP COLUMN recur_next`, + `ALTER TABLE events ADD COLUMN recur TEXT`, } var (