zeebe_rs/process_instance/
modify.rs

1use crate::{Client, ClientError, proto};
2use serde::Serialize;
3
4#[derive(Debug, Clone)]
5pub struct Initial;
6
7#[derive(Debug, Clone)]
8pub struct WithProcessInstance;
9
10pub trait ModifyProcessInstanceState {}
11impl ModifyProcessInstanceState for Initial {}
12impl ModifyProcessInstanceState for WithProcessInstance {}
13
14/// Instruction to terminate a specific element instance
15#[derive(Debug, Clone)]
16pub struct TerminateInstruction {
17    element_instance_key: i64,
18}
19
20/// Instruction to set variables in a specific scope
21#[derive(Debug, Clone)]
22pub struct VariableInstruction {
23    variables: serde_json::Value,
24    scope_id: String,
25}
26
27/// Instruction to activate a specific element
28#[derive(Debug, Clone)]
29pub struct ActivateInstruction {
30    element_id: String,
31    ancestor_element_instance_key: i64,
32    variable_instructions: Vec<VariableInstruction>,
33}
34
35/// Builder for constructing element activation instructions
36#[derive(Debug, Clone)]
37pub struct ActivateInstructionBuilder {
38    source_request: ModifyProcessInstanceRequest<WithProcessInstance>,
39    element_id: String,
40    ancestor_element_instance_key: i64,
41    variable_instructions: Vec<VariableInstruction>,
42}
43
44impl ActivateInstructionBuilder {
45    fn new(
46        source_request: ModifyProcessInstanceRequest<WithProcessInstance>,
47        element_id: String,
48        ancestor_element_instance_key: i64,
49    ) -> Self {
50        ActivateInstructionBuilder {
51            source_request,
52            element_id,
53            ancestor_element_instance_key,
54            variable_instructions: vec![],
55        }
56    }
57
58    /// Adds a variable instruction to the activation
59    ///
60    /// # Arguments
61    /// * `scope_id` - ID of the element scope for the variables
62    /// * `data` - Variables to set in the scope
63    ///
64    /// # Errors
65    /// Returns `ClientError` if serialization of `data` fails
66    pub fn with_variable_instruction<T: Serialize>(
67        mut self,
68        scope_id: String,
69        data: T,
70    ) -> Result<Self, ClientError> {
71        self.variable_instructions.push(VariableInstruction {
72            scope_id,
73            variables: serde_json::to_value(data)?,
74        });
75        Ok(self)
76    }
77
78    /// Builds the activation instruction and adds it to the request
79    pub fn build(mut self) -> ModifyProcessInstanceRequest<WithProcessInstance> {
80        self.source_request
81            .activate_instructions
82            .push(ActivateInstruction {
83                element_id: self.element_id,
84                ancestor_element_instance_key: self.ancestor_element_instance_key,
85                variable_instructions: self.variable_instructions,
86            });
87        self.source_request
88    }
89}
90
91/// Request to modify a process instance by activating/terminating elements
92///
93/// This struct represents a request to modify a process instance in the Zeebe workflow engine.
94/// It allows for building and sending instructions to activate specific elements or terminate
95/// specific element instances within a process instance.
96///
97/// The request goes through different states during its construction:
98/// - `Initial`: The initial state where the process instance key is not yet set.
99/// - `WithProcessInstance`: The state where the process instance key is set, and instructions can be added.
100///
101/// # Example
102///
103/// ```ignore
104/// client
105///     .modify_process_instance()
106///     .with_process_instance_key(12345)
107///         .with_activate_instruction("element_id".to_string(), 67890)
108///         .with_variable_instruction("scope_id".to_string(), serde_json::json!({"key": "value"}))?
109///         .build()
110///     .with_terminate_instruction(54321)
111///     .with_operation_reference(98765)
112///     .send()
113///     .await?;
114/// ```
115#[derive(Debug, Clone)]
116pub struct ModifyProcessInstanceRequest<T: ModifyProcessInstanceState> {
117    client: Client,
118    process_instance_key: i64,
119    activate_instructions: Vec<ActivateInstruction>,
120    terminate_instructions: Vec<TerminateInstruction>,
121    operation_reference: Option<u64>,
122    _state: std::marker::PhantomData<T>,
123}
124
125impl<T: ModifyProcessInstanceState> ModifyProcessInstanceRequest<T> {
126    pub(crate) fn new(client: Client) -> ModifyProcessInstanceRequest<Initial> {
127        ModifyProcessInstanceRequest {
128            client,
129            process_instance_key: 0,
130            activate_instructions: vec![],
131            terminate_instructions: vec![],
132            operation_reference: None,
133            _state: std::marker::PhantomData,
134        }
135    }
136
137    fn transition<NewState: ModifyProcessInstanceState>(
138        self,
139    ) -> ModifyProcessInstanceRequest<NewState> {
140        ModifyProcessInstanceRequest {
141            client: self.client,
142            process_instance_key: self.process_instance_key,
143            activate_instructions: self.activate_instructions,
144            terminate_instructions: self.terminate_instructions,
145            operation_reference: self.operation_reference,
146            _state: std::marker::PhantomData,
147        }
148    }
149}
150
151impl ModifyProcessInstanceRequest<Initial> {
152    /// Sets the process instance key identifying which instance to modify
153    ///
154    /// # Arguments
155    ///
156    /// * `process_instance_key` - The key of the process instance to modify
157    ///
158    /// # Returns
159    ///
160    /// A `ModifyProcessInstanceRequest<WithProcessInstance>` with the process instance key set
161    pub fn with_process_instance_key(
162        mut self,
163        process_instance_key: i64,
164    ) -> ModifyProcessInstanceRequest<WithProcessInstance> {
165        self.process_instance_key = process_instance_key;
166        self.transition()
167    }
168}
169
170impl ModifyProcessInstanceRequest<WithProcessInstance> {
171    /// Starts building an instruction to activate a specific element
172    ///
173    /// # Arguments
174    /// * `element_id` - ID of the element to activate
175    /// * `ancestor_element_instance_key` - Key of the ancestor scope
176    ///
177    /// # Returns
178    /// An `ActivateInstructionBuilder` instance to further build the instruction.
179    pub fn with_activate_instruction(
180        self,
181        element_id: String,
182        ancestor_element_instance_key: i64,
183    ) -> ActivateInstructionBuilder {
184        ActivateInstructionBuilder::new(self, element_id, ancestor_element_instance_key)
185    }
186
187    /// Adds an instruction to terminate a specific element instance
188    ///
189    /// # Arguments
190    /// * `element_instance_key` - Key of the element instance to terminate
191    ///
192    /// # Returns
193    /// The modified `ModifyProcessInstanceRequest` instance.
194    pub fn with_terminate_instruction(mut self, element_instance_key: i64) -> Self {
195        self.terminate_instructions.push(TerminateInstruction {
196            element_instance_key,
197        });
198        self
199    }
200
201    /// Adds instructions to terminate multiple element instances
202    ///
203    /// # Arguments
204    /// * `element_instance_keys` - Keys of element instances to terminate
205    ///
206    /// # Returns
207    /// The modified `ModifyProcessInstanceRequest` instance.
208    pub fn with_terminate_instructions(mut self, element_instance_keys: Vec<i64>) -> Self {
209        self.terminate_instructions
210            .extend(
211                element_instance_keys
212                    .into_iter()
213                    .map(|element_instance_key| TerminateInstruction {
214                        element_instance_key,
215                    }),
216            );
217        self
218    }
219
220    /// Sends the process instance modification request to the Zeebe workflow engine
221    ///
222    /// # Errors
223    /// - NOT_FOUND: No process instance exists with the given key
224    /// - INVALID_ARGUMENT: Invalid instructions or variables provided
225    ///
226    /// # Returns
227    /// A `Result` containing `ModifyProcessInstanceResponse` on success or `ClientError` on failure.
228    pub async fn send(mut self) -> Result<ModifyProcessInstanceResponse, ClientError> {
229        let res = self
230            .client
231            .gateway_client
232            .modify_process_instance(proto::ModifyProcessInstanceRequest {
233                process_instance_key: self.process_instance_key,
234                activate_instructions: self
235                    .activate_instructions
236                    .into_iter()
237                    .map(
238                        |a| proto::modify_process_instance_request::ActivateInstruction {
239                            element_id: a.element_id,
240                            ancestor_element_instance_key: a.ancestor_element_instance_key,
241                            variable_instructions: a
242                                .variable_instructions
243                                .into_iter()
244                                .map(|i| {
245                                    proto::modify_process_instance_request::VariableInstruction {
246                                        variables: i.variables.to_string(),
247                                        scope_id: i.scope_id,
248                                    }
249                                })
250                                .collect(),
251                        },
252                    )
253                    .collect(),
254                terminate_instructions: self
255                    .terminate_instructions
256                    .into_iter()
257                    .map(
258                        |t| proto::modify_process_instance_request::TerminateInstruction {
259                            element_instance_key: t.element_instance_key,
260                        },
261                    )
262                    .collect(),
263                operation_reference: self.operation_reference,
264            })
265            .await?;
266
267        Ok(res.into_inner().into())
268    }
269
270    /// Sets a reference key for tracking this operation
271    ///
272    /// # Arguments
273    /// * `operation_reference` - The reference key for tracking
274    ///
275    /// # Returns
276    /// The modified `ModifyProcessInstanceRequest` instance.
277    pub fn with_operation_reference(mut self, operation_reference: u64) -> Self {
278        self.operation_reference = Some(operation_reference);
279        self
280    }
281}
282
283/// Response from modifying a process instance
284#[derive(Debug, Clone)]
285pub struct ModifyProcessInstanceResponse {}
286
287impl From<proto::ModifyProcessInstanceResponse> for ModifyProcessInstanceResponse {
288    fn from(_value: proto::ModifyProcessInstanceResponse) -> ModifyProcessInstanceResponse {
289        ModifyProcessInstanceResponse {}
290    }
291}