Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 98 additions & 11 deletions rudof_rdf/src/rdf_impl/in_memory_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,6 @@ impl NeighsRDF for InMemoryGraph {
///
/// * `subject` - The subject to filter by
fn triples_with_subject(&self, subject: &Self::Subject) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
// Collect the triples into a Vec to avoid the lifetime dependency on subject
let triples: Vec<_> = self
.graph
.triples_for_subject(subject)
Expand All @@ -698,10 +697,84 @@ impl NeighsRDF for InMemoryGraph {
Ok(triples.into_iter())
}

/// Returns all triples with the specified subject and predicate.
///
/// Uses the oxrdf SPO index directly for O(k) lookup.
///
/// # Arguments
///
/// * `subject` - The subject to match
/// * `predicate` - The predicate to match
fn triples_with_subject_predicate(
&self,
subject: &Self::Subject,
predicate: &Self::IRI,
) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
let triples: Vec<_> = self
.graph
.objects_for_subject_predicate(OxSubjectRef::from(subject), NamedNodeRef::from(predicate))
.map(|o| OxTriple::new(subject.clone(), predicate.clone(), o.into_owned()))
.collect();
Ok(triples.into_iter())
}

/// Returns all triples with the specified predicate.
///
/// Uses the oxrdf POS index directly for O(k) lookup.
///
/// # Arguments
///
/// * `predicate` - The predicate to match
fn triples_with_predicate(&self, predicate: &Self::IRI) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
let triples: Vec<_> = self
.graph
.triples_for_predicate(NamedNodeRef::from(predicate))
.map(TripleRef::into_owned)
.collect();
Ok(triples.into_iter())
}

/// Returns all triples with the specified predicate and object.
///
/// Uses the oxrdf POS index directly for O(k) lookup.
///
/// # Arguments
///
/// * `predicate` - The predicate to match
/// * `object` - The object to match
fn triples_with_predicate_object(
&self,
predicate: &Self::IRI,
object: &Self::Term,
) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
let triples: Vec<_> = self
.graph
.subjects_for_predicate_object(NamedNodeRef::from(predicate), TermRef::from(object))
.map(|s| OxTriple::new(s.into_owned(), predicate.clone(), object.clone()))
.collect();
Ok(triples.into_iter())
}

/// Returns all triples with the specified object.
///
/// Uses the oxrdf OSP index directly for O(k) lookup.
///
/// # Arguments
///
/// * `object` - The object to match
fn triples_with_object(&self, object: &Self::Term) -> Result<impl Iterator<Item = Self::Triple>, Self::Err> {
let triples: Vec<_> = self
.graph
.triples_for_object(TermRef::from(object))
.map(TripleRef::into_owned)
.collect();
Ok(triples.into_iter())
}

/// Returns an iterator over triples matching a pattern.
///
/// This method filters triples based on patterns for subject, predicate, and object.
/// Each pattern can be a specific value or a wildcard matcher.
/// Uses the appropriate oxrdf index based on which positions are concrete
/// vs wildcard, giving O(k) complexity instead of a full O(n) table scan.
///
/// # Parameters
///
Expand All @@ -723,14 +796,28 @@ impl NeighsRDF for InMemoryGraph {
P: Matcher<Self::IRI>,
O: Matcher<Self::Term>,
{
// TODO: Implement this function in a way that it does not retrieve all triples
let triples = self.triples()?.filter_map(move |triple| {
match subject == &triple.subject && predicate == &triple.predicate && object == &triple.object {
true => Some(triple),
false => None,
}
});
Ok(triples)
// Dispatch to the most specific oxrdf index based on which positions are bound,
// avoiding a full scan.
let triples: Vec<OxTriple> = match (subject.value(), predicate.value(), object.value()) {
(Some(s), Some(p), Some(o)) => self
.graph
.contains(TripleRef::new(
OxSubjectRef::from(s),
NamedNodeRef::from(p),
TermRef::from(o),
))
.then_some(OxTriple::new(s.clone(), p.clone(), o.clone()))
.into_iter()
.collect(),
(Some(s), Some(p), None) => self.triples_with_subject_predicate(s, p)?.collect(),
(Some(s), None, Some(o)) => self.triples_with_subject(s)?.filter(|t| t.object == *o).collect(),
(Some(s), None, None) => self.triples_with_subject(s)?.collect(),
(None, Some(p), Some(o)) => self.triples_with_predicate_object(p, o)?.collect(),
(None, Some(p), None) => self.triples_with_predicate(p)?.collect(),
(None, None, Some(o)) => self.triples_with_object(o)?.collect(),
(None, None, None) => self.graph.iter().map(TripleRef::into_owned).collect(),
};
Ok(triples.into_iter())
}
}

Expand Down
Loading