diff options
Diffstat (limited to 'makima/src/db/repository.rs')
| -rw-r--r-- | makima/src/db/repository.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/makima/src/db/repository.rs b/makima/src/db/repository.rs index 95460f7..127f4cd 100644 --- a/makima/src/db/repository.rs +++ b/makima/src/db/repository.rs @@ -5105,6 +5105,68 @@ pub async fn delete_directive_for_owner( Ok(result.rows_affected() > 0) } +/// Clean up terminal tasks associated with a directive. +/// +/// Deletes tasks in terminal states (completed, failed, merged, done, interrupted) +/// that belong to this directive, excluding tasks currently referenced by +/// `completion_task_id` or `orchestrator_task_id` on the directive. +/// NULLs out `task_id` on directive_steps for deleted tasks. +pub async fn cleanup_directive_tasks( + pool: &PgPool, + owner_id: Uuid, + directive_id: Uuid, +) -> Result<i64, sqlx::Error> { + // NULL out task_id on steps that reference terminal tasks we're about to delete + sqlx::query( + r#" + UPDATE directive_steps + SET task_id = NULL + WHERE directive_id = $1 + AND task_id IS NOT NULL + AND task_id IN ( + SELECT t.id FROM tasks t + WHERE t.directive_id = $1 + AND t.owner_id = $2 + AND t.status IN ('completed', 'failed', 'merged', 'done', 'interrupted') + AND t.id NOT IN ( + SELECT COALESCE(d.completion_task_id, '00000000-0000-0000-0000-000000000000') + FROM directives d WHERE d.id = $1 + UNION + SELECT COALESCE(d.orchestrator_task_id, '00000000-0000-0000-0000-000000000000') + FROM directives d WHERE d.id = $1 + ) + ) + "#, + ) + .bind(directive_id) + .bind(owner_id) + .execute(pool) + .await?; + + // Delete terminal tasks not currently referenced by the directive + let result = sqlx::query( + r#" + DELETE FROM tasks + WHERE directive_id = $1 + AND owner_id = $2 + AND status IN ('completed', 'failed', 'merged', 'done', 'interrupted') + AND id NOT IN ( + SELECT COALESCE(d.completion_task_id, '00000000-0000-0000-0000-000000000000') + FROM directives d WHERE d.id = $1 + UNION + SELECT COALESCE(d.orchestrator_task_id, '00000000-0000-0000-0000-000000000000') + FROM directives d WHERE d.id = $1 + ) + "#, + ) + .bind(directive_id) + .bind(owner_id) + .execute(pool) + .await?; + + Ok(result.rows_affected() as i64) +} + // ============================================================================= // Directive Completion Helpers // ============================================================================= @@ -5499,6 +5561,7 @@ pub struct StepForDispatch { pub task_plan: Option<String>, pub order_index: i32, pub generation: i32, + pub depends_on: Vec<Uuid>, // Directive fields pub owner_id: Uuid, pub directive_title: String, @@ -5521,6 +5584,7 @@ pub async fn get_ready_steps_for_dispatch( ds.task_plan, ds.order_index, ds.generation, + ds.depends_on, d.owner_id, d.title AS directive_title, d.repository_url, @@ -5538,6 +5602,45 @@ pub async fn get_ready_steps_for_dispatch( .await } +/// Task info for a dependency step (step → linked task). +#[derive(Debug, Clone, sqlx::FromRow)] +pub struct DependencyTaskInfo { + pub step_id: Uuid, + pub task_id: Uuid, + pub task_name: String, +} + +/// Resolve dependency step UUIDs to their linked task IDs and names. +/// Returns results in the same order as the input `depends_on` slice. +pub async fn get_step_dependency_tasks( + pool: &PgPool, + depends_on: &[Uuid], +) -> Result<Vec<DependencyTaskInfo>, sqlx::Error> { + if depends_on.is_empty() { + return Ok(vec![]); + } + let rows = sqlx::query_as::<_, DependencyTaskInfo>( + r#" + SELECT ds.id AS step_id, t.id AS task_id, t.name AS task_name + FROM directive_steps ds + JOIN tasks t ON t.id = ds.task_id + WHERE ds.id = ANY($1) + "#, + ) + .bind(depends_on) + .fetch_all(pool) + .await?; + + // Re-order to match input ordering + let mut ordered = Vec::with_capacity(depends_on.len()); + for dep_id in depends_on { + if let Some(row) = rows.iter().find(|r| r.step_id == *dep_id) { + ordered.push(row.clone()); + } + } + Ok(ordered) +} + /// A running step joined with its task's current status. #[derive(Debug, Clone, sqlx::FromRow)] pub struct RunningStepWithTask { |
