use crate::domain::model::query::{QueryIdentifier, QueryResult};
use super::runner::QueryRunner;
use super::store::QueryStore;
pub fn execute_query(
store: &dyn QueryStore,
runner: &dyn QueryRunner,
name: &QueryIdentifier,
) -> anyhow::Result<QueryResult> {
let queries = store.list()?;
let query = queries
.get(name)
.ok_or_else(|| anyhow::anyhow!("unknown query '{name}'"))?;
runner.run(&query.script)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::model::query::{Queries, Query, QuerySchema, QueryScript, QueryValue};
use std::cell::RefCell;
struct StubStore {
listing: Queries,
}
impl QueryStore for StubStore {
fn list(&self) -> anyhow::Result<Queries> {
Ok(self.listing.clone())
}
}
struct StubRunner {
seen: RefCell<Option<String>>,
result: QueryResult,
}
impl QueryRunner for StubRunner {
fn run(&self, script: &QueryScript) -> anyhow::Result<QueryResult> {
*self.seen.borrow_mut() = Some(script.as_str().to_owned());
Ok(self.result.clone())
}
fn schema(&self) -> anyhow::Result<QuerySchema> {
Ok(QuerySchema::default())
}
}
fn name(s: &str) -> QueryIdentifier {
QueryIdentifier::new(s).unwrap()
}
fn nq(n: &str, body: &str) -> Query {
Query::new(name(n), QueryScript::new(body), None)
}
#[test]
fn execute_runs_the_matched_script_through_the_runner() {
let store = StubStore {
listing: [nq("counts", "?[n] := n = 1")].into_iter().collect(),
};
let runner = StubRunner {
seen: RefCell::new(None),
result: QueryResult::new(vec!["n".to_owned()], vec![vec![QueryValue::Int(1)]]),
};
let out = execute_query(&store, &runner, &name("counts")).unwrap();
assert_eq!(runner.seen.borrow().as_deref(), Some("?[n] := n = 1"));
assert_eq!(out.rows.len(), 1);
}
#[test]
fn execute_errors_when_the_identifier_is_unknown() {
let store = StubStore {
listing: Queries::new(),
};
let runner = StubRunner {
seen: RefCell::new(None),
result: QueryResult::default(),
};
let err = execute_query(&store, &runner, &name("missing")).unwrap_err();
assert!(err.to_string().contains("missing"));
assert!(runner.seen.borrow().is_none());
}
}