1use crate::quad_container::QuadContainer;
2use oxigraph::model::Quad;
3use oxigraph::sparql::QueryResults;
4use oxigraph::store::Store;
5use std::collections::HashSet;
6
7#[derive(Clone)]
10pub struct R2ROperator {
11 pub(crate) query: String,
12 pub(crate) static_data: HashSet<Quad>,
13}
14
15impl R2ROperator {
16 pub fn new(query: String) -> Self {
18 Self {
19 query,
20 static_data: HashSet::new(),
21 }
22 }
23
24 pub fn add_static_data(&mut self, quad: Quad) {
26 self.static_data.insert(quad);
27 }
28
29 pub fn execute(
31 &self,
32 container: &QuadContainer,
33 ) -> Result<QueryResults, Box<dyn std::error::Error>> {
34 let store = Store::new()?;
36
37 for quad in &container.elements {
39 store.insert(quad)?;
40 }
41
42 for quad in &self.static_data {
44 store.insert(quad)?;
45 }
46
47 #[cfg(debug_assertions)]
48 {
49 println!("[R2R] Executing query:");
50 println!("{}", self.query);
51 println!("[R2R] Container has {} quads", container.len());
52 println!("[R2R] Static data has {} quads", self.static_data.len());
53 for (i, quad) in container.elements.iter().enumerate() {
54 println!("[R2R] Quad {}: {:?}", i + 1, quad);
55 }
56 }
57
58 use oxigraph::sparql::SparqlEvaluator;
65 SparqlEvaluator::new()
66 .parse_query(&self.query)?
67 .on_store(&store)
68 .execute()
69 .map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
70 }
71
72 pub fn execute_select(
75 &self,
76 container: &QuadContainer,
77 ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
78 let results = self.execute(container)?;
79
80 let mut output = Vec::new();
81
82 if let QueryResults::Solutions(solutions) = results {
83 for solution in solutions {
84 let solution = solution?;
85 output.push(format!("{:?}", solution));
86 }
87 }
88
89 Ok(output)
90 }
91
92 pub fn query(&self) -> &str {
94 &self.query
95 }
96
97 pub fn static_data_size(&self) -> usize {
99 self.static_data.len()
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use oxigraph::model::*;
107
108 #[test]
109 fn test_r2r_operator_creation() {
110 let query = "SELECT * WHERE { ?s ?p ?o }".to_string();
111 let operator = R2ROperator::new(query.clone());
112 assert_eq!(operator.query(), query);
113 assert_eq!(operator.static_data_size(), 0);
114 }
115
116 #[test]
117 fn test_add_static_data() {
118 let query = "SELECT * WHERE { ?s ?p ?o }".to_string();
119 let mut operator = R2ROperator::new(query);
120
121 let quad = Quad::new(
122 NamedNode::new("http://example.org/subject").unwrap(),
123 NamedNode::new("http://example.org/predicate").unwrap(),
124 NamedNode::new("http://example.org/object").unwrap(),
125 GraphName::DefaultGraph,
126 );
127
128 operator.add_static_data(quad);
129 assert_eq!(operator.static_data_size(), 1);
130 }
131
132 #[test]
133 fn test_execute_query() -> Result<(), Box<dyn std::error::Error>> {
134 let query = "SELECT * WHERE { ?s ?p ?o }".to_string();
135 let mut operator = R2ROperator::new(query);
136
137 let static_quad = Quad::new(
139 NamedNode::new("http://example.org/static").unwrap(),
140 NamedNode::new("http://example.org/isStatic").unwrap(),
141 Literal::new_simple_literal("true"),
142 GraphName::DefaultGraph,
143 );
144 operator.add_static_data(static_quad.clone());
145
146 let mut container_quads = HashSet::new();
148 let stream_quad = Quad::new(
149 NamedNode::new("http://example.org/stream").unwrap(),
150 NamedNode::new("http://example.org/hasValue").unwrap(),
151 Literal::new_simple_literal("42"),
152 GraphName::DefaultGraph,
153 );
154 container_quads.insert(stream_quad);
155
156 let container = QuadContainer::new(container_quads, 0);
157
158 let results = operator.execute(&container)?;
160
161 if let QueryResults::Solutions(solutions) = results {
163 let count = solutions.count();
164 assert_eq!(count, 2); }
166
167 Ok(())
168 }
169}