use std::sync::Arc;
use minijinja::{State, Value, value::Object};
use taganak_core::graphs::Graph;
use taganak_framework::prelude::TryStreamExt;
use taganak_orm::re::{GraphView, Term};
use tokio::runtime::Handle;
use tracing::trace;
use crate::{
ParamsWithEnv,
res::{object::TermList, str_to_term},
};
#[derive(Debug, Clone)]
pub struct GraphFn<'e, G> {
params: ParamsWithEnv<'e, G>,
}
impl<'e, G> GraphFn<'e, G>
where
G: Graph + std::fmt::Debug + Sync + 'static,
{
pub fn new(params: ParamsWithEnv<'e, G>) -> Self {
Self { params }
}
}
impl<G> Object for GraphFn<'_, G>
where
G: Graph + std::fmt::Debug + Sync + 'static,
Self: 'static,
{
fn call(
self: &Arc<Self>,
_state: &State<'_, '_>,
args: &[Value],
) -> Result<Value, minijinja::Error> {
if args.len() < 2 {
return Err(minijinja::Error::new(
minijinja::ErrorKind::MissingArgument,
"needs predicate and object",
));
}
if args.len() > 2 {
return Err(minijinja::Error::new(
minijinja::ErrorKind::TooManyArguments,
"too many arguments",
));
}
let handle = Handle::current();
handle.block_on(async {
let subject = if args[0].is_none() {
None
} else {
Some(str_to_term(self.params.clone().to_params(), &args[0].to_string()).unwrap())
};
let predicate = if args[1].is_none() {
None
} else {
Some(str_to_term(self.params.clone().to_params(), &args[1].to_string()).unwrap())
};
trace!(?subject, ?predicate, "finding matching subjects");
let graph = self.params.graph.read().unwrap();
let view = graph.view().await;
static LIMIT: usize = 256;
let objects = view
.objects(subject.as_ref(), predicate.as_ref(), Some(LIMIT))
.await
.unwrap()
.try_collect::<Vec<Arc<Term>>>()
.await
.unwrap();
Ok(Value::from_object(TermList::new(
self.params.clone(),
objects,
)))
})
}
}