1use std::collections::HashMap;
2use std::time::Duration;
3
4use uni_common::{Properties, Value};
5
6use crate::types::{RuntimeWarning, RuntimeWarningCode};
7
8pub type FactRow = HashMap<String, Value>;
10
11#[derive(Debug, Clone)]
13pub struct LocyResult {
14 pub derived: HashMap<String, Vec<FactRow>>,
16 pub stats: LocyStats,
18 pub command_results: Vec<CommandResult>,
20 pub warnings: Vec<RuntimeWarning>,
22 pub approximate_groups: HashMap<String, Vec<String>>,
25 pub derived_fact_set: Option<DerivedFactSet>,
28}
29
30#[derive(Debug, Clone)]
32pub enum CommandResult {
33 Query(Vec<FactRow>),
34 Assume(Vec<FactRow>),
35 Explain(DerivationNode),
36 Abduce(AbductionResult),
37 Derive { affected: usize },
38 Cypher(Vec<FactRow>),
39}
40
41#[derive(Debug, Clone)]
43pub struct DerivationNode {
44 pub rule: String,
45 pub clause_index: usize,
46 pub priority: Option<i64>,
47 pub bindings: HashMap<String, Value>,
48 pub along_values: HashMap<String, Value>,
49 pub children: Vec<DerivationNode>,
50 pub graph_fact: Option<String>,
51 pub approximate: bool,
54 pub proof_probability: Option<f64>,
57}
58
59#[derive(Debug, Clone)]
61pub struct AbductionResult {
62 pub modifications: Vec<ValidatedModification>,
63}
64
65#[derive(Debug, Clone)]
67pub struct ValidatedModification {
68 pub modification: Modification,
69 pub validated: bool,
70 pub cost: f64,
71}
72
73#[derive(Debug, Clone)]
75pub enum Modification {
76 RemoveEdge {
77 source_var: String,
78 target_var: String,
79 edge_var: String,
80 edge_type: String,
81 match_properties: HashMap<String, Value>,
82 },
83 ChangeProperty {
84 element_var: String,
85 property: String,
86 old_value: Box<Value>,
87 new_value: Box<Value>,
88 },
89 AddEdge {
90 source_var: String,
91 target_var: String,
92 edge_type: String,
93 properties: HashMap<String, Value>,
94 },
95}
96
97#[derive(Debug, Clone)]
99pub struct DerivedEdge {
100 pub edge_type: String,
101 pub source_label: String,
102 pub source_properties: Properties,
103 pub target_label: String,
104 pub target_properties: Properties,
105 pub edge_properties: Properties,
106}
107
108#[derive(Debug, Clone)]
112pub struct DerivedFactSet {
113 pub vertices: HashMap<String, Vec<Properties>>,
115 pub edges: Vec<DerivedEdge>,
117 pub stats: LocyStats,
119 pub evaluated_at_version: u64,
121 #[doc(hidden)]
123 pub mutation_queries: Vec<uni_cypher::ast::Query>,
124}
125
126impl DerivedFactSet {
127 pub fn fact_count(&self) -> usize {
129 self.vertices.values().map(|v| v.len()).sum::<usize>() + self.edges.len()
130 }
131
132 pub fn is_empty(&self) -> bool {
134 self.vertices.is_empty() && self.edges.is_empty()
135 }
136}
137
138#[derive(Debug, Clone, Default)]
140pub struct LocyStats {
141 pub strata_evaluated: usize,
142 pub total_iterations: usize,
143 pub derived_nodes: usize,
144 pub derived_edges: usize,
145 pub evaluation_time: Duration,
146 pub queries_executed: usize,
147 pub mutations_executed: usize,
148 pub peak_memory_bytes: usize,
150}
151
152impl LocyResult {
153 pub fn derived_facts(&self, rule: &str) -> Option<&Vec<FactRow>> {
155 self.derived.get(rule)
156 }
157
158 pub fn rows(&self) -> Option<&Vec<FactRow>> {
160 self.command_results.iter().find_map(|cr| cr.as_query())
161 }
162
163 pub fn columns(&self) -> Option<Vec<String>> {
165 self.rows()
166 .and_then(|rows| rows.first().map(|row| row.keys().cloned().collect()))
167 }
168
169 pub fn stats(&self) -> &LocyStats {
171 &self.stats
172 }
173
174 pub fn iterations(&self) -> usize {
176 self.stats.total_iterations
177 }
178
179 pub fn warnings(&self) -> &[RuntimeWarning] {
181 &self.warnings
182 }
183
184 pub fn has_warning(&self, code: &RuntimeWarningCode) -> bool {
186 self.warnings.iter().any(|w| w.code == *code)
187 }
188}
189
190impl CommandResult {
191 pub fn as_explain(&self) -> Option<&DerivationNode> {
193 match self {
194 CommandResult::Explain(node) => Some(node),
195 _ => None,
196 }
197 }
198
199 pub fn as_query(&self) -> Option<&Vec<FactRow>> {
201 match self {
202 CommandResult::Query(rows) => Some(rows),
203 _ => None,
204 }
205 }
206
207 pub fn as_abduce(&self) -> Option<&AbductionResult> {
209 match self {
210 CommandResult::Abduce(result) => Some(result),
211 _ => None,
212 }
213 }
214}