Repair missing blueprint effect fields

This commit is contained in:
王鹏
2026-05-23 16:29:25 +08:00
parent d91161a302
commit dfbae3387f
2 changed files with 144 additions and 3 deletions

View File

@@ -1,10 +1,13 @@
package com.ruoyi.generator.service.front;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -508,6 +511,7 @@ public class AiGenerateServiceImpl implements IAiGenerateService
}
Set<String> actionCodes = new HashSet<String>();
Set<String> columnNames = collectColumnNames(response);
Map<String, Set<String>> columnNamesByTable = collectColumnNamesByTable(response);
int actionIndex = 1;
for (BusinessActionDesign action : response.getBusinessActions())
{
@@ -524,7 +528,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, columnNames);
normalizeBusinessEffects(action, columnNames, columnNamesByTable);
actionIndex++;
}
}
@@ -615,6 +619,32 @@ public class AiGenerateServiceImpl implements IAiGenerateService
return columnNames;
}
private Map<String, Set<String>> collectColumnNamesByTable(DatabaseDesignResponse response)
{
Map<String, Set<String>> columnNamesByTable = new HashMap<String, Set<String>>();
if (response == null || response.getTables() == null)
{
return columnNamesByTable;
}
for (DatabaseTableDesign table : response.getTables())
{
if (table == null || StringUtils.isBlank(table.getTableName()) || table.getColumns() == null)
{
continue;
}
Set<String> tableColumnNames = new HashSet<String>();
for (DatabaseColumnDesign column : table.getColumns())
{
if (column != null && StringUtils.isNotBlank(column.getColumnName()))
{
tableColumnNames.add(column.getColumnName());
}
}
columnNamesByTable.put(table.getTableName(), tableColumnNames);
}
return columnNamesByTable;
}
private List<String> trimStringList(List<String> values, int maxLength)
{
List<String> normalizedValues = new ArrayList<String>();
@@ -633,13 +663,14 @@ public class AiGenerateServiceImpl implements IAiGenerateService
return normalizedValues;
}
private void normalizeBusinessEffects(BusinessActionDesign action, Set<String> columnNames)
private void normalizeBusinessEffects(BusinessActionDesign action, Set<String> columnNames, Map<String, Set<String>> columnNamesByTable)
{
if (action.getEffects() == null)
{
action.setEffects(new ArrayList<BusinessActionEffectDesign>());
return;
}
List<BusinessActionEffectDesign> normalizedEffects = new ArrayList<BusinessActionEffectDesign>();
int effectIndex = 1;
for (BusinessActionEffectDesign effect : action.getEffects())
{
@@ -649,12 +680,83 @@ public class AiGenerateServiceImpl implements IAiGenerateService
}
effect.setType(normalizeEffectType(effect.getType(), effectIndex));
effect.setTargetTable(StringUtils.isBlank(effect.getTargetTable()) ? "" : normalizeDatabaseName(effect.getTargetTable(), "table_" + effectIndex));
effect.setTargetField(StringUtils.isBlank(effect.getTargetField()) ? "" : normalizeDatabaseName(effect.getTargetField(), "field_" + effectIndex));
String rawTargetField = StringUtils.isBlank(effect.getTargetField()) ? "" : normalizeDatabaseName(effect.getTargetField(), "field_" + effectIndex);
String targetField = resolveEffectTargetField(rawTargetField, effect.getTargetTable(), columnNamesByTable, columnNames);
if ("UPDATE_FIELD".equals(effect.getType()) && (StringUtils.isBlank(effect.getTargetTable()) || StringUtils.isBlank(targetField)))
{
effectIndex++;
continue;
}
effect.setTargetField(targetField);
effect.setValue(trimToLength(effect.getValue(), 200));
if (StringUtils.isNotBlank(rawTargetField) && StringUtils.isNotBlank(targetField) && !rawTargetField.equals(targetField))
{
effect.setValue(rewriteEffectValue(effect.getValue(), rawTargetField, targetField));
}
effect.setConditionFields(normalizeExistingFieldList(effect.getConditionFields(), columnNames));
effect.setDescription(trimToLength(effect.getDescription(), 200));
normalizedEffects.add(effect);
effectIndex++;
}
action.setEffects(normalizedEffects);
}
private String resolveEffectTargetField(String targetField, String targetTable, Map<String, Set<String>> columnNamesByTable, Set<String> columnNames)
{
if (StringUtils.isBlank(targetField))
{
return "";
}
Set<String> tableColumnNames = columnNamesByTable == null ? null : columnNamesByTable.get(targetTable);
if (tableColumnNames != null)
{
if (tableColumnNames.contains(targetField))
{
return targetField;
}
String relatedColumn = findRelatedColumn(targetField, tableColumnNames);
if (StringUtils.isNotBlank(relatedColumn))
{
return relatedColumn;
}
}
return columnNames != null && columnNames.contains(targetField) ? targetField : "";
}
private String findRelatedColumn(String targetField, Set<String> tableColumnNames)
{
if (StringUtils.isBlank(targetField) || tableColumnNames == null)
{
return "";
}
String[] tokens = targetField.split("_");
for (int i = tokens.length - 1; i >= 0; i--)
{
String token = tokens[i];
if (token.length() >= 3 && tableColumnNames.contains(token))
{
return token;
}
}
for (String columnName : tableColumnNames)
{
if (columnName.length() >= 3 && (targetField.endsWith("_" + columnName)
|| targetField.startsWith(columnName + "_") || targetField.contains("_" + columnName + "_")))
{
return columnName;
}
}
return "";
}
private String rewriteEffectValue(String value, String rawTargetField, String targetField)
{
String normalizedValue = trimToLength(value, 200);
if (StringUtils.isBlank(normalizedValue))
{
return normalizedValue;
}
return normalizedValue.replaceAll("(?<![A-Za-z0-9_])" + Pattern.quote(rawTargetField) + "(?![A-Za-z0-9_])", targetField);
}
private String normalizeEffectType(String type, int index)

