zeebe_rs/
decision.rs

1use crate::{Client, ClientError, proto};
2use serde::{Serialize, de::DeserializeOwned};
3
4pub struct Initial;
5pub struct WithKey;
6pub struct WithId;
7pub trait EvaluateDecisionRequestState {}
8impl EvaluateDecisionRequestState for Initial {}
9impl EvaluateDecisionRequestState for WithKey {}
10impl EvaluateDecisionRequestState for WithId {}
11
12/// Request to evaluate a DMN decision
13///
14/// The decision to evaluate can be specified either by using its unique key
15/// (as returned by DeployResource), or using the decision ID. When using the
16/// decision ID, the latest deployed version of the decision is used.
17///
18/// # Examples
19/// ```ignore
20/// client
21///     .evaluate_decision()
22///     .with_decision_key(123456)
23///     .with_decision_id(String::from("decision_id"))
24///     .send()
25///     .await?;
26/// ```
27#[derive(Debug, Clone)]
28pub struct EvaluateDecisionRequest<T: EvaluateDecisionRequestState> {
29    client: Client,
30    decision_key: i64,
31    decision_id: String,
32    variables: serde_json::Value,
33    tenant_id: String,
34    _state: std::marker::PhantomData<T>,
35}
36
37impl<T: EvaluateDecisionRequestState> EvaluateDecisionRequest<T> {
38    pub(crate) fn new(client: Client) -> EvaluateDecisionRequest<Initial> {
39        EvaluateDecisionRequest {
40            client,
41            decision_key: 0,
42            decision_id: String::new(),
43            variables: serde_json::Value::default(),
44            tenant_id: String::new(),
45            _state: std::marker::PhantomData,
46        }
47    }
48
49    fn transition<NewState: EvaluateDecisionRequestState>(
50        self,
51    ) -> EvaluateDecisionRequest<NewState> {
52        EvaluateDecisionRequest {
53            client: self.client,
54            decision_key: self.decision_key,
55            decision_id: self.decision_id,
56            variables: self.variables,
57            tenant_id: self.tenant_id,
58            _state: std::marker::PhantomData,
59        }
60    }
61}
62
63impl EvaluateDecisionRequest<Initial> {
64    /// Sets the unique key of the decision to evaluate
65    ///
66    /// # Arguments
67    /// * `decision_key` - The unique key identifying the decision (as returned by DeployResource)
68    ///
69    /// # Returns
70    /// The updated `EvaluateDecisionRequest` in the `WithKey` state.
71    pub fn with_decision_key(mut self, decision_key: i64) -> EvaluateDecisionRequest<WithKey> {
72        self.decision_key = decision_key;
73        self.transition()
74    }
75}
76
77impl EvaluateDecisionRequest<WithKey> {
78    /// Sets the ID of the decision to evaluate
79    ///
80    /// # Arguments
81    /// * `decision_id` - The ID of the decision to evaluate
82    ///
83    /// # Returns
84    /// The updated `EvaluateDecisionRequest` in the `WithId` state.
85    pub fn with_decision_id(mut self, decision_id: String) -> EvaluateDecisionRequest<WithId> {
86        self.decision_id = decision_id;
87        self.transition()
88    }
89}
90
91impl EvaluateDecisionRequest<WithId> {
92    /// Sets the variables used for decision evaluation
93    ///
94    /// The variables must be a JSON object, as variables will be mapped in a key-value fashion.
95    /// For example: `{ "a": 1, "b": 2 }` will create two variables named "a" and "b".
96    ///
97    /// # Arguments
98    /// * `data` - The variables to be used for decision evaluation
99    ///
100    /// # Returns
101    /// The updated `EvaluateDecisionRequest` with the variables set.
102    ///
103    /// # Errors
104    /// Returns a `ClientError` if the variables cannot be serialized to JSON.
105    pub fn with_variables<T: Serialize>(mut self, data: T) -> Result<Self, ClientError> {
106        self.variables = serde_json::to_value(data)
107            .map_err(|e| ClientError::SerializationFailed { source: e })?;
108        Ok(self)
109    }
110
111    /// Sends the decision evaluation request
112    ///
113    /// # Type Parameters
114    /// * `T` - The type of the decision output
115    ///
116    /// # Returns
117    /// A `Result` containing the `EvaluateDecisionResponse` or a `ClientError`.
118    pub async fn send<T: DeserializeOwned>(
119        mut self,
120    ) -> Result<EvaluateDecisionResponse<T>, ClientError> {
121        let res = self
122            .client
123            .gateway_client
124            .evaluate_decision(proto::EvaluateDecisionRequest {
125                decision_key: self.decision_key,
126                decision_id: self.decision_id,
127                variables: self.variables.to_string(),
128                tenant_id: self.tenant_id,
129            })
130            .await?;
131
132        res.into_inner().try_into()
133    }
134
135    /// Sets the tenant ID for the decision evaluation
136    ///
137    /// # Arguments
138    /// * `tenant_id` - The ID of the tenant that owns the decision
139    ///
140    /// # Returns
141    /// The updated `EvaluateDecisionRequest` with the tenant ID set.
142    pub fn with_tenant_id(mut self, tenant_id: String) -> Self {
143        self.tenant_id = tenant_id;
144        self
145    }
146}
147
148/// Represents an evaluated input in a decision
149#[derive(Debug, Clone)]
150pub struct EvaluatedDecisionInput {
151    input_id: String,
152    input_name: String,
153    input_value: String,
154}
155
156impl From<proto::EvaluatedDecisionInput> for EvaluatedDecisionInput {
157    fn from(value: proto::EvaluatedDecisionInput) -> EvaluatedDecisionInput {
158        EvaluatedDecisionInput {
159            input_id: value.input_id,
160            input_name: value.input_name,
161            input_value: value.input_value,
162        }
163    }
164}
165
166impl EvaluatedDecisionInput {
167    /// Returns the unique identifier of the evaluated input.
168    ///
169    /// # Returns
170    /// A string slice that holds the unique identifier of the evaluated input.
171    pub fn input_id(&self) -> &str {
172        &self.input_id
173    }
174
175    /// Returns the name/label of the evaluated input.
176    ///
177    /// # Returns
178    /// A string slice that holds the name/label of the evaluated input.
179    pub fn input_name(&self) -> &str {
180        &self.input_name
181    }
182
183    /// Returns the value of the input that was used during decision evaluation.
184    ///
185    /// # Returns
186    /// A string slice that holds the value of the input used during decision evaluation.
187    pub fn input_value(&self) -> &str {
188        &self.input_value
189    }
190}
191
192/// Represents an evaluated output in a decision
193#[derive(Debug, Clone)]
194pub struct EvaluatedDecisionOutput {
195    output_id: String,
196    output_name: String,
197    output_value: String,
198}
199
200impl From<proto::EvaluatedDecisionOutput> for EvaluatedDecisionOutput {
201    fn from(value: proto::EvaluatedDecisionOutput) -> EvaluatedDecisionOutput {
202        EvaluatedDecisionOutput {
203            output_id: value.output_id,
204            output_name: value.output_name,
205            output_value: value.output_value,
206        }
207    }
208}
209
210impl EvaluatedDecisionOutput {
211    /// Returns the unique identifier of the evaluated output
212    ///
213    /// # Returns
214    /// A string slice that holds the unique identifier of the evaluated output.
215    pub fn output_id(&self) -> &str {
216        &self.output_id
217    }
218
219    /// Returns the name/label of the evaluated output
220    ///
221    /// # Returns
222    /// A string slice that holds the name/label of the evaluated output.
223    pub fn output_name(&self) -> &str {
224        &self.output_name
225    }
226
227    /// Returns the value of the output that was used during decision evaluation
228    ///
229    /// # Returns
230    /// A string slice that holds the value of the output used during decision evaluation.
231    pub fn output_value(&self) -> &str {
232        &self.output_value
233    }
234}
235
236/// Represents a matched rule in a decision
237#[derive(Debug, Clone)]
238pub struct MatchedDecisionRule {
239    rule_id: String,
240    rule_index: i32,
241    evaluated_outputs: Vec<EvaluatedDecisionOutput>,
242}
243
244impl From<proto::MatchedDecisionRule> for MatchedDecisionRule {
245    fn from(value: proto::MatchedDecisionRule) -> MatchedDecisionRule {
246        MatchedDecisionRule {
247            rule_id: value.rule_id,
248            rule_index: value.rule_index,
249            evaluated_outputs: value
250                .evaluated_outputs
251                .into_iter()
252                .map(|e| e.into())
253                .collect(),
254        }
255    }
256}
257
258impl MatchedDecisionRule {
259    /// Returns the unique identifier of the matched rule.
260    ///
261    /// # Returns
262    /// A string slice that holds the unique identifier of the matched rule.
263    pub fn rule_id(&self) -> &str {
264        &self.rule_id
265    }
266
267    /// Returns the index position of the matched rule within the decision table.
268    ///
269    /// # Returns
270    /// An integer representing the index position of the matched rule.
271    pub fn rule_index(&self) -> i32 {
272        self.rule_index
273    }
274
275    /// Returns a slice containing all evaluated outputs for this matched rule.
276    ///
277    /// # Returns
278    /// A slice of `EvaluatedDecisionOutput` containing all evaluated outputs for this matched rule.
279    pub fn evaluated_outputs(&self) -> &[EvaluatedDecisionOutput] {
280        &self.evaluated_outputs
281    }
282}
283
284/// Represents an evaluated decision
285#[derive(Debug, Clone)]
286pub struct EvaluatedDecision {
287    decision_key: i64,
288    decision_id: String,
289    decision_name: String,
290    decision_version: i32,
291    decision_type: String,
292    decision_output: String,
293    matched_rules: Vec<MatchedDecisionRule>,
294    evaluated_inputs: Vec<EvaluatedDecisionInput>,
295    tenant_id: String,
296}
297
298impl From<proto::EvaluatedDecision> for EvaluatedDecision {
299    fn from(value: proto::EvaluatedDecision) -> EvaluatedDecision {
300        EvaluatedDecision {
301            decision_key: value.decision_key,
302            decision_id: value.decision_id,
303            decision_name: value.decision_name,
304            decision_version: value.decision_version,
305            decision_type: value.decision_type,
306            decision_output: value.decision_output,
307            matched_rules: value.matched_rules.into_iter().map(|m| m.into()).collect(),
308            evaluated_inputs: value
309                .evaluated_inputs
310                .into_iter()
311                .map(|e| e.into())
312                .collect(),
313            tenant_id: value.tenant_id,
314        }
315    }
316}
317
318impl EvaluatedDecision {
319    /// Returns the unique key identifying the evaluated decision
320    ///
321    /// # Returns
322    ///
323    /// An `i64` representing the unique key of the evaluated decision
324    pub fn decision_key(&self) -> i64 {
325        self.decision_key
326    }
327
328    /// Returns the ID of the decision which was evaluated
329    ///
330    /// # Returns
331    ///
332    /// A string slice (`&str`) representing the ID of the evaluated decision
333    pub fn decision_id(&self) -> &str {
334        &self.decision_id
335    }
336
337    /// Returns the name of the decision which was evaluated
338    ///
339    /// # Returns
340    ///
341    /// A string slice (`&str`) representing the name of the evaluated decision
342    pub fn decision_name(&self) -> &str {
343        &self.decision_name
344    }
345
346    /// Returns the version of the decision which was evaluated
347    ///
348    /// # Returns
349    ///
350    /// An `i32` representing the version of the evaluated decision
351    pub fn decision_version(&self) -> i32 {
352        self.decision_version
353    }
354
355    /// Returns the type of the decision which was evaluated
356    ///
357    /// # Returns
358    ///
359    /// A string slice (`&str`) representing the type of the evaluated decision
360    pub fn decision_type(&self) -> &str {
361        &self.decision_type
362    }
363
364    /// Returns the JSON output of the evaluated decision
365    ///
366    /// The output is a JSON-formatted string representing the decision result
367    ///
368    /// # Returns
369    pub fn decision_output(&self) -> &str {
370        &self.decision_output
371    }
372
373    /// A string slice (`&str`) representing the JSON output of the evaluated decision
374    ///
375    /// Returns a slice containing all rules that matched during decision evaluation
376    ///
377    /// # Returns
378    ///
379    /// A slice (`&[MatchedDecisionRule]`) containing all matched rules
380    pub fn matched_rules(&self) -> &[MatchedDecisionRule] {
381        &self.matched_rules
382    }
383
384    /// Returns a slice containing all inputs that were evaluated as part of the decision
385    ///
386    /// # Returns
387    ///
388    /// A slice (`&[EvaluatedDecisionInput]`) containing all evaluated inputs
389    pub fn evaluated_inputs(&self) -> &[EvaluatedDecisionInput] {
390        &self.evaluated_inputs
391    }
392
393    /// Returns the tenant identifier of the evaluated decision
394    ///
395    /// # Returns
396    ///
397    /// A string slice (`&str`) representing the tenant identifier of the evaluated decision
398    pub fn tenant_id(&self) -> &str {
399        &self.tenant_id
400    }
401}
402
403/// The response from evaluating a decision
404#[derive(Debug, Clone)]
405pub struct EvaluateDecisionResponse<T: DeserializeOwned> {
406    decision_key: i64,
407    decision_id: String,
408    decision_name: String,
409    decision_version: i32,
410    decision_requirements_id: String,
411    decision_requirements_key: i64,
412    decision_output: T,
413    evaluated_decisions: Vec<EvaluatedDecision>,
414    failed_decision_id: String,
415    failure_message: String,
416    tenant_id: String,
417    decision_instance_key: i64,
418}
419
420impl<T: DeserializeOwned> TryFrom<proto::EvaluateDecisionResponse> for EvaluateDecisionResponse<T> {
421    type Error = ClientError;
422    fn try_from(
423        value: proto::EvaluateDecisionResponse,
424    ) -> Result<EvaluateDecisionResponse<T>, Self::Error> {
425        Ok(EvaluateDecisionResponse {
426            decision_key: value.decision_key,
427            decision_id: value.decision_id,
428            decision_name: value.decision_name,
429            decision_version: value.decision_version,
430            decision_requirements_id: value.decision_requirements_id,
431            decision_requirements_key: value.decision_requirements_key,
432            decision_output: serde_json::from_str(&value.decision_output).map_err(|e| {
433                ClientError::DeserializationFailed {
434                    value: value.decision_output.clone(),
435                    source: e,
436                }
437            })?,
438            evaluated_decisions: value
439                .evaluated_decisions
440                .into_iter()
441                .map(|e| e.into())
442                .collect(),
443            failed_decision_id: value.failed_decision_id,
444            failure_message: value.failure_message,
445            tenant_id: value.tenant_id,
446            decision_instance_key: value.decision_instance_key,
447        })
448    }
449}
450
451/// Represents the response of evaluating a decision, parameterized by the type `T`.
452///
453/// This struct provides various methods to access details about the evaluated decision,
454/// including its key, ID, name, version, and output, as well as information about any
455/// failures that occurred during the evaluation.
456impl<T: DeserializeOwned> EvaluateDecisionResponse<T> {
457    /// Returns the unique key identifying the evaluated decision.
458    ///
459    /// # Returns
460    ///
461    /// An `i64` representing the unique key of the decision.
462    pub fn decision_key(&self) -> i64 {
463        self.decision_key
464    }
465
466    /// Returns the ID of the decision which was evaluated.
467    ///
468    /// # Returns
469    ///
470    /// A string slice representing the ID of the evaluated decision.
471    pub fn decision_id(&self) -> &str {
472        &self.decision_id
473    }
474
475    /// Returns the name of the decision which was evaluated.
476    ///
477    /// # Returns
478    ///
479    /// A string slice representing the name of the evaluated decision.
480    pub fn decision_name(&self) -> &str {
481        &self.decision_name
482    }
483
484    /// Returns the version of the decision which was evaluated.
485    ///
486    /// # Returns
487    ///
488    /// An `i32` representing the version of the evaluated decision.
489    pub fn decision_version(&self) -> i32 {
490        self.decision_version
491    }
492
493    /// Returns the ID of the decision requirements graph that the decision is part of.
494    ///
495    /// # Returns
496    ///
497    /// A string slice representing the ID of the decision requirements graph.
498    pub fn decision_requirements_id(&self) -> &str {
499        &self.decision_requirements_id
500    }
501
502    /// Returns the unique key identifying the decision requirements graph.
503    ///
504    /// # Returns
505    ///
506    /// An `i64` representing the unique key of the decision requirements graph.
507    pub fn decision_requirements_key(&self) -> i64 {
508        self.decision_requirements_key
509    }
510
511    /// Returns the output result of the decision evaluation.
512    ///
513    /// # Returns
514    ///
515    /// A reference to the output of the decision evaluation of type `T`.
516    pub fn decision_output(&self) -> &T {
517        &self.decision_output
518    }
519
520    /// Returns a list of all decisions that were evaluated within the requested decision evaluation.
521    ///
522    /// # Returns
523    ///
524    /// A slice of `EvaluatedDecision` representing all evaluated decisions.
525    pub fn evaluated_decisions(&self) -> &[EvaluatedDecision] {
526        &self.evaluated_decisions
527    }
528
529    /// Returns the ID of the decision which failed during evaluation, if any.
530    ///
531    /// # Returns
532    ///
533    /// A string slice representing the ID of the failed decision, if applicable.
534    pub fn failed_decision_id(&self) -> &str {
535        &self.failed_decision_id
536    }
537
538    /// Returns a message describing why the decision evaluation failed, if applicable.
539    ///
540    /// # Returns
541    ///
542    /// A string slice representing the failure message, if applicable.
543    pub fn failure_message(&self) -> &str {
544        &self.failure_message
545    }
546
547    /// Returns the tenant identifier of the evaluated decision.
548    ///
549    /// # Returns
550    ///
551    /// A string slice representing the tenant ID of the evaluated decision.
552    pub fn tenant_id(&self) -> &str {
553        &self.tenant_id
554    }
555
556    /// Returns the unique key identifying this decision evaluation.
557    ///
558    /// # Returns
559    ///
560    /// An `i64` representing the unique key of this decision evaluation.
561    pub fn decision_instance_key(&self) -> i64 {
562        self.decision_instance_key
563    }
564}