pyshacl_turbo_engine/
graph_read.rs1use oxigraph::model::*;
3use oxigraph::store::Transaction;
4
5use crate::{Error, Result};
6
7pub trait GraphRead {
18 fn matching_quads<'a>(
21 &'a self,
22 subject: Option<NamedOrBlankNodeRef<'_>>,
23 predicate: Option<NamedNodeRef<'_>>,
24 object: Option<TermRef<'_>>,
25 graph: Option<GraphNameRef<'_>>,
26 ) -> impl Iterator<Item = Result<Quad>> + use<'a, Self>;
27
28 fn named_graphs(&self) -> impl Iterator<Item = Result<NamedOrBlankNode>> + '_;
31
32 fn contains_named_graph(&self, graph: &NamedOrBlankNode) -> Result<bool>;
34}
35
36impl GraphRead for Dataset {
37 fn matching_quads<'a>(
38 &'a self,
39 subject: Option<NamedOrBlankNodeRef<'_>>,
40 predicate: Option<NamedNodeRef<'_>>,
41 object: Option<TermRef<'_>>,
42 graph: Option<GraphNameRef<'_>>,
43 ) -> impl Iterator<Item = Result<Quad>> + use<'a> {
44 let predicate = predicate.map(NamedNodeRef::into_owned);
46 let object = object.map(TermRef::into_owned);
47 let graph = graph.map(GraphNameRef::into_owned);
48 let candidates: Box<dyn Iterator<Item = QuadRef<'a>> + 'a> = if let Some(subject) = subject
49 {
50 Box::new(self.quads_for_subject(subject))
51 } else if let Some(object) = object.as_ref() {
52 Box::new(self.quads_for_object(object.as_ref()))
53 } else if let Some(predicate) = predicate.as_ref() {
54 Box::new(self.quads_for_predicate(predicate.as_ref()))
55 } else if let Some(graph) = graph.as_ref() {
56 Box::new(self.quads_for_graph_name(graph.as_ref()))
57 } else {
58 Box::new(self.iter())
59 };
60 candidates
61 .filter(move |q| {
62 predicate.as_ref().is_none_or(|p| p.as_ref() == q.predicate)
63 && object.as_ref().is_none_or(|o| o.as_ref() == q.object)
64 && graph.as_ref().is_none_or(|g| g.as_ref() == q.graph_name)
65 })
66 .map(|quad| Ok(quad.into_owned()))
67 }
68
69 fn named_graphs(&self) -> impl Iterator<Item = Result<NamedOrBlankNode>> + '_ {
70 self.iter().filter_map(|quad| {
72 let name = match quad.graph_name {
73 GraphNameRef::NamedNode(node) => NamedOrBlankNode::from(node.into_owned()),
74 GraphNameRef::BlankNode(node) => NamedOrBlankNode::from(node.into_owned()),
75 GraphNameRef::DefaultGraph => return None,
76 };
77 (self.quads_for_graph_name(quad.graph_name).next() == Some(quad)).then_some(Ok(name))
78 })
79 }
80 fn contains_named_graph(&self, graph: &NamedOrBlankNode) -> Result<bool> {
81 Ok(self.quads_for_graph_name(graph.as_ref()).next().is_some())
82 }
83}
84
85impl<'tx> GraphRead for Transaction<'tx> {
86 fn matching_quads<'a>(
87 &'a self,
88 subject: Option<NamedOrBlankNodeRef<'_>>,
89 predicate: Option<NamedNodeRef<'_>>,
90 object: Option<TermRef<'_>>,
91 graph: Option<GraphNameRef<'_>>,
92 ) -> impl Iterator<Item = Result<Quad>> + use<'a, 'tx> {
93 self.quads_for_pattern(subject, predicate, object, graph)
94 .map(|quad| {
95 quad.map_err(|error| Error::Runtime(format!("Storage read failed: {error}")))
96 })
97 }
98
99 fn named_graphs(&self) -> impl Iterator<Item = Result<NamedOrBlankNode>> + '_ {
100 Transaction::named_graphs(self).map(|graph| {
101 graph.map_err(|error| Error::Runtime(format!("Storage read failed: {error}")))
102 })
103 }
104
105 fn contains_named_graph(&self, graph: &NamedOrBlankNode) -> Result<bool> {
106 Transaction::contains_named_graph(self, graph.as_ref())
107 .map_err(|error| Error::Runtime(format!("Storage read failed: {error}")))
108 }
109}