Generate executable business action effects
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
package com.ruoyi.generator.domain.front.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BusinessActionEffectDesign
|
||||
{
|
||||
private String type;
|
||||
private String targetTable;
|
||||
private String targetField;
|
||||
private String value;
|
||||
private List<String> conditionFields;
|
||||
private String description;
|
||||
|
||||
public String getType() { return type; }
|
||||
@@ -16,6 +19,8 @@ public class BusinessActionEffectDesign
|
||||
public void setTargetField(String targetField) { this.targetField = targetField; }
|
||||
public String getValue() { return value; }
|
||||
public void setValue(String value) { this.value = value; }
|
||||
public List<String> getConditionFields() { return conditionFields; }
|
||||
public void setConditionFields(List<String> conditionFields) { this.conditionFields = conditionFields; }
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
}
|
||||
|
||||
@@ -135,6 +135,7 @@ public class AiBusinessBlueprintValidator
|
||||
{
|
||||
throw new ServiceException("业务影响目标字段不存在:" + effect.getTargetField());
|
||||
}
|
||||
validateEffectConditionFields(effect, columnNames);
|
||||
if (StringUtils.defaultString(effect.getValue()).length() > 200
|
||||
|| StringUtils.defaultString(effect.getDescription()).length() > 200)
|
||||
{
|
||||
@@ -143,6 +144,21 @@ public class AiBusinessBlueprintValidator
|
||||
}
|
||||
}
|
||||
|
||||
private void validateEffectConditionFields(BusinessActionEffectDesign effect, Set<String> columnNames)
|
||||
{
|
||||
if (StringUtils.isEmpty(effect.getConditionFields()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (String field : effect.getConditionFields())
|
||||
{
|
||||
if (StringUtils.isBlank(field) || !columnNames.contains(field))
|
||||
{
|
||||
throw new ServiceException("业务影响条件字段不存在:" + StringUtils.defaultString(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> collectTableNames(List<DatabaseTableDesign> tables)
|
||||
{
|
||||
Set<String> tableNames = new HashSet<String>();
|
||||
|
||||
@@ -109,9 +109,9 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
||||
private String buildPrompt(FrontProject project, GenerateDatabaseRequest request)
|
||||
{
|
||||
StringBuilder prompt = new StringBuilder();
|
||||
prompt.append("请为企业管理系统生成MySQL数据库设计和业务蓝图草稿,只返回JSON,格式为{\"tables\":[{\"tableName\":\"car_info\",\"tableComment\":\"车辆信息表\",\"columns\":[]}],\"businessActions\":[{\"code\":\"borrow_book\",\"name\":\"借书\",\"ownerTable\":\"borrow_record\",\"method\":\"POST\",\"path\":\"/library/borrow/borrow\",\"transaction\":true,\"requestFields\":[\"book_id\"],\"rules\":[\"图书必须可借\"],\"effects\":[{\"type\":\"UPDATE_FIELD\",\"targetTable\":\"book_info\",\"targetField\":\"stock\",\"value\":\"stock - 1\",\"description\":\"库存减一\"}]}]}。\n");
|
||||
prompt.append("请为企业管理系统生成MySQL数据库设计和业务蓝图草稿,只返回JSON,格式为{\"tables\":[{\"tableName\":\"car_info\",\"tableComment\":\"车辆信息表\",\"columns\":[]}],\"businessActions\":[{\"code\":\"borrow_book\",\"name\":\"借书\",\"ownerTable\":\"borrow_record\",\"method\":\"POST\",\"path\":\"/library/borrow/borrow\",\"transaction\":true,\"requestFields\":[\"book_id\"],\"rules\":[\"图书必须可借\"],\"effects\":[{\"type\":\"UPDATE_FIELD\",\"targetTable\":\"book_info\",\"targetField\":\"stock\",\"value\":\"stock - 1\",\"conditionFields\":[\"book_id\"],\"description\":\"库存减一\"}]}]}。\n");
|
||||
prompt.append("限制:表名和字段名使用小写字母、数字、下划线;必须且只能有一个主键;字段类型只能使用bigint(20)、int(11)、varchar(n)、char(n)、decimal(p,s)、datetime、date、text、longtext。\n");
|
||||
prompt.append("业务蓝图限制:businessActions只描述业务动作草稿,不直接返回代码;ownerTable、requestFields、effects.targetTable、effects.targetField必须引用已生成的表和字段;method只用GET、POST、PUT、DELETE。\n");
|
||||
prompt.append("业务蓝图限制:businessActions只描述业务动作DSL,不直接返回代码;ownerTable、requestFields、effects.targetTable、effects.targetField、effects.conditionFields必须引用已生成的表和字段;method只用GET、POST、PUT、DELETE;effects.type优先使用UPDATE_FIELD,conditionFields表示更新或删除时的WHERE条件字段。\n");
|
||||
prompt.append("项目名称:").append(firstNonBlank(request == null ? null : request.getProjectName(), project.getProjectName())).append("\n");
|
||||
prompt.append("项目描述:").append(firstNonBlank(request == null ? null : request.getProjectDesc(), project.getProjectDesc())).append("\n");
|
||||
prompt.append("行业模板:").append(firstNonBlank(request == null ? null : request.getIndustryTemplate(), project.getIndustryTemplate())).append("\n");
|
||||
@@ -313,7 +313,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
||||
action.setTransaction(action.getTransaction() == null ? Boolean.TRUE : action.getTransaction());
|
||||
action.setRequestFields(normalizeExistingFieldList(action.getRequestFields(), columnNames));
|
||||
action.setRules(trimStringList(action.getRules(), 200));
|
||||
normalizeBusinessEffects(action);
|
||||
normalizeBusinessEffects(action, columnNames);
|
||||
actionIndex++;
|
||||
}
|
||||
}
|
||||
@@ -422,7 +422,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
||||
return normalizedValues;
|
||||
}
|
||||
|
||||
private void normalizeBusinessEffects(BusinessActionDesign action)
|
||||
private void normalizeBusinessEffects(BusinessActionDesign action, Set<String> columnNames)
|
||||
{
|
||||
if (action.getEffects() == null)
|
||||
{
|
||||
@@ -440,6 +440,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
|
||||
effect.setTargetTable(StringUtils.isBlank(effect.getTargetTable()) ? "" : normalizeDatabaseName(effect.getTargetTable(), "table_" + effectIndex));
|
||||
effect.setTargetField(StringUtils.isBlank(effect.getTargetField()) ? "" : normalizeDatabaseName(effect.getTargetField(), "field_" + effectIndex));
|
||||
effect.setValue(trimToLength(effect.getValue(), 200));
|
||||
effect.setConditionFields(normalizeExistingFieldList(effect.getConditionFields(), columnNames));
|
||||
effect.setDescription(trimToLength(effect.getDescription(), 200));
|
||||
effectIndex++;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -169,6 +173,20 @@ public class GenProjectServiceImplTest {
|
||||
assertFalse(content.contains("return_book"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void businessBlueprintSqlTemplateGeneratesExecutableActionEffects() throws Exception {
|
||||
Path sqlPath = Paths.get("sql/business_blueprint_templates.sql");
|
||||
if (!Files.exists(sqlPath)) {
|
||||
sqlPath = Paths.get("../sql/business_blueprint_templates.sql");
|
||||
}
|
||||
String sql = new String(Files.readAllBytes(sqlPath), StandardCharsets.UTF_8);
|
||||
|
||||
assertFalse(sql.contains("Business action not implemented"));
|
||||
assertTrue(sql.contains("executeUpdateFieldEffect"));
|
||||
assertTrue(sql.contains("jdbcTemplate.update"));
|
||||
assertTrue(sql.contains("conditionFields"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProjectStructureForDraftProjectUsesFirstActiveTemplateWithoutLoadingProject() {
|
||||
GenProject project = project();
|
||||
|
||||
@@ -94,6 +94,7 @@ public class AiGenerateServiceImplTest
|
||||
ArgumentCaptor<String> promptCaptor = ArgumentCaptor.forClass(String.class);
|
||||
verify(deepSeekClient).chat(promptCaptor.capture());
|
||||
assertTrue(promptCaptor.getValue().contains("businessActions"));
|
||||
assertTrue(promptCaptor.getValue().contains("conditionFields"));
|
||||
ArgumentCaptor<FrontProject> projectCaptor = ArgumentCaptor.forClass(FrontProject.class);
|
||||
verify(frontProjectMapper).updateFrontProject(projectCaptor.capture());
|
||||
assertEquals(Long.valueOf(10L), projectCaptor.getValue().getProjectId());
|
||||
@@ -233,6 +234,7 @@ public class AiGenerateServiceImplTest
|
||||
assertEquals("UPDATE_FIELD", effect.getType());
|
||||
assertEquals("book_info", effect.getTargetTable());
|
||||
assertEquals("stock", effect.getTargetField());
|
||||
assertEquals("book_id", effect.getConditionFields().get(0));
|
||||
|
||||
ArgumentCaptor<FrontProject> projectCaptor = ArgumentCaptor.forClass(FrontProject.class);
|
||||
verify(frontProjectMapper).updateFrontProject(projectCaptor.capture());
|
||||
@@ -522,7 +524,7 @@ public class AiGenerateServiceImplTest
|
||||
+ " \"requestFields\": [\"book_id\", \"reader_id\"],\n"
|
||||
+ " \"rules\": [\"读者状态必须正常\", \"图书库存必须大于0\"],\n"
|
||||
+ " \"effects\": [\n"
|
||||
+ " {\"type\": \"update_field\", \"targetTable\": \"book_info\", \"targetField\": \"stock\", \"value\": \"stock - 1\", \"description\": \"图书库存减一\"}\n"
|
||||
+ " {\"type\": \"update_field\", \"targetTable\": \"book_info\", \"targetField\": \"stock\", \"value\": \"stock - 1\", \"conditionFields\": [\"book_id\"], \"description\": \"图书库存减一\"}\n"
|
||||
+ " ]\n"
|
||||
+ " }\n"
|
||||
+ " ]\n"
|
||||
|
||||
Reference in New Issue
Block a user