diff options
Diffstat (limited to 'internal/store')
| -rw-r--r-- | internal/store/sqlite.go | 97 | ||||
| -rw-r--r-- | internal/store/sqlite_test.go | 139 |
2 files changed, 236 insertions, 0 deletions
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go index a4d01a2..5b67234 100644 --- a/internal/store/sqlite.go +++ b/internal/store/sqlite.go @@ -595,3 +595,100 @@ func (s *Store) GetBugs() ([]Bug, error) { } return bugs, rows.Err() } + +// GetTasksByDateRange retrieves tasks due within a specific date range +func (s *Store) GetTasksByDateRange(start, end time.Time) ([]models.Task, error) { + rows, err := s.db.Query(` + SELECT id, content, description, project_id, project_name, due_date, priority, completed, labels, url, created_at + FROM tasks + WHERE due_date BETWEEN ? AND ? + ORDER BY due_date ASC, priority DESC + `, start, end) + if err != nil { + return nil, err + } + defer rows.Close() + + var tasks []models.Task + for rows.Next() { + var task models.Task + var labelsJSON string + var dueDate sql.NullTime + + err := rows.Scan( + &task.ID, + &task.Content, + &task.Description, + &task.ProjectID, + &task.ProjectName, + &dueDate, + &task.Priority, + &task.Completed, + &labelsJSON, + &task.URL, + &task.CreatedAt, + ) + if err != nil { + return nil, err + } + + if dueDate.Valid { + task.DueDate = &dueDate.Time + } + + if err := json.Unmarshal([]byte(labelsJSON), &task.Labels); err != nil { + log.Printf("Warning: failed to unmarshal labels for task %s: %v", task.ID, err) + task.Labels = []string{} + } + tasks = append(tasks, task) + } + + return tasks, rows.Err() +} + +// GetMealsByDateRange retrieves meals within a specific date range +func (s *Store) GetMealsByDateRange(start, end time.Time) ([]models.Meal, error) { + return s.GetMeals(start, end) +} + +// GetCardsByDateRange retrieves cards due within a specific date range +func (s *Store) GetCardsByDateRange(start, end time.Time) ([]models.Card, error) { + rows, err := s.db.Query(` + SELECT c.id, c.name, b.name, c.list_id, c.list_name, c.due_date, c.url + FROM cards c + JOIN boards b ON c.board_id = b.id + WHERE c.due_date BETWEEN ? AND ? + ORDER BY c.due_date ASC + `, start, end) + if err != nil { + return nil, err + } + defer rows.Close() + + var cards []models.Card + for rows.Next() { + var card models.Card + var dueDate sql.NullTime + + err := rows.Scan( + &card.ID, + &card.Name, + &card.BoardName, + &card.ListID, + &card.ListName, + &dueDate, + &card.URL, + ) + if err != nil { + return nil, err + } + + if dueDate.Valid { + card.DueDate = &dueDate.Time + } + + cards = append(cards, card) + } + + return cards, rows.Err() +} diff --git a/internal/store/sqlite_test.go b/internal/store/sqlite_test.go index c09f3ca..7027cbe 100644 --- a/internal/store/sqlite_test.go +++ b/internal/store/sqlite_test.go @@ -89,6 +89,39 @@ func setupTestStoreWithCards(t *testing.T) *Store { return store } +// setupTestStoreWithMeals creates a test store with meals table +func setupTestStoreWithMeals(t *testing.T) *Store { + t.Helper() + + tempDir := t.TempDir() + dbPath := filepath.Join(tempDir, "test.db") + + db, err := sql.Open("sqlite3", dbPath) + if err != nil { + t.Fatalf("Failed to open test database: %v", err) + } + + db.SetMaxOpenConns(1) + + store := &Store{db: db} + + schema := ` + CREATE TABLE IF NOT EXISTS meals ( + id TEXT PRIMARY KEY, + recipe_name TEXT NOT NULL, + date DATETIME, + meal_type TEXT, + recipe_url TEXT, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP + ); + ` + if _, err := db.Exec(schema); err != nil { + t.Fatalf("Failed to create schema: %v", err) + } + + return store +} + // TestDeleteTask verifies that DeleteTask removes a task from the cache func TestDeleteTask(t *testing.T) { store := setupTestStoreWithTasks(t) @@ -430,3 +463,109 @@ func TestSaveAndGetBoards_ManyBoards(t *testing.T) { t.Errorf("Expected %d total cards, got %d", expectedTotal, totalCards) } } + +func TestGetTasksByDateRange(t *testing.T) { + store := setupTestStoreWithTasks(t) + defer store.Close() + + now := time.Now() + tomorrow := now.Add(24 * time.Hour) + nextWeek := now.Add(7 * 24 * time.Hour) + + tasks := []models.Task{ + {ID: "1", Content: "Task 1", DueDate: &now}, + {ID: "2", Content: "Task 2", DueDate: &tomorrow}, + {ID: "3", Content: "Task 3", DueDate: &nextWeek}, + } + + if err := store.SaveTasks(tasks); err != nil { + t.Fatalf("Failed to save tasks: %v", err) + } + + // Test range covering today and tomorrow + start := now.Add(-1 * time.Hour) + end := tomorrow.Add(1 * time.Hour) + + results, err := store.GetTasksByDateRange(start, end) + if err != nil { + t.Fatalf("GetTasksByDateRange failed: %v", err) + } + + if len(results) != 2 { + t.Errorf("Expected 2 tasks, got %d", len(results)) + } +} + +func TestGetMealsByDateRange(t *testing.T) { + store := setupTestStoreWithMeals(t) + defer store.Close() + + now := time.Now() + tomorrow := now.Add(24 * time.Hour) + + meals := []models.Meal{ + {ID: "1", RecipeName: "Meal 1", Date: now, MealType: "lunch"}, + {ID: "2", RecipeName: "Meal 2", Date: tomorrow, MealType: "dinner"}, + } + + if err := store.SaveMeals(meals); err != nil { + t.Fatalf("Failed to save meals: %v", err) + } + + start := now.Add(-1 * time.Hour) + end := now.Add(1 * time.Hour) + + results, err := store.GetMealsByDateRange(start, end) + if err != nil { + t.Fatalf("GetMealsByDateRange failed: %v", err) + } + + if len(results) != 1 { + t.Errorf("Expected 1 meal, got %d", len(results)) + } + if results[0].ID != "1" { + t.Errorf("Expected meal 1, got %s", results[0].ID) + } +} + +func TestGetCardsByDateRange(t *testing.T) { + store := setupTestStoreWithCards(t) + defer store.Close() + + now := time.Now() + tomorrow := now.Add(24 * time.Hour) + + // Create board + _, err := store.db.Exec(`INSERT INTO boards (id, name) VALUES (?, ?)`, "board1", "Test Board") + if err != nil { + t.Fatalf("Failed to create board: %v", err) + } + + // Create cards + _, err = store.db.Exec(` + INSERT INTO cards (id, name, board_id, due_date) + VALUES + (?, ?, ?, ?), + (?, ?, ?, ?) + `, + "card1", "Card 1", "board1", now, + "card2", "Card 2", "board1", tomorrow) + if err != nil { + t.Fatalf("Failed to insert cards: %v", err) + } + + start := now.Add(-1 * time.Hour) + end := now.Add(1 * time.Hour) + + results, err := store.GetCardsByDateRange(start, end) + if err != nil { + t.Fatalf("GetCardsByDateRange failed: %v", err) + } + + if len(results) != 1 { + t.Errorf("Expected 1 card, got %d", len(results)) + } + if results[0].ID != "card1" { + t.Errorf("Expected card1, got %s", results[0].ID) + } +} |
