diff --git a/contracts/okp4-dataverse/src/credential/vc.rs b/contracts/okp4-dataverse/src/credential/vc.rs index eda36cb9..ea78fd11 100644 --- a/contracts/okp4-dataverse/src/credential/vc.rs +++ b/contracts/okp4-dataverse/src/credential/vc.rs @@ -217,12 +217,7 @@ impl<'a> VerifiableCredential<'a> { }) .map_ok(|claim_id| Claim { id: claim_id.iri, - content: Dataset::new( - dataset - .match_pattern(Some(claim_id.into()), None, None, None) - .copied() - .collect(), - ), + content: dataset.sub_graph(claim_id.into()), }) .collect() } diff --git a/packages/okp4-rdf/src/dataset.rs b/packages/okp4-rdf/src/dataset.rs index ef2d38bf..e7d4e414 100644 --- a/packages/okp4-rdf/src/dataset.rs +++ b/packages/okp4-rdf/src/dataset.rs @@ -1,6 +1,7 @@ use crate::owned_model::OwnedQuad; use itertools::Itertools; use rio_api::model::{GraphName, NamedNode, Quad, Subject, Term}; +use std::collections::HashSet; use std::slice::Iter; #[derive(Clone, Debug, PartialEq)] @@ -49,6 +50,39 @@ impl<'a> Dataset<'a> { ) -> QuadPatternFilter<'a, Iter<'a, Quad<'a>>> { self.iter().skip_pattern((s, p, o, g).into()) } + + pub fn sub_graph(&'a self, subject: Subject<'a>) -> Dataset<'a> { + Self::new(Self::sub_graph_from_quads(self.as_ref(), HashSet::new(), subject).0) + } + + fn sub_graph_from_quads( + quads: &'a [Quad<'a>], + mut visited: HashSet>, + subject: Subject<'a>, + ) -> (Vec>, HashSet>) { + let mut sub_graph = vec![]; + for quad in quads + .iter() + .match_pattern((Some(subject), None, None, None).into()) + { + sub_graph.push(*quad); + + let maybe_node: Option> = match quad.object { + Term::NamedNode(n) => Some(n.into()), + Term::BlankNode(n) => Some(n.into()), + _ => None, + }; + + if let Some(s) = maybe_node.filter(|n| !visited.contains(n)) { + visited.insert(subject); + let (new_quads, new_visited) = Self::sub_graph_from_quads(quads, visited, s); + visited = new_visited; + sub_graph.extend(new_quads); + } + } + + (sub_graph, visited) + } } #[derive(Copy, Clone)]