1use crate::parsing::ast::ArithmeticComputation;
18use crate::planning::semantics::{DataPath, RulePath};
19use crate::result_value::RuleResultValue;
20use serde::{Serialize, Serializer};
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
26#[serde(rename_all = "snake_case")]
27pub enum ExplainedListOp {
28 Find,
29 First,
30 Last,
31 Count,
32 Sum,
33 Avg,
34 Product,
35 Min,
36 Max,
37 Any,
38 All,
39 Where,
40 Sort { descending: bool },
41 Top,
42 With,
43 Key,
44}
45
46pub(crate) fn serialize_rule_path_as_name<S>(
47 path: &RulePath,
48 serializer: S,
49) -> Result<S::Ok, S::Error>
50where
51 S: Serializer,
52{
53 serializer.serialize_str(&path.input_key())
54}
55
56pub(crate) fn serialize_data_path_as_name<S>(
57 path: &DataPath,
58 serializer: S,
59) -> Result<S::Ok, S::Error>
60where
61 S: Serializer,
62{
63 serializer.serialize_str(&path.input_key())
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
69#[serde(transparent)]
70pub struct ExplainedRuleId(pub u32);
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
74pub struct ExplainedRule {
75 pub id: ExplainedRuleId,
76 #[serde(serialize_with = "serialize_rule_path_as_name")]
77 pub name: RulePath,
78 #[serde(flatten)]
79 pub result: RuleResultValue,
80 pub body: String,
81 #[serde(skip_serializing_if = "Vec::is_empty")]
82 pub causes: Vec<Cause>,
83 #[serde(skip_serializing_if = "Vec::is_empty")]
84 pub children: Vec<ExplanationNode>,
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
88#[serde(tag = "type", rename_all = "snake_case")]
89pub enum ExplanationNode {
90 RuleRef {
92 id: ExplainedRuleId,
93 #[serde(serialize_with = "serialize_rule_path_as_name")]
94 name: RulePath,
95 #[serde(flatten)]
96 result: RuleResultValue,
97 },
98 Compose {
99 expression: String,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 operator: Option<ArithmeticComputation>,
102 operands: Vec<ExplanationNode>,
103 #[serde(flatten)]
104 result: RuleResultValue,
105 },
106 ListCommand {
108 expression: String,
109 stage: String,
111 op: ExplainedListOp,
112 operands: Vec<ExplanationNode>,
113 #[serde(flatten)]
114 result: RuleResultValue,
115 },
116 Data {
118 #[serde(serialize_with = "serialize_data_path_as_name")]
119 name: DataPath,
120 #[serde(flatten)]
121 result: RuleResultValue,
122 },
123 DataUnused {
126 #[serde(serialize_with = "serialize_data_path_as_name")]
127 name: DataPath,
128 },
129 Conversion {
130 expression: String,
131 steps: Vec<SerializedConversionTraceStep>,
132 operands: Vec<ExplanationNode>,
133 #[serde(flatten)]
134 result: RuleResultValue,
135 },
136 Veto {
137 #[serde(skip_serializing_if = "Option::is_none")]
138 message: Option<String>,
139 },
140 Row {
142 number: usize,
143 #[serde(skip_serializing_if = "std::ops::Not::not")]
144 appended: bool,
145 #[serde(skip_serializing_if = "Vec::is_empty")]
146 key: Vec<ExplanationNode>,
147 fields: Vec<ExplanationNode>,
148 },
149 Filter {
151 condition: String,
152 matched: usize,
153 total: usize,
154 #[serde(skip_serializing_if = "Vec::is_empty")]
155 children: Vec<ExplanationNode>,
156 },
157}
158
159#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
160pub struct Cause {
161 pub condition: String,
162 pub value: String,
163 #[serde(skip_serializing_if = "Vec::is_empty")]
164 pub children: Vec<ExplanationNode>,
165}
166
167#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
168#[serde(rename_all = "snake_case")]
169pub enum ConversionTraceRole {
170 Outcome,
171 Rule,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
175pub struct SerializedConversionTraceStep {
176 pub(crate) role: ConversionTraceRole,
177 pub(crate) text: String,
178}