feat: custom node (#138)

* feat: custom node

* add zen template, expose $nodes and $root

* add custom handler to go and nodejs

* add support for python, improve bindings, add error to zen template

* fix: correct binding exports for nodejs and python

* fix benchmark

* improve rust api, trim template in zen templates

* update cargo action

* update expression version

* compile action

* fix action format
This commit is contained in:
stefan-gorules
2024-04-03 16:09:51 +02:00
committed by GitHub
parent 685a0345f5
commit daecf901e6
65 changed files with 1729 additions and 235 deletions
+22 -9
View File
@@ -1,5 +1,7 @@
use crate::custom_node::CustomNode;
use crate::decision::ZenDecision;
use crate::loader::DecisionLoader;
use crate::types::ZenEngineResponse;
use napi::anyhow::{anyhow, Context};
use napi::bindgen_prelude::Buffer;
use napi::{tokio, Env, JsFunction};
@@ -11,7 +13,7 @@ use zen_engine::{DecisionEngine, EvaluationOptions};
#[napi]
pub struct ZenEngine {
graph: Arc<DecisionEngine<DecisionLoader>>,
graph: Arc<DecisionEngine<DecisionLoader, CustomNode>>,
}
#[napi(object)]
@@ -33,6 +35,9 @@ impl Default for ZenEvaluateOptions {
pub struct ZenEngineOptions {
#[napi(ts_type = "(key: string) => Promise<Buffer>")]
pub loader: Option<JsFunction>,
#[napi(ts_type = "(request: ZenEngineHandlerRequest) => Promise<ZenEngineHandlerResponse>")]
pub custom_handler: Option<JsFunction>,
}
#[napi]
@@ -41,18 +46,26 @@ impl ZenEngine {
pub fn new(mut env: Env, options: Option<ZenEngineOptions>) -> napi::Result<Self> {
let Some(opts) = options else {
return Ok(Self {
graph: DecisionEngine::new(DecisionLoader::default()).into(),
graph: DecisionEngine::new(
DecisionLoader::default().into(),
CustomNode::default().into(),
)
.into(),
});
};
let Some(loader_fn) = opts.loader else {
return Ok(Self {
graph: DecisionEngine::new(DecisionLoader::default()).into(),
});
let loader = match opts.loader {
None => DecisionLoader::default(),
Some(loader_fn) => DecisionLoader::try_new(&mut env, loader_fn)?,
};
let custom_handler = match opts.custom_handler {
None => CustomNode::default(),
Some(custom_fn) => CustomNode::try_new(&mut env, custom_fn)?,
};
Ok(Self {
graph: DecisionEngine::new(DecisionLoader::try_new(&mut env, loader_fn)?).into(),
graph: DecisionEngine::new(loader.into(), custom_handler.into()).into(),
})
}
@@ -62,7 +75,7 @@ impl ZenEngine {
key: String,
context: Value,
opts: Option<ZenEvaluateOptions>,
) -> napi::Result<Value> {
) -> napi::Result<ZenEngineResponse> {
let graph = self.graph.clone();
let result = tokio::spawn(async move {
let options = opts.unwrap_or_default();
@@ -82,7 +95,7 @@ impl ZenEngine {
anyhow!(serde_json::to_string(e.as_ref()).unwrap_or_else(|_| e.to_string()))
})?;
Ok(serde_json::to_value(&result)?)
Ok(ZenEngineResponse::from(result))
}
#[napi]