feat: 工作流适配数据中枢查询节点
- 新增查询数据与写入数据节点并移除旧数据中心节点入口 - 将查询数据节点切换为连接服务加 SQL 的执行模型 - 同步更新工作流校验、提示词上下文与设计器交互
This commit is contained in:
@@ -8,6 +8,7 @@ import org.junit.Test;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckResult;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.WorkflowCheckStage;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.node.SearchDatasetNodeParser;
|
||||
import tech.easyflow.ai.node.WorkflowNodeParser;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
|
||||
@@ -69,6 +70,24 @@ public class WorkflowCheckServiceTest {
|
||||
assertHasCode(result, "EDGE_TARGET_NOT_FOUND");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveShouldBlockSearchDatasetWithoutSql() throws Exception {
|
||||
WorkflowCheckService service = newService(new HashMap<>());
|
||||
JSONObject searchData = data("查询数据");
|
||||
JSONObject datasetRef = new JSONObject();
|
||||
datasetRef.put("sourceId", "1001");
|
||||
datasetRef.put("tableId", "2001");
|
||||
searchData.put("datasetRef", datasetRef);
|
||||
String content = workflowJson(
|
||||
array(node("search-1", "search-dataset-node", null, searchData)),
|
||||
new JSONArray()
|
||||
);
|
||||
|
||||
WorkflowCheckResult result = service.checkContent(content, WorkflowCheckStage.SAVE, null);
|
||||
Assert.assertFalse(result.isPassed());
|
||||
assertHasCode(result, "SEARCH_DATASET_INVALID");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreExecuteShouldBlockMissingStartOrEnd() throws Exception {
|
||||
WorkflowCheckService service = newService(new HashMap<>());
|
||||
@@ -86,6 +105,26 @@ public class WorkflowCheckServiceTest {
|
||||
assertHasCode(result, "END_NODE_MISSING");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreExecuteShouldPassForSourceOnlySearchDatasetNode() throws Exception {
|
||||
WorkflowCheckService service = newService(new HashMap<>());
|
||||
String content = workflowJson(
|
||||
array(
|
||||
node("s1", "startNode", null, data("开始")),
|
||||
searchDatasetNode("q1", null, "1001"),
|
||||
node("e1", "endNode", null, data("结束"))
|
||||
),
|
||||
array(
|
||||
edge("e1", "s1", "q1"),
|
||||
edge("e2", "q1", "e1")
|
||||
)
|
||||
);
|
||||
|
||||
WorkflowCheckResult result = service.checkContent(content, WorkflowCheckStage.PRE_EXECUTE, BigInteger.ONE);
|
||||
Assert.assertTrue(result.isPassed());
|
||||
Assert.assertEquals(0, result.getIssueCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreExecuteShouldBlockRootEntryNotStart() throws Exception {
|
||||
WorkflowCheckService service = newService(new HashMap<>());
|
||||
@@ -203,8 +242,10 @@ public class WorkflowCheckServiceTest {
|
||||
.withDefaultParsers(true)
|
||||
.build();
|
||||
parser.addNodeParser("workflow-node", new WorkflowNodeParser());
|
||||
parser.addNodeParser("search-dataset-node", new SearchDatasetNodeParser());
|
||||
setField(service, "chainParser", parser);
|
||||
setField(service, "workflowService", mockWorkflowService(workflowStore));
|
||||
setField(service, "workflowDatacenterContentService", new WorkflowDatacenterContentService());
|
||||
return service;
|
||||
}
|
||||
|
||||
@@ -294,6 +335,15 @@ public class WorkflowCheckServiceTest {
|
||||
return node(id, "workflow-node", parentId, data);
|
||||
}
|
||||
|
||||
private static JSONObject searchDatasetNode(String id, String parentId, String sourceId) {
|
||||
JSONObject data = data("查询数据");
|
||||
JSONObject datasetRef = new JSONObject();
|
||||
datasetRef.put("sourceId", sourceId);
|
||||
data.put("datasetRef", datasetRef);
|
||||
data.put("querySql", "SELECT 1");
|
||||
return node(id, "search-dataset-node", parentId, data);
|
||||
}
|
||||
|
||||
private static JSONObject data(String title) {
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("title", title);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package tech.easyflow.ai.node;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.datacenter.execution.model.DatasetRef;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SearchDatasetNodeTest {
|
||||
|
||||
@Test
|
||||
public void testResolveQuerySqlShouldUseNodeQuerySqlAndResolveTemplate() throws Exception {
|
||||
DatasetRef datasetRef = new DatasetRef();
|
||||
datasetRef.setSourceId(BigInteger.valueOf(1001L));
|
||||
SearchDatasetNode node = new SearchDatasetNode(datasetRef, """
|
||||
SELECT id, name
|
||||
FROM orders_{{biz}}
|
||||
WHERE name LIKE '%{{keyword}}%'
|
||||
ORDER BY created_at {{direction}}
|
||||
""");
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("biz", "prod");
|
||||
params.put("keyword", "vip");
|
||||
params.put("direction", "DESC");
|
||||
|
||||
String sql = invokeResolveQuerySql(node, params);
|
||||
Assert.assertEquals("""
|
||||
SELECT id, name
|
||||
FROM orders_prod
|
||||
WHERE name LIKE '%vip%'
|
||||
ORDER BY created_at DESC
|
||||
""".trim(), sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveQuerySqlShouldUseNodeQuerySqlWhenParamsDoNotContainSql() throws Exception {
|
||||
DatasetRef datasetRef = new DatasetRef();
|
||||
datasetRef.setSourceId(BigInteger.valueOf(2002L));
|
||||
SearchDatasetNode node = new SearchDatasetNode(datasetRef, "SELECT * FROM fallback_table");
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
|
||||
String sql = invokeResolveQuerySql(node, params);
|
||||
Assert.assertEquals("SELECT * FROM fallback_table", sql);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveQuerySqlShouldRejectBlankSql() throws Exception {
|
||||
DatasetRef datasetRef = new DatasetRef();
|
||||
datasetRef.setSourceId(BigInteger.valueOf(3003L));
|
||||
SearchDatasetNode node = new SearchDatasetNode(datasetRef, " ");
|
||||
|
||||
try {
|
||||
invokeResolveQuerySql(node, new HashMap<>());
|
||||
Assert.fail("expected BusinessException");
|
||||
} catch (Exception e) {
|
||||
Throwable cause = e.getCause() == null ? e : e.getCause();
|
||||
Assert.assertTrue(cause instanceof BusinessException);
|
||||
Assert.assertEquals("查询数据节点未设置 SQL", cause.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String invokeResolveQuerySql(SearchDatasetNode node, Map<String, Object> params) throws Exception {
|
||||
Method method = SearchDatasetNode.class.getDeclaredMethod("resolveQuerySql", Map.class);
|
||||
method.setAccessible(true);
|
||||
return (String) method.invoke(node, params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user