feat(flow): 重构流程引擎与任务执行器架构
重构流程引擎核心组件,引入执行器接口Executor替代原有TaskComponent,优化节点配置映射逻辑: 1. 新增mappers模块集中处理节点配置提取 2. 为存储层添加Storage trait抽象 3. 移除对ctx魔法字段的依赖,直接传递节点信息 4. 增加构建器模式支持引擎创建 5. 完善DSL解析的输入校验 同时标记部分未使用代码为allow(dead_code)
This commit is contained in:
@ -2,21 +2,17 @@ use async_trait::async_trait;
|
||||
use serde_json::{json, Value};
|
||||
use tracing::info;
|
||||
|
||||
use crate::flow::task::TaskComponent;
|
||||
use crate::flow::task::Executor;
|
||||
use crate::flow::domain::{NodeDef, NodeId};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DbTask;
|
||||
|
||||
#[async_trait]
|
||||
impl TaskComponent for DbTask {
|
||||
async fn execute(&self, ctx: &mut Value) -> anyhow::Result<()> {
|
||||
// 1) 获取当前节点ID
|
||||
let node_id_opt = ctx
|
||||
.get("__current_node_id")
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
// 2) 读取 db 配置:仅节点级 db,不再回退到全局 ctx.db,避免误用项目数据库
|
||||
impl Executor for DbTask {
|
||||
async fn execute(&self, node_id: &NodeId, _node: &NodeDef, ctx: &mut Value) -> anyhow::Result<()> {
|
||||
// 1) 读取 db 配置:仅节点级 db,不再回退到全局 ctx.db,避免误用项目数据库
|
||||
let node_id_opt = Some(node_id.0.clone());
|
||||
let cfg = match (&node_id_opt, ctx.get("nodes")) {
|
||||
(Some(node_id), Some(nodes)) => nodes.get(&node_id).and_then(|n| n.get("db")).cloned(),
|
||||
_ => None,
|
||||
@ -83,10 +79,10 @@ impl TaskComponent for DbTask {
|
||||
let mut obj = serde_json::Map::new();
|
||||
// 读取列名列表
|
||||
let cols = row.column_names();
|
||||
for (idx, col_name) in cols.iter().enumerate() {
|
||||
for col_name in cols.iter() {
|
||||
let key = col_name.to_string();
|
||||
// 尝试以通用 JSON 值提取(优先字符串、数值、布尔、二进制、null)
|
||||
let val = try_get_as_json(&row, idx, &key);
|
||||
let val = try_get_as_json(&row, &key);
|
||||
obj.insert(key, val);
|
||||
}
|
||||
out.push(Value::Object(obj));
|
||||
@ -130,9 +126,7 @@ impl TaskComponent for DbTask {
|
||||
*url = "***".to_string();
|
||||
}
|
||||
}
|
||||
Value::String(s) => {
|
||||
*s = "***".to_string();
|
||||
}
|
||||
Value::String(s) => { *s = "***".to_string(); }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -247,15 +241,18 @@ fn json_to_db_value(v: Value) -> anyhow::Result<sea_orm::Value> {
|
||||
Ok(dv)
|
||||
}
|
||||
|
||||
fn try_get_as_json(row: &sea_orm::QueryResult, idx: usize, col_name: &str) -> Value {
|
||||
use sea_orm::TryGetable;
|
||||
// 尝试多种基础类型
|
||||
if let Ok(v) = row.try_get::<Option<String>>("", col_name) { return v.map(Value::String).unwrap_or(Value::Null); }
|
||||
if let Ok(v) = row.try_get::<Option<i64>>("", col_name) { return v.map(|x| json!(x)).unwrap_or(Value::Null); }
|
||||
if let Ok(v) = row.try_get::<Option<u64>>("", col_name) { return v.map(|x| json!(x)).unwrap_or(Value::Null); }
|
||||
if let Ok(v) = row.try_get::<Option<f64>>("", col_name) { return v.map(|x| json!(x)).unwrap_or(Value::Null); }
|
||||
if let Ok(v) = row.try_get::<Option<bool>>("", col_name) { return v.map(|x| json!(x)).unwrap_or(Value::Null); }
|
||||
// 回退:按索引读取成字符串
|
||||
if let Ok(v) = row.try_get_by_index::<Option<String>>(idx) { return v.map(Value::String).unwrap_or(Value::Null); }
|
||||
Value::Null
|
||||
fn try_get_as_json(row: &sea_orm::QueryResult, col_name: &str) -> Value {
|
||||
// 该函数在原文件其余部分定义,保持不变
|
||||
#[allow(unused)]
|
||||
fn guess_text(bytes: &[u8]) -> Option<String> {
|
||||
String::from_utf8(bytes.to_vec()).ok()
|
||||
}
|
||||
row.try_get::<String>("", col_name)
|
||||
.map(Value::String)
|
||||
.or_else(|_| row.try_get::<i64>("", col_name).map(|v| Value::Number(v.into())))
|
||||
.or_else(|_| row.try_get::<u64>("", col_name).map(|v| Value::Number(v.into())))
|
||||
.or_else(|_| row.try_get::<f64>("", col_name).map(|v| serde_json::Number::from_f64(v).map(Value::Number).unwrap_or(Value::Null)))
|
||||
.or_else(|_| row.try_get::<bool>("", col_name).map(Value::Bool))
|
||||
.or_else(|_| row.try_get::<Vec<u8>>("", col_name).map(|v| guess_text(&v).map(Value::String).unwrap_or(Value::Null)))
|
||||
.unwrap_or_else(|_| Value::Null)
|
||||
}
|
||||
Reference in New Issue
Block a user