ggen_graph/
interchangeable.rs1use crate::delta::RdfDelta;
10use crate::graph::dataset::DeterministicGraph;
11use crate::ocel::{EvidenceProjector, OcelLog};
12use crate::receipt::GraphReceipt;
13use crate::GraphError;
14use oxigraph::model::Quad;
15use serde_json::Value;
16
17#[derive(Clone)]
19pub struct GenesisCore {
20 graph: DeterministicGraph,
21}
22
23impl GenesisCore {
24 pub fn new() -> Result<Self, GraphError> {
26 Ok(Self {
27 graph: DeterministicGraph::new()?,
28 })
29 }
30
31 pub fn graph(&self) -> &DeterministicGraph {
33 &self.graph
34 }
35
36 pub fn execute_transaction(&self, delta: &RdfDelta) -> Result<GraphReceipt, GraphError> {
38 self.graph.apply_delta(delta, &[])
39 }
40}
41
42#[derive(Default)]
45pub struct OuterMembrane;
46
47impl OuterMembrane {
48 pub fn new() -> Self {
50 Self
51 }
52
53 pub fn admit_input(&self, query: &str) -> Result<(), GraphError> {
59 let trimmed = query.trim();
60 if trimmed.is_empty() {
61 return Err(GraphError::Other(
62 "Empty input rejected by outer membrane".to_string(),
63 ));
64 }
65
66 let upper = trimmed.to_uppercase();
68 if upper.contains("DROP GRAPH") || upper.contains("DELETE WHERE") {
69 return Err(GraphError::Other(
70 "Security violation: injection pattern blocked by outer membrane".to_string(),
71 ));
72 }
73
74 Ok(())
75 }
76
77 pub fn validate_quads(&self, quads: &[Quad]) -> Result<(), GraphError> {
83 for q in quads {
84 let predicate_uri = q.predicate.as_str();
85 if predicate_uri.is_empty() {
86 return Err(GraphError::Other(
87 "Invalid predicate rejected by outer membrane".to_string(),
88 ));
89 }
90 if q.subject.to_string().is_empty() {
91 return Err(GraphError::Other(
92 "Invalid subject rejected by outer membrane".to_string(),
93 ));
94 }
95 }
96 Ok(())
97 }
98}
99
100pub struct AdapterLayer;
102
103impl AdapterLayer {
104 pub fn adapt_json_rpc(request: &Value) -> Result<RdfDelta, GraphError> {
110 let method = request
111 .get("method")
112 .and_then(|m| m.as_str())
113 .ok_or_else(|| GraphError::Other("Missing JSON-RPC method".to_string()))?;
114
115 if method != "apply_delta" {
116 return Err(GraphError::Other(format!("Unsupported method: {}", method)));
117 }
118
119 let params = request
120 .get("params")
121 .ok_or_else(|| GraphError::Other("Missing JSON-RPC params".to_string()))?;
122
123 let additions_arr = params
124 .get("additions")
125 .and_then(|a| a.as_array())
126 .ok_or_else(|| {
127 GraphError::Other("Missing or invalid additions in params".to_string())
128 })?;
129
130 let deletions_arr = params
131 .get("deletions")
132 .and_then(|d| d.as_array())
133 .ok_or_else(|| {
134 GraphError::Other("Missing or invalid deletions in params".to_string())
135 })?;
136
137 let mut additions = Vec::new();
138 for val in additions_arr {
139 let s = val
140 .as_str()
141 .ok_or_else(|| GraphError::Other("Non-string addition quad".to_string()))?;
142 additions.push(s.to_string());
143 }
144
145 let mut deletions = Vec::new();
146 for val in deletions_arr {
147 let s = val
148 .as_str()
149 .ok_or_else(|| GraphError::Other("Non-string deletion quad".to_string()))?;
150 deletions.push(s.to_string());
151 }
152
153 Ok(RdfDelta::new(additions, deletions))
154 }
155}
156
157pub struct ProjectionLayer;
159
160impl ProjectionLayer {
161 pub fn project_state_to_ocel(core: &GenesisCore) -> Result<OcelLog, GraphError> {
163 EvidenceProjector::extract_ocel(core.graph())
164 }
165
166 pub fn project_ocel_to_state(core: &GenesisCore, log: &OcelLog) -> Result<(), GraphError> {
168 EvidenceProjector::project_ocel(core.graph(), log)
169 }
170}