From 54e2f162c03ff7c732751ef35c266093c842c7bc Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Wed, 15 Jul 2026 18:06:03 +0000 Subject: feat(tasks): add projects/labels schema, wire project_id through native tasks project_id joins the existing labels JSON column as series-level metadata: CreateNextIteration copies both onto every new recurring occurrence, matching content/description/priority's existing behavior. --- internal/store/native_tasks_test.go | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'internal/store/native_tasks_test.go') diff --git a/internal/store/native_tasks_test.go b/internal/store/native_tasks_test.go index c362eb7..6e93bca 100644 --- a/internal/store/native_tasks_test.go +++ b/internal/store/native_tasks_test.go @@ -30,6 +30,7 @@ func newNativeTasksTestStore(t *testing.T) *Store { content TEXT NOT NULL, description TEXT DEFAULT '', project_name TEXT DEFAULT '', + project_id TEXT DEFAULT '', due_date DATETIME, priority INTEGER DEFAULT 1, completed BOOLEAN DEFAULT 0, @@ -490,3 +491,72 @@ func TestAdvanceDueRecurringTasks_NonRecurringTask_NeverTouched(t *testing.T) { t.Errorf("expected 0 iterations created (no recurring tasks in fixture), got %d", n) } } + +func TestGetNativeTasks_ParsesProjectID(t *testing.T) { + s := newNativeTasksTestStore(t) + if _, err := s.db.Exec(`INSERT INTO native_tasks (id, content, project_id) VALUES ('proj-1', 'Task with project', 'project-abc')`); err != nil { + t.Fatal(err) + } + + tasks, err := s.GetNativeTasks() + if err != nil { + t.Fatalf("GetNativeTasks: %v", err) + } + var found *models.Task + for i := range tasks { + if tasks[i].ID == "proj-1" { + found = &tasks[i] + } + } + if found == nil { + t.Fatal("expected to find proj-1") + } + if found.ProjectID != "project-abc" { + t.Errorf("ProjectID = %q, want %q", found.ProjectID, "project-abc") + } +} + +func TestCreateNativeTask_PersistsProjectID(t *testing.T) { + s := newNativeTasksTestStore(t) + task := models.Task{ID: "new-1", Content: "New task", ProjectID: "project-xyz"} + if err := s.CreateNativeTask(task); err != nil { + t.Fatalf("CreateNativeTask: %v", err) + } + + got, err := s.GetNativeTaskByID("new-1") + if err != nil { + t.Fatal(err) + } + if got.ProjectID != "project-xyz" { + t.Errorf("ProjectID = %q, want %q", got.ProjectID, "project-xyz") + } +} + +func TestCreateNextIteration_InheritsProjectIDAndLabels(t *testing.T) { + s := newNativeTasksTestStore(t) + if _, err := s.db.Exec(` + INSERT INTO native_tasks (id, content, due_date, recurrence_freq, recurrence_interval, recurrence_series_id, project_id, labels) + VALUES ('rec-1', 'Water plants', '2026-07-13', 'weekly', 1, 'series-1', 'project-abc', '["chore","garden"]') + `); err != nil { + t.Fatal(err) + } + + if err := s.CompleteNativeTask("rec-1"); err != nil { + t.Fatalf("CompleteNativeTask: %v", err) + } + + var nextID string + if err := s.db.QueryRow(`SELECT id FROM native_tasks WHERE recurrence_series_id = 'series-1' AND id != 'rec-1'`).Scan(&nextID); err != nil { + t.Fatal(err) + } + next, err := s.GetNativeTaskByID(nextID) + if err != nil { + t.Fatal(err) + } + if next.ProjectID != "project-abc" { + t.Errorf("next iteration ProjectID = %q, want %q", next.ProjectID, "project-abc") + } + if len(next.Labels) != 2 || next.Labels[0] != "chore" || next.Labels[1] != "garden" { + t.Errorf("next iteration Labels = %v, want [chore garden]", next.Labels) + } +} -- cgit v1.2.3