use crate::machine::Machine;
use crate::{query, solve};
pub enum QueryResult {
Solutions,
ParseError(String),
RuntimeError(String),
}
pub fn run_query(m: &mut Machine, q: &str) -> QueryResult {
let goal = match query::parse_query(m, q) {
Ok(g) => g,
Err(e) => return QueryResult::ParseError(format!("Parse error: {e}")),
};
match solve::solve(m, goal) {
solve::Outcome::Error => {
let msg = m.error.take().map(|e| e.message).unwrap_or_default();
QueryResult::RuntimeError(format!("Runtime error: {msg}"))
}
solve::Outcome::Done => QueryResult::Solutions,
}
}
pub fn exhausted(m: &Machine) -> bool {
m.solution_limit.is_none_or(|l| m.solutions.len() < l)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::render::RenderedSolution;
use plg_shared::StringInterner;
fn machine() -> Box<Machine> {
Machine::new(StringInterner::new(), Vec::new())
}
#[test]
fn exhausted_follows_the_limit() {
let mut m = machine();
assert!(exhausted(&m), "no limit => exhausted");
m.solution_limit = Some(2);
assert!(exhausted(&m), "under the limit => exhausted");
m.solutions.push(RenderedSolution { bindings: vec![] });
m.solutions.push(RenderedSolution { bindings: vec![] });
assert!(!exhausted(&m), "limit hit exactly => not exhausted");
}
}