Skip to main content

ito_domain/tasks/
mutations.rs

1//! Task mutation port definitions.
2
3use std::io;
4use std::path::PathBuf;
5
6use thiserror::Error;
7
8use super::parse::TaskItem;
9
10/// Result alias for task mutation operations.
11pub type TaskMutationServiceResult<T> = Result<T, TaskMutationError>;
12
13/// Outcome of a task mutation.
14#[derive(Debug, Clone)]
15pub struct TaskMutationResult {
16    /// Change identifier the mutation applied to.
17    pub change_id: String,
18    /// Updated task item.
19    pub task: TaskItem,
20    /// Backend or store revision after the mutation, when applicable.
21    pub revision: Option<String>,
22}
23
24/// Outcome of initializing task tracking.
25#[derive(Debug, Clone)]
26pub struct TaskInitResult {
27    /// Change identifier the init applied to.
28    pub change_id: String,
29    /// Tracking path when filesystem-backed.
30    pub path: Option<PathBuf>,
31    /// Whether the tracking artifact already existed.
32    pub existed: bool,
33    /// Backend or store revision after the mutation, when applicable.
34    pub revision: Option<String>,
35}
36
37/// Error type for task mutation ports.
38#[derive(Debug, Error)]
39pub enum TaskMutationError {
40    /// Filesystem or transport failure.
41    #[error("I/O failure while {context}: {source}")]
42    Io {
43        /// Short operation context.
44        context: String,
45        /// Source error.
46        #[source]
47        source: io::Error,
48    },
49
50    /// Validation or precondition failure.
51    #[error("{0}")]
52    Validation(String),
53
54    /// Requested task artifact or item was not found.
55    #[error("{0}")]
56    NotFound(String),
57
58    /// Unexpected transport or backend failure.
59    #[error("{0}")]
60    Other(String),
61}
62
63impl TaskMutationError {
64    /// Build an I/O flavored error.
65    pub fn io(context: impl Into<String>, source: io::Error) -> Self {
66        Self::Io {
67            context: context.into(),
68            source,
69        }
70    }
71
72    /// Build a validation error.
73    pub fn validation(message: impl Into<String>) -> Self {
74        Self::Validation(message.into())
75    }
76
77    /// Build a not-found error.
78    pub fn not_found(message: impl Into<String>) -> Self {
79        Self::NotFound(message.into())
80    }
81
82    /// Build a catch-all error.
83    pub fn other(message: impl Into<String>) -> Self {
84        Self::Other(message.into())
85    }
86}
87
88/// Port for task mutations and raw markdown access.
89pub trait TaskMutationService: Send + Sync {
90    /// Load raw task tracking markdown, if available.
91    fn load_tasks_markdown(&self, change_id: &str) -> TaskMutationServiceResult<Option<String>>;
92    /// Initialize a tracking file or remote artifact for a change.
93    fn init_tasks(&self, change_id: &str) -> TaskMutationServiceResult<TaskInitResult>;
94    /// Mark a task as in-progress.
95    fn start_task(
96        &self,
97        change_id: &str,
98        task_id: &str,
99    ) -> TaskMutationServiceResult<TaskMutationResult>;
100    /// Mark a task as complete.
101    fn complete_task(
102        &self,
103        change_id: &str,
104        task_id: &str,
105        note: Option<String>,
106    ) -> TaskMutationServiceResult<TaskMutationResult>;
107    /// Shelve a task.
108    fn shelve_task(
109        &self,
110        change_id: &str,
111        task_id: &str,
112        reason: Option<String>,
113    ) -> TaskMutationServiceResult<TaskMutationResult>;
114    /// Unshelve a task.
115    fn unshelve_task(
116        &self,
117        change_id: &str,
118        task_id: &str,
119    ) -> TaskMutationServiceResult<TaskMutationResult>;
120    /// Add a new task.
121    fn add_task(
122        &self,
123        change_id: &str,
124        title: &str,
125        wave: Option<u32>,
126    ) -> TaskMutationServiceResult<TaskMutationResult>;
127}