summaryrefslogtreecommitdiff
path: root/internal/store
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-15 09:41:03 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-16 02:50:42 +0000
commit7d59a3020c9a98bb8af7240f584ac4c7813a46f6 (patch)
treeb73648ff848593e4e1ddd017e50471478bee9966 /internal/store
parentce1aa62b4b5a3a9af9933e73e416d7ae80142660 (diff)
refactor(store): extract meal methods from sqlite.go into meals.go
Pure move: SaveMeals/GetMeals/GetMealsByDateRange and their test (plus its setupTestStoreWithMeals helper, used only by that test) out of the 1400+ line sqlite.go into their own file. No behavior change. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VTUSAEKfsPc6WGDq45yPHD
Diffstat (limited to 'internal/store')
-rw-r--r--internal/store/meals.go82
-rw-r--r--internal/store/meals_test.go76
-rw-r--r--internal/store/sqlite.go76
-rw-r--r--internal/store/sqlite_test.go65
4 files changed, 158 insertions, 141 deletions
diff --git a/internal/store/meals.go b/internal/store/meals.go
new file mode 100644
index 0000000..5f4024b
--- /dev/null
+++ b/internal/store/meals.go
@@ -0,0 +1,82 @@
+package store
+
+import (
+ "time"
+
+ "task-dashboard/internal/models"
+)
+
+func (s *Store) SaveMeals(meals []models.Meal) error {
+ tx, err := s.db.Begin()
+ if err != nil {
+ return err
+ }
+ defer func() { _ = tx.Rollback() }()
+
+ stmt, err := tx.Prepare(`
+ INSERT OR REPLACE INTO meals
+ (id, recipe_name, date, meal_type, recipe_url, updated_at)
+ VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
+ `)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = stmt.Close() }()
+
+ for _, meal := range meals {
+ _, err := stmt.Exec(
+ meal.ID,
+ meal.RecipeName,
+ meal.Date,
+ meal.MealType,
+ meal.RecipeURL,
+ )
+ if err != nil {
+ return err
+ }
+ }
+
+ return tx.Commit()
+}
+
+// GetMeals retrieves meals from the database
+func (s *Store) GetMeals(startDate, endDate time.Time) ([]models.Meal, error) {
+ rows, err := s.db.Query(`
+ SELECT id, recipe_name, date, meal_type, recipe_url
+ FROM meals
+ WHERE date BETWEEN ? AND ?
+ ORDER BY date ASC,
+ CASE meal_type
+ WHEN 'breakfast' THEN 1
+ WHEN 'lunch' THEN 2
+ WHEN 'dinner' THEN 3
+ ELSE 4
+ END
+ `, startDate, endDate)
+ if err != nil {
+ return nil, err
+ }
+ defer func() { _ = rows.Close() }()
+
+ var meals []models.Meal
+ for rows.Next() {
+ var meal models.Meal
+ err := rows.Scan(
+ &meal.ID,
+ &meal.RecipeName,
+ &meal.Date,
+ &meal.MealType,
+ &meal.RecipeURL,
+ )
+ if err != nil {
+ return nil, err
+ }
+ meals = append(meals, meal)
+ }
+
+ return meals, rows.Err()
+}
+
+func (s *Store) GetMealsByDateRange(start, end time.Time) ([]models.Meal, error) {
+ return s.GetMeals(start, end)
+}
diff --git a/internal/store/meals_test.go b/internal/store/meals_test.go
new file mode 100644
index 0000000..b72796e
--- /dev/null
+++ b/internal/store/meals_test.go
@@ -0,0 +1,76 @@
+package store
+
+import (
+ "database/sql"
+ "path/filepath"
+ "testing"
+ "time"
+
+ _ "github.com/mattn/go-sqlite3"
+ "task-dashboard/internal/models"
+)
+
+// 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
+}
+
+func TestGetMealsByDateRange(t *testing.T) {
+ store := setupTestStoreWithMeals(t)
+ defer func() { _ = 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)
+ }
+}
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go
index ad88166..e8c9eac 100644
--- a/internal/store/sqlite.go
+++ b/internal/store/sqlite.go
@@ -140,77 +140,6 @@ func (s *Store) runMigrations() error {
// Meals operations
// SaveMeals saves multiple meals to the database
-func (s *Store) SaveMeals(meals []models.Meal) error {
- tx, err := s.db.Begin()
- if err != nil {
- return err
- }
- defer func() { _ = tx.Rollback() }()
-
- stmt, err := tx.Prepare(`
- INSERT OR REPLACE INTO meals
- (id, recipe_name, date, meal_type, recipe_url, updated_at)
- VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
- `)
- if err != nil {
- return err
- }
- defer func() { _ = stmt.Close() }()
-
- for _, meal := range meals {
- _, err := stmt.Exec(
- meal.ID,
- meal.RecipeName,
- meal.Date,
- meal.MealType,
- meal.RecipeURL,
- )
- if err != nil {
- return err
- }
- }
-
- return tx.Commit()
-}
-
-// GetMeals retrieves meals from the database
-func (s *Store) GetMeals(startDate, endDate time.Time) ([]models.Meal, error) {
- rows, err := s.db.Query(`
- SELECT id, recipe_name, date, meal_type, recipe_url
- FROM meals
- WHERE date BETWEEN ? AND ?
- ORDER BY date ASC,
- CASE meal_type
- WHEN 'breakfast' THEN 1
- WHEN 'lunch' THEN 2
- WHEN 'dinner' THEN 3
- ELSE 4
- END
- `, startDate, endDate)
- if err != nil {
- return nil, err
- }
- defer func() { _ = rows.Close() }()
-
- var meals []models.Meal
- for rows.Next() {
- var meal models.Meal
- err := rows.Scan(
- &meal.ID,
- &meal.RecipeName,
- &meal.Date,
- &meal.MealType,
- &meal.RecipeURL,
- )
- if err != nil {
- return nil, err
- }
- meals = append(meals, meal)
- }
-
- return meals, rows.Err()
-}
-
// Cache metadata operations
// GetCacheMetadata retrieves cache metadata for a key
@@ -536,11 +465,6 @@ func (s *Store) GetShoppingItemChecks(source string) (map[string]bool, error) {
return checks, 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,
// including overdue cards (due before start) so they appear in the timeline.
func (s *Store) GetCardsByDateRange(start, end time.Time) ([]models.Card, error) {
diff --git a/internal/store/sqlite_test.go b/internal/store/sqlite_test.go
index e8af436..55e1510 100644
--- a/internal/store/sqlite_test.go
+++ b/internal/store/sqlite_test.go
@@ -340,39 +340,6 @@ func TestGetGoogleTasksByDateRange_IncludesOverdue(t *testing.T) {
}
}
-// 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
-}
-
// TestDeleteCard verifies that DeleteCard removes a card from the cache
func TestDeleteCard(t *testing.T) {
store := setupTestStoreWithCards(t)
@@ -615,38 +582,6 @@ func TestSaveAndGetBoards_ManyBoards(t *testing.T) {
}
}
-func TestGetMealsByDateRange(t *testing.T) {
- store := setupTestStoreWithMeals(t)
- defer func() { _ = 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 func() { _ = store.Close() }()