diff options
Diffstat (limited to 'internal/storage/db.go')
| -rw-r--r-- | internal/storage/db.go | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/internal/storage/db.go b/internal/storage/db.go index a16ad4e..d571c2e 100644 --- a/internal/storage/db.go +++ b/internal/storage/db.go @@ -287,6 +287,36 @@ func (s *DB) ListSubtasks(parentID string) ([]*task.Task, error) { return tasks, rows.Err() } +// ListDependents returns tasks that directly depend on taskID — i.e. those +// whose depends_on_json contains taskID. depends_on_json has no reverse +// index, so this is a full-table scan; the codebase already accepts this +// tradeoff for other JSON-blob columns at self-hosted scale (see the +// "Additive migration strategy is fragile" design-debt note in CLAUDE.md). +// Only direct dependents are returned — callers that need the full +// transitive downstream subtree (e.g. cascade-cancellation) must recurse. +func (s *DB) ListDependents(taskID string) ([]*task.Task, error) { + rows, err := s.db.Query(`SELECT id, name, description, elaboration_input, project, repository_url, config_json, priority, timeout_ns, retry_json, tags_json, depends_on_json, parent_task_id, state, created_at, updated_at, rejection_comment, question_json, summary, interactions_json FROM tasks`) + if err != nil { + return nil, err + } + defer rows.Close() + + var dependents []*task.Task + for rows.Next() { + t, err := scanTaskRows(rows) + if err != nil { + return nil, err + } + for _, depID := range t.DependsOn { + if depID == taskID { + dependents = append(dependents, t) + break + } + } + } + return dependents, rows.Err() +} + // UpdateTaskState atomically updates a task's state, enforcing valid // transitions. The transition is attributed to the system actor; callers // acting on behalf of a user should use UpdateTaskStateBy. |
