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.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'internal/store/native_tasks.go') diff --git a/internal/store/native_tasks.go b/internal/store/native_tasks.go index 90cf275..1f898aa 100644 --- a/internal/store/native_tasks.go +++ b/internal/store/native_tasks.go @@ -23,7 +23,7 @@ var ErrNativeTaskNotFound = errors.New("native task not found") // GetNativeTasks returns all non-completed native tasks. func (s *Store) GetNativeTasks() ([]models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks WHERE completed = 0 @@ -42,7 +42,7 @@ func (s *Store) GetNativeTasks() ([]models.Task, error) { // without double-counting against that separate fetch. func (s *Store) GetNativeTasksByDateRange(start, end time.Time) ([]models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks WHERE completed = 0 AND due_date IS NOT NULL AND due_date >= ? AND due_date < ? @@ -63,7 +63,7 @@ func (s *Store) GetNativeTasksByDateRange(start, end time.Time) ([]models.Task, // ComputeDaySection to be marked IsOverdue. func (s *Store) GetOverdueNativeTasks(before time.Time) ([]models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks WHERE completed = 0 AND due_date IS NOT NULL AND due_date < ? @@ -79,7 +79,7 @@ func (s *Store) GetOverdueNativeTasks(before time.Time) ([]models.Task, error) { // GetUndatedNativeTasks returns non-completed native tasks with no due date. func (s *Store) GetUndatedNativeTasks() ([]models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks WHERE completed = 0 AND due_date IS NULL @@ -95,7 +95,7 @@ func (s *Store) GetUndatedNativeTasks() ([]models.Task, error) { // GetNativeTaskByID returns a single native task by id, or ErrNativeTaskNotFound. func (s *Store) GetNativeTaskByID(id string) (*models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks WHERE id = ? @@ -118,9 +118,9 @@ func (s *Store) GetNativeTaskByID(id string) (*models.Task, error) { func (s *Store) CreateNativeTask(task models.Task) error { labelsJSON, _ := json.Marshal(task.Labels) _, err := s.db.Exec(` - INSERT INTO native_tasks (id, content, description, project_name, due_date, priority, labels, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) - `, task.ID, task.Content, task.Description, task.ProjectName, task.DueDate, task.Priority, string(labelsJSON)) + INSERT INTO native_tasks (id, content, description, project_name, project_id, due_date, priority, labels, created_at, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + `, task.ID, task.Content, task.Description, task.ProjectName, task.ProjectID, task.DueDate, task.Priority, string(labelsJSON)) return err } @@ -245,17 +245,17 @@ func (s *Store) CreateNextIteration(old models.Task) error { labelsJSON, _ := json.Marshal(old.Labels) _, err := s.db.Exec(` INSERT INTO native_tasks ( - id, content, description, project_name, due_date, priority, labels, + id, content, description, project_name, project_id, due_date, priority, labels, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override, created_at, updated_at ) - SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP + SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP WHERE NOT EXISTS ( SELECT 1 FROM native_tasks WHERE recurrence_series_id = ? AND (due_date > ? OR (due_date = ? AND created_at > ?)) ) - `, newTaskID(), old.Content, old.Description, old.ProjectName, nextDue, old.Priority, string(labelsJSON), + `, newTaskID(), old.Content, old.Description, old.ProjectName, old.ProjectID, nextDue, old.Priority, string(labelsJSON), old.RecurrenceFreq, old.RecurrenceInterval, formatWeekdays(old.RecurrenceWeekdays), old.RecurrenceSeriesID, old.RecurrenceSeriesID, old.DueDate, old.DueDate, old.CreatedAt) return err @@ -321,7 +321,7 @@ func (s *Store) SetNextOccurrenceOverride(id string, date time.Time) error { // ignored recurring task doesn't block its successor from appearing. func (s *Store) GetSeriesNeedingNextIteration(now time.Time) ([]models.Task, error) { rows, err := s.db.Query(` - SELECT id, content, description, project_name, due_date, priority, completed, labels, created_at, + SELECT id, content, description, project_name, project_id, due_date, priority, completed, labels, created_at, recurrence_freq, recurrence_interval, recurrence_weekdays, recurrence_series_id, next_occurrence_override FROM native_tasks t1 WHERE recurrence_series_id != '' @@ -384,7 +384,7 @@ func scanNativeTasks(rows interface { var weekdaysStr string var nextOverrideStr string if err := rows.Scan( - &t.ID, &t.Content, &t.Description, &t.ProjectName, &dueDateStr, &t.Priority, &t.Completed, &labelsJSON, &t.CreatedAt, + &t.ID, &t.Content, &t.Description, &t.ProjectName, &t.ProjectID, &dueDateStr, &t.Priority, &t.Completed, &labelsJSON, &t.CreatedAt, &t.RecurrenceFreq, &t.RecurrenceInterval, &weekdaysStr, &t.RecurrenceSeriesID, &nextOverrideStr, ); err != nil { return nil, err -- cgit v1.2.3