use crate::decision_graph::graph::{DecisionGraph, DecisionGraphConfig, DecisionGraphResponse};
use crate::engine::{EvaluationOptions, EvaluationSerializedOptions, EvaluationTraceKind};
use crate::loader::{DynamicLoader, NoopLoader};
use crate::model::DecisionContent;
use crate::nodes::custom::{DynamicCustomNode, NoopCustomNode};
use crate::nodes::function::http_handler::DynamicHttpHandler;
use crate::nodes::validator_cache::ValidatorCache;
use crate::nodes::NodeHandlerExtensions;
use crate::{DecisionGraphValidationError, EvaluationError};
use serde_json::Value;
use std::cell::OnceCell;
use std::sync::Arc;
use zen_expression::variable::Variable;
#[derive(Debug, Clone)]
pub struct Decision {
content: Arc<DecisionContent>,
loader: DynamicLoader,
adapter: DynamicCustomNode,
http_handler: DynamicHttpHandler,
validator_cache: ValidatorCache,
}
impl From<DecisionContent> for Decision {
fn from(value: DecisionContent) -> Self {
Self {
content: value.into(),
loader: Arc::new(NoopLoader::default()),
adapter: Arc::new(NoopCustomNode::default()),
http_handler: None,
validator_cache: ValidatorCache::default(),
}
}
}
impl From<Arc<DecisionContent>> for Decision {
fn from(value: Arc<DecisionContent>) -> Self {
Self {
content: value,
loader: Arc::new(NoopLoader::default()),
adapter: Arc::new(NoopCustomNode::default()),
http_handler: None,
validator_cache: ValidatorCache::default(),
}
}
}
impl Decision {
pub fn with_loader(mut self, loader: DynamicLoader) -> Self {
self.loader = loader;
self
}
pub fn with_adapter(mut self, adapter: DynamicCustomNode) -> Self {
self.adapter = adapter;
self
}
pub fn with_http_handler(mut self, http_handler: DynamicHttpHandler) -> Self {
self.http_handler = http_handler;
self
}
pub async fn evaluate(
&self,
context: Variable,
) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
self.evaluate_with_opts(context, Default::default()).await
}
pub async fn evaluate_with_opts(
&self,
context: Variable,
options: EvaluationOptions,
) -> Result<DecisionGraphResponse, Box<EvaluationError>> {
let mut decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
content: self.content.clone(),
max_depth: options.max_depth,
trace: options.trace,
iteration: 0,
extensions: NodeHandlerExtensions {
loader: self.loader.clone(),
custom_node: self.adapter.clone(),
http_handler: self.http_handler.clone(),
compiled_cache: self.content.compiled_cache.clone(),
validator_cache: Arc::new(OnceCell::from(self.validator_cache.clone())),
..Default::default()
},
})?;
let response = decision_graph.evaluate(context).await?;
Ok(response)
}
pub async fn evaluate_serialized(
&self,
context: Variable,
options: EvaluationSerializedOptions,
) -> Result<Value, Value> {
let response = self
.evaluate_with_opts(
context,
EvaluationOptions {
trace: options.trace != EvaluationTraceKind::None,
max_depth: options.max_depth,
},
)
.await;
match response {
Ok(ok) => Ok(ok
.serialize_with_mode(serde_json::value::Serializer, options.trace)
.unwrap_or_default()),
Err(err) => Err(err
.serialize_with_mode(serde_json::value::Serializer, options.trace)
.unwrap_or_default()),
}
}
pub fn validate(&self) -> Result<(), DecisionGraphValidationError> {
let decision_graph = DecisionGraph::try_new(DecisionGraphConfig {
content: self.content.clone(),
max_depth: 1,
trace: false,
iteration: 0,
extensions: Default::default(),
})?;
decision_graph.validate()
}
pub fn compile(&mut self) -> () {
let cm = Arc::make_mut(&mut self.content);
cm.compile();
}
}