View File

@@ -309,6 +309,24 @@ public class AiGenerateServiceImplTest
assertFalse(projectCaptor.getValue().getBusinessBlueprint().contains("fine_record_id"));
}
@Test
public void generateDatabaseRepairsMissingBusinessEffectTargetField()
{
when(frontProjectMapper.selectFrontProjectByUserAndId(7L, 10L)).thenReturn(project());
when(deepSeekClient.chat(anyString())).thenReturn(responseWithMissingBusinessEffectTargetField());
DatabaseDesignResponse response = service.generateDatabase(7L, 10L, request());
BusinessActionEffectDesign effect = response.getBusinessActions().get(0).getEffects().get(0);
assertEquals("stock", effect.getTargetField());
assertEquals("stock - 1", effect.getValue());
ArgumentCaptor<FrontProject> projectCaptor = ArgumentCaptor.forClass(FrontProject.class);
verify(frontProjectMapper).updateFrontProject(projectCaptor.capture());
assertTrue(projectCaptor.getValue().getBusinessBlueprint().contains("\"targetField\":\"stock\""));
assertFalse(projectCaptor.getValue().getBusinessBlueprint().contains("available_stock"));
}
@Test
public void generateDatabaseRejectsBusinessActionReferencingMissingTable()
{
@@ -626,6 +644,27 @@ public class AiGenerateServiceImplTest
+ "}";
}
private String responseWithMissingBusinessEffectTargetField()
{
return "{\n"
+ " \"tables\": [\n"
+ " {\"tableName\": \"book_info\", \"tableComment\": \"Book info\", \"columns\": [\n"
+ " {\"columnName\": \"book_id\", \"columnType\": \"bigint(20)\", \"primaryKey\": true, \"autoIncrement\": true, \"columnComment\": \"Book ID\"},\n"
+ " {\"columnName\": \"stock\", \"columnType\": \"int(11)\", \"columnComment\": \"Stock\"}\n"
+ " ]},\n"
+ " {\"tableName\": \"borrow_record\", \"tableComment\": \"Borrow record\", \"columns\": [\n"
+ " {\"columnName\": \"borrow_id\", \"columnType\": \"bigint(20)\", \"primaryKey\": true, \"autoIncrement\": true, \"columnComment\": \"Borrow ID\"},\n"
+ " {\"columnName\": \"book_id\", \"columnType\": \"bigint(20)\", \"columnComment\": \"Book ID\"}\n"
+ " ]}\n"
+ " ],\n"
+ " \"businessActions\": [\n"
+ " {\"code\": \"borrow_book\", \"name\": \"Borrow Book\", \"ownerTable\": \"borrow_record\", \"method\": \"POST\", \"path\": \"/borrow\", \"requestFields\": [\"book_id\"], \"effects\": [\n"
+ " {\"type\": \"UPDATE_FIELD\", \"targetTable\": \"book_info\", \"targetField\": \"available_stock\", \"value\": \"available_stock - 1\", \"conditionFields\": [\"book_id\"], \"description\": \"Decrease available stock\"}\n"
+ " ]}\n"
+ " ]\n"
+ "}";
}
private String responseWithMissingBusinessActionTable()
{
return "{\n"