use vantage_rhai::rhai::Dynamic;
use vantage_rhai::{Block, Env, Host, Limits};
use super::handle::Handle;
use super::vocab::{DataVocab, TargetResolver, Writes};
pub const MIN_LIMIT: usize = 1;
pub const MAX_LIMIT: usize = 50;
pub const DEFAULT_LIMIT: usize = 5;
fn run_once(host: &Host, script: &str) -> Result<Dynamic, String> {
host.compile_uncached(&Block::from(script))
.and_then(|s| s.eval(&Env::new()))
.map_err(|e| e.to_string())
}
pub async fn run_script(
script: String,
resolver: TargetResolver,
limit: usize,
writes: Writes,
) -> Result<serde_json::Value, String> {
let limit = limit.clamp(MIN_LIMIT, MAX_LIMIT);
tokio::task::spawn_blocking(move || {
let host = Host::builder(Limits::background())
.vocab(DataVocab::read_write_with(
Some(resolver),
Some(limit),
writes,
))
.build();
run_once(&host, &script).map(|v| vantage_rhai::to_json(&v))
})
.await
.map_err(|e| format!("data script task failed to run: {e}"))?
}
pub fn preview_script(
script: String,
resolver: TargetResolver,
) -> Result<serde_json::Value, String> {
let host = Host::builder(Limits::background())
.vocab(DataVocab::describe(Some(resolver.clone())))
.build();
let handle = run_once(&host, &script)?
.try_cast::<Handle>()
.ok_or_else(|| {
"preview script must end on the query itself, e.g. \
`table(\"orders\").where(\"status\", \"paid\")`; this host has no \
terminal verbs (`list`, `count`, `first`)"
.to_string()
})?;
let vista = handle.resolve(Some(&resolver)).map_err(|e| e.to_string())?;
Ok(vista.preview_query())
}