mirror of
https://github.com/gorules/zen.git
synced 2026-10-07 16:02:26 +00:00
feat: rc variable (#246)
* feat: rc variable * feat: implement variable in engine * add exports * fix bindings and improve clone accuracy * fix tests, fix bindings * fix fmt * improve code
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rquickjs::promise::MaybePromise;
|
||||
use rquickjs::{async_with, AsyncContext, AsyncRuntime, CatchResultExt, Ctx, Module};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::handler::function::error::{FunctionError, FunctionResult, ResultExt};
|
||||
use crate::handler::function::listener::{RuntimeEvent, RuntimeListener};
|
||||
use crate::handler::function::module::console::{Console, Log};
|
||||
use crate::handler::function::module::ModuleLoader;
|
||||
use crate::handler::function::serde::JsValue;
|
||||
use rquickjs::promise::MaybePromise;
|
||||
use rquickjs::{async_with, AsyncContext, AsyncRuntime, CatchResultExt, Ctx, Module};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zen_expression::variable::Variable;
|
||||
|
||||
pub struct FunctionConfig {
|
||||
pub(crate) listeners: Option<Vec<Box<dyn RuntimeListener>>>,
|
||||
@@ -49,7 +48,7 @@ impl Function {
|
||||
};
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn dispatch_event(&self, event: RuntimeEvent) -> FunctionResult {
|
||||
@@ -121,5 +120,5 @@ impl Function {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct HandlerResponse {
|
||||
pub logs: Vec<Log>,
|
||||
pub data: Value,
|
||||
pub data: Variable,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
use crate::handler::function::error::ResultExt;
|
||||
use crate::handler::function::module::export_default;
|
||||
use crate::handler::function::serde::JsValue;
|
||||
use reqwest::header::{HeaderMap, HeaderName};
|
||||
use reqwest::Method;
|
||||
use rquickjs::module::{Declarations, Exports, ModuleDef};
|
||||
@@ -5,10 +8,7 @@ use rquickjs::prelude::{Async, Func, Opt};
|
||||
use rquickjs::{CatchResultExt, Ctx, FromJs, IntoAtom, IntoJs, Object, Value};
|
||||
use std::str::FromStr;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::handler::function::error::ResultExt;
|
||||
use crate::handler::function::module::export_default;
|
||||
use crate::handler::function::serde::JsValue;
|
||||
use zen_expression::variable::Variable;
|
||||
|
||||
pub(crate) struct HttpResponse<'js> {
|
||||
data: Value<'js>,
|
||||
@@ -62,7 +62,7 @@ async fn execute_http<'js>(
|
||||
)?;
|
||||
}
|
||||
|
||||
let data: serde_json::Value = response.json().await.or_throw(&ctx)?;
|
||||
let data: Variable = response.json().await.or_throw(&ctx)?;
|
||||
|
||||
Ok(HttpResponse {
|
||||
data: JsValue(data).into_js(&ctx)?,
|
||||
@@ -91,12 +91,12 @@ impl<'js> FromJs<'js> for HttpConfig {
|
||||
|
||||
let value = JsValue::from_js(ctx, value)?;
|
||||
let str_value = match value.0 {
|
||||
serde_json::Value::Null => None,
|
||||
serde_json::Value::Bool(b) => Some(b.to_string()),
|
||||
serde_json::Value::Number(n) => Some(n.to_string()),
|
||||
serde_json::Value::String(s) => Some(s),
|
||||
serde_json::Value::Array(_) => None,
|
||||
serde_json::Value::Object(_) => None,
|
||||
Variable::Null => None,
|
||||
Variable::Bool(b) => Some(b.to_string()),
|
||||
Variable::Number(n) => Some(n.to_string()),
|
||||
Variable::String(s) => Some(s.to_string()),
|
||||
Variable::Array(_) => None,
|
||||
Variable::Object(_) => None,
|
||||
};
|
||||
|
||||
let key_value = key.to_string()?;
|
||||
@@ -121,12 +121,12 @@ impl<'js> FromJs<'js> for HttpConfig {
|
||||
|
||||
let value = JsValue::from_js(ctx, value)?;
|
||||
let str_value = match value.0 {
|
||||
serde_json::Value::Null => None,
|
||||
serde_json::Value::Bool(b) => Some(b.to_string()),
|
||||
serde_json::Value::Number(n) => Some(n.to_string()),
|
||||
serde_json::Value::String(s) => Some(s),
|
||||
serde_json::Value::Array(_) => None,
|
||||
serde_json::Value::Object(_) => None,
|
||||
Variable::Null => None,
|
||||
Variable::Bool(b) => Some(b.to_string()),
|
||||
Variable::Number(n) => Some(n.to_string()),
|
||||
Variable::String(s) => Some(s.to_string()),
|
||||
Variable::Array(_) => None,
|
||||
Variable::Object(_) => None,
|
||||
};
|
||||
|
||||
let key = key.to_string()?;
|
||||
|
||||
@@ -2,10 +2,6 @@ use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rquickjs::module::{Declarations, Exports, ModuleDef};
|
||||
use rquickjs::prelude::{Async, Func, Opt};
|
||||
use rquickjs::{CatchResultExt, Ctx, Function, Object};
|
||||
|
||||
use crate::handler::custom_node_adapter::CustomNodeAdapter;
|
||||
use crate::handler::function::error::{FunctionResult, ResultExt};
|
||||
use crate::handler::function::listener::{RuntimeEvent, RuntimeListener};
|
||||
@@ -13,6 +9,9 @@ use crate::handler::function::module::export_default;
|
||||
use crate::handler::function::serde::JsValue;
|
||||
use crate::handler::graph::{DecisionGraph, DecisionGraphConfig};
|
||||
use crate::loader::DecisionLoader;
|
||||
use rquickjs::module::{Declarations, Exports, ModuleDef};
|
||||
use rquickjs::prelude::{Async, Func, Opt};
|
||||
use rquickjs::{CatchResultExt, Ctx, Function, Object};
|
||||
|
||||
pub(crate) struct ZenListener<Loader, Adapter> {
|
||||
pub loader: Arc<Loader>,
|
||||
@@ -68,11 +67,10 @@ impl<Loader: DecisionLoader + 'static, Adapter: CustomNodeAdapter + 'static> Run
|
||||
})
|
||||
.or_throw(&ctx)?;
|
||||
|
||||
let response =
|
||||
sub_tree.evaluate(&context.0).await.or_throw(&ctx)?;
|
||||
return rquickjs::Result::Ok(JsValue(
|
||||
serde_json::to_value(response).or_throw(&ctx)?,
|
||||
));
|
||||
let response = sub_tree.evaluate(context.0).await.or_throw(&ctx)?;
|
||||
let k = serde_json::to_value(response).or_throw(&ctx)?.into();
|
||||
|
||||
return rquickjs::Result::Ok(JsValue(k));
|
||||
}
|
||||
},
|
||||
)),
|
||||
@@ -89,7 +87,7 @@ fn evaluate_expression<'js>(
|
||||
expression: String,
|
||||
context: JsValue,
|
||||
) -> rquickjs::Result<JsValue> {
|
||||
let s = zen_expression::evaluate_expression(expression.as_str(), &context.0).or_throw(&ctx)?;
|
||||
let s = zen_expression::evaluate_expression(expression.as_str(), context.0).or_throw(&ctx)?;
|
||||
|
||||
Ok(JsValue(s))
|
||||
}
|
||||
@@ -99,8 +97,8 @@ fn evaluate_unary_expression<'js>(
|
||||
expression: String,
|
||||
context: JsValue,
|
||||
) -> rquickjs::Result<bool> {
|
||||
let s = zen_expression::evaluate_unary_expression(expression.as_str(), &context.0)
|
||||
.or_throw(&ctx)?;
|
||||
let s =
|
||||
zen_expression::evaluate_unary_expression(expression.as_str(), context.0).or_throw(&ctx)?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
@@ -1,84 +1,87 @@
|
||||
use crate::handler::function::error::ResultExt;
|
||||
use itertools::Itertools;
|
||||
use ahash::{HashMap, HashMapExt};
|
||||
use rquickjs::{Ctx, FromJs, IntoAtom, IntoJs, Type, Value as QValue};
|
||||
use serde_json::{json, Map, Number, Value};
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
use rust_decimal::Decimal;
|
||||
use serde_json::json;
|
||||
use std::rc::Rc;
|
||||
use zen_expression::variable::Variable;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct JsValue(pub(crate) Value);
|
||||
pub(crate) struct JsValue(pub(crate) Variable);
|
||||
|
||||
impl<'js> FromJs<'js> for JsValue {
|
||||
fn from_js(ctx: &Ctx<'js>, v: QValue<'js>) -> rquickjs::Result<Self> {
|
||||
let computed_value = match v.type_of() {
|
||||
Type::Uninitialized | Type::Undefined | Type::Null => Value::Null,
|
||||
Type::Bool => Value::Bool(v.as_bool().or_throw_msg(ctx, "failed to convert to bool")?),
|
||||
Type::Int => Value::Number(Number::from(
|
||||
Type::Uninitialized | Type::Undefined | Type::Null => Variable::Null,
|
||||
Type::Bool => {
|
||||
Variable::Bool(v.as_bool().or_throw_msg(ctx, "failed to convert to bool")?)
|
||||
}
|
||||
Type::Int => Variable::Number(Decimal::from(
|
||||
v.as_int().or_throw_msg(ctx, "failed to convert to int")?,
|
||||
)),
|
||||
Type::BigInt => Value::Number(Number::from(
|
||||
v.as_big_int()
|
||||
Type::BigInt => Variable::Number(Decimal::from(
|
||||
v.into_big_int()
|
||||
.map(|b| b.clone().to_i64().ok())
|
||||
.flatten()
|
||||
.or_throw_msg(ctx, "failed to convert to number")?,
|
||||
)),
|
||||
Type::Float => Value::Number(
|
||||
v.as_float()
|
||||
.map(|n| Number::from_f64(n))
|
||||
.flatten()
|
||||
.or_throw_msg(ctx, "failed to convert to number")?,
|
||||
Type::Float => Variable::Number(
|
||||
Decimal::try_from(
|
||||
v.as_float()
|
||||
.or_throw_msg(ctx, "failed to convert to number")?,
|
||||
)
|
||||
.or_throw_msg(ctx, "failed to convert to number")?,
|
||||
),
|
||||
Type::String => Value::String(
|
||||
v.as_string()
|
||||
Type::String => Variable::String(
|
||||
v.into_string()
|
||||
.map(|s| s.to_string().ok())
|
||||
.flatten()
|
||||
.map(|s| Rc::from(s.as_str()))
|
||||
.or_throw_msg(ctx, "failed to convert to string")?,
|
||||
),
|
||||
Type::Array => {
|
||||
let arr = v
|
||||
.as_array()
|
||||
.into_array()
|
||||
.or_throw_msg(ctx, "failed to convert to array")?;
|
||||
|
||||
let js_arr: Vec<Value> = arr
|
||||
.iter::<QValue>()
|
||||
.map_ok(|n| JsValue::from_js(ctx, n.clone()).map(|js_val| js_val.0))
|
||||
.flatten()
|
||||
.try_collect()
|
||||
.or_throw(ctx)?;
|
||||
let mut js_arr = Vec::with_capacity(arr.len());
|
||||
for x in arr.into_iter() {
|
||||
js_arr.push(JsValue::from_js(ctx, x.or_throw(ctx)?).or_throw(ctx)?.0)
|
||||
}
|
||||
|
||||
Value::Array(js_arr)
|
||||
Variable::from_array(js_arr)
|
||||
}
|
||||
Type::Object => {
|
||||
let object = v
|
||||
.as_object()
|
||||
.into_object()
|
||||
.or_throw_msg(ctx, "failed to convert to object")?;
|
||||
|
||||
let js_object: Map<String, Value> = object
|
||||
.props::<String, QValue>()
|
||||
.map_ok(|(key, value)| {
|
||||
JsValue::from_js(ctx, value.clone()).map(|js_val| (key, js_val.0))
|
||||
})
|
||||
.flatten()
|
||||
.try_collect()
|
||||
.or_throw(ctx)?;
|
||||
let mut js_object = HashMap::with_capacity(object.len());
|
||||
for p in object.props() {
|
||||
let (k, v) = p.or_throw(ctx)?;
|
||||
js_object.insert(k, JsValue::from_js(ctx, v).or_throw(ctx)?.0);
|
||||
}
|
||||
|
||||
Value::Object(js_object)
|
||||
Variable::from_object(js_object)
|
||||
}
|
||||
Type::Exception => {
|
||||
let exception = v
|
||||
.as_exception()
|
||||
.into_exception()
|
||||
.or_throw_msg(ctx, "failed to convert to exception")?;
|
||||
|
||||
let message = exception.message().unwrap_or_default();
|
||||
let description = exception.to_string();
|
||||
|
||||
json!({ "message": message, "description": description })
|
||||
json!({ "message": message, "description": description }).into()
|
||||
}
|
||||
Type::Function => json!("[Function]"),
|
||||
Type::Module => json!("[Module]"),
|
||||
Type::Constructor => json!("[Constructor]"),
|
||||
Type::Symbol => json!("[Symbol]"),
|
||||
Type::Unknown => json!("[Unknown]"),
|
||||
Type::Function => json!("[Function]").into(),
|
||||
Type::Module => json!("[Module]").into(),
|
||||
Type::Constructor => json!("[Constructor]").into(),
|
||||
Type::Symbol => json!("[Symbol]").into(),
|
||||
Type::Unknown => json!("[Unknown]").into(),
|
||||
Type::Promise => {
|
||||
let promise = v.as_promise().or_throw(ctx)?;
|
||||
let promise = v.into_promise().or_throw(ctx)?;
|
||||
let val: JsValue = promise.finish()?;
|
||||
val.0
|
||||
}
|
||||
@@ -91,26 +94,30 @@ impl<'js> FromJs<'js> for JsValue {
|
||||
impl<'js> IntoJs<'js> for JsValue {
|
||||
fn into_js(self, ctx: &Ctx<'js>) -> rquickjs::Result<QValue<'js>> {
|
||||
let res = match self.0 {
|
||||
Value::Null => QValue::new_null(ctx.clone()),
|
||||
Value::Bool(b) => QValue::new_bool(ctx.clone(), b),
|
||||
Value::Number(n) => QValue::new_number(
|
||||
Variable::Null => QValue::new_null(ctx.clone()),
|
||||
Variable::Bool(b) => QValue::new_bool(ctx.clone(), b),
|
||||
Variable::Number(n) => QValue::new_number(
|
||||
ctx.clone(),
|
||||
n.as_f64()
|
||||
n.to_f64()
|
||||
.or_throw_msg(ctx, "failed to convert float to number")?,
|
||||
),
|
||||
Value::String(str) => str.into_js(ctx)?,
|
||||
Value::Array(arr) => {
|
||||
Variable::String(str) => str.into_js(ctx)?,
|
||||
Variable::Array(a) => {
|
||||
let qarr = rquickjs::Array::new(ctx.clone())?;
|
||||
for (idx, item) in arr.into_iter().enumerate() {
|
||||
qarr.set(idx, JsValue(item))?;
|
||||
|
||||
let arr = a.borrow();
|
||||
for (idx, item) in arr.iter().enumerate() {
|
||||
qarr.set(idx, JsValue(item.clone()))?;
|
||||
}
|
||||
|
||||
qarr.into_value()
|
||||
}
|
||||
Value::Object(map) => {
|
||||
Variable::Object(o) => {
|
||||
let qmap = rquickjs::Object::new(ctx.clone())?;
|
||||
for (key, value) in map.into_iter() {
|
||||
qmap.set(key.into_atom(ctx)?, JsValue(value))?;
|
||||
|
||||
let obj = o.borrow();
|
||||
for (key, value) in obj.iter() {
|
||||
qmap.set(key.into_atom(ctx)?, JsValue(value.clone()))?;
|
||||
}
|
||||
|
||||
qmap.into_value()
|
||||
|
||||
Reference in New Issue
Block a user