}
}
}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn programatic_query() {
+ let mut machine = Machine::with_test_streams();
+
+ machine.load_module_string("facts", String::from(r#"
+ triple("a", "p1", "b").
+ triple("a", "p2", "b").
+ "#));
+
+ let query = String::from(r#"triple("a",P,"b")."#);
+ let output = machine.run_query(query);
+ assert_eq!(output, QueryResult::Matches(vec![
+ QueryMatch::from(btreemap!{
+ "P" => Value::from("p1"),
+ }),
+ QueryMatch::from(btreemap!{
+ "P" => Value::from("p2"),
+ }),
+ ]));
+
+ assert_eq!(
+ machine.run_query(String::from(r#"triple("a","p1","b")."#)),
+ QueryResult::True
+ );
+
+ assert_eq!(
+ machine.run_query(String::from(r#"triple("x","y","z")."#)),
+ QueryResult::False
+ );
+ }
+}
pub enum QueryResult {
True,
False,
- Matches(Vec<QueryResultLine>),
+ Matches(Vec<QueryMatch>),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct QueryMatch {
+ pub bindings: BTreeMap<String, Value>
}
#[derive(Debug, Clone, PartialEq, Eq)]
Var,
}
+impl From<BTreeMap<&str, Value>> for QueryMatch {
+ fn from(bindings: BTreeMap<&str, Value>) -> Self {
+ QueryMatch {
+ bindings: bindings.into_iter()
+ .map(|(k, v)| (k.to_string(), v))
+ .collect::<BTreeMap<_, _>>()
+ }
+ }
+}
+
+impl From<BTreeMap<String, Value>> for QueryMatch {
+ fn from(bindings: BTreeMap<String, Value>) -> Self {
+ QueryMatch {
+ bindings
+ }
+ }
+}
+
impl From<Vec<QueryResultLine>> for QueryResult {
fn from(query_result_lines: Vec<QueryResultLine>) -> Self {
// If there is only one line, and it is true or false, return that.
}
// If there is at least one match, return all matches.
- if query_result_lines.iter().any(|l| {
- if let &QueryResultLine::Match(_) = l { true } else { false }
- }) {
- let all_matches = query_result_lines.into_iter()
- .filter(|l| {
- if let &QueryResultLine::Match(_) = l { true } else { false }
- })
- .collect::<Vec<_>>();
+ let all_matches = query_result_lines.into_iter()
+ .filter(|l| {
+ if let &QueryResultLine::Match(_) = l { true } else { false }
+ })
+ .map(|l| {
+ match l {
+ QueryResultLine::Match(m) => {
+ QueryMatch::from(m)
+ },
+ _ => unreachable!()
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if !all_matches.is_empty() {
return QueryResult::Matches(all_matches);
}
Err(())
}
}
+}
+
+impl From<&str> for Value {
+ fn from(str: &str) -> Self {
+ Value::String(str.to_string())
+ }
}
\ No newline at end of file