From 6677d156d81b2578f8e1c670faf45a52c343ca12 Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Sun, 19 Jan 2025 11:16:34 +0100 Subject: [PATCH] sqlite --- plan/storage/memory/task.go | 2 +- plan/storage/sqlite/migrations.go | 7 +++ plan/storage/sqlite/schedule.go | 81 +++++++++++++++++++++++++++++++ plan/storage/storage.go | 8 ++- plan/storage/storage_test.go | 4 +- 5 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 plan/storage/sqlite/schedule.go diff --git a/plan/storage/memory/task.go b/plan/storage/memory/task.go index c91ef8d..b5ba26b 100644 --- a/plan/storage/memory/task.go +++ b/plan/storage/memory/task.go @@ -36,7 +36,7 @@ func (t *Task) FindMany(params storage.TaskListParams) ([]item.Task, error) { tasks := make([]item.Task, 0, len(t.tasks)) for _, tsk := range t.tasks { - if storage.Match(tsk, params) { + if storage.MatchTask(tsk, params) { tasks = append(tasks, tsk) } } diff --git a/plan/storage/sqlite/migrations.go b/plan/storage/sqlite/migrations.go index a786d46..af70c7e 100644 --- a/plan/storage/sqlite/migrations.go +++ b/plan/storage/sqlite/migrations.go @@ -44,4 +44,11 @@ var migrations = []string{ `ALTER TABLE tasks ADD COLUMN project TEXT NOT NULL DEFAULT ''`, `CREATE TABLE syncupdate ("timestamp" TIMESTAMP NOT NULL)`, `INSERT INTO syncupdate (timestamp) VALUES ("0001-01-01T00:00:00Z")`, + + `CREATE TABLE schedules ( + "id" TEXT UNIQUE NOT NULL DEFAULT '', + "title" TEXT NOT NULL DEFAULT '', + "date" TEXT NOT NULL DEFAULT '', + "recur" TEXT NOT NULL DEFAULT '', + "recur_next" TEXT NOT NULL DEFAULT '')`, } diff --git a/plan/storage/sqlite/schedule.go b/plan/storage/sqlite/schedule.go new file mode 100644 index 0000000..6b9271e --- /dev/null +++ b/plan/storage/sqlite/schedule.go @@ -0,0 +1,81 @@ +package sqlite + +import ( + "fmt" + + "go-mod.ewintr.nl/planner/item" + "go-mod.ewintr.nl/planner/plan/storage" +) + +type SqliteSchedule struct { + tx *storage.Tx +} + +func (ss *SqliteSchedule) Store(sched item.Schedule) error { + var recurStr string + if sched.Recurrer != nil { + recurStr = sched.Recurrer.String() + } + if _, err := ss.tx.Exec(` +INSERT INTO schedules +(id, title, date, recurrer) +VALUES +(?, ?, ?, ?) +ON CONFLICT(id) DO UPDATE +SET +title=?, +date=?, +recurrer=? +`, + sched.ID, sched.Title, sched.Date.String(), recurStr, + sched.Title, sched.Date.String(), recurStr); err != nil { + return fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + return nil +} + +func (ss *SqliteSchedule) Find(start, end item.Date) ([]item.Schedule, error) { + rows, err := ss.tx.Query(`SELECT +id, title, date, recurrer +FROM schedules +WHERE date >= ? AND date <= ?`, start.String(), end.String()) + if err != nil { + return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + defer rows.Close() + scheds := make([]item.Schedule, 0) + for rows.Next() { + var sched item.Schedule + var dateStr, recurStr string + if err := rows.Scan(&sched.ID, &sched.Title, &dateStr, &recurStr); err != nil { + return nil, fmt.Errorf("%w: %v", ErrSqliteFailure, err) + } + sched.Date = item.NewDateFromString(dateStr) + sched.Recurrer = item.NewRecurrer(recurStr) + + scheds = append(scheds, sched) + } + + return scheds, nil +} + +func (ss *SqliteSchedule) Delete(id string) error { + + result, err := ss.tx.Exec(` +DELETE FROM schedules +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 6bbc449..3230183 100644 --- a/plan/storage/storage.go +++ b/plan/storage/storage.go @@ -49,7 +49,13 @@ type Task interface { Projects() (map[string]int, error) } -func Match(tsk item.Task, params TaskListParams) bool { +type Schedule interface { + Store(sched item.Schedule) error + Find(start, end item.Date) ([]item.Schedule, error) + Delete(id string) error +} + +func MatchTask(tsk item.Task, params TaskListParams) bool { if params.HasRecurrer && tsk.Recurrer == nil { return false } diff --git a/plan/storage/storage_test.go b/plan/storage/storage_test.go index 7ed78ae..5bc62d8 100644 --- a/plan/storage/storage_test.go +++ b/plan/storage/storage_test.go @@ -59,10 +59,10 @@ func TestMatch(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - if !storage.Match(tskMatch, tc.params) { + if !storage.MatchTask(tskMatch, tc.params) { t.Errorf("exp tsk to match") } - if storage.Match(tskNotMatch, tc.params) { + if storage.MatchTask(tskNotMatch, tc.params) { t.Errorf("exp tsk to not match") } })