use crate::display::SessionJson;
use crate::index::IndexEntry;
use jaq_core::load::{Arena, File, Loader};
use jaq_core::{Filter, ValT, Vars, data, unwrap_valr};
use jaq_json::Val;
pub struct QueryFilter {
_arena: Arena,
filter: Filter<data::JustLut<Val>>,
}
impl QueryFilter {
pub fn parse(code: &str) -> anyhow::Result<Self> {
let arena = Arena::default();
let defs = jaq_core::defs()
.chain(jaq_std::defs())
.chain(jaq_json::defs());
let funs = jaq_core::funs::<data::JustLut<Val>>()
.chain(jaq_std::funs::<data::JustLut<Val>>())
.chain(jaq_json::funs::<data::JustLut<Val>>());
let loader = Loader::new(defs);
let program = File { code, path: () };
let modules = loader
.load(&arena, program)
.map_err(|errs| anyhow::anyhow!("failed to parse query filter: {errs:?}"))?;
let filter = jaq_core::Compiler::<_, data::JustLut<Val>>::default()
.with_funs(funs)
.compile(modules)
.map_err(|errs| anyhow::anyhow!("failed to compile query filter: {errs:?}"))?;
Ok(Self {
_arena: arena,
filter,
})
}
#[must_use]
pub fn matches(&self, entry: &IndexEntry) -> bool {
let session_json = SessionJson::from(entry);
let Ok(json_val) = serde_json::to_value(&session_json) else {
return false;
};
let Ok(val): Result<Val, _> = serde_json::from_value(json_val) else {
return false;
};
let ctx = jaq_core::Ctx::<data::JustLut<Val>>::new(&self.filter.lut, Vars::new([]));
let mut out = self.filter.id.run((ctx, val)).map(unwrap_valr);
out.any(|res| match res {
Ok(v) => v.as_bool(),
Err(_) => false,
})
}
}