Skip to main content

lemma/api/
response.rs

1//! Response / RuleResult JSON shapes.
2
3use crate::api::value::RuleResultValue;
4use crate::evaluation::explanations::Explanation;
5use crate::evaluation::response::{Response as DomainResponse, RuleResult as DomainRuleResult};
6use crate::parsing::ast::DateTimeValue;
7use indexmap::IndexMap;
8use serde::Serialize;
9
10#[derive(Debug, Clone, Serialize)]
11pub struct Response {
12    #[serde(rename = "spec")]
13    pub spec_name: String,
14    pub effective: String,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub spec_effective_from: Option<DateTimeValue>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub spec_effective_to: Option<DateTimeValue>,
19    pub results: IndexMap<String, RuleResult>,
20}
21
22impl From<&DomainResponse> for Response {
23    fn from(response: &DomainResponse) -> Self {
24        Self {
25            spec_name: response.spec_name.clone(),
26            effective: response.effective.clone(),
27            spec_effective_from: response.spec_effective_from.clone(),
28            spec_effective_to: response.spec_effective_to.clone(),
29            results: response
30                .results
31                .iter()
32                .map(|(name, result)| (name.clone(), RuleResult::from(result)))
33                .collect(),
34        }
35    }
36}
37
38/// Rule result JSON: flattened value fields, no rule/veto_detail.
39#[derive(Debug, Clone, Serialize)]
40pub struct RuleResult {
41    pub vetoed: bool,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub veto_reason: Option<String>,
44    pub rule_type: String,
45    #[serde(flatten)]
46    pub value: Option<RuleResultValue>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub explanation: Option<Explanation>,
49    #[serde(skip_serializing_if = "Vec::is_empty")]
50    pub missing_data: Vec<String>,
51}
52
53impl From<&DomainRuleResult> for RuleResult {
54    fn from(result: &DomainRuleResult) -> Self {
55        Self {
56            vetoed: result.vetoed,
57            veto_reason: result.veto_reason.clone(),
58            rule_type: result.rule_type.clone(),
59            value: result.value.as_ref().map(RuleResultValue::from),
60            explanation: result.explanation.clone(),
61            missing_data: result.missing_data().to_vec(),
62        }
63    }
64}