-
Notifications
You must be signed in to change notification settings - Fork 4
Implement Basic Functionalities for the Query Module #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
19bac93
ce1ecfe
6ff72bf
74dae99
4c1d8f1
e604f89
431ab2b
50a3863
f4b6c4a
85edf20
36281f1
23ea2d3
32ec649
4239b49
3465168
7f871e9
9b6c9da
4ddfeed
20aed7e
abe38b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,4 +10,7 @@ use core::error::Error; | |
| pub trait Enumerable: | ||
| Countable + Iterator<Item = Result<Box<dyn Statement>, Box<dyn Error>>> | ||
| { | ||
| fn grep(&self, pattern: &impl PartialEq<Box<dyn Statement>>) -> Self | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| where | ||
| Self: Sized; | ||
| } | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| use crate::{pattern::Pattern, query::Query}; | ||
|
|
||
| pub enum GraphPattern { | ||
| BasicGraphPattern(Query), | ||
| TriplePattern(Pattern), | ||
| } | ||
|
|
||
| impl From<Query> for GraphPattern { | ||
| fn from(query: Query) -> Self { | ||
| Self::BasicGraphPattern(query) | ||
| } | ||
| } | ||
|
|
||
| impl From<Pattern> for GraphPattern { | ||
| fn from(pattern: Pattern) -> Self { | ||
| Self::TriplePattern(pattern) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,56 @@ | ||||||||||||||||||||||
| extern crate alloc; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| use alloc::boxed::Box; | ||||||||||||||||||||||
| use rdf_model::Term; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| use crate::variable::Variable; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| pub enum Matcher { | ||||||||||||||||||||||
| Variable(Variable), | ||||||||||||||||||||||
| Term(Box<dyn Term>), | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl Matcher { | ||||||||||||||||||||||
| pub fn as_variable(&self) -> Option<&Variable> { | ||||||||||||||||||||||
| match self { | ||||||||||||||||||||||
| Self::Variable(var) => Some(var), | ||||||||||||||||||||||
| _ => None, | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl PartialEq<&dyn Term> for Matcher { | ||||||||||||||||||||||
| fn eq(&self, term: &&dyn Term) -> bool { | ||||||||||||||||||||||
| match self { | ||||||||||||||||||||||
| Self::Variable(_) => true, | ||||||||||||||||||||||
| Self::Term(t) => t.as_str() == term.as_str(), | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl From<Variable> for Matcher { | ||||||||||||||||||||||
| fn from(var: Variable) -> Self { | ||||||||||||||||||||||
| Self::Variable(var) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl From<&str> for Matcher { | ||||||||||||||||||||||
| fn from(name: &str) -> Self { | ||||||||||||||||||||||
| name.into() | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+37
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation is self-recursing.
Suggested change
|
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl From<Box<dyn Term>> for Matcher { | ||||||||||||||||||||||
| fn from(term: Box<dyn Term>) -> Self { | ||||||||||||||||||||||
| Self::Term(term) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| impl core::fmt::Debug for Matcher { | ||||||||||||||||||||||
| fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||||||||||||||||||||||
| match self { | ||||||||||||||||||||||
| Self::Variable(var) => write!(f, "{:?}", var), | ||||||||||||||||||||||
| Self::Term(t) => f.write_str(&t.as_str()), | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| extern crate alloc; | ||
|
|
||
| use alloc::{boxed::Box, collections::BTreeMap, vec}; | ||
| use rdf_model::{Statement, Term}; | ||
|
|
||
| use crate::{ | ||
| matcher::Matcher, solution::Solution, traits::queryable::Queryable, variable::Variable, | ||
| }; | ||
|
|
||
| pub struct Pattern { | ||
| subject: Matcher, | ||
| predicate: Matcher, | ||
| object: Matcher, | ||
| graph_name: Option<Box<dyn Term>>, | ||
| } | ||
|
|
||
| impl Pattern { | ||
| pub fn new( | ||
| subject: impl Into<Matcher>, | ||
| predicate: impl Into<Matcher>, | ||
| object: impl Into<Matcher>, | ||
| graph_name: Option<Box<dyn Term>>, | ||
| ) -> Self { | ||
| Self { | ||
| subject: subject.into(), | ||
| predicate: predicate.into(), | ||
| object: object.into(), | ||
| graph_name, | ||
| } | ||
| } | ||
|
|
||
| pub(crate) fn execute<Q: Queryable>(&self, queryable: &Q) -> Q | ||
| where | ||
| Self: Sized, | ||
| { | ||
| queryable.query_pattern(self) | ||
| } | ||
|
|
||
| /// Returns a query solution constructed by binding any variables in this | ||
| /// pattern with the corresponding terms in the given statement. | ||
| pub fn solution(&self, statement: Box<dyn Statement>) -> Solution { | ||
| let mut ans = BTreeMap::new(); | ||
|
|
||
| let bindings = vec![ | ||
| (self.subject.as_variable(), statement.subject()), | ||
| (self.predicate.as_variable(), statement.predicate()), | ||
| (self.object.as_variable(), statement.object()), | ||
| ]; | ||
|
|
||
| for (variable, term) in bindings { | ||
| if let Some(variable) = variable.map(Variable::name).map(Variable::unbound) { | ||
| ans.insert(variable, term); | ||
| } | ||
| } | ||
|
|
||
| Solution::new(ans) | ||
| } | ||
| } | ||
|
|
||
| impl PartialEq<Box<dyn Statement>> for Pattern { | ||
| fn eq(&self, statement: &Box<dyn Statement>) -> bool { | ||
| let (s, p, o) = ( | ||
| statement.subject(), | ||
| statement.predicate(), | ||
| statement.object(), | ||
| ); | ||
| self.subject == s && self.predicate == p && self.object == o | ||
| } | ||
| } | ||
|
|
||
| impl core::fmt::Debug for Pattern { | ||
| fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| f.debug_struct("Pattern") | ||
| .field("subject", &self.subject) | ||
| .field("predicate", &self.predicate) | ||
| .field("object", &self.object) | ||
| .field( | ||
| "graph_name", | ||
| &self.graph_name.as_ref().map(|gn| gn.as_str()), | ||
| ) | ||
| .finish() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,41 @@ | ||||||||||
| extern crate alloc; | ||||||||||
|
|
||||||||||
| use alloc::vec::Vec; | ||||||||||
|
|
||||||||||
| use crate::{pattern::Pattern, solutions::Solutions, traits::queryable::Queryable}; | ||||||||||
|
|
||||||||||
| pub struct Query { | ||||||||||
| patterns: Vec<Pattern>, | ||||||||||
| } | ||||||||||
|
|
||||||||||
| impl Query { | ||||||||||
| pub fn new(patterns: Vec<Pattern>) -> Self { | ||||||||||
| Self { patterns } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /// Executes the query on the given graph. | ||||||||||
| /// | ||||||||||
| /// If the query nas no patterns, it returns a single empty solution as per | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| /// If the query nas no patterns, it returns a single empty solution as per | |
| /// If the query has no patterns, it returns a single empty solution as per |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional: I think this would be good to rename to match the idiomatic format rust uses. Also you're using empty elsewhere with different semantics (Solutions::empty() -> Solutions).
| pub fn empty(&self) -> bool { | |
| pub fn is_empty(&self) -> bool { |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| extern crate alloc; | ||
|
|
||
| use alloc::collections::BTreeMap; | ||
| use rdf_model::HeapTerm; | ||
|
|
||
| use crate::variable::Variable; | ||
|
|
||
| pub struct Solution { | ||
| bindings: BTreeMap<Variable, HeapTerm>, | ||
| } | ||
|
|
||
| impl Solution { | ||
| pub fn new(bindings: BTreeMap<Variable, impl Into<HeapTerm>>) -> Self { | ||
| let bindings = bindings | ||
| .into_iter() | ||
| .map(|(var, term)| (var, term.into())) | ||
| .collect(); | ||
|
|
||
| Self { bindings } | ||
| } | ||
|
|
||
| pub fn binding(&self, var: &Variable) -> Option<&HeapTerm> { | ||
| self.bindings.get(var) | ||
| } | ||
|
|
||
| pub fn each_binding(&self) -> impl Iterator<Item = (&Variable, &HeapTerm)> { | ||
| self.bindings.iter() | ||
| } | ||
|
|
||
| pub fn each_name(&self) -> impl Iterator<Item = &Variable> { | ||
| self.bindings.keys() | ||
| } | ||
|
|
||
| pub fn each_value(&self) -> impl Iterator<Item = &HeapTerm> { | ||
| self.bindings.values() | ||
| } | ||
| } | ||
|
|
||
| impl core::fmt::Debug for Solution { | ||
| fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| f.debug_struct("Solution").finish() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| extern crate alloc; | ||
|
|
||
| use alloc::boxed::Box; | ||
|
|
||
| use crate::solution::Solution; | ||
|
|
||
| pub struct Solutions { | ||
| iter: Box<dyn Iterator<Item = Solution>>, | ||
| } | ||
|
|
||
| impl Solutions { | ||
| pub fn new(iter: impl Iterator<Item = Solution> + 'static) -> Self { | ||
| Self { | ||
| iter: Box::new(iter), | ||
| } | ||
| } | ||
|
|
||
| pub fn empty() -> Self { | ||
| Self { | ||
| iter: Box::new(core::iter::empty()), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Iterator for Solutions { | ||
| type Item = Solution; | ||
|
|
||
| fn next(&mut self) -> Option<Self::Item> { | ||
| self.iter.next() | ||
| } | ||
| } | ||
|
|
||
| impl core::fmt::Debug for Solutions { | ||
| fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { | ||
| f.debug_struct("Solutions").finish() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // This is free and unencumbered software released into the public domain. | ||
| extern crate alloc; | ||
|
|
||
| use alloc::vec; | ||
| use rdf_model::Enumerable; | ||
|
|
||
| use crate::{graph_pattern::GraphPattern, pattern::Pattern, query::Query, solutions::Solutions}; | ||
|
|
||
| pub trait Queryable: Enumerable { | ||
| fn query(&self, pattern: impl Into<GraphPattern>) -> Solutions | ||
| where | ||
| Self: Sized, | ||
| { | ||
| match pattern.into() { | ||
| GraphPattern::BasicGraphPattern(query) => self.query_execute(query), | ||
| GraphPattern::TriplePattern(pattern) => self.query_execute(Query::new(vec![pattern])), | ||
| } | ||
| } | ||
|
|
||
| fn query_execute(&self, query: Query) -> Solutions | ||
| where | ||
| Self: Sized, | ||
| { | ||
| query.execute(self) | ||
| } | ||
|
|
||
| fn query_pattern(&self, pattern: &Pattern) -> Self | ||
| where | ||
| Self: Sized, | ||
| { | ||
| self.grep(pattern) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The grep method is left as a stub using todo!(), which may cause runtime issues when called. Consider implementing the method or providing an explicit indication that it is intentionally unimplemented.