Add test for programatic queries
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate static_assertions;
|
||||
#[cfg(test)]
|
||||
#[macro_use] extern crate maplit;
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
|
||||
@@ -936,3 +936,40 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,12 @@ use crate::atom_table::*;
|
||||
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)]
|
||||
@@ -30,6 +35,24 @@ pub enum Value {
|
||||
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.
|
||||
@@ -50,14 +73,21 @@ impl From<Vec<QueryResultLine>> for QueryResult {
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -145,4 +175,10 @@ impl TryFrom<String> for Value {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Value {
|
||||
fn from(str: &str) -> Self {
|
||||
Value::String(str.to_string())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user