Skip to content

Define the basic query operations in the SRDF trait #246

@angelip2303

Description

@angelip2303

I am trying to implement the SHACL-based subsetting algorithm (#211), and I found that the SRDF trait could include more functionality that is interesting for working with graphs. The idea is that by implementing a triples_matching method which can resolve Basic Graph Patterns, all the other implementations can be understood as specializations of the matcher.

pub trait Query: Rdf {
    /// An iterator over all the triples matching a given pattern.
    fn triples_matching(
        &self,
        subject: impl Into<Matcher<Self>>,
        predicate: impl Into<Matcher<Self>>,
        object: impl Into<Matcher<Self>>,
    ) -> Result<impl Iterator<Item = Self::Triple>, Self::Error>;

    /// An iterator over all the triples.
    fn triples(&self) -> Result<impl Iterator<Item = Self::Triple>, Self::Error> {
        self.triples_matching(Matcher::Any, Matcher::Any, Matcher::Any)
    }

    /// An iterator over all the subjects of the triples.
    fn subjects(&self) -> Result<impl Iterator<Item = Self::Subject>, Self::Error> {
        let subjects = self.triples()?.map(Triple::into_subject);
        Ok(subjects)
    }

    /// An iterator over all the predicates of the triples.
    fn predicates(&self) -> Result<impl Iterator<Item = Self::IRI>, Self::Error> {
        let predicates = self.triples()?.map(Triple::into_predicate);
        Ok(predicates)
    }

    /// An iterator over all the objects of the triples.
    fn objects(&self) -> Result<impl Iterator<Item = Self::Term>, Self::Error> {
        let objects = self.triples()?.map(Triple::into_object);
        Ok(objects)
    }

    /// An iterator over all the triples with a given subject.
    fn triples_with_subject(
        &self,
        subject: Self::Subject,
    ) -> Result<impl Iterator<Item = Self::Triple>, Self::Error> {
        self.triples_matching(subject, Matcher::Any, Matcher::Any)
    }

    /// An iterator over all the triples with a given predicate.
    fn triples_with_predicate(
        &self,
        predicate: Self::IRI,
    ) -> Result<impl Iterator<Item = Self::Triple>, Self::Error> {
        self.triples_matching(Matcher::Any, predicate, Matcher::Any)
    }

    /// An iterator over all the triples with a given object.
    fn triples_with_object(
        &self,
        object: Self::Term,
    ) -> Result<impl Iterator<Item = Self::Triple>, Self::Error> {
        self.triples_matching(Matcher::Any, Matcher::Any, object)
    }

    /// An iterator over all the neighbours of a given subject.
    fn neighs(
        &self,
        node: Self::Subject,
    ) -> Result<impl Iterator<Item = Self::Term>, Self::Error> {
        let objects = self.triples_with_subject(node)?.map(Triple::into_object);
        Ok(objects)
    }

    /// An iterator over all the outgoing arcs from a given subject.
    fn outgoing_arcs(&self, subject: Self::Subject) -> Result<OutgoingArcs<Self>, Self::Error> {
        let mut results: OutgoingArcs<Self> = HashMap::new();
        for triple in self.triples_with_subject(subject)? {
            let (_, p, o) = triple.spo();
            results.entry(p.clone()).or_default().insert(o.clone());
        }
        Ok(results)
    }

    /// An iterator over all the incoming arcs to a given object.
    fn incoming_arcs(&self, object: Self::Term) -> Result<IncomingArcs<Self>, Self::Error> {
        let mut results: IncomingArcs<Self> = HashMap::new();
        for triple in self.triples_with_object(object)? {
            let (s, p, _) = triple.spo();
            results.entry(p.clone()).or_default().insert(s.clone());
        }
        Ok(results)
    }
}

Note that the snippet above should be understood as pseudocode, and it may not work as-is.

Tasks

  • Define the basic triples_matching method
  • Define all the rest of the remaining pieces which depend on triples_matching
  • The project is buildable after all the refactoring
  • Write some docs explaining how the Query trait works

Note: Something like what is shown in the comment.

Note: this involves changing the names/behavior of several methods, thus the refactoring involves deep changes in the codebase.

Metadata

Metadata

Assignees

Labels

architectureAbout rudof architecturebugSomething isn't workingrdfRelated to RDF supportrustRelated to the Rust implementation

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions